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