[Libguestfs] [PATCH 3/3] Add APIs for resolving the appliance kernel/initrd

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


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




More information about the Libguestfs mailing list