[Libguestfs] [PATCH supermin 2/2] helper: Implement --dtb / device tree search.

Richard W.M. Jones rjones at redhat.com
Fri Sep 6 15:45:07 UTC 2013


From: "Richard W.M. Jones" <rjones at redhat.com>

For architectures such as ARM which require a device tree, this
implements a supermin-helper --dtb option which can be used to search
for a device tree file matching a wildcard.

Usage example:

  supermin-helper -f ext2 --dtb 'vexpress-*a9' supermin-d -o /tmp

would find a suitable dtb and symlink it as /tmp/dtb (or exit with an
error is none could be found).
---
 helper/helper.h |   2 +-
 helper/kernel.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 helper/main.c   |  33 +++++++++++-----
 3 files changed, 126 insertions(+), 24 deletions(-)

diff --git a/helper/helper.h b/helper/helper.h
index 281cec9..94ad9e1 100644
--- a/helper/helper.h
+++ b/helper/helper.h
@@ -65,7 +65,7 @@ extern struct writer cpio_writer;
 extern struct writer ext2_writer;
 
 /* kernel.c */
-extern const char *create_kernel (const char *hostcpu, const char *kernel);
+extern const char *create_kernel (const char *hostcpu, const char *kernel, const char *dtb_wildcard, const char *dtb);
 
 /* utils.c */
 extern void print_timestamped_message (const char *fs, ...);
diff --git a/helper/kernel.c b/helper/kernel.c
index 7957b25..4ff207b 100644
--- a/helper/kernel.c
+++ b/helper/kernel.c
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/utsname.h>
+#include <assert.h>
 
 #include "error.h"
 #include "xvasprintf.h"
@@ -44,8 +45,8 @@
 #define MODULESDIR "/lib/modules"
 
 static char* get_kernel_version (char* filename);
-static const char *create_kernel_from_env (const char *hostcpu, const char *kernel, const char *kernel_env, const char *modpath_env);
-static void copy_or_symlink_kernel (const char *from, const char *to);
+static const char *create_kernel_from_env (const char *hostcpu, const char *kernel, const char *kernel_env, const char *modpath_env, const char *dtb_wildcard, const char *dtb);
+static void copy_or_symlink_file (const char *what, const char *from, const char *to);
 
 static char *
 get_modpath (const char *kernel_name)
@@ -109,8 +110,85 @@ has_modpath (const char *kernel_name)
   }
 }
 
-/* Create the kernel.  This chooses an appropriate kernel and makes a
- * symlink to it (or copies it if --copy-kernel was passed).
+/* Try to find a device tree file in the kernel's dtb directory which
+ * matches the 'dtb_wildcard' pattern.  Copy the file (or symlink it) to
+ * 'dtb'.
+ *
+ * The dtb directory is formed by replacing "vmlinuz-" at the
+ * beginning of the 'kernel' filename with "dtb-".
+ *
+ * We can override the whole lot by setting $SUPERMIN_DTB.
+ */
+static void
+get_dtb (const char *kernel, const char *dtb_wildcard, const char *dtb)
+{
+  char *dtb_env = getenv ("SUPERMIN_DTB");
+  if (dtb_env) {
+    copy_or_symlink_file ("dtb", dtb_env, dtb);
+    return;
+  }
+
+  if (!dtb_wildcard)
+    return;
+
+  assert (dtb);      /* command line arg parsing should ensure this */
+  assert (kernel != NULL);
+
+  /* Replace /vmlinuz- with /dtb- */
+  if (strncmp (kernel, "vmlinuz-", 8) != 0) {
+  no_dtb_dir:
+    fprintf (stderr,
+             "supermin-helper: failed to find a dtb (device tree) directory.\n"
+             "I expected to take '%s'\n"
+	     "and replace vmlinuz- with dtb- to form a directory.\n"
+             "You can set SUPERMIN_DTB to point to the dtb *file* that should\n"
+             "be used.\n",
+             kernel);
+    exit (EXIT_FAILURE);
+  }
+
+  char *dtb_dir;
+  if (asprintf (&dtb_dir, KERNELDIR "/dtb-%s", &kernel[8]) == -1) {
+    perror ("asprintf");
+    exit (EXIT_FAILURE);
+  }
+
+  /* It should be a directory. */
+  if (!isdir (dtb_dir))
+    goto no_dtb_dir;
+
+  if (verbose)
+    fprintf (stderr, "looking for dtb matching %s in %s\n",
+	     dtb_wildcard, dtb_dir);
+
+  /* Look for the wildcard match.
+   * XXX Should probably do some sorting here and/or worry if there
+   * are multiple matches.
+   */
+  char **all_files = read_dir (dtb_dir);
+  char **candidates = filter_fnmatch (all_files, dtb_wildcard, FNM_NOESCAPE);
+
+  if (candidates[0] == NULL) {
+    fprintf (stderr,
+             "supermin-helper: failed to find a matching device tree.\n"
+             "I looked for a file matching '%s' in directory '%s'\n"
+             "You can set SUPERMIN_DTB to point to the dtb file that should\n"
+             "be used.\n",
+             dtb_wildcard, dtb_dir);
+    exit (EXIT_FAILURE);
+  }
+
+  if (verbose)
+    fprintf (stderr, "picked dtb %s\n", candidates[0]);
+
+  char *tmp = xasprintf ("%s/%s", dtb_dir, candidates[0]);
+  copy_or_symlink_file ("dtb", tmp, dtb);
+  free (tmp);
+}
+
+/* Create the kernel and device tree files.  This chooses an
+ * appropriate kernel, and optionally a device tree, and makes a
+ * symlink to them (or copies them if --copy-kernel was passed).
  *
  * Look for the most recent kernel named vmlinuz-*.<arch>* which has a
  * corresponding directory in /lib/modules/. If the architecture is
@@ -124,7 +202,8 @@ has_modpath (const char *kernel_name)
  * This function returns the module path (ie. /lib/modules/<version>).
  */
 const char *
