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); }