blsuki: Add blscfg command to parse Boot Loader Specification snippets

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 <pjones@redhat.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Will Thompson <wjt@endlessm.com>
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
Peter Jones 2025-08-12 03:45:33 +00:00 committed by Daniel Kiper
parent e016d6d60a
commit 8cee1c284b
9 changed files with 1145 additions and 6 deletions

View File

@ -24,6 +24,7 @@ gnulib_modules="
argp argp
base64 base64
error error
filevercmp
fnmatch fnmatch
getdelim getdelim
getline getline

View File

@ -3282,6 +3282,7 @@ These variables have special meaning to GRUB.
@menu @menu
* biosnum:: * biosnum::
* blsuki_save_default::
* check_signatures:: * check_signatures::
* chosen:: * chosen::
* cmdpath:: * cmdpath::
@ -3345,6 +3346,13 @@ For an alternative approach which also changes BIOS drive mappings for the
chain-loaded system, @pxref{drivemap}. chain-loaded system, @pxref{drivemap}.
@node blsuki_save_default
@subsection blsuki_save_default
If this variable is set, menu entries generated from BLS config files
(@pxref{blscfg}) will be set as the default boot entry when selected.
@node check_signatures @node check_signatures
@subsection check_signatures @subsection check_signatures
@ -6471,6 +6479,7 @@ you forget a command, you can run the command @command{help}
* background_image:: Load background image for active terminal * background_image:: Load background image for active terminal
* badram:: Filter out bad regions of RAM * badram:: Filter out bad regions of RAM
* blocklist:: Print a block list * blocklist:: Print a block list
* blscfg:: Load Boot Loader Specification menu entries
* boot:: Start up your operating system * boot:: Start up your operating system
* cat:: Show the contents of a file * cat:: Show the contents of a file
* clear:: Clear the screen * clear:: Clear the screen
@ -6659,6 +6668,72 @@ Print a block list (@pxref{Block list syntax}) for @var{file}.
@end deffn @end deffn
@node blscfg
@subsection blscfg
@deffn Command blscfg [@option{-p|--path} dir] [@option{-f|--enable-fallback}] [@option{-d|--show-default}] [@option{-n|--show-non-default}] [@option{-e|--entry} file]
Load Boot Loader Specification (BLS) entries into the GRUB menu. Boot entries
generated from @command{blscfg} won't interfere with entries from @file{grub.cfg} appearing in
the GRUB menu. Also, entries generated from @command{blscfg} exists only in memory and
don't update @file{grub.cfg}.
By default, the BLS entries are stored in the @file{/loader/entries} directory in the
boot partition. If BLS entries are stored elsewhere, the @option{--path} option can be
used to check a different directory instead of the default location. If no BLS
entries are found while using the @option{--path} option, the @option{--enable-fallback} option
can be used to check for entries in the default location.
The @option{--show-default} option allows the default boot entry to be added to the
GRUB menu from the BLS entries.
The @option{--show-non-default} option allows non-default boot entries to be added to
the GRUB menu from the BLS entries.
The @option{--entry} option allows specific boot entries to be added to the GRUB menu
from the BLS entries.
The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options
are used to filter which BLS entries are added to the GRUB menu. If none are
used, all entries in the default location or the location specified by @option{--path}
will be added to the GRUB menu.
A BLS config file example:
@example
# /boot/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf
title Fedora 19 (Rawhide)
sort-key fedora
machine-id 6a9857a393724b7a981ebb5b8495b9ea
version 3.8.0-2.fc19.x86_64
options root=UUID=6d3376e4-fc93-4509-95ec-a21d68011da2 quiet
architecture x64
linux /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux
initrd /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd
@end example
For more information on BLS entry keys as well as other information on BLS,
see: @uref{https://uapi-group.org/specifications/specs/boot_loader_specification/, The Boot Loader Specification}. For the GRUB, there are a few additional
BLS entry keys based on the @command{menuentry} command (@pxref{menuentry}).
The @code{grub_class} key may be used any number of times to group menu entries into
classes. Menu themes may display different classes using different styles.
The @code{grub_users} key grants specific users access to specific menu
entries. @xref{Security}.
The @code{grub_hotkey} key associates a hotkey with a menu entry.
@var{key} may be a single letter, or one of the aliases @samp{backspace},
@samp{tab}, or @samp{delete}.
The @code{grub_args} key can be used for any other argument to be passed as positonal
parameters when the list of commands generated from the BLS config file are
executed.
Variable expansion using the @samp{$} character (@xref{Shell-like scripting}) may be
used with BLS config files for the GRUB but might not be compatible with other
bootloaders.
@end deffn
@node boot @node boot
@subsection boot @subsection boot

View File

@ -847,6 +847,18 @@ module = {
common = commands/blocklist.c; common = commands/blocklist.c;
}; };
module = {
name = blsuki;
common = commands/blsuki.c;
common = lib/gnulib/filevercmp.c;
enable = powerpc_ieee1275;
enable = efi;
enable = i386_pc;
enable = emu;
cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
};
module = { module = {
name = boot; name = boot;
common = commands/boot.c; common = commands/boot.c;

1028
grub-core/commands/blsuki.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -143,7 +143,7 @@ legacy_file (const char *filename)
args[0] = oldname; args[0] = oldname;
grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy", grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy",
NULL, NULL, NULL, NULL,
entrysrc, 0); entrysrc, 0, NULL);
grub_free (args); grub_free (args);
entrysrc[0] = 0; entrysrc[0] = 0;
grub_free (oldname); grub_free (oldname);
@ -204,7 +204,7 @@ legacy_file (const char *filename)
} }
args[0] = entryname; args[0] = entryname;
grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
NULL, NULL, entrysrc, 0); NULL, NULL, entrysrc, 0, NULL);
grub_free (args); grub_free (args);
} }

