From 9d0bd7407d9355ef73d63384959b7a89e76b33b1 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 10 Jun 2010 18:15:38 +0530 Subject: [PATCH 01/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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 262b2d73c73f0f9b4b2e9d0a9a32c1ea36ab118b Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Tue, 3 Aug 2010 16:33:36 +0530 Subject: [PATCH 09/19] regexp sets matches to $match* --- commands/regexp.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/commands/regexp.c b/commands/regexp.c index e8e8243b5..2e84c3b0d 100644 --- a/commands/regexp.c +++ b/commands/regexp.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -29,28 +31,50 @@ grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { int argn = 0; - int matches = 0; regex_t regex; int ret; grub_size_t s; char *comperr; grub_err_t err; + regmatch_t *matches = 0; if (argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "2 arguments expected"); - ret = regcomp (®ex, args[0], RE_SYNTAX_GNU_AWK); + ret = regcomp (®ex, args[0], REG_EXTENDED); if (ret) goto fail; - ret = regexec (®ex, args[1], 0, 0, 0); + matches = grub_zalloc (sizeof (*matches) * (regex.re_nsub + 1)); + if (! matches) + goto fail; + + ret = regexec (®ex, args[1], regex.re_nsub + 1, matches, 0); if (!ret) { + int i; + char ch; + char buf[5 + sizeof (size_t) * 3]; + + for (i = 0; i <= regex.re_nsub && matches[i].rm_so != -1; i++) + { + ch = args[1][matches[i].rm_eo]; + args[1][matches[i].rm_eo] = '\0'; + + grub_snprintf (buf, sizeof (buf), "%s%u", "match", i); + if (grub_env_set (buf, args[1] + matches[i].rm_so)) + break; + + args[1][matches[i].rm_eo] = ch; + } + regfree (®ex); + grub_free (matches); return GRUB_ERR_NONE; } fail: + grub_free (matches); s = regerror (ret, ®ex, 0, 0); comperr = grub_malloc (s); if (!comperr) From 1355b096f6613d8aed2bf878b02ad26fee8ca3ab Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 4 Aug 2010 11:08:26 +0530 Subject: [PATCH 10/19] regexp can take variable names to update with matches --- commands/regexp.c | 92 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/commands/regexp.c b/commands/regexp.c index 2e84c3b0d..8edf818a3 100644 --- a/commands/regexp.c +++ b/commands/regexp.c @@ -22,13 +22,69 @@ #include #include #include -#include +#include #include #include +static const struct grub_arg_option options[] = + { + { "set", 's', GRUB_ARG_OPTION_REPEATABLE, + N_("Variable names to update with matches."), + N_("[NUMBER:]VARNAME"), ARG_TYPE_STRING }, + { 0, 0, 0, 0, 0, 0 } + }; + static grub_err_t -grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), - int argc, char **args) +set_matches (char **varnames, char *str, grub_size_t nmatches, + regmatch_t *matches) +{ + int i; + char ch; + char *p; + char *q; + grub_err_t err; + unsigned long j; + + auto void setvar (char *v, regmatch_t *m); + void setvar (char *v, regmatch_t *m) + { + ch = str[m->rm_eo]; + str[m->rm_eo] = '\0'; + err = grub_env_set (v, str + m->rm_so); + str[m->rm_eo] = ch; + } + + for (i = 0; varnames && varnames[i]; i++) + { + if (! (p = grub_strchr (varnames[i], ':'))) + { + /* varname w/o index defaults to 1 */ + if (nmatches < 2 || matches[1].rm_so == -1) + grub_env_unset (varnames[i]); + else + setvar (varnames[i], &matches[1]); + } + else + { + j = grub_strtoul (varnames[i], &q, 10); + if (q != p) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "invalid variable name format %s", varnames[i]); + + if (nmatches <= j || matches[j].rm_so == -1) + grub_env_unset (p + 1); + else + setvar (p + 1, &matches[j]); + } + + if (err != GRUB_ERR_NONE) + return err; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_regexp (grub_extcmd_context_t ctxt, int argc, char **args) { int argn = 0; regex_t regex; @@ -52,25 +108,11 @@ grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), ret = regexec (®ex, args[1], regex.re_nsub + 1, matches, 0); if (!ret) { - int i; - char ch; - char buf[5 + sizeof (size_t) * 3]; - - for (i = 0; i <= regex.re_nsub && matches[i].rm_so != -1; i++) - { - ch = args[1][matches[i].rm_eo]; - args[1][matches[i].rm_eo] = '\0'; - - grub_snprintf (buf, sizeof (buf), "%s%u", "match", i); - if (grub_env_set (buf, args[1] + matches[i].rm_so)) - break; - - args[1][matches[i].rm_eo] = ch; - } - + err = set_matches (ctxt->state[0].args, args[1], + regex.re_nsub + 1, matches); regfree (®ex); grub_free (matches); - return GRUB_ERR_NONE; + return err; } fail: @@ -89,16 +131,16 @@ grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), return err; } -static grub_command_t cmd; +static grub_extcmd_t cmd; GRUB_MOD_INIT(regexp) { - cmd = grub_register_command ("regexp", grub_cmd_regexp, - N_("REGEXP STRING"), - N_("Test if REGEXP matches STRING.")); + cmd = grub_register_extcmd ("regexp", grub_cmd_regexp, + GRUB_COMMAND_FLAG_BOTH, N_("REGEXP STRING"), + N_("Test if REGEXP matches STRING."), options); } GRUB_MOD_FINI(regexp) { - grub_unregister_command (cmd); + grub_unregister_extcmd (cmd); } From cd838e22c2ed09788abc79e3a0056b30af90025c Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 4 Aug 2010 19:21:18 +0530 Subject: [PATCH 11/19] added a testcase --- conf/tests.rmk | 4 ++++ tests/regexp_vars.in | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/regexp_vars.in diff --git a/conf/tests.rmk b/conf/tests.rmk index 9144e5528..f7ec76366 100644 --- a/conf/tests.rmk +++ b/conf/tests.rmk @@ -74,6 +74,9 @@ grub_script_comments_SOURCES = tests/grub_script_comments.in check_SCRIPTS += grub_script_functions grub_script_functions_SOURCES = tests/grub_script_functions.in +check_SCRIPTS += regexp_vars +regexp_vars_SOURCES = tests/regexp_vars.in + # List of tests to execute on "make check" # SCRIPTED_TESTS = example_scripted_test # SCRIPTED_TESTS += example_grub_script_test @@ -91,6 +94,7 @@ SCRIPTED_TESTS += grub_script_final_semicolon SCRIPTED_TESTS += grub_script_dollar SCRIPTED_TESTS += grub_script_comments SCRIPTED_TESTS += grub_script_functions +SCRIPTED_TESTS += regexp_vars # dependencies between tests and testing-tools $(SCRIPTED_TESTS): grub-shell grub-shell-tester diff --git a/tests/regexp_vars.in b/tests/regexp_vars.in new file mode 100644 index 000000000..43b479fec --- /dev/null +++ b/tests/regexp_vars.in @@ -0,0 +1,41 @@ +#! /bin/bash -e + +# Run GRUB script in a Qemu instance +# 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 . + +cmd='regexp -s version "vm-(.*)" vm-1.2.3; echo $version' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != 1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 1:version "vm-(.*)" vm-1.2.3; echo $version' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != 1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 0:match "vm-(.*)" vm-1.2.3; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != vm-1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 2:match "vm-(.*)" vm-1.2.3; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test -n "$v"; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s match "\\\((.*)\\\)" (hd0,msdos1); echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != "hd0,msdos1"; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s match "hd([0-9]+)" hd0; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != "0"; then echo "error: $cmd" >&2; exit 1; fi From 3a20130e7a667e89c369346d122a7f900f65990b Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Sun, 15 Aug 2010 12:02:33 +0530 Subject: [PATCH 12/19] setparams command to set positional parameters --- conf/tests.rmk | 4 +++ include/grub/script_sh.h | 4 +++ script/argv.c | 17 ++++++++++ script/execute.c | 61 +++++++++++++++++++++++++++++++--- script/main.c | 8 +++++ tests/grub_script_setparams.in | 59 ++++++++++++++++++++++++++++++++ util/grub-script-check.c | 8 +++++ 7 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 tests/grub_script_setparams.in diff --git a/conf/tests.rmk b/conf/tests.rmk index c14fe0fda..0d41a711b 100644 --- a/conf/tests.rmk +++ b/conf/tests.rmk @@ -83,6 +83,9 @@ grub_script_continue_SOURCES = tests/grub_script_continue.in check_SCRIPTS += grub_script_shift grub_script_shift_SOURCES = tests/grub_script_shift.in +check_SCRIPTS += grub_script_setparams +grub_script_setparams_SOURCES = tests/grub_script_setparams.in + # List of tests to execute on "make check" # SCRIPTED_TESTS = example_scripted_test # SCRIPTED_TESTS += example_grub_script_test @@ -103,6 +106,7 @@ SCRIPTED_TESTS += grub_script_functions SCRIPTED_TESTS += grub_script_break SCRIPTED_TESTS += grub_script_continue SCRIPTED_TESTS += grub_script_shift +SCRIPTED_TESTS += grub_script_setparams # dependencies between tests and testing-tools $(SCRIPTED_TESTS): grub-shell grub-shell-tester diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 77e807360..e0ed5c005 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -227,6 +227,7 @@ void grub_script_init (void); void grub_script_fini (void); void grub_script_argv_free (struct grub_script_argv *argv); +int grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args); int grub_script_argv_next (struct grub_script_argv *argv); int grub_script_argv_append (struct grub_script_argv *argv, const char *s); int grub_script_argv_split_append (struct grub_script_argv *argv, char *s); @@ -321,6 +322,9 @@ grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]); /* SHIFT command for GRUB script. */ grub_err_t grub_script_shift (grub_command_t cmd, int argc, char *argv[]); +/* SETPARAMS command for GRUB script functions. */ +grub_err_t grub_script_setparams (grub_command_t cmd, int argc, char *argv[]); + /* This variable points to the parsed command. This is used to communicate with the bison code. */ extern struct grub_script_cmd *grub_script_parsed; diff --git a/script/argv.c b/script/argv.c index b69ee39c5..c642ea9c5 100644 --- a/script/argv.c +++ b/script/argv.c @@ -57,6 +57,23 @@ grub_script_argv_free (struct grub_script_argv *argv) argv->args = 0; } +/* Make argv from argc, args pair. */ +int +grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args) +{ + int i; + struct grub_script_argv r = { 0, 0}; + + for (i = 0; i < argc; i++) + if (grub_script_argv_next (&r) || grub_script_argv_append (&r, args[i])) + { + grub_script_argv_free (&r); + return 1; + } + *argv = r; + return 0; +} + /* Prepare for next argc. */ int grub_script_argv_next (struct grub_script_argv *argv) diff --git a/script/execute.c b/script/execute.c index 26a46b12b..b911163f7 100644 --- a/script/execute.c +++ b/script/execute.c @@ -34,13 +34,35 @@ static unsigned long is_continue; static unsigned long active_loops; static unsigned long active_breaks; +#define GRUB_SCRIPT_SCOPE_MALLOCED 1 +#define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2 + /* Scope for grub script functions. */ struct grub_script_scope { + unsigned flags; + unsigned shifts; struct grub_script_argv argv; }; static struct grub_script_scope *scope = 0; +static void +replace_scope (struct grub_script_scope *new_scope) +{ + if (scope) + { + scope->argv.argc += scope->shifts; + scope->argv.args -= scope->shifts; + + if (scope->flags & GRUB_SCRIPT_SCOPE_ARGS_MALLOCED) + grub_script_argv_free (&scope->argv); + + if (scope->flags & GRUB_SCRIPT_SCOPE_MALLOCED) + grub_free (scope); + } + scope = new_scope; +} + grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]) { @@ -85,11 +107,41 @@ grub_script_shift (grub_command_t cmd __attribute__((unused)), if (n > scope->argv.argc) return GRUB_ERR_BAD_ARGUMENT; + scope->shifts += n; scope->argv.argc -= n; scope->argv.args += n; return GRUB_ERR_NONE; } +grub_err_t +grub_script_setparams (grub_command_t cmd __attribute__((unused)), + int argc, char **args) +{ + struct grub_script_scope *new_scope; + struct grub_script_argv argv = { 0, 0 }; + + if (! scope) + return GRUB_ERR_INVALID_COMMAND; + + new_scope = grub_malloc (sizeof (*new_scope)); + if (! new_scope) + return grub_errno; + + if (grub_script_argv_make (&argv, argc, args)) + { + grub_free (new_scope); + return grub_errno; + } + + new_scope->shifts = 0; + new_scope->argv = argv; + new_scope->flags = GRUB_SCRIPT_SCOPE_MALLOCED | + GRUB_SCRIPT_SCOPE_ARGS_MALLOCED; + + replace_scope (new_scope); + return GRUB_ERR_NONE; +} + static int grub_env_special (const char *name) { @@ -104,6 +156,7 @@ grub_env_special (const char *name) static char ** grub_script_env_get (const char *name, grub_script_arg_type_t type) { + unsigned i; struct grub_script_argv result = { 0, 0 }; if (grub_script_argv_next (&result)) @@ -138,8 +191,6 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else if (grub_strcmp (name, "*") == 0) { - unsigned i; - for (i = 0; i < scope->argv.argc; i++) if (type == GRUB_SCRIPT_ARG_TYPE_VAR) { @@ -160,8 +211,6 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else if (grub_strcmp (name, "@") == 0) { - unsigned i; - for (i = 0; i < scope->argv.argc; i++) { if (i != 0 && grub_script_argv_next (&result)) @@ -302,6 +351,8 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) struct grub_script_scope new_scope; active_loops = 0; + new_scope.flags = 0; + new_scope.shifts = 0; new_scope.argv.argc = argc; new_scope.argv.args = args; @@ -311,7 +362,7 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) ret = grub_script_execute (func->func); active_loops = loops; - scope = old_scope; + replace_scope (old_scope); /* free any scopes by setparams */ return ret; } diff --git a/script/main.c b/script/main.c index ff714d060..a16a65c13 100644 --- a/script/main.c +++ b/script/main.c @@ -44,6 +44,7 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline) static grub_command_t cmd_break; static grub_command_t cmd_continue; static grub_command_t cmd_shift; +static grub_command_t cmd_setparams; void grub_script_init (void) @@ -54,6 +55,9 @@ grub_script_init (void) N_("[n]"), N_("Continue loops")); cmd_shift = grub_register_command ("shift", grub_script_shift, N_("[n]"), N_("Shift positional parameters.")); + cmd_setparams = grub_register_command ("setparams", grub_script_setparams, + N_("[VALUE]..."), + N_("Set positional parameters.")); } void @@ -70,4 +74,8 @@ grub_script_fini (void) if (cmd_shift) grub_unregister_command (cmd_shift); cmd_shift = 0; + + if (cmd_setparams) + grub_unregister_command (cmd_setparams); + cmd_setparams = 0; } diff --git a/tests/grub_script_setparams.in b/tests/grub_script_setparams.in new file mode 100644 index 000000000..82d316813 --- /dev/null +++ b/tests/grub_script_setparams.in @@ -0,0 +1,59 @@ +#! @builddir@/grub-shell-tester + +# Run GRUB script in a Qemu instance +# 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 . + +if test x$grubshell = xyes; then cmd=setparams; else cmd=set; fi + +function f1 { + echo $# + echo "$#" + + echo $@ + echo "$@" + + echo $* + echo "$*" + + echo $1 $2 + for v in "$@"; do echo $v; done + shift + echo $1 $2 + for v in "$@"; do echo $v; done + + $cmd 1 2 3 4 + + echo $# + echo "$#" + + echo $@ + echo "$@" + + echo $* + echo "$*" + + echo $1 $2 + for v in "$@"; do echo $v; done + shift + echo $1 $2 + for v in "$@"; do echo $v; done +} +# f1 +# f1 a +f1 a b +f1 a b c +f1 a b c d +f1 a b c d e diff --git a/util/grub-script-check.c b/util/grub-script-check.c index 4ca85c4bd..375d064d4 100644 --- a/util/grub-script-check.c +++ b/util/grub-script-check.c @@ -73,6 +73,14 @@ grub_script_shift (grub_command_t cmd __attribute__((unused)), return 0; } +grub_err_t +grub_script_setparams (grub_command_t cmd __attribute__((unused)), + int argc __attribute__((unused)), + char *argv[] __attribute__((unused))) +{ + return 0; +} + char * grub_script_execute_argument_to_string (struct grub_script_arg *arg __attribute__ ((unused))) { From aa5cd41af5b603b06f0082be797e668be3f7e256 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 25 Aug 2010 19:35:52 +0530 Subject: [PATCH 13/19] return command for functions --- ChangeLog | 11 +++ Makefile.util.def | 6 ++ grub-core/script/execute.c | 60 +++++++++++++--- grub-core/script/main.c | 7 ++ include/grub/script_sh.h | 3 + tests/grub_script_return.in | 134 ++++++++++++++++++++++++++++++++++++ 6 files changed, 212 insertions(+), 9 deletions(-) create mode 100644 tests/grub_script_return.in diff --git a/ChangeLog b/ChangeLog index 2db022484..0ce38240f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2010-08-25 BVK Chaitanya + + "return" command for GRUB script functions. + + * grub-core/script/main.c: Register/unregister return command. + * grub-core/script/execute.c (grub_script_return): New function. + * include/grub/script_sh.h (grub_script_return): New prototype. + + * tests/grub_script_return.in: New test for return command. + * Makefile.util.def: Rules for grub_script_return test. + 2010-08-23 BVK Chaitanya New Automake based build system for GRUB. diff --git a/Makefile.util.def b/Makefile.util.def index fd3428e76..4998bd254 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -496,6 +496,12 @@ script = { common = tests/grub_script_shift.in; }; +script = { + testcase; + name = grub_script_return; + common = tests/grub_script_return.in; +}; + program = { testcase; name = example_unit_test; diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index 26a46b12b..e78a41bb5 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -33,6 +33,7 @@ static unsigned long is_continue; static unsigned long active_loops; static unsigned long active_breaks; +static unsigned long function_return; /* Scope for grub script functions. */ struct grub_script_scope @@ -90,6 +91,30 @@ grub_script_shift (grub_command_t cmd __attribute__((unused)), return GRUB_ERR_NONE; } +grub_err_t +grub_script_return (grub_command_t cmd __attribute__((unused)), + int argc, char *argv[]) +{ + char *p; + unsigned long n; + + if (! scope || argc > 1) + return GRUB_ERR_BAD_ARGUMENT; + + if (argc == 0) + { + function_return = 1; + return grub_strtoul (grub_env_get ("?"), NULL, 10); + } + + n = grub_strtoul (argv[0], &p, 10); + if (*p != '\0') + return GRUB_ERR_BAD_ARGUMENT; + + function_return = 1; + return n; +} + static int grub_env_special (const char *name) { @@ -310,6 +335,7 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) ret = grub_script_execute (func->func); + function_return = 0; active_loops = loops; scope = old_scope; return ret; @@ -395,8 +421,16 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list) struct grub_script_cmd *cmd; /* Loop over every command and execute it. */ - for (cmd = list->next; cmd && ! active_breaks; cmd = cmd->next) - ret = grub_script_execute_cmd (cmd); + for (cmd = list->next; cmd; cmd = cmd->next) + { + if (active_breaks) + break; + + ret = grub_script_execute_cmd (cmd); + + if (function_return) + break; + } return ret; } @@ -405,14 +439,17 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list) grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd) { - struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd; + int ret; char *result; + struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd; /* Check if the commands results in a true or a false. The value is read from the env variable `?'. */ - grub_script_execute_cmd (cmdif->exec_to_evaluate); - result = grub_env_get ("?"); + ret = grub_script_execute_cmd (cmdif->exec_to_evaluate); + if (function_return) + return ret; + result = grub_env_get ("?"); grub_errno = GRUB_ERR_NONE; /* Execute the `if' or the `else' part depending on the value of @@ -447,6 +484,8 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { grub_script_env_set (cmdfor->name->str, argv.args[i]); result = grub_script_execute_cmd (cmdfor->list); + if (function_return) + break; } } @@ -462,18 +501,21 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) grub_err_t grub_script_execute_cmdwhile (struct grub_script_cmd *cmd) { - int cond; int result; struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd; active_loops++; - result = 0; do { - cond = grub_script_execute_cmd (cmdwhile->cond); - if (cmdwhile->until ? !cond : cond) + result = grub_script_execute_cmd (cmdwhile->cond); + if (function_return) + break; + + if (cmdwhile->until ? !result : result) break; result = grub_script_execute_cmd (cmdwhile->list); + if (function_return) + break; if (active_breaks == 1 && is_continue) active_breaks = 0; diff --git a/grub-core/script/main.c b/grub-core/script/main.c index ff714d060..7caeb2661 100644 --- a/grub-core/script/main.c +++ b/grub-core/script/main.c @@ -44,6 +44,7 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline) static grub_command_t cmd_break; static grub_command_t cmd_continue; static grub_command_t cmd_shift; +static grub_command_t cmd_return; void grub_script_init (void) @@ -54,6 +55,8 @@ grub_script_init (void) N_("[n]"), N_("Continue loops")); cmd_shift = grub_register_command ("shift", grub_script_shift, N_("[n]"), N_("Shift positional parameters.")); + cmd_return = grub_register_command ("return", grub_script_return, + N_("[n]"), N_("Return from a function.")); } void @@ -70,4 +73,8 @@ grub_script_fini (void) if (cmd_shift) grub_unregister_command (cmd_shift); cmd_shift = 0; + + if (cmd_return) + grub_unregister_command (cmd_return); + cmd_return = 0; } diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 77e807360..844ef7930 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -321,6 +321,9 @@ grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]); /* SHIFT command for GRUB script. */ grub_err_t grub_script_shift (grub_command_t cmd, int argc, char *argv[]); +/* RETURN command for functions. */ +grub_err_t grub_script_return (grub_command_t cmd, int argc, char *argv[]); + /* This variable points to the parsed command. This is used to communicate with the bison code. */ extern struct grub_script_cmd *grub_script_parsed; diff --git a/tests/grub_script_return.in b/tests/grub_script_return.in new file mode 100644 index 000000000..712d1dfcf --- /dev/null +++ b/tests/grub_script_return.in @@ -0,0 +1,134 @@ +#! @builddir@/grub-shell-tester + +# Run GRUB script in a Qemu instance +# 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 . + +function f1 { + return + echo one +} +f1 + +function f2 { + true + return + echo one +} +if f2; then echo true; else echo false; fi + +function f3 { + false + return + echo one +} +if f3; then echo true; else echo false; fi + +function f4 { + true + return 1; + echo one +} +if f4; then echo true; else echo false; fi + +function f5 { + false + return 0; + echo one +} +if f5; then echo true; else echo false; fi + +function f6 { + echo one + if true; then + echo two + return 0 + else + echo three + return 1 + fi + echo four +} +if f6; then echo true; else echo false; fi + +function f7 { + if return 1; then + echo one + else + echo no + fi +} +if f7; then echo true; else echo false; fi + +function f8 { + echo one + for v in 1 2 3 4 5; do + echo $v + if test $v = 3; then return 1; fi + done + echo two +} +if f8; then echo true; else echo false; fi + +function f9 { + x=1 + echo one + until test x = 11111111; do + echo $x + x="1$x" + if test $x = 1111; then return 0; fi + done + echo two +} +if f9; then echo true; else echo false; fi + +function f10 { + echo one + while return 0; do + echo two + done + echo three +} +if f10; then echo true; else echo false; fi + +function f11 { + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 +} +if f11; then echo true; else echo false; fi + +function f12 { + echo one + f11 + return 1 + echo two +} +if f12; then echo true; else echo false; fi + +function f13 { + echo one + f12 + echo two + return 0 +} +if f13; then echo true; else echo false; fi From 78780e7005c687d35d9a4a0ba09059520a1ecff6 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 3 Sep 2010 20:53:38 +0530 Subject: [PATCH 14/19] 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 15/19] 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 16/19] 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 17/19] --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; From 49649ac85d1c384597a3834948249fa9aac7ddd5 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Sat, 4 Sep 2010 14:32:59 +0530 Subject: [PATCH 18/19] review comments --- grub-core/script/execute.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index e78a41bb5..2c3772ed8 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -99,7 +99,7 @@ grub_script_return (grub_command_t cmd __attribute__((unused)), unsigned long n; if (! scope || argc > 1) - return GRUB_ERR_BAD_ARGUMENT; + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in function scope"); if (argc == 0) { @@ -109,10 +109,10 @@ grub_script_return (grub_command_t cmd __attribute__((unused)), n = grub_strtoul (argv[0], &p, 10); if (*p != '\0') - return GRUB_ERR_BAD_ARGUMENT; + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad argument"); function_return = 1; - return n; + return n ? grub_error (GRUB_ERR_TEST_FAILURE, "false") : GRUB_ERR_NONE; } static int From 3759a35f757924867450ec3c8ffca6e64cd9b7c5 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Sat, 4 Sep 2010 18:28:42 +0200 Subject: [PATCH 19/19] * include/grub/file.h (grub_file): New member not_easly_seekable. (grub_file_seekable): New inline function. * grub-core/io/gzio.c (test_header): Don't test end magic if file isn't easily seekable. (grub_gzio_open): Set not_easly_seekable. * grub-core/fs/i386/pc/pxe.c (grub_pxefs_open): Set not_easily_seekable. * grub-core/io/bufio.c (grub_bufio_open): Propagate not_easily_seekable. --- ChangeLog | 10 ++++++++++ grub-core/fs/i386/pc/pxe.c | 1 + grub-core/io/bufio.c | 1 + grub-core/io/gzio.c | 11 +++++++---- include/grub/file.h | 9 +++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index a155853d9..fee952996 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2010-09-04 Szymon Janc + + * include/grub/file.h (grub_file): New member not_easly_seekable. + (grub_file_seekable): New inline function. + * grub-core/io/gzio.c (test_header): Don't test end magic if file isn't + easily seekable. + (grub_gzio_open): Set not_easly_seekable. + * grub-core/fs/i386/pc/pxe.c (grub_pxefs_open): Set not_easily_seekable. + * grub-core/io/bufio.c (grub_bufio_open): Propagate not_easily_seekable. + 2010-09-04 BVK Chaitanya Support for options to appear multiple times on cmdline. diff --git a/grub-core/fs/i386/pc/pxe.c b/grub-core/fs/i386/pc/pxe.c index 90dfd5067..baaff0ffc 100644 --- a/grub-core/fs/i386/pc/pxe.c +++ b/grub-core/fs/i386/pc/pxe.c @@ -282,6 +282,7 @@ grub_pxefs_open (struct grub_file *file, const char *name) } file->data = data; + file->not_easly_seekable = 1; grub_memcpy (file_int, file, sizeof (struct grub_file)); curr_file = file_int; diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c index 92f29279e..8a72ecd79 100644 --- a/grub-core/io/bufio.c +++ b/grub-core/io/bufio.c @@ -74,6 +74,7 @@ grub_bufio_open (grub_file_t io, int size) file->data = bufio; file->read_hook = 0; file->fs = &grub_bufio_fs; + file->not_easly_seekable = io->not_easly_seekable; return file; } diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c index 9bf609105..0545e32bd 100644 --- a/grub-core/io/gzio.c +++ b/grub-core/io/gzio.c @@ -214,12 +214,14 @@ test_header (grub_file_t file) grub_file_seek (gzio->file, grub_file_size (gzio->file) - 4); - if (grub_file_read (gzio->file, &orig_len, 4) != 4) + if (grub_file_seekable (gzio->file)) { - grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported gzip format"); - return 0; + if (grub_file_read (gzio->file, &orig_len, 4) != 4) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported gzip format"); + return 0; + } } - /* FIXME: this does not handle files whose original size is over 4GB. But how can we know the real original size? */ file->size = grub_le_to_cpu32 (orig_len); @@ -1135,6 +1137,7 @@ grub_gzio_open (grub_file_t io, int transparent) file->data = gzio; file->read_hook = 0; file->fs = &grub_gzio_fs; + file->not_easly_seekable = 1; if (! test_header (file)) { diff --git a/include/grub/file.h b/include/grub/file.h index 2aacf936f..05c9907d5 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -39,6 +39,9 @@ struct grub_file /* The file size. */ grub_off_t size; + /* If file is not easly seekable. Should be set by underlying layer. */ + int not_easly_seekable; + /* Filesystem-specific data. */ void *data; @@ -69,4 +72,10 @@ grub_file_tell (const grub_file_t file) return file->offset; } +static inline int +grub_file_seekable (const grub_file_t file) +{ + return !file->not_easly_seekable; +} + #endif /* ! GRUB_FILE_HEADER */