On Wed, May 21, 2025 at 12:51:25PM +0000, Alec Brown wrote:
> From: Robbie Harwood <[email protected]>
>
> Irritatingly, BLS defines paths relative 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 <[email protected]>
> Signed-off-by: Alec Brown <[email protected]>
> ---
> 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 67628f65f..93b88795e 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 2ad960ae3..bf2edc5ac 100644
> --- a/grub-core/commands/blsuki.c
> +++ b/grub-core/commands/blsuki.c
> @@ -32,6 +32,13 @@
> #include <grub/vercmp.h>
> #include <grub/lib/envblk.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;
> +
> + 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);
> +}
> +
> /*
> * This function will add a new keyval pair to a list of keyvals stored in
> the
> * entry parameter.
> @@ -582,7 +623,7 @@ bls_get_linux (grub_blsuki_entry_t *entry)
> if (options == NULL)
> options = blsuki_expand_val (grub_env_get ("default_kernelopts"));
>
> - if (grub_add (grub_strlen ("linux "), grub_strlen (linux_path), &size))
> + if (grub_add (grub_strlen ("linux " GRUB_BOOT_DEVICE), grub_strlen
> (linux_path), &size))
> {
> grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while
> calculating linux buffer size");
> goto finish;
> @@ -604,6 +645,7 @@ bls_get_linux (grub_blsuki_entry_t *entry)
>
> tmp = linux_cmd;
> tmp = grub_stpcpy (tmp, "linux ");
> + tmp = blsuki_update_boot_device (tmp);
> tmp = grub_stpcpy (tmp, linux_path);
> if (options != NULL)
> {
> @@ -679,7 +721,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry)
>
> for (i = 0; early_initrd_list != NULL && early_initrd_list[i] != NULL;
> i++)
> {
> - if (grub_add (size, 1, &size) ||
> + if (grub_add (size, grub_strlen (" " GRUB_BOOT_DEVICE), &size) ||
s/grub_strlen/sizeof (...) - 1/
> grub_add (size, grub_strlen (prefix), &size) ||
> grub_add (size, grub_strlen (early_initrd_list[i]), &size))
> {
> @@ -690,7 +732,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry)
>
> for (i = 0; initrd_list != NULL && initrd_list[i] != NULL; i++)
> {
> - if (grub_add (size, 1, &size) ||
> + if (grub_add (size, grub_strlen (" " GRUB_BOOT_DEVICE), &size) ||
Ditto.
> grub_add (size, grub_strlen (initrd_list[i]), &size))
> {
> grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating
> initrd buffer size");
> @@ -713,6 +755,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry)
> {
> grub_dprintf ("blsuki", "adding early initrd %s\n",
> early_initrd_list[i]);
> tmp = grub_stpcpy (tmp, " ");
> + tmp = blsuki_update_boot_device (tmp);
> tmp = grub_stpcpy (tmp, prefix);
> tmp = grub_stpcpy (tmp, early_initrd_list[i]);
> }
> @@ -721,6 +764,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry)
> {
> grub_dprintf ("blsuki", "adding initrd %s\n", initrd_list[i]);
> tmp = grub_stpcpy (tmp, " ");
> + tmp = blsuki_update_boot_device (tmp);
> tmp = grub_stpcpy (tmp, initrd_list[i]);
> }
> tmp = grub_stpcpy (tmp, "\n");
> @@ -775,7 +819,7 @@ bls_get_devicetree (grub_blsuki_entry_t *entry)
> }
> }
>
> - if (grub_add (grub_strlen ("devicetree "), grub_strlen (dt_path),
> &size) ||
> + if (grub_add (grub_strlen ("devicetree " GRUB_BOOT_DEVICE),
> grub_strlen (dt_path), &size) ||
Ditto.
> grub_add (size, 1, &size))
> {
> grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating
> device tree buffer size");
> @@ -796,6 +840,7 @@ bls_get_devicetree (grub_blsuki_entry_t *entry)
> tmp = dt_cmd;
> tmp = grub_stpcpy (dt_cmd, "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, dt_path);
> @@ -924,7 +969,11 @@ blsuki_set_find_entry_info (struct find_entry_info
> *info, const char *dirname, c
>
> if (devid == NULL)
> {
> +#ifdef GRUB_MACHINE_EMU
> + devid = "host";
> +#else
> devid = grub_env_get ("root");
> +#endif
> if (devid == NULL)
> return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't
> set"), "root");
> }
> @@ -966,10 +1015,13 @@ blsuki_set_find_entry_info (struct find_entry_info
> *info, const char *dirname, c
> * parameter. If the fallback option is enabled, the default location will be
> * checked for BLS config files if the first attempt fails.
> */
> -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;
> bool fallback = false;
> @@ -1000,7 +1052,15 @@ blsuki_find_entry (struct find_entry_info *info, bool
> enable_fallback)
> */
> if (entries == NULL && fallback == false && enable_fallback == true)
> {
> - blsuki_set_find_entry_info (info, GRUB_BLS_CONFIG_PATH, NULL);
> + default_size = grub_strlen (GRUB_BOOT_DEVICE) + grub_strlen
> (GRUB_BLS_CONFIG_PATH);
s/grub_strlen/sizeof/ * 2
Do not forget about NUL at the end...
> + 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 = true;
> @@ -1009,6 +1069,9 @@ blsuki_find_entry (struct find_entry_info *info, bool
> enable_fallback)
> fallback = false;
> }
> while (fallback == true);
> +
> + grub_free (default_dir);
> + return GRUB_ERR_NONE;
> }
>
> static grub_err_t
> @@ -1018,6 +1081,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,
> @@ -1059,15 +1125,25 @@ blsuki_load_entries (char *path, bool enable_fallback)
> }
>
> if (dir == NULL)
> - dir = (char *) GRUB_BLS_CONFIG_PATH;
> + {
> + dir_size = grub_strlen (GRUB_BOOT_DEVICE) + grub_strlen
> (GRUB_BLS_CONFIG_PATH);
Ditto...
> + 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
The changes to this file look like unrelated ones. Are they really needed?
> @@ -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)
s/* EXPORT_FUNC(/*EXPORT_FUNC (/
Daniel
_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel