1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Peter Jones <pjones@redhat.com>
3 Date: Tue, 22 Jan 2013 06:31:38 +0100
4 Subject: [PATCH] blscfg: add blscfg module to parse Boot Loader Specification
7 The BootLoaderSpec (BLS) defines a scheme where different bootloaders can
8 share a format for boot items and a configuration directory that accepts
9 these common configurations as drop-in files.
11 Signed-off-by: Peter Jones <pjones@redhat.com>
12 Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
13 [wjt: some cleanups and fixes]
14 Signed-off-by: Will Thompson <wjt@endlessm.com>
16 grub-core/Makefile.core.def | 11 +
17 grub-core/commands/blscfg.c | 1096 ++++++++++++++++++++++++++++++++++++++++
18 grub-core/commands/legacycfg.c | 5 +-
19 grub-core/commands/loadenv.c | 77 +--
20 grub-core/commands/menuentry.c | 20 +-
21 grub-core/normal/main.c | 6 +
22 grub-core/commands/loadenv.h | 93 ++++
23 include/grub/compiler.h | 2 +
24 include/grub/menu.h | 13 +
25 include/grub/normal.h | 2 +-
26 10 files changed, 1243 insertions(+), 82 deletions(-)
27 create mode 100644 grub-core/commands/blscfg.c
28 create mode 100644 grub-core/commands/loadenv.h
30 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
31 index 41b5e16a3ce..57e253ab1a1 100644
32 --- a/grub-core/Makefile.core.def
33 +++ b/grub-core/Makefile.core.def
34 @@ -811,6 +811,16 @@ module = {
35 common = commands/blocklist.c;
40 + common = commands/blscfg.c;
41 + common = commands/loadenv.h;
42 + enable = powerpc_ieee1275;
50 common = commands/boot.c;
51 @@ -988,6 +998,7 @@ module = {
54 common = commands/loadenv.c;
55 + common = commands/loadenv.h;
56 common = lib/envblk.c;
59 diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
61 index 00000000000..54458b14518
63 +++ b/grub-core/commands/blscfg.c
65 +/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/
67 +/* bls.c - implementation of the boot loader spec */
70 + * GRUB -- GRand Unified Bootloader
72 + * GRUB is free software: you can redistribute it and/or modify
73 + * it under the terms of the GNU General Public License as published by
74 + * the Free Software Foundation, either version 3 of the License, or
75 + * (at your option) any later version.
77 + * GRUB is distributed in the hope that it will be useful,
78 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
79 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
80 + * GNU General Public License for more details.
82 + * You should have received a copy of the GNU General Public License
83 + * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
86 +#include <grub/list.h>
87 +#include <grub/types.h>
88 +#include <grub/misc.h>
90 +#include <grub/err.h>
92 +#include <grub/extcmd.h>
93 +#include <grub/i18n.h>
95 +#include <grub/env.h>
96 +#include <grub/file.h>
97 +#include <grub/normal.h>
98 +#include <grub/lib/envblk.h>
100 +#include <stdbool.h>
102 +GRUB_MOD_LICENSE ("GPLv3+");
104 +#include "loadenv.h"
106 +#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
107 +#ifdef GRUB_MACHINE_EMU
108 +#define GRUB_BOOT_DEVICE "/boot"
110 +#define GRUB_BOOT_DEVICE "($root)"
119 +static struct bls_entry *entries = NULL;
121 +#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
123 +static int bls_add_keyval(struct bls_entry *entry, char *key, char *val)
126 + struct keyval **kvs, *kv;
127 + int new_n = entry->nkeyvals + 1;
129 + kvs = grub_realloc (entry->keyvals, new_n * sizeof (struct keyval *));
131 + return grub_error (GRUB_ERR_OUT_OF_MEMORY,
132 + "couldn't find space for BLS entry");
133 + entry->keyvals = kvs;
135 + kv = grub_malloc (sizeof (struct keyval));
137 + return grub_error (GRUB_ERR_OUT_OF_MEMORY,
138 + "couldn't find space for BLS entry");
140 + k = grub_strdup (key);
144 + return grub_error (GRUB_ERR_OUT_OF_MEMORY,
145 + "couldn't find space for BLS entry");
148 + v = grub_strdup (val);
153 + return grub_error (GRUB_ERR_OUT_OF_MEMORY,
154 + "couldn't find space for BLS entry");
160 + entry->keyvals[entry->nkeyvals] = kv;
161 + grub_dprintf("blscfg", "new keyval at %p:%s:%s\n", entry->keyvals[entry->nkeyvals], k, v);
162 + entry->nkeyvals = new_n;
167 +/* Find they value of the key named by keyname. If there are allowed to be
168 + * more than one, pass a pointer to an int set to -1 the first time, and pass
169 + * the same pointer through each time after, and it'll return them in sorted
170 + * order as defined in the BLS fragment file */
171 +static char *bls_get_val(struct bls_entry *entry, const char *keyname, int *last)
173 + int idx, start = 0;
174 + struct keyval *kv = NULL;
179 + for (idx = start; idx < entry->nkeyvals; idx++) {
180 + kv = entry->keyvals[idx];
182 + if (!grub_strcmp (keyname, kv->key))
186 + if (idx == entry->nkeyvals) {
198 +#define goto_return(x) ({ ret = (x); goto finish; })
200 +/* compare alpha and numeric segments of two versions */
201 +/* return 1: a is newer than b */
202 +/* 0: a and b are the same version */
203 +/* -1: b is newer than a */
204 +static int vercmp(const char * a, const char * b)
206 + char oldch1, oldch2;
214 + grub_dprintf("blscfg", "%s comparing %s and %s\n", __func__, a, b);
215 + if (!grub_strcmp(a, b))
218 + abuf = grub_malloc(grub_strlen(a) + 1);
219 + bbuf = grub_malloc(grub_strlen(b) + 1);
222 + grub_strcpy(str1, a);
223 + grub_strcpy(str2, b);
228 + /* loop through each version segment of str1 and str2 and compare them */
229 + while (*one || *two) {
230 + while (*one && !grub_isalnum(*one) && *one != '~') one++;
231 + while (*two && !grub_isalnum(*two) && *two != '~') two++;
233 + /* handle the tilde separator, it sorts before everything else */
234 + if (*one == '~' || *two == '~') {
235 + if (*one != '~') goto_return (1);
236 + if (*two != '~') goto_return (-1);
242 + /* If we ran to the end of either, we are finished with the loop */
243 + if (!(*one && *two)) break;
248 + /* grab first completely alpha or completely numeric segment */
249 + /* leave one and two pointing to the start of the alpha or numeric */
250 + /* segment and walk str1 and str2 to end of segment */
251 + if (grub_isdigit(*str1)) {
252 + while (*str1 && grub_isdigit(*str1)) str1++;
253 + while (*str2 && grub_isdigit(*str2)) str2++;
256 + while (*str1 && grub_isalpha(*str1)) str1++;
257 + while (*str2 && grub_isalpha(*str2)) str2++;
261 + /* save character at the end of the alpha or numeric segment */
262 + /* so that they can be restored after the comparison */
268 + /* this cannot happen, as we previously tested to make sure that */
269 + /* the first string has a non-null segment */
270 + if (one == str1) goto_return(-1); /* arbitrary */
272 + /* take care of the case where the two version segments are */
273 + /* different types: one numeric, the other alpha (i.e. empty) */
274 + /* numeric segments are always newer than alpha segments */
275 + /* XXX See patch #60884 (and details) from bugzilla #50977. */
276 + if (two == str2) goto_return (isnum ? 1 : -1);
279 + grub_size_t onelen, twolen;
280 + /* this used to be done by converting the digit segments */
281 + /* to ints using atoi() - it's changed because long */
282 + /* digit segments can overflow an int - this should fix that. */
284 + /* throw away any leading zeros - it's a number, right? */
285 + while (*one == '0') one++;
286 + while (*two == '0') two++;
288 + /* whichever number has more digits wins */
289 + onelen = grub_strlen(one);
290 + twolen = grub_strlen(two);
291 + if (onelen > twolen) goto_return (1);
292 + if (twolen > onelen) goto_return (-1);
295 + /* grub_strcmp will return which one is greater - even if the two */
296 + /* segments are alpha or if they are numeric. don't return */
297 + /* if they are equal because there might be more segments to */
299 + rc = grub_strcmp(one, two);
300 + if (rc) goto_return (rc < 1 ? -1 : 1);
302 + /* restore character that was replaced by null above */
309 + /* this catches the case where all numeric and alpha segments have */
310 + /* compared identically but the segment sepparating characters were */
312 + if ((!*one) && (!*two)) goto_return (0);
314 + /* whichever version still has characters left over wins */
315 + if (!*one) goto_return (-1); else goto_return (1);
323 +/* returns name/version/release */
324 +/* NULL string pointer returned if nothing found */
326 +split_package_string (char *package_string, char **name,
327 + char **version, char **release)
329 + char *package_version, *package_release;
332 + package_release = grub_strrchr (package_string, '-');
334 + if (package_release != NULL)
335 + *package_release++ = '\0';
337 + *release = package_release;
341 + *version = package_string;
346 + package_version = grub_strrchr(package_string, '-');
348 + if (package_version != NULL)
349 + *package_version++ = '\0';
351 + *version = package_version;
353 + *name = package_string;
356 + /* Bubble up non-null values from release to name */
357 + if (name != NULL && *name == NULL)
359 + *name = (*version == NULL ? *release : *version);
360 + *version = *release;
363 + if (*version == NULL)
365 + *version = *release;
371 +split_cmp(char *nvr0, char *nvr1, int has_name)
374 + char *name0, *version0, *release0;
375 + char *name1, *version1, *release1;
377 + split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0);
378 + split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1);
382 + ret = vercmp(name0 == NULL ? "" : name0,
383 + name1 == NULL ? "" : name1);
388 + ret = vercmp(version0 == NULL ? "" : version0,
389 + version1 == NULL ? "" : version1);
393 + ret = vercmp(release0 == NULL ? "" : release0,
394 + release1 == NULL ? "" : release1);
398 +/* return 1: e0 is newer than e1 */
399 +/* 0: e0 and e1 are the same version */
400 +/* -1: e1 is newer than e0 */
401 +static int bls_cmp(const struct bls_entry *e0, const struct bls_entry *e1)
406 + id0 = grub_strdup(e0->filename);
407 + id1 = grub_strdup(e1->filename);
409 + r = split_cmp(id0, id1, 1);
417 +static void list_add_tail(struct bls_entry *head, struct bls_entry *item)
421 + head->prev->next = item;
422 + item->prev = head->prev;
426 +static int bls_add_entry(struct bls_entry *entry)
428 + struct bls_entry *e, *last = NULL;
432 + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename);
437 + FOR_BLS_ENTRIES(e) {
438 + rc = bls_cmp(entry, e);
441 + return GRUB_ERR_BAD_ARGUMENT;
444 + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename);
445 + list_add_tail (e, entry);
446 + if (e == entries) {
448 + entry->prev = NULL;
456 + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename);
457 + last->next = entry;
458 + entry->prev = last;
464 +struct read_entry_info {
466 + const char *dirname;
470 +static int read_entry (
471 + const char *filename,
472 + const struct grub_dirhook_info *dirhook_info UNUSED,
475 + grub_size_t m = 0, n, clip = 0;
478 + grub_file_t f = NULL;
479 + struct bls_entry *entry;
480 + struct read_entry_info *info = (struct read_entry_info *)data;
482 + grub_dprintf ("blscfg", "filename: \"%s\"\n", filename);
484 + n = grub_strlen (filename);
492 + if (filename[0] == '.')
498 + if (grub_strcmp (filename + n - 5, ".conf") != 0)
501 + p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
503 + f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG);
508 + entry = grub_zalloc (sizeof (*entry));
516 + if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0)
519 + slash = grub_strrchr (filename, '/');
521 + slash = grub_strrchr (filename, '\\');
523 + while (*slash == '/' || *slash == '\\')
526 + m = slash ? slash - filename : 0;
535 + entry->filename = grub_strndup(filename + m, n - clip);
536 + if (!entry->filename)
539 + entry->filename[n - 5] = '\0';
546 + buf = grub_file_getline (f);
550 + while (buf && buf[0] && (buf[0] == ' ' || buf[0] == '\t'))
555 + separator = grub_strchr (buf, ' ');
558 + separator = grub_strchr (buf, '\t');
560 + if (!separator || separator[1] == '\0')
566 + separator[0] = '\0';
570 + } while (*separator == ' ' || *separator == '\t');
572 + rc = bls_add_keyval (entry, buf, separator);
579 + bls_add_entry(entry);
586 + grub_file_close (f);
591 +static grub_envblk_t saved_env = NULL;
594 +save_var (const char *name, const char *value, void *whitelist UNUSED)
596 + const char *val = grub_env_get (name);
597 + grub_dprintf("blscfg", "saving \"%s\"\n", name);
600 + grub_envblk_set (saved_env, name, value);
606 +unset_var (const char *name, const char *value UNUSED, void *whitelist)
608 + grub_dprintf("blscfg", "restoring \"%s\"\n", name);
611 + grub_env_unset (name);
615 + if (test_whitelist_membership (name,
616 + (const grub_env_whitelist_t *) whitelist))
617 + grub_env_unset (name);
622 +static char **bls_make_list (struct bls_entry *entry, const char *key, int *num)
628 + char **list = NULL;
630 + list = grub_malloc (sizeof (char *));
639 + val = bls_get_val (entry, key, &last);
643 + new = grub_realloc (list, (nlist + 2) * sizeof (char *));
648 + list[nlist++] = val;
649 + list[nlist] = NULL;
658 +static char *field_append(bool is_var, char *buffer, char *start, char *end)
660 + char *temp = grub_strndup(start, end - start + 1);
661 + const char *field = temp;
664 + field = grub_env_get (temp);
670 + buffer = grub_strdup(field);
674 + buffer = grub_realloc (buffer, grub_strlen(buffer) + grub_strlen(field));
678 + grub_stpcpy (buffer + grub_strlen(buffer), field);
684 +static char *expand_val(char *value)
686 + char *buffer = NULL;
687 + char *start = value;
689 + bool is_var = false;
695 + if (*value == '$') {
696 + if (start != end) {
697 + buffer = field_append(is_var, buffer, start, end);
704 + } else if (is_var) {
705 + if (!grub_isalnum(*value) && *value != '_') {
706 + buffer = field_append(is_var, buffer, start, end);
716 + if (start != end) {
717 + buffer = field_append(is_var, buffer, start, end);
725 +static char **early_initrd_list (const char *initrd)
728 + char **list = NULL;
731 + while ((separator = grub_strchr (initrd, ' ')))
733 + list = grub_realloc (list, (nlist + 2) * sizeof (char *));
737 + list[nlist++] = grub_strndup(initrd, separator - initrd);
738 + list[nlist] = NULL;
739 + initrd = separator + 1;
742 + list = grub_realloc (list, (nlist + 2) * sizeof (char *));
746 + list[nlist++] = grub_strndup(initrd, grub_strlen(initrd));
747 + list[nlist] = NULL;
752 +static void create_entry (struct bls_entry *entry)
755 + const char **argv = NULL;
757 + char *title = NULL;
758 + char *clinux = NULL;
759 + char *options = NULL;
760 + char **initrds = NULL;
761 + char *initrd = NULL;
762 + const char *early_initrd = NULL;
763 + char **early_initrds = NULL;
764 + char *initrd_prefix = NULL;
765 + char *id = entry->filename;
766 + char *dotconf = id;
767 + char *hotkey = NULL;
769 + char *users = NULL;
770 + char **classes = NULL;
772 + char **args = NULL;
777 + grub_dprintf("blscfg", "%s got here\n", __func__);
778 + clinux = bls_get_val (entry, "linux", NULL);
781 + grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", entry->filename);
786 + * strip the ".conf" off the end before we make it our "id" field.
790 + dotconf = grub_strstr(dotconf, ".conf");
791 + } while (dotconf != NULL && dotconf[5] != '\0');
795 + title = bls_get_val (entry, "title", NULL);
796 + options = expand_val (bls_get_val (entry, "options", NULL));
799 + options = expand_val (grub_env_get("default_kernelopts"));
801 + initrds = bls_make_list (entry, "initrd", NULL);
803 + hotkey = bls_get_val (entry, "grub_hotkey", NULL);
804 + users = expand_val (bls_get_val (entry, "grub_users", NULL));
805 + classes = bls_make_list (entry, "grub_class", NULL);
806 + args = bls_make_list (entry, "grub_arg", &argc);
809 + argv = grub_malloc ((argc + 1) * sizeof (char *));
810 + argv[0] = title ? title : clinux;
811 + for (i = 1; i < argc; i++)
812 + argv[i] = args[i-1];
815 + early_initrd = grub_env_get("early_initrd");
817 + grub_dprintf ("blscfg", "adding menu entry for \"%s\" with id \"%s\"\n",
821 + early_initrds = early_initrd_list(early_initrd);
822 + if (!early_initrds)
824 + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
828 + if (initrds != NULL && initrds[0] != NULL)
830 + initrd_prefix = grub_strrchr (initrds[0], '/');
831 + initrd_prefix = grub_strndup(initrds[0], initrd_prefix - initrds[0] + 1);
835 + initrd_prefix = grub_strrchr (clinux, '/');
836 + initrd_prefix = grub_strndup(clinux, initrd_prefix - clinux + 1);
839 + if (!initrd_prefix)
841 + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
846 + if (early_initrds || initrds)
848 + int initrd_size = sizeof ("initrd");
851 + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
852 + initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \
853 + + grub_strlen(initrd_prefix) \
854 + + grub_strlen (early_initrds[i]) + 1;
856 + for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
857 + initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \
858 + + grub_strlen (initrds[i]) + 1;
861 + initrd = grub_malloc (initrd_size);
864 + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
869 + tmp = grub_stpcpy(initrd, "initrd");
870 + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
872 + grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]);
873 + tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
874 + tmp = grub_stpcpy (tmp, initrd_prefix);
875 + tmp = grub_stpcpy (tmp, early_initrds[i]);
876 + grub_free(early_initrds[i]);
879 + for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
881 + grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]);
882 + tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
883 + tmp = grub_stpcpy (tmp, initrds[i]);
885 + tmp = grub_stpcpy (tmp, "\n");
888 + src = grub_xasprintf ("load_video\n"
889 + "set gfxpayload=keep\n"
893 + GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "",
894 + initrd ? initrd : "");
896 + grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry);
897 + grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id);
900 + grub_free (initrd);
901 + grub_free (initrd_prefix);
902 + grub_free (early_initrds);
903 + grub_free (initrds);
904 + grub_free (options);
905 + grub_free (classes);
911 +struct find_entry_info {
912 + const char *dirname;
919 + * info: the filesystem object the file is on.
921 +static int find_entry (struct find_entry_info *info)
923 + struct read_entry_info read_entry_info;
924 + grub_fs_t blsdir_fs = NULL;
925 + grub_device_t blsdir_dev = NULL;
926 + const char *blsdir = info->dirname;
931 + blsdir = grub_env_get ("blsdir");
933 + blsdir = GRUB_BLS_CONFIG_PATH;
936 + read_entry_info.file = NULL;
937 + read_entry_info.dirname = blsdir;
939 + grub_dprintf ("blscfg", "scanning blsdir: %s\n", blsdir);
941 + blsdir_dev = info->dev;
942 + blsdir_fs = info->fs;
943 + read_entry_info.devid = info->devid;
946 + r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry,
949 + grub_dprintf ("blscfg", "read_entry returned error\n");
953 + e = grub_error_pop();
957 + if (r && !info->dirname && !fallback) {
958 + read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH;
959 + grub_dprintf ("blscfg", "Entries weren't found in %s, fallback to %s\n",
960 + blsdir, read_entry_info.dirname);
962 + goto read_fallback;
969 +bls_load_entries (const char *path)
974 + static grub_err_t r;
975 + const char *devid = NULL;
976 + char *blsdir = NULL;
977 + struct find_entry_info info = {
982 + struct read_entry_info rei = {
988 + len = grub_strlen (path);
989 + if (grub_strcmp (path + len - 5, ".conf") == 0) {
990 + rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG);
994 + * read_entry() closes the file
996 + return read_entry(path, NULL, &rei);
997 + } else if (path[0] == '(') {
1000 + blsdir = grub_strchr (path, ')');
1002 + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Filepath isn't correct"));
1005 + blsdir = blsdir + 1;
1010 +#ifdef GRUB_MACHINE_EMU
1012 +#elif defined(GRUB_MACHINE_EFI)
1013 + devid = grub_env_get ("root");
1015 + devid = grub_env_get ("boot");
1018 + return grub_error (GRUB_ERR_FILE_NOT_FOUND,
1019 + N_("variable `%s' isn't set"), "boot");
1022 + grub_dprintf ("blscfg", "opening %s\n", devid);
1023 + dev = grub_device_open (devid);
1025 + return grub_errno;
1027 + grub_dprintf ("blscfg", "probing fs\n");
1028 + fs = grub_fs_probe (dev);
1035 + info.dirname = blsdir;
1036 + info.devid = devid;
1039 + find_entry(&info);
1043 + grub_device_close (dev);
1049 +is_default_entry(const char *def_entry, struct bls_entry *entry, int idx)
1051 + const char *title;
1057 + if (grub_strcmp(def_entry, entry->filename) == 0)
1060 + title = bls_get_val(entry, "title", NULL);
1062 + if (title && grub_strcmp(def_entry, title) == 0)
1065 + def_idx = (int)grub_strtol(def_entry, NULL, 0);
1066 + if (grub_errno == GRUB_ERR_BAD_NUMBER) {
1067 + grub_errno = GRUB_ERR_NONE;
1071 + if (def_idx == idx)
1078 +bls_create_entries (bool show_default, bool show_non_default, char *entry_id)
1080 + const char *def_entry = NULL;
1081 + struct bls_entry *entry = NULL;
1084 + def_entry = grub_env_get("default");
1086 + grub_dprintf ("blscfg", "%s Creating entries from bls\n", __func__);
1087 + FOR_BLS_ENTRIES(entry) {
1088 + if (entry->visible) {
1093 + if ((show_default && is_default_entry(def_entry, entry, idx)) ||
1094 + (show_non_default && !is_default_entry(def_entry, entry, idx)) ||
1095 + (entry_id && grub_strcmp(entry_id, entry->filename) == 0)) {
1096 + create_entry(entry);
1097 + entry->visible = 1;
1102 + return GRUB_ERR_NONE;
1106 +grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
1107 + int argc, char **args)
1110 + char *path = NULL;
1111 + char *entry_id = NULL;
1112 + bool show_default = true;
1113 + bool show_non_default = true;
1116 + if (grub_strcmp (args[0], "default") == 0) {
1117 + show_non_default = false;
1118 + } else if (grub_strcmp (args[0], "non-default") == 0) {
1119 + show_default = false;
1120 + } else if (args[0][0] == '(') {
1123 + entry_id = args[0];
1124 + show_default = false;
1125 + show_non_default = false;
1129 + r = bls_load_entries(path);
1133 + return bls_create_entries(show_default, show_non_default, entry_id);
1136 +static grub_extcmd_t cmd;
1137 +static grub_extcmd_t oldcmd;
1139 +GRUB_MOD_INIT(blscfg)
1141 + grub_dprintf("blscfg", "%s got here\n", __func__);
1142 + cmd = grub_register_extcmd ("blscfg",
1146 + N_("Import Boot Loader Specification snippets."),
1148 + oldcmd = grub_register_extcmd ("bls_import",
1152 + N_("Import Boot Loader Specification snippets."),
1156 +GRUB_MOD_FINI(blscfg)
1158 + grub_unregister_extcmd (cmd);
1159 + grub_unregister_extcmd (oldcmd);
1161 diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c
1162 index db7a8f00273..891eac5a33f 100644
1163 --- a/grub-core/commands/legacycfg.c
1164 +++ b/grub-core/commands/legacycfg.c
1165 @@ -133,7 +133,7 @@ legacy_file (const char *filename)
1167 grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy",
1170 + entrysrc, 0, NULL, NULL);
1173 grub_free (oldname);
1174 @@ -186,7 +186,8 @@ legacy_file (const char *filename)
1176 args[0] = entryname;
1177 grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
1178 - NULL, NULL, entrysrc, 0);
1179 + NULL, NULL, entrysrc, 0, NULL,
1184 diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c
1185 index 3fd664aac33..163b9a09042 100644
1186 --- a/grub-core/commands/loadenv.c
1187 +++ b/grub-core/commands/loadenv.c
1189 #include <grub/extcmd.h>
1190 #include <grub/i18n.h>
1192 +#include "loadenv.h"
1194 GRUB_MOD_LICENSE ("GPLv3+");
1196 static const struct grub_arg_option options[] =
1197 @@ -79,81 +81,6 @@ open_envblk_file (char *filename,
1201 -static grub_envblk_t
1202 -read_envblk_file (grub_file_t file)
1204 - grub_off_t offset = 0;
1206 - grub_size_t size = grub_file_size (file);
1207 - grub_envblk_t envblk;
1209 - buf = grub_malloc (size);
1217 - ret = grub_file_read (file, buf + offset, size);
1228 - envblk = grub_envblk_open (buf, offset);
1232 - grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
1239 -struct grub_env_whitelist
1244 -typedef struct grub_env_whitelist grub_env_whitelist_t;
1247 -test_whitelist_membership (const char* name,
1248 - const grub_env_whitelist_t* whitelist)
1252 - for (i = 0; i < whitelist->len; i++)
1253 - if (grub_strcmp (name, whitelist->list[i]) == 0)
1254 - return 1; /* found it */
1256 - return 0; /* not found */
1259 -/* Helper for grub_cmd_load_env. */
1261 -set_var (const char *name, const char *value, void *whitelist)
1265 - grub_env_set (name, value);
1269 - if (test_whitelist_membership (name,
1270 - (const grub_env_whitelist_t *) whitelist))
1271 - grub_env_set (name, value);
1277 grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args)
1279 diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c
1280 index 2c5363da7f5..9faf2be0f64 100644
1281 --- a/grub-core/commands/menuentry.c
1282 +++ b/grub-core/commands/menuentry.c
1283 @@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args,
1284 char **classes, const char *id,
1285 const char *users, const char *hotkey,
1286 const char *prefix, const char *sourcecode,
1288 + int submenu, int *index, struct bls_entry *bls)
1290 int menu_hotkey = 0;
1291 char **menu_args = NULL;
1292 @@ -149,9 +149,12 @@ grub_normal_add_menu_entry (int argc, const char **args,
1296 + grub_dprintf ("menu", "id:\"%s\"\n", id);
1297 + grub_dprintf ("menu", "title:\"%s\"\n", menu_title);
1298 menu_id = grub_strdup (id ? : menu_title);
1301 + grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id);
1303 /* Save argc, args to pass as parameters to block arg later. */
1304 menu_args = grub_calloc (argc + 1, sizeof (char *));
1305 @@ -170,8 +173,12 @@ grub_normal_add_menu_entry (int argc, const char **args,
1308 /* Add the menu entry at the end of the list. */
1311 - last = &(*last)->next;
1314 + last = &(*last)->next;
1317 *last = grub_zalloc (sizeof (**last));
1319 @@ -188,8 +195,11 @@ grub_normal_add_menu_entry (int argc, const char **args,
1320 (*last)->args = menu_args;
1321 (*last)->sourcecode = menu_sourcecode;
1322 (*last)->submenu = submenu;
1323 + (*last)->bls = bls;
1328 return GRUB_ERR_NONE;
1331 @@ -286,7 +296,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
1333 ctxt->state[2].arg, 0,
1335 - ctxt->extcmd->cmd->name[0] == 's');
1336 + ctxt->extcmd->cmd->name[0] == 's',
1339 src = args[argc - 1];
1340 args[argc - 1] = NULL;
1341 @@ -303,7 +314,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
1342 ctxt->state[0].args, ctxt->state[4].arg,
1344 ctxt->state[2].arg, prefix, src + 1,
1345 - ctxt->extcmd->cmd->name[0] == 's');
1346 + ctxt->extcmd->cmd->name[0] == 's', NULL,
1350 args[argc - 1] = src;
1351 diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
1352 index 9ef98481f70..a326b192c89 100644
1353 --- a/grub-core/normal/main.c
1354 +++ b/grub-core/normal/main.c
1356 #include <grub/net.h>
1357 #include <grub/normal.h>
1358 #include <grub/dl.h>
1359 +#include <grub/menu.h>
1360 #include <grub/misc.h>
1361 #include <grub/file.h>
1362 #include <grub/mm.h>
1363 @@ -70,6 +71,11 @@ grub_normal_free_menu (grub_menu_t menu)
1364 grub_free (entry->args);
1369 + entry->bls->visible = 0;
1372 grub_free ((void *) entry->id);
1373 grub_free ((void *) entry->users);
1374 grub_free ((void *) entry->title);
1375 diff --git a/grub-core/commands/loadenv.h b/grub-core/commands/loadenv.h
1376 new file mode 100644
1377 index 00000000000..952f46121bd
1379 +++ b/grub-core/commands/loadenv.h
1381 +/* loadenv.c - command to load/save environment variable. */
1383 + * GRUB -- GRand Unified Bootloader
1384 + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc.
1386 + * GRUB is free software: you can redistribute it and/or modify
1387 + * it under the terms of the GNU General Public License as published by
1388 + * the Free Software Foundation, either version 3 of the License, or
1389 + * (at your option) any later version.
1391 + * GRUB is distributed in the hope that it will be useful,
1392 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1393 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1394 + * GNU General Public License for more details.
1396 + * You should have received a copy of the GNU General Public License
1397 + * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
1400 +static grub_envblk_t UNUSED
1401 +read_envblk_file (grub_file_t file)
1403 + grub_off_t offset = 0;
1405 + grub_size_t size = grub_file_size (file);
1406 + grub_envblk_t envblk;
1408 + buf = grub_malloc (size);
1416 + ret = grub_file_read (file, buf + offset, size);
1427 + envblk = grub_envblk_open (buf, offset);
1431 + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
1438 +struct grub_env_whitelist
1443 +typedef struct grub_env_whitelist grub_env_whitelist_t;
1446 +test_whitelist_membership (const char* name,
1447 + const grub_env_whitelist_t* whitelist)
1451 + for (i = 0; i < whitelist->len; i++)
1452 + if (grub_strcmp (name, whitelist->list[i]) == 0)
1453 + return 1; /* found it */
1455 + return 0; /* not found */
1458 +/* Helper for grub_cmd_load_env. */
1460 +set_var (const char *name, const char *value, void *whitelist)
1464 + grub_env_set (name, value);
1468 + if (test_whitelist_membership (name,
1469 + (const grub_env_whitelist_t *) whitelist))
1470 + grub_env_set (name, value);
1474 diff --git a/include/grub/compiler.h b/include/grub/compiler.h
1475 index c9e1d7a73dc..9859ff4cc79 100644
1476 --- a/include/grub/compiler.h
1477 +++ b/include/grub/compiler.h
1479 # define CLANG_PREREQ(maj,min) 0
1482 +#define UNUSED __attribute__((__unused__))
1484 #endif /* ! GRUB_COMPILER_HEADER */
1485 diff --git a/include/grub/menu.h b/include/grub/menu.h
1486 index ee2b5e91045..0acdc2aa6bf 100644
1487 --- a/include/grub/menu.h
1488 +++ b/include/grub/menu.h
1490 #ifndef GRUB_MENU_HEADER
1491 #define GRUB_MENU_HEADER 1
1495 + struct bls_entry *next;
1496 + struct bls_entry *prev;
1497 + struct keyval **keyvals;
1503 struct grub_menu_entry_class
1506 @@ -60,6 +70,9 @@ struct grub_menu_entry
1508 /* The next element. */
1509 struct grub_menu_entry *next;
1511 + /* BLS used to populate the entry */
1512 + struct bls_entry *bls;
1514 typedef struct grub_menu_entry *grub_menu_entry_t;
1516 diff --git a/include/grub/normal.h b/include/grub/normal.h
1517 index 218cbabccaf..8839ad85a19 100644
1518 --- a/include/grub/normal.h
1519 +++ b/include/grub/normal.h
1520 @@ -145,7 +145,7 @@ grub_normal_add_menu_entry (int argc, const char **args, char **classes,
1522 const char *users, const char *hotkey,
1523 const char *prefix, const char *sourcecode,
1525 + int submenu, int *index, struct bls_entry *bls);
1528 grub_normal_set_password (const char *user, const char *password);