+ addr.sin_family = AF_INET;
+ addr.sin_port = htons (0);
+ addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ if (bind (g->sock, (struct sockaddr *) &addr, addrlen) == -1) {
+ perrorf (g, "bind");
+ goto cleanup0;
+ }
+
+ if (listen (g->sock, 256) == -1) {
+ perrorf (g, "listen");
+ goto cleanup0;
+ }
+
+ if (getsockname (g->sock, (struct sockaddr *) &addr, &addrlen) == -1) {
+ perrorf (g, "getsockname");
+ goto cleanup0;
+ }
+
+ if (fcntl (g->sock, F_SETFL, O_NONBLOCK) == -1) {
+ perrorf (g, "fcntl");
+ goto cleanup0;
+ }
+
+ null_vmchannel_sock = ntohs (addr.sin_port);
+ if (g->verbose)
+ fprintf (stderr, "null_vmchannel_sock = %d\n", null_vmchannel_sock);
+ } else {
+ /* Using some vmchannel impl. We need to create a local Unix
+ * domain socket for qemu to use.
+ */
+ snprintf (unixsock, sizeof unixsock, "%s/sock", g->tmpdir);
+ unlink (unixsock);
+ null_vmchannel_sock = 0;
+ }
+
+ if (!g->direct) {
+ if (pipe (wfd) == -1 || pipe (rfd) == -1) {
+ perrorf (g, "pipe");
+ goto cleanup0;
+ }
+ }
+
+ r = fork ();
+ if (r == -1) {
+ perrorf (g, "fork");
+ if (!g->direct) {
+ close (wfd[0]);
+ close (wfd[1]);
+ close (rfd[0]);
+ close (rfd[1]);
+ }
+ goto cleanup0;
+ }
+
+ if (r == 0) { /* Child (qemu). */
+ char buf[256];
+ const char *vmchannel = NULL;
+
+ /* Set up the full command line. Do this in the subprocess so we
+ * don't need to worry about cleaning up.
+ */
+ g->cmdline[0] = g->qemu;
+
+ snprintf (buf, sizeof buf, "%d", g->memsize);
+ add_cmdline (g, "-m");
+ add_cmdline (g, buf);
+
+ add_cmdline (g, "-no-reboot"); /* Force exit instead of reboot on panic */
+ add_cmdline (g, "-nographic");
+ add_cmdline (g, "-serial");
+ add_cmdline (g, "stdio");
+
+ /* These options recommended by KVM developers to improve reliability. */
+ if (qemu_supports (g, "-no-hpet"))
+ add_cmdline (g, "-no-hpet");
+
+ if (qemu_supports (g, "-rtc-td-hack"))
+ add_cmdline (g, "-rtc-td-hack");
+
+ /* If qemu has SLIRP (user mode network) enabled then we can get
+ * away with "no vmchannel", where we just connect back to a random
+ * host port.
+ */
+ if (null_vmchannel_sock) {
+ add_cmdline (g, "-net");
+ 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);
+ vmchannel = strdup (buf);
+ }
+
+ /* New-style -net user,guestfwd=... syntax for guestfwd. See:
+ *
+ * http://git.savannah.gnu.org/cgit/qemu.git/commit/?id=c92ef6a22d3c71538fcc48fb61ad353f7ba03b62
+ *
+ * The original suggested format doesn't work, see:
+ *
+ * http://lists.gnu.org/archive/html/qemu-devel/2009-07/msg01654.html
+ *
+ * However Gerd Hoffman privately suggested to me using -chardev
+ * instead, which does work.
+ */
+ else if (qemu_supports (g, "-chardev") && qemu_supports (g, "guestfwd")) {
+ snprintf (buf, sizeof buf,
+ "socket,id=guestfsvmc,path=%s,server,nowait", unixsock);
+
+ add_cmdline (g, "-chardev");
+ add_cmdline (g, buf);
+
+ snprintf (buf, sizeof buf,
+ "user,vlan=0,net=10.0.2.0/8,"
+ "guestfwd=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT
+ "-chardev:guestfsvmc");
+
+ add_cmdline (g, "-net");
+ add_cmdline (g, buf);
+
+ vmchannel = "guestfs_vmchannel=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT;
+ }
+
+ /* Not guestfwd. HOPEFULLY this qemu uses the older -net channel
+ * syntax, or if not then we'll get a quick failure.
+ */
+ else {
+ snprintf (buf, sizeof buf,
+ "channel," GUESTFWD_PORT ":unix:%s,server,nowait", unixsock);
+
+ add_cmdline (g, "-net");
+ add_cmdline (g, buf);
+ add_cmdline (g, "-net");
+ add_cmdline (g, "user,vlan=0,net=10.0.2.0/8");
+
+ vmchannel = "guestfs_vmchannel=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT;
+ }
+ add_cmdline (g, "-net");
+ add_cmdline (g, "nic,model=" NET_IF ",vlan=0");
+
+#define LINUX_CMDLINE \
+ "panic=1 " /* force kernel to panic if daemon exits */ \
+ "console=ttyS0 " /* serial console */ \
+ "udevtimeout=300 " /* good for very slow systems (RHBZ#480319) */ \
+ "noapic " /* workaround for RHBZ#502058 - ok if not SMP */ \
+ "acpi=off " /* we don't need ACPI, turn it off */ \
+ "cgroup_disable=memory " /* saves us about 5 MB of RAM */
+
+ /* Linux kernel command line. */
+ snprintf (buf, sizeof buf,
+ LINUX_CMDLINE
+ "%s " /* (selinux) */
+ "%s " /* (vmchannel) */
+ "%s " /* (verbose) */
+ "%s", /* (append) */
+ g->selinux ? "selinux=1 enforcing=0" : "selinux=0",
+ vmchannel ? vmchannel : "",
+ g->verbose ? "guestfs_verbose=1" : "",
+ g->append ? g->append : "");
+
+ add_cmdline (g, "-kernel");
+ add_cmdline (g, (char *) kernel);
+ add_cmdline (g, "-initrd");
+ add_cmdline (g, (char *) initrd);
+ add_cmdline (g, "-append");
+ add_cmdline (g, buf);
+
+ /* Finish off the command line. */
+ incr_cmdline_size (g);
+ g->cmdline[g->cmdline_size-1] = NULL;
+
+ if (g->verbose)
+ print_cmdline (g);
+
+ 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;
+
+ close (wfd[0]);
+ close (rfd[1]);
+ }
+
+#if 0
+ /* Set up a new process group, so we can signal this process
+ * and all subprocesses (eg. if qemu is really a shell script).
+ */
+ setpgid (0, 0);
+#endif
+
+ execv (g->qemu, g->cmdline); /* Run qemu. */
+ perror (g->qemu);
+ _exit (1);
+ }
+
+ /* Parent (library). */
+ g->pid = r;
+
+ free (kernel);
+ kernel = NULL;
+ free (initrd);
+ initrd = NULL;
+
+ /* 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
+ */
+
+ /* 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);
+ }
+ }
+
+ /* 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);
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+
+ if (null_vmchannel_sock) {
+ int sock = -1;
+ uid_t uid;
+
+ /* Null vmchannel implementation: We listen on g->sock for a
+ * connection. The connection could come from any local process
+ * so we must check it comes from the appliance (or at least
+ * from our UID) for security reasons.
+ */
+ while (sock == -1) {
+ sock = accept_from_daemon (g);
+ if (sock == -1)
+ goto cleanup1;
+
+ if (check_peer_euid (g, sock, &uid) == -1)
+ goto cleanup1;
+ if (uid != geteuid ()) {
+ fprintf (stderr,
+ "libguestfs: warning: unexpected connection from UID %d to port %d\n",
+ uid, null_vmchannel_sock);
+ close (sock);
+ continue;
+ }
+ }
+
+ if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) {
+ perrorf (g, "fcntl");
+ goto cleanup1;
+ }
+
+ close (g->sock);
+ g->sock = sock;
+ } else {
+ /* Other vmchannel. Open the Unix socket.
+ *
+ * The vmchannel implementation that got merged with qemu sucks in
+ * a number of ways. Both ends do connect(2), which means that no
+ * one knows what, if anything, is connected to the other end, or
+ * if it becomes disconnected. Even worse, we have to wait some
+ * indeterminate time for qemu to create the socket and connect to
+ * it (which happens very early in qemu's start-up), so any code
+ * that uses vmchannel is inherently racy. Hence this silly loop.
+ */
+ g->sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (g->sock == -1) {
+ perrorf (g, "socket");
+ goto cleanup1;
+ }
+
+ if (fcntl (g->sock, F_SETFL, O_NONBLOCK) == -1) {
+ perrorf (g, "fcntl");
+ goto cleanup1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ strncpy (addr.sun_path, unixsock, UNIX_PATH_MAX);
+ addr.sun_path[UNIX_PATH_MAX-1] = '\0';
+
+ tries = 100;
+ /* Always sleep at least once to give qemu a small chance to start up. */
+ usleep (10000);
+ while (tries > 0) {
+ r = connect (g->sock, (struct sockaddr *) &addr, sizeof addr);
+ if ((r == -1 && errno == EINPROGRESS) || r == 0)
+ goto connected;
+
+ if (errno != ENOENT)
+ perrorf (g, "connect");
+ tries--;
+ usleep (100000);
+ }
+
+ error (g, _("failed to connect to vmchannel socket"));
+ goto cleanup1;
+
+ connected: ;
+ }
+
+ g->state = LAUNCHING;
+
+ /* Wait for qemu to start and to connect back to us via vmchannel and
+ * send the GUESTFS_LAUNCH_FLAG message.
+ */
+ uint32_t size;
+ void *buf = NULL;
+ r = recv_from_daemon (g, &size, &buf);
+ free (buf);
+
+ if (r == -1) return -1;
+
+ if (size != GUESTFS_LAUNCH_FLAG) {
+ error (g, _("guestfs_launch failed, see earlier error messages"));
+ goto cleanup1;
+ }
+
+ /* This is possible in some really strange situations, such as
+ * guestfsd starts up OK but then qemu immediately exits. Check for
+ * it because the caller is probably expecting to be able to send
+ * commands after this function returns.
+ */
+ if (g->state != READY) {
+ error (g, _("qemu launched and contacted daemon, but state != READY"));
+ goto cleanup1;
+ }
+
+ return 0;
+
+ cleanup1:
+ 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);
+ if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0);
+ g->fd[0] = -1;
+ g->fd[1] = -1;
+ g->pid = 0;
+ g->recoverypid = 0;
+ g->start_t = 0;
+
+ cleanup0:
+ if (g->sock >= 0) {
+ close (g->sock);
+ g->sock = -1;
+ }
+ g->state = CONFIG;
+ free (kernel);
+ free (initrd);
+ return -1;
+}
+
+/* This function is used to print the qemu command line before it gets
+ * executed, when in verbose mode.
+ */
+static void
+print_cmdline (guestfs_h *g)
+{
+ int i = 0;
+ int needs_quote;
+
+ while (g->cmdline[i]) {
+ if (g->cmdline[i][0] == '-') /* -option starts a new line */
+ fprintf (stderr, " \\\n ");
+
+ if (i > 0) fputc (' ', stderr);
+
+ /* Does it need shell quoting? This only deals with simple cases. */
+ needs_quote = strcspn (g->cmdline[i], " ") != strlen (g->cmdline[i]);
+
+ if (needs_quote) fputc ('\'', stderr);
+ fprintf (stderr, "%s", g->cmdline[i]);
+ if (needs_quote) fputc ('\'', stderr);
+ i++;
+ }
+
+ fputc ('\n', stderr);
+}
+
+/* This function does the hard work of building the supermin appliance
+ * on the fly. 'path' is the directory containing the control files.
+ * 'kernel' and 'initrd' are where we will return the names of the
+ * kernel and initrd (only initrd is built). The work is done by
+ * an external script. We just tell it where to put the result.
+ */
+static int
+build_supermin_appliance (guestfs_h *g, const char *path,
+ char **kernel, char **initrd)
+{
+ char cmd[4096];
+ int r, len;
+
+ len = strlen (g->tmpdir);
+ *kernel = safe_malloc (g, len + 8);
+ snprintf (*kernel, len+8, "%s/kernel", g->tmpdir);
+ *initrd = safe_malloc (g, len + 8);
+ snprintf (*initrd, len+8, "%s/initrd", g->tmpdir);
+
+ snprintf (cmd, sizeof cmd,
+ "PATH='%s':$PATH "
+ "libguestfs-supermin-helper '%s' %s %s",
+ path,
+ path, *kernel, *initrd);
+
+ r = system (cmd);
+ if (r == -1 || WEXITSTATUS(r) != 0) {
+ error (g, _("external command failed: %s"), cmd);
+ free (*kernel);
+ free (*initrd);
+ *kernel = *initrd = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int read_all (guestfs_h *g, FILE *fp, char **ret);
+
+/* Test qemu binary (or wrapper) runs, and do 'qemu -help' and
+ * 'qemu -version' so we know what options this qemu supports and
+ * the version.
+ */
+static int
+test_qemu (guestfs_h *g)
+{
+ char cmd[1024];
+ FILE *fp;
+
+ free (g->qemu_help);
+ free (g->qemu_version);
+ g->qemu_help = NULL;
+ g->qemu_version = NULL;
+
+ snprintf (cmd, sizeof cmd, "'%s' -help", g->qemu);
+
+ fp = popen (cmd, "r");
+ /* qemu -help should always work (qemu -version OTOH wasn't
+ * supported by qemu 0.9). If this command doesn't work then it
+ * probably indicates that the qemu binary is missing.
+ */
+ if (!fp) {
+ /* XXX This error is never printed, even if the qemu binary
+ * doesn't exist. Why?
+ */
+ error:
+ perrorf (g, _("%s: command failed: If qemu is located on a non-standard path, try setting the LIBGUESTFS_QEMU environment variable."), cmd);
+ return -1;
+ }
+
+ if (read_all (g, fp, &g->qemu_help) == -1)
+ goto error;
+
+ if (pclose (fp) == -1)
+ goto error;
+
+ snprintf (cmd, sizeof cmd, "'%s' -version 2>/dev/null", g->qemu);
+
+ fp = popen (cmd, "r");
+ if (fp) {
+ /* Intentionally ignore errors. */
+ read_all (g, fp, &g->qemu_version);
+ pclose (fp);
+ }
+
+ return 0;
+}
+
+static int
+read_all (guestfs_h *g, FILE *fp, char **ret)
+{
+ int r, n = 0;
+ char *p;
+
+ again:
+ if (feof (fp)) {
+ *ret = safe_realloc (g, *ret, n + 1);
+ (*ret)[n] = '\0';
+ return n;
+ }
+
+ *ret = safe_realloc (g, *ret, n + BUFSIZ);
+ p = &(*ret)[n];
+ r = fread (p, 1, BUFSIZ, fp);
+ if (ferror (fp)) {
+ perrorf (g, "read");
+ return -1;
+ }
+ n += r;
+ goto again;
+}
+
+/* Test if option is supported by qemu command line (just by grepping
+ * the help text).
+ */
+static int
+qemu_supports (guestfs_h *g, const char *option)
+{
+ return g->qemu_help && strstr (g->qemu_help, option) != NULL;
+}
+
+/* Check the peer effective UID for a TCP socket. Ideally we'd like
+ * SO_PEERCRED for a loopback TCP socket. This isn't possible on
+ * Linux (but it is on Solaris!) so we read /proc/net/tcp instead.
+ */
+static int
+check_peer_euid (guestfs_h *g, int sock, uid_t *rtn)
+{
+ struct sockaddr_in peer;
+ socklen_t addrlen = sizeof peer;
+
+ if (getpeername (sock, (struct sockaddr *) &peer, &addrlen) == -1) {
+ perrorf (g, "getpeername");
+ return -1;
+ }
+
+ if (peer.sin_family != AF_INET ||
+ ntohl (peer.sin_addr.s_addr) != INADDR_LOOPBACK) {
+ error (g, "check_peer_euid: unexpected connection from non-IPv4, non-loopback peer (family = %d, addr = %s)",
+ peer.sin_family, inet_ntoa (peer.sin_addr));
+ return -1;
+ }
+
+ struct sockaddr_in our;
+ addrlen = sizeof our;
+ if (getsockname (sock, (struct sockaddr *) &our, &addrlen) == -1) {
+ perrorf (g, "getsockname");
+ return -1;
+ }
+
+ FILE *fp = fopen ("/proc/net/tcp", "r");
+ if (fp == NULL) {
+ perrorf (g, "/proc/net/tcp");
+ return -1;
+ }
+
+ char line[256];
+ if (fgets (line, sizeof line, fp) == NULL) { /* Drop first line. */
+ error (g, "unexpected end of file in /proc/net/tcp");
+ fclose (fp);