Makes a series of non-trivial calls.
authorRichard Jones <rjones@redhat.com>
Fri, 3 Apr 2009 18:08:19 +0000 (19:08 +0100)
committerRichard Jones <rjones@redhat.com>
Fri, 3 Apr 2009 18:08:19 +0000 (19:08 +0100)
daemon/daemon.h
daemon/guestfsd.c
daemon/proto.c
daemon/stubs.c
src/generator.ml
src/guestfs-actions.c
src/guestfs.c
src/guestfs_protocol.c
src/guestfs_protocol.h
src/guestfs_protocol.x

index b8a9001..a328435 100644 (file)
@@ -25,6 +25,7 @@
 
 /* in guestfsd.c */
 extern void xwrite (int sock, const void *buf, size_t len);
+extern void xread (int sock, void *buf, size_t len);
 
 /* in proto.c */
 extern int proc_nr;
@@ -36,6 +37,7 @@ extern void dispatch_incoming_message (XDR *);
 /* in proto.c */
 extern void main_loop (int sock);
 extern void reply_with_error (const char *fs, ...);
-extern void reply (xdrproc_t, XDR *);
+extern void reply_with_perror (const char *fs, ...);
+extern void reply (xdrproc_t xdrp, char *ret);
 
 #endif /* GUESTFSD_DAEMON_H */
index eaba7f0..6fc8b19 100644 (file)
@@ -204,6 +204,26 @@ xwrite (int sock, const void *buf, size_t len)
   }
 }
 
+void
+xread (int sock, void *buf, size_t len)
+{
+  int r;
+
+  while (len > 0) {
+    r = read (sock, buf, len);
+    if (r == -1) {
+      perror ("read");
+      exit (1);
+    }
+    if (r == 0) {
+      fprintf (stderr, "read: unexpected end of file on comms socket\n");
+      exit (1);
+    }
+    buf += r;
+    len -= r;
+  }
+}
+
 static void
 usage (void)
 {
index f045751..131c66b 100644 (file)
 #include <stdarg.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
 #include <rpc/types.h>
 #include <rpc/xdr.h>
 
 #include "daemon.h"
+#include "../src/guestfs_protocol.h"
+
+/* XXX We should make this configurable from /proc/cmdline so that the
+ * verbose setting of the guestfs_h can be inherited here.
+ */
+#define DEBUG 1
 
 /* The message currently being processed. */
 int proc_nr;
@@ -38,22 +46,208 @@ static int sock;
 void
 main_loop (int _sock)
 {
+  XDR xdr;
+  char *buf;
+  char lenbuf[4];
+  unsigned len;
+  struct guestfs_message_header hdr;
+
   sock = _sock;
 
-  
+  for (;;) {
+    /* Read the length word. */
+    xread (sock, lenbuf, 4);
+    xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE);
+    xdr_uint32_t (&xdr, &len);
+    xdr_destroy (&xdr);
+
+    if (len > GUESTFS_MESSAGE_MAX) {
+      fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
+              len);
+      exit (1);
+    }
+
+    buf = malloc (len);
+    if (!buf) {
+      reply_with_perror ("malloc");
+      continue;
+    }
+
+    xread (sock, buf, len);
+
+#if DEBUG
+    int i, j;
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+    for (i = 0; i < len; i += 16) {
+      printf ("%04x: ", i);
+      for (j = i; j < MIN (i+16, len); ++j)
+       printf ("%02x ", (unsigned char) buf[j]);
+      for (; j < i+16; ++j)
+       printf ("   ");
+      printf ("|");
+      for (j = i; j < MIN (i+16, len); ++j)
+       if (isprint (buf[j]))
+         printf ("%c", buf[j]);
+       else
+         printf (".");
+      for (; j < i+16; ++j)
+       printf (" ");
+      printf ("|\n");
+    }
+#endif
+
+    /* Decode the message header. */
+    xdrmem_create (&xdr, buf, len, XDR_DECODE);
+    if (!xdr_guestfs_message_header (&xdr, &hdr)) {
+      fprintf (stderr, "guestfsd: could not decode message header\n");
+      exit (1);
+    }
 
+    /* Check the version etc. */
+    if (hdr.prog != GUESTFS_PROGRAM) {
+      reply_with_error ("wrong program (%d)", hdr.prog);
+      goto cont;
+    }
+    if (hdr.vers != GUESTFS_PROTOCOL_VERSION) {
+      reply_with_error ("wrong protocol version (%d)", hdr.vers);
+      goto cont;
+    }
+    if (hdr.direction != GUESTFS_DIRECTION_CALL) {
+      reply_with_error ("unexpected message direction (%d)", hdr.direction);
+      goto cont;
+    }
+    if (hdr.status != GUESTFS_STATUS_OK) {
+      reply_with_error ("unexpected message status (%d)", hdr.status);
+      goto cont;
+    }
 
+    /* Now start to process this message. */
+    proc_nr = hdr.proc;
+    serial = hdr.serial;
+    dispatch_incoming_message (&xdr);
+    /* Note that dispatch_incoming_message will also send a reply. */
+
+  cont:
+    xdr_destroy (&xdr);
+    free (buf);
+  }
 }
 
