summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard Jones <rjones@redhat.com>2009-04-14 13:51:12 +0100
committerRichard Jones <rjones@redhat.com>2009-04-14 13:51:12 +0100
commit5365ebd501850ea10d9a5b28fc6480ea34dbe16d (patch)
tree3c3bedf7581ea8485db6f039f2633ee07361b031 /src
parent161018ed1e90c796e6e099859979da02d5f3e410 (diff)
downloadlibguestfs-5365ebd501850ea10d9a5b28fc6480ea34dbe16d.tar.gz
libguestfs-5365ebd501850ea10d9a5b28fc6480ea34dbe16d.tar.xz
libguestfs-5365ebd501850ea10d9a5b28fc6480ea34dbe16d.zip
Add 'command' and 'command-lines'. Fix args freeing in Perl bindings.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/generator.ml72
-rw-r--r--src/guestfs-actions.c154
-rw-r--r--src/guestfs-actions.h2
-rw-r--r--src/guestfs_protocol.c43
-rw-r--r--src/guestfs_protocol.h41
-rw-r--r--src/guestfs_protocol.x18
6 files changed, 308 insertions, 22 deletions
diff --git a/src/generator.ml b/src/generator.ml
index c9da57e9..1017ad1c 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -969,6 +969,38 @@ The exact command which runs is C<file -bsL path>. Note in
particular that the filename is not prepended to the output
(the C<-b> option).");
+ ("command", (RString "output", [StringList "arguments"]), 50, [],
+ [], (* XXX how to test? *)
+ "run a command from the guest filesystem",
+ "\
+This calls runs a command from the guest filesystem. The
+filesystem must be mounted, and must contain a compatible
+operating system (ie. something Linux, with the same
+or compatible processor architecture).
+
+The single parameter is an argv-style list of arguments.
+The first element is the name of the program to run.
+Subsequent elements are parameters. The list must be
+non-empty (ie. must contain a program name).
+
+The C<$PATH> environment variable will contain at least
+C</usr/bin> and C</bin>. If you require a program from
+another location, you should provide the full path in the
+first parameter.
+
+Shared libraries and data files required by the program
+must be available on filesystems which are mounted in the
+correct places. It is the caller's responsibility to ensure
+all filesystems that are needed are mounted at the right
+locations.");
+
+ ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [],
+ [], (* XXX how to test? *)
+ "run a command, returning lines",
+ "\
+This is the same as C<guestfs_command>, but splits the
+result into a list of lines.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
@@ -1163,7 +1195,9 @@ let check_functions () =
failwithf "%s param/ret %s should not contain '-' or '_'"
name n;
if n = "value" then
- failwithf "%s has a param/ret called 'value', which causes conflicts in the OCaml bindings, use something like 'val' or a more descriptive name" n
+ failwithf "%s has a param/ret called 'value', which causes conflicts in the OCaml bindings, use something like 'val' or a more descriptive name" n;
+ if n = "argv" || n = "args" then
+ failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" n
in
(match fst style with
@@ -3351,20 +3385,22 @@ DESTROY (g)
| OptString _
| Bool _
| Int _ -> ()
- | StringList n -> pr " free (%s);\n" n
+ | StringList n -> pr " free (%s);\n" n
) (snd style)
in
(* Code. *)
(match fst style with
| RErr ->
+ pr "PREINIT:\n";
+ pr " int r;\n";
pr " PPCODE:\n";
- pr " if (guestfs_%s " name;
+ pr " r = guestfs_%s " name;
generate_call_args ~handle:"g" style;
- pr " == -1) {\n";
+ pr ";\n";
do_cleanups ();
+ pr " if (r == -1)\n";
pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
- pr " }\n"
| RInt n
| RBool n ->
pr "PREINIT:\n";
@@ -3373,10 +3409,9 @@ DESTROY (g)
pr " %s = guestfs_%s " n name;
generate_call_args ~handle:"g" style;
pr ";\n";
- pr " if (%s == -1) {\n" n;
do_cleanups ();
+ pr " if (%s == -1)\n" n;
pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
- pr " }\n";
pr " RETVAL = newSViv (%s);\n" n;
pr " OUTPUT:\n";
pr " RETVAL\n"
@@ -3387,10 +3422,9 @@ DESTROY (g)
pr " %s = guestfs_%s " n name;
generate_call_args ~handle:"g" style;
pr ";\n";
- pr " if (%s == NULL) {\n" n;
do_cleanups ();
+ pr " if (%s == NULL)\n" n;
pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
- pr " }\n";
pr " RETVAL = newSVpv (%s, 0);\n" n;
pr " OUTPUT:\n";
pr " RETVAL\n"
@@ -3401,10 +3435,9 @@ DESTROY (g)
pr " %s = guestfs_%s " n name;
generate_call_args ~handle:"g" style;
pr ";\n";
- pr " if (%s == NULL) {\n" n;
do_cleanups ();
+ pr " if (%s == NULL)\n" n;
pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
- pr " }\n";
pr " RETVAL = newSVpv (%s, 0);\n" n;
pr " free (%s);\n" n;
pr " OUTPUT:\n";
@@ -3417,10 +3450,9 @@ DESTROY (g)
pr " %s = guestfs_%s " n name;
generate_call_args ~handle:"g" style;
pr ";\n";
- pr " if (%s == NULL) {\n" n;
do_cleanups ();
+ pr " if (%s == NULL)\n" n;
pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
- pr " }\n";
pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
pr " EXTEND (SP, n);\n";
pr " for (i = 0; i < n; ++i) {\n";
@@ -3435,28 +3467,25 @@ DESTROY (g)
pr " r = guestfs_%s " name;
generate_call_args ~handle:"g" style;
pr ";\n";
- pr " if (r == NULL) {\n";
do_cleanups ();
+ pr " if (r == NULL)\n";
pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
- pr " }\n";
pr " EXTEND (SP, 2);\n";
pr " PUSHs (sv_2mortal (newSViv (r->i)));\n";
pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
pr " guestfs_free_int_bool (r);\n";
| RPVList n ->
- generate_perl_lvm_code "pv" pv_cols name style n;
+ generate_perl_lvm_code "pv" pv_cols name style n do_cleanups;
| RVGList n ->
- generate_perl_lvm_code "vg" vg_cols name style n;
+ generate_perl_lvm_code "vg" vg_cols name style n do_cleanups;
| RLVList n ->
- generate_perl_lvm_code "lv" lv_cols name style n;
+ generate_perl_lvm_code "lv" lv_cols name style n do_cleanups;
);
- do_cleanups ();
-
pr "\n"
) all_functions
-and generate_perl_lvm_code typ cols name style n =
+and generate_perl_lvm_code typ cols name style n do_cleanups =
pr "PREINIT:\n";
pr " struct guestfs_lvm_%s_list *%s;\n" typ n;
pr " int i;\n";
@@ -3465,6 +3494,7 @@ and generate_perl_lvm_code typ cols name style n =
pr " %s = guestfs_%s " n name;
generate_call_args ~handle:"g" style;
pr ";\n";
+ do_cleanups ();
pr " if (%s == NULL)\n" n;
pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
pr " EXTEND (SP, %s->len);\n" n;
diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c
index 4b6b9822..c6f574a7 100644
--- a/src/guestfs-actions.c
+++ b/src/guestfs-actions.c
@@ -3545,3 +3545,157 @@ char *guestfs_file (guestfs_h *g,
return rv.ret.description; /* caller will free */
}
+struct command_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+ struct guestfs_command_ret ret;
+};
+
+static void command_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct command_rv *rv = (struct command_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_command: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_command: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_command_ret (xdr, &rv->ret)) {
+ error (g, "guestfs_command: failed to parse reply");
+ return;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+char *guestfs_command (guestfs_h *g,
+ char * const* const arguments)
+{
+ struct guestfs_command_args args;
+ struct command_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_command called from the wrong state, %d != READY",
+ g->state);
+ return NULL;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.arguments.arguments_val = (char **) arguments;
+ for (args.arguments.arguments_len = 0; arguments[args.arguments.arguments_len]; args.arguments.arguments_len++) ;
+ serial = dispatch (g, GUESTFS_PROC_COMMAND,
+ (xdrproc_t) xdr_guestfs_command_args, (char *) &args);
+ if (serial == -1)
+ return NULL;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = command_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_command failed, see earlier error messages");
+ return NULL;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_COMMAND, serial) == -1)
+ return NULL;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return NULL;
+ }
+
+ return rv.ret.output; /* caller will free */
+}
+
+struct command_lines_rv {
+ int cb_done; /* flag to indicate callback was called */
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+ struct guestfs_command_lines_ret ret;
+};
+
+static void command_lines_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ struct command_lines_rv *rv = (struct command_lines_rv *) data;
+
+ if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+ error (g, "guestfs_command_lines: failed to parse reply header");
+ return;
+ }
+ if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+ error (g, "guestfs_command_lines: failed to parse reply error");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_command_lines_ret (xdr, &rv->ret)) {
+ error (g, "guestfs_command_lines: failed to parse reply");
+ return;
+ }
+ done:
+ rv->cb_done = 1;
+ main_loop.main_loop_quit (g);
+}
+
+char **guestfs_command_lines (guestfs_h *g,
+ char * const* const arguments)
+{
+ struct guestfs_command_lines_args args;
+ struct command_lines_rv rv;
+ int serial;
+
+ if (g->state != READY) {
+ error (g, "guestfs_command_lines called from the wrong state, %d != READY",
+ g->state);
+ return NULL;
+ }
+
+ memset (&rv, 0, sizeof rv);
+
+ args.arguments.arguments_val = (char **) arguments;
+ for (args.arguments.arguments_len = 0; arguments[args.arguments.arguments_len]; args.arguments.arguments_len++) ;
+ serial = dispatch (g, GUESTFS_PROC_COMMAND_LINES,
+ (xdrproc_t) xdr_guestfs_command_lines_args, (char *) &args);
+ if (serial == -1)
+ return NULL;
+
+ rv.cb_done = 0;
+ g->reply_cb_internal = command_lines_cb;
+ g->reply_cb_internal_data = &rv;
+ main_loop.main_loop_run (g);
+ g->reply_cb_internal = NULL;
+ g->reply_cb_internal_data = NULL;
+ if (!rv.cb_done) {
+ error (g, "guestfs_command_lines failed, see earlier error messages");
+ return NULL;
+ }
+
+ if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_COMMAND_LINES, serial) == -1)
+ return NULL;
+
+ if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", rv.err.error);
+ return NULL;
+ }
+
+ /* caller will free this, but we need to add a NULL entry */
+ rv.ret.lines.lines_val = safe_realloc (g, rv.ret.lines.lines_val,
+ sizeof (char *) * (rv.ret.lines.lines_len + 1));
+ rv.ret.lines.lines_val[rv.ret.lines.lines_len] = NULL;
+ return rv.ret.lines.lines_val;
+}
+
diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h
index 73739647..06efabf0 100644
--- a/src/guestfs-actions.h
+++ b/src/guestfs-actions.h
@@ -80,3 +80,5 @@ extern char **guestfs_mounts (guestfs_h *handle);
extern int guestfs_umount_all (guestfs_h *handle);
extern int guestfs_lvm_remove_all (guestfs_h *handle);
extern char *guestfs_file (guestfs_h *handle, const char *path);
+extern char *guestfs_command (guestfs_h *handle, char * const* const arguments);
+extern char **guestfs_command_lines (guestfs_h *handle, char * const* const arguments);
diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c
index 82b227c9..0849f7ae 100644
--- a/src/guestfs_protocol.c
+++ b/src/guestfs_protocol.c
@@ -847,6 +847,49 @@ xdr_guestfs_file_ret (XDR *xdrs, guestfs_file_ret *objp)
}
bool_t
+xdr_guestfs_command_args (XDR *xdrs, guestfs_command_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_array (xdrs, (char **)&objp->arguments.arguments_val, (u_int *) &objp->arguments.arguments_len, ~0,
+ sizeof (str), (xdrproc_t) xdr_str))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_command_ret (XDR *xdrs, guestfs_command_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->output, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_command_lines_args (XDR *xdrs, guestfs_command_lines_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_array (xdrs, (char **)&objp->arguments.arguments_val, (u_int *) &objp->arguments.arguments_len, ~0,
+ sizeof (str), (xdrproc_t) xdr_str))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_command_lines_ret (XDR *xdrs, guestfs_command_lines_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_array (xdrs, (char **)&objp->lines.lines_val, (u_int *) &objp->lines.lines_len, ~0,
+ sizeof (str), (xdrproc_t) xdr_str))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
{
register int32_t *buf;
diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h
index 339f0699..4b314682 100644
--- a/src/guestfs_protocol.h
+++ b/src/guestfs_protocol.h
@@ -436,6 +436,35 @@ struct guestfs_file_ret {
};
typedef struct guestfs_file_ret guestfs_file_ret;
+struct guestfs_command_args {
+ struct {
+ u_int arguments_len;
+ str *arguments_val;
+ } arguments;
+};
+typedef struct guestfs_command_args guestfs_command_args;
+
+struct guestfs_command_ret {
+ char *output;
+};
+typedef struct guestfs_command_ret guestfs_command_ret;
+
+struct guestfs_command_lines_args {
+ struct {
+ u_int arguments_len;
+ str *arguments_val;
+ } arguments;
+};
+typedef struct guestfs_command_lines_args guestfs_command_lines_args;
+
+struct guestfs_command_lines_ret {
+ struct {
+ u_int lines_len;
+ str *lines_val;
+ } lines;
+};
+typedef struct guestfs_command_lines_ret guestfs_command_lines_ret;
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
@@ -486,7 +515,9 @@ enum guestfs_procedure {
GUESTFS_PROC_UMOUNT_ALL = 47,
GUESTFS_PROC_LVM_REMOVE_ALL = 48,
GUESTFS_PROC_FILE = 49,
- GUESTFS_PROC_dummy = 49 + 1,
+ GUESTFS_PROC_COMMAND = 50,
+ GUESTFS_PROC_COMMAND_LINES = 51,
+ GUESTFS_PROC_dummy = 51 + 1,
};
typedef enum guestfs_procedure guestfs_procedure;
#define GUESTFS_MESSAGE_MAX 4194304
@@ -588,6 +619,10 @@ extern bool_t xdr_guestfs_umount_args (XDR *, guestfs_umount_args*);
extern bool_t xdr_guestfs_mounts_ret (XDR *, guestfs_mounts_ret*);
extern bool_t xdr_guestfs_file_args (XDR *, guestfs_file_args*);
extern bool_t xdr_guestfs_file_ret (XDR *, guestfs_file_ret*);
+extern bool_t xdr_guestfs_command_args (XDR *, guestfs_command_args*);
+extern bool_t xdr_guestfs_command_ret (XDR *, guestfs_command_ret*);
+extern bool_t xdr_guestfs_command_lines_args (XDR *, guestfs_command_lines_args*);
+extern bool_t xdr_guestfs_command_lines_ret (XDR *, guestfs_command_lines_ret*);
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*);
@@ -659,6 +694,10 @@ extern bool_t xdr_guestfs_umount_args ();
extern bool_t xdr_guestfs_mounts_ret ();
extern bool_t xdr_guestfs_file_args ();
extern bool_t xdr_guestfs_file_ret ();
+extern bool_t xdr_guestfs_command_args ();
+extern bool_t xdr_guestfs_command_ret ();
+extern bool_t xdr_guestfs_command_lines_args ();
+extern bool_t xdr_guestfs_command_lines_ret ();
extern bool_t xdr_guestfs_procedure ();
extern bool_t xdr_guestfs_message_direction ();
extern bool_t xdr_guestfs_message_status ();
diff --git a/src/guestfs_protocol.x b/src/guestfs_protocol.x
index d133bb56..68362d64 100644
--- a/src/guestfs_protocol.x
+++ b/src/guestfs_protocol.x
@@ -336,6 +336,22 @@ struct guestfs_file_ret {
string description<>;
};
+struct guestfs_command_args {
+ str arguments<>;
+};
+
+struct guestfs_command_ret {
+ string output<>;
+};
+
+struct guestfs_command_lines_args {
+ str arguments<>;
+};
+
+struct guestfs_command_lines_ret {
+ str lines<>;
+};
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
@@ -386,6 +402,8 @@ enum guestfs_procedure {
GUESTFS_PROC_UMOUNT_ALL = 47,
GUESTFS_PROC_LVM_REMOVE_ALL = 48,
GUESTFS_PROC_FILE = 49,
+ GUESTFS_PROC_COMMAND = 50,
+ GUESTFS_PROC_COMMAND_LINES = 51,
GUESTFS_PROC_dummy
};