Don't stash strings in the handle.
[libguestfs.git] / src / guestfs.c
index 9fd943f..b30ade0 100644 (file)
@@ -158,8 +158,9 @@ struct guestfs_h
   int verbose;
   int autosync;
 
-  const char *path;
-  const char *qemu;
+  char *path;                  /* Path to kernel, initrd. */
+  char *qemu;                  /* Qemu binary. */
+  char *append;                        /* Append to kernel command line. */
 
   char *last_error;
 
@@ -220,10 +221,18 @@ guestfs_create (void)
   g->verbose = str != NULL && strcmp (str, "1") == 0;
 
   str = getenv ("LIBGUESTFS_PATH");
-  g->path = str != NULL ? str : GUESTFS_DEFAULT_PATH;
+  g->path = str != NULL ? strdup (str) : strdup (GUESTFS_DEFAULT_PATH);
+  if (!g->path) goto error;
 
   str = getenv ("LIBGUESTFS_QEMU");
-  g->qemu = str != NULL ? str : QEMU;
+  g->qemu = str != NULL ? strdup (str) : strdup (QEMU);
+  if (!g->qemu) goto error;
+
+  str = getenv ("LIBGUESTFS_APPEND");
+  if (str) {
+    g->append = strdup (str);
+    if (!g->append) goto error;
+  }
 
   g->main_loop = guestfs_get_default_main_loop ();
 
@@ -248,6 +257,13 @@ guestfs_create (void)
     fprintf (stderr, "new guestfs handle %p\n", g);
 
   return g;
+
+ error:
+  free (g->path);
+  free (g->qemu);
+  free (g->append);
+  free (g);
+  return NULL;
 }
 
 void
@@ -311,6 +327,9 @@ guestfs_close (guestfs_h *g)
   free (g->msg_in);
   free (g->msg_out);
   free (g->last_error);
+  free (g->path);
+  free (g->qemu);
+  free (g->append);
   free (g);
 }
 
@@ -511,10 +530,12 @@ guestfs_get_autosync (guestfs_h *g)
 int
 guestfs_set_path (guestfs_h *g, const char *path)
 {
-  if (path == NULL)
-    g->path = GUESTFS_DEFAULT_PATH;
-  else
-    g->path = path;
+  free (g->path);
+  g->path = NULL;
+
+  g->path =
+    path == NULL ?
+    safe_strdup (g, GUESTFS_DEFAULT_PATH) : safe_strdup (g, path);
   return 0;
 }
 
@@ -527,10 +548,10 @@ guestfs_get_path (guestfs_h *g)
 int
 guestfs_set_qemu (guestfs_h *g, const char *qemu)
 {
-  if (qemu == NULL)
-    g->qemu = QEMU;
-  else
-    g->qemu = qemu;
+  free (g->qemu);
+  g->qemu = NULL;
+
+  g->qemu = qemu == NULL ? safe_strdup (g, QEMU) : safe_strdup (g, qemu);
   return 0;
 }
 
@@ -540,6 +561,22 @@ guestfs_get_qemu (guestfs_h *g)
   return g->qemu;
 }
 
+int
+guestfs_set_append (guestfs_h *g, const char *append)
+{
+  free (g->append);
+  g->append = NULL;
+
+  g->append = append ? safe_strdup (g, append) : NULL;
+  return 0;
+}
+
+const char *
+guestfs_get_append (guestfs_h *g)
+{
+  return g->append;
+}
+
 /* Add a string to the current command line. */
 static void
 incr_cmdline_size (guestfs_h *g)
@@ -755,7 +792,7 @@ guestfs_launch (guestfs_h *g)
     /* Set up the full command line.  Do this in the subprocess so we
      * don't need to worry about cleaning up.
      */
-    g->cmdline[0] = (char *) g->qemu;
+    g->cmdline[0] = g->qemu;
 
     /* Construct the -net channel parameter for qemu. */
     snprintf (vmchannel, sizeof vmchannel,
@@ -764,9 +801,10 @@ guestfs_launch (guestfs_h *g)
 
     /* Linux kernel command line. */
     snprintf (append, sizeof append,
-             "panic=1 console=ttyS0 guestfs=%s:%d%s",
+             "panic=1 console=ttyS0 guestfs=%s:%d%s%s%s",
              VMCHANNEL_ADDR, VMCHANNEL_PORT,
-             g->verbose ? " guestfs_verbose=1" : "");
+             g->verbose ? " guestfs_verbose=1" : "",
+             g->append ? " " : "", g->append ? g->append : "");
 
     snprintf (memsize_str, sizeof memsize_str, "%d", memsize);
 
@@ -906,10 +944,9 @@ guestfs_launch (guestfs_h *g)
   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) {
-    /* Always sleep at least once to give qemu a small chance to start up. */
-    usleep (10000);
-
     r = connect (g->sock, (struct sockaddr *) &addr, sizeof addr);
     if ((r == -1 && errno == EINPROGRESS) || r == 0)
       goto connected;
@@ -917,6 +954,7 @@ guestfs_launch (guestfs_h *g)
     if (errno != ENOENT)
       perrorf (g, "connect");
     tries--;
+    usleep (100000);
   }
 
   error (g, "failed to connect to vmchannel socket");
@@ -2175,6 +2213,8 @@ select_main_loop_run (guestfs_main_loop *mlv, guestfs_h *g)
     xset2 = ml->xset;
     r = select (ml->max_fd+1, &rset2, &wset2, &xset2, NULL);
     if (r == -1) {
+      if (errno == EINTR || errno == EAGAIN)
+       continue;
       perrorf (g, "select");
       ml->is_running = 0;
       return -1;