Daemon and library are mostly talking to each other now.
authorRichard Jones <rjones@redhat.com>
Fri, 3 Apr 2009 16:24:35 +0000 (17:24 +0100)
committerRichard Jones <rjones@redhat.com>
Fri, 3 Apr 2009 16:24:35 +0000 (17:24 +0100)
18 files changed:
.gitignore
daemon/Makefile.am
daemon/actions.h
daemon/daemon.h [new file with mode: 0644]
daemon/guestfsd.c
daemon/proto.c [new file with mode: 0644]
daemon/stubs.c
daemon/sync.c [new file with mode: 0644]
examples/Makefile.am
examples/hello.c [new file with mode: 0644]
guestfs.pod
src/Makefile.am
src/generator.ml
src/guestfs-actions.c
src/guestfs.c
src/guestfs_protocol.c [new file with mode: 0644]
src/guestfs_protocol.h [new file with mode: 0644]
src/guestfs_protocol.x

index a9bd0d6..8771111 100644 (file)
@@ -22,6 +22,7 @@ daemon/missing
 depcomp
 emptydisk
 examples/df
 depcomp
 emptydisk
 examples/df
+examples/hello
 guestfs.3
 initramfs
 initramfs.timestamp
 guestfs.3
 initramfs
 initramfs.timestamp
index 6a5a4ee..cf55250 100644 (file)
 ACLOCAL_AMFLAGS = -I m4
 
 noinst_PROGRAMS = guestfsd
 ACLOCAL_AMFLAGS = -I m4
 
 noinst_PROGRAMS = guestfsd
-guestfsd_SOURCES = guestfsd.c
+guestfsd_SOURCES = \
+       actions.h \
+       daemon.h \
+       guestfsd.c \
+       proto.c \
+       stubs.c \
+       sync.c \
+       ../src/guestfs_protocol.h \
+       ../src/guestfs_protocol.c
 
 
-guestfsd_CFLAGS = -Wall -Werror
\ No newline at end of file
+guestfsd_CFLAGS = -Wall
\ No newline at end of file
index c7d64df..61b583c 100644 (file)
@@ -19,6 +19,6 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-extern int do_mount (guestfs_h *handle, const char *device, const char *mountpoint);
-extern int do_sync (guestfs_h *handle);
-extern int do_touch (guestfs_h *handle, const char *path);
+extern int do_mount (const char *device, const char *mountpoint);
+extern int do_sync ();
+extern int do_touch (const char *path);
diff --git a/daemon/daemon.h b/daemon/daemon.h
new file mode 100644 (file)
index 0000000..b8a9001
--- /dev/null
@@ -0,0 +1,41 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef GUESTFSD_DAEMON_H
+#define GUESTFSD_DAEMON_H
+
+#include <stdarg.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+/* in guestfsd.c */
+extern void xwrite (int sock, const void *buf, size_t len);
+
+/* in proto.c */
+extern int proc_nr;
+extern int serial;
+
+/* in stubs.c (auto-generated) */
+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 *);
+
+#endif /* GUESTFSD_DAEMON_H */
index c27d1b6..eaba7f0 100644 (file)
 #include <getopt.h>
 #include <netdb.h>
 
 #include <getopt.h>
 #include <netdb.h>
 
-static void xwrite (int sock, const void *buf, size_t len);
+#include "daemon.h"
+
+void xwrite (int sock, const void *buf, size_t len);
+
 static void usage (void);
 
 /* Also in guestfs.c */
 static void usage (void);
 
 /* Also in guestfs.c */
@@ -177,12 +180,15 @@ main (int argc, char *argv[])
 
 
 
 
 
 
-  sleep (1000000);
+
+
+
+  main_loop (sock);
 
   exit (0);
 }
 
 
   exit (0);
 }
 
-static void
+void
 xwrite (int sock, const void *buf, size_t len)
 {
   int r;
 xwrite (int sock, const void *buf, size_t len)
 {
   int r;
@@ -203,3 +209,18 @@ usage (void)
 {
   fprintf (stderr, "guestfsd [-f] [-h host -p port]\n");
 }
 {
   fprintf (stderr, "guestfsd [-f] [-h host -p port]\n");
 }
+
+/* Some unimplemented actions. */
+int
+do_mount (const char *device, const char *mountpoint)
+{
+  reply_with_error ("mount not implemented");
+  return -1;
+}
+
+int
+do_touch (const char *path)
+{
+  reply_with_error ("touch not implemented");
+  return -1;
+}
diff --git a/daemon/proto.c b/daemon/proto.c
new file mode 100644 (file)
index 0000000..f045751
--- /dev/null
@@ -0,0 +1,59 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 Red Hat Inc. 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+#include "daemon.h"
+
+/* The message currently being processed. */
+int proc_nr;
+int serial;
+
+/* The daemon communications socket. */
+static int sock;
+
+void
+main_loop (int _sock)
+{
+  sock = _sock;
+
+  
+
+
+}
+
+void
+reply_with_error (const char *fs, ...)
+{
+  
+
+
+}
+
+void
+reply (xdrproc_t xdrp, XDR *xdr)
+{
+}
index 81c5b72..22fd575 100644 (file)
@@ -22,7 +22,7 @@
 #include <rpc/types.h>
 #include <rpc/xdr.h>
 #include "daemon.h"
 #include <rpc/types.h>
 #include <rpc/xdr.h>
 #include "daemon.h"
-#include "../src/guest_protocol.h"
+#include "../src/guestfs_protocol.h"
 #include "actions.h"
 
 static void mount_stub (XDR *xdr_in)
 #include "actions.h"
 
 static void mount_stub (XDR *xdr_in)
@@ -79,3 +79,19 @@ static void touch_stub (XDR *xdr_in)
   reply (NULL, NULL);
 }
 
   reply (NULL, NULL);
 }
 
