fprintf (stderr, "warning: \"guestfs_vg_activate\" has no tests\n");
fprintf (stderr, "warning: \"guestfs_resize2fs\" has no tests\n");
fprintf (stderr, "warning: \"guestfs_e2fsck_f\" has no tests\n");
+ fprintf (stderr, "warning: \"guestfs_sh\" has no tests\n");
+ fprintf (stderr, "warning: \"guestfs_sh_lines\" has no tests\n");
}
static int test_ntfs_3g_probe_0_skip (void)
extern int do_e2fsck_f (char *device);
extern int do_sleep (int secs);
extern int do_ntfs_3g_probe (int rw, char *device);
+extern char *do_sh (char *command);
+extern char **do_sh_lines (char *command);
xdr_free ((xdrproc_t) xdr_guestfs_ntfs_3g_probe_args, (char *) &args);
}
+static void sh_stub (XDR *xdr_in)
+{
+ char *r;
+ struct guestfs_sh_args args;
+ char *command;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_sh_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "sh");
+ return;
+ }
+ command = args.command;
+
+ r = do_sh (command);
+ if (r == NULL)
+ /* do_sh has already called reply_with_error */
+ goto done;
+
+ struct guestfs_sh_ret ret;
+ ret.output = r;
+ reply ((xdrproc_t) &xdr_guestfs_sh_ret, (char *) &ret);
+ free (r);
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_sh_args, (char *) &args);
+}
+
+static void sh_lines_stub (XDR *xdr_in)
+{
+ char **r;
+ struct guestfs_sh_lines_args args;
+ char *command;
+
+ memset (&args, 0, sizeof args);
+
+ if (!xdr_guestfs_sh_lines_args (xdr_in, &args)) {
+ reply_with_error ("%s: daemon failed to decode procedure arguments", "sh_lines");
+ return;
+ }
+ command = args.command;
+
+ r = do_sh_lines (command);
+ if (r == NULL)
+ /* do_sh_lines has already called reply_with_error */
+ goto done;
+
+ struct guestfs_sh_lines_ret ret;
+ ret.lines.lines_len = count_strings (r);
+ ret.lines.lines_val = r;
+ reply ((xdrproc_t) &xdr_guestfs_sh_lines_ret, (char *) &ret);
+ free_strings (r);
+done:
+ xdr_free ((xdrproc_t) xdr_guestfs_sh_lines_args, (char *) &args);
+}
+
void dispatch_incoming_message (XDR *xdr_in)
{
switch (proc_nr) {
case GUESTFS_PROC_NTFS_3G_PROBE:
ntfs_3g_probe_stub (xdr_in);
break;
+ case GUESTFS_PROC_SH:
+ sh_stub (xdr_in);
+ break;
+ case GUESTFS_PROC_SH_LINES:
+ sh_lines_stub (xdr_in);
+ break;
default:
reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
}
printf ("%-20s %s\n", "sfdisk-disk-geometry", "display the disk geometry from the partition table");
printf ("%-20s %s\n", "sfdisk-kernel-geometry", "display the kernel geometry");
printf ("%-20s %s\n", "sfdisk-l", "display the partition table");
+ printf ("%-20s %s\n", "sh", "run a command via the shell");
+ printf ("%-20s %s\n", "sh-lines", "run a command via the shell returning lines");
printf ("%-20s %s\n", "sleep", "sleep for some seconds");
printf ("%-20s %s\n", "stat", "get file information");
printf ("%-20s %s\n", "statvfs", "get file system statistics");
pod2text ("file - determine file type", " file <path>\n\nThis call uses the standard L<file(1)> command to determine\nthe type or contents of the file. This also works on devices,\nfor example to find out whether a partition contains a filesystem.\n\nThe exact command which runs is C<file -bsL path>. Note in\nparticular that the filename is not prepended to the output\n(the C<-b> option).");
else
if (strcasecmp (cmd, "command") == 0)
- pod2text ("command - run a command from the guest filesystem", " command <arguments>\n\nThis call runs a command from the guest filesystem. The\nfilesystem must be mounted, and must contain a compatible\noperating system (ie. something Linux, with the same\nor compatible processor architecture).\n\nThe single parameter is an argv-style list of arguments.\nThe first element is the name of the program to run.\nSubsequent elements are parameters. The list must be\nnon-empty (ie. must contain a program name).\n\nThe return value is anything printed to I<stdout> by\nthe command.\n\nIf the command returns a non-zero exit status, then\nthis function returns an error message. The error message\nstring is the content of I<stderr> from the command.\n\nThe C<$PATH> environment variable will contain at least\nC</usr/bin> and C</bin>. If you require a program from\nanother location, you should provide the full path in the\nfirst parameter.\n\nShared libraries and data files required by the program\nmust be available on filesystems which are mounted in the\ncorrect places. It is the caller's responsibility to ensure\nall filesystems that are needed are mounted at the right\nlocations.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB. To transfer large files you should use\nFTP.");
+ pod2text ("command - run a command from the guest filesystem", " command <arguments>\n\nThis call runs a command from the guest filesystem. The\nfilesystem must be mounted, and must contain a compatible\noperating system (ie. something Linux, with the same\nor compatible processor architecture).\n\nThe single parameter is an argv-style list of arguments.\nThe first element is the name of the program to run.\nSubsequent elements are parameters. The list must be\nnon-empty (ie. must contain a program name). Note that\nthe command runs directly, and is I<not> invoked via\nthe shell (see C<sh>).\n\nThe return value is anything printed to I<stdout> by\nthe command.\n\nIf the command returns a non-zero exit status, then\nthis function returns an error message. The error message\nstring is the content of I<stderr> from the command.\n\nThe C<$PATH> environment variable will contain at least\nC</usr/bin> and C</bin>. If you require a program from\nanother location, you should provide the full path in the\nfirst parameter.\n\nShared libraries and data files required by the program\nmust be available on filesystems which are mounted in the\ncorrect places. It is the caller's responsibility to ensure\nall filesystems that are needed are mounted at the right\nlocations.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB. To transfer large files you should use\nFTP.");
else
if (strcasecmp (cmd, "command_lines") == 0 || strcasecmp (cmd, "command-lines") == 0)
- pod2text ("command-lines - run a command, returning lines", " command-lines <arguments>\n\nThis is the same as C<command>, but splits the\nresult into a list of lines.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB. To transfer large files you should use\nFTP.");
+ pod2text ("command-lines - run a command, returning lines", " command-lines <arguments>\n\nThis is the same as C<command>, but splits the\nresult into a list of lines.\n\nSee also: C<sh_lines>\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB. To transfer large files you should use\nFTP.");
else
if (strcasecmp (cmd, "stat") == 0)
pod2text ("stat - get file information", " stat <path>\n\nReturns file information for the given C<path>.\n\nThis is the same as the C<stat(2)> system call.");
if (strcasecmp (cmd, "ntfs_3g_probe") == 0 || strcasecmp (cmd, "ntfs-3g-probe") == 0)
pod2text ("ntfs-3g-probe - probe NTFS volume", " ntfs-3g-probe <rw> <device>\n\nThis command runs the L<ntfs-3g.probe(8)> command which probes\nan NTFS C<device> for mountability. (Not all NTFS volumes can\nbe mounted read-write, and some cannot be mounted at all).\n\nC<rw> is a boolean flag. Set it to true if you want to test\nif the volume can be mounted read-write. Set it to false if\nyou want to test if the volume can be mounted read-only.\n\nThe return value is an integer which C<0> if the operation\nwould succeed, or some non-zero value documented in the\nL<ntfs-3g.probe(8)> manual page.");
else
+ if (strcasecmp (cmd, "sh") == 0)
+ pod2text ("sh - run a command via the shell", " sh <command>\n\nThis call runs a command from the guest filesystem via the\nguest's C</bin/sh>.\n\nThis is like C<command>, but passes the command to:\n\n /bin/sh -c \"command\"\n\nDepending on the guest's shell, this usually results in\nwildcards being expanded, shell expressions being interpolated\nand so on.\n\nAll the provisos about C<command> apply to this call.");
+ else
+ if (strcasecmp (cmd, "sh_lines") == 0 || strcasecmp (cmd, "sh-lines") == 0)
+ pod2text ("sh-lines - run a command via the shell returning lines", " sh-lines <command>\n\nThis is the same as C<sh>, but splits the result\ninto a list of lines.\n\nSee also: C<command_lines>");
+ else
display_builtin_command (cmd);
}
return 0;
}
+static int run_sh (const char *cmd, int argc, char *argv[])
+{
+ char *r;
+ const char *command;
+ if (argc != 1) {
+ fprintf (stderr, "%s should have 1 parameter(s)\n", cmd);
+ fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+ return -1;
+ }
+ command = argv[0];
+ r = guestfs_sh (g, command);
+ if (r == NULL) return -1;
+ printf ("%s\n", r);
+ free (r);
+ return 0;
+}
+
+static int run_sh_lines (const char *cmd, int argc, char *argv[])
+{
+ char **r;
+ const char *command;
+ if (argc != 1) {
+ fprintf (stderr, "%s should have 1 parameter(s)\n", cmd);
+ fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+ return -1;
+ }
+ command = argv[0];
+ r = guestfs_sh_lines (g, command);
+ if (r == NULL) return -1;
+ print_strings (r);
+ free_strings (r);
+ return 0;
+}
+
int run_action (const char *cmd, int argc, char *argv[])
{
if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0)
if (strcasecmp (cmd, "ntfs_3g_probe") == 0 || strcasecmp (cmd, "ntfs-3g-probe") == 0)
return run_ntfs_3g_probe (cmd, argc, argv);
else
+ if (strcasecmp (cmd, "sh") == 0)
+ return run_sh (cmd, argc, argv);
+ else
+ if (strcasecmp (cmd, "sh_lines") == 0 || strcasecmp (cmd, "sh-lines") == 0)
+ return run_sh_lines (cmd, argc, argv);
+ else
{
fprintf (stderr, "%s: unknown command\n", cmd);
return -1;
"e2fsck-f",
"sleep",
"ntfs-3g-probe",
+ "sh",
+ "sh-lines",
NULL
};
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).
+non-empty (ie. must contain a program name). Note that
+the command runs directly, and is I<not> invoked via
+the shell (see C<sh>).
The return value is anything printed to I<stdout> by
the command.
This is the same as C<command>, but splits the
result into a list of lines.
+See also: C<sh-lines>
+
Because of the message protocol, there is a transfer limit
of somewhere between 2MB and 4MB. To transfer large files you should use
FTP.
human-readable output of the L<sfdisk(8)> command. It is
not intended to be parsed.
+=head2 sh
+
+ sh command
+
+This call runs a command from the guest filesystem via the
+guest's C</bin/sh>.
+
+This is like C<command>, but passes the command to:
+
+ /bin/sh -c "command"
+
+Depending on the guest's shell, this usually results in
+wildcards being expanded, shell expressions being interpolated
+and so on.
+
+All the provisos about C<command> apply to this call.
+
+=head2 sh-lines
+
+ sh-lines command
+
+This is the same as C<sh>, but splits the result
+into a list of lines.
+
+See also: C<command-lines>
+
=head2 sleep
sleep secs
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).
+non-empty (ie. must contain a program name). Note that
+the command runs directly, and is I<not> invoked via
+the shell (see C<guestfs_sh>).
The return value is anything printed to I<stdout> by
the command.
This is the same as C<guestfs_command>, but splits the
result into a list of lines.
+See also: C<guestfs_sh_lines>
+
This function returns a NULL-terminated array of strings
(like L<environ(3)>), or NULL if there was an error.
I<The caller must free the strings and the array after use>.
This function returns a string, or NULL on error.
I<The caller must free the returned string after use>.
+=head2 guestfs_sh
+
+ char *guestfs_sh (guestfs_h *handle,
+ const char *command);
+
+This call runs a command from the guest filesystem via the
+guest's C</bin/sh>.
+
+This is like C<guestfs_command>, but passes the command to:
+
+ /bin/sh -c "command"
+
+Depending on the guest's shell, this usually results in
+wildcards being expanded, shell expressions being interpolated
+and so on.
+
+All the provisos about C<guestfs_command> apply to this call.
+
+This function returns a string, or NULL on error.
+I<The caller must free the returned string after use>.
+
+=head2 guestfs_sh_lines
+
+ char **guestfs_sh_lines (guestfs_h *handle,
+ const char *command);
+
+This is the same as C<guestfs_sh>, but splits the result
+into a list of lines.
+
+See also: C<guestfs_command_lines>
+
+This function returns a NULL-terminated array of strings
+(like L<environ(3)>), or NULL if there was an error.
+I<The caller must free the strings and the array after use>.
+
=head2 guestfs_sleep
int guestfs_sleep (guestfs_h *handle,
* 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).
+ * non-empty (ie. must contain a program name). Note that
+ * the command runs directly, and is *not* invoked via the
+ * shell (see "g.sh").
* <p>
* The return value is anything printed to *stdout* by the
* command.
* This is the same as "g.command", but splits the result
* into a list of lines.
* <p>
+ * See also: "g.sh_lines"
+ * <p>
* Because of the message protocol, there is a transfer
* limit of somewhere between 2MB and 4MB. To transfer
* large files you should use FTP.
private native int _ntfs_3g_probe (long g, boolean rw, String device)
throws LibGuestFSException;
+ /**
+ * run a command via the shell
+ * <p>
+ * This call runs a command from the guest filesystem via
+ * the guest's "/bin/sh".
+ * <p>
+ * This is like "g.command", but passes the command to:
+ * <p>
+ * /bin/sh -c "command"
+ * <p>
+ * Depending on the guest's shell, this usually results in
+ * wildcards being expanded, shell expressions being
+ * interpolated and so on.
+ * <p>
+ * All the provisos about "g.command" apply to this call.
+ * <p>
+ * @throws LibGuestFSException
+ */
+ public String sh (String command)
+ throws LibGuestFSException
+ {
+ if (g == 0)
+ throw new LibGuestFSException ("sh: handle is closed");
+ return _sh (g, command);
+ }
+ private native String _sh (long g, String command)
+ throws LibGuestFSException;
+
+ /**
+ * run a command via the shell returning lines
+ * <p>
+ * This is the same as "g.sh", but splits the result into a
+ * list of lines.
+ * <p>
+ * See also: "g.command_lines"
+ * <p>
+ * @throws LibGuestFSException
+ */
+ public String[] sh_lines (String command)
+ throws LibGuestFSException
+ {
+ if (g == 0)
+ throw new LibGuestFSException ("sh_lines: handle is closed");
+ return _sh_lines (g, command);
+ }
+ private native String[] _sh_lines (long g, String command)
+ throws LibGuestFSException;
+
}
return (jint) r;
}
+JNIEXPORT jstring JNICALL
+Java_com_redhat_et_libguestfs_GuestFS__1sh
+ (JNIEnv *env, jobject obj, jlong jg, jstring jcommand)
+{
+ guestfs_h *g = (guestfs_h *) (long) jg;
+ jstring jr;
+ char *r;
+ const char *command;
+
+ command = (*env)->GetStringUTFChars (env, jcommand, NULL);
+ r = guestfs_sh (g, command);
+ (*env)->ReleaseStringUTFChars (env, jcommand, command);
+ if (r == NULL) {
+ throw_exception (env, guestfs_last_error (g));
+ return NULL;
+ }
+ jr = (*env)->NewStringUTF (env, r);
+ free (r);
+ return jr;
+}
+
+JNIEXPORT jobjectArray JNICALL
+Java_com_redhat_et_libguestfs_GuestFS__1sh_1lines
+ (JNIEnv *env, jobject obj, jlong jg, jstring jcommand)
+{
+ guestfs_h *g = (guestfs_h *) (long) jg;
+ jobjectArray jr;
+ int r_len;
+ jclass cl;
+ jstring jstr;
+ char **r;
+ const char *command;
+ int i;
+
+ command = (*env)->GetStringUTFChars (env, jcommand, NULL);
+ r = guestfs_sh_lines (g, command);
+ (*env)->ReleaseStringUTFChars (env, jcommand, command);
+ if (r == NULL) {
+ throw_exception (env, guestfs_last_error (g));
+ return NULL;
+ }
+ for (r_len = 0; r[r_len] != NULL; ++r_len) ;
+ cl = (*env)->FindClass (env, "java/lang/String");
+ jstr = (*env)->NewStringUTF (env, "");
+ jr = (*env)->NewObjectArray (env, r_len, cl, jstr);
+ for (i = 0; i < r_len; ++i) {
+ jstr = (*env)->NewStringUTF (env, r[i]);
+ (*env)->SetObjectArrayElement (env, jr, i, jstr);
+ free (r[i]);
+ }
+ free (r);
+ return jr;
+}
+
external e2fsck_f : t -> string -> unit = "ocaml_guestfs_e2fsck_f"
external sleep : t -> int -> unit = "ocaml_guestfs_sleep"
external ntfs_3g_probe : t -> bool -> string -> int = "ocaml_guestfs_ntfs_3g_probe"
+external sh : t -> string -> string = "ocaml_guestfs_sh"
+external sh_lines : t -> string -> string array = "ocaml_guestfs_sh_lines"
val ntfs_3g_probe : t -> bool -> string -> int
(** probe NTFS volume *)
+val sh : t -> string -> string
+(** run a command via the shell *)
+
+val sh_lines : t -> string -> string array
+(** run a command via the shell returning lines *)
+
CAMLreturn (rv);
}
+CAMLprim value
+ocaml_guestfs_sh (value gv, value commandv)
+{
+ CAMLparam2 (gv, commandv);
+ CAMLlocal1 (rv);
+
+ guestfs_h *g = Guestfs_val (gv);
+ if (g == NULL)
+ caml_failwith ("sh: used handle after closing it");
+
+ const char *command = String_val (commandv);
+ char *r;
+
+ caml_enter_blocking_section ();
+ r = guestfs_sh (g, command);
+ caml_leave_blocking_section ();
+ if (r == NULL)
+ ocaml_guestfs_raise_error (g, "sh");
+
+ rv = caml_copy_string (r);
+ free (r);
+ CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_guestfs_sh_lines (value gv, value commandv)
+{
+ CAMLparam2 (gv, commandv);
+ CAMLlocal1 (rv);
+
+ guestfs_h *g = Guestfs_val (gv);
+ if (g == NULL)
+ caml_failwith ("sh_lines: used handle after closing it");
+
+ const char *command = String_val (commandv);
+ int i;
+ char **r;
+
+ caml_enter_blocking_section ();
+ r = guestfs_sh_lines (g, command);
+ caml_leave_blocking_section ();
+ if (r == NULL)
+ ocaml_guestfs_raise_error (g, "sh_lines");
+
+ rv = caml_copy_string_array ((const char **) r);
+ for (i = 0; r[i] != NULL; ++i) free (r[i]);
+ free (r);
+ CAMLreturn (rv);
+}
+
OUTPUT:
RETVAL
+SV *
+sh (g, command)
+ guestfs_h *g;
+ char *command;
+PREINIT:
+ char *output;
+ CODE:
+ output = guestfs_sh (g, command);
+ if (output == NULL)
+ croak ("sh: %s", guestfs_last_error (g));
+ RETVAL = newSVpv (output, 0);
+ free (output);
+ OUTPUT:
+ RETVAL
+
+void
+sh_lines (g, command)
+ guestfs_h *g;
+ char *command;
+PREINIT:
+ char **lines;
+ int i, n;
+ PPCODE:
+ lines = guestfs_sh_lines (g, command);
+ if (lines == NULL)
+ croak ("sh_lines: %s", guestfs_last_error (g));
+ for (n = 0; lines[n] != NULL; ++n) /**/;
+ EXTEND (SP, n);
+ for (i = 0; i < n; ++i) {
+ PUSHs (sv_2mortal (newSVpv (lines[i], 0)));
+ free (lines[i]);
+ }
+ free (lines);
+
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).
+non-empty (ie. must contain a program name). Note that
+the command runs directly, and is I<not> invoked via
+the shell (see C<$h-E<gt>sh>).
The return value is anything printed to I<stdout> by
the command.
This is the same as C<$h-E<gt>command>, but splits the
result into a list of lines.
+See also: C<$h-E<gt>sh_lines>
+
Because of the message protocol, there is a transfer limit
of somewhere between 2MB and 4MB. To transfer large files you should use
FTP.
human-readable output of the L<sfdisk(8)> command. It is
not intended to be parsed.
+=item $output = $h->sh ($command);
+
+This call runs a command from the guest filesystem via the
+guest's C</bin/sh>.
+
+This is like C<$h-E<gt>command>, but passes the command to:
+
+ /bin/sh -c "command"
+
+Depending on the guest's shell, this usually results in
+wildcards being expanded, shell expressions being interpolated
+and so on.
+
+All the provisos about C<$h-E<gt>command> apply to this call.
+
+=item @lines = $h->sh_lines ($command);
+
+This is the same as C<$h-E<gt>sh>, but splits the result
+into a list of lines.
+
+See also: C<$h-E<gt>command_lines>
+
=item $h->sleep ($secs);
Sleep for C<secs> seconds.
return py_r;
}
+static PyObject *
+py_guestfs_sh (PyObject *self, PyObject *args)
+{
+ PyObject *py_g;
+ guestfs_h *g;
+ PyObject *py_r;
+ char *r;
+ const char *command;
+
+ if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_sh",
+ &py_g, &command))
+ return NULL;
+ g = get_handle (py_g);
+
+ r = guestfs_sh (g, command);
+ if (r == NULL) {
+ PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+ return NULL;
+ }
+
+ py_r = PyString_FromString (r);
+ free (r);
+ return py_r;
+}
+
+static PyObject *
+py_guestfs_sh_lines (PyObject *self, PyObject *args)
+{
+ PyObject *py_g;
+ guestfs_h *g;
+ PyObject *py_r;
+ char **r;
+ const char *command;
+
+ if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_sh_lines",
+ &py_g, &command))
+ return NULL;
+ g = get_handle (py_g);
+
+ r = guestfs_sh_lines (g, command);
+ if (r == NULL) {
+ PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+ return NULL;
+ }
+
+ py_r = put_string_list (r);
+ free_strings (r);
+ return py_r;
+}
+
static PyMethodDef methods[] = {
{ (char *) "create", py_guestfs_create, METH_VARARGS, NULL },
{ (char *) "close", py_guestfs_close, METH_VARARGS, NULL },
{ (char *) "e2fsck_f", py_guestfs_e2fsck_f, METH_VARARGS, NULL },
{ (char *) "sleep", py_guestfs_sleep, METH_VARARGS, NULL },
{ (char *) "ntfs_3g_probe", py_guestfs_ntfs_3g_probe, METH_VARARGS, NULL },
+ { (char *) "sh", py_guestfs_sh, METH_VARARGS, NULL },
+ { (char *) "sh_lines", py_guestfs_sh_lines, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
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).
+ non-empty (ie. must contain a program name). Note that
+ the command runs directly, and is *not* invoked via the
+ shell (see "g.sh").
The return value is anything printed to *stdout* by the
command.
u"""This is the same as "g.command", but splits the result
into a list of lines.
+ See also: "g.sh_lines"
+
This function returns a list of strings.
Because of the message protocol, there is a transfer
"""
return libguestfsmod.ntfs_3g_probe (self._o, rw, device)
+ def sh (self, command):
+ u"""This call runs a command from the guest filesystem via
+ the guest's "/bin/sh".
+
+ This is like "g.command", but passes the command to:
+
+ /bin/sh -c "command"
+
+ Depending on the guest's shell, this usually results in
+ wildcards being expanded, shell expressions being
+ interpolated and so on.
+
+ All the provisos about "g.command" apply to this call.
+ """
+ return libguestfsmod.sh (self._o, command)
+
+ def sh_lines (self, command):
+ u"""This is the same as "g.sh", but splits the result into a
+ list of lines.
+
+ See also: "g.command_lines"
+
+ This function returns a list of strings.
+ """
+ return libguestfsmod.sh_lines (self._o, command)
+
return INT2NUM (r);
}
+static VALUE ruby_guestfs_sh (VALUE gv, VALUE commandv)
+{
+ guestfs_h *g;
+ Data_Get_Struct (gv, guestfs_h, g);
+ if (!g)
+ rb_raise (rb_eArgError, "%s: used handle after closing it", "sh");
+
+ const char *command = StringValueCStr (commandv);
+ if (!command)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "command", "sh");
+
+ char *r;
+
+ r = guestfs_sh (g, command);
+ if (r == NULL)
+ rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+ VALUE rv = rb_str_new2 (r);
+ free (r);
+ return rv;
+}
+
+static VALUE ruby_guestfs_sh_lines (VALUE gv, VALUE commandv)
+{
+ guestfs_h *g;
+ Data_Get_Struct (gv, guestfs_h, g);
+ if (!g)
+ rb_raise (rb_eArgError, "%s: used handle after closing it", "sh_lines");
+
+ const char *command = StringValueCStr (commandv);
+ if (!command)
+ rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+ "command", "sh_lines");
+
+ char **r;
+
+ r = guestfs_sh_lines (g, command);
+ if (r == NULL)
+ rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+ int i, len = 0;
+ for (i = 0; r[i] != NULL; ++i) len++;
+ VALUE rv = rb_ary_new2 (len);
+ for (i = 0; r[i] != NULL; ++i) {
+ rb_ary_push (rv, rb_str_new2 (r[i]));
+ free (r[i]);
+ }
+ free (r);
+ return rv;
+}
+
/* Initialize the module. */
void Init__guestfs ()
{
ruby_guestfs_sleep, 1);
rb_define_method (c_guestfs, "ntfs_3g_probe",
ruby_guestfs_ntfs_3g_probe, 2);
+ rb_define_method (c_guestfs, "sh",
+ ruby_guestfs_sh, 1);
+ rb_define_method (c_guestfs, "sh_lines",
+ ruby_guestfs_sh_lines, 1);
}
return ctx.ret.status;
}
+struct sh_ctx {
+ /* This flag is set by the callbacks, so we know we've done
+ * the callbacks as expected, and in the right sequence.
+ * 0 = not called, 1 = reply_cb called.
+ */
+ int cb_sequence;
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+ struct guestfs_sh_ret ret;
+};
+
+static void sh_reply_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ struct sh_ctx *ctx = (struct sh_ctx *) data;
+
+ /* This should definitely not happen. */
+ if (ctx->cb_sequence != 0) {
+ ctx->cb_sequence = 9999;
+ error (g, "%s: internal error: reply callback called twice", "guestfs_sh");
+ return;
+ }
+
+ ml->main_loop_quit (ml, g);
+
+ if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
+ error (g, "%s: failed to parse reply header", "guestfs_sh");
+ return;
+ }
+ if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
+ error (g, "%s: failed to parse reply error", "guestfs_sh");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_sh_ret (xdr, &ctx->ret)) {
+ error (g, "%s: failed to parse reply", "guestfs_sh");
+ return;
+ }
+ done:
+ ctx->cb_sequence = 1;
+}
+
+char *guestfs_sh (guestfs_h *g,
+ const char *command)
+{
+ struct guestfs_sh_args args;
+ struct sh_ctx ctx;
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ int serial;
+
+ if (check_state (g, "guestfs_sh") == -1) return NULL;
+ guestfs_set_busy (g);
+
+ memset (&ctx, 0, sizeof ctx);
+
+ args.command = (char *) command;
+ serial = guestfs__send_sync (g, GUESTFS_PROC_SH,
+ (xdrproc_t) xdr_guestfs_sh_args, (char *) &args);
+ if (serial == -1) {
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ guestfs__switch_to_receiving (g);
+ ctx.cb_sequence = 0;
+ guestfs_set_reply_callback (g, sh_reply_cb, &ctx);
+ (void) ml->main_loop_run (ml, g);
+ guestfs_set_reply_callback (g, NULL, NULL);
+ if (ctx.cb_sequence != 1) {
+ error (g, "%s reply failed, see earlier error messages", "guestfs_sh");
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SH, serial) == -1) {
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", ctx.err.error_message);
+ free (ctx.err.error_message);
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ guestfs_end_busy (g);
+ return ctx.ret.output; /* caller will free */
+}
+
+struct sh_lines_ctx {
+ /* This flag is set by the callbacks, so we know we've done
+ * the callbacks as expected, and in the right sequence.
+ * 0 = not called, 1 = reply_cb called.
+ */
+ int cb_sequence;
+ struct guestfs_message_header hdr;
+ struct guestfs_message_error err;
+ struct guestfs_sh_lines_ret ret;
+};
+
+static void sh_lines_reply_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ struct sh_lines_ctx *ctx = (struct sh_lines_ctx *) data;
+
+ /* This should definitely not happen. */
+ if (ctx->cb_sequence != 0) {
+ ctx->cb_sequence = 9999;
+ error (g, "%s: internal error: reply callback called twice", "guestfs_sh_lines");
+ return;
+ }
+
+ ml->main_loop_quit (ml, g);
+
+ if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
+ error (g, "%s: failed to parse reply header", "guestfs_sh_lines");
+ return;
+ }
+ if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
+ if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
+ error (g, "%s: failed to parse reply error", "guestfs_sh_lines");
+ return;
+ }
+ goto done;
+ }
+ if (!xdr_guestfs_sh_lines_ret (xdr, &ctx->ret)) {
+ error (g, "%s: failed to parse reply", "guestfs_sh_lines");
+ return;
+ }
+ done:
+ ctx->cb_sequence = 1;
+}
+
+char **guestfs_sh_lines (guestfs_h *g,
+ const char *command)
+{
+ struct guestfs_sh_lines_args args;
+ struct sh_lines_ctx ctx;
+ guestfs_main_loop *ml = guestfs_get_main_loop (g);
+ int serial;
+
+ if (check_state (g, "guestfs_sh_lines") == -1) return NULL;
+ guestfs_set_busy (g);
+
+ memset (&ctx, 0, sizeof ctx);
+
+ args.command = (char *) command;
+ serial = guestfs__send_sync (g, GUESTFS_PROC_SH_LINES,
+ (xdrproc_t) xdr_guestfs_sh_lines_args, (char *) &args);
+ if (serial == -1) {
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ guestfs__switch_to_receiving (g);
+ ctx.cb_sequence = 0;
+ guestfs_set_reply_callback (g, sh_lines_reply_cb, &ctx);
+ (void) ml->main_loop_run (ml, g);
+ guestfs_set_reply_callback (g, NULL, NULL);
+ if (ctx.cb_sequence != 1) {
+ error (g, "%s reply failed, see earlier error messages", "guestfs_sh_lines");
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SH_LINES, serial) == -1) {
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
+ error (g, "%s", ctx.err.error_message);
+ free (ctx.err.error_message);
+ guestfs_end_busy (g);
+ return NULL;
+ }
+
+ guestfs_end_busy (g);
+ /* caller will free this, but we need to add a NULL entry */
+ ctx.ret.lines.lines_val =
+ safe_realloc (g, ctx.ret.lines.lines_val,
+ sizeof (char *) * (ctx.ret.lines.lines_len + 1));
+ ctx.ret.lines.lines_val[ctx.ret.lines.lines_len] = NULL;
+ return ctx.ret.lines.lines_val;
+}
+
extern int guestfs_e2fsck_f (guestfs_h *handle, const char *device);
extern int guestfs_sleep (guestfs_h *handle, int secs);
extern int guestfs_ntfs_3g_probe (guestfs_h *handle, int rw, const char *device);
+extern char *guestfs_sh (guestfs_h *handle, const char *command);
+extern char **guestfs_sh_lines (guestfs_h *handle, const char *command);
}
bool_t
+xdr_guestfs_sh_args (XDR *xdrs, guestfs_sh_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->command, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_sh_ret (XDR *xdrs, guestfs_sh_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->output, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_sh_lines_args (XDR *xdrs, guestfs_sh_lines_args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, &objp->command, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_sh_lines_ret (XDR *xdrs, guestfs_sh_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;
};
typedef struct guestfs_ntfs_3g_probe_ret guestfs_ntfs_3g_probe_ret;
+struct guestfs_sh_args {
+ char *command;
+};
+typedef struct guestfs_sh_args guestfs_sh_args;
+
+struct guestfs_sh_ret {
+ char *output;
+};
+typedef struct guestfs_sh_ret guestfs_sh_ret;
+
+struct guestfs_sh_lines_args {
+ char *command;
+};
+typedef struct guestfs_sh_lines_args guestfs_sh_lines_args;
+
+struct guestfs_sh_lines_ret {
+ struct {
+ u_int lines_len;
+ str *lines_val;
+ } lines;
+};
+typedef struct guestfs_sh_lines_ret guestfs_sh_lines_ret;
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
GUESTFS_PROC_E2FSCK_F = 108,
GUESTFS_PROC_SLEEP = 109,
GUESTFS_PROC_NTFS_3G_PROBE = 110,
- GUESTFS_PROC_NR_PROCS = 110 + 1,
+ GUESTFS_PROC_SH = 111,
+ GUESTFS_PROC_SH_LINES = 112,
+ GUESTFS_PROC_NR_PROCS = 112 + 1,
};
typedef enum guestfs_procedure guestfs_procedure;
#define GUESTFS_MESSAGE_MAX 4194304
extern bool_t xdr_guestfs_sleep_args (XDR *, guestfs_sleep_args*);
extern bool_t xdr_guestfs_ntfs_3g_probe_args (XDR *, guestfs_ntfs_3g_probe_args*);
extern bool_t xdr_guestfs_ntfs_3g_probe_ret (XDR *, guestfs_ntfs_3g_probe_ret*);
+extern bool_t xdr_guestfs_sh_args (XDR *, guestfs_sh_args*);
+extern bool_t xdr_guestfs_sh_ret (XDR *, guestfs_sh_ret*);
+extern bool_t xdr_guestfs_sh_lines_args (XDR *, guestfs_sh_lines_args*);
+extern bool_t xdr_guestfs_sh_lines_ret (XDR *, guestfs_sh_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*);
extern bool_t xdr_guestfs_sleep_args ();
extern bool_t xdr_guestfs_ntfs_3g_probe_args ();
extern bool_t xdr_guestfs_ntfs_3g_probe_ret ();
+extern bool_t xdr_guestfs_sh_args ();
+extern bool_t xdr_guestfs_sh_ret ();
+extern bool_t xdr_guestfs_sh_lines_args ();
+extern bool_t xdr_guestfs_sh_lines_ret ();
extern bool_t xdr_guestfs_procedure ();
extern bool_t xdr_guestfs_message_direction ();
extern bool_t xdr_guestfs_message_status ();
int status;
};
+struct guestfs_sh_args {
+ string command<>;
+};
+
+struct guestfs_sh_ret {
+ string output<>;
+};
+
+struct guestfs_sh_lines_args {
+ string command<>;
+};
+
+struct guestfs_sh_lines_ret {
+ str lines<>;
+};
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
GUESTFS_PROC_E2FSCK_F = 108,
GUESTFS_PROC_SLEEP = 109,
GUESTFS_PROC_NTFS_3G_PROBE = 110,
+ GUESTFS_PROC_SH = 111,
+ GUESTFS_PROC_SH_LINES = 112,
GUESTFS_PROC_NR_PROCS
};