+static void send_error (const char *msg);
+
 void
 reply_with_error (const char *fs, ...)
 {
-  
+  char err[GUESTFS_ERROR_LEN];
+  va_list args;
+
+  va_start (args, fs);
+  vsnprintf (err, sizeof err, fs, args);
+  va_end (args);
+
+  send_error (err);
+}
+
+void
+reply_with_perror (const char *fs, ...)
+{
+  char buf1[GUESTFS_ERROR_LEN];
+  char buf2[GUESTFS_ERROR_LEN];
+  va_list args;
+  int err = errno;
+
+  va_start (args, fs);
+  vsnprintf (buf1, sizeof buf1, fs, args);
+  va_end (args);
+
+  snprintf (buf2, sizeof buf2, "%s: %s", buf1, strerror (err));
+
+  send_error (buf2);
+}
+
+static void
+send_error (const char *msg)
+{
+  XDR xdr;
+  char buf[GUESTFS_ERROR_LEN + 200];
+  char lenbuf[4];
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  unsigned len;
+
+  fprintf (stderr, "guestfsd: error: %s\n", msg);
+
+  xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
+
+  hdr.prog = GUESTFS_PROGRAM;
+  hdr.vers = GUESTFS_PROTOCOL_VERSION;
+  hdr.direction = GUESTFS_DIRECTION_REPLY;
+  hdr.status = GUESTFS_STATUS_ERROR;
+  hdr.proc = proc_nr;
+  hdr.serial = serial;
+
+  if (!xdr_guestfs_message_header (&xdr, &hdr)) {
+    fprintf (stderr, "guestfsd: failed to encode error message header\n");
+    exit (1);
+  }
+
+  err.error = (char *) msg;
 
+  if (!xdr_guestfs_message_error (&xdr, &err)) {
+    fprintf (stderr, "guestfsd: failed to encode error message body\n");
+    exit (1);
+  }
 
+  len = xdr_getpos (&xdr);
+  xdr_destroy (&xdr);
+
+  xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
+  xdr_uint32_t (&xdr, &len);
+  xdr_destroy (&xdr);
+
+  xwrite (sock, lenbuf, 4);
+  xwrite (sock, buf, len);
 }
 
 void
-reply (xdrproc_t xdrp, XDR *xdr)
+reply (xdrproc_t xdrp, char *ret)
 {
+  XDR xdr;
+  char buf[GUESTFS_MESSAGE_MAX];
+  char lenbuf[4];
+  struct guestfs_message_header hdr;
+  unsigned len;
+
+  xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
+
+  hdr.prog = GUESTFS_PROGRAM;
+  hdr.vers = GUESTFS_PROTOCOL_VERSION;
+  hdr.direction = GUESTFS_DIRECTION_REPLY;
+  hdr.status = GUESTFS_STATUS_OK;
+  hdr.proc = proc_nr;
+  hdr.serial = serial;
+
+  if (!xdr_guestfs_message_header (&xdr, &hdr)) {
+    fprintf (stderr, "guestfsd: failed to encode reply header\n");
+    exit (1);
+  }
+
+  if (xdrp) {
+    if (!(*xdrp) (&xdr, ret)) {
+      fprintf (stderr, "guestfsd: failed to encode reply body\n");
+      exit (1);
+    }
+  }
+
+  len = xdr_getpos (&xdr);
+  xdr_destroy (&xdr);
+
+  xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
+  xdr_uint32_t (&xdr, &len);
+  xdr_destroy (&xdr);
+
+  xwrite (sock, lenbuf, 4);
+  xwrite (sock, buf, len);
 }
