diff options
author | Richard Jones <rjones@redhat.com> | 2009-04-14 13:51:12 +0100 |
---|---|---|
committer | Richard Jones <rjones@redhat.com> | 2009-04-14 13:51:12 +0100 |
commit | 5365ebd501850ea10d9a5b28fc6480ea34dbe16d (patch) | |
tree | 3c3bedf7581ea8485db6f039f2633ee07361b031 /src | |
parent | 161018ed1e90c796e6e099859979da02d5f3e410 (diff) | |
download | libguestfs-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-x | src/generator.ml | 72 | ||||
-rw-r--r-- | src/guestfs-actions.c | 154 | ||||
-rw-r--r-- | src/guestfs-actions.h | 2 | ||||
-rw-r--r-- | src/guestfs_protocol.c | 43 | ||||
-rw-r--r-- | src/guestfs_protocol.h | 41 | ||||
-rw-r--r-- | src/guestfs_protocol.x | 18 |
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 }; |