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

Reply via email to