Mac OS X: define MAX macro if not already defined.
[libguestfs.git] / src / guestfs.c
index 0e91b96..a00e8db 100644 (file)
@@ -33,6 +33,7 @@
 #include <sys/stat.h>
 #include <sys/select.h>
 #include <dirent.h>
+#include <signal.h>
 
 #include <rpc/types.h>
 #include <rpc/xdr.h>
@@ -91,9 +92,14 @@ static int recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn);
 static int accept_from_daemon (guestfs_h *g);
 static int check_peer_euid (guestfs_h *g, int sock, uid_t *rtn);
 static void close_handles (void);
+static int qemu_supports (guestfs_h *g, const char *option);
 
 #define UNIX_PATH_MAX 108
 
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
 /* Also in guestfsd.c */
 #define GUESTFWD_ADDR "10.0.2.4"
 #define GUESTFWD_PORT "6666"
@@ -791,9 +797,6 @@ int
 guestfs__add_drive_ro_with_if (guestfs_h *g, const char *filename,
                                const char *drive_if)
 {
-  size_t len = strlen (filename) + 64;
-  char buf[len];
-
   if (strchr (filename, ',') != NULL) {
     error (g, _("filename cannot contain ',' (comma) character"));
     return -1;
@@ -804,7 +807,24 @@ guestfs__add_drive_ro_with_if (guestfs_h *g, const char *filename,
     return -1;
   }
 
-  snprintf (buf, len, "file=%s,snapshot=on,if=%s", filename, drive_if);
+  if (qemu_supports (g, NULL) == -1)
+    return -1;
+
+  /* Only SCSI and virtio drivers support readonly mode.
+   * This is only supported as a QEMU feature since 2010/01.
+   */
+  int supports_ro = 0;
+  if ((STREQ (drive_if, "scsi") || STREQ (drive_if, "virtio")) &&
+      qemu_supports (g, "readonly=on"))
+    supports_ro = 1;
+
+  size_t len = strlen (filename) + 100;
+  char buf[len];
+
+  snprintf (buf, len, "file=%s,snapshot=on,%sif=%s",
+            filename,
+            supports_ro ? "readonly=on," : "",
+            drive_if);
 
   return guestfs__config (g, "-drive", buf);
 }
@@ -870,8 +890,6 @@ dir_contains_files (const char *dir, ...)
 
 static void print_timestamped_message (guestfs_h *g, const char *fs, ...);
 static int build_supermin_appliance (guestfs_h *g, const char *path, char **kernel, char **initrd);
-static int test_qemu (guestfs_h *g);
-static int qemu_supports (guestfs_h *g, const char *option);
 static int is_openable (guestfs_h *g, const char *path, int flags);
 static void print_cmdline (guestfs_h *g);
 
@@ -1023,7 +1041,7 @@ guestfs__launch (guestfs_h *g)
     print_timestamped_message (g, "begin testing qemu features");
 
   /* Get qemu help text and version. */
-  if (test_qemu (g) == -1)
+  if (qemu_supports (g, NULL) == -1)
     goto cleanup0;
 
   /* Choose which vmchannel implementation to use. */
@@ -1537,8 +1555,9 @@ build_supermin_appliance (guestfs_h *g, const char *path,
 
   snprintf (cmd, sizeof cmd,
             "PATH='%s':$PATH "
-            "libguestfs-supermin-helper '%s' " host_cpu " " REPO " %s %s",
+            "libguestfs-supermin-helper%s '%s' " host_cpu " " REPO " %s %s",
             path,
+            g->verbose ? " --verbose" : "",
             path, *kernel, *initrd);
   if (g->verbose)
     print_timestamped_message (g, "%s", cmd);
@@ -1606,12 +1625,7 @@ 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, "LC_ALL=C '%s' -help", g->qemu);
+  snprintf (cmd, sizeof cmd, "LC_ALL=C '%s' -nographic -help", g->qemu);
 
   fp = popen (cmd, "r");
   /* qemu -help should always work (qemu -version OTOH wasn't
@@ -1633,7 +1647,8 @@ test_qemu (guestfs_h *g)
   if (pclose (fp) == -1)
     goto error;
 
-  snprintf (cmd, sizeof cmd, "LC_ALL=C '%s' -version 2>/dev/null", g->qemu);
+  snprintf (cmd, sizeof cmd, "LC_ALL=C '%s' -nographic -version 2>/dev/null",
+           g->qemu);
 
   fp = popen (cmd, "r");
   if (fp) {
@@ -1671,11 +1686,26 @@ read_all (guestfs_h *g, FILE *fp, char **ret)
 
 /* Test if option is supported by qemu command line (just by grepping
  * the help text).
+ *
+ * The first time this is used, it has to run the external qemu
+ * binary.  If that fails, it returns -1.
+ *
+ * To just do the first-time run of the qemu binary, call this with
+ * option == NULL, in which case it will return -1 if there was an
+ * error doing that.
  */
 static int
 qemu_supports (guestfs_h *g, const char *option)
 {
-  return g->qemu_help && strstr (g->qemu_help, option) != NULL;
+  if (!g->qemu_help) {
+    if (test_qemu (g) == -1)
+      return -1;
+  }
+
+  if (option == NULL)
+    return 1;
+
+  return strstr (g->qemu_help, option) != NULL;
 }
 
 /* Check if a file can be opened. */