summaryrefslogtreecommitdiffstats
path: root/daemon
diff options
context:
space:
mode:
authorRichard Jones <rjones@redhat.com>2009-04-03 19:08:19 +0100
committerRichard Jones <rjones@redhat.com>2009-04-03 19:08:19 +0100
commitd134143b55ecb5f7e6f74318acbf04f9e1370af6 (patch)
treedd12c32499204fc9967babb5b3207143e644e631 /daemon
parent40ca9a57829f2e82362e391d7d998bf33c8bd671 (diff)
downloadlibguestfs-d134143b55ecb5f7e6f74318acbf04f9e1370af6.tar.gz
libguestfs-d134143b55ecb5f7e6f74318acbf04f9e1370af6.tar.xz
libguestfs-d134143b55ecb5f7e6f74318acbf04f9e1370af6.zip
Makes a series of non-trivial calls.
Diffstat (limited to 'daemon')
-rw-r--r--daemon/daemon.h4
-rw-r--r--daemon/guestfsd.c20
-rw-r--r--daemon/proto.c200
-rw-r--r--daemon/stubs.c4
4 files changed, 224 insertions, 4 deletions
diff --git a/daemon/daemon.h b/daemon/daemon.h
index b8a9001f..a328435d 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 eaba7f04..6fc8b19f 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 f045751f..131c66be 100644
--- a/daemon/proto.c
+++ b/daemon/proto.c
@@ -23,10 +23,18 @@
#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);
}
diff --git a/daemon/stubs.c b/daemon/stubs.c
index 22fd5755..54fa8e00 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;