On Sun, Jul 27, 2025 at 01:54:33AM +0000, Alec Brown wrote:
> From: Peter Jones <pjo...@redhat.com>
>
> The BootLoaderSpec (BLS) defines a scheme where different bootloaders can
> share a format for boot items and a configuration directory that accepts
> these common configurations as drop-in files.
>
> The BLS Specification:
> https://uapi-group.org/specifications/specs/boot_loader_specification/
>
> Signed-off-by: Peter Jones <pjo...@redhat.com>
> Signed-off-by: Javier Martinez Canillas <javi...@redhat.com>
> Signed-off-by: Will Thompson <w...@endlessm.com>
> Signed-off-by: Alec Brown <alec.r.br...@oracle.com>
> ---
>  bootstrap.conf                 |    1 +
>  docs/grub.texi                 |   67 +++
>  grub-core/Makefile.core.def    |   12 +
>  grub-core/commands/blsuki.c    | 1032 ++++++++++++++++++++++++++++++++
>  grub-core/commands/legacycfg.c |    4 +-
>  grub-core/commands/menuentry.c |    8 +-
>  grub-core/normal/main.c        |    6 +
>  include/grub/menu.h            |   15 +
>  include/grub/normal.h          |    2 +-
>  9 files changed, 1141 insertions(+), 6 deletions(-)
>  create mode 100644 grub-core/commands/blsuki.c

[...]

> diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
> new file mode 100644
> index 000000000..c275dbb92
> --- /dev/null
> +++ b/grub-core/commands/blsuki.c

[...]

> +static int
> +blsuki_read_entry (const char *filename,
> +                const struct grub_dirhook_info *dirhook_info __attribute__ 
> ((__unused__)),
> +                void *data)
> +{
> +  grub_size_t path_len = 0, filename_len;
> +  grub_err_t err;
> +  char *p = NULL;
> +  grub_file_t f = NULL;
> +  grub_blsuki_entry_t *entry;
> +  struct read_entry_info *info = (struct read_entry_info *) data;
> +
> +  grub_dprintf ("blsuki", "filename: \"%s\"\n", filename);
> +
> +  filename_len = grub_strlen (filename);
> +
> +  if (info->file != NULL)
> +    f = info->file;
> +  else
> +    {
> +      if (filename_len < BLS_EXT_LEN ||
> +       grub_strcmp (filename + filename_len - BLS_EXT_LEN, ".conf") != 0)
> +     return 0;
> +
> +      p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
> +
> +      f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG);
> +      grub_free (p);
> +      if (f == NULL)
> +     goto finish;
> +    }
> +
> +  entry = grub_zalloc (sizeof (*entry));
> +  if (entry == NULL)
> +    goto finish;
> +
> +  /*
> +   * If a file is opened before this function, the filename may have a path.
> +   * Since the filename is used for the ID of the GRUB menu entry, we can
> +   * remove the path.
> +   */
> +  if (info->file != NULL)
> +    {
> +      char *slash;
> +
> +      slash = grub_strrchr (filename, '/');
> +      if (slash != NULL)
> +     {
> +       while (*slash == '/')
> +         slash++;

I think this while is redundant.

> +       path_len = slash - filename;
> +     }
> +    }
> +  filename_len -= path_len;
> +
> +  entry->filename = grub_strndup (filename + path_len, filename_len);
> +  if (entry->filename == NULL)
> +    {
> +      grub_free (entry);
> +      goto finish;
> +    }
> +
> +  err = bls_parse_keyvals (f, entry);
> +
> +  if (err == GRUB_ERR_NONE)
> +    blsuki_add_entry (entry);
> +  else
> +    grub_free (entry);
> +
> + finish:
> +  if (f != NULL)
> +    grub_file_close (f);
> +
> +  return 0;
> +}

[...]

