From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Fedora Ninjas Date: Tue, 22 Jan 2013 06:31:38 +0100 Subject: [PATCH] blscfg: add blscfg module to parse Boot Loader Specification snippets http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec Works like this: insmod blscfg bls_import Done! You should now have menu items for your snippets in place. Signed-off-by: Peter Jones --- grub-core/Makefile.core.def | 8 ++ grub-core/commands/blscfg.c | 201 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 grub-core/commands/blscfg.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index f8065388213..cd0902b46b8 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -768,6 +768,14 @@ module = { common = commands/blocklist.c; }; +module = { + name = blscfg; + common = commands/blscfg.c; + enable = i386_efi; + enable = x86_64_efi; + enable = i386_pc; +}; + module = { name = boot; common = commands/boot.c; diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c new file mode 100644 index 00000000000..4274aca5a9d --- /dev/null +++ b/grub-core/commands/blscfg.c @@ -0,0 +1,201 @@ +/*-*- 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#ifdef GRUB_MACHINE_EFI +#define GRUB_LINUX_CMD "linuxefi" +#define GRUB_INITRD_CMD "initrdefi" +#define GRUB_BLS_CONFIG_PATH "/EFI/fedora/loader/entries/" +#define GRUB_BOOT_DEVICE "($boot)" +#else +#define GRUB_LINUX_CMD "linux" +#define GRUB_INITRD_CMD "initrd" +#define GRUB_BLS_CONFIG_PATH "/loader/entries/" +#define GRUB_BOOT_DEVICE "($root)" +#endif + +static int parse_entry ( + const char *filename, + const struct grub_dirhook_info *info __attribute__ ((unused)), + void *data __attribute__ ((unused))) +{ + grub_size_t n; + char *p; + grub_file_t f = NULL; + grub_off_t sz; + char *title = NULL, *options = NULL, *clinux = NULL, *initrd = NULL, *src = NULL; + const char *args[2] = { NULL, NULL }; + + if (filename[0] == '.') + return 0; + + n = grub_strlen (filename); + if (n <= 5) + return 0; + + if (grub_strcmp (filename + n - 5, ".conf") != 0) + return 0; + + p = grub_xasprintf (GRUB_BLS_CONFIG_PATH "%s", filename); + + f = grub_file_open (p); + if (!f) + goto finish; + + sz = grub_file_size (f); + if (sz == GRUB_FILE_SIZE_UNKNOWN || sz > 1024*1024) + goto finish; + + for (;;) + { + char *buf; + + buf = grub_file_getline (f); + if (!buf) + break; + + if (grub_strncmp (buf, "title ", 6) == 0) + { + grub_free (title); + title = grub_strdup (buf + 6); + if (!title) + goto finish; + } + else if (grub_strncmp (buf, "options ", 8) == 0) + { + grub_free (options); + options = grub_strdup (buf + 8); + if (!options) + goto finish; + } + else if (grub_strncmp (buf, "linux ", 6) == 0) + { + grub_free (clinux); + clinux = grub_strdup (buf + 6); + if (!clinux) + goto finish; + } + else if (grub_strncmp (buf, "initrd ", 7) == 0) + { + grub_free (initrd); + initrd = grub_strdup (buf + 7); + if (!initrd) + goto finish; + } + + grub_free(buf); + } + + if (!linux) + { + grub_printf ("Skipping file %s with no 'linux' key.", p); + goto finish; + } + + args[0] = title ? title : filename; + + src = grub_xasprintf ("load_video\n" + "set gfx_payload=keep\n" + "insmod gzio\n" + GRUB_LINUX_CMD " %s%s%s%s\n" + "%s%s%s%s", + GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "", + initrd ? GRUB_INITRD_CMD " " : "", initrd ? GRUB_BOOT_DEVICE : "", initrd ? initrd : "", initrd ? "\n" : ""); + + grub_normal_add_menu_entry (1, args, NULL, NULL, "bls", NULL, NULL, src, 0); + +finish: + grub_free (p); + grub_free (title); + grub_free (options); + grub_free (clinux); + grub_free (initrd); + grub_free (src); + + if (f) + grub_file_close (f); + + return 0; +} + +static grub_err_t +grub_cmd_bls_import (grub_extcmd_context_t ctxt __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + grub_fs_t fs; + grub_device_t dev; + static grub_err_t r; + const char *devid; + + devid = grub_env_get ("root"); + if (!devid) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "root"); + + dev = grub_device_open (devid); + if (!dev) + return grub_errno; + + fs = grub_fs_probe (dev); + if (!fs) + { + r = grub_errno; + goto finish; + } + + r = fs->dir (dev, GRUB_BLS_CONFIG_PATH, parse_entry, NULL); + +finish: + if (dev) + grub_device_close (dev); + + return r; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(bls) +{ + cmd = grub_register_extcmd ("bls_import", + grub_cmd_bls_import, + 0, + NULL, + N_("Import Boot Loader Specification snippets."), + NULL); +} + +GRUB_MOD_FINI(bls) +{ + grub_unregister_extcmd (cmd); +}