index 22fd575..54fa8e0 100644 (file)
@@ -32,6 +32,8 @@ static void mount_stub (XDR *xdr_in)
   const char *device;
   const char *mountpoint;
 
+  memset (&args, 0, sizeof args);
+
   if (!xdr_guestfs_mount_args (xdr_in, &args)) {
     reply_with_error ("mount: daemon failed to decode procedure arguments");
     return;
@@ -65,6 +67,8 @@ static void touch_stub (XDR *xdr_in)
   struct guestfs_touch_args args;
   const char *path;
 
+  memset (&args, 0, sizeof args);
+
   if (!xdr_guestfs_touch_args (xdr_in, &args)) {
     reply_with_error ("touch: daemon failed to decode procedure arguments");
     return;
index 8588cf3..f3e53cd 100755 (executable)
@@ -208,6 +208,12 @@ enum guestfs_message_status {
   GUESTFS_STATUS_ERROR = 1
 };
 
+const GUESTFS_ERROR_LEN = 256;
+
+struct guestfs_message_error {
+  string error<GUESTFS_ERROR_LEN>;   /* error message */
+};
+
 struct guestfs_message_header {
   unsigned prog;                     /* GUESTFS_PROGRAM */
   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
@@ -239,10 +245,10 @@ and generate_client_actions () =
       pr "struct %s_rv {\n" shortname;
       pr "  int err_code;      /* 0 OK or -1 error */\n";
       pr "  int serial;        /* serial number of reply */\n";
-      pr "  char err_str[256]; /* error from daemon */\n";
+      pr "  char err_str[GUESTFS_ERROR_LEN]; /* error from daemon */\n";
       (match style with
        | (Err, _) -> ()
-    (* | _ -> pr "  struct %s_ret ret;\n" name; *)
+    (* | _ -> pr "  struct %s_ret ret;\n" name; REMEMBER TO MEMSET *)
       );
       pr "};\n\n";
 
@@ -366,6 +372,8 @@ and generate_daemon_actions () =
       (match style with
        | (_, P0) -> ()
        | (_, args) ->
+          pr "  memset (&args, 0, sizeof args);\n";
+          pr "\n";
           pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
           pr "    reply_with_error (\"%s: daemon failed to decode procedure arguments\");\n" name;
           pr "    return;\n";
index 12ae602..f6130d3 100644 (file)
@@ -22,7 +22,7 @@
 struct mount_rv {
   int err_code;      /* 0 OK or -1 error */
   int serial;        /* serial number of reply */
-  char err_str[256]; /* error from daemon */
+  char err_str[GUESTFS_ERROR_LEN]; /* error from daemon */
 };
 
 static void mount_cb (guestfs_h *g, void *data, XDR *xdr)
@@ -78,7 +78,7 @@ int guestfs_mount (guestfs_h *g,
 struct sync_rv {
   int err_code;      /* 0 OK or -1 error */
   int serial;        /* serial number of reply */
-  char err_str[256]; /* error from daemon */
+  char err_str[GUESTFS_ERROR_LEN]; /* error from daemon */
 };
 
 static void sync_cb (guestfs_h *g, void *data, XDR *xdr)
@@ -127,7 +127,7 @@ int guestfs_sync (guestfs_h *g)
 struct touch_rv {
   int err_code;      /* 0 OK or -1 error */
   int serial;        /* serial number of reply */
-  char err_str[256]; /* error from daemon */
+  char err_str[GUESTFS_ERROR_LEN]; /* error from daemon */
 };
 
 static void touch_cb (guestfs_h *g, void *data, XDR *xdr)
index 309cd15..6de631f 100644 (file)
@@ -170,6 +170,11 @@ guestfs_create (void)
   str = getenv ("LIBGUESTFS_DEBUG");
   g->verbose = str != NULL && strcmp (str, "1") == 0;
 
+  /* Start with large serial numbers so they are easy to spot
+   * inside the protocol.
+   */
+  g->msg_next_serial = 0x00123400;
+
   return g;
 }
 
@@ -862,13 +867,13 @@ sock_read_event (void *data, int watch, int fd, int events)
     goto cleanup;
   }
 
-  if (g->msg_in_size < len) return; /* Need more of this message. */
+  if (g->msg_in_size-4 < len) return; /* Need more of this message. */
 
   /* This should not happen, and if it does it probably means we've
    * lost all hope of synchronization.
    */
-  if (g->msg_in_size > len) {
-    error (g, "len = %d, but msg_in_size = %d", len, g->msg_in_size);
+  if (g->msg_in_size-4 > len) {
+    error (g, "len = %d, but msg_in_size-4 = %d", len, g->msg_in_size-4);
     goto cleanup;
   }
 
@@ -944,7 +949,7 @@ sock_write_event (void *data, int watch, int fd, int events)
     return;
 
   if (g->verbose)
-    fprintf (stderr, "sock_write_event: done writing, switching back to reading events\n", n);
+    fprintf (stderr, "sock_write_event: done writing, switching back to reading events\n");
 
   free (g->msg_out);
   g->msg_out_pos = g->msg_out_size = 0;
index 8a59085..aa5f4e3 100644 (file)
@@ -58,6 +58,16 @@ xdr_guestfs_message_status (XDR *xdrs, guestfs_message_status *objp)
 }
 
 bool_t
+xdr_guestfs_message_error (XDR *xdrs, guestfs_message_error *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->error, GUESTFS_ERROR_LEN))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
 xdr_guestfs_message_header (XDR *xdrs, guestfs_message_header *objp)
 {
        register int32_t *buf;
index 562d72f..f8c8043 100644 (file)
@@ -47,6 +47,12 @@ enum guestfs_message_status {
        GUESTFS_STATUS_ERROR = 1,
 };
 typedef enum guestfs_message_status guestfs_message_status;
+#define GUESTFS_ERROR_LEN 256
+
+struct guestfs_message_error {
+       char *error;
+};
+typedef struct guestfs_message_error guestfs_message_error;
 
 struct guestfs_message_header {
        u_int prog;
@@ -66,6 +72,7 @@ extern  bool_t xdr_guestfs_touch_args (XDR *, guestfs_touch_args*);
 extern  bool_t xdr_guestfs_procedure (XDR *, guestfs_procedure*);
 extern  bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*);
 extern  bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*);
+extern  bool_t xdr_guestfs_message_error (XDR *, guestfs_message_error*);
 extern  bool_t xdr_guestfs_message_header (XDR *, guestfs_message_header*);
 
 #else /* K&R C */
@@ -74,6 +81,7 @@ extern bool_t xdr_guestfs_touch_args ();
 extern bool_t xdr_guestfs_procedure ();
 extern bool_t xdr_guestfs_message_direction ();
 extern bool_t xdr_guestfs_message_status ();
+extern bool_t xdr_guestfs_message_error ();
 extern bool_t xdr_guestfs_message_header ();
 
 #endif /* K&R C */
index 1641b3d..106bb60 100644 (file)
@@ -56,6 +56,12 @@ enum guestfs_message_status {
   GUESTFS_STATUS_ERROR = 1
 };
 
+const GUESTFS_ERROR_LEN = 256;
+
+struct guestfs_message_error {
+  string error<GUESTFS_ERROR_LEN>;   /* error message */
+};
+
 struct guestfs_message_header {
   unsigned prog;                     /* GUESTFS_PROGRAM */
   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */