Flexible guestfs_vmchannel parameter for future appliances.
[libguestfs.git] / src / guestfs.c
index 069de45..ec7473e 100644 (file)
@@ -85,8 +85,8 @@ static void close_handles (void);
 #define UNIX_PATH_MAX 108
 
 /* Also in guestfsd.c */
-#define GUESTFWD_PORT 6666
-//#define GUESTFWD_ADDR "10.0.2.4"
+#define GUESTFWD_ADDR "10.0.2.4"
+#define GUESTFWD_PORT "6666"
 
 /* GuestFS handle and connection. */
 enum state { CONFIG, LAUNCHING, READY, BUSY, NO_HANDLE };
@@ -983,88 +983,97 @@ guestfs__launch (guestfs_h *g)
   }
 
   if (r == 0) {                        /* Child (qemu). */
-    char vmchannel[256];
-    char append[256];
-    char memsize_str[256];
+    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;
 
-#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 (append, sizeof append,
-              LINUX_CMDLINE
-              "%s"              /* (selinux) */
-              "%s"              /* (verbose) */
-              "%s",             /* (append) */
-              g->selinux ? "selinux=1 enforcing=0 " : "selinux=0 ",
-              g->verbose ? "guestfs_verbose=1 " : " ",
-              g->append ? g->append : "");
-
-    snprintf (memsize_str, sizeof memsize_str, "%d", g->memsize);
-
+    snprintf (buf, sizeof buf, "%d", g->memsize);
     add_cmdline (g, "-m");
-    add_cmdline (g, memsize_str);
+    add_cmdline (g, buf);
+
     add_cmdline (g, "-no-reboot"); /* Force exit instead of reboot on panic */
-    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, append);
     add_cmdline (g, "-nographic");
     add_cmdline (g, "-serial");
     add_cmdline (g, "stdio");
 
-#if 0
-    /* Doesn't work.  See:
-     * http://lists.gnu.org/archive/html/qemu-devel/2009-07/threads.html
-     * Subject "guestfwd option doesn't allow supplementary ,server,nowait"
-     */
-    if (qemu_supports (g, "guestfwd")) {
-      /* New-style -net user,guestfwd=... syntax for vmchannel.  See:
+    /* 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_supports (g, "-chardev") && qemu_supports (g, "guestfwd")) {
+      /* 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.
        */
-      snprintf (vmchannel, sizeof vmchannel,
-                "user,vlan=0,net=10.0.2.0/8,guestfwd=tcp:%s:%d-unix:%s,server,nowait",
-                GUESTFWD_ADDR, GUESTFWD_PORT, unixsock);
+      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, vmchannel);
+      add_cmdline (g, buf);
     } else {
-#endif
       /* Not guestfwd.  HOPEFULLY this qemu uses the older -net channel
        * syntax, or if not then we'll get a quick failure.
        */
-      snprintf (vmchannel, sizeof vmchannel,
-                "channel,%d:unix:%s,server,nowait",
-                GUESTFWD_PORT, unixsock);
+      snprintf (buf, sizeof buf,
+                "channel," GUESTFWD_PORT ":unix:%s,server,nowait", unixsock);
 
       add_cmdline (g, "-net");
-      add_cmdline (g, vmchannel);
+      add_cmdline (g, buf);
       add_cmdline (g, "-net");
       add_cmdline (g, "user,vlan=0,net=10.0.2.0/8");
-#if 0
     }
-#endif
     add_cmdline (g, "-net");
     add_cmdline (g, "nic,model=" NET_IF ",vlan=0");
+    vmchannel = "guestfs_vmchannel=tcp:" GUESTFWD_ADDR ":" GUESTFWD_PORT " ";
 
-    /* These options recommended by KVM developers to improve reliability. */
-    if (qemu_supports (g, "-no-hpet"))
-      add_cmdline (g, "-no-hpet");
+#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 */
 
-    if (qemu_supports (g, "-rtc-td-hack"))
-      add_cmdline (g, "-rtc-td-hack");
+    /* 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);
@@ -1203,6 +1212,32 @@ guestfs__launch (guestfs_h *g)
 
  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 cleanup2;
+  }
+
+  /* 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 cleanup2;
+  }
+
   return 0;
 
  cleanup2:
@@ -1376,45 +1411,17 @@ qemu_supports (guestfs_h *g, const char *option)
   return g->qemu_help && strstr (g->qemu_help, option) != NULL;
 }
 
+/* You had to call this function after launch in versions <= 1.0.70,
+ * but it is now a no-op.
+ */
 int
 guestfs__wait_ready (guestfs_h *g)
 {
-  int r;
-  uint32_t size;
-  void *buf = NULL;
-
-  if (g->state == READY) return 0;
-
-  if (g->state == BUSY) {
-    error (g, _("qemu has finished launching already"));
-    return -1;
-  }
-
-  if (g->state != LAUNCHING) {
+  if (g->state != READY)  {
     error (g, _("qemu has not been launched yet"));
     return -1;
   }
 
-  r = recv_from_daemon (g, &size, &buf);
-  free (buf);
-
-  if (r == -1) return -1;
-
-  if (size != GUESTFS_LAUNCH_FLAG) {
-    error (g, _("guestfs_wait_ready failed, see earlier error messages"));
-    return -1;
-  }
-
-  /* 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"));
-    return -1;
-  }
-
   return 0;
 }