Add test for qemu broken -machine option (RHBZ#748266).
[libguestfs.git] / src / launch.c
index d6e99f7..7b3372c 100644 (file)
@@ -76,6 +76,7 @@ static int64_t timeval_diff (const struct timeval *x, const struct timeval *y);
 static void print_qemu_command_line (guestfs_h *g, char **argv);
 static int connect_unix_socket (guestfs_h *g, const char *sock);
 static int qemu_supports (guestfs_h *g, const char *option);
+static char *qemu_drive_param (guestfs_h *g, const struct drive *drv);
 
 #if 0
 static int qemu_supports_re (guestfs_h *g, const pcre *option_regex);
@@ -186,20 +187,8 @@ guestfs__debug_drives (guestfs_h *g)
 
   ret = safe_malloc (g, sizeof (char *) * (count + 1));
 
-  for (i = 0, drv = g->drives; drv; i++, drv = drv->next) {
-    size_t len = 64 + strlen (drv->path) + strlen (drv->iface);
-    if (drv->format) len += strlen (drv->format);
-
-    ret[i] = safe_malloc (g, len);
-
-    snprintf (ret[i], len, "file=%s%s%s%s%s,if=%s",
-              drv->path,
-              drv->readonly ? ",snapshot=on" : "",
-              drv->use_cache_off ? ",cache=off" : "",
-              drv->format ? ",format=" : "",
-              drv->format ? drv->format : "",
-              drv->iface);
-  }
+  for (i = 0, drv = g->drives; drv; i++, drv = drv->next)
+    ret[i] = qemu_drive_param (g, drv);
 
   ret[count] = NULL;
 
@@ -244,17 +233,21 @@ guestfs__config (guestfs_h *g,
  * O_DIRECT.  This fails on some filesystem types (notably tmpfs).
  * So we check if we can open the file with or without O_DIRECT,
  * and use cache=off (or not) accordingly.
+ *
+ * NB: This function is only called on the !readonly path.  We must
+ * try to open with O_RDWR to test that the file is readable and
+ * writable here.
  */
 static int
 test_cache_off (guestfs_h *g, const char *filename)
 {
-  int fd = open (filename, O_RDONLY|O_DIRECT);
+  int fd = open (filename, O_RDWR|O_DIRECT);
   if (fd >= 0) {
     close (fd);
     return 1;
   }
 
-  fd = open (filename, O_RDONLY);
+  fd = open (filename, O_RDWR);
   if (fd >= 0) {
     close (fd);
     return 0;
@@ -289,6 +282,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
   int readonly;
   char *format;
   char *iface;
+  char *name;
   int use_cache_off;
 
   if (strchr (filename, ',') != NULL) {
@@ -302,12 +296,15 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
            ? safe_strdup (g, optargs->format) : NULL;
   iface = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK
           ? safe_strdup (g, optargs->iface) : safe_strdup (g, DRIVE_IF);
+  name = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_NAME_BITMASK
+          ? safe_strdup (g, optargs->name) : NULL;
 
   if (format && !valid_format_iface (format)) {
     error (g, _("%s parameter is empty or contains disallowed characters"),
            "format");
     free (format);
     free (iface);
+    free (name);
     return -1;
   }
   if (!valid_format_iface (iface)) {
@@ -315,6 +312,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
            "iface");
     free (format);
     free (iface);
+    free (name);
     return -1;
   }
 
@@ -326,14 +324,16 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
   if (use_cache_off == -1) {
     free (format);
     free (iface);
+    free (name);
     return -1;
   }
 
   if (readonly) {
-    if (access (filename, F_OK) == -1) {
+    if (access (filename, R_OK) == -1) {
       perrorf (g, "%s", filename);
       free (format);
       free (iface);
+      free (name);
       return -1;
     }
   }
@@ -347,6 +347,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
   (*i)->readonly = readonly;
   (*i)->format = format;
   (*i)->iface = iface;
+  (*i)->name = name;
   (*i)->use_cache_off = use_cache_off;
 
   return 0;
@@ -564,25 +565,16 @@ launch_appliance (guestfs_h *g)
     g->cmdline[0] = g->qemu;
 
     /* Add drives */
-    struct drive *i = g->drives;
-    while (i != NULL) {
+    struct drive *drv = g->drives;
+    while (drv != NULL) {
       /* Construct the final -drive parameter. */
-      size_t len = 64 + strlen (i->path) + strlen (i->iface);
-      if (i->format) len += strlen (i->format);
-      char buf[len];
-
-      snprintf (buf, len, "file=%s%s%s%s%s,if=%s",
-                i->path,
-                i->readonly ? ",snapshot=on" : "",
-                i->use_cache_off ? ",cache=off" : "",
-                i->format ? ",format=" : "",
-                i->format ? i->format : "",
-                i->iface);
+      char *buf = qemu_drive_param (g, drv);
 
       add_cmdline (g, "-drive");
       add_cmdline (g, buf);
+      free (buf);
 
-      i = i->next;
+      drv = drv->next;
     }
 
     if (qemu_supports (g, "-nodefconfig"))
@@ -594,7 +586,19 @@ launch_appliance (guestfs_h *g)
      */
     if (qemu_supports (g, "-machine")) {
       add_cmdline (g, "-machine");
+#if QEMU_MACHINE_TYPE_IS_BROKEN
+      /* Workaround for qemu 0.15: We have to add the '[type=]pc'
+       * since there is no default.  This is not a permanent solution
+       * because this only works on PC-like hardware.  Other platforms
+       * like ppc would need a different machine type.
+       *
+       * This bug is fixed in qemu commit 2645c6dcaf6ea2a51a, and was
+       * not a problem in qemu < 0.15.
+       */
+      add_cmdline (g, "pc,accel=kvm:tcg");
+#else
       add_cmdline (g, "accel=kvm:tcg");
+#endif
     } else {
       /* qemu sometimes needs this option to enable hardware
        * virtualization, but some versions of 'qemu-kvm' will use KVM
@@ -865,6 +869,13 @@ launch_appliance (guestfs_h *g)
   if (r == -1)
     goto cleanup1;
 
+  /* NB: We reach here just because qemu has opened the socket.  It
+   * does not mean the daemon is up until we read the
+   * GUESTFS_LAUNCH_FLAG below.  Failures in qemu startup can still
+   * happen even if we reach here, even early failures like not being
+   * able to open a drive.
+   */
+
   close (g->sock); /* Close the listening socket. */
   g->sock = r; /* This is the accepted data socket. */
 
@@ -1273,6 +1284,30 @@ is_openable (guestfs_h *g, const char *path, int flags)
   return 1;
 }
 
+static char *
+qemu_drive_param (guestfs_h *g, const struct drive *drv)
+{
+  size_t len = 64;
+  char *r;
+
+  len += strlen (drv->path);
+  len += strlen (drv->iface);
+  if (drv->format)
+    len += strlen (drv->format);
+
+  r = safe_malloc (g, len);
+
+  snprintf (r, len, "file=%s%s%s%s%s,if=%s",
+            drv->path,
+            drv->readonly ? ",snapshot=on" : "",
+            drv->use_cache_off ? ",cache=off" : "",
+            drv->format ? ",format=" : "",
+            drv->format ? drv->format : "",
+            drv->iface);
+
+  return r;                     /* caller frees */
+}
+
 /* You had to call this function after launch in versions <= 1.0.70,
  * but it is now a no-op.
  */