New event API (RHBZ#664558).
[libguestfs.git] / src / launch.c
index 775f7a6..261136d 100644 (file)
@@ -71,6 +71,7 @@
 #include "guestfs_protocol.h"
 
 static int launch_appliance (guestfs_h *g);
+static int connect_unix_socket (guestfs_h *g, const char *sock);
 static int qemu_supports (guestfs_h *g, const char *option);
 
 /* Add a string to the current command line. */
@@ -372,9 +373,19 @@ guestfs__launch (guestfs_h *g)
    * want. (RHBZ#610880).
    */
   if (chmod (g->tmpdir, 0755) == -1)
-    fprintf (stderr, "chmod: %s: %m (ignored)\n", g->tmpdir);
+    warning (g, "chmod: %s: %m (ignored)", g->tmpdir);
 
-  return launch_appliance (g);
+  /* Launch the appliance or attach to an existing daemon. */
+  switch (g->attach_method) {
+  case ATTACH_METHOD_APPLIANCE:
+    return launch_appliance (g);
+
+  case ATTACH_METHOD_UNIX:
+    return connect_unix_socket (g, g->attach_method_arg);
+
+  default:
+    abort ();
+  }
 }
 
 static int
@@ -758,7 +769,7 @@ launch_appliance (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;
@@ -778,6 +789,78 @@ launch_appliance (guestfs_h *g)
   return -1;
 }
 
+/* Alternate attach method: instead of launching the appliance,
+ * connect to an existing unix socket.
+ */
+static int
+connect_unix_socket (guestfs_h *g, const char *sockpath)
+{
+  int r;
+  struct sockaddr_un addr;
+
+  /* Start the clock ... */
+  gettimeofday (&g->launch_t, NULL);
+
+  /* Set these to nothing so we don't try to kill random processes or
+   * read from random file descriptors.
+   */
+  g->pid = 0;
+  g->recoverypid = 0;
+  g->fd[0] = -1;
+  g->fd[1] = -1;
+
+  if (g->verbose)
+    guestfs___print_timestamped_message (g, "connecting to %s", sockpath);
+
+  g->sock = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (g->sock == -1) {
+    perrorf (g, "socket");
+    return -1;
+  }
+
+  addr.sun_family = AF_UNIX;
+  strncpy (addr.sun_path, sockpath, UNIX_PATH_MAX);
+  addr.sun_path[UNIX_PATH_MAX-1] = '\0';
+
+  g->state = LAUNCHING;
+
+  if (connect (g->sock, &addr, sizeof addr) == -1) {
+    perrorf (g, "bind");
+    goto cleanup;
+  }
+
+  if (fcntl (g->sock, F_SETFL, O_NONBLOCK) == -1) {
+    perrorf (g, "fcntl");
+    goto cleanup;
+  }
+
+  uint32_t size;
+  void *buf = NULL;
+  r = guestfs___recv_from_daemon (g, &size, &buf);
+  free (buf);
+
+  if (r == -1) return -1;
+
+  if (size != GUESTFS_LAUNCH_FLAG) {
+    error (g, _("guestfs_launch failed, unexpected initial message from guestfsd"));
+    goto cleanup;
+  }
+
+  if (g->verbose)
+    guestfs___print_timestamped_message (g, "connected");
+
+  if (g->state != READY) {
+    error (g, _("contacted guestfsd, but state != READY"));
+    goto cleanup;
+  }
+
+  return 0;
+
+ cleanup:
+  close (g->sock);
+  return -1;
+}
+
 /* Return the location of the tmpdir (eg. "/tmp") and allow users
  * to override it at runtime using $TMPDIR.
  * http://www.pathname.com/fhs/pub/fhs-2.3.html#TMPTEMPORARYFILES
@@ -835,27 +918,40 @@ guestfs___print_timestamped_argv (guestfs_h *g, const char * argv[])
 {
   int i = 0;
   int needs_quote;
+  char *buf = NULL;
+  size_t len;
+  FILE *fp;
+
+  fp = open_memstream (&buf, &len);
+  if (fp == NULL) {
+    warning (g, "open_memstream: %m");
+    return;
+  }
 
   struct timeval tv;
   gettimeofday (&tv, NULL);
-  fprintf (stderr, "[%05" PRIi64 "ms] ", timeval_diff (&g->launch_t, &tv));
+  fprintf (fp, "[%05" PRIi64 "ms] ", timeval_diff (&g->launch_t, &tv));
 
   while (argv[i]) {
     if (argv[i][0] == '-') /* -option starts a new line */
-      fprintf (stderr, " \\\n   ");
+      fprintf (fp, " \\\n   ");
 
-    if (i > 0) fputc (' ', stderr);
+    if (i > 0) fputc (' ', fp);
 
     /* Does it need shell quoting?  This only deals with simple cases. */
     needs_quote = strcspn (argv[i], " ") != strlen (argv[i]);
 
-    if (needs_quote) fputc ('\'', stderr);
-    fprintf (stderr, "%s", argv[i]);
-    if (needs_quote) fputc ('\'', stderr);
+    if (needs_quote) fputc ('\'', fp);
+    fprintf (fp, "%s", argv[i]);
+    if (needs_quote) fputc ('\'', fp);
     i++;
   }
 
-  fputc ('\n', stderr);
+  fclose (fp);
+
+  debug (g, "%s", buf);
+
+  free (buf);
 }
 
 void
@@ -874,8 +970,7 @@ guestfs___print_timestamped_message (guestfs_h *g, const char *fs, ...)
 
   gettimeofday (&tv, NULL);
 
-  fprintf (stderr, "[%05" PRIi64 "ms] %s\n",
-           timeval_diff (&g->launch_t, &tv), msg);
+  debug (g, "[%05" PRIi64 "ms] %s", timeval_diff (&g->launch_t, &tv), msg);
 
   free (msg);
 }
@@ -981,8 +1076,7 @@ is_openable (guestfs_h *g, const char *path, int flags)
 {
   int fd = open (path, flags);
   if (fd == -1) {
-    if (g->verbose)
-      perror (path);
+    debug (g, "is_openable: %s: %m", path);
     return 0;
   }
   close (fd);
@@ -1011,8 +1105,7 @@ guestfs__kill_subprocess (guestfs_h *g)
     return -1;
   }
 
-  if (g->verbose)
-    fprintf (stderr, "sending SIGTERM to process %d\n", g->pid);
+  debug (g, "sending SIGTERM to process %d", g->pid);
 
   if (g->pid > 0) kill (g->pid, SIGTERM);
   if (g->recoverypid > 0) kill (g->recoverypid, 9);