mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
Daemon and library are mostly talking to each other now.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,6 +22,7 @@ daemon/missing
|
||||
depcomp
|
||||
emptydisk
|
||||
examples/df
|
||||
examples/hello
|
||||
guestfs.3
|
||||
initramfs
|
||||
initramfs.timestamp
|
||||
|
||||
@@ -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
|
||||
@@ -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
41
daemon/daemon.h
Normal 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 */
|
||||
@@ -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
59
daemon/proto.c
Normal 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)
|
||||
{
|
||||
}
|
||||
@@ -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
32
daemon/sync.c
Normal 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;
|
||||
}
|
||||
@@ -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
33
examples/hello.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
133
src/generator.ml
133
src/generator.ml
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
178
src/guestfs.c
178
src/guestfs.c
@@ -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
78
src/guestfs_protocol.c
Normal 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
85
src/guestfs_protocol.h
Normal 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 */
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user