> +static char *
> +bls_get_devicetree (grub_blsuki_entry_t *entry)
> +{
> +  char *dt_path;
> +  char *dt_cmd = NULL;
> +  char *tmp;
> +  grub_size_t size;
> +
> +  dt_path = blsuki_expand_val (blsuki_get_val (entry, "devicetree", NULL));
> +  if (dt_path != NULL)
> +    {
> +      if (grub_add (sizeof ("devicetree "), grub_strlen (dt_path), &size) ||
> +       grub_add (size, 1, &size))
> +     {
> +       grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating 
> device tree buffer size");
> +       return NULL;
> +     }
> +
> +      dt_cmd = grub_malloc (size);
> +      if (dt_cmd == NULL)
> +     return NULL;
> +
> +      tmp = dt_cmd;
> +      tmp = grub_stpcpy (dt_cmd, "devicetree");
> +      tmp = grub_stpcpy (tmp, " ");


Hmmm... Why not tmp = grub_stpcpy (dt_cmd, "devicetree ")?
Note space after "devicetree"...

> +      tmp = grub_stpcpy (tmp, dt_path);
> +      tmp = grub_stpcpy (tmp, "\n");
> +    }
> +
> +  return dt_cmd;
> +}
> +
> +/*
> + * This function puts together all of the commands generated from the 
> contents
> + * of the BLS config file and creates a new entry in the GRUB boot menu.
> + */
> +static void
> +bls_create_entry (grub_blsuki_entry_t *entry)
> +{
> +  int argc = 0;
> +  const char **argv = NULL;
> +  char *title = NULL;
> +  char *linux_path = NULL;
> +  char *linux_cmd = NULL;
> +  char *initrd_cmd = NULL;
> +  char *dt_cmd = NULL;
> +  char *id = entry->filename;
> +  grub_size_t id_len;
> +  char *hotkey = NULL;
> +  char *users = NULL;
> +  char **classes = NULL;
> +  char **args = NULL;
> +  char *src = NULL;
> +  const char *sdval = NULL;
> +  int i;
> +  grub_size_t size;
> +  bool savedefault;
> +
> +  linux_path = blsuki_get_val (entry, "linux", NULL);
> +  if (linux_path == NULL)
> +    {
> +      grub_dprintf ("blsuki", "Skipping file %s with no 'linux' key.\n", 
> entry->filename);
> +      goto finish;
> +    }
> +
> +  id_len = grub_strlen (id);
> +  if (id_len >= BLS_EXT_LEN && grub_strcmp (id + id_len - BLS_EXT_LEN, 
> ".conf") == 0)
> +    id[id_len - BLS_EXT_LEN] = '\0';
> +
> +  title = blsuki_get_val (entry, "title", NULL);
> +  hotkey = blsuki_get_val (entry, "grub_hotkey", NULL);
> +  users = blsuki_expand_val (blsuki_get_val (entry, "grub_users", NULL));
> +  classes = blsuki_make_list (entry, "grub_class", NULL);
> +  args = blsuki_make_list (entry, "grub_arg", &argc);
> +
> +  argc++;
> +  if (grub_mul (argc + 1, sizeof (char *), &size))
> +    {
> +      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected creating argv 
> list"));
> +      goto finish;
> +    }
> +
> +  argv = grub_malloc (size);
> +  if (argv == NULL)
> +    goto finish;
> +
> +  argv[0] = (title != NULL) ? title : linux_path;
> +  for (i = 1; i < argc; i++)
> +    argv[i] = args[i-1];
> +  argv[argc] = NULL;
> +
> +  linux_cmd = bls_get_linux (entry);
> +  if (linux_cmd == NULL)
> +    goto finish;
> +
> +  initrd_cmd = bls_get_initrd (entry);
> +  if (grub_errno != GRUB_ERR_NONE)
> +    goto finish;
> +
> +  dt_cmd = bls_get_devicetree (entry);
> +  if (grub_errno != GRUB_ERR_NONE)
> +    goto finish;
> +
> +  sdval = grub_env_get ("save_default");

This variable does not seem documented... And it seams BLS/UKI specific.
So, probably blsuki_save_default...

> +  savedefault = ((NULL != sdval) && (grub_strcmp (sdval, "true") == 0));

s/savedefault/blsuki_save_default/

grub_env_get_bool() and you are done...

> +  src = grub_xasprintf ("%s%s%s%s",
> +                     savedefault ? "savedefault\n" : "",
> +                     linux_cmd, initrd_cmd ? initrd_cmd : "",
> +                     dt_cmd ? dt_cmd : "");
> +
> +  grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, 
> src, 0, entry);
> +
> + finish:
> +  grub_free (linux_cmd);
> +  grub_free (dt_cmd);
> +  grub_free (initrd_cmd);
> +  grub_free (classes);
> +  grub_free (args);
> +  grub_free (argv);
> +  grub_free (src);
> +}
> +
> +/*
> + * This function fills a find_entry_info struct passed in by the info 
> parameter.
> + * If the dirname or devid parameters are set to NULL, the dirname and devid
> + * fields in the info parameter will be set to default values. If info 
> already
> + * has a value in the dev fields, we can compare it to the value passed in by
> + * the devid parameter or the default devid to see if we need to open a new
> + * device.
> + */
> +static grub_err_t
> +blsuki_set_find_entry_info (struct find_entry_info *info, const char 
> *dirname, const char *devid)
> +{
> +  grub_device_t dev;
> +  grub_fs_t fs;
> +
> +  if (info == NULL)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "info parameter is not set");
> +
> +  if (devid == NULL)
> +    {
> +      devid = grub_env_get ("root");
> +      if (devid == NULL)
> +     return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't 
> set"), "root");

Huh... "variable `root' isn't set"...

> +    }
> +
> +  /* Check that we aren't closing and opening the same device. */
> +  if (info->dev != NULL && grub_strcmp (info->devid, devid) != 0)
> +    {
> +      grub_device_close (info->dev);
> +      info->dev = NULL;
> +    }
> +  /* If we are using the same device, then we can skip this step and only 
> set the directory. */
> +  if (info->dev == NULL)
> +    {
> +      grub_dprintf ("blsuki", "opening %s\n", devid);
> +      dev = grub_device_open (devid);
> +      if (dev == NULL)
> +     return grub_errno;
> +
> +      grub_dprintf ("blsuki", "probing fs\n");
> +      fs = grub_fs_probe (dev);
> +      if (fs == NULL)
> +     {
> +       grub_device_close (dev);
> +       return grub_errno;
> +     }
> +
> +      info->devid = devid;
> +      info->dev = dev;
> +      info->fs = fs;
> +    }
> +
> +  info->dirname = dirname;
> +
> +  return GRUB_ERR_NONE;
> +}

