On Mon, Sep 30, 2024 at 1:09 PM Vladimir 'phcoder' Serbinenko < phco...@gmail.com> wrote:
> This is already being reviewed in separate thread > I did not see a similar patch being reviewed before sending the series, so I will drop it. if possible, can you send the grub-devel archive link? I could not find it through google nor search string field at https://lists.gnu.org/archive/html/grub-devel/ > > Le lun. 30 sept. 2024, 20:46, Leo Sandoval <lsand...@redhat.com> a écrit : > >> 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. >> >> Signed-off-by: Peter Jones <pjo...@redhat.com> >> Signed-off-by: Javier Martinez Canillas <javi...@redhat.com> >> [wjt: some cleanups and fixes] >> Signed-off-by: Will Thompson <w...@endlessm.com> >> --- >> grub-core/Makefile.core.def | 11 + >> grub-core/commands/blscfg.c | 1177 ++++++++++++++++++++++++++++++++ >> grub-core/commands/legacycfg.c | 5 +- >> grub-core/commands/loadenv.c | 77 +-- >> grub-core/commands/loadenv.h | 93 +++ >> grub-core/commands/menuentry.c | 20 +- >> grub-core/normal/main.c | 6 + >> include/grub/compiler.h | 2 + >> include/grub/menu.h | 13 + >> include/grub/normal.h | 2 +- >> 10 files changed, 1324 insertions(+), 82 deletions(-) >> create mode 100644 grub-core/commands/blscfg.c >> create mode 100644 grub-core/commands/loadenv.h >> >> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def >> index 0bffbfea9..47c0fc755 100644 >> --- a/grub-core/Makefile.core.def >> +++ b/grub-core/Makefile.core.def >> @@ -842,6 +842,16 @@ module = { >> common = commands/blocklist.c; >> }; >> >> +module = { >> + name = blscfg; >> + common = commands/blscfg.c; >> + common = commands/loadenv.h; >> + enable = powerpc_ieee1275; >> + enable = efi; >> + enable = i386_pc; >> + enable = emu; >> +}; >> + >> module = { >> name = boot; >> common = commands/boot.c; >> @@ -1009,6 +1019,7 @@ module = { >> module = { >> name = loadenv; >> common = commands/loadenv.c; >> + common = commands/loadenv.h; >> common = lib/envblk.c; >> }; >> >> diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c >> new file mode 100644 >> index 000000000..e907a6a5d >> --- /dev/null >> +++ b/grub-core/commands/blscfg.c >> @@ -0,0 +1,1177 @@ >> +/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/ >> + >> +/* bls.c - implementation of the boot loader spec */ >> + >> +/* >> + * GRUB -- GRand Unified Bootloader >> + * >> + * GRUB is free software: you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation, either version 3 of the License, or >> + * (at your option) any later version. >> + * >> + * GRUB is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. >> + */ >> + >> +#include <grub/list.h> >> +#include <grub/types.h> >> +#include <grub/misc.h> >> +#include <grub/mm.h> >> +#include <grub/err.h> >> +#include <grub/dl.h> >> +#include <grub/extcmd.h> >> +#include <grub/i18n.h> >> +#include <grub/fs.h> >> +#include <grub/env.h> >> +#include <grub/file.h> >> +#include <grub/normal.h> >> +#include <grub/lib/envblk.h> >> + >> +#include <stdbool.h> >> + >> +GRUB_MOD_LICENSE ("GPLv3+"); >> + >> +#include "loadenv.h" >> + >> +#define GRUB_BLS_CONFIG_PATH "/loader/entries/" >> +#ifdef GRUB_MACHINE_EMU >> +#define GRUB_BOOT_DEVICE "/boot" >> +#else >> +#define GRUB_BOOT_DEVICE "($root)" >> +#endif >> + >> +struct keyval >> +{ >> + const char *key; >> + char *val; >> +}; >> + >> +static struct bls_entry *entries = NULL; >> + >> +#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) >> + >> +static int bls_add_keyval(struct bls_entry *entry, char *key, char *val) >> +{ >> + char *k, *v; >> + struct keyval **kvs, *kv; >> + int new_n = entry->nkeyvals + 1; >> + >> + kvs = grub_realloc (entry->keyvals, new_n * sizeof (struct keyval *)); >> + if (!kvs) >> + return grub_error (GRUB_ERR_OUT_OF_MEMORY, >> + "couldn't find space for BLS entry"); >> + entry->keyvals = kvs; >> + >> + kv = grub_malloc (sizeof (struct keyval)); >> + if (!kv) >> + return grub_error (GRUB_ERR_OUT_OF_MEMORY, >> + "couldn't find space for BLS entry"); >> + >> + k = grub_strdup (key); >> + if (!k) >> + { >> + grub_free (kv); >> + return grub_error (GRUB_ERR_OUT_OF_MEMORY, >> + "couldn't find space for BLS entry"); >> + } >> + >> + v = grub_strdup (val); >> + if (!v) >> + { >> + grub_free (k); >> + grub_free (kv); >> + return grub_error (GRUB_ERR_OUT_OF_MEMORY, >> + "couldn't find space for BLS entry"); >> + } >> + >> + kv->key = k; >> + kv->val = v; >> + >> + entry->keyvals[entry->nkeyvals] = kv; >> + grub_dprintf("blscfg", "new keyval at %p:%s:%s\n", >> entry->keyvals[entry->nkeyvals], k, v); >> + entry->nkeyvals = new_n; >> + >> + return 0; >> +} >> + >> +/* Find they value of the key named by keyname. If there are allowed to >> be >> + * more than one, pass a pointer to an int set to -1 the first time, and >> pass >> + * the same pointer through each time after, and it'll return them in >> sorted >> + * order as defined in the BLS fragment file */ >> +static char *bls_get_val(struct bls_entry *entry, const char *keyname, >> int *last) >> +{ >> + int idx, start = 0; >> + struct keyval *kv = NULL; >> + >> + if (last) >> + start = *last + 1; >> + >> + for (idx = start; idx < entry->nkeyvals; idx++) { >> + kv = entry->keyvals[idx]; >> + >> + if (!grub_strcmp (keyname, kv->key)) >> + break; >> + } >> + >> + if (idx == entry->nkeyvals) { >> + if (last) >> + *last = -1; >> + return NULL; >> + } >> + >> + if (last) >> + *last = idx; >> + >> + return kv->val; >> +} >> + >> +#define goto_return(x) ({ ret = (x); goto finish; }) >> + >> +/* compare alpha and numeric segments of two versions */ >> +/* return 1: a is newer than b */ >> +/* 0: a and b are the same version */ >> +/* -1: b is newer than a */ >> +static int vercmp(const char * a, const char * b) >> +{ >> + char oldch1, oldch2; >> + char *abuf, *bbuf; >> + char *str1, *str2; >> + char * one, * two; >> + int rc; >> + int isnum; >> + int ret = 0; >> + >> + grub_dprintf("blscfg", "%s comparing %s and %s\n", __func__, a, b); >> + if (!grub_strcmp(a, b)) >> + return 0; >> + >> + abuf = grub_malloc(grub_strlen(a) + 1); >> + bbuf = grub_malloc(grub_strlen(b) + 1); >> + str1 = abuf; >> + str2 = bbuf; >> + grub_strcpy(str1, a); >> + grub_strcpy(str2, b); >> + >> + one = str1; >> + two = str2; >> + >> + /* loop through each version segment of str1 and str2 and compare >> them */ >> + while (*one || *two) { >> + while (*one && !grub_isalnum(*one) && *one != '~' && *one != '+') >> one++; >> + while (*two && !grub_isalnum(*two) && *two != '~' && *two != '+') >> two++; >> + >> + /* handle the tilde separator, it sorts before everything else */ >> + if (*one == '~' || *two == '~') { >> + if (*one != '~') goto_return (1); >> + if (*two != '~') goto_return (-1); >> + one++; >> + two++; >> + continue; >> + } >> + >> + /* >> + * Handle plus separator. Concept is the same as tilde, >> + * except that if one of the strings ends (base version), >> + * the other is considered as higher version. >> + */ >> + if (*one == '+' || *two == '+') { >> + if (!*one) return -1; >> + if (!*two) return 1; >> + if (*one != '+') goto_return (1); >> + if (*two != '+') goto_return (-1); >> + one++; >> + two++; >> + continue; >> + } >> + >> + /* If we ran to the end of either, we are finished with the loop >> */ >> + if (!(*one && *two)) break; >> + >> + str1 = one; >> + str2 = two; >> + >> + /* grab first completely alpha or completely numeric segment */ >> + /* leave one and two pointing to the start of the alpha or >> numeric */ >> + /* segment and walk str1 and str2 to end of segment */ >> + if (grub_isdigit(*str1)) { >> + while (*str1 && grub_isdigit(*str1)) str1++; >> + while (*str2 && grub_isdigit(*str2)) str2++; >> + isnum = 1; >> + } else { >> + while (*str1 && grub_isalpha(*str1)) str1++; >> + while (*str2 && grub_isalpha(*str2)) str2++; >> + isnum = 0; >> + } >> + >> + /* save character at the end of the alpha or numeric segment */ >> + /* so that they can be restored after the comparison */ >> + oldch1 = *str1; >> + *str1 = '\0'; >> + oldch2 = *str2; >> + *str2 = '\0'; >> + >> + /* this cannot happen, as we previously tested to make sure that >> */ >> + /* the first string has a non-null segment */ >> + if (one == str1) goto_return(-1); /* arbitrary */ >> + >> + /* take care of the case where the two version segments are */ >> + /* different types: one numeric, the other alpha (i.e. empty) */ >> + /* numeric segments are always newer than alpha segments */ >> + /* XXX See patch #60884 (and details) from bugzilla #50977. */ >> + if (two == str2) goto_return (isnum ? 1 : -1); >> + >> + if (isnum) { >> + grub_size_t onelen, twolen; >> + /* this used to be done by converting the digit segments */ >> + /* to ints using atoi() - it's changed because long */ >> + /* digit segments can overflow an int - this should fix that. >> */ >> + >> + /* throw away any leading zeros - it's a number, right? */ >> + while (*one == '0') one++; >> + while (*two == '0') two++; >> + >> + /* whichever number has more digits wins */ >> + onelen = grub_strlen(one); >> + twolen = grub_strlen(two); >> + if (onelen > twolen) goto_return (1); >> + if (twolen > onelen) goto_return (-1); >> + } >> + >> + /* grub_strcmp will return which one is greater - even if the two >> */ >> + /* segments are alpha or if they are numeric. don't return */ >> + /* if they are equal because there might be more segments to */ >> + /* compare */ >> + rc = grub_strcmp(one, two); >> + if (rc) goto_return (rc < 1 ? -1 : 1); >> + >> + /* restore character that was replaced by null above */ >> + *str1 = oldch1; >> + one = str1; >> + *str2 = oldch2; >> + two = str2; >> + } >> + >> + /* this catches the case where all numeric and alpha segments have */ >> + /* compared identically but the segment sepparating characters were >> */ >> + /* different */ >> + if ((!*one) && (!*two)) goto_return (0); >> + >> + /* whichever version still has characters left over wins */ >> + if (!*one) goto_return (-1); else goto_return (1); >> + >> +finish: >> + grub_free (abuf); >> + grub_free (bbuf); >> + return ret; >> +} >> + >> +/* returns name/version/release */ >> +/* NULL string pointer returned if nothing found */ >> +static void >> +split_package_string (char *package_string, char **name, >> + char **version, char **release) >> +{ >> + char *package_version, *package_release; >> + >> + /* Release */ >> + package_release = grub_strrchr (package_string, '-'); >> + >> + if (package_release != NULL) >> + *package_release++ = '\0'; >> + >> + *release = package_release; >> + >> + if (name == NULL) >> + { >> + *version = package_string; >> + } >> + else >> + { >> + /* Version */ >> + package_version = grub_strrchr(package_string, '-'); >> + >> + if (package_version != NULL) >> + *package_version++ = '\0'; >> + >> + *version = package_version; >> + /* Name */ >> + *name = package_string; >> + } >> + >> + /* Bubble up non-null values from release to name */ >> + if (name != NULL && *name == NULL) >> + { >> + *name = (*version == NULL ? *release : *version); >> + *version = *release; >> + *release = NULL; >> + } >> + if (*version == NULL) >> + { >> + *version = *release; >> + *release = NULL; >> + } >> +} >> + >> +static int >> +split_cmp(char *nvr0, char *nvr1, int has_name) >> +{ >> + int ret = 0; >> + char *name0, *version0, *release0; >> + char *name1, *version1, *release1; >> + >> + split_package_string(nvr0, has_name ? &name0 : NULL, &version0, >> &release0); >> + split_package_string(nvr1, has_name ? &name1 : NULL, &version1, >> &release1); >> + >> + if (has_name) >> + { >> + ret = vercmp(name0 == NULL ? "" : name0, >> + name1 == NULL ? "" : name1); >> + if (ret != 0) >> + return ret; >> + } >> + >> + ret = vercmp(version0 == NULL ? "" : version0, >> + version1 == NULL ? "" : version1); >> + if (ret != 0) >> + return ret; >> + >> + ret = vercmp(release0 == NULL ? "" : release0, >> + release1 == NULL ? "" : release1); >> + return ret; >> +} >> + >> +/* return 1: e0 is newer than e1 */ >> +/* 0: e0 and e1 are the same version */ >> +/* -1: e1 is newer than e0 */ >> +static int bls_cmp(const struct bls_entry *e0, const struct bls_entry >> *e1) >> +{ >> + char *id0, *id1; >> + int r; >> + >> + id0 = grub_strdup(e0->filename); >> + id1 = grub_strdup(e1->filename); >> + >> + r = split_cmp(id0, id1, 1); >> + >> + grub_free(id0); >> + grub_free(id1); >> + >> + return r; >> +} >> + >> +static void list_add_tail(struct bls_entry *head, struct bls_entry *item) >> +{ >> + item->next = head; >> + if (head->prev) >> + head->prev->next = item; >> + item->prev = head->prev; >> + head->prev = item; >> +} >> + >> +static int bls_add_entry(struct bls_entry *entry) >> +{ >> + struct bls_entry *e, *last = NULL; >> + int rc; >> + >> + if (!entries) { >> + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", >> entry->filename); >> + entries = entry; >> + return 0; >> + } >> + >> + FOR_BLS_ENTRIES(e) { >> + rc = bls_cmp(entry, e); >> + >> + if (!rc) >> + return GRUB_ERR_BAD_ARGUMENT; >> + >> + if (rc == 1) { >> + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", >> entry->filename); >> + list_add_tail (e, entry); >> + if (e == entries) { >> + entries = entry; >> + entry->prev = NULL; >> + } >> + return 0; >> + } >> + last = e; >> + } >> + >> + if (last) { >> + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", >> entry->filename); >> + last->next = entry; >> + entry->prev = last; >> + } >> + >> + return 0; >> +} >> + >> +struct read_entry_info { >> + const char *devid; >> + const char *dirname; >> + grub_file_t file; >> +}; >> + >> +static int read_entry ( >> + const char *filename, >> + const struct grub_dirhook_info *dirhook_info UNUSED, >> + void *data) >> +{ >> + grub_size_t m = 0, n, clip = 0; >> + int rc = 0; >> + char *p = NULL; >> + grub_file_t f = NULL; >> + struct bls_entry *entry; >> + struct read_entry_info *info = (struct read_entry_info *)data; >> + >> + grub_dprintf ("blscfg", "filename: \"%s\"\n", filename); >> + >> + n = grub_strlen (filename); >> + >> + if (info->file) >> + { >> + f = info->file; >> + } >> + else >> + { >> + if (filename[0] == '.') >> + return 0; >> + >> + if (n <= 5) >> + return 0; >> + >> + if (grub_strcmp (filename + n - 5, ".conf") != 0) >> + return 0; >> + >> + p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, >> filename); >> + >> + f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG); >> + if (!f) >> + goto finish; >> + } >> + >> + entry = grub_zalloc (sizeof (*entry)); >> + if (!entry) >> + goto finish; >> + >> + if (info->file) >> + { >> + char *slash; >> + >> + if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0) >> + clip = 5; >> + >> + slash = grub_strrchr (filename, '/'); >> + if (!slash) >> + slash = grub_strrchr (filename, '\\'); >> + >> + while (*slash == '/' || *slash == '\\') >> + slash++; >> + >> + m = slash ? slash - filename : 0; >> + } >> + else >> + { >> + m = 0; >> + clip = 5; >> + } >> + n -= m; >> + >> + entry->filename = grub_strndup(filename + m, n - clip); >> + if (!entry->filename) >> + goto finish; >> + >> + entry->filename[n - 5] = '\0'; >> + >> + for (;;) >> + { >> + char *buf; >> + char *separator; >> + >> + buf = grub_file_getline (f); >> + if (!buf) >> + break; >> + >> + while (buf && buf[0] && (buf[0] == ' ' || buf[0] == '\t')) >> + buf++; >> + if (buf[0] == '#') >> + continue; >> + >> + separator = grub_strchr (buf, ' '); >> + >> + if (!separator) >> + separator = grub_strchr (buf, '\t'); >> + >> + if (!separator || separator[1] == '\0') >> + { >> + grub_free (buf); >> + break; >> + } >> + >> + separator[0] = '\0'; >> + >> + do { >> + separator++; >> + } while (*separator == ' ' || *separator == '\t'); >> + >> + rc = bls_add_keyval (entry, buf, separator); >> + grub_free (buf); >> + if (rc < 0) >> + break; >> + } >> + >> + if (!rc) >> + bls_add_entry(entry); >> + >> +finish: >> + if (p) >> + grub_free (p); >> + >> + if (f) >> + grub_file_close (f); >> + >> + return 0; >> +} >> + >> +static grub_envblk_t saved_env = NULL; >> + >> +static int UNUSED >> +save_var (const char *name, const char *value, void *whitelist UNUSED) >> +{ >> + const char *val = grub_env_get (name); >> + grub_dprintf("blscfg", "saving \"%s\"\n", name); >> + >> + if (val) >> + grub_envblk_set (saved_env, name, value); >> + >> + return 0; >> +} >> + >> +static int UNUSED >> +unset_var (const char *name, const char *value UNUSED, void *whitelist) >> +{ >> + grub_dprintf("blscfg", "restoring \"%s\"\n", name); >> + if (! whitelist) >> + { >> + grub_env_unset (name); >> + return 0; >> + } >> + >> + if (test_whitelist_membership (name, >> + (const grub_env_whitelist_t *) >> whitelist)) >> + grub_env_unset (name); >> + >> + return 0; >> +} >> + >> +static char **bls_make_list (struct bls_entry *entry, const char *key, >> int *num) >> +{ >> + int last = -1; >> + char *val; >> + >> + int nlist = 0; >> + char **list = NULL; >> + >> + list = grub_malloc (sizeof (char *)); >> + if (!list) >> + return NULL; >> + list[0] = NULL; >> + >> + while (1) >> + { >> + char **new; >> + >> + val = bls_get_val (entry, key, &last); >> + if (!val) >> + break; >> + >> + new = grub_realloc (list, (nlist + 2) * sizeof (char *)); >> + if (!new) >> + break; >> + >> + list = new; >> + list[nlist++] = val; >> + list[nlist] = NULL; >> + } >> + >> + if (!nlist) >> + { >> + grub_free (list); >> + return NULL; >> + } >> + >> + if (num) >> + *num = nlist; >> + >> + return list; >> +} >> + >> +static char *field_append(bool is_var, char *buffer, const char *start, >> const char *end) >> +{ >> + char *tmp = grub_strndup(start, end - start + 1); >> + const char *field = tmp; >> + int term = is_var ? 2 : 1; >> + >> + if (is_var) { >> + field = grub_env_get (tmp); >> + if (!field) >> + return buffer; >> + } >> + >> + if (!buffer) >> + buffer = grub_zalloc (grub_strlen(field) + term); >> + else >> + buffer = grub_realloc (buffer, grub_strlen(buffer) + >> grub_strlen(field) + term); >> + >> + if (!buffer) >> + return NULL; >> + >> + tmp = buffer + grub_strlen(buffer); >> + tmp = grub_stpcpy (tmp, field); >> + >> + if (is_var) >> + tmp = grub_stpcpy (tmp, " "); >> + >> + return buffer; >> +} >> + >> +static char *expand_val(const char *value) >> +{ >> + char *buffer = NULL; >> + const char *start = value; >> + const char *end = value; >> + bool is_var = false; >> + >> + if (!value) >> + return NULL; >> + >> + while (*value) { >> + if (*value == '$') { >> + if (start != end) { >> + buffer = field_append(is_var, buffer, start, end); >> + if (!buffer) >> + return NULL; >> + } >> + >> + is_var = true; >> + start = value + 1; >> + } else if (is_var) { >> + if (!grub_isalnum(*value) && *value != '_') { >> + buffer = field_append(is_var, buffer, start, end); >> + is_var = false; >> + start = value; >> + if (*start == ' ') >> + start++; >> + } >> + } >> + >> + end = value; >> + value++; >> + } >> + >> + if (start != end) { >> + buffer = field_append(is_var, buffer, start, end); >> + if (!buffer) >> + return NULL; >> + } >> + >> + return buffer; >> +} >> + >> +static char **early_initrd_list (const char *initrd) >> +{ >> + int nlist = 0; >> + char **list = NULL; >> + char *separator; >> + >> + while ((separator = grub_strchr (initrd, ' '))) >> + { >> + list = grub_realloc (list, (nlist + 2) * sizeof (char *)); >> + if (!list) >> + return NULL; >> + >> + list[nlist++] = grub_strndup(initrd, separator - initrd); >> + list[nlist] = NULL; >> + initrd = separator + 1; >> + } >> + >> + list = grub_realloc (list, (nlist + 2) * sizeof (char *)); >> + if (!list) >> + return NULL; >> + >> + list[nlist++] = grub_strndup(initrd, grub_strlen(initrd)); >> + list[nlist] = NULL; >> + >> + return list; >> +} >> + >> +static void create_entry (struct bls_entry *entry) >> +{ >> + int argc = 0; >> + const char **argv = NULL; >> + >> + char *title = NULL; >> + char *clinux = NULL; >> + char *options = NULL; >> + char **initrds = NULL; >> + char *initrd = NULL; >> + const char *early_initrd = NULL; >> + char **early_initrds = NULL; >> + char *initrd_prefix = NULL; >> + char *devicetree = NULL; >> + char *dt = NULL; >> + char *id = entry->filename; >> + char *dotconf = id; >> + char *hotkey = NULL; >> + >> + char *users = NULL; >> + char **classes = NULL; >> + >> + char **args = NULL; >> + >> + char *src = NULL; >> + int i, index; >> + bool add_dt_prefix = false; >> + >> + grub_dprintf("blscfg", "%s got here\n", __func__); >> + clinux = bls_get_val (entry, "linux", NULL); >> + if (!clinux) >> + { >> + grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", >> entry->filename); >> + goto finish; >> + } >> + >> + /* >> + * strip the ".conf" off the end before we make it our "id" field. >> + */ >> + do >> + { >> + dotconf = grub_strstr(dotconf, ".conf"); >> + } while (dotconf != NULL && dotconf[5] != '\0'); >> + if (dotconf) >> + dotconf[0] = '\0'; >> + >> + title = bls_get_val (entry, "title", NULL); >> + options = expand_val (bls_get_val (entry, "options", NULL)); >> + >> + if (!options) >> + options = expand_val (grub_env_get("default_kernelopts")); >> + >> + initrds = bls_make_list (entry, "initrd", NULL); >> + >> + devicetree = expand_val (bls_get_val (entry, "devicetree", NULL)); >> + >> + if (!devicetree) >> + { >> + devicetree = expand_val (grub_env_get("devicetree")); >> + add_dt_prefix = true; >> + } >> + >> + hotkey = bls_get_val (entry, "grub_hotkey", NULL); >> + users = expand_val (bls_get_val (entry, "grub_users", NULL)); >> + classes = bls_make_list (entry, "grub_class", NULL); >> + args = bls_make_list (entry, "grub_arg", &argc); >> + >> + argc += 1; >> + argv = grub_malloc ((argc + 1) * sizeof (char *)); >> + argv[0] = title ? title : clinux; >> + for (i = 1; i < argc; i++) >> + argv[i] = args[i-1]; >> + argv[argc] = NULL; >> + >> + early_initrd = grub_env_get("early_initrd"); >> + >> + grub_dprintf ("blscfg", "adding menu entry for \"%s\" with id >> \"%s\"\n", >> + title, id); >> + if (early_initrd) >> + { >> + early_initrds = early_initrd_list(early_initrd); >> + if (!early_initrds) >> + { >> + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); >> + goto finish; >> + } >> + >> + if (initrds != NULL && initrds[0] != NULL) >> + { >> + initrd_prefix = grub_strrchr (initrds[0], '/'); >> + initrd_prefix = grub_strndup(initrds[0], initrd_prefix - >> initrds[0] + 1); >> + } >> + else >> + { >> + initrd_prefix = grub_strrchr (clinux, '/'); >> + initrd_prefix = grub_strndup(clinux, initrd_prefix - clinux + >> 1); >> + } >> + >> + if (!initrd_prefix) >> + { >> + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); >> + goto finish; >> + } >> + } >> + >> + if (early_initrds || initrds) >> + { >> + int initrd_size = sizeof ("initrd"); >> + char *tmp; >> + >> + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) >> + initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \ >> + + grub_strlen(initrd_prefix) \ >> + + grub_strlen (early_initrds[i]) + 1; >> + >> + for (i = 0; initrds != NULL && initrds[i] != NULL; i++) >> + initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \ >> + + grub_strlen (initrds[i]) + 1; >> + initrd_size += 1; >> + >> + initrd = grub_malloc (initrd_size); >> + if (!initrd) >> + { >> + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); >> + goto finish; >> + } >> + >> + tmp = grub_stpcpy(initrd, "initrd"); >> + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) >> + { >> + grub_dprintf ("blscfg", "adding early initrd %s\n", >> early_initrds[i]); >> + tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); >> + tmp = grub_stpcpy (tmp, initrd_prefix); >> + tmp = grub_stpcpy (tmp, early_initrds[i]); >> + grub_free(early_initrds[i]); >> + } >> + >> + for (i = 0; initrds != NULL && initrds[i] != NULL; i++) >> + { >> + grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]); >> + tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); >> + tmp = grub_stpcpy (tmp, initrds[i]); >> + } >> + tmp = grub_stpcpy (tmp, "\n"); >> + } >> + >> + if (devicetree) >> + { >> + char *prefix = NULL; >> + int dt_size; >> + >> + if (add_dt_prefix) >> + { >> + prefix = grub_strrchr (clinux, '/'); >> + prefix = grub_strndup(clinux, prefix - clinux + 1); >> + if (!prefix) >> + { >> + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); >> + goto finish; >> + } >> + } >> + >> + dt_size = sizeof("devicetree " GRUB_BOOT_DEVICE) + >> grub_strlen(devicetree) + 1; >> + >> + if (add_dt_prefix) >> + { >> + dt_size += grub_strlen(prefix); >> + } >> + >> + dt = grub_malloc (dt_size); >> + if (!dt) >> + { >> + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); >> + goto finish; >> + } >> + char *tmp = dt; >> + tmp = grub_stpcpy (dt, "devicetree"); >> + tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); >> + if (add_dt_prefix) >> + tmp = grub_stpcpy (tmp, prefix); >> + tmp = grub_stpcpy (tmp, devicetree); >> + tmp = grub_stpcpy (tmp, "\n"); >> + >> + grub_free(prefix); >> + } >> + >> + grub_dprintf ("blscfg2", "devicetree %s for id:\"%s\"\n", dt, id); >> + >> + const char *sdval = grub_env_get("save_default"); >> + bool savedefault = ((NULL != sdval) && (grub_strcmp(sdval, "true") == >> 0)); >> + src = grub_xasprintf ("%sload_video\n" >> + "set gfxpayload=keep\n" >> + "insmod gzio\n" >> + "linux %s%s%s%s\n" >> + "%s%s", >> + savedefault ? "savedefault\n" : "", >> + GRUB_BOOT_DEVICE, clinux, options ? " " : "", >> options ? options : "", >> + initrd ? initrd : "", dt ? dt : ""); >> + >> + grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, >> NULL, src, 0, &index, entry); >> + grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id); >> + >> +finish: >> + grub_free (dt); >> + grub_free (initrd); >> + grub_free (initrd_prefix); >> + grub_free (early_initrds); >> + grub_free (devicetree); >> + grub_free (initrds); >> + grub_free (options); >> + grub_free (classes); >> + grub_free (args); >> + grub_free (argv); >> + grub_free (src); >> +} >> + >> +struct find_entry_info { >> + const char *dirname; >> + const char *devid; >> + grub_device_t dev; >> + grub_fs_t fs; >> +}; >> + >> +/* >> + * info: the filesystem object the file is on. >> + */ >> +static int find_entry (struct find_entry_info *info) >> +{ >> + struct read_entry_info read_entry_info; >> + grub_fs_t blsdir_fs = NULL; >> + grub_device_t blsdir_dev = NULL; >> + const char *blsdir = info->dirname; >> + int fallback = 0; >> + int r = 0; >> + >> + if (!blsdir) { >> + blsdir = grub_env_get ("blsdir"); >> + if (!blsdir) >> + blsdir = GRUB_BLS_CONFIG_PATH; >> + } >> + >> + read_entry_info.file = NULL; >> + read_entry_info.dirname = blsdir; >> + >> + grub_dprintf ("blscfg", "scanning blsdir: %s\n", blsdir); >> + >> + blsdir_dev = info->dev; >> + blsdir_fs = info->fs; >> + read_entry_info.devid = info->devid; >> + >> +read_fallback: >> + r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry, >> + &read_entry_info); >> + if (r != 0) { >> + grub_dprintf ("blscfg", "read_entry returned error\n"); >> + grub_err_t e; >> + do >> + { >> + e = grub_error_pop(); >> + } while (e); >> + } >> + >> + if (r && !info->dirname && !fallback) { >> + read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH; >> + grub_dprintf ("blscfg", "Entries weren't found in %s, fallback to >> %s\n", >> + blsdir, read_entry_info.dirname); >> + fallback = 1; >> + goto read_fallback; >> + } >> + >> + return 0; >> +} >> + >> +static grub_err_t >> +bls_load_entries (const char *path) >> +{ >> + grub_size_t len; >> + grub_fs_t fs; >> + grub_device_t dev; >> + static grub_err_t r; >> + const char *devid = NULL; >> + char *blsdir = NULL; >> + struct find_entry_info info = { >> + .dev = NULL, >> + .fs = NULL, >> + .dirname = NULL, >> + }; >> + struct read_entry_info rei = { >> + .devid = NULL, >> + .dirname = NULL, >> + }; >> + >> + if (path) { >> + len = grub_strlen (path); >> + if (grub_strcmp (path + len - 5, ".conf") == 0) { >> + rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG); >> + if (!rei.file) >> + return grub_errno; >> + /* >> + * read_entry() closes the file >> + */ >> + return read_entry(path, NULL, &rei); >> + } else if (path[0] == '(') { >> + devid = path + 1; >> + >> + blsdir = grub_strchr (path, ')'); >> + if (!blsdir) >> + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Filepath isn't >> correct")); >> + >> + *blsdir = '\0'; >> + blsdir = blsdir + 1; >> + } >> + } >> + >> + if (!devid) { >> +#ifdef GRUB_MACHINE_EMU >> + devid = "host"; >> +#else >> + devid = grub_env_get ("root"); >> +#endif >> + if (!devid) >> + return grub_error (GRUB_ERR_FILE_NOT_FOUND, >> + N_("variable `%s' isn't set"), "root"); >> + } >> + >> + grub_dprintf ("blscfg", "opening %s\n", devid); >> + dev = grub_device_open (devid); >> + if (!dev) >> + return grub_errno; >> + >> + grub_dprintf ("blscfg", "probing fs\n"); >> + fs = grub_fs_probe (dev); >> + if (!fs) >> + { >> + r = grub_errno; >> + goto finish; >> + } >> + >> + info.dirname = blsdir; >> + info.devid = devid; >> + info.dev = dev; >> + info.fs = fs; >> + find_entry(&info); >> + >> +finish: >> + if (dev) >> + grub_device_close (dev); >> + >> + return r; >> +} >> + >> +static bool >> +is_default_entry(const char *def_entry, struct bls_entry *entry, int idx) >> +{ >> + const char *title; >> + int def_idx; >> + >> + if (!def_entry) >> + return false; >> + >> + if (grub_strcmp(def_entry, entry->filename) == 0) >> + return true; >> + >> + title = bls_get_val(entry, "title", NULL); >> + >> + if (title && grub_strcmp(def_entry, title) == 0) >> + return true; >> + >> + def_idx = (int)grub_strtol(def_entry, NULL, 0); >> + if (grub_errno == GRUB_ERR_BAD_NUMBER) { >> + grub_errno = GRUB_ERR_NONE; >> + return false; >> + } >> + >> + if (def_idx == idx) >> + return true; >> + >> + return false; >> +} >> + >> +static grub_err_t >> +bls_create_entries (bool show_default, bool show_non_default, char >> *entry_id) >> +{ >> + const char *def_entry = NULL; >> + struct bls_entry *entry = NULL; >> + int idx = 0; >> + >> + def_entry = grub_env_get("default"); >> + >> + grub_dprintf ("blscfg", "%s Creating entries from bls\n", __func__); >> + FOR_BLS_ENTRIES(entry) { >> + if (entry->visible) { >> + idx++; >> + continue; >> + } >> + >> + if ((show_default && is_default_entry(def_entry, entry, idx)) || >> + (show_non_default && !is_default_entry(def_entry, entry, idx)) || >> + (entry_id && grub_strcmp(entry_id, entry->filename) == 0)) { >> + create_entry(entry); >> + entry->visible = 1; >> + } >> + idx++; >> + } >> + >> + return GRUB_ERR_NONE; >> +} >> + >> +static grub_err_t >> +grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED, >> + int argc, char **args) >> +{ >> + grub_err_t r; >> + char *path = NULL; >> + char *entry_id = NULL; >> + bool show_default = true; >> + bool show_non_default = true; >> + >> + if (argc == 1) { >> + if (grub_strcmp (args[0], "default") == 0) { >> + show_non_default = false; >> + } else if (grub_strcmp (args[0], "non-default") == 0) { >> + show_default = false; >> + } else if (args[0][0] == '(') { >> + path = args[0]; >> + } else { >> + entry_id = args[0]; >> + show_default = false; >> + show_non_default = false; >> + } >> + } >> + >> + r = bls_load_entries(path); >> + if (r) >> + return r; >> + >> + return bls_create_entries(show_default, show_non_default, entry_id); >> +} >> + >> +static grub_extcmd_t cmd; >> +static grub_extcmd_t oldcmd; >> + >> +GRUB_MOD_INIT(blscfg) >> +{ >> + grub_dprintf("blscfg", "%s got here\n", __func__); >> + cmd = grub_register_extcmd ("blscfg", >> + grub_cmd_blscfg, >> + 0, >> + NULL, >> + N_("Import Boot Loader Specification >> snippets."), >> + NULL); >> + oldcmd = grub_register_extcmd ("bls_import", >> + grub_cmd_blscfg, >> + 0, >> + NULL, >> + N_("Import Boot Loader Specification >> snippets."), >> + NULL); >> +} >> + >> +GRUB_MOD_FINI(blscfg) >> +{ >> + grub_unregister_extcmd (cmd); >> + grub_unregister_extcmd (oldcmd); >> +} >> diff --git a/grub-core/commands/legacycfg.c >> b/grub-core/commands/legacycfg.c >> index e9e9d94ef..2c5d1a0ef 100644 >> --- a/grub-core/commands/legacycfg.c >> +++ b/grub-core/commands/legacycfg.c >> @@ -143,7 +143,7 @@ legacy_file (const char *filename) >> args[0] = oldname; >> grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy", >> NULL, NULL, >> - entrysrc, 0); >> + entrysrc, 0, NULL, NULL); >> grub_free (args); >> entrysrc[0] = 0; >> grub_free (oldname); >> @@ -205,7 +205,8 @@ legacy_file (const char *filename) >> } >> args[0] = entryname; >> grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, >> - NULL, NULL, entrysrc, 0); >> + NULL, NULL, entrysrc, 0, NULL, >> + NULL); >> grub_free (args); >> } >> >> diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c >> index 166445849..dfcb19e0f 100644 >> --- a/grub-core/commands/loadenv.c >> +++ b/grub-core/commands/loadenv.c >> @@ -28,6 +28,8 @@ >> #include <grub/extcmd.h> >> #include <grub/i18n.h> >> >> +#include "loadenv.h" >> + >> GRUB_MOD_LICENSE ("GPLv3+"); >> >> static const struct grub_arg_option options[] = >> @@ -79,81 +81,6 @@ open_envblk_file (char *filename, >> return file; >> } >> >> -static grub_envblk_t >> -read_envblk_file (grub_file_t file) >> -{ >> - grub_off_t offset = 0; >> - char *buf; >> - grub_size_t size = grub_file_size (file); >> - grub_envblk_t envblk; >> - >> - buf = grub_malloc (size); >> - if (! buf) >> - return 0; >> - >> - while (size > 0) >> - { >> - grub_ssize_t ret; >> - >> - ret = grub_file_read (file, buf + offset, size); >> - if (ret <= 0) >> - { >> - grub_free (buf); >> - return 0; >> - } >> - >> - size -= ret; >> - offset += ret; >> - } >> - >> - envblk = grub_envblk_open (buf, offset); >> - if (! envblk) >> - { >> - grub_free (buf); >> - grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); >> - return 0; >> - } >> - >> - return envblk; >> -} >> - >> -struct grub_env_whitelist >> -{ >> - grub_size_t len; >> - char **list; >> -}; >> -typedef struct grub_env_whitelist grub_env_whitelist_t; >> - >> -static int >> -test_whitelist_membership (const char* name, >> - const grub_env_whitelist_t* whitelist) >> -{ >> - grub_size_t i; >> - >> - for (i = 0; i < whitelist->len; i++) >> - if (grub_strcmp (name, whitelist->list[i]) == 0) >> - return 1; /* found it */ >> - >> - return 0; /* not found */ >> -} >> - >> -/* Helper for grub_cmd_load_env. */ >> -static int >> -set_var (const char *name, const char *value, void *whitelist) >> -{ >> - if (! whitelist) >> - { >> - grub_env_set (name, value); >> - return 0; >> - } >> - >> - if (test_whitelist_membership (name, >> - (const grub_env_whitelist_t *) >> whitelist)) >> - grub_env_set (name, value); >> - >> - return 0; >> -} >> - >> static grub_err_t >> grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args) >> { >> diff --git a/grub-core/commands/loadenv.h b/grub-core/commands/loadenv.h >> new file mode 100644 >> index 000000000..952f46121 >> --- /dev/null >> +++ b/grub-core/commands/loadenv.h >> @@ -0,0 +1,93 @@ >> +/* loadenv.c - command to load/save environment variable. */ >> +/* >> + * GRUB -- GRand Unified Bootloader >> + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. >> + * >> + * GRUB is free software: you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation, either version 3 of the License, or >> + * (at your option) any later version. >> + * >> + * GRUB is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. >> + */ >> + >> +static grub_envblk_t UNUSED >> +read_envblk_file (grub_file_t file) >> +{ >> + grub_off_t offset = 0; >> + char *buf; >> + grub_size_t size = grub_file_size (file); >> + grub_envblk_t envblk; >> + >> + buf = grub_malloc (size); >> + if (! buf) >> + return 0; >> + >> + while (size > 0) >> + { >> + grub_ssize_t ret; >> + >> + ret = grub_file_read (file, buf + offset, size); >> + if (ret <= 0) >> + { >> + grub_free (buf); >> + return 0; >> + } >> + >> + size -= ret; >> + offset += ret; >> + } >> + >> + envblk = grub_envblk_open (buf, offset); >> + if (! envblk) >> + { >> + grub_free (buf); >> + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); >> + return 0; >> + } >> + >> + return envblk; >> +} >> + >> +struct grub_env_whitelist >> +{ >> + grub_size_t len; >> + char **list; >> +}; >> +typedef struct grub_env_whitelist grub_env_whitelist_t; >> + >> +static int UNUSED >> +test_whitelist_membership (const char* name, >> + const grub_env_whitelist_t* whitelist) >> +{ >> + grub_size_t i; >> + >> + for (i = 0; i < whitelist->len; i++) >> + if (grub_strcmp (name, whitelist->list[i]) == 0) >> + return 1; /* found it */ >> + >> + return 0; /* not found */ >> +} >> + >> +/* Helper for grub_cmd_load_env. */ >> +static int UNUSED >> +set_var (const char *name, const char *value, void *whitelist) >> +{ >> + if (! whitelist) >> + { >> + grub_env_set (name, value); >> + return 0; >> + } >> + >> + if (test_whitelist_membership (name, >> + (const grub_env_whitelist_t *) >> whitelist)) >> + grub_env_set (name, value); >> + >> + return 0; >> +} >> diff --git a/grub-core/commands/menuentry.c >> b/grub-core/commands/menuentry.c >> index 720e6d8ea..b194123eb 100644 >> --- a/grub-core/commands/menuentry.c >> +++ b/grub-core/commands/menuentry.c >> @@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args, >> char **classes, const char *id, >> const char *users, const char *hotkey, >> const char *prefix, const char *sourcecode, >> - int submenu) >> + int submenu, int *index, struct bls_entry >> *bls) >> { >> int menu_hotkey = 0; >> char **menu_args = NULL; >> @@ -149,9 +149,12 @@ grub_normal_add_menu_entry (int argc, const char >> **args, >> if (! menu_title) >> goto fail; >> >> + grub_dprintf ("menu", "id:\"%s\"\n", id); >> + grub_dprintf ("menu", "title:\"%s\"\n", menu_title); >> menu_id = grub_strdup (id ? : menu_title); >> if (! menu_id) >> goto fail; >> + grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id); >> >> /* Save argc, args to pass as parameters to block arg later. */ >> menu_args = grub_calloc (argc + 1, sizeof (char *)); >> @@ -170,8 +173,12 @@ grub_normal_add_menu_entry (int argc, const char >> **args, >> } >> >> /* Add the menu entry at the end of the list. */ >> + int ind=0; >> while (*last) >> - last = &(*last)->next; >> + { >> + ind++; >> + last = &(*last)->next; >> + } >> >> *last = grub_zalloc (sizeof (**last)); >> if (! *last) >> @@ -188,8 +195,11 @@ grub_normal_add_menu_entry (int argc, const char >> **args, >> (*last)->args = menu_args; >> (*last)->sourcecode = menu_sourcecode; >> (*last)->submenu = submenu; >> + (*last)->bls = bls; >> >> menu->size++; >> + if (index) >> + *index = ind; >> return GRUB_ERR_NONE; >> >> fail: >> @@ -286,7 +296,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int >> argc, char **args) >> users, >> ctxt->state[2].arg, 0, >> ctxt->state[3].arg, >> - ctxt->extcmd->cmd->name[0] == 's'); >> + ctxt->extcmd->cmd->name[0] == 's', >> + NULL, NULL); >> >> src = args[argc - 1]; >> args[argc - 1] = NULL; >> @@ -303,7 +314,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int >> argc, char **args) >> ctxt->state[0].args, ctxt->state[4].arg, >> users, >> ctxt->state[2].arg, prefix, src + 1, >> - ctxt->extcmd->cmd->name[0] == 's'); >> + ctxt->extcmd->cmd->name[0] == 's', NULL, >> + NULL); >> >> src[len - 1] = ch; >> args[argc - 1] = src; >> diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c >> index 08f48c71d..1317279c0 100644 >> --- a/grub-core/normal/main.c >> +++ b/grub-core/normal/main.c >> @@ -21,6 +21,7 @@ >> #include <grub/net.h> >> #include <grub/normal.h> >> #include <grub/dl.h> >> +#include <grub/menu.h> >> #include <grub/misc.h> >> #include <grub/file.h> >> #include <grub/mm.h> >> @@ -70,6 +71,11 @@ grub_normal_free_menu (grub_menu_t menu) >> grub_free (entry->args); >> } >> >> + if (entry->bls) >> + { >> + entry->bls->visible = 0; >> + } >> + >> grub_free ((void *) entry->id); >> grub_free ((void *) entry->users); >> grub_free ((void *) entry->title); >> diff --git a/include/grub/compiler.h b/include/grub/compiler.h >> index 0c5519387..441a9eca0 100644 >> --- a/include/grub/compiler.h >> +++ b/include/grub/compiler.h >> @@ -56,4 +56,6 @@ >> # define CLANG_PREREQ(maj,min) 0 >> #endif >> >> +#define UNUSED __attribute__((__unused__)) >> + >> #endif /* ! GRUB_COMPILER_HEADER */ >> diff --git a/include/grub/menu.h b/include/grub/menu.h >> index ee2b5e910..0acdc2aa6 100644 >> --- a/include/grub/menu.h >> +++ b/include/grub/menu.h >> @@ -20,6 +20,16 @@ >> #ifndef GRUB_MENU_HEADER >> #define GRUB_MENU_HEADER 1 >> >> +struct bls_entry >> +{ >> + struct bls_entry *next; >> + struct bls_entry *prev; >> + struct keyval **keyvals; >> + int nkeyvals; >> + char *filename; >> + int visible; >> +}; >> + >> struct grub_menu_entry_class >> { >> char *name; >> @@ -60,6 +70,9 @@ struct grub_menu_entry >> >> /* The next element. */ >> struct grub_menu_entry *next; >> + >> + /* BLS used to populate the entry */ >> + struct bls_entry *bls; >> }; >> typedef struct grub_menu_entry *grub_menu_entry_t; >> >> diff --git a/include/grub/normal.h b/include/grub/normal.h >> index 218cbabcc..8839ad85a 100644 >> --- a/include/grub/normal.h >> +++ b/include/grub/normal.h >> @@ -145,7 +145,7 @@ grub_normal_add_menu_entry (int argc, const char >> **args, char **classes, >> const char *id, >> const char *users, const char *hotkey, >> const char *prefix, const char *sourcecode, >> - int submenu); >> + int submenu, int *index, struct bls_entry >> *bls); >> >> grub_err_t >> grub_normal_set_password (const char *user, const char *password); >> -- >> 2.46.1 >> >> >> _______________________________________________ >> Grub-devel mailing list >> Grub-devel@gnu.org >> https://lists.gnu.org/mailman/listinfo/grub-devel >> > _______________________________________________ > Grub-devel mailing list > Grub-devel@gnu.org > https://lists.gnu.org/mailman/listinfo/grub-devel >
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel