Daemon and library are mostly talking to each other now.

This commit is contained in:
Richard Jones
2009-04-03 17:24:35 +01:00
parent cd2fd58da3
commit 40ca9a5782
18 changed files with 760 additions and 60 deletions

1
.gitignore vendored
View File

@@ -22,6 +22,7 @@ daemon/missing
depcomp
emptydisk
examples/df
examples/hello
guestfs.3
initramfs
initramfs.timestamp

View File

@@ -18,6 +18,14 @@
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
guestfsd_CFLAGS = -Wall

View File

@@ -19,6 +19,6 @@
* 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);

41
daemon/daemon.h Normal file
View File

@@ -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 */

View File

@@ -27,7 +27,10 @@
#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 */
@@ -177,12 +180,15 @@ main (int argc, char *argv[])
sleep (1000000);
main_loop (sock);
exit (0);
}
static void
void
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");
}
/* 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;
}

59
daemon/proto.c Normal file
View File

@@ -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)
{
}

View File

@@ -22,7 +22,7 @@
#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)
@@ -79,3 +79,19 @@ static void touch_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);
}
}

32
daemon/sync.c Normal file
View File

@@ -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;
}

View File

@@ -1,7 +1,11 @@
# 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

33
examples/hello.c Normal file
View File

@@ -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;
}

View 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
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
@@ -366,6 +365,8 @@ this function with C<cb> set to C<NULL>.
=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.
@@ -391,8 +392,7 @@ For example:
}
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

View File

@@ -17,5 +17,27 @@
lib_LTLIBRARIES = libguestfs.la
libguestfs_la_SOURCES = guestfs.c guestfs.h
libguestfs_la_CFLAGS = -Wall -Werror
# 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

View File

@@ -41,7 +41,7 @@ and argt =
| 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
@@ -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.");
("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
@@ -64,7 +64,7 @@ underlying disk image.
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
@@ -137,11 +137,11 @@ let rec generate_header comment license =
(* 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
@@ -153,8 +153,9 @@ and generate_pod () =
(* 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
@@ -169,30 +170,76 @@ and generate_xdr () =
);
(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; *)
@@ -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 " /* 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";
@@ -224,6 +272,7 @@ and generate_client_actions () =
);
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"
@@ -233,18 +282,23 @@ and generate_client_actions () =
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;
@@ -262,6 +316,8 @@ and generate_client_actions () =
pr " }\n";
pr "\n";
pr " /* XXX check serial number agrees */\n\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 (
fun (name, style, _, _) ->
fun (name, style, _, _, _) ->
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 \"../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";
@@ -335,19 +391,46 @@ and generate_daemon_actions () =
);
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

View File

@@ -20,15 +20,17 @@
*/
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);
}
@@ -38,6 +40,7 @@ int guestfs_mount (guestfs_h *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",
@@ -47,7 +50,9 @@ int guestfs_mount (guestfs_h *g,
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;
@@ -65,31 +70,40 @@ int guestfs_mount (guestfs_h *g,
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;
@@ -105,19 +119,23 @@ int guestfs_sync (guestfs_h *g)
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);
}
@@ -126,6 +144,7 @@ int guestfs_touch (guestfs_h *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",
@@ -134,7 +153,9 @@ int guestfs_touch (guestfs_h *g,
}
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;
@@ -152,6 +173,8 @@ int guestfs_touch (guestfs_h *g,
return -1;
}
/* XXX check serial number agrees */
return 0;
}

View File

@@ -54,6 +54,7 @@
#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, ...);
@@ -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 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);
@@ -138,7 +139,9 @@ struct guestfs_h
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 *
@@ -587,7 +590,8 @@ guestfs_launch (guestfs_h *g)
if ((r == -1 && errno == EINPROGRESS) || r == 0)
goto connected;
perrorf (g, "connect");
if (errno != ENOENT)
perrorf (g, "connect");
tries--;
}
@@ -603,6 +607,7 @@ guestfs_launch (guestfs_h *g)
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],
@@ -615,9 +620,7 @@ guestfs_launch (guestfs_h *g)
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");
@@ -793,7 +796,7 @@ sock_read_event (void *data, int watch, int fd, int events)
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) {
@@ -852,6 +855,13 @@ sock_read_event (void *data, int watch, int fd, int events)
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
@@ -888,6 +898,160 @@ sock_read_event (void *data, int watch, int fd, int events)
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 {

78
src/guestfs_protocol.c Normal file
View File

@@ -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;
}

85
src/guestfs_protocol.h Normal file
View File

@@ -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 */

View File

@@ -34,3 +34,33 @@ struct guestfs_touch_args {
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;
};