[Libguestfs] [PATCH 2/3] Allow connecting to an externally spawned QEMU + appliance

Daniel P. Berrange berrange at redhat.com
Mon Jul 5 16:26:00 UTC 2010


This introduces 2 new API calls to allow connecting to an
externally spawned QEMU + appliance. The default behaviour
remains unchanged, and can be altered by running

   guestfs_set_launch_method(g, "attach");
   guestfs_set_sockpath(g, "/path/to/unix/socket");

Or in guestfish

   launch-method attach
   sockpath /path/to/unix/socket

The unix socket must point to a QEMU chardev connected to
the guest daemon.  The 'sockpath' also has effect when using
the default 'spawn' method, preventing the use of the tmpdir
for the socket.
---
 src/generator.ml |   50 ++++++++++++++++++++++++
 src/guestfs.c    |  110 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 153 insertions(+), 7 deletions(-)

diff --git a/src/generator.ml b/src/generator.ml
index d640343..641973a 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -610,6 +610,56 @@ Return the current qemu binary.
 This is always non-NULL.  If it wasn't set already, then this will
 return the default qemu binary name.");
 
+  ("set_launch_method", (RErr, [OptString "methodvalue"]), -1, [FishAlias "launch-method"],
+   [],
+   "set the appliance launch method",
+   "\
+Set the appliance launch method that we will use.
+
+Valid methods are
+
+ * spawn:  spawn a QEMU process for the appliance (default)
+ * attach: attach to existing QEMU over a UNIX socket
+
+You can also override this by setting the C<LIBGUESTFS_METHOD>
+environment variable.
+
+Setting C<method> to C<NULL> restores the default launch method.");
+
+  ("get_launch_method", (RConstString "methodvalue", []), -1, [],
+   [InitNone, Always, TestRun (
+      [["get_launch_method"]])],
+   "get the appliance launch method",
+   "\
+Return the appliance launch method.
+
+This is always non-NULL. If it wasn't set already, then this will
+return the default method.");
+
+  ("set_sockpath", (RErr, [OptString "sockpath"]), -1, [FishAlias "sockpath"],
+   [],
+   "set the UNIX domain socket path",
+   "\
+Set the UNIX domain socket path that we will use.
+
+The default is a file in a randomly named temporary directory.
+
+You can also override this by setting the C<LIBGUESTFS_SOCKPATH>
+environment variable.
+
+Setting C<sockpath> to C<NULL> restores the default UNIX domain
+socket path.");
+
+  ("get_sockpath", (RConstString "sockpath", []), -1, [],
+   [InitNone, Always, TestRun (
+      [["get_sockpath"]])],
+   "get the UNIX domain socket path",
+   "\
+Return the current UNIX domain socket path.
+
+This is NULL if a random temporary directory is to be used,
+otherwise it returns the configured socket path.");
+
   ("set_path", (RErr, [OptString "searchpath"]), -1, [FishAlias "path"],
    [],
    "set the search path",
diff --git a/src/guestfs.c b/src/guestfs.c
index 6e9947f..29636cc 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -133,6 +133,11 @@ static int qemu_supports (guestfs_h *g, const char *option);
 #define GUESTFWD_ADDR "169.254.2.4"
 #define GUESTFWD_PORT "6666"
 
+
+#define GUESTFS_LAUNCH_METHOD_SPAWN "spawn"
+#define GUESTFS_LAUNCH_METHOD_ATTACH "attach"
+
+
 /* GuestFS handle and connection. */
 enum state { CONFIG, LAUNCHING, READY, BUSY, NO_HANDLE };
 
@@ -163,6 +168,8 @@ struct guestfs_h
   int direct;
   int recovery_proc;
 
+  char *method;                 /* Appliance launch method */
+  char *sockpath;               /* Path to UNIX socket */
   char *path;			/* Path to kernel, initrd. */
   char *qemu;			/* Qemu binary. */
   char *append;			/* Append to kernel command line. */
@@ -226,6 +233,14 @@ guestfs_create (void)
   g->path = str != NULL ? strdup (str) : strdup (GUESTFS_DEFAULT_PATH);
   if (!g->path) goto error;
 
+  str = getenv ("LIBGUESTFS_METHOD");
+  g->method = str != NULL ? strdup (str) : strdup (GUESTFS_LAUNCH_METHOD_SPAWN);
+  if (!g->method) goto error;
+
+  str = getenv ("LIBGUESTFS_SOCKPATH");
+  g->sockpath = str != NULL ? strdup (str) : NULL;
+  if (str && !g->sockpath) goto error;
+
   str = getenv ("LIBGUESTFS_QEMU");
   g->qemu = str != NULL ? strdup (str) : strdup (QEMU);
   if (!g->qemu) goto error;
@@ -365,6 +380,8 @@ guestfs_close (guestfs_h *g)
   gl_lock_unlock (handles_lock);
 
   free (g->last_error);
+  free (g->method);
+  free (g->sockpath);
   free (g->path);
   free (g->qemu);
   free (g->append);
@@ -611,6 +628,38 @@ guestfs__get_path (guestfs_h *g)
 }
 
 int
+guestfs__set_launch_method (guestfs_h *g, const char *value)
+{
+  free (g->method);
+
+  g->method = value == NULL ?
+    safe_strdup (g, GUESTFS_LAUNCH_METHOD_SPAWN) :
+    safe_strdup (g, value);
+  return 0;
+}
+
+const char *
+guestfs__get_launch_method (guestfs_h *g)
+{
+  return g->method;
+}
+
+int
+guestfs__set_sockpath (guestfs_h *g, const char *sockpath)
+{
+  free (g->sockpath);
+
+  g->sockpath = sockpath == NULL ? NULL : safe_strdup (g, sockpath);
+  return 0;
+}
+
+const char *
+guestfs__get_sockpath (guestfs_h *g)
+{
+  return g->sockpath;
+}
+
+int
 guestfs__set_qemu (guestfs_h *g, const char *qemu)
 {
   free (g->qemu);
@@ -1071,7 +1120,7 @@ guestfs__connect_handshake(guestfs_h *g)
 }
 
 int
-guestfs__launch (guestfs_h *g)
+guestfs__launch_spawn (guestfs_h *g)
 {
   const char *tmpdir;
   char dir_template[PATH_MAX];
@@ -1090,11 +1139,6 @@ guestfs__launch (guestfs_h *g)
     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);
 
@@ -1255,7 +1299,10 @@ guestfs__launch (guestfs_h *g)
     /* Using some vmchannel impl.  We need to create a local Unix
      * domain socket for qemu to use.
      */
-    snprintf (unixsock, sizeof unixsock, "%s/sock", g->tmpdir);
+    if (g->sockpath)
+      snprintf (unixsock, sizeof unixsock, "%s", g->sockpath);
+    else
+      snprintf (unixsock, sizeof unixsock, "%s/sock", g->tmpdir);
     unlink (unixsock);
     null_vmchannel_sock = 0;
   }
@@ -1577,6 +1624,50 @@ guestfs__launch (guestfs_h *g)
   return -1;
 }
 
+
+int
+guestfs__launch_attach (guestfs_h *g)
+{
+  if (!g->sockpath) {
+    error (g, _("no socket path specified with launch method '%s'"), g->method);
+    return -1;
+  }
+
+  if (guestfs__connect_unix (g, g->sockpath) < 0)
+    goto cleanup0;
+
+  if (guestfs__connect_handshake (g) < 0)
+    goto cleanup0;
+
+  return 0;
+
+ cleanup0:
+  if (g->sock >= 0) {
+    close (g->sock);
+    g->sock = -1;
+  }
+  g->state = CONFIG;
+  return -1;
+}
+
+
+int
+guestfs__launch (guestfs_h *g)
+{
+  if (g->state != CONFIG) {
+    error (g, _("the libguestfs handle has already been launched"));
+    return -1;
+  }
+
+  if (strcmp(g->method, GUESTFS_LAUNCH_METHOD_ATTACH) == 0)
+    return guestfs__launch_attach (g);
+  else if (strcmp(g->method, GUESTFS_LAUNCH_METHOD_SPAWN) == 0)
+    return guestfs__launch_spawn (g);
+
+  error (g, "unknown launch method '%s'", g->method);
+  return -1;
+}
+
 /* This function is used to print the qemu command line before it gets
  * executed, when in verbose mode.
  */
@@ -1905,6 +1996,11 @@ guestfs__kill_subprocess (guestfs_h *g)
     return -1;
   }
 
+  if (strcmp(g->method, GUESTFS_LAUNCH_METHOD_SPAWN) != 0) {
+    error (g, _("cannot kill subprocess with launch method '%s'"), g->method);
+    return -1;
+  }
+
   if (g->verbose)
     fprintf (stderr, "sending SIGTERM to process %d\n", g->pid);
 
-- 
1.6.6.1




More information about the Libguestfs mailing list