+void dispatch_incoming_message (XDR *xdr_in)
+{
+  switch (proc_nr) {
+    case GUESTFS_PROC_MOUNT:
+      mount_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_SYNC:
+      sync_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_TOUCH:
+      touch_stub (xdr_in);
+      break;
+    default:
+      reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
+  }
+}
diff --git a/daemon/sync.c b/daemon/sync.c
new file mode 100644 (file)
index 0000000..9ade840
--- /dev/null
@@ -0,0 +1,32 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 Red Hat Inc. 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "actions.h"
+
+int
+do_sync ()
+{
+  sync ();
+  fprintf (stderr, "guestfsd: disk synched\n");
+  return 0;
+}
index 66a32d7..9bac5f3 100644 (file)
@@ -1,7 +1,11 @@
 # libguestfs examples
 
 # libguestfs examples
 
-noinst_PROGRAMS = df
+noinst_PROGRAMS = df hello
 
 df_SOURCES = df.c
 
 df_SOURCES = df.c
-df_CFLAGS = -I$(top_builddir)/src
+df_CFLAGS = -I$(top_builddir)/src -Wall
 df_LDADD = $(top_builddir)/src/libguestfs.la
 df_LDADD = $(top_builddir)/src/libguestfs.la
+
+hello_SOURCES = hello.c
+hello_CFLAGS = -I$(top_builddir)/src -Wall
+hello_LDADD = $(top_builddir)/src/libguestfs.la
diff --git a/examples/hello.c b/examples/hello.c
new file mode 100644 (file)
index 0000000..5f1ab0e
--- /dev/null
@@ -0,0 +1,33 @@
+/* Create a "/hello" file on /dev/sda1. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <guestfs.h>
+
+int
+main (int argc, char *argv[])
+{
+  guestfs_h *g;
+
+  if (argc != 2 || access (argv[1], F_OK) != 0) {
+    fprintf (stderr, "Usage: hello disk-image\n");
+    exit (1);
+  }
+
+  if (!(g = guestfs_create ())) exit (1);
+
+  guestfs_set_verbose (g, 1);
+  if (guestfs_add_drive (g, argv[1]) == -1) exit (1);
+
+  if (guestfs_launch (g) == -1) exit (1);
+  if (guestfs_wait_ready (g) == -1) exit (1);
+
+  if (guestfs_mount (g, "/dev/sda1", "/") == -1) exit (1);
+
+  if (guestfs_touch (g, "/hello") == -1) exit (1);
+
+  guestfs_sync (g);
+  guestfs_close (g);
+  return 0;
+}
index bf75e42..61d51b7 100644 (file)
@@ -34,8 +34,7 @@ schemes, qcow, qcow2, vmdk.
 
 Libguestfs provides ways to enumerate guest storage (eg. partitions,
 LVs, what filesystem is in each LV, etc.).  It can also run commands
 
 Libguestfs provides ways to enumerate guest storage (eg. partitions,
 LVs, what filesystem is in each LV, etc.).  It can also run commands
-in the context of the guest.  Also you can mount guest filesystems on
-the host (requires root privs and NFS).
+in the context of the guest.  Also you can access filesystems over FTP.
 
 Libguestfs is a library that can be linked with C and C++ management
 programs (or management programs written in other languages, if people
 
 Libguestfs is a library that can be linked with C and C++ management
 programs (or management programs written in other languages, if people
@@ -366,6 +365,8 @@ this function with C<cb> set to C<NULL>.
 
 =head2 NON-BLOCKING ACTIONS
 
 
 =head2 NON-BLOCKING ACTIONS
 
+XXX NOT IMPLEMENTED YET XXX
+
 C<guestfs_set_reply_callback> is the most interesting callback to
 play with, since it allows you to perform actions without blocking.
 
 C<guestfs_set_reply_callback> is the most interesting callback to
 play with, since it allows you to perform actions without blocking.
 
@@ -391,8 +392,7 @@ For example:
  }
 
 There are C<guestfs_nb_*> and C<guestfs_nb_*_r> functions
  }
 
 There are C<guestfs_nb_*> and C<guestfs_nb_*_r> functions
-corresponding to (very nearly) every C<guestfs_*> action in the
-high-level API.
+corresponding to every C<guestfs_*> action in the high-level API.
 
 =head2 guestfs_set_reply_callback
 
 
 =head2 guestfs_set_reply_callback
 
index a0066db..68cabba 100644 (file)
 
 lib_LTLIBRARIES = libguestfs.la
 
 
 lib_LTLIBRARIES = libguestfs.la
 
-libguestfs_la_SOURCES = guestfs.c guestfs.h
-libguestfs_la_CFLAGS = -Wall -Werror
\ No newline at end of file
+# NB. guestfs-actions.c is #include'd into guestfs.c, so it should not
+# be listed as a source file.
+EXTRA_DIST = guestfs-actions.c
+
+libguestfs_la_SOURCES = \
+       guestfs.c \
+       guestfs.h \
+       guestfs_protocol.c \
+       guestfs_protocol.h \
+       guestfs-actions.h
+
+libguestfs_la_CFLAGS = -Wall
+
+if RPCGEN
+guestfs_protocol.c: guestfs_protocol.x
+       rm -f $@-t
+       $(RPCGEN) -c -o $@-t $<
+       mv $@-t $@
+
+guestfs_protocol.h: guestfs_protocol.x
+       rm -f $@-t
+       $(RPCGEN) -h -o $@-t $<
+       mv $@-t $@
+endif
\ No newline at end of file
index d08e269..8588cf3 100755 (executable)
@@ -41,7 +41,7 @@ and argt =
   | String of string   (* const char *name, cannot be NULL *)
 
 let functions = [
   | String of string   (* const char *name, cannot be NULL *)
 
 let functions = [
-  ("mount", (Err, P2 (String "device", String "mountpoint")),
+  ("mount", (Err, P2 (String "device", String "mountpoint")), 1,
    "Mount a guest disk at a position in the filesystem",
    "\
 Mount a guest disk at a position in the filesystem.  Block devices
    "Mount a guest disk at a position in the filesystem",
    "\
 Mount a guest disk at a position in the filesystem.  Block devices
@@ -55,7 +55,7 @@ first be mounted on C</> before others can be mounted.  Other
 filesystems can only be mounted on directories which already
 exist.");
 
 filesystems can only be mounted on directories which already
 exist.");
 
-  ("sync", (Err, P0),
+  ("sync", (Err, P0), 2,
    "Sync disks, writes are flushed through to the disk image",
    "\
 This syncs the disk, so that any writes are flushed through to the
    "Sync disks, writes are flushed through to the disk image",
    "\
 This syncs the disk, so that any writes are flushed through to the
@@ -64,7 +64,7 @@ underlying disk image.
 You should always call this if you have modified a disk image, before
 calling C<guestfs_close>.");
 
 You should always call this if you have modified a disk image, before
 calling C<guestfs_close>.");
 
-  ("touch", (Err, P1 (String "path")),
+  ("touch", (Err, P1 (String "path")), 3,
    "Update file timestamps or create a new file",
    "\
 Touch acts like the L<touch(1)> command.  It can be used to
    "Update file timestamps or create a new file",
    "\
 Touch acts like the L<touch(1)> command.  It can be used to
@@ -137,11 +137,11 @@ let rec generate_header comment license =
 (* Generate the pod documentation for the C API. *)
 and generate_pod () =
   List.iter (
 (* Generate the pod documentation for the C API. *)
 and generate_pod () =
   List.iter (
-    fun (shortname, style, _, longdesc) ->
+    fun (shortname, style, _, _, longdesc) ->
       let name = "guestfs_" ^ shortname in
       pr "=head2 %s\n\n" name;
       pr " ";
       let name = "guestfs_" ^ shortname in
       pr "=head2 %s\n\n" name;
       pr " ";
-      generate_prototype ~extern:false name style;
+      generate_prototype ~extern:false ~handle:"handle" name style;
       pr "\n\n";
       pr "%s\n\n" longdesc;
       (match style with
       pr "\n\n";
       pr "%s\n\n" longdesc;
       (match style with
@@ -153,8 +153,9 @@ and generate_pod () =
 (* Generate the protocol (XDR) file. *)
 and generate_xdr () =
   generate_header CStyle LGPLv2;
 (* Generate the protocol (XDR) file. *)
 and generate_xdr () =
   generate_header CStyle LGPLv2;
+
   List.iter (
   List.iter (
-    fun (shortname, style, _, _) ->
+    fun (shortname, style, _, _, _) ->
       let name = "guestfs_" ^ shortname in
       pr "/* %s */\n\n" name;
       (match style with
       let name = "guestfs_" ^ shortname in
       pr "/* %s */\n\n" name;
       (match style with
@@ -169,30 +170,76 @@ and generate_xdr () =
       );
       (match style with
        | (Err, _) -> () 
       );
       (match style with
        | (Err, _) -> () 
-    (* | ... -> pr "struct %s_ret ...\n" name; *)
+          (* | ... -> pr "struct %s_ret ...\n" name; *)
       );
       );
