To facilitate apps which want to run QEMU themselves, provide
new APIs for locating the appliance and querying the associated
kernel/initrd paths.
<fs> find-appliance
<fs> get-kernel
/tmp/libguestfsJYEam9/kernel
<fs> get-initrd
/tmp/libguestfsJYEam9/initrd
Now boot a QEMU pointing at these initrd/kernel images
and attach to it
<fs> launch-method attach
<fs> sockpath /tmp/guest/sock
<fs> launch
The method for locating the appliance may create temporary
files. These will be deleted when the guestfs handle is
closed.
---
src/generator.ml | 29 +++++++++++
src/guestfs.c | 139 ++++++++++++++++++++++++++++++++++--------------------
2 files changed, 117 insertions(+), 51 deletions(-)
diff --git a/src/generator.ml b/src/generator.ml
index 641973a..41f8014 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -458,6 +458,15 @@ using L<qemu(1)>.
You should call this after configuring the handle
(eg. adding drives) but before performing any actions.");
+ ("find_appliance", (RErr, []), -1, [FishAlias "find_appliance"],
+ [],
+ "find the appliance kernel/initrd",
+ "\
+Find the guest daemon appliance kernel and initrd images.
+
+This prefers to build a super-min appliance, but falls
+back to a traditional appliance if the former was not found.");
+
("wait_ready", (RErr, []), -1, [NotInFish],
[],
"wait until the qemu subprocess launches (no op)",
@@ -660,6 +669,26 @@ 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.");
+ ("get_kernel", (RConstString "kernel", []), -1, [],
+ [InitNone, Always, TestRun (
+ [["get_kernel"]])],
+ "get the appliance kernel path",
+ "\
+Return the appliance kernel path.
+
+This is NULL if the kernel has not yet been located,
+otherwise it returns the kernel path.");
+
+ ("get_initrd", (RConstString "initrd", []), -1, [],
+ [InitNone, Always, TestRun (
+ [["get_initrd"]])],
+ "get the appliance initrd path",
+ "\
+Return the current appliance initrd path.
+
+This is NULL if the initrd has not yet been located,
+otherwise it returns the initrd path.");
+
("set_path", (RErr, [OptString "searchpath"]), -1, [FishAlias
"path"],
[],
"set the search path",
diff --git a/src/guestfs.c b/src/guestfs.c
index 29636cc..850dc9a 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -170,7 +170,9 @@ struct guestfs_h
char *method; /* Appliance launch method */
char *sockpath; /* Path to UNIX socket */
- char *path; /* Path to kernel, initrd. */
+ char *kernel; /* Path to kernel */
+ char *initrd; /* Path to initrd */
+ char *path; /* Search path to locate kernel, initrd. */
char *qemu; /* Qemu binary. */
char *append; /* Append to kernel command line. */
@@ -383,6 +385,8 @@ guestfs_close (guestfs_h *g)
free (g->method);
free (g->sockpath);
free (g->path);
+ free (g->initrd);
+ free (g->kernel);
free (g->qemu);
free (g->append);
free (g->qemu_help);
@@ -659,6 +663,18 @@ guestfs__get_sockpath (guestfs_h *g)
return g->sockpath;
}
+const char *
+guestfs__get_kernel (guestfs_h *g)
+{
+ return g->kernel;
+}
+
+const char *
+guestfs__get_initrd (guestfs_h *g)
+{
+ return g->initrd;
+}
+
int
guestfs__set_qemu (guestfs_h *g, const char *qemu)
{
@@ -977,7 +993,7 @@ dir_contains_files (const char *dir, ...)
}
static void print_timestamped_message (guestfs_h *g, const char *fs, ...);
-static int build_supermin_appliance (guestfs_h *g, const char *path, char **kernel, char
**initrd);
+static int build_supermin_appliance (guestfs_h *g, const char *path);
static int is_openable (guestfs_h *g, const char *path, int flags);
static void print_cmdline (guestfs_h *g);
@@ -1119,28 +1135,15 @@ guestfs__connect_handshake(guestfs_h *g)
return 0;
}
+
int
-guestfs__launch_spawn (guestfs_h *g)
+guestfs__find_appliance (guestfs_h *g)
{
- const char *tmpdir;
- char dir_template[PATH_MAX];
- int r, pmore;
size_t len;
- int wfd[2], rfd[2];
- int tries;
+ int r, pmore;
char *path, *pelem, *pend;
- char *kernel = NULL, *initrd = NULL;
- int null_vmchannel_sock;
- char unixsock[256];
-
- /* Configured? */
- if (!g->cmdline) {
- error (g, _("you must call guestfs_add_drive before guestfs_launch"));
- return -1;
- }
-
- /* Start the clock ... */
- gettimeofday (&g->launch_t, NULL);
+ const char *tmpdir;
+ char dir_template[PATH_MAX];
/* Make the temporary directory. */
#ifdef P_tmpdir
@@ -1149,6 +1152,11 @@ guestfs__launch_spawn (guestfs_h *g)
tmpdir = "/tmp";
#endif
+ if (g->tmpdir ||
+ g->kernel ||
+ g->initrd)
+ return 0;
+
tmpdir = getenv ("TMPDIR") ? : tmpdir;
snprintf (dir_template, sizeof dir_template, "%s/libguestfsXXXXXX", tmpdir);
@@ -1156,7 +1164,7 @@ guestfs__launch_spawn (guestfs_h *g)
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;
}
}
@@ -1179,7 +1187,7 @@ guestfs__launch_spawn (guestfs_h *g)
"looking for supermin appliance in current directory\n");
if (dir_contains_files (".",
"supermin.d", "kmod.whitelist", NULL))
{
- if (build_supermin_appliance (g, ".", &kernel, &initrd) == -1)
+ if (build_supermin_appliance (g, ".") == -1)
return -1;
break;
}
@@ -1191,7 +1199,7 @@ guestfs__launch_spawn (guestfs_h *g)
if (dir_contains_files (pelem,
"supermin.d", "kmod.whitelist", NULL))
{
- if (build_supermin_appliance (g, pelem, &kernel, &initrd) == -1)
+ if (build_supermin_appliance (g, pelem) == -1)
return -1;
break;
}
@@ -1202,7 +1210,7 @@ guestfs__launch_spawn (guestfs_h *g)
free (path);
- if (kernel == NULL || initrd == NULL) {
+ if (g->kernel == NULL || g->initrd == NULL) {
/* Search g->path for the kernel and initrd. */
pelem = path = safe_strdup (g, g->path);
do {
@@ -1217,8 +1225,8 @@ guestfs__launch_spawn (guestfs_h *g)
fprintf (stderr,
"looking for appliance in current directory\n");
if (dir_contains_files (".", kernel_name, initrd_name, NULL)) {
- kernel = safe_strdup (g, kernel_name);
- initrd = safe_strdup (g, initrd_name);
+ g->kernel = safe_strdup (g, kernel_name);
+ g->initrd = safe_strdup (g, initrd_name);
break;
}
}
@@ -1228,10 +1236,10 @@ guestfs__launch_spawn (guestfs_h *g)
fprintf (stderr, "looking for appliance in %s\n", pelem);
if (dir_contains_files (pelem, kernel_name, initrd_name, NULL)) {
- kernel = safe_malloc (g, len + strlen (kernel_name) + 2);
- initrd = safe_malloc (g, len + strlen (initrd_name) + 2);
- sprintf (kernel, "%s/%s", pelem, kernel_name);
- sprintf (initrd, "%s/%s", pelem, initrd_name);
+ g->kernel = safe_malloc (g, len + strlen (kernel_name) + 2);
+ g->initrd = safe_malloc (g, len + strlen (initrd_name) + 2);
+ sprintf (g->kernel, "%s/%s", pelem, kernel_name);
+ sprintf (g->initrd, "%s/%s", pelem, initrd_name);
break;
}
}
@@ -1242,12 +1250,36 @@ guestfs__launch_spawn (guestfs_h *g)
free (path);
}
- if (kernel == NULL || initrd == NULL) {
+ if (g->kernel == NULL || g->initrd == NULL) {
error (g, _("cannot find %s or %s on LIBGUESTFS_PATH (current path =
%s)"),
kernel_name, initrd_name, g->path);
- goto cleanup0;
+ return -1;
}
+ return 0;
+}
+
+int
+guestfs__launch_spawn (guestfs_h *g)
+{
+ int r;
+ int wfd[2], rfd[2];
+ int tries;
+ int null_vmchannel_sock;
+ char unixsock[256];
+
+ /* Configured? */
+ if (!g->cmdline) {
+ error (g, _("you must call guestfs_add_drive before guestfs_launch"));
+ return -1;
+ }
+
+ /* Start the clock ... */
+ gettimeofday (&g->launch_t, NULL);
+
+ if (guestfs__find_appliance (g) < 0)
+ return -1;
+
if (g->verbose)
print_timestamped_message (g, "begin testing qemu features");
@@ -1467,9 +1499,9 @@ guestfs__launch_spawn (guestfs_h *g)
g->append ? g->append : "");
add_cmdline (g, "-kernel");
- add_cmdline (g, (char *) kernel);
+ add_cmdline (g, g->kernel);
add_cmdline (g, "-initrd");
- add_cmdline (g, (char *) initrd);
+ add_cmdline (g, g->initrd);
add_cmdline (g, "-append");
add_cmdline (g, buf);
@@ -1516,11 +1548,6 @@ guestfs__launch_spawn (guestfs_h *g)
/* Parent (library). */
g->pid = r;
- free (kernel);
- kernel = NULL;
- free (initrd);
- initrd = NULL;
-
/* Fork the recovery process off which will kill qemu if the parent
* process fails to do so (eg. if the parent segfaults).
*/
@@ -1619,8 +1646,6 @@ guestfs__launch_spawn (guestfs_h *g)
g->sock = -1;
}
g->state = CONFIG;
- free (kernel);
- free (initrd);
return -1;
}
@@ -1702,20 +1727,27 @@ print_cmdline (guestfs_h *g)
* an external script. We just tell it where to put the result.
*/
static int
-build_supermin_appliance (guestfs_h *g, const char *path,
- char **kernel, char **initrd)
+build_supermin_appliance (guestfs_h *g, const char *path)
{
char cmd[4096];
int r, len;
+ bool tmpkernel = false;
+ bool tmpinitrd = false;
if (g->verbose)
print_timestamped_message (g, "begin building supermin appliance");
len = strlen (g->tmpdir);
- *kernel = safe_malloc (g, len + 8);
- snprintf (*kernel, len+8, "%s/kernel", g->tmpdir);
- *initrd = safe_malloc (g, len + 8);
- snprintf (*initrd, len+8, "%s/initrd", g->tmpdir);
+ if (!g->kernel) {
+ g->kernel = safe_malloc (g, len + 8);
+ snprintf (g->kernel, len+8, "%s/kernel", g->tmpdir);
+ tmpkernel = true;
+ }
+ if (!g->initrd) {
+ g->initrd = safe_malloc (g, len + 8);
+ snprintf (g->initrd, len+8, "%s/initrd", g->tmpdir);
+ tmpinitrd = true;
+ }
snprintf (cmd, sizeof cmd,
"febootstrap-supermin-helper%s "
@@ -1726,16 +1758,21 @@ build_supermin_appliance (guestfs_h *g, const char *path,
g->verbose ? " --verbose" : "",
path,
path,
- *kernel, *initrd);
+ g->kernel, g->initrd);
if (g->verbose)
print_timestamped_message (g, "%s", cmd);
r = system (cmd);
if (r == -1 || WEXITSTATUS(r) != 0) {
error (g, _("external command failed: %s"), cmd);
- free (*kernel);
- free (*initrd);
- *kernel = *initrd = NULL;
+ if (tmpkernel) {
+ free (g->kernel);
+ g->kernel = NULL;
+ }
+ if (tmpinitrd) {
+ free (g->initrd);
+ g->initrd = NULL;
+ }
return -1;
}
--
1.6.6.1