depcomp
emptydisk
examples/df
+examples/hello
guestfs.3
initramfs
initramfs.timestamp
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
* 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);
--- /dev/null
+/* 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 */
#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 */
- sleep (1000000);
+
+
+
+ main_loop (sock);
exit (0);
}
-static void
+void
xwrite (int sock, const void *buf, size_t len)
{
int r;
{
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;
+}
--- /dev/null
+/* 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)
+{
+}
#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)
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);
+ }
+}
--- /dev/null
+/* 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;
+}
# libguestfs examples
-noinst_PROGRAMS = df
+noinst_PROGRAMS = df hello
df_SOURCES = df.c
-df_CFLAGS = -I$(top_builddir)/src
+df_CFLAGS = -I$(top_builddir)/src -Wall
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
--- /dev/null
+/* 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;
+}
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
=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.
}
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
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
| 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
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
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
(* 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 " ";
- 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
(* Generate the protocol (XDR) file. *)
and generate_xdr () =
generate_header CStyle LGPLv2;
+
List.iter (
- fun (shortname, style, _, _) ->
+ fun (shortname, style, _, _, _) ->
let name = "guestfs_" ^ shortname in
pr "/* %s */\n\n" name;
(match style with
);
(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 (
- fun (shortname, style, _, _) ->
+ fun (shortname, style, _, _, _) ->
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 (
- fun (shortname, style, _, _) ->
+ fun (shortname, style, _, _, _) ->
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; *)
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 " 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";
(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;
- 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;
- 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 " }\n";
pr "\n";
+ pr " /* XXX check serial number agrees */\n\n";
+
(match style with
| (Err, _) -> pr " return 0;\n"
);
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
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 (
- fun (name, style, _, _) ->
+ fun (name, style, _, _, _) ->
(* Generate server-side stubs. *)
pr "static void %s_stub (XDR *xdr_in)\n" name;
pr "{\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)
- ?(handle = "handle") name style =
+ ?handle name style =
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
*/
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;
- /* XXX */ rv.code = 0;
+ /* XXX */ rv->err_code = 0;
+ /* XXX rv->serial = ?; */
main_loop.main_loop_quit (g);
}
{
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",
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;
}
+ /* XXX check serial number agrees */
+
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;
- /* 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;
+ int serial;
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;
return -1;
}
+ /* XXX check serial number agrees */
+
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;
- /* XXX */ rv.code = 0;
+ /* XXX */ rv->err_code = 0;
+ /* XXX rv->serial = ?; */
main_loop.main_loop_quit (g);
}
{
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",
}
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;
}
+ /* XXX check serial number agrees */
+
return 0;
}
#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 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);
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 *
if ((r == -1 && errno == EINPROGRESS) || r == 0)
goto connected;
- perrorf (g, "connect");
+ if (errno != ENOENT)
+ perrorf (g, "connect");
tries--;
}
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->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");
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) {
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
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 {
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
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;
+};