-  ) functions
+  ) functions;
+
+  (* Table of procedure numbers. *)
+  pr "enum guestfs_procedure {\n";
+  List.iter (
+    fun (shortname, _, proc_nr, _, _) ->
+      pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
+  ) functions;
+  pr "  GUESTFS_PROC_dummy\n"; (* so we don't have a "hanging comma" *)
+  pr "};\n";
+  pr "\n";
+
+  (* Having to choose a maximum message size is annoying for several
+   * reasons (it limits what we can do in the API), but it (a) makes
+   * the protocol a lot simpler, and (b) provides a bound on the size
+   * of the daemon which operates in limited memory space.  For large
+   * file transfers you should use FTP.
+   *)
+  pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
+  pr "\n";
+
+  (* Message header, etc. *)
+  pr "\
+const GUESTFS_PROGRAM = 0x2000F5F5;
+const GUESTFS_PROTOCOL_VERSION = 1;
+
+enum guestfs_message_direction {
+  GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
+  GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
+};
+
+enum guestfs_message_status {
+  GUESTFS_STATUS_OK = 0,
+  GUESTFS_STATUS_ERROR = 1
+};
+
+struct guestfs_message_header {
+  unsigned prog;                     /* GUESTFS_PROGRAM */
+  unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
+  guestfs_procedure proc;            /* GUESTFS_PROC_x */
+  guestfs_message_direction direction;
+  unsigned serial;                   /* message serial number */
+  guestfs_message_status status;
+};
+"
 
 (* Generate the guestfs-actions.h file. *)
 and generate_actions_h () =
   generate_header CStyle LGPLv2;
   List.iter (
 
 (* Generate the guestfs-actions.h file. *)
 and generate_actions_h () =
   generate_header CStyle LGPLv2;
   List.iter (
-    fun (shortname, style, _, _) ->
+    fun (shortname, style, _, _, _) ->
       let name = "guestfs_" ^ shortname in
       let name = "guestfs_" ^ shortname in
-      generate_prototype ~single_line:true ~newline:true name style
+      generate_prototype ~single_line:true ~newline:true ~handle:"handle"
+       name style
   ) functions
 
 (* Generate the client-side dispatch stubs. *)
 and generate_client_actions () =
   generate_header CStyle LGPLv2;
   List.iter (
   ) functions
 
 (* Generate the client-side dispatch stubs. *)
 and generate_client_actions () =
   generate_header CStyle LGPLv2;
   List.iter (
-    fun (shortname, style, _, _) ->
+    fun (shortname, style, _, _, _) ->
       let name = "guestfs_" ^ shortname in
 
       (* Generate the return value struct. *)
       pr "struct %s_rv {\n" shortname;
       let name = "guestfs_" ^ shortname in
 
       (* Generate the return value struct. *)
       pr "struct %s_rv {\n" shortname;
-      pr "  int err_code; /* 0 or -1 */\n";
-      pr "  char err_str[256];\n";
+      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";
       (match style with
        | (Err, _) -> ()
     (* | _ -> pr "  struct %s_ret ret;\n" name; *)
       (match style with
        | (Err, _) -> ()
     (* | _ -> pr "  struct %s_ret ret;\n" name; *)
@@ -204,7 +251,8 @@ and generate_client_actions () =
       pr "{\n";
       pr "  struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname;
       pr "\n";
       pr "{\n";
       pr "  struct %s_rv *rv = (struct %s_rv *) data;\n" shortname shortname;
       pr "\n";
-      pr "  /* XXX */ rv.code = 0;\n";
+      pr "  /* XXX */ rv->err_code = 0;\n";
+      pr "  /* XXX rv->serial = ?; */\n";
       pr "  main_loop.main_loop_quit (g);\n";
       pr "}\n\n";
 
       pr "  main_loop.main_loop_quit (g);\n";
       pr "}\n\n";
 
@@ -224,6 +272,7 @@ and generate_client_actions () =
       );
 
       pr "  struct %s_rv rv;\n" shortname;
       );
 
       pr "  struct %s_rv rv;\n" shortname;
+      pr "  int serial;\n";
       pr "\n";
       pr "  if (g->state != READY) {\n";
       pr "    error (g, \"%s called from the wrong state, %%d != READY\",\n"
       pr "\n";
       pr "  if (g->state != READY) {\n";
       pr "    error (g, \"%s called from the wrong state, %%d != READY\",\n"
@@ -233,18 +282,23 @@ and generate_client_actions () =
       pr "  }\n";
 
       (match style with
       pr "  }\n";
 
       (match style with
-       | (_, P0) -> ()
+       | (_, P0) ->
+          pr "  serial = dispatch (g, GUESTFS_PROC_%s, NULL, NULL);\n"
+            (String.uppercase shortname)
        | (_, args) ->
           pr "\n";
           iter_args (
             function
             | String name -> pr "  args.%s = (char *) %s;\n" name name
           ) args;
        | (_, args) ->
           pr "\n";
           iter_args (
             function
             | String name -> pr "  args.%s = (char *) %s;\n" name name
           ) args;
-          pr "  if (dispatch (g, (xdrproc_t) xdr_%s_args, (char *) &args) == -1)\n"
+          pr "  serial = dispatch (g, GUESTFS_PROC_%s,\n"
+            (String.uppercase shortname);
+          pr "                     (xdrproc_t) xdr_%s_args, (char *) &args);\n"
             name;
             name;
-          pr "    return %s;\n" error_code;
-          pr "\n";
       );
       );
+      pr "  if (serial == -1)\n";
+      pr "    return %s;\n" error_code;
+      pr "\n";
 
       pr "  rv.err_code = 42;\n";
       pr "  g->reply_cb_internal = %s_cb;\n" shortname;
 
       pr "  rv.err_code = 42;\n";
       pr "  g->reply_cb_internal = %s_cb;\n" shortname;
@@ -262,6 +316,8 @@ and generate_client_actions () =
       pr "  }\n";
       pr "\n";
 
       pr "  }\n";
       pr "\n";
 
+      pr "  /* XXX check serial number agrees */\n\n";
+
       (match style with
        | (Err, _) -> pr "  return 0;\n"
       );
       (match style with
        | (Err, _) -> pr "  return 0;\n"
       );
@@ -273,7 +329,7 @@ and generate_client_actions () =
 and generate_daemon_actions_h () =
   generate_header CStyle GPLv2;
   List.iter (
 and generate_daemon_actions_h () =
   generate_header CStyle GPLv2;
   List.iter (
-    fun (name, style, _, _) ->
+    fun (name, style, _, _, _) ->
       generate_prototype ~single_line:true ~newline:true ("do_" ^ name) style;
   ) functions
 
       generate_prototype ~single_line:true ~newline:true ("do_" ^ name) style;
   ) functions
 
@@ -284,12 +340,12 @@ and generate_daemon_actions () =
   pr "#include <rpc/types.h>\n";
   pr "#include <rpc/xdr.h>\n";
   pr "#include \"daemon.h\"\n";
   pr "#include <rpc/types.h>\n";
   pr "#include <rpc/xdr.h>\n";
   pr "#include \"daemon.h\"\n";
-  pr "#include \"../src/guest_protocol.h\"\n";
+  pr "#include \"../src/guestfs_protocol.h\"\n";
   pr "#include \"actions.h\"\n";
   pr "\n";
 
   List.iter (
   pr "#include \"actions.h\"\n";
   pr "\n";
 
   List.iter (
-    fun (name, style, _, _) ->
+    fun (name, style, _, _, _) ->
       (* Generate server-side stubs. *)
       pr "static void %s_stub (XDR *xdr_in)\n" name;
       pr "{\n";
       (* Generate server-side stubs. *)
       pr "static void %s_stub (XDR *xdr_in)\n" name;
       pr "{\n";
@@ -335,19 +391,46 @@ and generate_daemon_actions () =
       );
 
       pr "}\n\n";
       );
 
       pr "}\n\n";
-  ) functions
+  ) functions;
+
+  (* Dispatch function. *)
+  pr "void dispatch_incoming_message (XDR *xdr_in)\n";
+  pr "{\n";
+  pr "  switch (proc_nr) {\n";
+
+  List.iter (
+    fun (name, style, _, _, _) ->
+      pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
+      pr "      %s_stub (xdr_in);\n" name;
+      pr "      break;\n"
+  ) functions;
+
+  pr "    default:\n";
+  pr "      reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
+  pr "  }\n";
+  pr "}\n";
 
 (* Generate a C function prototype. *)
 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
     ?(single_line = false) ?(newline = false)
 
 (* Generate a C function prototype. *)
 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
     ?(single_line = false) ?(newline = false)
-    ?(handle = "handle") name style =
+    ?handle name style =
   if extern then pr "extern ";
   if static then pr "static ";
   (match style with
    | (Err, _) -> pr "int "
   );
   if extern then pr "extern ";
   if static then pr "static ";
   (match style with
    | (Err, _) -> pr "int "
   );
-  pr "%s (guestfs_h *%s" name handle;
-  let next () = if single_line then pr ", " else pr ",\n\t\t" in
+  pr "%s (" name;
+  let comma = ref false in
+  (match handle with
+   | None -> ()
+   | Some handle -> pr "guestfs_h *%s" handle; comma := true
+  );
+  let next () =
+    if !comma then (
+      if single_line then pr ", " else pr ",\n\t\t"
+    );
+    comma := true
+  in
   iter_args (
     function
     | String name -> next (); pr "const char *%s" name
   iter_args (
     function
     | String name -> next (); pr "const char *%s" name
index db701ef..12ae602 100644 (file)
  */
 
 struct mount_rv {
  */
 
 struct mount_rv {
-  int err_code; /* 0 or -1 */
-  char err_str[256];
+  int err_code;      /* 0 OK or -1 error */
+  int serial;        /* serial number of reply */
+  char err_str[256]; /* error from daemon */
 };
 
 static void mount_cb (guestfs_h *g, void *data, XDR *xdr)
 {
   struct mount_rv *rv = (struct mount_rv *) data;
 
 };
 
 static void mount_cb (guestfs_h *g, void *data, XDR *xdr)
 {
   struct mount_rv *rv = (struct mount_rv *) data;
 
-  /* XXX */ rv.code = 0;
+  /* XXX */ rv->err_code = 0;
+  /* XXX rv->serial = ?; */
   main_loop.main_loop_quit (g);
 }
 
   main_loop.main_loop_quit (g);
 }
 
@@ -38,6 +40,7 @@ int guestfs_mount (guestfs_h *g,
 {
   struct guestfs_mount_args args;
   struct mount_rv rv;
 {
   struct guestfs_mount_args args;
   struct mount_rv rv;
+  int serial;
 
   if (g->state != READY) {
     error (g, "guestfs_mount called from the wrong state, %d != READY",
 
   if (g->state != READY) {
     error (g, "guestfs_mount called from the wrong state, %d != READY",
@@ -47,7 +50,9 @@ int guestfs_mount (guestfs_h *g,
 
   args.device = (char *) device;
   args.mountpoint = (char *) mountpoint;
 
   args.device = (char *) device;
   args.mountpoint = (char *) mountpoint;
-  if (dispatch (g, (xdrproc_t) xdr_guestfs_mount_args, (char *) &args) == -1)
+  serial = dispatch (g, GUESTFS_PROC_MOUNT,
+                     (xdrproc_t) xdr_guestfs_mount_args, (char *) &args);
+  if (serial == -1)
     return -1;
 
   rv.err_code = 42;
     return -1;
 
   rv.err_code = 42;
@@ -65,31 +70,40 @@ int guestfs_mount (guestfs_h *g,
     return -1;
   }
 
     return -1;
   }
 
+  /* XXX check serial number agrees */
+
   return 0;
 }
 
 struct sync_rv {
   return 0;
 }
 
 struct sync_rv {
-  int err_code; /* 0 or -1 */
-  char err_str[256];
+  int err_code;      /* 0 OK or -1 error */
+  int serial;        /* serial number of reply */
+  char err_str[256]; /* error from daemon */
 };
 
 static void sync_cb (guestfs_h *g, void *data, XDR *xdr)
 {
   struct sync_rv *rv = (struct sync_rv *) data;
 
 };
 
 static void sync_cb (guestfs_h *g, void *data, XDR *xdr)
 {
   struct sync_rv *rv = (struct sync_rv *) data;
 
-  /* XXX */ rv.code = 0;
+  /* XXX */ rv->err_code = 0;
+  /* XXX rv->serial = ?; */
   main_loop.main_loop_quit (g);
 }
 
 int guestfs_sync (guestfs_h *g)
 {
   struct sync_rv rv;
   main_loop.main_loop_quit (g);
 }
 
 int guestfs_sync (guestfs_h *g)
 {
   struct sync_rv rv;
+  int serial;
 
   if (g->state != READY) {
     error (g, "guestfs_sync called from the wrong state, %d != READY",
       g->state);
     return -1;
   }
 
   if (g->state != READY) {
     error (g, "guestfs_sync called from the wrong state, %d != READY",
       g->state);
     return -1;
   }
+  serial = dispatch (g, GUESTFS_PROC_SYNC, NULL, NULL);
+  if (serial == -1)
+    return -1;
+
   rv.err_code = 42;
   g->reply_cb_internal = sync_cb;
   g->reply_cb_internal_data = &rv;
   rv.err_code = 42;
   g->reply_cb_internal = sync_cb;
   g->reply_cb_internal_data = &rv;
@@ -105,19 +119,23 @@ int guestfs_sync (guestfs_h *g)
     return -1;
   }
 
     return -1;
   }
 
+  /* XXX check serial number agrees */
+
   return 0;
 }
 
 struct touch_rv {
   return 0;
 }
 
 struct touch_rv {
-  int err_code; /* 0 or -1 */
-  char err_str[256];
+  int err_code;      /* 0 OK or -1 error */
+  int serial;        /* serial number of reply */
+  char err_str[256]; /* error from daemon */
 };
 
 static void touch_cb (guestfs_h *g, void *data, XDR *xdr)
 {
   struct touch_rv *rv = (struct touch_rv *) data;
 
 };
 
 static void touch_cb (guestfs_h *g, void *data, XDR *xdr)
 {
   struct touch_rv *rv = (struct touch_rv *) data;
 
-  /* XXX */ rv.code = 0;
+  /* XXX */ rv->err_code = 0;
+  /* XXX rv->serial = ?; */
   main_loop.main_loop_quit (g);
 }
 
   main_loop.main_loop_quit (g);
 }
 
@@ -126,6 +144,7 @@ int guestfs_touch (guestfs_h *g,
 {
   struct guestfs_touch_args args;
   struct touch_rv rv;
 {
   struct guestfs_touch_args args;
   struct touch_rv rv;
+  int serial;
 
   if (g->state != READY) {
     error (g, "guestfs_touch called from the wrong state, %d != READY",
 
   if (g->state != READY) {
     error (g, "guestfs_touch called from the wrong state, %d != READY",
@@ -134,7 +153,9 @@ int guestfs_touch (guestfs_h *g,
   }
 
   args.path = (char *) path;
   }
 
   args.path = (char *) path;
-  if (dispatch (g, (xdrproc_t) xdr_guestfs_touch_args, (char *) &args) == -1)
+  serial = dispatch (g, GUESTFS_PROC_TOUCH,
+                     (xdrproc_t) xdr_guestfs_touch_args, (char *) &args);
+  if (serial == -1)
     return -1;
 
   rv.err_code = 42;
     return -1;
 
   rv.err_code = 42;
@@ -152,6 +173,8 @@ int guestfs_touch (guestfs_h *g,
     return -1;
   }
 
     return -1;
   }
 
+  /* XXX check serial number agrees */
+
   return 0;
 }
 
   return 0;
 }
 
index bbcf7a6..309cd15 100644 (file)
@@ -54,6 +54,7 @@
 #endif
 
 #include "guestfs.h"
 #endif
 
 #include "guestfs.h"
+#include "guestfs_protocol.h"
 
 static void error (guestfs_h *g, const char *fs, ...);
 static void perrorf (guestfs_h *g, const char *fs, ...);
 
 static void error (guestfs_h *g, const char *fs, ...);
 static void perrorf (guestfs_h *g, const char *fs, ...);
@@ -64,7 +65,7 @@ static char *safe_strdup (guestfs_h *g, const char *str);
 static void default_error_cb (guestfs_h *g, void *data, const char *msg);
 static void stdout_event (void *data, int watch, int fd, int events);
 static void sock_read_event (void *data, int watch, int fd, int events);
 static void default_error_cb (guestfs_h *g, void *data, const char *msg);
 static void stdout_event (void *data, int watch, int fd, int events);
 static void sock_read_event (void *data, int watch, int fd, int events);
-//static void sock_write_event (void *data, int watch, int fd, int events);
+static void sock_write_event (void *data, int watch, int fd, int events);
 
 static int select_add_handle (guestfs_h *g, int fd, int events, guestfs_handle_event_cb cb, void *data);
 static int select_remove_handle (guestfs_h *g, int watch);
 
 static int select_add_handle (guestfs_h *g, int fd, int events, guestfs_handle_event_cb cb, void *data);
 static int select_remove_handle (guestfs_h *g, int watch);
@@ -138,7 +139,9 @@ struct guestfs_h
   char *msg_in;
   int msg_in_size, msg_in_allocated;
   char *msg_out;
   char *msg_in;
   int msg_in_size, msg_in_allocated;
   char *msg_out;
-  int msg_out_size;
+  int msg_out_size, msg_out_pos;
+
+  int msg_next_serial;
 };
 
 guestfs_h *
 };
 
 guestfs_h *
@@ -587,7 +590,8 @@ guestfs_launch (guestfs_h *g)
     if ((r == -1 && errno == EINPROGRESS) || r == 0)
       goto connected;
 
     if ((r == -1 && errno == EINPROGRESS) || r == 0)
       goto connected;
 
-    perrorf (g, "connect");
+    if (errno != ENOENT)
+      perrorf (g, "connect");
     tries--;
   }
 
     tries--;
   }
 
@@ -603,6 +607,7 @@ guestfs_launch (guestfs_h *g)
   free (g->msg_out);
   g->msg_out = NULL;
   g->msg_out_size = 0;
   free (g->msg_out);
   g->msg_out = NULL;
   g->msg_out_size = 0;
+  g->msg_out_pos = 0;
 
   g->stdout_watch =
     main_loop.add_handle (g, g->fd[1],
 
   g->stdout_watch =
     main_loop.add_handle (g, g->fd[1],
@@ -615,9 +620,7 @@ guestfs_launch (guestfs_h *g)
 
   g->sock_watch =
     main_loop.add_handle (g, g->sock,
 
   g->sock_watch =
     main_loop.add_handle (g, g->sock,
-                         GUESTFS_HANDLE_READABLE |
-                         GUESTFS_HANDLE_HANGUP |
-                         GUESTFS_HANDLE_ERROR,
+                         GUESTFS_HANDLE_READABLE,
                          sock_read_event, g);
   if (g->sock_watch == -1) {
     error (g, "could not watch daemon communications socket");
                          sock_read_event, g);
   if (g->sock_watch == -1) {
     error (g, "could not watch daemon communications socket");
@@ -793,7 +796,7 @@ sock_read_event (void *data, int watch, int fd, int events)
 
   if (g->verbose)
     fprintf (stderr,
 
   if (g->verbose)
     fprintf (stderr,
-            "sock_event: %p g->state = %d, fd = %d, events = 0x%x\n",
+            "sock_read_event: %p g->state = %d, fd = %d, events = 0x%x\n",
             g, g->state, fd, events);
 
   if (g->sock != fd) {
             g, g->state, fd, events);
 
   if (g->sock != fd) {
@@ -852,6 +855,13 @@ sock_read_event (void *data, int watch, int fd, int events)
     goto cleanup;
   }
 
     goto cleanup;
   }
 
+  /* If this happens, it's pretty bad and we've probably lost synchronization.*/
+  if (len > GUESTFS_MESSAGE_MAX) {
+    error (g, "message length (%u) > maximum possible size (%d)",
+          len, GUESTFS_MESSAGE_MAX);
+    goto cleanup;
+  }
+
   if (g->msg_in_size < len) return; /* Need more of this message. */
 
   /* This should not happen, and if it does it probably means we've
   if (g->msg_in_size < len) return; /* Need more of this message. */
 
   /* This should not happen, and if it does it probably means we've
@@ -888,6 +898,160 @@ sock_read_event (void *data, int watch, int fd, int events)
   xdr_destroy (&xdr);
 }
 
   xdr_destroy (&xdr);
 }
 
+/* The function is called whenever we can write something on the
+ * guestfsd (daemon inside the guest) communication socket.
+ */
+static void
+sock_write_event (void *data, int watch, int fd, int events)
+{
+  guestfs_h *g = (guestfs_h *) data;
+  int n;
+
+  if (g->verbose)
+    fprintf (stderr,
+            "sock_write_event: %p g->state = %d, fd = %d, events = 0x%x\n",
+            g, g->state, fd, events);
+
+  if (g->sock != fd) {
+    error (g, "sock_write_event: internal error: %d != %d", g->sock, fd);
+    return;
+  }
+
+  if (g->state != BUSY) {
+    error (g, "sock_write_event: state %d != BUSY", g->state);
+    return;
+  }
+
+  if (g->verbose)
+    fprintf (stderr, "sock_write_event: writing %d bytes ...\n",
+            g->msg_out_size - g->msg_out_pos);
+
+  n = write (g->sock, g->msg_out + g->msg_out_pos,
+            g->msg_out_size - g->msg_out_pos);
+  if (n == -1) {
+    if (errno != EAGAIN)
+      perrorf (g, "write");
+    return;
+  }
+
+  if (g->verbose)
+    fprintf (stderr, "sock_write_event: wrote %d bytes\n", n);
+
+  g->msg_out_pos += n;
+
+  /* More to write? */
+  if (g->msg_out_pos < g->msg_out_size)
+    return;
+
+  if (g->verbose)
+    fprintf (stderr, "sock_write_event: done writing, switching back to reading events\n", n);
+
+  free (g->msg_out);
+  g->msg_out_pos = g->msg_out_size = 0;
+
+  if (main_loop.remove_handle (g, g->sock_watch) == -1) {
+    error (g, "remove_handle failed in sock_write_event");
+    return;
+  }
+  g->sock_watch =
+    main_loop.add_handle (g, g->sock,
+                         GUESTFS_HANDLE_READABLE,
+                         sock_read_event, g);
+  if (g->sock_watch == -1) {
+    error (g, "add_handle failed in sock_write_event");
+    return;
+  }
+}
+
+/* Dispatch a call to the remote daemon.  This function just queues
+ * the call in msg_out, to be sent when we next enter the main loop.
+ * Returns -1 for error, or the message serial number.
+ */
+static int
+dispatch (guestfs_h *g, int proc_nr, xdrproc_t xdrp, char *args)
+{
+  char buffer[GUESTFS_MESSAGE_MAX];
+  struct guestfs_message_header hdr;
+  XDR xdr;
+  unsigned len;
+  int serial = g->msg_next_serial++;
+
+  if (g->state != READY) {
+    error (g, "dispatch: state %d != READY", g->state);
+    return -1;
+  }
+
+  /* Serialize the header. */
+  hdr.prog = GUESTFS_PROGRAM;
+  hdr.vers = GUESTFS_PROTOCOL_VERSION;
+  hdr.proc = proc_nr;
+  hdr.direction = GUESTFS_DIRECTION_CALL;
+  hdr.serial = serial;
+  hdr.status = GUESTFS_STATUS_OK;
+
+  xdrmem_create (&xdr, buffer, sizeof buffer, XDR_ENCODE);
+  if (!xdr_guestfs_message_header (&xdr, &hdr)) {
+    error (g, "xdr_guestfs_message_header failed");
+    return -1;
+  }
+
+  /* Serialize the args.  If any, because some message types
+   * have no parameters.
+   */
+  if (xdrp) {
+    if (!(*xdrp) (&xdr, args)) {
+      error (g, "dispatch failed to marshal args");
+      return -1;
+    }
+  }
+
+  len = xdr_getpos (&xdr);
+  xdr_destroy (&xdr);
+
+  /* Allocate the outgoing message buffer. */
+  g->msg_out = safe_malloc (g, len + 4);
+
+  g->msg_out_size = len + 4;
+  g->msg_out_pos = 0;
+  g->state = BUSY;
+
+  xdrmem_create (&xdr, g->msg_out, 4, XDR_ENCODE);
+  if (!xdr_uint32_t (&xdr, &len)) {
+    error (g, "xdr_uint32_t failed in dispatch");
+    goto cleanup1;
+  }
+
+  memcpy (g->msg_out + 4, buffer, len);
+
+  /* Change the handle to sock_write_event. */
+  if (main_loop.remove_handle (g, g->sock_watch) == -1) {
+    error (g, "remove_handle failed in dispatch");
+    goto cleanup1;
+  }
+  g->sock_watch =
+    main_loop.add_handle (g, g->sock,
+                         GUESTFS_HANDLE_WRITABLE,
+                         sock_write_event, g);
+  if (g->sock_watch == -1) {
+    error (g, "add_handle failed in dispatch");
+    goto cleanup1;
+  }
+
+  return serial;
+
+ cleanup1:
+  free (g->msg_out);
+  g->msg_out = NULL;
+  g->msg_out_size = 0;
+  g->state = READY;
+  return -1;
+}
+
+/* The high-level actions are autogenerated by generator.ml.  Include
+ * them here.
+ */
+#include "guestfs-actions.c"
+
 /* This is the default main loop implementation, using select(2). */
 
 struct handle_cb_data {
 /* This is the default main loop implementation, using select(2). */
 
 struct handle_cb_data {
diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c
new file mode 100644 (file)
index 0000000..8a59085
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "guestfs_protocol.h"
+
+bool_t
+xdr_guestfs_mount_args (XDR *xdrs, guestfs_mount_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->device, ~0))
+                return FALSE;
+        if (!xdr_string (xdrs, &objp->mountpoint, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_touch_args (XDR *xdrs, guestfs_touch_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->path, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_enum (xdrs, (enum_t *) objp))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_message_direction (XDR *xdrs, guestfs_message_direction *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_enum (xdrs, (enum_t *) objp))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_message_status (XDR *xdrs, guestfs_message_status *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_enum (xdrs, (enum_t *) objp))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_message_header (XDR *xdrs, guestfs_message_header *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_u_int (xdrs, &objp->prog))
+                return FALSE;
+        if (!xdr_u_int (xdrs, &objp->vers))
+                return FALSE;
+        if (!xdr_guestfs_procedure (xdrs, &objp->proc))
+                return FALSE;
+        if (!xdr_guestfs_message_direction (xdrs, &objp->direction))
+                return FALSE;
+        if (!xdr_u_int (xdrs, &objp->serial))
+                return FALSE;
+        if (!xdr_guestfs_message_status (xdrs, &objp->status))
+                return FALSE;
+       return TRUE;
+}
diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h
new file mode 100644 (file)
index 0000000..562d72f
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _GUESTFS_PROTOCOL_H_RPCGEN
+#define _GUESTFS_PROTOCOL_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct guestfs_mount_args {
+       char *device;
+       char *mountpoint;
+};
+typedef struct guestfs_mount_args guestfs_mount_args;
+
+struct guestfs_touch_args {
+       char *path;
+};
+typedef struct guestfs_touch_args guestfs_touch_args;
+
+enum guestfs_procedure {
+       GUESTFS_PROC_MOUNT = 1,
+       GUESTFS_PROC_SYNC = 2,
+       GUESTFS_PROC_TOUCH = 3,
+       GUESTFS_PROC_dummy = 3 + 1,
+};
+typedef enum guestfs_procedure guestfs_procedure;
+#define GUESTFS_MESSAGE_MAX 4194304
+#define GUESTFS_PROGRAM 0x2000F5F5
+#define GUESTFS_PROTOCOL_VERSION 1
+
+enum guestfs_message_direction {
+       GUESTFS_DIRECTION_CALL = 0,
+       GUESTFS_DIRECTION_REPLY = 1,
+};
+typedef enum guestfs_message_direction guestfs_message_direction;
+
+enum guestfs_message_status {
+       GUESTFS_STATUS_OK = 0,
+       GUESTFS_STATUS_ERROR = 1,
+};
+typedef enum guestfs_message_status guestfs_message_status;
+
+struct guestfs_message_header {
+       u_int prog;
+       u_int vers;
+       guestfs_procedure proc;
+       guestfs_message_direction direction;
+       u_int serial;
+       guestfs_message_status status;
+};
+typedef struct guestfs_message_header guestfs_message_header;
+
+/* the xdr functions */
+
+#if defined(__STDC__) || defined(__cplusplus)
+extern  bool_t xdr_guestfs_mount_args (XDR *, guestfs_mount_args*);
+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_header (XDR *, guestfs_message_header*);
+
+#else /* K&R C */
+extern bool_t xdr_guestfs_mount_args ();
+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_header ();
+
+#endif /* K&R C */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_GUESTFS_PROTOCOL_H_RPCGEN */
index 6569d27..1641b3d 100644 (file)
@@ -34,3 +34,33 @@ struct guestfs_touch_args {
   string path<>;
 };
 
   string path<>;
 };
 
+enum guestfs_procedure {
+  GUESTFS_PROC_MOUNT = 1,
+  GUESTFS_PROC_SYNC = 2,
+  GUESTFS_PROC_TOUCH = 3,
+  GUESTFS_PROC_dummy
+};
+
+const GUESTFS_MESSAGE_MAX = 4194304;
+
+const GUESTFS_PROGRAM = 0x2000F5F5;
+const GUESTFS_PROTOCOL_VERSION = 1;
+
+enum guestfs_message_direction {
+  GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
+  GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
+};
+
+enum guestfs_message_status {
+  GUESTFS_STATUS_OK = 0,
+  GUESTFS_STATUS_ERROR = 1
+};
+
+struct guestfs_message_header {
+  unsigned prog;                     /* GUESTFS_PROGRAM */
+  unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
+  guestfs_procedure proc;            /* GUESTFS_PROC_x */
+  guestfs_message_direction direction;
+  unsigned serial;                   /* message serial number */
+  guestfs_message_status status;
+};