aboutsummaryrefslogtreecommitdiffstats
path: root/pseudo_ipc.c
diff options
context:
space:
mode:
Diffstat (limited to 'pseudo_ipc.c')
-rw-r--r--pseudo_ipc.c244
1 files changed, 244 insertions, 0 deletions
diff --git a/pseudo_ipc.c b/pseudo_ipc.c
new file mode 100644
index 0000000..cd18140
--- /dev/null
+++ b/pseudo_ipc.c
@@ -0,0 +1,244 @@
+/*
+ * pseudo_ipc.c, IPC code for pseudo client/server
+ *
+ * Copyright (c) 2008-2010 Wind River Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the Lesser GNU General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Lesser GNU General Public License for more details.
+ *
+ * You should have received a copy of the Lesser GNU General Public License
+ * version 2.1 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "pseudo.h"
+#include "pseudo_ipc.h"
+
+/* Short reads or writes can cause a sigpipe, killing the program, so we
+ * trap it and report that something happened.
+ */
+static sig_atomic_t pipe_error = 0;
+static void (*old_handler)(int) = SIG_DFL;
+
+static void
+sigpipe_trap(int unused) {
+ pipe_error = 1;
+}
+
+static void
+ignore_sigpipe(void) {
+ pipe_error = 0;
+ old_handler = signal(SIGPIPE, sigpipe_trap);
+}
+
+static void
+allow_sigpipe(void) {
+ signal(SIGPIPE, old_handler);
+}
+
+#if 0
+/* useful only when debugging crazy stuff */
+static void
+display_msg_header(pseudo_msg_t *msg) {
+ pseudo_debug(4, "type: %d\n", msg->type);
+ pseudo_debug(4, "inode: %llu\n", (unsigned long long) msg->ino);
+ pseudo_debug(4, "uid: %d\n", msg->uid);
+ pseudo_debug(4, "pathlen: %d\n", (int) msg->pathlen);
+ if (msg->pathlen) {
+ pseudo_debug(4, "path: %s\n", msg->path);
+ }
+}
+#endif
+
+/*
+ * send message on fd
+ * return:
+ * 0 on success
+ * >0 on error
+ * <0 on error suggesting other end is dead
+ */
+int
+pseudo_msg_send(int fd, pseudo_msg_t *msg, size_t len, const char *path) {
+ int r;
+
+ if (!msg)
+ return 1;
+
+ if (fd < 0)
+ return -1;
+
+ if (path) {
+ pseudo_debug(4, "msg type %d (%s), external path %s, mode 0%o\n",
+ msg->type, pseudo_op_name(msg->op), path, (int) msg->mode);
+ if (len == -1)
+ len = strlen(path) + 1;
+ msg->pathlen = len;
+ ignore_sigpipe();
+ r = write(fd, msg, PSEUDO_HEADER_SIZE);
+ if (r == PSEUDO_HEADER_SIZE) {
+ r += write(fd, path, len);
+ }
+ allow_sigpipe();
+ pseudo_debug(5, "wrote %d bytes\n", r);
+ if (pipe_error || (r == -1 && errno == EBADF))
+ return -1;
+ return (r != PSEUDO_HEADER_SIZE + len);
+ } else {
+ pseudo_debug(4, "msg type %d (%s), result %d (%s), path %.*s, mode 0%o\n",
+ msg->type, pseudo_op_name(msg->op),
+ msg->result, pseudo_res_name(msg->result),
+ msg->pathlen, msg->path, (int) msg->mode);
+ // display_msg_header(msg);
+ ignore_sigpipe();
+ r = write(fd, msg, PSEUDO_HEADER_SIZE + msg->pathlen);
+ allow_sigpipe();
+ pseudo_debug(5, "wrote %d bytes\n", r);
+ if (pipe_error || (r == -1 && errno == EBADF))
+ return -1;
+ return (r != PSEUDO_HEADER_SIZE + msg->pathlen);
+ }
+}
+
+/* attempts to receive a message from fd
+ * return is allocated message if one is provided
+ */
+pseudo_msg_t *
+pseudo_msg_receive(int fd) {
+ static pseudo_msg_t *incoming;
+ static size_t incoming_pathlen;
+ pseudo_msg_t *newmsg, header;
+ int r;
+
+ if (fd < 0)
+ return 0;
+ errno = 0;
+ r = read(fd, &header, PSEUDO_HEADER_SIZE);
+ if (r == -1) {
+ pseudo_debug(2, "read failed: %s\n", strerror(errno));
+ return 0;
+ }
+ if (r < (int) PSEUDO_HEADER_SIZE) {
+ pseudo_debug(2, "got only %d bytes (%s)\n", r, strerror(errno));
+ return 0;
+ }
+ pseudo_debug(4, "got header, type %d, pathlen %d\n", header.type, (int) header.pathlen);
+ // display_msg_header(&header);
+ if (!incoming || header.pathlen >= incoming_pathlen) {
+ newmsg = pseudo_msg_new(header.pathlen + 128, 0);
+ if (!newmsg) {
+ pseudo_diag("Couldn't allocate header for path of %d bytes.\n",
+ (int) header.pathlen);
+ return 0;
+ }
+ free(incoming);
+ incoming = newmsg;
+ incoming_pathlen = header.pathlen + 128;
+ }
+ *incoming = header;
+ if (incoming->pathlen) {
+ r = read(fd, incoming->path, incoming->pathlen);
+ if (r < incoming->pathlen) {
+ pseudo_debug(2, "short read on path, expecting %d, got %d\n",
+ (int) incoming->pathlen, r);
+ return 0;
+ }
+ /* ensure null termination */
+ incoming->path[r] = '\0';
+ }
+ // display_msg_header(incoming);
+ return incoming;
+}
+
+/* duplicate a message -- currently totally unused */
+pseudo_msg_t *
+pseudo_msg_dup(pseudo_msg_t *old) {
+ pseudo_msg_t *newmsg;
+ if (!old)
+ return NULL;
+ newmsg = malloc(sizeof(pseudo_msg_t) + old->pathlen);
+ if (!newmsg)
+ return NULL;
+ memcpy(newmsg, old, sizeof(pseudo_msg_t) + old->pathlen);
+ return newmsg;
+}
+
+/* allocate a message either with pathlen chars of storage or with enough
+ * storage for path
+ */
+pseudo_msg_t *
+pseudo_msg_new(size_t pathlen, const char *path) {
+ pseudo_msg_t *newmsg;
+ if (pathlen) {
+ newmsg = malloc(sizeof(pseudo_msg_t) + pathlen);
+ if (newmsg) {
+ newmsg->pathlen = pathlen;
+ if (path)
+ memcpy(newmsg->path, path, pathlen);
+ newmsg->path[pathlen - 1] = '\0';
+ }
+ return newmsg;
+ } else {
+ if (!path) {
+ /* no pathlen, no path == purely informational */
+ newmsg = malloc(sizeof(pseudo_msg_t));
+ if (newmsg) {
+ newmsg->pathlen = 0;
+ }
+ return newmsg;
+ } else {
+ pathlen = strlen(path) + 1;
+ newmsg = malloc(sizeof(pseudo_msg_t) + pathlen);
+ if (newmsg) {
+ memcpy(newmsg->path, path, pathlen);
+ newmsg->pathlen = pathlen;
+ }
+ return newmsg;
+ }
+ }
+}
+
+/* The following functions populate messages from statbufs and vice versa.
+ * It is intentional that copying a message into a stat doesn't touch nlink;
+ * the nlink value was not stored in the database (it is in the message at
+ * all only so the server can do sanity checks).
+ */
+
+void
+pseudo_msg_stat(pseudo_msg_t *msg, const struct stat64 *buf) {
+ if (!msg || !buf)
+ return;
+ msg->uid = buf->st_uid;
+ msg->gid = buf->st_gid;
+ msg->dev = buf->st_dev;
+ msg->ino = buf->st_ino;
+ msg->mode = buf->st_mode;
+ msg->rdev = buf->st_rdev;
+ msg->nlink = buf->st_nlink;
+}
+
+void
+pseudo_stat_msg(struct stat64 *buf, const pseudo_msg_t *msg) {
+ if (!msg || !buf)
+ return;
+ buf->st_uid = msg->uid;
+ buf->st_gid = msg->gid;
+ buf->st_mode = msg->mode;
+ buf->st_rdev = msg->rdev;
+}
+