You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Ventoy/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blscfg.c

1112 lines
25 KiB
C

/*-*- 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++;
while (*two && !grub_isalnum(*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;
}
/* 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 (num)
*num = nlist;
return list;
}
static char *field_append(bool is_var, char *buffer, char *start, char *end)
{
char *temp = grub_strndup(start, end - start + 1);
const char *field = temp;
if (is_var) {
field = grub_env_get (temp);
if (!field)
return buffer;
}
if (!buffer) {
buffer = grub_strdup(field);
if (!buffer)
return NULL;
} else {
buffer = grub_realloc (buffer, grub_strlen(buffer) + grub_strlen(field));
if (!buffer)
return NULL;
grub_stpcpy (buffer + grub_strlen(buffer), field);
}
return buffer;
}
static char *expand_val(char *value)
{
char *buffer = NULL;
char *start = value;
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;
}
}
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 *id = entry->filename;
char *dotconf = id;
char *hotkey = NULL;
char *users = NULL;
char **classes = NULL;
char **args = NULL;
char *src = NULL;
int bootlen;
const char *bootdev;
int i, index;
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;
}
bootdev = grub_env_get("ventoy_bls_bootdev");
if (!bootdev)
{
bootdev = GRUB_BOOT_DEVICE;
}
bootlen = grub_strlen(bootdev) + 2;//space and \0
/*
* 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 ((char *)grub_env_get("default_kernelopts"));
initrds = bls_make_list (entry, "initrd", NULL);
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 += bootlen \
+ grub_strlen(initrd_prefix) \
+ grub_strlen (early_initrds[i]) + 1;
for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
initrd_size += bootlen \
+ 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, " ");
tmp = grub_stpcpy (tmp, bootdev);
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, " ");
tmp = grub_stpcpy (tmp, bootdev);
tmp = grub_stpcpy (tmp, initrds[i]);
}
tmp = grub_stpcpy (tmp, "\n");
}
src = grub_xasprintf ("load_video\n"
"set gfxpayload=keep\n"
"insmod gzio\n"
"linux %s%s%s%s\n"
"%s",
bootdev, clinux, options ? " " : "", options ? options : "",
initrd ? initrd : "");
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 (initrd);
grub_free (initrd_prefix);
grub_free (early_initrds);
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";
#elif defined(GRUB_MACHINE_EFI)
devid = grub_env_get ("root");
#else
devid = grub_env_get ("boot");
if (!devid)
{
devid = grub_env_get ("root");
}
#endif
if (!devid)
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
N_("variable `%s' isn't set"), "boot");
}
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);
}