From 9d0bd7407d9355ef73d63384959b7a89e76b33b1 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 10 Jun 2010 18:15:38 +0530 Subject: [PATCH 01/12] remove menuentry from GRUB script --- include/grub/script_sh.h | 22 ---------------------- script/execute.c | 25 ------------------------- script/parser.y | 26 ++------------------------ script/script.c | 24 ------------------------ script/yylex.l | 1 - util/grub-script-check.c | 6 ------ 6 files changed, 2 insertions(+), 102 deletions(-) diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index a17dcca70..88641300f 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -139,21 +139,6 @@ struct grub_script_cmdwhile int until; }; -/* A menu entry generate statement. */ -struct grub_script_cmd_menuentry -{ - struct grub_script_cmd cmd; - - /* The arguments for this menu entry. */ - struct grub_script_arglist *arglist; - - /* The sourcecode the entry will be generated from. */ - const char *sourcecode; - - /* Options. XXX: Not used yet. */ - int options; -}; - /* State of the lexer as passed to the lexer. */ struct grub_lexer_param { @@ -263,12 +248,6 @@ grub_script_create_cmdwhile (struct grub_parser_param *state, struct grub_script_cmd *list, int is_an_until_loop); -struct grub_script_cmd * -grub_script_create_cmdmenu (struct grub_parser_param *state, - struct grub_script_arglist *arglist, - char *sourcecode, - int options); - struct grub_script_cmd * grub_script_append_cmd (struct grub_parser_param *state, struct grub_script_cmd *list, @@ -313,7 +292,6 @@ grub_err_t grub_script_execute_cmdlist (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdfor (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdwhile (struct grub_script_cmd *cmd); -grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd); /* Execute any GRUB pre-parsed command or script. */ grub_err_t grub_script_execute (struct grub_script *script); diff --git a/script/execute.c b/script/execute.c index 0ac42cf4a..e7a809bd1 100644 --- a/script/execute.c +++ b/script/execute.c @@ -424,31 +424,6 @@ grub_script_execute_cmdwhile (struct grub_script_cmd *cmd) return result; } -/* Execute the menu entry generate statement. */ -grub_err_t -grub_script_execute_menuentry (struct grub_script_cmd *cmd) -{ - struct grub_script_cmd_menuentry *cmd_menuentry; - struct grub_script_argv argv = { 0, 0, 0 }; - - cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd; - - if (cmd_menuentry->arglist) - { - if (grub_script_arglist_to_argv (cmd_menuentry->arglist, &argv)) - return grub_errno; - } - - grub_normal_add_menu_entry (argv.argc, (const char **) argv.args, - cmd_menuentry->sourcecode); - - grub_script_argv_free (&argv); - - return grub_errno; -} - - - /* Execute any GRUB pre-parsed command or script. */ grub_err_t grub_script_execute (struct grub_script *script) diff --git a/script/parser.y b/script/parser.y index d774ca918..39cf675a1 100644 --- a/script/parser.y +++ b/script/parser.y @@ -73,7 +73,6 @@ %token GRUB_PARSER_TOKEN_WHILE "while" %token GRUB_PARSER_TOKEN_TIME "time" %token GRUB_PARSER_TOKEN_FUNCTION "function" -%token GRUB_PARSER_TOKEN_MENUENTRY "menuentry" %token GRUB_PARSER_TOKEN_NAME "name" %token GRUB_PARSER_TOKEN_WORD "word" @@ -81,7 +80,7 @@ %type script_init script %type grubcmd ifclause ifcmd forcmd whilecmd untilcmd -%type command commands1 menuentry statement +%type command commands1 statement %pure-parser %lex-param { struct grub_parser_param *state }; @@ -127,8 +126,7 @@ word: GRUB_PARSER_TOKEN_NAME { $$ = grub_script_add_arglist (state, 0, $1); } statement: command { $$ = $1; } | function { $$ = 0; } - | menuentry { $$ = $1; } - +; argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } | "do" { $$ = grub_script_add_arglist (state, 0, $1); } | "done" { $$ = grub_script_add_arglist (state, 0, $1); } @@ -144,7 +142,6 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } | "until" { $$ = grub_script_add_arglist (state, 0, $1); } | "while" { $$ = grub_script_add_arglist (state, 0, $1); } | "function" { $$ = grub_script_add_arglist (state, 0, $1); } - | "menuentry" { $$ = grub_script_add_arglist (state, 0, $1); } | word { $$ = $1; } ; @@ -263,25 +260,6 @@ function: "function" "name" } ; -menuentry: "menuentry" - { - grub_script_lexer_ref (state->lexerstate); - } - arguments1 - { - $$ = grub_script_lexer_record_start (state); - } - delimiters0 "{" commands1 delimiters1 "}" - { - char *def; - def = grub_script_lexer_record_stop (state, $4); - *grub_strrchr(def, '}') = '\0'; - - grub_script_lexer_deref (state->lexerstate); - $$ = grub_script_create_cmdmenu (state, $3, def, 0); - } -; - ifcmd: "if" { grub_script_lexer_ref (state->lexerstate); diff --git a/script/script.c b/script/script.c index 9017a08e8..847e4f077 100644 --- a/script/script.c +++ b/script/script.c @@ -273,30 +273,6 @@ grub_script_create_cmdwhile (struct grub_parser_param *state, return (struct grub_script_cmd *) cmd; } -/* Create a command that adds a menu entry to the menu. Title is an - argument that is parsed to generate a string that can be used as - the title. The sourcecode for this entry is passed in SOURCECODE. - The options for this entry are passed in OPTIONS. */ -struct grub_script_cmd * -grub_script_create_cmdmenu (struct grub_parser_param *state, - struct grub_script_arglist *arglist, - char *sourcecode, int options) -{ - struct grub_script_cmd_menuentry *cmd; - - cmd = grub_script_malloc (state, sizeof (*cmd)); - if (!cmd) - return 0; - - cmd->cmd.exec = grub_script_execute_menuentry; - cmd->cmd.next = 0; - cmd->sourcecode = sourcecode; - cmd->arglist = arglist; - cmd->options = options; - - return (struct grub_script_cmd *) cmd; -} - /* Create a chain of commands. LAST contains the command that should be added at the end of LIST's list. If LIST is zero, a new list will be created. */ diff --git a/script/yylex.l b/script/yylex.l index bfc53a6ff..a084ba1fc 100644 --- a/script/yylex.l +++ b/script/yylex.l @@ -169,7 +169,6 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ "until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; } "while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; } "function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; } -"menuentry" { RECORD; return GRUB_PARSER_TOKEN_MENUENTRY; } {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; } {WORD} { diff --git a/util/grub-script-check.c b/util/grub-script-check.c index 8995520bb..2469d5b06 100644 --- a/util/grub-script-check.c +++ b/util/grub-script-check.c @@ -93,12 +93,6 @@ grub_script_execute_cmdwhile (struct grub_script_cmd *cmd __attribute__ ((unused return 0; } -grub_err_t -grub_script_execute_menuentry (struct grub_script_cmd *cmd __attribute__ ((unused))) -{ - return 0; -} - grub_err_t grub_script_execute (struct grub_script *script) { From 627c30f7f1f6053b5a7e68cc568c921dca745ee6 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 10 Jun 2010 20:50:49 +0530 Subject: [PATCH 02/12] initial impl. for menuentry command --- commands/menuentry.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ conf/common.rmk | 6 +++++ 2 files changed, 65 insertions(+) create mode 100644 commands/menuentry.c diff --git a/commands/menuentry.c b/commands/menuentry.c new file mode 100644 index 000000000..f27b246b1 --- /dev/null +++ b/commands/menuentry.c @@ -0,0 +1,59 @@ +/* menuentry.c - menuentry command */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +static grub_err_t +grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) +{ + char *src; + grub_err_t r; + + /* XXX Rewrite to make use of already parsed menu definition. */ + if (! argc || ! ctxt->script_params || ! ctxt->script_params[argc - 1]) + return GRUB_ERR_BAD_ARGUMENT; + + src = args[argc - 1]; + args[argc - 1] = '\0'; + + r = 0; //grub_normal_add_menu_entry (argc - 1, (const char **) args, src); + + args[argc - 1] = src; + return r; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(menuentry) +{ + cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry, + GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS, + N_("BLOCK"), N_("Define a menuentry."), 0); +} + +GRUB_MOD_FINI(menuentry) +{ + grub_unregister_extcmd (cmd); +} diff --git a/conf/common.rmk b/conf/common.rmk index 3674cae07..b9a973f76 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -846,6 +846,12 @@ boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c boot_mod_CFLAGS = $(COMMON_CFLAGS) boot_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For menuentry.mod. +pkglib_MODULES += menuentry.mod +menuentry_mod_SOURCES = commands/menuentry.c +menuentry_mod_CFLAGS = $(COMMON_CFLAGS) +menuentry_mod_LDFLAGS = $(COMMON_LDFLAGS) + bin_UTILITIES += grub-mkpasswd-pbkdf2 grub_mkpasswd_pbkdf2_SOURCES = gnulib/progname.c gnulib/getdelim.c gnulib/getline.c util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/emu/misc.c kern/emu/mm.c kern/err.c grub_mkpasswd_pbkdf2_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap -DGRUB_MKPASSWD=1 From 9ced4652e054f624fb871240a443f03b5a438384 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 10 Jun 2010 21:26:03 +0530 Subject: [PATCH 03/12] uncomment menuentry addition --- commands/menuentry.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/menuentry.c b/commands/menuentry.c index f27b246b1..95ec67bbd 100644 --- a/commands/menuentry.c +++ b/commands/menuentry.c @@ -38,7 +38,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) src = args[argc - 1]; args[argc - 1] = '\0'; - r = 0; //grub_normal_add_menu_entry (argc - 1, (const char **) args, src); + r = grub_normal_add_menu_entry (argc - 1, (const char **) args, src); args[argc - 1] = src; return r; From 57a095bc01f08d2e803331d521c09a90f8e33970 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Mon, 19 Jul 2010 01:01:53 +0530 Subject: [PATCH 04/12] fix a memory leak --- lib/arg.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arg.c b/lib/arg.c index 400314d30..04e0ea8ba 100644 --- a/lib/arg.c +++ b/lib/arg.c @@ -228,9 +228,13 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, grub_err_t add_arg (char *s) { + char **p = argl; argl = grub_realloc (argl, (++num) * sizeof (char *)); if (! argl) - return grub_errno; + { + grub_free (p); + return grub_errno; + } argl[num - 1] = s; return 0; } From b14906860b578b5911cf35bfa10c93182fd62efb Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Tue, 20 Jul 2010 02:33:57 +0530 Subject: [PATCH 05/12] full menuentry command support --- commands/extcmd.c | 5 +---- commands/menuentry.c | 6 +++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/commands/extcmd.c b/commands/extcmd.c index 349e9bfc7..9dbb0a2ce 100644 --- a/commands/extcmd.c +++ b/commands/extcmd.c @@ -40,9 +40,7 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, context.extcmd = ext; context.script_params = scripts; - /* Dynamic commands should not perform option parsing before - corresponding module gets loaded. */ - if (cmd->flags & GRUB_COMMAND_FLAG_DYNCMD) + if (! ext->options) { ret = (ext->func) (&context, argc, args); return ret; @@ -65,7 +63,6 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, ret = grub_errno; grub_free (state); - return ret; } diff --git a/commands/menuentry.c b/commands/menuentry.c index 95ec67bbd..0ce5a9e0e 100644 --- a/commands/menuentry.c +++ b/commands/menuentry.c @@ -29,6 +29,7 @@ static grub_err_t grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) { char *src; + unsigned len; grub_err_t r; /* XXX Rewrite to make use of already parsed menu definition. */ @@ -37,9 +38,12 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) src = args[argc - 1]; args[argc - 1] = '\0'; + len = grub_strlen(src); + src[len - 1] = '\0'; - r = grub_normal_add_menu_entry (argc - 1, (const char **) args, src); + r = grub_normal_add_menu_entry (argc - 1, (const char **) args, src + 1); + src[len - 1] = '}'; args[argc - 1] = src; return r; } From 639cc5ab447f41f2d4e3c325ca7acb25c84ec598 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 22 Jul 2010 19:01:40 +0530 Subject: [PATCH 06/12] menuentry option parsing is done using lib/arg.c --- commands/extcmd.c | 20 ++-- commands/menuentry.c | 141 +++++++++++++++++++++++++++- include/grub/lib/arg.h | 9 +- include/grub/normal.h | 2 - lib/arg.c | 60 +++++++++++- normal/main.c | 203 ----------------------------------------- script/script.c | 2 +- 7 files changed, 208 insertions(+), 229 deletions(-) diff --git a/commands/extcmd.c b/commands/extcmd.c index 8fe2ead35..4b3d9d36b 100644 --- a/commands/extcmd.c +++ b/commands/extcmd.c @@ -29,10 +29,8 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, { int new_argc; char **new_args; - struct grub_arg_option *parser; struct grub_arg_list *state; struct grub_extcmd_context context; - int maxargs = 0; grub_err_t ret; grub_extcmd_t ext = cmd->data; @@ -46,24 +44,20 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, return ret; } - parser = (struct grub_arg_option *) ext->options; - while (parser && (parser++)->doc) - maxargs++; - - /* Set up the option state. */ - state = grub_zalloc (sizeof (struct grub_arg_list) * maxargs); - + state = grub_arg_list_alloc (ext, argc, args); if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc)) { context.state = state; ret = (ext->func) (&context, new_argc, new_args); grub_free (new_args); + grub_free (state); + return ret; } - else - ret = grub_errno; - grub_free (state); - return ret; + if (state) + grub_free (state); + + return grub_errno; } static grub_err_t diff --git a/commands/menuentry.c b/commands/menuentry.c index 2d389e942..6b7214d62 100644 --- a/commands/menuentry.c +++ b/commands/menuentry.c @@ -25,25 +25,156 @@ #include #include +static const struct grub_arg_option options[] = + { + {"class", 1, GRUB_ARG_OPTION_REPEATABLE, + N_("Menu entry type."), "STRING", ARG_TYPE_STRING}, + {"users", 2, 0, + N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING}, + {"hotkey", 3, 0, + N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +static struct +{ + char *name; + int key; +} hotkey_aliases[] = + { + {"backspace", '\b'}, + {"tab", '\t'}, + {"delete", GRUB_TERM_DC} + }; + +/* Add a menu entry to the current menu context (as given by the environment + variable data slot `menu'). As the configuration file is read, the script + parser calls this when a menu entry is to be created. */ +static grub_err_t +add_menu_entry (int argc, const char **args, char **classes, + const char *users, const char *hotkey, + const char *sourcecode) +{ + unsigned i; + int menu_hotkey = 0; + char *menu_users = NULL; + char *menu_title = NULL; + char *menu_sourcecode = NULL; + struct grub_menu_entry_class *menu_classes = NULL; + + grub_menu_t menu; + grub_menu_entry_t *last; + + menu = grub_env_get_menu (); + if (! menu) + return grub_error (GRUB_ERR_MENU, "no menu context"); + + last = &menu->entry_list; + + menu_sourcecode = grub_strdup (sourcecode); + if (! menu_sourcecode) + return grub_errno; + + if (classes) + { + for (i = 0; classes[i]; i++); /* count # of menuentry classes */ + menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class) * i); + if (! menu_classes) + goto fail; + + for (i = 0; classes[i]; i++) + { + menu_classes[i].name = grub_strdup (classes[i]); + if (! menu_classes[i].name) + goto fail; + menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL; + } + } + + if (users) + { + menu_users = grub_strdup (users); + if (! menu_users) + goto fail; + } + + if (hotkey) + { + for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++) + if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0) + { + menu_hotkey = hotkey_aliases[i].key; + break; + } + if (i > ARRAY_SIZE (hotkey_aliases)) + goto fail; + } + + if (! argc) + { + grub_error (GRUB_ERR_MENU, "menuentry is missing title"); + goto fail; + } + + menu_title = grub_strdup (args[0]); + if (! menu_title) + goto fail; + + /* XXX: pass args[1..end] as parameters to block arg. */ + + /* Add the menu entry at the end of the list. */ + while (*last) + last = &(*last)->next; + + *last = grub_zalloc (sizeof (**last)); + if (! *last) + goto fail; + + (*last)->title = menu_title; + (*last)->hotkey = menu_hotkey; + (*last)->classes = menu_classes; + if (menu_users) + (*last)->restricted = 1; + (*last)->users = menu_users; + (*last)->sourcecode = menu_sourcecode; + + menu->size++; + return GRUB_ERR_NONE; + + fail: + + grub_free (menu_sourcecode); + for (i = 0; menu_classes && menu_classes[i].name; i++) + grub_free (menu_classes[i].name); + grub_free (menu_classes); + grub_free (menu_users); + grub_free (menu_title); + return grub_errno; +} + static grub_err_t grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) { + char ch; char *src; unsigned len; grub_err_t r; - /* XXX Rewrite to make use of already parsed menu definition. */ if (! argc || ! ctxt->script) return GRUB_ERR_BAD_ARGUMENT; src = args[argc - 1]; - args[argc - 1] = '\0'; + args[argc - 1] = NULL; + len = grub_strlen(src); + ch = src[len - 1]; src[len - 1] = '\0'; - r = grub_normal_add_menu_entry (argc - 1, (const char **) args, src + 1); + r = add_menu_entry (argc - 1, (const char **) args, + ctxt->state[0].args, ctxt->state[1].arg, + ctxt->state[2].arg, src + 1); - src[len - 1] = '}'; + src[len - 1] = ch; args[argc - 1] = src; return r; } @@ -54,7 +185,7 @@ GRUB_MOD_INIT(menuentry) { cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry, GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS, - N_("BLOCK"), N_("Define a menuentry."), 0); + N_("BLOCK"), N_("Define a menuentry."), options); } GRUB_MOD_FINI(menuentry) diff --git a/include/grub/lib/arg.h b/include/grub/lib/arg.h index e6af60cf9..3bab27781 100644 --- a/include/grub/lib/arg.h +++ b/include/grub/lib/arg.h @@ -38,6 +38,8 @@ typedef enum grub_arg_type grub_arg_type_t; /* Flags for the option field op grub_arg_option. */ #define GRUB_ARG_OPTION_OPTIONAL (1 << 1) +/* Flags for an option that can appear multiple times. */ +#define GRUB_ARG_OPTION_REPEATABLE (1 << 2) enum grub_key_type { @@ -59,7 +61,10 @@ struct grub_arg_option struct grub_arg_list { int set; - char *arg; + union { + char *arg; + char **args; + }; }; struct grub_extcmd; @@ -68,5 +73,7 @@ int grub_arg_parse (struct grub_extcmd *cmd, int argc, char **argv, struct grub_arg_list *usr, char ***args, int *argnum); void grub_arg_show_help (struct grub_extcmd *cmd); +struct grub_arg_list* grub_arg_list_alloc (struct grub_extcmd *cmd, + int argc, char *argv[]); #endif /* ! GRUB_ARG_HEADER */ diff --git a/include/grub/normal.h b/include/grub/normal.h index a33e42e61..04d08a557 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -54,8 +54,6 @@ void grub_normal_execute (const char *config, int nested, int batch); void grub_menu_init_page (int nested, int edit, struct grub_term_output *term); void grub_normal_init_page (struct grub_term_output *term); -grub_err_t grub_normal_add_menu_entry (int argc, const char **args, - const char *sourcecode); char *grub_file_getline (grub_file_t file); void grub_cmdline_run (int nested); diff --git a/lib/arg.c b/lib/arg.c index 04e0ea8ba..a11496d5b 100644 --- a/lib/arg.c +++ b/lib/arg.c @@ -207,8 +207,16 @@ parse_option (grub_extcmd_t cmd, int key, char *arg, struct grub_arg_list *usr) if (found == -1) return -1; - usr[found].set = 1; - usr[found].arg = arg; + if (opt->flags & GRUB_ARG_OPTION_REPEATABLE) + { + usr[found].args[usr[found].set++] = arg; + usr[found].args[usr[found].set] = NULL; + } + else + { + usr[found].set = 1; + usr[found].arg = arg; + } } } @@ -229,13 +237,14 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, grub_err_t add_arg (char *s) { char **p = argl; - argl = grub_realloc (argl, (++num) * sizeof (char *)); + argl = grub_realloc (argl, (++num + 1) * sizeof (char *)); if (! argl) { grub_free (p); return grub_errno; } argl[num - 1] = s; + argl[num] = NULL; return 0; } @@ -312,8 +321,11 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, if (option) { arglen = option - arg - 2; option++; - } else + } else { arglen = grub_strlen (arg) - 2; + if (argv[curarg + 1]) + option = argv[curarg + 1][0] == '-' ? 0 : argv[++curarg]; + } opt = find_long (cmd->options, arg + 2, arglen); if (! opt) @@ -392,3 +404,43 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, fail: return complete; } + +struct grub_arg_list* +grub_arg_list_alloc(grub_extcmd_t extcmd, int argc, + char **argv __attribute__((unused))) +{ + int i; + char **args; + unsigned argcnt; + struct grub_arg_list *list; + const struct grub_arg_option *options; + + options = extcmd->options; + if (! options) + return 0; + + argcnt = 0; + for (i = 0; options[i].doc; i++) + { + if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE) + argcnt += (argc + 1) / 2 + 1; /* max possible for any option */ + } + + list = grub_zalloc (sizeof (*list) * i + sizeof (char*) * argcnt); + if (! list) + return 0; + + args = (char**) (list + i); + for (i = 0; options[i].doc; i++) + { + list[i].set = 0; + list[i].arg = 0; + + if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE) + { + list[i].args = args; + args += argc / 2 + 1; + } + } + return list; +} diff --git a/normal/main.c b/normal/main.c index 710b68d14..6997b5d6a 100644 --- a/normal/main.c +++ b/normal/main.c @@ -141,209 +141,6 @@ free_menu (grub_menu_t menu) grub_env_unset_menu (); } -static void -free_menu_entry_classes (struct grub_menu_entry_class *head) -{ - /* Free all the classes. */ - while (head) - { - struct grub_menu_entry_class *next; - - grub_free (head->name); - next = head->next; - grub_free (head); - head = next; - } -} - -static struct -{ - char *name; - int key; -} hotkey_aliases[] = - { - {"backspace", '\b'}, - {"tab", '\t'}, - {"delete", GRUB_TERM_DC} - }; - -/* Add a menu entry to the current menu context (as given by the environment - variable data slot `menu'). As the configuration file is read, the script - parser calls this when a menu entry is to be created. */ -grub_err_t -grub_normal_add_menu_entry (int argc, const char **args, - const char *sourcecode) -{ - const char *menutitle = 0; - const char *menusourcecode; - grub_menu_t menu; - grub_menu_entry_t *last; - int failed = 0; - int i; - struct grub_menu_entry_class *classes_head; /* Dummy head node for list. */ - struct grub_menu_entry_class *classes_tail; - char *users = NULL; - int hotkey = 0; - - /* Allocate dummy head node for class list. */ - classes_head = grub_zalloc (sizeof (struct grub_menu_entry_class)); - if (! classes_head) - return grub_errno; - classes_tail = classes_head; - - menu = grub_env_get_menu (); - if (! menu) - return grub_error (GRUB_ERR_MENU, "no menu context"); - - last = &menu->entry_list; - - menusourcecode = grub_strdup (sourcecode); - if (! menusourcecode) - return grub_errno; - - /* Parse menu arguments. */ - for (i = 0; i < argc; i++) - { - /* Capture arguments. */ - if (grub_strncmp ("--", args[i], 2) == 0 && i + 1 < argc) - { - const char *arg = &args[i][2]; - - /* Handle menu class. */ - if (grub_strcmp(arg, "class") == 0) - { - char *class_name; - struct grub_menu_entry_class *new_class; - - i++; - class_name = grub_strdup (args[i]); - if (! class_name) - { - failed = 1; - break; - } - - /* Create a new class and add it at the tail of the list. */ - new_class = grub_zalloc (sizeof (struct grub_menu_entry_class)); - if (! new_class) - { - grub_free (class_name); - failed = 1; - break; - } - /* Fill in the new class node. */ - new_class->name = class_name; - /* Link the tail to it, and make it the new tail. */ - classes_tail->next = new_class; - classes_tail = new_class; - continue; - } - else if (grub_strcmp(arg, "users") == 0) - { - i++; - users = grub_strdup (args[i]); - if (! users) - { - failed = 1; - break; - } - - continue; - } - else if (grub_strcmp(arg, "hotkey") == 0) - { - unsigned j; - - i++; - if (args[i][1] == 0) - { - hotkey = args[i][0]; - continue; - } - - for (j = 0; j < ARRAY_SIZE (hotkey_aliases); j++) - if (grub_strcmp (args[i], hotkey_aliases[j].name) == 0) - { - hotkey = hotkey_aliases[j].key; - break; - } - - if (j < ARRAY_SIZE (hotkey_aliases)) - continue; - - failed = 1; - grub_error (GRUB_ERR_MENU, - "Invalid hotkey: '%s'.", args[i]); - break; - } - else - { - /* Handle invalid argument. */ - failed = 1; - grub_error (GRUB_ERR_MENU, - "invalid argument for menuentry: %s", args[i]); - break; - } - } - - /* Capture title. */ - if (! menutitle) - { - menutitle = grub_strdup (args[i]); - } - else - { - failed = 1; - grub_error (GRUB_ERR_MENU, - "too many titles for menuentry: %s", args[i]); - break; - } - } - - /* Validate arguments. */ - if ((! failed) && (! menutitle)) - { - grub_error (GRUB_ERR_MENU, "menuentry is missing title"); - failed = 1; - } - - /* If argument parsing failed, free any allocated resources. */ - if (failed) - { - free_menu_entry_classes (classes_head); - grub_free ((void *) menutitle); - grub_free ((void *) menusourcecode); - - /* Here we assume that grub_error has been used to specify failure details. */ - return grub_errno; - } - - /* Add the menu entry at the end of the list. */ - while (*last) - last = &(*last)->next; - - *last = grub_zalloc (sizeof (**last)); - if (! *last) - { - free_menu_entry_classes (classes_head); - grub_free ((void *) menutitle); - grub_free ((void *) menusourcecode); - return grub_errno; - } - - (*last)->title = menutitle; - (*last)->hotkey = hotkey; - (*last)->classes = classes_head; - if (users) - (*last)->restricted = 1; - (*last)->users = users; - (*last)->sourcecode = menusourcecode; - - menu->size++; - - return GRUB_ERR_NONE; -} - static grub_menu_t read_config_file (const char *config) { diff --git a/script/script.c b/script/script.c index bcefd81d8..c1b5cf8cd 100644 --- a/script/script.c +++ b/script/script.c @@ -104,8 +104,8 @@ grub_script_free (struct grub_script *script) s = script->children; while (s) { - grub_script_put (s); s = s->siblings; + grub_script_put (s); } grub_free (script); } From 1767f7096ca2398bd725879021e4db0e66b77c70 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 22 Jul 2010 21:15:14 +0530 Subject: [PATCH 07/12] menuentry can pass parameters to its definition --- commands/menuentry.c | 33 ++++++++++++++++++----- include/grub/menu.h | 4 +++ include/grub/script_sh.h | 1 + normal/menu.c | 41 +---------------------------- script/execute.c | 56 ++++++++++++++++++++++++++++++++++++++++ script/script.c | 4 ++- 6 files changed, 91 insertions(+), 48 deletions(-) diff --git a/commands/menuentry.c b/commands/menuentry.c index 6b7214d62..be4fa3347 100644 --- a/commands/menuentry.c +++ b/commands/menuentry.c @@ -51,12 +51,13 @@ static struct variable data slot `menu'). As the configuration file is read, the script parser calls this when a menu entry is to be created. */ static grub_err_t -add_menu_entry (int argc, const char **args, char **classes, - const char *users, const char *hotkey, - const char *sourcecode) +append_menu_entry (int argc, const char **args, char **classes, + const char *users, const char *hotkey, + const char *sourcecode) { unsigned i; int menu_hotkey = 0; + char **menu_args = NULL; char *menu_users = NULL; char *menu_title = NULL; char *menu_sourcecode = NULL; @@ -120,7 +121,18 @@ add_menu_entry (int argc, const char **args, char **classes, if (! menu_title) goto fail; - /* XXX: pass args[1..end] as parameters to block arg. */ + /* Save argc, args to pass as parameters to block arg later. */ + menu_args = grub_malloc (sizeof (char*) * (argc + 1)); + if (! menu_args) + goto fail; + + for (i = 0; args[i]; i++) + { + menu_args[i] = grub_strdup (args[i]); + if (! menu_args[i]) + goto fail; + } + menu_args[argc] = NULL; /* Add the menu entry at the end of the list. */ while (*last) @@ -136,6 +148,8 @@ add_menu_entry (int argc, const char **args, char **classes, if (menu_users) (*last)->restricted = 1; (*last)->users = menu_users; + (*last)->argc = argc; + (*last)->args = menu_args; (*last)->sourcecode = menu_sourcecode; menu->size++; @@ -147,6 +161,11 @@ add_menu_entry (int argc, const char **args, char **classes, for (i = 0; menu_classes && menu_classes[i].name; i++) grub_free (menu_classes[i].name); grub_free (menu_classes); + + for (i = 0; menu_args && menu_args[i]; i++) + grub_free (menu_args[i]); + grub_free (menu_args); + grub_free (menu_users); grub_free (menu_title); return grub_errno; @@ -170,9 +189,9 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) ch = src[len - 1]; src[len - 1] = '\0'; - r = add_menu_entry (argc - 1, (const char **) args, - ctxt->state[0].args, ctxt->state[1].arg, - ctxt->state[2].arg, src + 1); + r = append_menu_entry (argc - 1, (const char **) args, + ctxt->state[0].args, ctxt->state[1].arg, + ctxt->state[2].arg, src + 1); src[len - 1] = ch; args[argc - 1] = src; diff --git a/include/grub/menu.h b/include/grub/menu.h index e5e5fb110..9dc257ab7 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h @@ -47,6 +47,10 @@ struct grub_menu_entry /* The sourcecode of the menu entry, used by the editor. */ const char *sourcecode; + /* Parameters to be passed to menu definition. */ + int argc; + char **args; + int hotkey; /* The next element. */ diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 122d89862..7869a4680 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -303,6 +303,7 @@ grub_err_t grub_script_execute_cmdwhile (struct grub_script_cmd *cmd); /* Execute any GRUB pre-parsed command or script. */ grub_err_t grub_script_execute (struct grub_script *script); +grub_err_t grub_script_execute_sourcecode (const char *source, int argc, char **args); /* This variable points to the parsed command. This is used to communicate with the bison code. */ diff --git a/normal/menu.c b/normal/menu.c index b57990b0d..f483349e4 100644 --- a/normal/menu.c +++ b/normal/menu.c @@ -142,44 +142,6 @@ get_and_remove_first_entry_number (const char *name) return entry; } -static void -grub_menu_execute_entry_real (grub_menu_entry_t entry) -{ - const char *source; - - auto grub_err_t getline (char **line, int cont); - grub_err_t getline (char **line, int cont __attribute__ ((unused))) - { - const char *p; - - if (!source) - { - *line = 0; - return 0; - } - - p = grub_strchr (source, '\n'); - - if (p) - *line = grub_strndup (source, p - source); - else - *line = grub_strdup (source); - source = p ? p + 1 : 0; - return 0; - } - - source = entry->sourcecode; - - while (source) - { - char *line; - - getline (&line, 0); - grub_normal_parse_line (line, getline); - grub_free (line); - } -} - /* Run a menu entry. */ void grub_menu_execute_entry(grub_menu_entry_t entry) @@ -197,8 +159,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry) } grub_env_set ("chosen", entry->title); - - grub_menu_execute_entry_real (entry); + grub_script_execute_sourcecode (entry->sourcecode, entry->argc, entry->args); if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) /* Implicit execution of boot, only if something is loaded. */ diff --git a/script/execute.c b/script/execute.c index 4b906b06f..43a8bd1d7 100644 --- a/script/execute.c +++ b/script/execute.c @@ -268,6 +268,62 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) return ret; } +/* Execute a source script. */ +grub_err_t +grub_script_execute_sourcecode (const char *source, int argc, char **args) +{ + grub_err_t ret = 0; + struct grub_script *parsed_script; + struct grub_script_scope new_scope; + struct grub_script_scope *old_scope; + + auto grub_err_t getline (char **line, int cont); + grub_err_t getline (char **line, int cont __attribute__ ((unused))) + { + const char *p; + + if (! source) + { + *line = 0; + return 0; + } + + p = grub_strchr (source, '\n'); + + if (p) + *line = grub_strndup (source, p - source); + else + *line = grub_strdup (source); + source = p ? p + 1 : 0; + return 0; + } + + new_scope.argv.argc = argc; + new_scope.argv.args = args; + + old_scope = scope; + scope = &new_scope; + + while (source) + { + char *line; + + getline (&line, 0); + parsed_script = grub_script_parse (line, getline); + if (! parsed_script) + { + ret = grub_errno; + break; + } + + ret = grub_script_execute (parsed_script); + grub_free (line); + } + + scope = old_scope; + return ret; +} + /* Execute a single command line. */ grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd) diff --git a/script/script.c b/script/script.c index c1b5cf8cd..6da4b72cd 100644 --- a/script/script.c +++ b/script/script.c @@ -95,6 +95,7 @@ void grub_script_free (struct grub_script *script) { struct grub_script *s; + struct grub_script *t; if (!script) return; @@ -104,8 +105,9 @@ grub_script_free (struct grub_script *script) s = script->children; while (s) { - s = s->siblings; + t = s->siblings; grub_script_put (s); + s = t; } grub_free (script); } From 1a60d363b0808700bfaa8b475852c5063eda7f21 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 22 Jul 2010 23:22:36 +0530 Subject: [PATCH 08/12] cleanup --- commands/extcmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/commands/extcmd.c b/commands/extcmd.c index 4b3d9d36b..44a4b6cfd 100644 --- a/commands/extcmd.c +++ b/commands/extcmd.c @@ -54,9 +54,7 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, return ret; } - if (state) - grub_free (state); - + grub_free (state); return grub_errno; } From 78780e7005c687d35d9a4a0ba09059520a1ecff6 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 3 Sep 2010 20:53:38 +0530 Subject: [PATCH 09/12] fix hotkey handling --- grub-core/commands/menuentry.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c index be4fa3347..b6662bb96 100644 --- a/grub-core/commands/menuentry.c +++ b/grub-core/commands/menuentry.c @@ -107,8 +107,8 @@ append_menu_entry (int argc, const char **args, char **classes, menu_hotkey = hotkey_aliases[i].key; break; } - if (i > ARRAY_SIZE (hotkey_aliases)) - goto fail; + if (i == ARRAY_SIZE (hotkey_aliases)) + menu_hotkey = hotkey[0]; } if (! argc) From 9284756e17c87a76c2ec22b1c59f5e5eab2f3a1b Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 3 Sep 2010 21:08:12 +0530 Subject: [PATCH 10/12] merge menuentry.mod into normal.mod --- grub-core/Makefile.core.def | 7 ++----- grub-core/commands/menuentry.c | 6 ++++-- grub-core/normal/main.c | 2 ++ include/grub/menu.h | 3 +++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index bba3503a6..be005378b 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1173,6 +1173,8 @@ module = { common = script/lexer.c; common = script/argv.c; + common = commands/menuentry.c; + common = unidata.c; common_nodist = grub_script.tab.c; common_nodist = grub_script.yy.c; @@ -1408,8 +1410,3 @@ module = { name = test_blockarg; common = tests/test_blockarg.c; }; - -module = { - name = menuentry; - common = commands/menuentry.c; -}; \ No newline at end of file diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c index b6662bb96..5e20d4285 100644 --- a/grub-core/commands/menuentry.c +++ b/grub-core/commands/menuentry.c @@ -200,14 +200,16 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) static grub_extcmd_t cmd; -GRUB_MOD_INIT(menuentry) +void +grub_menu_init (void) { cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry, GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS, N_("BLOCK"), N_("Define a menuentry."), options); } -GRUB_MOD_FINI(menuentry) +void +grub_menu_fini (void) { grub_unregister_extcmd (cmd); } diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c index 64d438a91..6a008f577 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -476,6 +476,7 @@ GRUB_MOD_INIT(normal) { grub_context_init (); grub_script_init (); + grub_menu_init (); grub_xputs_saved = grub_xputs; grub_xputs = grub_xputs_normal; @@ -515,6 +516,7 @@ GRUB_MOD_FINI(normal) { grub_context_fini (); grub_script_fini (); + grub_menu_fini (); grub_xputs = grub_xputs_saved; diff --git a/include/grub/menu.h b/include/grub/menu.h index 9dc257ab7..608253863 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h @@ -100,4 +100,7 @@ void grub_menu_execute_with_fallback (grub_menu_t menu, void grub_menu_entry_run (grub_menu_entry_t entry); int grub_menu_get_default_entry_index (grub_menu_t menu); +void grub_menu_init (void); +void grub_menu_fini (void); + #endif /* GRUB_MENU_HEADER */ From e89f9ec539fdae1e5425d207a60a6ce1e9384106 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 3 Sep 2010 22:28:16 +0530 Subject: [PATCH 11/12] add setparams prefix --- grub-core/commands/menuentry.c | 63 ++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c index 5e20d4285..6fdb172b6 100644 --- a/grub-core/commands/menuentry.c +++ b/grub-core/commands/menuentry.c @@ -53,7 +53,7 @@ static struct static grub_err_t append_menu_entry (int argc, const char **args, char **classes, const char *users, const char *hotkey, - const char *sourcecode) + const char *prefix, const char *sourcecode) { unsigned i; int menu_hotkey = 0; @@ -72,7 +72,7 @@ append_menu_entry (int argc, const char **args, char **classes, last = &menu->entry_list; - menu_sourcecode = grub_strdup (sourcecode); + menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode); if (! menu_sourcecode) return grub_errno; @@ -171,11 +171,63 @@ append_menu_entry (int argc, const char **args, char **classes, return grub_errno; } +static char * +setparams_prefix (int argc, char **args) +{ + int i; + int j; + char *p; + char *result; + grub_size_t len = 10; + static const char *escape_characters = "\"\\"; + + auto char *strescpy (char *, const char *, const char *); + char * strescpy (char *d, const char *s, const char *escapes) + { + while (*s) + { + if (grub_strchr (escapes, *s)) + *d++ = '\\'; + *d++ = *s++; + } + *d = '\0'; + return d; + } + + /* Count resulting string length */ + for (i = 0; i < argc; i++) + { + len += 3; /* 3 = 1 space + 2 quotes */ + p = args[i]; + while (*p) + len += grub_strchr (escape_characters, *p++) ? 2 : 1; + } + + result = grub_malloc (len + 2); + if (! result) + return 0; + + grub_strcpy (result, "setparams"); + i = 9; + + for (j = 0; j < argc; j++) + { + result[i++] = ' '; + result[i++] = '"'; + i = strescpy (result + i, args[j], escape_characters) - result; + result[i++] = '"'; + } + result[i++] = '\n'; + result[i] = '\0'; + return result; +} + static grub_err_t grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) { char ch; char *src; + char *prefix; unsigned len; grub_err_t r; @@ -189,12 +241,17 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) ch = src[len - 1]; src[len - 1] = '\0'; + prefix = setparams_prefix (argc - 1, args); + if (! prefix) + return grub_errno; + r = append_menu_entry (argc - 1, (const char **) args, ctxt->state[0].args, ctxt->state[1].arg, - ctxt->state[2].arg, src + 1); + ctxt->state[2].arg, prefix, src + 1); src[len - 1] = ch; args[argc - 1] = src; + grub_free (prefix); return r; } From 80f5b97cdce1cf615da9ad4fccfdbd9af6c3d47a Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Sat, 4 Sep 2010 08:14:50 +0530 Subject: [PATCH 12/12] --source option for menuentry --- grub-core/commands/menuentry.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c index 6fdb172b6..fc1ae71c7 100644 --- a/grub-core/commands/menuentry.c +++ b/grub-core/commands/menuentry.c @@ -33,6 +33,8 @@ static const struct grub_arg_option options[] = N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING}, {"hotkey", 3, 0, N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING}, + {"source", 4, 0, + N_("Menu entry definition as a string."), "STRING", ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -231,8 +233,19 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) unsigned len; grub_err_t r; - if (! argc || ! ctxt->script) - return GRUB_ERR_BAD_ARGUMENT; + if (! argc) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments"); + + if (ctxt->state[3].set && ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions"); + + if (! ctxt->state[3].set && ! ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition"); + + if (! ctxt->script) + return append_menu_entry (argc, (const char **) args, + ctxt->state[0].args, ctxt->state[1].arg, + ctxt->state[2].arg, 0, ctxt->state[3].arg); src = args[argc - 1]; args[argc - 1] = NULL;