helper: Allow kernel and modpath to be selected from envvars (RHBZ#671082).
authorRichard W.M. Jones <rjones@redhat.com>
Fri, 22 Jul 2011 14:18:36 +0000 (15:18 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Fri, 22 Jul 2011 14:40:28 +0000 (15:40 +0100)
febootstrap.pod
helper/febootstrap-supermin-helper.pod
helper/helper.h
helper/kernel.c
helper/utils.c

index 6620976..e38c171 100644 (file)
@@ -249,8 +249,11 @@ For example:
 Usually the kernel and kernel modules are I<not> included in the
 supermin appliance.  When the appliance is instantiated, the kernel
 modules from the host kernel are copied in, and it is booted using the
-host kernel.  febootstrap-supermin-helper is able to choose the best
-host kernel available to boot the appliance.
+host kernel.
+
+febootstrap-supermin-helper is able to choose the best host kernel
+available to boot the appliance.  Users can override this by setting
+environment variables (see L<febootstrap-supermin-helper(8)>).
 
 =head2 BOOTING AND CACHING THE SUPERMIN APPLIANCE
 
index fc44643..7fee09e 100644 (file)
@@ -130,6 +130,34 @@ Minimize the appliance, removing as much extraneous junk as possible.
 
 =back
 
+=head1 ENVIRONMENT VARIABLES
+
+=over 4
+
+=item FEBOOTSTRAP_KERNEL
+
+If this environment variable is set, then automatic selection of the
+kernel is bypassed and this kernel is used.
+
+The environment variable should point to a kernel file,
+eg. C</boot/vmlinuz-3.0.x86_64>
+
+The corresponding module path is guessed from the kernel name, but you
+can override that by setting C<FEBOOTSTRAP_MODULES>.
+
+=item FEBOOTSTRAP_MODULES
+
+If C<FEBOOTSTRAP_KERNEL> and C<FEBOOTSTRAP_MODULES> are both set, then
+automatic selection of the kernel is bypassed and the kernel and
+module path are set to these values.
+
+The environment variable should point to a module directory,
+eg. C</lib/modules/3.0.x86_64/>
+
+This has no effect if C<FEBOOTSTRAP_KERNEL> is not set.
+
+=back
+
 =head1 SEE ALSO
 
 L<febootstrap(8)>.
index e0d1fbb..2ff2050 100644 (file)
@@ -78,6 +78,7 @@ extern char **filter_fnmatch (char **strings, const char *patt, int flags);
 extern char **filter_notmatching_substring (char **strings, const char *sub);
 extern void sort (char **strings, int (*compare) (const void *, const void *));
 extern int isdir (const char *path);
+extern int isfile (const char *path);
 extern char **load_file (const char *filename);
 
 #endif /* FEBOOTSTRAP_SUPERMIN_HELPER_H */
index 538942c..6a68e55 100644 (file)
@@ -79,6 +79,7 @@ has_modpath (const char *kernel_name)
 }
 
 static const char *create_kernel_archlinux (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);
 
 /* Create the kernel.  This chooses an appropriate kernel and makes a
  * symlink to it.
@@ -97,6 +98,13 @@ static const char *create_kernel_archlinux (const char *hostcpu, const char *ker
 const char *
 create_kernel (const char *hostcpu, const char *kernel)
 {
+  /* Override kernel selection using environment variables? */
+  char *kernel_env = getenv ("FEBOOTSTRAP_KERNEL");
+  if (kernel_env) {
+    char *modpath_env = getenv ("FEBOOTSTRAP_MODULES");
+    return create_kernel_from_env (hostcpu, kernel, kernel_env, modpath_env);
+  }
+
   /* In ArchLinux, kernel is always named /boot/vmlinuz26. */
   if (access ("/boot/vmlinuz26", F_OK) == 0)
     return create_kernel_archlinux (hostcpu, kernel);
@@ -207,3 +215,64 @@ create_kernel_archlinux (const char *hostcpu, const char *kernel)
   /* Return module path. */
   return modpath;
 }
+
+/* Select the kernel from environment variables set by the user.
+ * modpath_env may be NULL, in which case we attempt to work it out
+ * from kernel_env.
+ */
+static const char *
+create_kernel_from_env (const char *hostcpu, const char *kernel,
+                        const char *kernel_env, const char *modpath_env)
+{
+  if (verbose) {
+    fprintf (stderr,
+             "febootstrap-supermin-helper: using environment variable(s) FEBOOTSTRAP_* to\n"
+             "select kernel %s", kernel_env);
+    if (modpath_env)
+      fprintf (stderr, " and module path %s", modpath_env);
+    fprintf (stderr, "\n");
+  }
+
+  if (!isfile (kernel_env)) {
+    fprintf (stderr,
+             "febootstrap-supermin-helper: %s: not a regular file\n"
+             "(what is $FEBOOTSTRAP_KERNEL set to?)\n", kernel_env);
+    exit (EXIT_FAILURE);
+  }
+
+  if (!modpath_env) {
+    /* Try to guess modpath from kernel path. */
+    const char *p = strrchr (kernel_env, '/');
+    if (p) p++; else p = kernel_env;
+
+    /* NB: We need the extra test to ensure calling get_modpath is safe. */
+    if (strncmp (p, "vmlinuz-", 8) != 0) {
+      fprintf (stderr,
+               "febootstrap-supermin-helper: cannot guess module path.\n"
+               "Set $FEBOOTSTRAP_MODULES to the modules directory corresponding to\n"
+               "kernel %s, or unset $FEBOOTSTRAP_KERNEL to autoselect a kernel.\n",
+               kernel_env);
+      exit (EXIT_FAILURE);
+    }
+
+    modpath_env = get_modpath (p);
+  }
+
+  if (!isdir (modpath_env)) {
+    fprintf (stderr,
+             "febootstrap-supermin-helper: %s: not a directory\n"
+             "(what is $FEBOOTSTRAP_MODULES set to?)\n", modpath_env);
+    exit (EXIT_FAILURE);
+  }
+
+  /* Create the symlink. */
+  if (kernel) {
+    if (verbose >= 2)
+      fprintf (stderr, "creating symlink %s -> %s\n", kernel_env, kernel);
+
+    if (symlink (kernel_env, kernel) == -1)
+      error (EXIT_FAILURE, errno, "symlink kernel");
+  }
+
+  return modpath_env;
+}
index 4d54cc5..81b300a 100644 (file)
@@ -273,6 +273,20 @@ isdir (const char *path)
   return S_ISDIR (statbuf.st_mode);
 }
 
+/* Return true iff path exists and is a regular file.  This version
+ * follows symlinks.
+ */
+int
+isfile (const char *path)
+{
+  struct stat statbuf;
+
+  if (stat (path, &statbuf) == -1)
+    return 0;
+
+  return S_ISREG (statbuf.st_mode);
+}
+
 /* Load in a file, returning a list of lines. */
 char **
 load_file (const char *filename)