From ad47b1cf5010721fc12f814a1b3275361fef6493 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 22 Jul 2011 15:18:36 +0100 Subject: [PATCH] helper: Allow kernel and modpath to be selected from envvars (RHBZ#671082). --- febootstrap.pod | 7 +++- helper/febootstrap-supermin-helper.pod | 28 ++++++++++++++ helper/helper.h | 1 + helper/kernel.c | 69 ++++++++++++++++++++++++++++++++++ helper/utils.c | 14 +++++++ 5 files changed, 117 insertions(+), 2 deletions(-) diff --git a/febootstrap.pod b/febootstrap.pod index 6620976..e38c171 100644 --- a/febootstrap.pod +++ b/febootstrap.pod @@ -249,8 +249,11 @@ For example: Usually the kernel and kernel modules are I 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). =head2 BOOTING AND CACHING THE SUPERMIN APPLIANCE diff --git a/helper/febootstrap-supermin-helper.pod b/helper/febootstrap-supermin-helper.pod index fc44643..7fee09e 100644 --- a/helper/febootstrap-supermin-helper.pod +++ b/helper/febootstrap-supermin-helper.pod @@ -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 + +The corresponding module path is guessed from the kernel name, but you +can override that by setting C. + +=item FEBOOTSTRAP_MODULES + +If C and C 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 + +This has no effect if C is not set. + +=back + =head1 SEE ALSO L. diff --git a/helper/helper.h b/helper/helper.h index e0d1fbb..2ff2050 100644 --- a/helper/helper.h +++ b/helper/helper.h @@ -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 */ diff --git a/helper/kernel.c b/helper/kernel.c index 538942c..6a68e55 100644 --- a/helper/kernel.c +++ b/helper/kernel.c @@ -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; +} diff --git a/helper/utils.c b/helper/utils.c index 4d54cc5..81b300a 100644 --- a/helper/utils.c +++ b/helper/utils.c @@ -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) -- 1.8.3.1