[...]

> +static bool
> +blsuki_is_default_entry (const char *def_entry, grub_blsuki_entry_t *entry, 
> int idx)
> +{
> +  const char *title;
> +  const char *def_entry_end;
> +  int def_idx;

long def_idx;

> +
> +  if (def_entry == NULL || *def_entry == '\0')
> +    return false;
> +
> +  if (grub_strcmp (def_entry, entry->filename) == 0)
> +    return true;
> +
> +  title = blsuki_get_val (entry, "title", NULL);
> +
> +  if (title != NULL && grub_strcmp (def_entry, title) == 0)
> +    return true;
> +
> +  def_idx = (int) grub_strtol (def_entry, &def_entry_end, 0);

Drop cast from here...

> +  if (*def_entry_end != '\0')

*def_entry_end != '\0' || def_idx < 0 || def_idx > GRUB_INT_MAX

> +    return false;
> +
> +  if (def_idx == idx)

(int) def_idx == idx

> +    return true;
> +
> +  return false;
> +}

[...]

> diff --git a/include/grub/menu.h b/include/grub/menu.h
> index ee2b5e910..c25a0d16d 100644
> --- a/include/grub/menu.h
> +++ b/include/grub/menu.h
> @@ -20,6 +20,18 @@
>  #ifndef GRUB_MENU_HEADER
>  #define GRUB_MENU_HEADER 1
>
> +struct grub_blsuki_entry
> +{
> +  struct grub_blsuki_entry *next;
> +  struct grub_blsuki_entry **prev;
> +  struct keyval **keyvals;
> +  grub_size_t keyvals_size;
> +  int nkeyvals;
> +  char *filename;
> +  int visible;

Why is not it bool?

Daniel

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to