- updated to 2.04
[packages/grub2.git] / blscfg.patch
1 diff -urN grub-2.04.orig/grub-core/commands/blscfg.c grub-2.04/grub-core/commands/blscfg.c
2 --- grub-2.04.orig/grub-core/commands/blscfg.c  1970-01-01 01:00:00.000000000 +0100
3 +++ grub-2.04/grub-core/commands/blscfg.c       2019-08-18 16:14:44.723000000 +0200
4 @@ -0,0 +1,1096 @@
5 +/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/
6 +
7 +/* bls.c - implementation of the boot loader spec */
8 +
9 +/*
10 + *  GRUB  --  GRand Unified Bootloader
11 + *
12 + *  GRUB is free software: you can redistribute it and/or modify
13 + *  it under the terms of the GNU General Public License as published by
14 + *  the Free Software Foundation, either version 3 of the License, or
15 + *  (at your option) any later version.
16 + *
17 + *  GRUB is distributed in the hope that it will be useful,
18 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 + *  GNU General Public License for more details.
21 + *
22 + *  You should have received a copy of the GNU General Public License
23 + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
24 + */
25 +
26 +#include <grub/list.h>
27 +#include <grub/types.h>
28 +#include <grub/misc.h>
29 +#include <grub/mm.h>
30 +#include <grub/err.h>
31 +#include <grub/dl.h>
32 +#include <grub/extcmd.h>
33 +#include <grub/i18n.h>
34 +#include <grub/fs.h>
35 +#include <grub/env.h>
36 +#include <grub/file.h>
37 +#include <grub/normal.h>
38 +#include <grub/lib/envblk.h>
39 +
40 +#include <stdbool.h>
41 +
42 +GRUB_MOD_LICENSE ("GPLv3+");
43 +
44 +#include "loadenv.h"
45 +
46 +#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
47 +#ifdef GRUB_MACHINE_EMU
48 +#define GRUB_BOOT_DEVICE "/boot"
49 +#else
50 +#define GRUB_BOOT_DEVICE "($root)"
51 +#endif
52 +
53 +struct keyval
54 +{
55 +  const char *key;
56 +  char *val;
57 +};
58 +
59 +static struct bls_entry *entries = NULL;
60 +
61 +#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
62 +
63 +static int bls_add_keyval(struct bls_entry *entry, char *key, char *val)
64 +{
65 +  char *k, *v;
66 +  struct keyval **kvs, *kv;
67 +  int new_n = entry->nkeyvals + 1;
68 +
69 +  kvs = grub_realloc (entry->keyvals, new_n * sizeof (struct keyval *));
70 +  if (!kvs)
71 +    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
72 +                      "couldn't find space for BLS entry");
73 +  entry->keyvals = kvs;
74 +
75 +  kv = grub_malloc (sizeof (struct keyval));
76 +  if (!kv)
77 +    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
78 +                      "couldn't find space for BLS entry");
79 +
80 +  k = grub_strdup (key);
81 +  if (!k)
82 +    {
83 +      grub_free (kv);
84 +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
85 +                        "couldn't find space for BLS entry");
86 +    }
87 +
88 +  v = grub_strdup (val);
89 +  if (!v)
90 +    {
91 +      grub_free (k);
92 +      grub_free (kv);
93 +      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
94 +                        "couldn't find space for BLS entry");
95 +    }
96 +
97 +  kv->key = k;
98 +  kv->val = v;
99 +
100 +  entry->keyvals[entry->nkeyvals] = kv;
101 +  grub_dprintf("blscfg", "new keyval at %p:%s:%s\n", entry->keyvals[entry->nkeyvals], k, v);
102 +  entry->nkeyvals = new_n;
103 +
104 +  return 0;
105 +}
106 +
107 +/* Find they value of the key named by keyname.  If there are allowed to be
108 + * more than one, pass a pointer to an int set to -1 the first time, and pass
109 + * the same pointer through each time after, and it'll return them in sorted
110 + * order as defined in the BLS fragment file */
111 +static char *bls_get_val(struct bls_entry *entry, const char *keyname, int *last)
112 +{
113 +  int idx, start = 0;
114 +  struct keyval *kv = NULL;
115 +
116 +  if (last)
117 +    start = *last + 1;
118 +
119 +  for (idx = start; idx < entry->nkeyvals; idx++) {
120 +    kv = entry->keyvals[idx];
121 +
122 +    if (!grub_strcmp (keyname, kv->key))
123 +      break;
124 +  }
125 +
126 +  if (idx == entry->nkeyvals) {
127 +    if (last)
128 +      *last = -1;
129 +    return NULL;
130 +  }
131 +
132 +  if (last)
133 +    *last = idx;
134 +
135 +  return kv->val;
136 +}
137 +
138 +#define goto_return(x) ({ ret = (x); goto finish; })
139 +
140 +/* compare alpha and numeric segments of two versions */
141 +/* return 1: a is newer than b */
142 +/*        0: a and b are the same version */
143 +/*       -1: b is newer than a */
144 +static int vercmp(const char * a, const char * b)
145 +{
146 +    char oldch1, oldch2;
147 +    char *abuf, *bbuf;
148 +    char *str1, *str2;
149 +    char * one, * two;
150 +    int rc;
151 +    int isnum;
152 +    int ret = 0;
153 +
154 +    grub_dprintf("blscfg", "%s comparing %s and %s\n", __func__, a, b);
155 +    if (!grub_strcmp(a, b))
156 +           return 0;
157 +
158 +    abuf = grub_malloc(grub_strlen(a) + 1);
159 +    bbuf = grub_malloc(grub_strlen(b) + 1);
160 +    str1 = abuf;
161 +    str2 = bbuf;
162 +    grub_strcpy(str1, a);
163 +    grub_strcpy(str2, b);
164 +
165 +    one = str1;
166 +    two = str2;
167 +
168 +    /* loop through each version segment of str1 and str2 and compare them */
169 +    while (*one || *two) {
170 +       while (*one && !grub_isalnum(*one) && *one != '~') one++;
171 +       while (*two && !grub_isalnum(*two) && *two != '~') two++;
172 +
173 +       /* handle the tilde separator, it sorts before everything else */
174 +       if (*one == '~' || *two == '~') {
175 +           if (*one != '~') goto_return (1);
176 +           if (*two != '~') goto_return (-1);
177 +           one++;
178 +           two++;
179 +           continue;
180 +       }
181 +
182 +       /* If we ran to the end of either, we are finished with the loop */
183 +       if (!(*one && *two)) break;
184 +
185 +       str1 = one;
186 +       str2 = two;
187 +
188 +       /* grab first completely alpha or completely numeric segment */
189 +       /* leave one and two pointing to the start of the alpha or numeric */
190 +       /* segment and walk str1 and str2 to end of segment */
191 +       if (grub_isdigit(*str1)) {
192 +           while (*str1 && grub_isdigit(*str1)) str1++;
193 +           while (*str2 && grub_isdigit(*str2)) str2++;
194 +           isnum = 1;
195 +       } else {
196 +           while (*str1 && grub_isalpha(*str1)) str1++;
197 +           while (*str2 && grub_isalpha(*str2)) str2++;
198 +           isnum = 0;
199 +       }
200 +
201 +       /* save character at the end of the alpha or numeric segment */
202 +       /* so that they can be restored after the comparison */
203 +       oldch1 = *str1;
204 +       *str1 = '\0';
205 +       oldch2 = *str2;
206 +       *str2 = '\0';
207 +
208 +       /* this cannot happen, as we previously tested to make sure that */
209 +       /* the first string has a non-null segment */
210 +       if (one == str1) goto_return(-1);       /* arbitrary */
211 +
212 +       /* take care of the case where the two version segments are */
213 +       /* different types: one numeric, the other alpha (i.e. empty) */
214 +       /* numeric segments are always newer than alpha segments */
215 +       /* XXX See patch #60884 (and details) from bugzilla #50977. */
216 +       if (two == str2) goto_return (isnum ? 1 : -1);
217 +
218 +       if (isnum) {
219 +           grub_size_t onelen, twolen;
220 +           /* this used to be done by converting the digit segments */
221 +           /* to ints using atoi() - it's changed because long  */
222 +           /* digit segments can overflow an int - this should fix that. */
223 +
224 +           /* throw away any leading zeros - it's a number, right? */
225 +           while (*one == '0') one++;
226 +           while (*two == '0') two++;
227 +
228 +           /* whichever number has more digits wins */
229 +           onelen = grub_strlen(one);
230 +           twolen = grub_strlen(two);
231 +           if (onelen > twolen) goto_return (1);
232 +           if (twolen > onelen) goto_return (-1);
233 +       }
234 +
235 +       /* grub_strcmp will return which one is greater - even if the two */
236 +       /* segments are alpha or if they are numeric.  don't return  */
237 +       /* if they are equal because there might be more segments to */
238 +       /* compare */
239 +       rc = grub_strcmp(one, two);
240 +       if (rc) goto_return (rc < 1 ? -1 : 1);
241 +
242 +       /* restore character that was replaced by null above */
243 +       *str1 = oldch1;
244 +       one = str1;
245 +       *str2 = oldch2;
246 +       two = str2;
247 +    }
248 +
249 +    /* this catches the case where all numeric and alpha segments have */
250 +    /* compared identically but the segment sepparating characters were */
251 +    /* different */
252 +    if ((!*one) && (!*two)) goto_return (0);
253 +
254 +    /* whichever version still has characters left over wins */
255 +    if (!*one) goto_return (-1); else goto_return (1);
256 +
257 +finish:
258 +    grub_free (abuf);
259 +    grub_free (bbuf);
260 +    return ret;
261 +}
262 +
263 +/* returns name/version/release */
264 +/* NULL string pointer returned if nothing found */
265 +static void
266 +split_package_string (char *package_string, char **name,
267 +                     char **version, char **release)
268 +{
269 +  char *package_version, *package_release;
270 +
271 +  /* Release */
272 +  package_release = grub_strrchr (package_string, '-');
273 +
274 +  if (package_release != NULL)
275 +      *package_release++ = '\0';
276 +
277 +  *release = package_release;
278 +
279 +  if (name == NULL)
280 +    {
281 +      *version = package_string;
282 +    }
283 +  else
284 +    {
285 +      /* Version */
286 +      package_version = grub_strrchr(package_string, '-');
287 +
288 +      if (package_version != NULL)
289 +       *package_version++ = '\0';
290 +
291 +      *version = package_version;
292 +      /* Name */
293 +      *name = package_string;
294 +    }
295 +
296 +  /* Bubble up non-null values from release to name */
297 +  if (name != NULL && *name == NULL)
298 +    {
299 +      *name = (*version == NULL ? *release : *version);
300 +      *version = *release;
301 +      *release = NULL;
302 +    }
303 +  if (*version == NULL)
304 +    {
305 +      *version = *release;
306 +      *release = NULL;
307 +    }
308 +}
309 +
310 +static int
311 +split_cmp(char *nvr0, char *nvr1, int has_name)
312 +{
313 +  int ret = 0;
314 +  char *name0, *version0, *release0;
315 +  char *name1, *version1, *release1;
316 +
317 +  split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0);
318 +  split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1);
319 +
320 +  if (has_name)
321 +    {
322 +      ret = vercmp(name0 == NULL ? "" : name0,
323 +                  name1 == NULL ? "" : name1);
324 +      if (ret != 0)
325 +       return ret;
326 +    }
327 +
328 +  ret = vercmp(version0 == NULL ? "" : version0,
329 +              version1 == NULL ? "" : version1);
330 +  if (ret != 0)
331 +    return ret;
332 +
333 +  ret = vercmp(release0 == NULL ? "" : release0,
334 +              release1 == NULL ? "" : release1);
335 +  return ret;
336 +}
337 +
338 +/* return 1: e0 is newer than e1 */
339 +/*        0: e0 and e1 are the same version */
340 +/*       -1: e1 is newer than e0 */
341 +static int bls_cmp(const struct bls_entry *e0, const struct bls_entry *e1)
342 +{
343 +  char *id0, *id1;
344 +  int r;
345 +
346 +  id0 = grub_strdup(e0->filename);
347 +  id1 = grub_strdup(e1->filename);
348 +
349 +  r = split_cmp(id0, id1, 1);
350 +
351 +  grub_free(id0);
352 +  grub_free(id1);
353 +
354 +  return r;
355 +}
356 +
357 +static void list_add_tail(struct bls_entry *head, struct bls_entry *item)
358 +{
359 +  item->next = head;
360 +  if (head->prev)
361 +    head->prev->next = item;
362 +  item->prev = head->prev;
363 +  head->prev = item;
364 +}
365 +
366 +static int bls_add_entry(struct bls_entry *entry)
367 +{
368 +  struct bls_entry *e, *last = NULL;
369 +  int rc;
370 +
371 +  if (!entries) {
372 +    grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename);
373 +    entries = entry;
374 +    return 0;
375 +  }
376 +
377 +  FOR_BLS_ENTRIES(e) {
378 +    rc = bls_cmp(entry, e);
379 +
380 +    if (!rc)
381 +      return GRUB_ERR_BAD_ARGUMENT;
382 +
383 +    if (rc == 1) {
384 +      grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename);
385 +      list_add_tail (e, entry);
386 +      if (e == entries) {
387 +       entries = entry;
388 +       entry->prev = NULL;
389 +      }
390 +      return 0;
391 +    }
392 +    last = e;
393 +  }
394 +
395 +  if (last) {
396 +    grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename);
397 +    last->next = entry;
398 +    entry->prev = last;
399 +  }
400 +
401 +  return 0;
402 +}
403 +
404 +struct read_entry_info {
405 +  const char *devid;
406 +  const char *dirname;
407 +  grub_file_t file;
408 +};
409 +
410 +static int read_entry (
411 +    const char *filename,
412 +    const struct grub_dirhook_info *dirhook_info UNUSED,
413 +    void *data)
414 +{
415 +  grub_size_t m = 0, n, clip = 0;
416 +  int rc = 0;
417 +  char *p = NULL;
418 +  grub_file_t f = NULL;
419 +  struct bls_entry *entry;
420 +  struct read_entry_info *info = (struct read_entry_info *)data;
421 +
422 +  grub_dprintf ("blscfg", "filename: \"%s\"\n", filename);
423 +
424 +  n = grub_strlen (filename);
425 +
426 +  if (info->file)
427 +    {
428 +      f = info->file;
429 +    }
430 +  else
431 +    {
432 +      if (filename[0] == '.')
433 +       return 0;
434 +
435 +      if (n <= 5)
436 +       return 0;
437 +
438 +      if (grub_strcmp (filename + n - 5, ".conf") != 0)
439 +       return 0;
440 +
441 +      p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
442 +
443 +      f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG);
444 +      if (!f)
445 +       goto finish;
446 +    }
447 +
448 +  entry = grub_zalloc (sizeof (*entry));
449 +  if (!entry)
450 +    goto finish;
451 +
452 +  if (info->file)
453 +    {
454 +      char *slash;
455 +
456 +      if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0)
457 +       clip = 5;
458 +
459 +      slash = grub_strrchr (filename, '/');
460 +      if (!slash)
461 +       slash = grub_strrchr (filename, '\\');
462 +
463 +      while (*slash == '/' || *slash == '\\')
464 +       slash++;
465 +
466 +      m = slash ? slash - filename : 0;
467 +    }
468 +  else
469 +    {
470 +      m = 0;
471 +      clip = 5;
472 +    }
473 +  n -= m;
474 +
475 +  entry->filename = grub_strndup(filename + m, n - clip);
476 +  if (!entry->filename)
477 +    goto finish;
478 +
479 +  entry->filename[n - 5] = '\0';
480 +
481 +  for (;;)
482 +    {
483 +      char *buf;
484 +      char *separator;
485 +
486 +      buf = grub_file_getline (f);
487 +      if (!buf)
488 +       break;
489 +
490 +      while (buf && buf[0] && (buf[0] == ' ' || buf[0] == '\t'))
491 +       buf++;
492 +      if (buf[0] == '#')
493 +       continue;
494 +
495 +      separator = grub_strchr (buf, ' ');
496 +
497 +      if (!separator)
498 +       separator = grub_strchr (buf, '\t');
499 +
500 +      if (!separator || separator[1] == '\0')
501 +       {
502 +         grub_free (buf);
503 +         break;
504 +       }
505 +
506 +      separator[0] = '\0';
507 +
508 +      do {
509 +       separator++;
510 +      } while (*separator == ' ' || *separator == '\t');
511 +
512 +      rc = bls_add_keyval (entry, buf, separator);
513 +      grub_free (buf);
514 +      if (rc < 0)
515 +       break;
516 +    }
517 +
518 +    if (!rc)
519 +      bls_add_entry(entry);
520 +
521 +finish:
522 +  if (p)
523 +    grub_free (p);
524 +
525 +  if (f)
526 +    grub_file_close (f);
527 +
528 +  return 0;
529 +}
530 +
531 +static grub_envblk_t saved_env = NULL;
532 +
533 +static int UNUSED
534 +save_var (const char *name, const char *value, void *whitelist UNUSED)
535 +{
536 +  const char *val = grub_env_get (name);
537 +  grub_dprintf("blscfg", "saving \"%s\"\n", name);
538 +
539 +  if (val)
540 +    grub_envblk_set (saved_env, name, value);
541 +
542 +  return 0;
543 +}
544 +
545 +static int UNUSED
546 +unset_var (const char *name, const char *value UNUSED, void *whitelist)
547 +{
548 +  grub_dprintf("blscfg", "restoring \"%s\"\n", name);
549 +  if (! whitelist)
550 +    {
551 +      grub_env_unset (name);
552 +      return 0;
553 +    }
554 +
555 +  if (test_whitelist_membership (name,
556 +                                (const grub_env_whitelist_t *) whitelist))
557 +    grub_env_unset (name);
558 +
559 +  return 0;
560 +}
561 +
562 +static char **bls_make_list (struct bls_entry *entry, const char *key, int *num)
563 +{
564 +  int last = -1;
565 +  char *val;
566 +
567 +  int nlist = 0;
568 +  char **list = NULL;
569 +
570 +  list = grub_malloc (sizeof (char *));
571 +  if (!list)
572 +    return NULL;
573 +  list[0] = NULL;
574 +
575 +  while (1)
576 +    {
577 +      char **new;
578 +
579 +      val = bls_get_val (entry, key, &last);
580 +      if (!val)
581 +       break;
582 +
583 +      new = grub_realloc (list, (nlist + 2) * sizeof (char *));
584 +      if (!new)
585 +       break;
586 +
587 +      list = new;
588 +      list[nlist++] = val;
589 +      list[nlist] = NULL;
590 +  }
591 +
592 +  if (num)
593 +    *num = nlist;
594 +
595 +  return list;
596 +}
597 +
598 +static char *field_append(bool is_var, char *buffer, char *start, char *end)
599 +{
600 +  char *temp = grub_strndup(start, end - start + 1);
601 +  const char *field = temp;
602 +
603 +  if (is_var) {
604 +    field = grub_env_get (temp);
605 +    if (!field)
606 +      return buffer;
607 +  }
608 +
609 +  if (!buffer) {
610 +    buffer = grub_strdup(field);
611 +    if (!buffer)
612 +      return NULL;
613 +  } else {
614 +    buffer = grub_realloc (buffer, grub_strlen(buffer) + grub_strlen(field));
615 +    if (!buffer)
616 +      return NULL;
617 +
618 +    grub_stpcpy (buffer + grub_strlen(buffer), field);
619 +  }
620 +
621 +  return buffer;
622 +}
623 +
624 +static char *expand_val(char *value)
625 +{
626 +  char *buffer = NULL;
627 +  char *start = value;
628 +  char *end = value;
629 +  bool is_var = false;
630 +
631 +  if (!value)
632 +    return NULL;
633 +
634 +  while (*value) {
635 +    if (*value == '$') {
636 +      if (start != end) {
637 +       buffer = field_append(is_var, buffer, start, end);
638 +       if (!buffer)
639 +         return NULL;
640 +      }
641 +
642 +      is_var = true;
643 +      start = value + 1;
644 +    } else if (is_var) {
645 +      if (!grub_isalnum(*value) && *value != '_') {
646 +       buffer = field_append(is_var, buffer, start, end);
647 +       is_var = false;
648 +       start = value;
649 +      }
650 +    }
651 +
652 +    end = value;
653 +    value++;
654 +  }
655 +
656 +  if (start != end) {
657 +    buffer = field_append(is_var, buffer, start, end);
658 +    if (!buffer)
659 +      return NULL;
660 +  }
661 +
662 +  return buffer;
663 +}
664 +
665 +static char **early_initrd_list (const char *initrd)
666 +{
667 +  int nlist = 0;
668 +  char **list = NULL;
669 +  char *separator;
670 +
671 +  while ((separator = grub_strchr (initrd, ' ')))
672 +    {
673 +      list = grub_realloc (list, (nlist + 2) * sizeof (char *));
674 +      if (!list)
675 +        return NULL;
676 +
677 +      list[nlist++] = grub_strndup(initrd, separator - initrd);
678 +      list[nlist] = NULL;
679 +      initrd = separator + 1;
680 +  }
681 +
682 +  list = grub_realloc (list, (nlist + 2) * sizeof (char *));
683 +  if (!list)
684 +    return NULL;
685 +
686 +  list[nlist++] = grub_strndup(initrd, grub_strlen(initrd));
687 +  list[nlist] = NULL;
688 +
689 +  return list;
690 +}
691 +
692 +static void create_entry (struct bls_entry *entry)
693 +{
694 +  int argc = 0;
695 +  const char **argv = NULL;
696 +
697 +  char *title = NULL;
698 +  char *clinux = NULL;
699 +  char *options = NULL;
700 +  char **initrds = NULL;
701 +  char *initrd = NULL;
702 +  const char *early_initrd = NULL;
703 +  char **early_initrds = NULL;
704 +  char *initrd_prefix = NULL;
705 +  char *id = entry->filename;
706 +  char *dotconf = id;
707 +  char *hotkey = NULL;
708 +
709 +  char *users = NULL;
710 +  char **classes = NULL;
711 +
712 +  char **args = NULL;
713 +
714 +  char *src = NULL;
715 +  int i, index;
716 +
717 +  grub_dprintf("blscfg", "%s got here\n", __func__);
718 +  clinux = bls_get_val (entry, "linux", NULL);
719 +  if (!clinux)
720 +    {
721 +      grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", entry->filename);
722 +      goto finish;
723 +    }
724 +
725 +  /*
726 +   * strip the ".conf" off the end before we make it our "id" field.
727 +   */
728 +  do
729 +    {
730 +      dotconf = grub_strstr(dotconf, ".conf");
731 +    } while (dotconf != NULL && dotconf[5] != '\0');
732 +  if (dotconf)
733 +    dotconf[0] = '\0';
734 +
735 +  title = bls_get_val (entry, "title", NULL);
736 +  options = expand_val (bls_get_val (entry, "options", NULL));
737 +
738 +  if (!options)
739 +    options = expand_val (grub_env_get("default_kernelopts"));
740 +
741 +  initrds = bls_make_list (entry, "initrd", NULL);
742 +
743 +  hotkey = bls_get_val (entry, "grub_hotkey", NULL);
744 +  users = expand_val (bls_get_val (entry, "grub_users", NULL));
745 +  classes = bls_make_list (entry, "grub_class", NULL);
746 +  args = bls_make_list (entry, "grub_arg", &argc);
747 +
748 +  argc += 1;
749 +  argv = grub_malloc ((argc + 1) * sizeof (char *));
750 +  argv[0] = title ? title : clinux;
751 +  for (i = 1; i < argc; i++)
752 +    argv[i] = args[i-1];
753 +  argv[argc] = NULL;
754 +
755 +  early_initrd = grub_env_get("early_initrd");
756 +
757 +  grub_dprintf ("blscfg", "adding menu entry for \"%s\" with id \"%s\"\n",
758 +               title, id);
759 +  if (early_initrd)
760 +    {
761 +      early_initrds = early_initrd_list(early_initrd);
762 +      if (!early_initrds)
763 +      {
764 +       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
765 +       goto finish;
766 +      }
767 +
768 +      if (initrds != NULL && initrds[0] != NULL)
769 +       {
770 +         initrd_prefix = grub_strrchr (initrds[0], '/');
771 +         initrd_prefix = grub_strndup(initrds[0], initrd_prefix - initrds[0] + 1);
772 +       }
773 +      else
774 +       {
775 +         initrd_prefix = grub_strrchr (clinux, '/');
776 +         initrd_prefix = grub_strndup(clinux, initrd_prefix - clinux + 1);
777 +       }
778 +
779 +      if (!initrd_prefix)
780 +       {
781 +         grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
782 +         goto finish;
783 +       }
784 +    }
785 +
786 +  if (early_initrds || initrds)
787 +    {
788 +      int initrd_size = sizeof ("initrd");
789 +      char *tmp;
790 +
791 +      for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
792 +       initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \
793 +                      + grub_strlen(initrd_prefix)  \
794 +                      + grub_strlen (early_initrds[i]) + 1;
795 +
796 +      for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
797 +       initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \
798 +                      + grub_strlen (initrds[i]) + 1;
799 +      initrd_size += 1;
800 +
801 +      initrd = grub_malloc (initrd_size);
802 +      if (!initrd)
803 +       {
804 +         grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
805 +         goto finish;
806 +       }
807 +
808 +
809 +      tmp = grub_stpcpy(initrd, "initrd");
810 +      for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
811 +       {
812 +         grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]);
813 +         tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
814 +         tmp = grub_stpcpy (tmp, initrd_prefix);
815 +         tmp = grub_stpcpy (tmp, early_initrds[i]);
816 +         grub_free(early_initrds[i]);
817 +       }
818 +
819 +      for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
820 +       {
821 +         grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]);
822 +         tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
823 +         tmp = grub_stpcpy (tmp, initrds[i]);
824 +       }
825 +      tmp = grub_stpcpy (tmp, "\n");
826 +    }
827 +
828 +  src = grub_xasprintf ("load_video\n"
829 +                       "set gfxpayload=keep\n"
830 +                       "insmod gzio\n"
831 +                       "linux %s%s%s%s\n"
832 +                       "%s",
833 +                       GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "",
834 +                       initrd ? initrd : "");
835 +
836 +  grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry);
837 +  grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id);
838 +
839 +finish:
840 +  grub_free (initrd);
841 +  grub_free (initrd_prefix);
842 +  grub_free (early_initrds);
843 +  grub_free (initrds);
844 +  grub_free (options);
845 +  grub_free (classes);
846 +  grub_free (args);
847 +  grub_free (argv);
848 +  grub_free (src);
849 +}
850 +
851 +struct find_entry_info {
852 +       const char *dirname;
853 +       const char *devid;
854 +       grub_device_t dev;
855 +       grub_fs_t fs;
856 +};
857 +
858 +/*
859 + * info: the filesystem object the file is on.
860 + */
861 +static int find_entry (struct find_entry_info *info)
862 +{
863 +  struct read_entry_info read_entry_info;
864 +  grub_fs_t blsdir_fs = NULL;
865 +  grub_device_t blsdir_dev = NULL;
866 +  const char *blsdir = info->dirname;
867 +  int fallback = 0;
868 +  int r = 0;
869 +
870 +  if (!blsdir) {
871 +    blsdir = grub_env_get ("blsdir");
872 +    if (!blsdir)
873 +      blsdir = GRUB_BLS_CONFIG_PATH;
874 +  }
875 +
876 +  read_entry_info.file = NULL;
877 +  read_entry_info.dirname = blsdir;
878 +
879 +  grub_dprintf ("blscfg", "scanning blsdir: %s\n", blsdir);
880 +
881 +  blsdir_dev = info->dev;
882 +  blsdir_fs = info->fs;
883 +  read_entry_info.devid = info->devid;
884 +
885 +read_fallback:
886 +  r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry,
887 +                        &read_entry_info);
888 +  if (r != 0) {
889 +      grub_dprintf ("blscfg", "read_entry returned error\n");
890 +      grub_err_t e;
891 +      do
892 +       {
893 +         e = grub_error_pop();
894 +       } while (e);
895 +  }
896 +
897 +  if (r && !info->dirname && !fallback) {
898 +    read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH;
899 +    grub_dprintf ("blscfg", "Entries weren't found in %s, fallback to %s\n",
900 +                 blsdir, read_entry_info.dirname);
901 +    fallback = 1;
902 +    goto read_fallback;
903 +  }
904 +
905 +  return 0;
906 +}
907 +
908 +static grub_err_t
909 +bls_load_entries (const char *path)
910 +{
911 +  grub_size_t len;
912 +  grub_fs_t fs;
913 +  grub_device_t dev;
914 +  static grub_err_t r;
915 +  const char *devid = NULL;
916 +  char *blsdir = NULL;
917 +  struct find_entry_info info = {
918 +      .dev = NULL,
919 +      .fs = NULL,
920 +      .dirname = NULL,
921 +  };
922 +  struct read_entry_info rei = {
923 +      .devid = NULL,
924 +      .dirname = NULL,
925 +  };
926 +
927 +  if (path) {
928 +    len = grub_strlen (path);
929 +    if (grub_strcmp (path + len - 5, ".conf") == 0) {
930 +      rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG);
931 +      if (!rei.file)
932 +       return grub_errno;
933 +      /*
934 +       * read_entry() closes the file
935 +       */
936 +      return read_entry(path, NULL, &rei);
937 +    } else if (path[0] == '(') {
938 +      devid = path + 1;
939 +
940 +      blsdir = grub_strchr (path, ')');
941 +      if (!blsdir)
942 +       return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Filepath isn't correct"));
943 +
944 +      *blsdir = '\0';
945 +      blsdir = blsdir + 1;
946 +    }
947 +  }
948 +
949 +  if (!devid) {
950 +#ifdef GRUB_MACHINE_EMU
951 +    devid = "host";
952 +#elif defined(GRUB_MACHINE_EFI)
953 +    devid = grub_env_get ("root");
954 +#else
955 +    devid = grub_env_get ("boot");
956 +#endif
957 +    if (!devid)
958 +      return grub_error (GRUB_ERR_FILE_NOT_FOUND,
959 +                        N_("variable `%s' isn't set"), "boot");
960 +  }
961 +
962 +  grub_dprintf ("blscfg", "opening %s\n", devid);
963 +  dev = grub_device_open (devid);
964 +  if (!dev)
965 +    return grub_errno;
966 +
967 +  grub_dprintf ("blscfg", "probing fs\n");
968 +  fs = grub_fs_probe (dev);
969 +  if (!fs)
970 +    {
971 +      r = grub_errno;
972 +      goto finish;
973 +    }
974 +
975 +  info.dirname = blsdir;
976 +  info.devid = devid;
977 +  info.dev = dev;
978 +  info.fs = fs;
979 +  find_entry(&info);
980 +
981 +finish:
982 +  if (dev)
983 +    grub_device_close (dev);
984 +
985 +  return r;
986 +}
987 +
988 +static bool
989 +is_default_entry(const char *def_entry, struct bls_entry *entry, int idx)
990 +{
991 +  const char *title;
992 +  int def_idx;
993 +
994 +  if (!def_entry)
995 +    return false;
996 +
997 +  if (grub_strcmp(def_entry, entry->filename) == 0)
998 +    return true;
999 +
1000 +  title = bls_get_val(entry, "title", NULL);
1001 +
1002 +  if (title && grub_strcmp(def_entry, title) == 0)
1003 +    return true;
1004 +
1005 +  def_idx = (int)grub_strtol(def_entry, NULL, 0);
1006 +  if (grub_errno == GRUB_ERR_BAD_NUMBER) {
1007 +    grub_errno = GRUB_ERR_NONE;
1008 +    return false;
1009 +  }
1010 +
1011 +  if (def_idx == idx)
1012 +    return true;
1013 +
1014 +  return false;
1015 +}
1016 +
1017 +static grub_err_t
1018 +bls_create_entries (bool show_default, bool show_non_default, char *entry_id)
1019 +{
1020 +  const char *def_entry = NULL;
1021 +  struct bls_entry *entry = NULL;
1022 +  int idx = 0;
1023 +
1024 +  def_entry = grub_env_get("default");
1025 +
1026 +  grub_dprintf ("blscfg", "%s Creating entries from bls\n", __func__);
1027 +  FOR_BLS_ENTRIES(entry) {
1028 +    if (entry->visible) {
1029 +      idx++;
1030 +      continue;
1031 +    }
1032 +
1033 +    if ((show_default && is_default_entry(def_entry, entry, idx)) ||
1034 +       (show_non_default && !is_default_entry(def_entry, entry, idx)) ||
1035 +       (entry_id && grub_strcmp(entry_id, entry->filename) == 0)) {
1036 +      create_entry(entry);
1037 +      entry->visible = 1;
1038 +    }
1039 +    idx++;
1040 +  }
1041 +
1042 +  return GRUB_ERR_NONE;
1043 +}
1044 +
1045 +static grub_err_t
1046 +grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
1047 +                int argc, char **args)
1048 +{
1049 +  grub_err_t r;
1050 +  char *path = NULL;
1051 +  char *entry_id = NULL;
1052 +  bool show_default = true;
1053 +  bool show_non_default = true;
1054 +
1055 +  if (argc == 1) {
1056 +    if (grub_strcmp (args[0], "default") == 0) {
1057 +      show_non_default = false;
1058 +    } else if (grub_strcmp (args[0], "non-default") == 0) {
1059 +      show_default = false;
1060 +    } else if (args[0][0] == '(') {
1061 +      path = args[0];
1062 +    } else {
1063 +      entry_id = args[0];
1064 +      show_default = false;
1065 +      show_non_default = false;
1066 +    }
1067 +  }
1068 +
1069 +  r = bls_load_entries(path);
1070 +  if (r)
1071 +    return r;
1072 +
1073 +  return bls_create_entries(show_default, show_non_default, entry_id);
1074 +}
1075 +
1076 +static grub_extcmd_t cmd;
1077 +static grub_extcmd_t oldcmd;
1078 +
1079 +GRUB_MOD_INIT(blscfg)
1080 +{
1081 +  grub_dprintf("blscfg", "%s got here\n", __func__);
1082 +  cmd = grub_register_extcmd ("blscfg",
1083 +                             grub_cmd_blscfg,
1084 +                             0,
1085 +                             NULL,
1086 +                             N_("Import Boot Loader Specification snippets."),
1087 +                             NULL);
1088 +  oldcmd = grub_register_extcmd ("bls_import",
1089 +                                grub_cmd_blscfg,
1090 +                                0,
1091 +                                NULL,
1092 +                                N_("Import Boot Loader Specification snippets."),
1093 +                                NULL);
1094 +}
1095 +
1096 +GRUB_MOD_FINI(blscfg)
1097 +{
1098 +  grub_unregister_extcmd (cmd);
1099 +  grub_unregister_extcmd (oldcmd);
1100 +}
1101 diff -urN grub-2.04.orig/grub-core/commands/legacycfg.c grub-2.04/grub-core/commands/legacycfg.c
1102 --- grub-2.04.orig/grub-core/commands/legacycfg.c       2018-11-24 18:13:02.000000000 +0100
1103 +++ grub-2.04/grub-core/commands/legacycfg.c    2019-08-18 16:14:44.723000000 +0200
1104 @@ -133,7 +133,7 @@
1105             args[0] = oldname;
1106             grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy",
1107                                         NULL, NULL,
1108 -                                       entrysrc, 0);
1109 +                                       entrysrc, 0, NULL, NULL);
1110             grub_free (args);
1111             entrysrc[0] = 0;
1112             grub_free (oldname);
1113 @@ -186,7 +186,8 @@
1114         }
1115        args[0] = entryname;
1116        grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
1117 -                                 NULL, NULL, entrysrc, 0);
1118 +                                 NULL, NULL, entrysrc, 0, NULL,
1119 +                                 NULL);
1120        grub_free (args);
1121      }
1122  
1123 diff -urN grub-2.04.orig/grub-core/commands/loadenv.c grub-2.04/grub-core/commands/loadenv.c
1124 --- grub-2.04.orig/grub-core/commands/loadenv.c 2018-11-24 18:13:02.000000000 +0100
1125 +++ grub-2.04/grub-core/commands/loadenv.c      2019-08-18 16:14:44.723000000 +0200
1126 @@ -28,6 +28,8 @@
1127  #include <grub/extcmd.h>
1128  #include <grub/i18n.h>
1129  
1130 +#include "loadenv.h"
1131 +
1132  GRUB_MOD_LICENSE ("GPLv3+");
1133  
1134  static const struct grub_arg_option options[] =
1135 @@ -79,81 +81,6 @@
1136    return file;
1137  }
1138  
1139 -static grub_envblk_t
1140 -read_envblk_file (grub_file_t file)
1141 -{
1142 -  grub_off_t offset = 0;
1143 -  char *buf;
1144 -  grub_size_t size = grub_file_size (file);
1145 -  grub_envblk_t envblk;
1146 -
1147 -  buf = grub_malloc (size);
1148 -  if (! buf)
1149 -    return 0;
1150 -
1151 -  while (size > 0)
1152 -    {
1153 -      grub_ssize_t ret;
1154 -
1155 -      ret = grub_file_read (file, buf + offset, size);
1156 -      if (ret <= 0)
1157 -        {
1158 -          grub_free (buf);
1159 -          return 0;
1160 -        }
1161 -
1162 -      size -= ret;
1163 -      offset += ret;
1164 -    }
1165 -
1166 -  envblk = grub_envblk_open (buf, offset);
1167 -  if (! envblk)
1168 -    {
1169 -      grub_free (buf);
1170 -      grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
1171 -      return 0;
1172 -    }
1173 -
1174 -  return envblk;
1175 -}
1176 -
1177 -struct grub_env_whitelist
1178 -{
1179 -  grub_size_t len;
1180 -  char **list;
1181 -};
1182 -typedef struct grub_env_whitelist grub_env_whitelist_t;
1183 -
1184 -static int
1185 -test_whitelist_membership (const char* name,
1186 -                           const grub_env_whitelist_t* whitelist)
1187 -{
1188 -  grub_size_t i;
1189 -
1190 -  for (i = 0; i < whitelist->len; i++)
1191 -    if (grub_strcmp (name, whitelist->list[i]) == 0)
1192 -      return 1;  /* found it */
1193 -
1194 -  return 0;  /* not found */
1195 -}
1196 -
1197 -/* Helper for grub_cmd_load_env.  */
1198 -static int
1199 -set_var (const char *name, const char *value, void *whitelist)
1200 -{
1201 -  if (! whitelist)
1202 -    {
1203 -      grub_env_set (name, value);
1204 -      return 0;
1205 -    }
1206 -
1207 -  if (test_whitelist_membership (name,
1208 -                                (const grub_env_whitelist_t *) whitelist))
1209 -    grub_env_set (name, value);
1210 -
1211 -  return 0;
1212 -}
1213 -
1214  static grub_err_t
1215  grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args)
1216  {
1217 diff -urN grub-2.04.orig/grub-core/commands/loadenv.h grub-2.04/grub-core/commands/loadenv.h
1218 --- grub-2.04.orig/grub-core/commands/loadenv.h 1970-01-01 01:00:00.000000000 +0100
1219 +++ grub-2.04/grub-core/commands/loadenv.h      2019-08-18 16:14:44.724000000 +0200
1220 @@ -0,0 +1,93 @@
1221 +/* loadenv.c - command to load/save environment variable.  */
1222 +/*
1223 + *  GRUB  --  GRand Unified Bootloader
1224 + *  Copyright (C) 2008,2009,2010  Free Software Foundation, Inc.
1225 + *
1226 + *  GRUB is free software: you can redistribute it and/or modify
1227 + *  it under the terms of the GNU General Public License as published by
1228 + *  the Free Software Foundation, either version 3 of the License, or
1229 + *  (at your option) any later version.
1230 + *
1231 + *  GRUB is distributed in the hope that it will be useful,
1232 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1233 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1234 + *  GNU General Public License for more details.
1235 + *
1236 + *  You should have received a copy of the GNU General Public License
1237 + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
1238 + */
1239 +
1240 +static grub_envblk_t UNUSED
1241 +read_envblk_file (grub_file_t file)
1242 +{
1243 +  grub_off_t offset = 0;
1244 +  char *buf;
1245 +  grub_size_t size = grub_file_size (file);
1246 +  grub_envblk_t envblk;
1247 +
1248 +  buf = grub_malloc (size);
1249 +  if (! buf)
1250 +    return 0;
1251 +
1252 +  while (size > 0)
1253 +    {
1254 +      grub_ssize_t ret;
1255 +
1256 +      ret = grub_file_read (file, buf + offset, size);
1257 +      if (ret <= 0)
1258 +        {
1259 +          grub_free (buf);
1260 +          return 0;
1261 +        }
1262 +
1263 +      size -= ret;
1264 +      offset += ret;
1265 +    }
1266 +
1267 +  envblk = grub_envblk_open (buf, offset);
1268 +  if (! envblk)
1269 +    {
1270 +      grub_free (buf);
1271 +      grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
1272 +      return 0;
1273 +    }
1274 +
1275 +  return envblk;
1276 +}
1277 +
1278 +struct grub_env_whitelist
1279 +{
1280 +  grub_size_t len;
1281 +  char **list;
1282 +};
1283 +typedef struct grub_env_whitelist grub_env_whitelist_t;
1284 +
1285 +static int UNUSED
1286 +test_whitelist_membership (const char* name,
1287 +                           const grub_env_whitelist_t* whitelist)
1288 +{
1289 +  grub_size_t i;
1290 +
1291 +  for (i = 0; i < whitelist->len; i++)
1292 +    if (grub_strcmp (name, whitelist->list[i]) == 0)
1293 +      return 1;  /* found it */
1294 +
1295 +  return 0;  /* not found */
1296 +}
1297 +
1298 +/* Helper for grub_cmd_load_env.  */
1299 +static int UNUSED
1300 +set_var (const char *name, const char *value, void *whitelist)
1301 +{
1302 +  if (! whitelist)
1303 +    {
1304 +      grub_env_set (name, value);
1305 +      return 0;
1306 +    }
1307 +
1308 +  if (test_whitelist_membership (name,
1309 +                                (const grub_env_whitelist_t *) whitelist))
1310 +    grub_env_set (name, value);
1311 +
1312 +  return 0;
1313 +}
1314 diff -urN grub-2.04.orig/grub-core/commands/menuentry.c grub-2.04/grub-core/commands/menuentry.c
1315 --- grub-2.04.orig/grub-core/commands/menuentry.c       2018-11-24 18:13:02.000000000 +0100
1316 +++ grub-2.04/grub-core/commands/menuentry.c    2019-08-18 16:14:44.723000000 +0200
1317 @@ -78,7 +78,7 @@
1318                             char **classes, const char *id,
1319                             const char *users, const char *hotkey,
1320                             const char *prefix, const char *sourcecode,
1321 -                           int submenu)
1322 +                           int submenu, int *index, struct bls_entry *bls)
1323  {
1324    int menu_hotkey = 0;
1325    char **menu_args = NULL;
1326 @@ -149,9 +149,12 @@
1327    if (! menu_title)
1328      goto fail;
1329  
1330 +  grub_dprintf ("menu", "id:\"%s\"\n", id);
1331 +  grub_dprintf ("menu", "title:\"%s\"\n", menu_title);
1332    menu_id = grub_strdup (id ? : menu_title);
1333    if (! menu_id)
1334      goto fail;
1335 +  grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id);
1336  
1337    /* Save argc, args to pass as parameters to block arg later. */
1338    menu_args = grub_malloc (sizeof (char*) * (argc + 1));
1339 @@ -170,8 +173,12 @@
1340    }
1341  
1342    /* Add the menu entry at the end of the list.  */
1343 +  int ind=0;
1344    while (*last)
1345 -    last = &(*last)->next;
1346 +    {
1347 +      ind++;
1348 +      last = &(*last)->next;
1349 +    }
1350  
1351    *last = grub_zalloc (sizeof (**last));
1352    if (! *last)
1353 @@ -188,8 +195,11 @@
1354    (*last)->args = menu_args;
1355    (*last)->sourcecode = menu_sourcecode;
1356    (*last)->submenu = submenu;
1357 +  (*last)->bls = bls;
1358  
1359    menu->size++;
1360 +  if (index)
1361 +    *index = ind;
1362    return GRUB_ERR_NONE;
1363  
1364   fail:
1365 @@ -286,7 +296,8 @@
1366                                        users,
1367                                        ctxt->state[2].arg, 0,
1368                                        ctxt->state[3].arg,
1369 -                                      ctxt->extcmd->cmd->name[0] == 's');
1370 +                                      ctxt->extcmd->cmd->name[0] == 's',
1371 +                                      NULL, NULL);
1372  
1373    src = args[argc - 1];
1374    args[argc - 1] = NULL;
1375 @@ -303,7 +314,8 @@
1376                                   ctxt->state[0].args, ctxt->state[4].arg,
1377                                   users,
1378                                   ctxt->state[2].arg, prefix, src + 1,
1379 -                                 ctxt->extcmd->cmd->name[0] == 's');
1380 +                                 ctxt->extcmd->cmd->name[0] == 's', NULL,
1381 +                                 NULL);
1382  
1383    src[len - 1] = ch;
1384    args[argc - 1] = src;
1385 diff -urN grub-2.04.orig/grub-core/Makefile.core.def grub-2.04/grub-core/Makefile.core.def
1386 --- grub-2.04.orig/grub-core/Makefile.core.def  2019-04-23 10:54:47.000000000 +0200
1387 +++ grub-2.04/grub-core/Makefile.core.def       2019-08-18 16:14:44.723000000 +0200
1388 @@ -810,6 +810,16 @@
1389  };
1390  
1391  module = {
1392 +  name = blscfg;
1393 +  common = commands/blscfg.c;
1394 +  common = commands/loadenv.h;
1395 +  enable = powerpc_ieee1275;
1396 +  enable = efi;
1397 +  enable = i386_pc;
1398 +  enable = emu;
1399 +};
1400 +
1401 +module = {
1402    name = boot;
1403    common = commands/boot.c;
1404    i386_pc = lib/i386/pc/biosnum.c;
1405 @@ -986,6 +996,7 @@
1406  module = {
1407    name = loadenv;
1408    common = commands/loadenv.c;
1409 +  common = commands/loadenv.h;
1410    common = lib/envblk.c;
1411  };
1412  
1413 diff -urN grub-2.04.orig/grub-core/normal/main.c grub-2.04/grub-core/normal/main.c
1414 --- grub-2.04.orig/grub-core/normal/main.c      2018-11-24 18:13:02.000000000 +0100
1415 +++ grub-2.04/grub-core/normal/main.c   2019-08-18 16:14:44.724000000 +0200
1416 @@ -20,6 +20,7 @@
1417  #include <grub/kernel.h>
1418  #include <grub/normal.h>
1419  #include <grub/dl.h>
1420 +#include <grub/menu.h>
1421  #include <grub/misc.h>
1422  #include <grub/file.h>
1423  #include <grub/mm.h>
1424 @@ -66,6 +67,11 @@
1425           grub_free (entry->args);
1426         }
1427  
1428 +      if (entry->bls)
1429 +       {
1430 +         entry->bls->visible = 0;
1431 +       }
1432 +
1433        grub_free ((void *) entry->id);
1434        grub_free ((void *) entry->users);
1435        grub_free ((void *) entry->title);
1436 diff -urN grub-2.04.orig/include/grub/compiler.h grub-2.04/include/grub/compiler.h
1437 --- grub-2.04.orig/include/grub/compiler.h      2018-11-24 18:13:02.000000000 +0100
1438 +++ grub-2.04/include/grub/compiler.h   2019-08-18 16:14:44.724000000 +0200
1439 @@ -48,4 +48,6 @@
1440  #  define WARN_UNUSED_RESULT
1441  #endif
1442  
1443 +#define UNUSED __attribute__((__unused__))
1444 +
1445  #endif /* ! GRUB_COMPILER_HEADER */
1446 diff -urN grub-2.04.orig/include/grub/menu.h grub-2.04/include/grub/menu.h
1447 --- grub-2.04.orig/include/grub/menu.h  2018-11-24 18:13:02.000000000 +0100
1448 +++ grub-2.04/include/grub/menu.h       2019-08-18 16:14:44.724000000 +0200
1449 @@ -20,6 +20,16 @@
1450  #ifndef GRUB_MENU_HEADER
1451  #define GRUB_MENU_HEADER 1
1452  
1453 +struct bls_entry
1454 +{
1455 +  struct bls_entry *next;
1456 +  struct bls_entry *prev;
1457 +  struct keyval **keyvals;
1458 +  int nkeyvals;
1459 +  char *filename;
1460 +  int visible;
1461 +};
1462 +
1463  struct grub_menu_entry_class
1464  {
1465    char *name;
1466 @@ -60,6 +70,9 @@
1467  
1468    /* The next element.  */
1469    struct grub_menu_entry *next;
1470 +
1471 +  /* BLS used to populate the entry */
1472 +  struct bls_entry *bls;
1473  };
1474  typedef struct grub_menu_entry *grub_menu_entry_t;
1475  
1476 diff -urN grub-2.04.orig/include/grub/normal.h grub-2.04/include/grub/normal.h
1477 --- grub-2.04.orig/include/grub/normal.h        2018-11-24 18:13:02.000000000 +0100
1478 +++ grub-2.04/include/grub/normal.h     2019-08-18 16:14:44.724000000 +0200
1479 @@ -145,7 +145,7 @@
1480                             const char *id,
1481                             const char *users, const char *hotkey,
1482                             const char *prefix, const char *sourcecode,
1483 -                           int submenu);
1484 +                           int submenu, int *index, struct bls_entry *bls);
1485  
1486  grub_err_t
1487  grub_normal_set_password (const char *user, const char *password);