Irritatingly, BLS defines paths relatives to the mountpoint of the filesystem which contains its snippets, not / or any other fixed location. So grub2-emu needs to know whether /boot is a separate filesystem from / and conditionally prepend a path.
Signed-off-by: Robbie Harwood <rharw...@redhat.com> Signed-off-by: Alec Brown <alec.r.br...@oracle.com> --- grub-core/Makefile.core.def | 4 ++ grub-core/commands/blsuki.c | 92 ++++++++++++++++++++++++++++++--- grub-core/osdep/linux/getroot.c | 8 +++ grub-core/osdep/unix/getroot.c | 10 ++++ include/grub/emu/misc.h | 2 +- 5 files changed, 107 insertions(+), 9 deletions(-) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index f3b776c0a..9a0e7bc55 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -367,6 +367,10 @@ kernel = { emu = kern/emu/cache_s.S; emu = kern/emu/hostdisk.c; emu = osdep/unix/hostdisk.c; + emu = osdep/relpath.c; + emu = osdep/getroot.c; + emu = osdep/unix/getroot.c; + emu = osdep/devmapper/getroot.c; emu = osdep/exec.c; extra_dist = osdep/unix/exec.c; emu = osdep/devmapper/hostdisk.c; diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 0fb4f870a..7b7b3e0e4 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -32,6 +32,13 @@ #include <grub/lib/envblk.h> #include <grub/lib/vercmp.h> +#ifdef GRUB_MACHINE_EMU +#include <grub/emu/misc.h> +#define GRUB_BOOT_DEVICE "/boot" +#else +#define GRUB_BOOT_DEVICE "" +#endif + GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BLS_CONFIG_PATH "/loader/entries/" @@ -56,6 +63,40 @@ static grub_blsuki_entry_t *entries = NULL; #define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) +#ifdef GRUB_MACHINE_EMU +/* + * Cache probing in blsuki_update_boot_device(). + */ +static int separate_boot = -1; +#endif + +/* + * BLS appears to make paths relative to the filesystem that snippets are + * on, not /. Attempt to cope. + */ +static char *blsuki_update_boot_device (char *tmp) +{ +#ifdef GRUB_MACHINE_EMU + char *ret = NULL; + + if (separate_boot != -1) + goto probed; + + separate_boot = 0; + + ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE); + + if (ret != NULL && ret[0] == '\0') + separate_boot = 1; + + probed: + if (!separate_boot) + return tmp; +#endif + + return grub_stpcpy (tmp, GRUB_BOOT_DEVICE); +} + static grub_err_t blsuki_add_keyval (grub_blsuki_entry_t *entry, char *key, char *val) { @@ -561,7 +602,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) goto finish; } - if (grub_add (sizeof ("linux "), grub_strlen (linux_path), &linux_size)) + if (grub_add (sizeof ("linux " GRUB_BOOT_DEVICE), grub_strlen (linux_path), &linux_size)) { grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating linux buffer size"); goto finish; @@ -572,6 +613,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) tmp = clinux; tmp = grub_stpcpy (tmp, "linux"); tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device (tmp); tmp = grub_stpcpy (tmp, linux_path); /* Strip the ".conf" off the end before we make it our "id" field. */ @@ -655,7 +697,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) { - if (grub_add (initrd_size, sizeof (" "), &initrd_size) || + if (grub_add (initrd_size, sizeof (" " GRUB_BOOT_DEVICE), &initrd_size) || grub_add (initrd_size, grub_strlen (initrd_prefix), &initrd_size) || grub_add (initrd_size, grub_strlen (early_initrds[i]), &initrd_size) || grub_add (initrd_size, 1, &initrd_size)) @@ -667,7 +709,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) for (i = 0; initrds != NULL && initrds[i] != NULL; i++) { - if (grub_add (initrd_size, sizeof (" "), &initrd_size) || + if (grub_add (initrd_size, sizeof (" " GRUB_BOOT_DEVICE), &initrd_size) || grub_add (initrd_size, grub_strlen (initrds[i]), &initrd_size) || grub_add (initrd_size, 1, &initrd_size)) { @@ -691,6 +733,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) { grub_dprintf ("blsuki", "adding early initrd %s\n", early_initrds[i]); tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device (tmp); tmp = grub_stpcpy (tmp, initrd_prefix); tmp = grub_stpcpy (tmp, early_initrds[i]); grub_free (early_initrds[i]); @@ -700,6 +743,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) { grub_dprintf ("blsuki", "adding initrd %s\n", initrds[i]); tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device (tmp); tmp = grub_stpcpy (tmp, initrds[i]); } tmp = grub_stpcpy (tmp, "\n"); @@ -718,7 +762,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) } } - if (grub_add (sizeof ("devicetree "), grub_strlen (devicetree), &dt_size) || + if (grub_add (sizeof ("devicetree " GRUB_BOOT_DEVICE), grub_strlen (devicetree), &dt_size) || grub_add (dt_size, 1, &dt_size)) { grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating device tree buffer size"); @@ -740,6 +784,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) tmp = dt; tmp = grub_stpcpy (dt, "devicetree"); tmp = grub_stpcpy (tmp, " "); + tmp = blsuki_update_boot_device (tmp); if (add_dt_prefix == true) tmp = grub_stpcpy (tmp, prefix); tmp = grub_stpcpy (tmp, devicetree); @@ -836,10 +881,13 @@ blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, c } /* info: the filesystem object the file is on. */ -static void +static grub_err_t blsuki_find_entry (struct find_entry_info *info, bool enable_fallback) { struct read_entry_info read_entry_info; + char *default_dir = NULL; + char *tmp; + grub_size_t default_size; grub_fs_t dir_fs = NULL; grub_device_t dir_dev = NULL; int fallback = 0; @@ -869,12 +917,25 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback) */ if (entries == NULL && fallback == 0 && enable_fallback == true) { - blsuki_set_find_entry_info (info, GRUB_BLS_CONFIG_PATH, NULL); + if (grub_add (grub_strlen (GRUB_BOOT_DEVICE), grub_strlen (GRUB_BLS_CONFIG_PATH), &default_size)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating default directory buffer size"); + + default_dir = grub_malloc (default_size); + if (default_dir == NULL) + return grub_errno; + + tmp = blsuki_update_boot_device (default_dir); + tmp = grub_stpcpy (tmp, GRUB_BLS_CONFIG_PATH); + + blsuki_set_find_entry_info (info, default_dir, NULL); grub_dprintf ("blsuki", "Entries weren't found in %s, fallback to %s\n", read_entry_info.dirname, info->dirname); fallback = 1; goto read_fallback; } + + grub_free (default_dir); + return GRUB_ERR_NONE; } static grub_err_t @@ -884,6 +945,9 @@ blsuki_load_entries (char *path, bool enable_fallback) static grub_err_t r; const char *devid = NULL; char *dir = NULL; + char *default_dir = NULL; + char *tmp; + grub_size_t dir_size; struct find_entry_info info = { .dev = NULL, .fs = NULL, @@ -925,15 +989,27 @@ blsuki_load_entries (char *path, bool enable_fallback) } if (dir == NULL) - dir = (char *) GRUB_BLS_CONFIG_PATH; + { + if (grub_add (grub_strlen (GRUB_BOOT_DEVICE), grub_strlen (GRUB_BLS_CONFIG_PATH), &dir_size)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating default directory buffer size"); + + default_dir = grub_malloc (dir_size); + if (default_dir == NULL) + return grub_errno; + + tmp = blsuki_update_boot_device (default_dir); + tmp = grub_stpcpy (tmp, GRUB_BLS_CONFIG_PATH); + dir = default_dir; + } r = blsuki_set_find_entry_info (&info, dir, devid); if (r == GRUB_ERR_NONE) - blsuki_find_entry (&info, enable_fallback); + r = blsuki_find_entry (&info, enable_fallback); if (info.dev != NULL) grub_device_close (info.dev); + grub_free (default_dir); return r; } diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c index 527d4f0c5..2fc212276 100644 --- a/grub-core/osdep/linux/getroot.c +++ b/grub-core/osdep/linux/getroot.c @@ -131,6 +131,7 @@ struct mountinfo_entry char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1]; }; +#ifdef GRUB_UTIL static char ** grub_util_raid_getmembers (const char *name, int bootable) { @@ -191,6 +192,7 @@ grub_util_raid_getmembers (const char *name, int bootable) return devicelist; } +#endif /* Statting something on a btrfs filesystem always returns a virtual device major/minor pair rather than the real underlying device, because btrfs @@ -579,6 +581,7 @@ out: return ret; } +#ifdef GRUB_UTIL static char * get_mdadm_uuid (const char *os_dev) { @@ -636,6 +639,7 @@ out: return name; } +#endif static int grub_util_is_imsm (const char *os_dev) @@ -968,6 +972,7 @@ grub_util_part_to_disk (const char *os_dev, struct stat *st, return path; } +#ifdef GRUB_UTIL static char * grub_util_get_raid_grub_dev (const char *os_dev) { @@ -1070,6 +1075,7 @@ grub_util_get_raid_grub_dev (const char *os_dev) } return grub_dev; } +#endif enum grub_dev_abstraction_types grub_util_get_dev_abstraction_os (const char *os_dev) @@ -1086,6 +1092,7 @@ grub_util_get_dev_abstraction_os (const char *os_dev) return GRUB_DEV_ABSTRACTION_NONE; } +#ifdef GRUB_UTIL int grub_util_pull_device_os (const char *os_dev, enum grub_dev_abstraction_types ab) @@ -1142,6 +1149,7 @@ grub_util_get_grub_dev_os (const char *os_dev) return grub_dev; } +#endif char * grub_make_system_path_relative_to_its_root_os (const char *path) diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c index c7aa202ab..1380638d3 100644 --- a/grub-core/osdep/unix/getroot.c +++ b/grub-core/osdep/unix/getroot.c @@ -17,6 +17,14 @@ */ #include <config.h> +#undef _GL_INLINE_HEADER_BEGIN +#undef _GL_INLINE_HEADER_END +#undef _GL_GNUC_PREREQ +#undef _GL_ATTRIBUTE_COLD +#undef _GL_ATTRIBUTE_CONST +#undef _GL_ATTRIBUTE_DEALLOC +#undef _GL_ATTRIBUTE_FALLTHROUGH +#undef _GL_ATTRIBUTE_MALLOC #include <config-util.h> #include <sys/stat.h> @@ -566,6 +574,7 @@ grub_guess_root_devices (const char *dir_in) #endif +#ifdef GRUB_UTIL void grub_util_pull_lvm_by_command (const char *os_dev) { @@ -662,6 +671,7 @@ out: free (buf); free (vgid); } +#endif /* ZFS has similar problems to those of btrfs (see above). */ void diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h index fefbec499..542f4c18d 100644 --- a/include/grub/emu/misc.h +++ b/include/grub/emu/misc.h @@ -39,7 +39,7 @@ void grub_fini_all (void); void grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs); -char *grub_make_system_path_relative_to_its_root (const char *path) +char * EXPORT_FUNC(grub_make_system_path_relative_to_its_root) (const char *path) WARN_UNUSED_RESULT; int grub_util_device_is_mapped (const char *dev); -- 2.27.0 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel