+ 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;
+ }
+ }
+
+ if (g->verbose)
+ print_timestamped_message (g, "finished testing qemu features");
+
+ 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;
+
+ /* qemu sometimes needs this option to enable hardware
+ * virtualization, but some versions of 'qemu-kvm' will use KVM
+ * regardless (even where this option appears in the help text).
+ * It is rumoured that there are versions of qemu where supplying
+ * this option when hardware virtualization is not available will
+ * cause qemu to fail, so we we have to check at least that
+ * /dev/kvm is openable. That's not reliable, since /dev/kvm
+ * might be openable by qemu but not by us (think: SELinux) in
+ * which case the user would not get hardware virtualization,
+ * although at least shouldn't fail. A giant clusterfuck with the
+ * qemu command line, again.
+ */
+ if (qemu_supports (g, "-enable-kvm") &&
+ is_openable (g, "/dev/kvm", O_RDWR))
+ add_cmdline (g, "-enable-kvm");
+
+ /* Newer versions of qemu (from around 2009/12) changed the
+ * behaviour of monitors so that an implicit '-monitor stdio' is
+ * assumed if we are in -nographic mode and there is no other
+ * -monitor option. Only a single stdio device is allowed, so
+ * this broke the '-serial stdio' option. There is a new flag
+ * called -nodefaults which gets rid of all this default crud, so
+ * let's use that to avoid this and any future surprises.
+ */
+ if (qemu_supports (g, "-nodefaults"))
+ add_cmdline (g, "-nodefaults");
+
+ add_cmdline (g, "-nographic");
+ add_cmdline (g, "-serial");
+ add_cmdline (g, "stdio");
+
+ snprintf (buf, sizeof buf, "%d", g->memsize);
+ add_cmdline (g, "-m");
+ add_cmdline (g, buf);
+
+ /* Force exit instead of reboot on panic */
+ add_cmdline (g, "-no-reboot");
+
+ /* 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=" NETWORK);
+
+ snprintf (buf, sizeof buf,
+ "guestfs_vmchannel=tcp:" ROUTER ":%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=" NETWORK ","
+ "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=" NETWORK);
+
+ 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 */ \
+ "printk.time=1 " /* display timestamp before kernel messages */ \
+ "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) */
+ "TERM=%s " /* (TERM environment variable) */
+ "%s", /* (append) */
+ g->selinux ? "selinux=1 enforcing=0" : "selinux=0",
+ vmchannel ? vmchannel : "",
+ g->verbose ? "guestfs_verbose=1" : "",
+ getenv ("TERM") ? : "linux",
+ g->append ? g->append : "");