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
 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
 
 
 =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
 
 
 =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)>.
 =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 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 */
 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_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.
 
 /* 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)
 {
 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);
   /* 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;
 }
   /* 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 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)
 /* Load in a file, returning a list of lines. */
 char **
 load_file (const char *filename)