blkid: Use -c /dev/null option to kill the cache.
[libguestfs.git] / src / launch.c
index 48ddb8d..3e46e8f 100644 (file)
@@ -1,5 +1,5 @@
 /* libguestfs
- * Copyright (C) 2009-2010 Red Hat Inc.
+ * Copyright (C) 2009-2011 Red Hat Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -70,6 +70,8 @@
 #include "guestfs-internal-actions.h"
 #include "guestfs_protocol.h"
 
+static int launch_appliance (guestfs_h *g);
+static int64_t timeval_diff (const struct timeval *x, const struct timeval *y);
 static int qemu_supports (guestfs_h *g, const char *option);
 
 /* Add a string to the current command line. */
@@ -120,6 +122,30 @@ guestfs___rollback_cmdline (guestfs_h *g, int pos)
   g->cmdline_size = pos;
 }
 
+/* Internal command to return the command line. */
+char **
+guestfs__debug_cmdline (guestfs_h *g)
+{
+  int i;
+  char **r;
+
+  if (g->cmdline == NULL) {
+    r = safe_malloc (g, sizeof (char *) * 1);
+    r[0] = NULL;
+    return r;
+  }
+
+  r = safe_malloc (g, sizeof (char *) * (g->cmdline_size + 1));
+  r[0] = safe_strdup (g, g->qemu); /* g->cmdline[0] is always NULL */
+
+  for (i = 1; i < g->cmdline_size; ++i)
+    r[i] = safe_strdup (g, g->cmdline[i]);
+
+  r[g->cmdline_size] = NULL;
+
+  return r;                     /* caller frees */
+}
+
 int
 guestfs__config (guestfs_h *g,
                  const char *qemu_param, const char *qemu_value)
@@ -326,33 +352,19 @@ static int is_openable (guestfs_h *g, const char *path, int flags);
 int
 guestfs__launch (guestfs_h *g)
 {
-  int r;
-  int wfd[2], rfd[2];
-  int tries;
-  char unixsock[256];
-  struct sockaddr_un addr;
-
   /* Configured? */
-  if (!g->cmdline) {
-    error (g, _("you must call guestfs_add_drive before guestfs_launch"));
-    return -1;
-  }
-
   if (g->state != CONFIG) {
     error (g, _("the libguestfs handle has already been launched"));
     return -1;
   }
 
-  /* Start the clock ... */
-  gettimeofday (&g->launch_t, NULL);
-
   /* Make the temporary directory. */
   if (!g->tmpdir) {
     TMP_TEMPLATE_ON_STACK (dir_template);
     g->tmpdir = safe_strdup (g, dir_template);
     if (mkdtemp (g->tmpdir) == NULL) {
       perrorf (g, _("%s: cannot create temporary directory"), dir_template);
-      goto cleanup0;
+      return -1;
     }
   }
 
@@ -363,6 +375,28 @@ guestfs__launch (guestfs_h *g)
   if (chmod (g->tmpdir, 0755) == -1)
     fprintf (stderr, "chmod: %s: %m (ignored)\n", g->tmpdir);
 
+  return launch_appliance (g);
+}
+
+static int
+launch_appliance (guestfs_h *g)
+{
+  int r;
+  int wfd[2], rfd[2];
+  char guestfsd_sock[256];
+  struct sockaddr_un addr;
+
+  /* At present you must add drives before starting the appliance.  In
+   * future when we enable hotplugging you won't need to do this.
+   */
+  if (!g->cmdline) {
+    error (g, _("you must call guestfs_add_drive before guestfs_launch"));
+    return -1;
+  }
+
+  /* Start the clock ... */
+  gettimeofday (&g->launch_t, NULL);
+
   /* Locate and/or build the appliance. */
   char *kernel = NULL, *initrd = NULL, *appliance = NULL;
   if (guestfs___build_appliance (g, &kernel, &initrd, &appliance) == -1)
@@ -378,8 +412,8 @@ guestfs__launch (guestfs_h *g)
   /* Using virtio-serial, we need to create a local Unix domain socket
    * for qemu to connect to.
    */
-  snprintf (unixsock, sizeof unixsock, "%s/sock", g->tmpdir);
-  unlink (unixsock);
+  snprintf (guestfsd_sock, sizeof guestfsd_sock, "%s/guestfsd.sock", g->tmpdir);
+  unlink (guestfsd_sock);
 
   g->sock = socket (AF_UNIX, SOCK_STREAM, 0);
   if (g->sock == -1) {
@@ -393,7 +427,7 @@ guestfs__launch (guestfs_h *g)
   }
 
   addr.sun_family = AF_UNIX;
-  strncpy (addr.sun_path, unixsock, UNIX_PATH_MAX);
+  strncpy (addr.sun_path, guestfsd_sock, UNIX_PATH_MAX);
   addr.sun_path[UNIX_PATH_MAX-1] = '\0';
 
   if (bind (g->sock, &addr, sizeof addr) == -1) {
@@ -502,7 +536,7 @@ guestfs__launch (guestfs_h *g)
 
     /* Set up virtio-serial for the communications channel. */
     add_cmdline (g, "-chardev");
-    snprintf (buf, sizeof buf, "socket,path=%s,id=channel0", unixsock);
+    snprintf (buf, sizeof buf, "socket,path=%s,id=channel0", guestfsd_sock);
     add_cmdline (g, buf);
     add_cmdline (g, "-device");
     add_cmdline (g, "virtserialport,chardev=channel0,name=org.libguestfs.channel.0");
@@ -568,17 +602,27 @@ guestfs__launch (guestfs_h *g)
       guestfs___print_timestamped_argv (g, (const char **)g->cmdline);
 
     if (!g->direct) {
-      /* Set up stdin, stdout. */
+      /* Set up stdin, stdout, stderr. */
       close (0);
       close (1);
       close (wfd[1]);
       close (rfd[0]);
 
+      /* Stdin. */
       if (dup (wfd[0]) == -1) {
       dup_failed:
         perror ("dup failed");
         _exit (EXIT_FAILURE);
       }
+      /* Stdout. */
+      if (dup (rfd[1]) == -1)
+        goto dup_failed;
+
+      /* Particularly since qemu 0.15, qemu spews all sorts of debug
+       * information on stderr.  It is useful to both capture this and
+       * not confuse casual users, so send stderr to the pipe as well.
+       */
+      close (2);
       if (dup (rfd[1]) == -1)
         goto dup_failed;
 
@@ -725,7 +769,7 @@ guestfs__launch (guestfs_h *g)
   }
   if (g->pid > 0) kill (g->pid, 9);
   if (g->recoverypid > 0) kill (g->recoverypid, 9);
-  waitpid (g->pid, NULL, 0);
+  if (g->pid > 0) waitpid (g->pid, NULL, 0);
   if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0);
   g->fd[0] = -1;
   g->fd[1] = -1;