-create_kernel (const char *hostcpu, const char *kernel)
+create_kernel (const char *hostcpu, const char *kernel,
+               const char *dtb_wildcard, const char *dtb)
 {
   int is_x86;			/* x86 but not x86-64 */
   int is_arm;			/* arm */
@@ -138,7 +217,8 @@ create_kernel (const char *hostcpu, const char *kernel)
   char *kernel_env = getenv ("SUPERMIN_KERNEL");
   if (kernel_env) {
     char *modpath_env = getenv ("SUPERMIN_MODULES");
-    return create_kernel_from_env (hostcpu, kernel, kernel_env, modpath_env);
+    return create_kernel_from_env (hostcpu, kernel, kernel_env, modpath_env,
+                                   dtb_wildcard, dtb);
   }
 
   /* In original: ls -1dvr /boot/vmlinuz-*.$arch* 2>/dev/null | grep -v xen */
@@ -176,15 +256,18 @@ create_kernel (const char *hostcpu, const char *kernel)
   sort (candidates, reverse_filevercmp);
 
   if (verbose)
-    fprintf (stderr, "picked %s\n", candidates[0]);
+    fprintf (stderr, "picked kernel %s\n", candidates[0]);
 
   if (kernel) {
     /* Choose the first candidate. */
     char *tmp = xasprintf (KERNELDIR "/%s", candidates[0]);
-    copy_or_symlink_kernel (tmp, kernel);
+    copy_or_symlink_file ("kernel", tmp, kernel);
     free (tmp);
   }
 
+  /* Device tree. */
+  get_dtb (candidates[0], dtb_wildcard, dtb);
+
   return get_modpath (candidates[0]);
 
   /* Print more diagnostics here than the old script did. */
@@ -205,7 +288,8 @@ create_kernel (const char *hostcpu, const char *kernel)
  */
 static const char *
 create_kernel_from_env (const char *hostcpu, const char *kernel,
-                        const char *kernel_env, const char *modpath_env)
+                        const char *kernel_env, const char *modpath_env,
+                        const char *dtb_wildcard, const char *dtb)
 {
   if (verbose) {
     fprintf (stderr,
@@ -250,25 +334,28 @@ create_kernel_from_env (const char *hostcpu, const char *kernel,
 
   /* Create the symlink. */
   if (kernel)
-    copy_or_symlink_kernel (kernel_env, kernel);
+    copy_or_symlink_file ("kernel", kernel_env, kernel);
+
+  /* Device tree. */
+  get_dtb (kernel, dtb_wildcard, dtb);
 
   return modpath_env;
 }
 
 static void
-copy_or_symlink_kernel (const char *from, const char *to)
+copy_or_symlink_file (const char *what, const char *from, const char *to)
 {
   int fd1, fd2;
   char buf[BUFSIZ];
   ssize_t r;
 
   if (verbose >= 2)
-    fprintf (stderr, "%s kernel %s -> %s\n",
-             !copy_kernel ? "symlink" : "copy", from, to);
+    fprintf (stderr, "%s %s %s -> %s\n",
+             !copy_kernel ? "symlink" : "copy", what, from, to);
 
   if (!copy_kernel) {
     if (symlink (from, to) == -1)
-      error (EXIT_FAILURE, errno, "creating kernel symlink %s %s", from, to);
+      error (EXIT_FAILURE, errno, "creating %s symlink %s %s", what, from, to);
   }
   else {
     fd1 = open (from, O_RDONLY | O_CLOEXEC);
diff --git a/helper/main.c b/helper/main.c
index 5632b9f..a4c33dc 100644
--- a/helper/main.c
+++ b/helper/main.c
@@ -187,9 +187,12 @@ main (int argc, char *argv[])
   const char *hostcpu = host_cpu;
 
   /* Output files. */
-  char *kernel = NULL, *initrd = NULL, *appliance = NULL;
+  char *kernel = NULL, *dtb = NULL, *initrd = NULL, *appliance = NULL;
   const char *output_dir = NULL;
 
+  /* Device tree wildcard (--dtb argument). */
+  const char *dtb_wildcard = NULL;
+
   uid_t euid = geteuid ();
   gid_t egid = getegid ();
 
@@ -211,8 +214,8 @@ main (int argc, char *argv[])
         copy_kernel = 1;
       }
       else if (strcmp (long_options[option_index].name, "dtb") == 0) {
-        fprintf (stderr, "%s: error: --dtb is not implemented yet\n", argv[0]);
-        exit (EXIT_FAILURE);
+        dtb_wildcard = optarg;
+        old_style = false;      /* --dtb + old-style wouldn't work anyway */
       }
       else if (strcmp (long_options[option_index].name, "host-cpu") == 0) {
         hostcpu = optarg;
@@ -223,13 +226,8 @@ main (int argc, char *argv[])
         old_style = false;
       }
       else if (strcmp (long_options[option_index].name, "output-dtb") == 0) {
-        /*
         dtb = optarg;
         old_style = false;
-        */
-        fprintf (stderr, "%s: error: --output-dtb is not implemented yet\n",
-                 argv[0]);
-        exit (EXIT_FAILURE);
       }
       else if (strcmp (long_options[option_index].name, "output-initrd") == 0) {
         initrd = optarg;
@@ -287,6 +285,8 @@ main (int argc, char *argv[])
   bool needs_initrd;
   bool needs_appliance;
 
+  bool needs_dtb = dtb_wildcard != NULL;
+
   if (strcmp (format, "cpio") == 0) {
     writer = &cpio_writer;
     needs_kernel = true;
@@ -357,6 +357,15 @@ main (int argc, char *argv[])
       }
     }
 
+    if (needs_dtb && !dtb) {
+      if (!output_dir)
+        goto no_output_dir;
+      if (asprintf (&dtb, "%s/dtb", output_dir) == -1) {
+        perror ("asprintf");
+        exit (EXIT_FAILURE);
+      }
+    }
+
     if (needs_initrd && !initrd) {
       if (!output_dir)
         goto no_output_dir;
@@ -387,12 +396,16 @@ main (int argc, char *argv[])
   if (verbose) {
     print_timestamped_message ("whitelist = %s, "
                                "host_cpu = %s, "
+                               "dtb_wildcard = %s, "
                                "kernel = %s, "
+                               "dtb = %s, "
                                "initrd = %s, "
                                "appliance = %s",
                                whitelist ? : "(not specified)",
                                hostcpu,
+                               dtb_wildcard ? : "(not specified)",
                                kernel ? : "(none)",
+                               dtb ? : "(none)",
                                initrd ? : "(none)",
                                appliance ? : "(none)");
     int i;
@@ -441,13 +454,15 @@ main (int argc, char *argv[])
   /* Remove the output files if they exist. */
   if (kernel)
     unlink (kernel);
+  if (dtb)
+    unlink (dtb);
   if (initrd)
     unlink (initrd);
   if (appliance)
     unlink (appliance);
 
   /* Create kernel output file. */
-  const char *modpath = create_kernel (hostcpu, kernel);
+  const char *modpath = create_kernel (hostcpu, kernel, dtb_wildcard, dtb);
 
   if (verbose)
     print_timestamped_message ("finished creating kernel");
-- 
1.8.3.1




More information about the Libguestfs mailing list