View File

@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args,
char **classes, const char *id, char **classes, const char *id,
const char *users, const char *hotkey, const char *users, const char *hotkey,
const char *prefix, const char *sourcecode, const char *prefix, const char *sourcecode,
int submenu) int submenu, grub_blsuki_entry_t *blsuki)
{ {
int menu_hotkey = 0; int menu_hotkey = 0;
char **menu_args = NULL; char **menu_args = NULL;
@ -188,6 +188,7 @@ grub_normal_add_menu_entry (int argc, const char **args,
(*last)->args = menu_args; (*last)->args = menu_args;
(*last)->sourcecode = menu_sourcecode; (*last)->sourcecode = menu_sourcecode;
(*last)->submenu = submenu; (*last)->submenu = submenu;
(*last)->blsuki = blsuki;
menu->size++; menu->size++;
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
@ -286,7 +287,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
users, users,
ctxt->state[2].arg, 0, ctxt->state[2].arg, 0,
ctxt->state[3].arg, ctxt->state[3].arg,
ctxt->extcmd->cmd->name[0] == 's'); ctxt->extcmd->cmd->name[0] == 's',
NULL);
src = args[argc - 1]; src = args[argc - 1];
args[argc - 1] = NULL; args[argc - 1] = NULL;
@ -303,7 +305,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
ctxt->state[0].args, ctxt->state[4].arg, ctxt->state[0].args, ctxt->state[4].arg,
users, users,
ctxt->state[2].arg, prefix, src + 1, ctxt->state[2].arg, prefix, src + 1,
ctxt->extcmd->cmd->name[0] == 's'); ctxt->extcmd->cmd->name[0] == 's', NULL);
src[len - 1] = ch; src[len - 1] = ch;
args[argc - 1] = src; args[argc - 1] = src;

View File

@ -21,6 +21,7 @@
#include <grub/net.h> #include <grub/net.h>
#include <grub/normal.h> #include <grub/normal.h>
#include <grub/dl.h> #include <grub/dl.h>
#include <grub/menu.h>
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/file.h> #include <grub/file.h>
#include <grub/mm.h> #include <grub/mm.h>
@ -67,6 +68,11 @@ grub_normal_free_menu (grub_menu_t menu)
grub_free (entry->args); grub_free (entry->args);
} }
if (entry->blsuki)
{
entry->blsuki->visible = 0;
}
grub_free ((void *) entry->id); grub_free ((void *) entry->id);
grub_free ((void *) entry->users); grub_free ((void *) entry->users);
grub_free ((void *) entry->title); grub_free ((void *) entry->title);

View File

@ -20,6 +20,18 @@
#ifndef GRUB_MENU_HEADER #ifndef GRUB_MENU_HEADER
#define GRUB_MENU_HEADER 1 #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;
bool visible;
};
typedef struct grub_blsuki_entry grub_blsuki_entry_t;
struct grub_menu_entry_class struct grub_menu_entry_class
{ {
char *name; char *name;
@ -60,6 +72,9 @@ struct grub_menu_entry
/* The next element. */ /* The next element. */
struct grub_menu_entry *next; struct grub_menu_entry *next;
/* BLS used to populate the entry */
grub_blsuki_entry_t *blsuki;
}; };
typedef struct grub_menu_entry *grub_menu_entry_t; typedef struct grub_menu_entry *grub_menu_entry_t;

View File

@ -145,7 +145,7 @@ grub_normal_add_menu_entry (int argc, const char **args, char **classes,
const char *id, const char *id,
const char *users, const char *hotkey, const char *users, const char *hotkey,
const char *prefix, const char *sourcecode, const char *prefix, const char *sourcecode,
int submenu); int submenu, grub_blsuki_entry_t *blsuki);
grub_err_t grub_err_t
grub_normal_set_password (const char *user, const char *password); grub_normal_set_password (const char *user, const char *password);