X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fguestfs.c;h=f7df27e9c620e9a378b4d01eeaab6c86387e5e46;hb=79125c4dea9c69d08b522ed7c85f26dc6ee1bcb3;hp=17e2c7cd5d7d684e477b3b2246bb8db8401089d5;hpb=ae2e569489eea72083aab8109d8012f74587f692;p=libguestfs.git diff --git a/src/guestfs.c b/src/guestfs.c index 17e2c7c..f7df27e 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -62,6 +61,7 @@ #include "guestfs.h" #include "guestfs-internal-actions.h" #include "guestfs_protocol.h" +#include "c-ctype.h" #include "ignore-value.h" #ifdef HAVE_GETTEXT @@ -119,6 +119,8 @@ struct guestfs_h int verbose; int trace; int autosync; + int direct; + int recovery_proc; char *path; /* Path to kernel, initrd. */ char *qemu; /* Qemu binary. */ @@ -168,6 +170,8 @@ guestfs_create (void) 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; @@ -651,6 +655,32 @@ guestfs__get_trace (guestfs_h *g) 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) @@ -1018,18 +1048,22 @@ guestfs__launch (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; } @@ -1067,7 +1101,7 @@ guestfs__launch (guestfs_h *g) 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); } @@ -1097,7 +1131,7 @@ guestfs__launch (guestfs_h *g) 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 @@ -1112,7 +1146,7 @@ guestfs__launch (guestfs_h *g) 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"); @@ -1128,13 +1162,13 @@ guestfs__launch (guestfs_h *g) /* 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"); @@ -1151,22 +1185,24 @@ guestfs__launch (guestfs_h *g) 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 @@ -1175,6 +1211,8 @@ guestfs__launch (guestfs_h *g) setpgid (0, 0); #endif + setenv ("LC_ALL", "C", 1); + execv (g->qemu, g->cmdline); /* Run qemu. */ perror (g->qemu); _exit (1); @@ -1191,53 +1229,70 @@ guestfs__launch (guestfs_h *g) /* 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; @@ -1346,8 +1401,10 @@ guestfs__launch (guestfs_h *g) 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); @@ -1450,7 +1507,7 @@ test_qemu (guestfs_h *g) 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 @@ -1472,7 +1529,7 @@ test_qemu (guestfs_h *g) 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) { @@ -2100,7 +2157,7 @@ recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn) 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 (".");