From d134143b55ecb5f7e6f74318acbf04f9e1370af6 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Fri, 3 Apr 2009 19:08:19 +0100 Subject: [PATCH] Makes a series of non-trivial calls. --- daemon/daemon.h | 4 +- daemon/guestfsd.c | 20 +++++ daemon/proto.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++- daemon/stubs.c | 4 + src/generator.ml | 12 ++- src/guestfs-actions.c | 6 +- src/guestfs.c | 13 +++- src/guestfs_protocol.c | 10 +++ src/guestfs_protocol.h | 8 ++ src/guestfs_protocol.x | 6 ++ 10 files changed, 270 insertions(+), 13 deletions(-) diff --git a/daemon/daemon.h b/daemon/daemon.h index b8a9001..a328435 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -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 */ diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c index eaba7f0..6fc8b19 100644 --- a/daemon/guestfsd.c +++ b/daemon/guestfsd.c @@ -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) { diff --git a/daemon/proto.c b/daemon/proto.c index f045751..131c66b 100644 --- a/daemon/proto.c +++ b/daemon/proto.c @@ -23,10 +23,18 @@ #include #include #include +#include +#include #include #include #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); } diff --git a/daemon/stubs.c b/daemon/stubs.c index 22fd575..54fa8e0 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -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; diff --git a/src/generator.ml b/src/generator.ml index 8588cf3..f3e53cd 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -208,6 +208,12 @@ enum guestfs_message_status { GUESTFS_STATUS_ERROR = 1 }; +const GUESTFS_ERROR_LEN = 256; + +struct guestfs_message_error { + string error; /* 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"; diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index 12ae602..f6130d3 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -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) diff --git a/src/guestfs.c b/src/guestfs.c index 309cd15..6de631f 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -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; diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index 8a59085..aa5f4e3 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -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; diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h index 562d72f..f8c8043 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -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 */ diff --git a/src/guestfs_protocol.x b/src/guestfs_protocol.x index 1641b3d..106bb60 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -56,6 +56,12 @@ enum guestfs_message_status { GUESTFS_STATUS_ERROR = 1 }; +const GUESTFS_ERROR_LEN = 256; + +struct guestfs_message_error { + string error; /* error message */ +}; + struct guestfs_message_header { unsigned prog; /* GUESTFS_PROGRAM */ unsigned vers; /* GUESTFS_PROTOCOL_VERSION */ -- 1.8.3.1