From: Richard Jones Date: Fri, 21 May 2010 08:35:05 +0000 (+0100) Subject: Fix febootstrap-supermin-helper for dual boot case (RHBZ#594021). X-Git-Tag: 2.8~10 X-Git-Url: http://git.annexia.org/?p=febootstrap.git;a=commitdiff_plain;h=51f70a0bc0f57e72889208bd7f5ec8a7f229c541 Fix febootstrap-supermin-helper for dual boot case (RHBZ#594021). Jinxin Zheng found a case where libguestfs-supermin-helper (now febootstrap-supermin-helper) would fail to locate a suitable kernel on a dual boot RHEL 5 + 6 system. The issue was that febootstrap-supermin-helper will first look for kernels with an field in the name (as is the case for RHEL 6 kernels). If none of these are found, it would look for kernels without an field (RHEL 5 kernels). Then it would look for corresponding module directories. This fails if the dual boot system is booted into RHEL 5 because the first step will find only RHEL 6 kernels, and then the third step will fail to find any module directories (step two having been skipped in this case). This changes the code to look for module directories when searching for kernels, and discard any kernels which don't have module directories first. Thus all RHEL 6 kernels will be discarded, and we will proceed to step two and find some RHEL 5 kernels. --- diff --git a/febootstrap-supermin-helper.c b/febootstrap-supermin-helper.c index 1a43cf2..a81cf61 100644 --- a/febootstrap-supermin-helper.c +++ b/febootstrap-supermin-helper.c @@ -233,6 +233,7 @@ print_timestamped_message (const char *fs, ...) } static char **read_dir (const char *dir); +static char **filter (char **strings, int (*)(const char *)); static char **filter_fnmatch (char **strings, const char *patt, int flags); static char **filter_notmatching_substring (char **strings, const char *sub); static void sort (char **strings, int (*compare) (const void *, const void *)); @@ -248,6 +249,48 @@ reverse_filevercmp (const void *p1, const void *p2) return filevercmp (s2, s1); } +static char * +get_modpath (const char *kernel_name) +{ + /* Ignore "vmlinuz-" at the beginning of the kernel name. */ + const char *version = &kernel_name[8]; + + /* /lib/modules/ */ + char *modpath = xasprintf (MODULESDIR "/%s", version); + if (!modpath) { + perror ("xasprintf"); + exit (EXIT_FAILURE); + } + + return modpath; +} + +/* kernel_name is "vmlinuz-*". Check if there is a corresponding + * module path in /lib/modules. + */ +static int +has_modpath (const char *kernel_name) +{ + char *modpath = get_modpath (kernel_name); + + if (verbose) + fprintf (stderr, "checking modpath %s is a directory\n", modpath); + + int r = isdir (modpath); + + if (r) { + if (verbose) + fprintf (stderr, "picked %s because modpath %s exists\n", + kernel_name, modpath); + free (modpath); + return 1; + } + else { + free (modpath); + return 0; + } +} + /* Create the kernel. This chooses an appropriate kernel and makes a * symlink to it. * @@ -278,12 +321,14 @@ create_kernel (const char *hostcpu, const char *kernel) char **candidates; candidates = filter_fnmatch (all_files, patt, FNM_NOESCAPE); candidates = filter_notmatching_substring (candidates, "xen"); + candidates = filter (candidates, has_modpath); if (candidates[0] == NULL) { /* In original: ls -1dvr /boot/vmlinuz-* 2>/dev/null | grep -v xen */ patt = "vmlinuz-*"; candidates = filter_fnmatch (all_files, patt, FNM_NOESCAPE); candidates = filter_notmatching_substring (candidates, "xen"); + candidates = filter (candidates, has_modpath); if (candidates[0] == NULL) goto no_kernels; @@ -291,41 +336,18 @@ create_kernel (const char *hostcpu, const char *kernel) sort (candidates, reverse_filevercmp); - /* Choose the first candidate which has a corresponding /lib/modules - * directory. - */ - int i; - for (i = 0; candidates[i] != NULL; ++i) { - if (verbose >= 2) - fprintf (stderr, "candidate kernel: " KERNELDIR "/%s\n", candidates[i]); - - /* Ignore "vmlinuz-" at the beginning of the kernel name. */ - const char *version = &candidates[i][8]; + /* Choose the first candidate. */ + char *tmp = xasprintf (KERNELDIR "/%s", candidates[0]); - /* /lib/modules/ */ - char *modpath = xasprintf (MODULESDIR "/%s", version); - - if (verbose >= 2) - fprintf (stderr, "checking modpath %s is a directory\n", modpath); - - if (isdir (modpath)) { - if (verbose >= 2) - fprintf (stderr, "picked %s because modpath %s exists\n", - candidates[i], modpath); - - char *tmp = xasprintf (KERNELDIR "/%s", candidates[i]); - - if (verbose >= 2) - fprintf (stderr, "creating symlink %s -> %s\n", kernel, tmp); + if (verbose) + fprintf (stderr, "creating symlink %s -> %s\n", kernel, tmp); - if (symlink (tmp, kernel) == -1) - error (EXIT_FAILURE, errno, "symlink kernel"); + if (symlink (tmp, kernel) == -1) + error (EXIT_FAILURE, errno, "symlink kernel"); - free (tmp); + free (tmp); - return modpath; - } - } + return get_modpath (candidates[0]); /* Print more diagnostics here than the old script did. */ no_kernels: @@ -716,6 +738,23 @@ read_dir (const char *name) return files; } +/* Filter a list of strings, returning only those where f(s) != 0. */ +static char ** +filter (char **strings, int (*f) (const char *)) +{ + char **out = NULL; + size_t n_used = 0, n_alloc = 0; + + int i; + for (i = 0; strings[i] != NULL; ++i) { + if (f (strings[i]) != 0) + add_string (&out, &n_used, &n_alloc, strings[i]); + } + + add_string (&out, &n_used, &n_alloc, NULL); + return out; +} + /* Filter a list of strings and return only those matching the wildcard. */ static char ** filter_fnmatch (char **strings, const char *patt, int flags)