#include <stdarg.h>
#include <stddef.h>
#include <unistd.h>
-#include <ctype.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include "guestfs.h"
#include "guestfs-internal-actions.h"
#include "guestfs_protocol.h"
+#include "c-ctype.h"
#include "ignore-value.h"
#ifdef HAVE_GETTEXT
int verbose;
int trace;
int autosync;
+ int direct;
+ int recovery_proc;
char *path; /* Path to kernel, initrd. */
char *qemu; /* Qemu binary. */
g->error_cb = default_error_cb;
g->error_cb_data = NULL;
+ g->recovery_proc = 1;
+
str = getenv ("LIBGUESTFS_DEBUG");
g->verbose = str != NULL && strcmp (str, "1") == 0;
return g->trace;
}
+int
+guestfs__set_direct (guestfs_h *g, int d)
+{
+ g->direct = !!d;
+ return 0;
+}
+
+int
+guestfs__get_direct (guestfs_h *g)
+{
+ return g->direct;
+}
+
+int
+guestfs__set_recovery_proc (guestfs_h *g, int f)
+{
+ g->recovery_proc = !!f;
+ return 0;
+}
+
+int
+guestfs__get_recovery_proc (guestfs_h *g)
+{
+ return g->recovery_proc;
+}
+
/* Add a string to the current command line. */
static void
incr_cmdline_size (guestfs_h *g)
null_vmchannel_sock = 0;
}
- if (pipe (wfd) == -1 || pipe (rfd) == -1) {
- perrorf (g, "pipe");
- goto cleanup0;
+ if (!g->direct) {
+ if (pipe (wfd) == -1 || pipe (rfd) == -1) {
+ perrorf (g, "pipe");
+ goto cleanup0;
+ }
}
r = fork ();
if (r == -1) {
perrorf (g, "fork");
- close (wfd[0]);
- close (wfd[1]);
- close (rfd[0]);
- close (rfd[1]);
+ if (!g->direct) {
+ close (wfd[0]);
+ close (wfd[1]);
+ close (rfd[0]);
+ close (rfd[1]);
+ }
goto cleanup0;
}
add_cmdline (g, "user,vlan=0,net=10.0.2.0/8");
snprintf (buf, sizeof buf,
- "guestfs_vmchannel=tcp:10.0.2.2:%d ", null_vmchannel_sock);
+ "guestfs_vmchannel=tcp:10.0.2.2:%d", null_vmchannel_sock);
vmchannel = strdup (buf);
}
add_cmdline (g, "-net");
add_cmdline (g, buf);
- vmchannel = "guestfs_vmchannel=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT " ";
+ vmchannel = "guestfs_vmchannel=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT;
}
/* Not guestfwd. HOPEFULLY this qemu uses the older -net channel
add_cmdline (g, "-net");
add_cmdline (g, "user,vlan=0,net=10.0.2.0/8");
- vmchannel = "guestfs_vmchannel=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT " ";
+ vmchannel = "guestfs_vmchannel=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT;
}
add_cmdline (g, "-net");
add_cmdline (g, "nic,model=" NET_IF ",vlan=0");
/* Linux kernel command line. */
snprintf (buf, sizeof buf,
LINUX_CMDLINE
- "%s" /* (selinux) */
- "%s" /* (vmchannel) */
- "%s" /* (verbose) */
+ "%s " /* (selinux) */
+ "%s " /* (vmchannel) */
+ "%s " /* (verbose) */
"%s", /* (append) */
- g->selinux ? "selinux=1 enforcing=0 " : "selinux=0 ",
+ g->selinux ? "selinux=1 enforcing=0" : "selinux=0",
vmchannel ? vmchannel : "",
- g->verbose ? "guestfs_verbose=1 " : "",
+ g->verbose ? "guestfs_verbose=1" : "",
g->append ? g->append : "");
add_cmdline (g, "-kernel");
if (g->verbose)
print_cmdline (g);
- /* Set up stdin, stdout. */
- close (0);
- close (1);
- close (wfd[1]);
- close (rfd[0]);
+ if (!g->direct) {
+ /* Set up stdin, stdout. */
+ close (0);
+ close (1);
+ close (wfd[1]);
+ close (rfd[0]);
+
+ if (dup (wfd[0]) == -1) {
+ dup_failed:
+ perror ("dup failed");
+ _exit (1);
+ }
+ if (dup (rfd[1]) == -1)
+ goto dup_failed;
- if (dup (wfd[0]) == -1) {
- dup_failed:
- perror ("dup failed");
- _exit (1);
+ close (wfd[0]);
+ close (rfd[1]);
}
- if (dup (rfd[1]) == -1)
- goto dup_failed;
-
- close (wfd[0]);
- close (rfd[1]);
#if 0
/* Set up a new process group, so we can signal this process
setpgid (0, 0);
#endif
+ setenv ("LC_ALL", "C", 1);
+
execv (g->qemu, g->cmdline); /* Run qemu. */
perror (g->qemu);
_exit (1);
/* Fork the recovery process off which will kill qemu if the parent
* process fails to do so (eg. if the parent segfaults).
*/
- r = fork ();
- if (r == 0) {
- pid_t qemu_pid = g->pid;
- pid_t parent_pid = getppid ();
-
- /* Writing to argv is hideously complicated and error prone. See:
- * http://anoncvs.postgresql.org/cvsweb.cgi/pgsql/src/backend/utils/misc/ps_status.c?rev=1.33.2.1;content-type=text%2Fplain
- */
+ g->recoverypid = -1;
+ if (g->recovery_proc) {
+ r = fork ();
+ if (r == 0) {
+ pid_t qemu_pid = g->pid;
+ pid_t parent_pid = getppid ();
+
+ /* Writing to argv is hideously complicated and error prone. See:
+ * http://anoncvs.postgresql.org/cvsweb.cgi/pgsql/src/backend/utils/misc/ps_status.c?rev=1.33.2.1;content-type=text%2Fplain
+ */
- /* Loop around waiting for one or both of the other processes to
- * disappear. It's fair to say this is very hairy. The PIDs that
- * we are looking at might be reused by another process. We are
- * effectively polling. Is the cure worse than the disease?
- */
- for (;;) {
- if (kill (qemu_pid, 0) == -1) /* qemu's gone away, we aren't needed */
- _exit (0);
- if (kill (parent_pid, 0) == -1) {
- /* Parent's gone away, qemu still around, so kill qemu. */
- kill (qemu_pid, 9);
- _exit (0);
+ /* Loop around waiting for one or both of the other processes to
+ * disappear. It's fair to say this is very hairy. The PIDs that
+ * we are looking at might be reused by another process. We are
+ * effectively polling. Is the cure worse than the disease?
+ */
+ for (;;) {
+ if (kill (qemu_pid, 0) == -1) /* qemu's gone away, we aren't needed */
+ _exit (0);
+ if (kill (parent_pid, 0) == -1) {
+ /* Parent's gone away, qemu still around, so kill qemu. */
+ kill (qemu_pid, 9);
+ _exit (0);
+ }
+ sleep (2);
}
- sleep (2);
}
- }
- /* Don't worry, if the fork failed, this will be -1. The recovery
- * process isn't essential.
- */
- g->recoverypid = r;
+ /* Don't worry, if the fork failed, this will be -1. The recovery
+ * process isn't essential.
+ */
+ g->recoverypid = r;
+ }
/* Start the clock ... */
time (&g->start_t);
- /* Close the other ends of the pipe. */
- close (wfd[0]);
- close (rfd[1]);
+ if (!g->direct) {
+ /* Close the other ends of the pipe. */
+ close (wfd[0]);
+ close (rfd[1]);
+
+ if (fcntl (wfd[1], F_SETFL, O_NONBLOCK) == -1 ||
+ fcntl (rfd[0], F_SETFL, O_NONBLOCK) == -1) {
+ perrorf (g, "fcntl");
+ goto cleanup1;
+ }
- if (fcntl (wfd[1], F_SETFL, O_NONBLOCK) == -1 ||
- fcntl (rfd[0], F_SETFL, O_NONBLOCK) == -1) {
- perrorf (g, "fcntl");
- goto cleanup1;
+ g->fd[0] = wfd[1]; /* stdin of child */
+ g->fd[1] = rfd[0]; /* stdout of child */
+ } else {
+ g->fd[0] = open ("/dev/null", O_RDWR);
+ if (g->fd[0] == -1) {
+ perrorf (g, "open /dev/null");
+ goto cleanup1;
+ }
+ g->fd[1] = dup (g->fd[0]);
+ if (g->fd[1] == -1) {
+ perrorf (g, "dup");
+ close (g->fd[0]);
+ goto cleanup1;
+ }
}
- g->fd[0] = wfd[1]; /* stdin of child */
- g->fd[1] = rfd[0]; /* stdout of child */
-
if (null_vmchannel_sock) {
int sock = -1;
uid_t uid;
return 0;
cleanup1:
- close (wfd[1]);
- close (rfd[0]);
+ if (!g->direct) {
+ close (wfd[1]);
+ close (rfd[0]);
+ }
kill (g->pid, 9);
if (g->recoverypid > 0) kill (g->recoverypid, 9);
waitpid (g->pid, NULL, 0);
g->qemu_help = NULL;
g->qemu_version = NULL;
- snprintf (cmd, sizeof cmd, "'%s' -help", g->qemu);
+ snprintf (cmd, sizeof cmd, "LC_ALL=C '%s' -help", g->qemu);
fp = popen (cmd, "r");
/* qemu -help should always work (qemu -version OTOH wasn't
if (pclose (fp) == -1)
goto error;
- snprintf (cmd, sizeof cmd, "'%s' -version 2>/dev/null", g->qemu);
+ snprintf (cmd, sizeof cmd, "LC_ALL=C '%s' -version 2>/dev/null", g->qemu);
fp = popen (cmd, "r");
if (fp) {
printf (" ");
printf ("|");
for (j = i; j < MIN (i+16, nr); ++j)
- if (isprint ((*(char **)buf_rtn)[j]))
+ if (c_isprint ((*(char **)buf_rtn)[j]))
printf ("%c", (*(char **)buf_rtn)[j]);
else
printf (".");