From 0993355a68b5e954c26184a4fb19310c15eef701 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 29 Apr 2010 18:10:22 +0530 Subject: [PATCH 01/34] nested recording support --- include/grub/script_sh.h | 4 +-- script/lexer.c | 68 +++++++++++++++++----------------------- script/parser.y | 11 ++++--- 3 files changed, 37 insertions(+), 46 deletions(-) diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index b55b6a806..17b1c5a5a 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -282,8 +282,8 @@ struct grub_lexer_param *grub_script_lexer_init (struct grub_parser_param *parse void grub_script_lexer_fini (struct grub_lexer_param *); void grub_script_lexer_ref (struct grub_lexer_param *); void grub_script_lexer_deref (struct grub_lexer_param *); -void grub_script_lexer_record_start (struct grub_parser_param *); -char *grub_script_lexer_record_stop (struct grub_parser_param *); +unsigned grub_script_lexer_record_start (struct grub_parser_param *); +char *grub_script_lexer_record_stop (struct grub_parser_param *, unsigned); int grub_script_lexer_yywrap (struct grub_parser_param *); void grub_script_lexer_record (struct grub_parser_param *, char *); diff --git a/script/lexer.c b/script/lexer.c index 42a570348..73adf627f 100644 --- a/script/lexer.c +++ b/script/lexer.c @@ -38,68 +38,57 @@ grub_script_lexer_deref (struct grub_lexer_param *state) } /* Start recording all characters passing through the lexer. */ -void +unsigned grub_script_lexer_record_start (struct grub_parser_param *parser) { struct grub_lexer_param *lexer = parser->lexerstate; - lexer->record = 1; - lexer->recordpos = 0; - if (lexer->recording) /* reuse last record */ - return; + lexer->record++; + if (lexer->recording) + return lexer->recordpos; + lexer->recordpos = 0; lexer->recordlen = GRUB_LEXER_INITIAL_RECORD_SIZE; lexer->recording = grub_malloc (lexer->recordlen); if (!lexer->recording) { grub_script_yyerror (parser, 0); - lexer->record = 0; lexer->recordlen = 0; } + return lexer->recordpos; } char * -grub_script_lexer_record_stop (struct grub_parser_param *parser) +grub_script_lexer_record_stop (struct grub_parser_param *parser, unsigned offset) { - char *ptr; + int count; char *result; struct grub_lexer_param *lexer = parser->lexerstate; - auto char *compact (char *start, char *end); - char *compact (char *start, char *end) - { - /* Delete '{' and '}' characters and whitespaces. */ - while (*start && grub_isspace (*start)) start++; - if (*start == '{') start++; - while (*start && grub_isspace (*start)) start++; - - while (*end && grub_isspace (*end)) end--; - if (*end == '}') end--; - while (*end && grub_isspace (*end)) end--; - end[1] = '\0'; - - return start; - } - - if (!lexer->record || !lexer->recording) + if (!lexer->record) return 0; - /* XXX This is not necessary in BASH. */ + lexer->record--; + if (!lexer->recording) + return 0; - ptr = compact (lexer->recording, lexer->recording + lexer->recordpos - 1); - lexer->record = 0; - lexer->recordpos = 0; - - /* This memory would be freed by, grub_script_free. */ - result = grub_script_malloc (parser, grub_strlen (ptr) + 1); - if (result) - grub_strcpy (result, ptr); + count = lexer->recordpos - offset; + result = grub_script_malloc (parser, count + 1); + if (result) { + grub_strncpy (result, lexer->recording + offset, count); + result[count] = '\0'; + } + if (lexer->record == 0) + { + grub_free (lexer->recording); + lexer->recording = 0; + lexer->recordlen = 0; + lexer->recordpos = 0; + } return result; } -#define MAX(a,b) ((a) < (b) ? (b) : (a)) - /* Record STR if input recording is enabled. */ void grub_script_lexer_record (struct grub_parser_param *parser, char *str) @@ -108,21 +97,20 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str) char *old; struct grub_lexer_param *lexer = parser->lexerstate; - if (!lexer->record) + if (!lexer->record || !lexer->recording) return; len = grub_strlen (str); if (lexer->recordpos + len + 1 > lexer->recordlen) { old = lexer->recording; - lexer->recordlen = MAX (len, lexer->recordlen) * 2; + lexer->recordlen = grub_max (len, lexer->recordlen) * 2; lexer->recording = grub_realloc (lexer->recording, lexer->recordlen); if (!lexer->recording) { grub_free (old); - lexer->record = 0; lexer->recordpos = 0; - lexer->recordlen /= 2; + lexer->recordlen = 0; grub_script_yyerror (parser, 0); return; } diff --git a/script/parser.y b/script/parser.y index b5815ea8d..e5de35cf4 100644 --- a/script/parser.y +++ b/script/parser.y @@ -33,6 +33,7 @@ struct grub_script_arglist *arglist; struct grub_script_arg *arg; char *string; + unsigned offset; } %token GRUB_PARSER_TOKEN_BAD @@ -217,14 +218,16 @@ menuentry: "menuentry" } arguments1 { - grub_script_lexer_record_start (state); + $$ = grub_script_lexer_record_start (state); } delimiters0 "{" commands1 delimiters1 "}" { - char *menu_entry; - menu_entry = grub_script_lexer_record_stop (state); + 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, menu_entry, 0); + $$ = grub_script_create_cmdmenu (state, $3, def, 0); } ; From 19dd394f56733b6beecf560b82984c293522455b Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 30 Apr 2010 12:09:31 +0530 Subject: [PATCH 02/34] block argument support --- include/grub/script_sh.h | 6 ++++- script/execute.c | 1 + script/parser.y | 50 ++++++++++++++++++++++++++++++++++++++-- script/yylex.l | 2 +- 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 17b1c5a5a..e1bf6f22e 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -49,7 +49,8 @@ typedef enum GRUB_SCRIPT_ARG_TYPE_TEXT, GRUB_SCRIPT_ARG_TYPE_DQVAR, GRUB_SCRIPT_ARG_TYPE_DQSTR, - GRUB_SCRIPT_ARG_TYPE_SQSTR + GRUB_SCRIPT_ARG_TYPE_SQSTR, + GRUB_SCRIPT_ARG_TYPE_BLOCK } grub_script_arg_type_t; /* A part of an argument. */ @@ -59,6 +60,9 @@ struct grub_script_arg char *str; + /* Parsed block argument. */ + struct grub_script_cmd *block; + /* Next argument part. */ struct grub_script_arg *next; }; diff --git a/script/execute.c b/script/execute.c index 40f161267..31fce554c 100644 --- a/script/execute.c +++ b/script/execute.c @@ -152,6 +152,7 @@ grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *c } break; + case GRUB_SCRIPT_ARG_TYPE_BLOCK: case GRUB_SCRIPT_ARG_TYPE_TEXT: if (grub_strlen (arg->str) > 0) { diff --git a/script/parser.y b/script/parser.y index e5de35cf4..9d256a153 100644 --- a/script/parser.y +++ b/script/parser.y @@ -74,7 +74,7 @@ %token GRUB_PARSER_TOKEN_NAME "name" %token GRUB_PARSER_TOKEN_WORD "word" -%type word argument arguments0 arguments1 +%type word argument block parameters0 parameters1 arguments0 arguments1 %type script_init script %type grubcmd ifclause ifcmd forcmd whilecmd untilcmd @@ -147,6 +147,27 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } | word { $$ = $1; } ; +block: "{" + { + grub_script_lexer_ref (state->lexerstate); + $$ = grub_script_lexer_record_start (state); + } + commands1 delimiters0 "}" + { + char *p; + struct grub_script_arg *arg; + + grub_script_lexer_deref (state->lexerstate); + if (p = grub_script_lexer_record_stop (state, $2)) + *grub_strrchr (p, '}') = '\0'; + + if (arg = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p)) + arg->block = $3; + + $$ = grub_script_add_arglist (state, 0, arg); + } +; + arguments0: /* Empty */ { $$ = 0; } | arguments1 { $$ = $1; } ; @@ -162,7 +183,32 @@ arguments1: argument arguments0 } ; -grubcmd: word arguments0 +parameters1: argument parameters0 + { + if ($1 && $2) + { + $1->next = $2; + $1->argcount += $2->argcount; + $2->argcount = 0; + } + $$ = $1; + } + | block parameters0 + { + if ($1 && $2) + { + $1->next = $2; + $1->argcount += $2->argcount; + $2->argcount = 0; + } + $$ = $1; + } +; +parameters0: /* Empty */ { $$ = 0; } + | parameters1 { $$ = $1; } +; + +grubcmd: word parameters0 { if ($1 && $2) { $1->next = $2; diff --git a/script/yylex.l b/script/yylex.l index 29aa5c2e3..585f818cb 100644 --- a/script/yylex.l +++ b/script/yylex.l @@ -114,7 +114,7 @@ typedef size_t yy_size_t; BLANK [ \t] COMMENT ^[ \t]*#.*$ -CHAR [^|&$;<> \t\n\'\"\\] +CHAR [^{}|&$;<> \t\n\'\"\\] DIGITS [[:digit:]]+ NAME [[:alpha:]_][[:alnum:][:digit:]_]* From a8a145eb2fa1656dfbd92da3ea36af05544c206f Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 5 May 2010 14:05:06 +0530 Subject: [PATCH 03/34] simplify cmdblock with cmdlist --- include/grub/script_sh.h | 19 ++++------------- script/execute.c | 6 +++--- script/parser.y | 10 +++------ script/script.c | 46 +++++++++++++++++----------------------- util/grub-script-check.c | 2 +- 5 files changed, 31 insertions(+), 52 deletions(-) diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index b55b6a806..53f4f13bb 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -82,15 +82,6 @@ struct grub_script_cmdline struct grub_script_arglist *arglist; }; -/* A block of commands, this can be used to group commands. */ -struct grub_script_cmdblock -{ - struct grub_script_cmd cmd; - - /* A chain of commands. */ - struct grub_script_cmd *cmdlist; -}; - /* An if statement. */ struct grub_script_cmdif { @@ -234,8 +225,6 @@ grub_script_add_arglist (struct grub_parser_param *state, struct grub_script_cmd * grub_script_create_cmdline (struct grub_parser_param *state, struct grub_script_arglist *arglist); -struct grub_script_cmd * -grub_script_create_cmdblock (struct grub_parser_param *state); struct grub_script_cmd * grub_script_create_cmdif (struct grub_parser_param *state, @@ -262,9 +251,9 @@ grub_script_create_cmdmenu (struct grub_parser_param *state, int options); struct grub_script_cmd * -grub_script_add_cmd (struct grub_parser_param *state, - struct grub_script_cmdblock *cmdblock, - struct grub_script_cmd *cmd); +grub_script_append_cmd (struct grub_parser_param *state, + struct grub_script_cmd *list, + struct grub_script_cmd *last); struct grub_script_arg * grub_script_arg_add (struct grub_parser_param *state, struct grub_script_arg *arg, @@ -301,7 +290,7 @@ void grub_script_yyerror (struct grub_parser_param *, char const *); /* Commands to execute, don't use these directly. */ grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd); -grub_err_t grub_script_execute_cmdblock (struct grub_script_cmd *cmd); +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); diff --git a/script/execute.c b/script/execute.c index 40f161267..e10558b4d 100644 --- a/script/execute.c +++ b/script/execute.c @@ -269,13 +269,13 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) /* Execute a block of one or more commands. */ grub_err_t -grub_script_execute_cmdblock (struct grub_script_cmd *cmd) +grub_script_execute_cmdlist (struct grub_script_cmd *list) { int ret = 0; - struct grub_script_cmdblock *cmdblock = (struct grub_script_cmdblock *) cmd; + struct grub_script_cmd *cmd; /* Loop over every command and execute it. */ - for (cmd = cmdblock->cmdlist; cmd; cmd = cmd->next) + for (cmd = list->next; cmd; cmd = cmd->next) ret = grub_script_execute_cmd (cmd); return ret; diff --git a/script/parser.y b/script/parser.y index b5815ea8d..cc08af37a 100644 --- a/script/parser.y +++ b/script/parser.y @@ -96,9 +96,7 @@ script: newlines0 } | script statement delimiter newlines0 { - struct grub_script_cmdblock *cmdblock; - cmdblock = (struct grub_script_cmdblock *) $1; - $$ = grub_script_add_cmd (state, cmdblock, $2); + $$ = grub_script_append_cmd (state, $1, $2); } | error { @@ -183,13 +181,11 @@ command: grubcmd { $$ = $1; } /* A list of commands. */ commands1: newlines0 command { - $$ = grub_script_add_cmd (state, 0, $2); + $$ = grub_script_append_cmd (state, 0, $2); } | commands1 delimiters1 command { - struct grub_script_cmdblock *cmdblock; - cmdblock = (struct grub_script_cmdblock *) $1; - $$ = grub_script_add_cmd (state, cmdblock, $3); + $$ = grub_script_append_cmd (state, $1, $3); } ; diff --git a/script/script.c b/script/script.c index 4c87d9491..9cee40dcb 100644 --- a/script/script.c +++ b/script/script.c @@ -291,46 +291,40 @@ grub_script_create_cmdmenu (struct grub_parser_param *state, return (struct grub_script_cmd *) cmd; } -/* Create a block of commands. CMD contains the command that should - be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new - cmdblock will be created. */ +/* 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. */ struct grub_script_cmd * -grub_script_add_cmd (struct grub_parser_param *state, - struct grub_script_cmdblock *cmdblock, - struct grub_script_cmd *cmd) +grub_script_append_cmd (struct grub_parser_param *state, + struct grub_script_cmd *list, + struct grub_script_cmd *last) { struct grub_script_cmd *ptr; - grub_dprintf ("scripting", "cmdblock\n"); + grub_dprintf ("scripting", "append command\n"); - if (!cmd) - return (struct grub_script_cmd *) cmdblock; + if (! last) + return list; - if (!cmdblock) + if (! list) { - cmdblock = grub_script_malloc (state, sizeof (*cmdblock)); - if (!cmdblock) + list = grub_script_malloc (state, sizeof (*list)); + if (! list) return 0; - cmdblock->cmd.exec = grub_script_execute_cmdblock; - cmdblock->cmd.next = 0; - cmdblock->cmdlist = cmd; - cmd->next = 0; + list->exec = grub_script_execute_cmdlist; + list->next = last; } else { - if (!cmdblock->cmdlist) - cmdblock->cmdlist = cmd; - else - { - ptr = cmdblock->cmdlist; - while (ptr->next) - ptr = ptr->next; - ptr->next = cmd; - } + ptr = list; + while (ptr->next) + ptr = ptr->next; + + ptr->next = last; } - return (struct grub_script_cmd *) cmdblock; + return list; } diff --git a/util/grub-script-check.c b/util/grub-script-check.c index dc732aa01..3b7ab295d 100644 --- a/util/grub-script-check.c +++ b/util/grub-script-check.c @@ -70,7 +70,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd __attribute__ ((unused) } grub_err_t -grub_script_execute_cmdblock (struct grub_script_cmd *cmd __attribute__ ((unused))) +grub_script_execute_cmdlist (struct grub_script_cmd *cmd __attribute__ ((unused))) { return 0; } From 342bf06e583bb768060d52783272e0e91abc10e3 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 5 May 2010 14:47:50 +0530 Subject: [PATCH 04/34] function parameters support --- conf/tests.rmk | 4 ++ include/grub/script_sh.h | 13 +++++- script/execute.c | 75 +++++++++++++++++++++++++++++++--- script/function.c | 9 ---- script/yylex.l | 7 ++-- tests/grub_script_functions.in | 63 ++++++++++++++++++++++++++++ 6 files changed, 151 insertions(+), 20 deletions(-) create mode 100644 tests/grub_script_functions.in diff --git a/conf/tests.rmk b/conf/tests.rmk index 9af2f8f86..9144e5528 100644 --- a/conf/tests.rmk +++ b/conf/tests.rmk @@ -71,6 +71,9 @@ grub_script_dollar_SOURCES = tests/grub_script_dollar.in check_SCRIPTS += grub_script_comments grub_script_comments_SOURCES = tests/grub_script_comments.in +check_SCRIPTS += grub_script_functions +grub_script_functions_SOURCES = tests/grub_script_functions.in + # List of tests to execute on "make check" # SCRIPTED_TESTS = example_scripted_test # SCRIPTED_TESTS += example_grub_script_test @@ -87,6 +90,7 @@ SCRIPTED_TESTS += grub_script_blanklines SCRIPTED_TESTS += grub_script_final_semicolon SCRIPTED_TESTS += grub_script_dollar SCRIPTED_TESTS += grub_script_comments +SCRIPTED_TESTS += grub_script_functions # 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 53f4f13bb..730aa3005 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -73,6 +73,15 @@ struct grub_script_arglist int argcount; }; +/* Scope for grub script constructs. */ +struct grub_script_scope +{ + struct grub_script_scope *next; + + char **args; + unsigned int argc; +}; + /* A single command line. */ struct grub_script_cmdline { @@ -329,8 +338,8 @@ grub_script_function_t grub_script_function_create (struct grub_script_arg *func void grub_script_function_remove (const char *name); grub_script_function_t grub_script_function_find (char *functionname); int grub_script_function_iterate (int (*iterate) (grub_script_function_t)); -int grub_script_function_call (grub_script_function_t func, - int argc, char **args); +grub_err_t grub_script_function_call (grub_script_function_t func, + int argc, char **args); char ** grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *count); diff --git a/script/execute.c b/script/execute.c index e10558b4d..571b6785b 100644 --- a/script/execute.c +++ b/script/execute.c @@ -30,6 +30,52 @@ is sizeof (int) * 3, and one extra for a possible -ve sign. */ #define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1) +static struct grub_script_scope *scope = 0; + +static char * +grub_script_env_get (const char *name) +{ + char *p = 0; + unsigned long num = 0; + + if (! scope) + return grub_env_get (name); + + if (grub_isdigit (name[0])) + { + num = grub_strtoul (name, &p, 10); + if (p && *p == '\0') + { + if (num == 0) + return 0; /* XXX no file name, for now. */ + + return (num > scope->argc ? 0 : scope->args[num - 1]); + } + else + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "bad variabe name substitution"); + return 0; + } + } + else if (grub_strcmp (name, "#") == 0) + { + static char buf[32]; /* Rewritten everytime. */ + grub_snprintf (buf, sizeof (buf), "%u", scope->argc); + return buf; + } + else + return grub_env_get (name); +} + +static grub_err_t +grub_script_env_set (const char *name, const char *val) +{ + if (grub_isdigit (name[0]) || grub_strcmp (name, "#") == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad variable name"); + + return grub_env_set (name, val); +} + static grub_err_t grub_script_execute_cmd (struct grub_script_cmd *cmd) { @@ -143,7 +189,7 @@ grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *c switch (arg->type) { case GRUB_SCRIPT_ARG_TYPE_VAR: - value = grub_env_get (arg->str); + value = grub_script_env_get (arg->str); while (value && *value && (ptr = move_to_next(&value))) { empty = 0; @@ -168,7 +214,7 @@ grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *c case GRUB_SCRIPT_ARG_TYPE_DQVAR: empty = 0; - append (grub_env_get (arg->str), 0); + append (grub_script_env_get (arg->str), 0); break; } arg = arg->next; @@ -191,6 +237,23 @@ grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *c return argv; } +/* Execute a function call. */ +grub_err_t +grub_script_function_call (grub_script_function_t func, int argc, char **args) +{ + grub_err_t ret = 0; + struct grub_script_scope new_scope; + + new_scope.argc = argc; + new_scope.args = args; + grub_list_push (GRUB_AS_LIST_P (&scope), GRUB_AS_LIST (&new_scope)); + + ret = grub_script_execute (func->func); + + grub_list_pop (GRUB_AS_LIST_P (&scope)); + return ret; +} + /* Execute a single command line. */ grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd) @@ -232,12 +295,12 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) /* Create two strings and set the variable. */ *eq = '\0'; eq++; - grub_env_set (assign, eq); + grub_script_env_set (assign, eq); } grub_free (assign); grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno); - grub_env_set ("?", errnobuf); + grub_script_env_set ("?", errnobuf); grub_print_error (); @@ -291,7 +354,7 @@ grub_script_execute_cmdif (struct grub_script_cmd *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 ("?"); + result = grub_script_env_get ("?"); grub_errno = GRUB_ERR_NONE; @@ -320,7 +383,7 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) result = 0; for (i = 0; i < argcount; i++) { - grub_env_set (cmdfor->name->str, args[i]); + grub_script_env_set (cmdfor->name->str, args[i]); result = grub_script_execute_cmd (cmdfor->list); grub_free (args[i]); } diff --git a/script/function.c b/script/function.c index ded470c4e..82c753bcd 100644 --- a/script/function.c +++ b/script/function.c @@ -115,12 +115,3 @@ grub_script_function_iterate (int (*iterate) (grub_script_function_t)) return 0; } - -int -grub_script_function_call (grub_script_function_t func, - int argc __attribute__((unused)), - char **args __attribute__((unused))) -{ - /* XXX: Arguments are not supported yet. */ - return grub_script_execute (func->func); -} diff --git a/script/yylex.l b/script/yylex.l index 7d4ea9e4e..f563ac30d 100644 --- a/script/yylex.l +++ b/script/yylex.l @@ -119,7 +119,8 @@ DIGITS [[:digit:]]+ NAME [[:alpha:]_][[:alnum:][:digit:]_]* ESC \\. -VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|$\?|$\{\?\} +SPECIAL \?|\# +VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\} DQSTR \"([^\\\"]|{ESC})*\" SQSTR \'[^\']*\' WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ @@ -221,7 +222,7 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ } { - \? | + {SPECIAL} | {DIGITS} | {NAME} { COPY (yytext, yyleng); @@ -231,7 +232,7 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ else ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR); } - \{\?\} | + \{{SPECIAL}\} | \{{DIGITS}\} | \{{NAME}\} { yytext[yyleng - 1] = '\0'; diff --git a/tests/grub_script_functions.in b/tests/grub_script_functions.in new file mode 100644 index 000000000..41af87474 --- /dev/null +++ b/tests/grub_script_functions.in @@ -0,0 +1,63 @@ +#! @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 . + +echo parameter count +function fcount { + echo "$#" +} + +fcount +fcount a +fcount a b + +echo parameter count, with nesting +function ffcount { + echo "$#" + fcount + fcount a + fcount a b +} + +ffcount +ffcount 1 +ffcount 1 2 + +echo parameters +function fparam { + echo 1 $1 + echo 2 $2 + echo 3 $3 +} + +fparam +fparam a +fparam a b + +echo parameters, with nesting +function ffparam { + echo 1 $1 + echo 2 $2 + echo 3 $3 + fparam + fparam a + fparam a b +} + +ffparam +ffparam 1 +ffparam 1 2 From 01b0317f7b70fc6fe7fe73f7a36c2e4d26621255 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Tue, 11 May 2010 10:52:10 +0530 Subject: [PATCH 05/34] simplified nesting dynamic scopes --- include/grub/script_sh.h | 9 --------- script/execute.c | 13 +++++++++++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 730aa3005..e1edbec15 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -73,15 +73,6 @@ struct grub_script_arglist int argcount; }; -/* Scope for grub script constructs. */ -struct grub_script_scope -{ - struct grub_script_scope *next; - - char **args; - unsigned int argc; -}; - /* A single command line. */ struct grub_script_cmdline { diff --git a/script/execute.c b/script/execute.c index 571b6785b..573dab4cb 100644 --- a/script/execute.c +++ b/script/execute.c @@ -30,6 +30,12 @@ is sizeof (int) * 3, and one extra for a possible -ve sign. */ #define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1) +/* Scope for grub script functions. */ +struct grub_script_scope +{ + char **args; + unsigned int argc; +}; static struct grub_script_scope *scope = 0; static char * @@ -242,15 +248,18 @@ grub_err_t grub_script_function_call (grub_script_function_t func, int argc, char **args) { grub_err_t ret = 0; + struct grub_script_scope *old_scope; struct grub_script_scope new_scope; new_scope.argc = argc; new_scope.args = args; - grub_list_push (GRUB_AS_LIST_P (&scope), GRUB_AS_LIST (&new_scope)); + + old_scope = scope; + scope = &new_scope; ret = grub_script_execute (func->func); - grub_list_pop (GRUB_AS_LIST_P (&scope)); + scope = old_scope; return ret; } From a0167e8bdf046724f3eb227b1c4ef9c3abe6f0f5 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 12 May 2010 10:19:12 +0530 Subject: [PATCH 06/34] rewrote arglist to argv conversion and added $@, $* support --- conf/common.rmk | 2 +- include/grub/script_sh.h | 12 ++ script/argv.c | 128 ++++++++++++ script/execute.c | 362 +++++++++++++++------------------ script/yylex.l | 2 +- tests/grub_script_echo1.in | 27 +++ tests/grub_script_functions.in | 70 ++++++- tests/grub_script_vars1.in | 2 +- 8 files changed, 392 insertions(+), 213 deletions(-) create mode 100644 script/argv.c diff --git a/conf/common.rmk b/conf/common.rmk index 4b39e9b71..54146904b 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -660,7 +660,7 @@ normal_mod_CFLAGS = $(COMMON_CFLAGS) normal_mod_LDFLAGS = $(COMMON_LDFLAGS) # For sh.mod. -sh_mod_SOURCES = script/main.c script/script.c script/execute.c \ +sh_mod_SOURCES = script/main.c script/script.c script/argv.c script/execute.c \ script/function.c script/lexer.c grub_script.tab.c grub_script.yy.c sh_mod_CFLAGS = $(COMMON_CFLAGS) $(POSIX_CFLAGS) -Wno-error sh_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index e1edbec15..5455fc763 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -63,6 +63,13 @@ struct grub_script_arg struct grub_script_arg *next; }; +/* An argument vector. */ +struct grub_script_argv +{ + int argc; + char **args; +}; + /* A complete argument. It consists of a list of one or more `struct grub_script_arg's. */ struct grub_script_arglist @@ -215,6 +222,11 @@ struct grub_parser_param struct grub_lexer_param *lexerstate; }; +void grub_script_argv_free (struct grub_script_argv *argv); +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); + struct grub_script_arglist * grub_script_create_arglist (struct grub_parser_param *state); diff --git a/script/argv.c b/script/argv.c new file mode 100644 index 000000000..1ac81f4b8 --- /dev/null +++ b/script/argv.c @@ -0,0 +1,128 @@ +/* argv.c - methods for constructing argument vector */ +/* + * 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 + +#define ARG_ALLOCATION_UNIT (32 * sizeof (char)) +#define ARGV_ALLOCATION_UNIT (8 * sizeof (void*)) + +void +grub_script_argv_free (struct grub_script_argv *argv) +{ + int i; + + if (argv->args) + { + for (i = 0; i < argv->argc; i++) + grub_free (argv->args[i]); + + grub_free (argv->args); + } + + argv->argc = 0; + argv->args = 0; +} + +/* Prepare for next argc. */ +int +grub_script_argv_next (struct grub_script_argv *argv) +{ + char **p = argv->args; + + if (argv->argc == 0) + { + p = grub_malloc (ALIGN_UP (2 * sizeof (char *), ARG_ALLOCATION_UNIT)); + if (! p) + return 1; + + argv->argc = 1; + argv->args = p; + argv->args[0] = 0; + argv->args[1] = 0; + return 0; + } + + if (! argv->args[argv->argc - 1]) + return 0; + + p = grub_realloc (p, ALIGN_UP ((argv->argc + 1) * sizeof (char *), + ARG_ALLOCATION_UNIT)); + if (! p) + return 1; + + argv->argc++; + argv->args = p; + argv->args[argv->argc] = 0; + return 0; +} + +/* Append `s' to the last argument. */ +int +grub_script_argv_append (struct grub_script_argv *argv, const char *s) +{ + int a, b; + char *p = argv->args[argv->argc - 1]; + + if (! s) + return 0; + + a = p ? grub_strlen (p) : 0; + b = grub_strlen (s); + + p = grub_realloc (p, ALIGN_UP ((a + b + 1) * sizeof (char), + ARG_ALLOCATION_UNIT)); + if (! p) + return 1; + + grub_strcpy (p + a, s); + argv->args[argv->argc - 1] = p; + return 0; +} + +/* Split `s' and append words as multiple arguments. */ +int +grub_script_argv_split_append (struct grub_script_argv *argv, char *s) +{ + char ch; + char *p; + int errors = 0; + + if (! s) + return 0; + + while (! errors && *s) + { + p = s; + while (*s && ! grub_isspace (*s)) + s++; + + ch = *s; + *s = '\0'; + errors += grub_script_argv_append (argv, p); + *s = ch; + + while (*s && grub_isspace (*s)) + s++; + + if (*s) + errors += grub_script_argv_next (argv); + } + return errors; +} diff --git a/script/execute.c b/script/execute.c index 573dab4cb..905f457d3 100644 --- a/script/execute.c +++ b/script/execute.c @@ -33,55 +33,172 @@ /* Scope for grub script functions. */ struct grub_script_scope { - char **args; - unsigned int argc; + struct grub_script_argv argv; }; static struct grub_script_scope *scope = 0; -static char * -grub_script_env_get (const char *name) +static int +grub_env_special (const char *name) { - char *p = 0; - unsigned long num = 0; + if (grub_isdigit (name[0]) || + grub_strcmp (name, "#") == 0 || + grub_strcmp (name, "*") == 0 || + grub_strcmp (name, "@") == 0) + return 1; + return 0; +} - if (! scope) - return grub_env_get (name); +static char ** +grub_script_env_get (const char *name, grub_script_arg_type_t type) +{ + int errors = 0; + struct grub_script_argv result = { 0, 0 }; - if (grub_isdigit (name[0])) + errors += grub_script_argv_next (&result); + if (! grub_env_special (name)) { - num = grub_strtoul (name, &p, 10); - if (p && *p == '\0') + char *v = grub_env_get (name); + if (v && v[0]) { - if (num == 0) - return 0; /* XXX no file name, for now. */ - - return (num > scope->argc ? 0 : scope->args[num - 1]); - } - else - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "bad variabe name substitution"); - return 0; + if (type == GRUB_SCRIPT_ARG_TYPE_VAR) + errors += grub_script_argv_split_append (&result, v); + else + errors += grub_script_argv_append (&result, v); } } + else if (! scope) + errors += grub_script_argv_append (&result, 0); + else if (grub_strcmp (name, "#") == 0) { - static char buf[32]; /* Rewritten everytime. */ - grub_snprintf (buf, sizeof (buf), "%u", scope->argc); - return buf; + char buffer[ERRNO_DIGITS_MAX + 1]; + grub_snprintf (buffer, sizeof (buffer), "%u", scope->argv.argc); + errors += grub_script_argv_append (&result, buffer); + } + else if (grub_strcmp (name, "*") == 0) + { + int i; + + for (i = 0; ! errors && i < scope->argv.argc; i++) + if (type == GRUB_SCRIPT_ARG_TYPE_VAR) + { + if (i != 0) + errors += grub_script_argv_next (&result); + errors += grub_script_argv_split_append (&result, + scope->argv.args[i]); + } + else + { + if (i != 0) + errors += grub_script_argv_append (&result, " "); + errors += grub_script_argv_append (&result, + scope->argv.args[i]); + } + } + else if (grub_strcmp (name, "@") == 0) + { + int i; + + for (i = 0; ! errors && i < scope->argv.argc; i++) + { + if (i != 0) + errors += grub_script_argv_next (&result); + + if (type == GRUB_SCRIPT_ARG_TYPE_VAR) + errors += grub_script_argv_split_append (&result, + scope->argv.args[i]); + else + errors += grub_script_argv_append (&result, + scope->argv.args[i]); + } } else - return grub_env_get (name); + { + unsigned long num = grub_strtoul (name, 0, 10); + if (num == 0) + ; /* XXX no file name, for now. */ + + else if (num <= scope->argv.argc) + { + if (type == GRUB_SCRIPT_ARG_TYPE_VAR) + errors += grub_script_argv_split_append (&result, + scope->argv.args[num - 1]); + else + errors += grub_script_argv_append (&result, + scope->argv.args[num - 1]); + } + } + return result.args; } static grub_err_t grub_script_env_set (const char *name, const char *val) { - if (grub_isdigit (name[0]) || grub_strcmp (name, "#") == 0) + if (grub_env_special (name)) return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad variable name"); return grub_env_set (name, val); } +/* Expand arguments in ARGLIST into multiple arguments. */ +static int +grub_script_arglist_to_argv (struct grub_script_arglist *arglist, + struct grub_script_argv *argv) +{ + int i; + int error = 0; + char **values = 0; + struct grub_script_arg *arg = 0; + struct grub_script_argv result = { 0, 0 }; + + for (; error == 0 && arglist && arglist->arg; arglist = arglist->next) + { + error += grub_script_argv_next (&result); + + arg = arglist->arg; + while (arg) + { + if (error) + break; + + switch (arg->type) + { + case GRUB_SCRIPT_ARG_TYPE_VAR: + case GRUB_SCRIPT_ARG_TYPE_DQVAR: + values = grub_script_env_get (arg->str, arg->type); + for (i = 0; values && values[i]; i++) + { + if (i != 0) + error += grub_script_argv_next (&result); + error += grub_script_argv_append (&result, values[i]); + } + grub_free (values); + break; + + case GRUB_SCRIPT_ARG_TYPE_TEXT: + if (grub_strlen (arg->str)) + error += grub_script_argv_append (&result, arg->str); + break; + + case GRUB_SCRIPT_ARG_TYPE_DQSTR: + case GRUB_SCRIPT_ARG_TYPE_SQSTR: + error += grub_script_argv_append (&result, arg->str); + break; + } + arg = arg->next; + } + } + + if (error) + return 1; + + if (! result.args[result.argc - 1]) + result.argc--; + + *argv = result; + return 0; +} + static grub_err_t grub_script_execute_cmd (struct grub_script_cmd *cmd) { @@ -98,151 +215,6 @@ grub_script_execute_cmd (struct grub_script_cmd *cmd) return ret; } -#define ARG_ALLOCATION_UNIT (32 * sizeof (char)) -#define ARGV_ALLOCATION_UNIT (8 * sizeof (void*)) - -/* Expand arguments in ARGLIST into multiple arguments. */ -char ** -grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *count) -{ - int i; - int oom; - int argc; - int empty; - char *ptr; - char **argv; - char *value; - struct grub_script_arg *arg; - - auto void push (char *str); - void push (char *str) - { - char **p; - - if (oom) - return; - - p = grub_realloc (argv, ALIGN_UP (sizeof(char*) * (argc + 1), ARGV_ALLOCATION_UNIT)); - if (!p) - oom = 1; - else - { - p[argc++] = str; - argv = p; - } - } - - auto char* append (const char *str, grub_size_t nchar); - char* append (const char *str, grub_size_t nchar) - { - int len; - int old; - char *p; - - if (oom || !str) - return 0; - - len = nchar ?: grub_strlen (str); - old = argv[argc - 1] ? grub_strlen (argv[argc - 1]) : 0; - p = grub_realloc (argv[argc - 1], ALIGN_UP(old + len + 1, ARG_ALLOCATION_UNIT)); - - if (p) - { - grub_strncpy (p + old, str, len); - p[old + len] = '\0'; - } - else - { - oom = 1; - grub_free (argv[argc - 1]); - } - argv[argc - 1] = p; - return argv[argc - 1]; - } - - /* Move *STR to the begining of next word, but return current word. */ - auto char* move_to_next (char **str); - char* move_to_next (char **str) - { - char *end; - char *start; - - if (oom || !str || !*str) - return 0; - - start = *str; - while (*start && grub_isspace (*start)) start++; - if (*start == '\0') - return 0; - - end = start + 1; - while (*end && !grub_isspace (*end)) end++; - - *str = end; - return start; - } - - oom = 0; - argv = 0; - argc = 0; - push (0); - for (; arglist; arglist = arglist->next) - { - empty = 1; - arg = arglist->arg; - while (arg) - { - switch (arg->type) - { - case GRUB_SCRIPT_ARG_TYPE_VAR: - value = grub_script_env_get (arg->str); - while (value && *value && (ptr = move_to_next(&value))) - { - empty = 0; - append (ptr, value - ptr); - if (*value) push(0); - } - break; - - case GRUB_SCRIPT_ARG_TYPE_TEXT: - if (grub_strlen (arg->str) > 0) - { - empty = 0; - append (arg->str, 0); - } - break; - - case GRUB_SCRIPT_ARG_TYPE_DQSTR: - case GRUB_SCRIPT_ARG_TYPE_SQSTR: - empty = 0; - append (arg->str, 0); - break; - - case GRUB_SCRIPT_ARG_TYPE_DQVAR: - empty = 0; - append (grub_script_env_get (arg->str), 0); - break; - } - arg = arg->next; - } - if (!empty) - push (0); - } - - if (oom) - { - for (i = 0; i < argc; i++) - grub_free (argv[i]); - grub_free (argv); - argv = 0; - } - - if (argv) - *count = argc - 1; - - return argv; -} - /* Execute a function call. */ grub_err_t grub_script_function_call (grub_script_function_t func, int argc, char **args) @@ -251,8 +223,8 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) struct grub_script_scope *old_scope; struct grub_script_scope new_scope; - new_scope.argc = argc; - new_scope.args = args; + new_scope.argv.argc = argc; + new_scope.argv.args = args; old_scope = scope; scope = &new_scope; @@ -268,21 +240,18 @@ grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd) { struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd; - char **args = 0; - int i = 0; grub_command_t grubcmd; grub_err_t ret = 0; - int argcount = 0; grub_script_function_t func = 0; char errnobuf[18]; char *cmdname; + struct grub_script_argv argv = { 0, 0 }; /* Lookup the command. */ - args = grub_script_execute_arglist_to_argv (cmdline->arglist, &argcount); - if (!args) + if (grub_script_arglist_to_argv (cmdline->arglist, &argv)) return grub_errno; - cmdname = args[0]; + cmdname = argv.args[0]; grubcmd = grub_command_find (cmdname); if (! grubcmd) { @@ -319,14 +288,12 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) /* Execute the GRUB command or function. */ if (grubcmd) - ret = (grubcmd->func) (grubcmd, argcount - 1, args + 1); + ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1); else - ret = grub_script_function_call (func, argcount - 1, args + 1); + ret = grub_script_function_call (func, argv.argc - 1, argv.args + 1); /* Free arguments. */ - for (i = 0; i < argcount; i++) - grub_free (args[i]); - grub_free (args); + grub_script_argv_free (&argv); if (grub_errno == GRUB_ERR_TEST_FAILURE) grub_errno = GRUB_ERR_NONE; @@ -363,7 +330,7 @@ grub_script_execute_cmdif (struct grub_script_cmd *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_script_env_get ("?"); + result = grub_env_get ("?"); grub_errno = GRUB_ERR_NONE; @@ -381,23 +348,20 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { int i; int result; - char **args; - int argcount; + struct grub_script_argv argv; struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd; - args = grub_script_execute_arglist_to_argv (cmdfor->words, &argcount); - if (!args) + if (grub_script_arglist_to_argv (cmdfor->words, &argv)) return grub_errno; result = 0; - for (i = 0; i < argcount; i++) + for (i = 0; i < argv.argc; i++) { - grub_script_env_set (cmdfor->name->str, args[i]); + grub_script_env_set (cmdfor->name->str, argv.args[i]); result = grub_script_execute_cmd (cmdfor->list); - grub_free (args[i]); } - grub_free (args); + grub_script_argv_free (&argv); return result; } @@ -426,26 +390,20 @@ grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd) { struct grub_script_cmd_menuentry *cmd_menuentry; - char **args = 0; - int argcount = 0; - int i = 0; + struct grub_script_argv argv = {0, 0}; cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd; if (cmd_menuentry->arglist) { - args = grub_script_execute_arglist_to_argv (cmd_menuentry->arglist, &argcount); - if (!args) + if (grub_script_arglist_to_argv (cmd_menuentry->arglist, &argv)) return grub_errno; } - grub_normal_add_menu_entry (argcount, (const char **) args, + grub_normal_add_menu_entry (argv.argc, (const char **) argv.args, cmd_menuentry->sourcecode); - /* Free arguments. */ - for (i = 0; i < argcount; i++) - grub_free (args[i]); - grub_free (args); + grub_script_argv_free (&argv); return grub_errno; } diff --git a/script/yylex.l b/script/yylex.l index f563ac30d..bfc53a6ff 100644 --- a/script/yylex.l +++ b/script/yylex.l @@ -119,7 +119,7 @@ DIGITS [[:digit:]]+ NAME [[:alpha:]_][[:alnum:][:digit:]_]* ESC \\. -SPECIAL \?|\# +SPECIAL \?|\#|\*|\@ VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\} DQSTR \"([^\\\"]|{ESC})*\" SQSTR \'[^\']*\' diff --git a/tests/grub_script_echo1.in b/tests/grub_script_echo1.in index 048907a76..554dd68ed 100644 --- a/tests/grub_script_echo1.in +++ b/tests/grub_script_echo1.in @@ -16,6 +16,33 @@ # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . +# simple arguments +echo one two three +echo "one two three" +echo 'one two three' + +# empty arguments +echo a "" b +echo a '' b + +echo a $foo b +echo a ${foo} b + +echo a "$foo" b +echo a "${foo}" b + +# multi-part arguments +echo one"two"three +echo one${two}three +echo one"two"$three + +echo one'two'three +echo one${two}three +echo one'two'$three + +echo one'two'three"four"five${six}seven$eight + + foo=bar echo $foo ${foo} echo "$foo" "${foo}" diff --git a/tests/grub_script_functions.in b/tests/grub_script_functions.in index 41af87474..234a1be13 100644 --- a/tests/grub_script_functions.in +++ b/tests/grub_script_functions.in @@ -18,7 +18,7 @@ echo parameter count function fcount { - echo "$#" + echo fcount "$#" } fcount @@ -27,7 +27,7 @@ fcount a b echo parameter count, with nesting function ffcount { - echo "$#" + echo ffcount "$#" fcount fcount a fcount a b @@ -39,9 +39,9 @@ ffcount 1 2 echo parameters function fparam { - echo 1 $1 - echo 2 $2 - echo 3 $3 + echo fparam 1 $1 + echo fparam 2 $2 + echo fparam 3 $3 } fparam @@ -50,9 +50,9 @@ fparam a b echo parameters, with nesting function ffparam { - echo 1 $1 - echo 2 $2 - echo 3 $3 + echo ffparam 1 $1 + echo ffparam 2 $2 + echo ffparam 3 $3 fparam fparam a fparam a b @@ -61,3 +61,57 @@ function ffparam { ffparam ffparam 1 ffparam 1 2 + +echo parameter expansion with specials +function fstar { + for f in $* + do + echo fstar $f + done +} + +fstar +fstar a +fstar a "1 2" +fstar a "1 2" b + +function fdqstar { + for f in "$*" + do + echo fdqstar $f + done +} + +fdqstar +fdqstar a +fdqstar a "1 2" +fdqstar a "1 2" b + +function fat { + for f in $@ + do + echo fat $f + done +} + +fat +fat a +fat a "1 2" +fat a "1 2" b +fat a "1 2" b "c d" +fat a "1 2" b "c d" e + +function fdqat { + for f in "$@" + do + echo fdqat $f + done +} + +# fdqat # this case needs special handling, lets ignore till we really need it. +fdqat a +fdqat a "1 2" +fdqat a "1 2" b +fdqat a "1 2" b "c d" +fdqat a "1 2" b "c d" e + diff --git a/tests/grub_script_vars1.in b/tests/grub_script_vars1.in index 9ff897627..77b3cf298 100644 --- a/tests/grub_script_vars1.in +++ b/tests/grub_script_vars1.in @@ -28,7 +28,7 @@ foo=foo echo "" $foo echo $bar $foo - + bar="" echo $bar $foo From d13f69de73b15e7034c2ab110f3742bafbe2bf79 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 12 May 2010 10:45:22 +0530 Subject: [PATCH 07/34] handle failure case --- script/execute.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/script/execute.c b/script/execute.c index 905f457d3..5200b04a7 100644 --- a/script/execute.c +++ b/script/execute.c @@ -128,6 +128,13 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) scope->argv.args[num - 1]); } } + + if (errors) + { + grub_script_argv_free (&result); + return 0; + } + return result.args; } From 53018ca6c361f6975eaa92aea3777144b7e04b66 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 12 May 2010 13:12:49 +0530 Subject: [PATCH 08/34] minor fix --- script/execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/execute.c b/script/execute.c index 5200b04a7..2040be13c 100644 --- a/script/execute.c +++ b/script/execute.c @@ -285,7 +285,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) grub_free (assign); grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno); - grub_script_env_set ("?", errnobuf); + grub_env_set ("?", errnobuf); grub_print_error (); From 04888e878791894927261c4a8dc34ed44b27b37d Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 12 May 2010 13:53:50 +0530 Subject: [PATCH 09/34] few more testcases added --- tests/grub_script_functions.in | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/grub_script_functions.in b/tests/grub_script_functions.in index 234a1be13..3e69014d6 100644 --- a/tests/grub_script_functions.in +++ b/tests/grub_script_functions.in @@ -68,6 +68,11 @@ function fstar { do echo fstar $f done + + for f in aaa$*bbb + do + echo fstar $f + done } fstar @@ -80,6 +85,16 @@ function fdqstar { do echo fdqstar $f done + + for f in aaa"$*"bbb + do + echo fdqstar $f + done + + for f in "aaa$*bbb" + do + echo fdqstar $f + done } fdqstar @@ -92,6 +107,11 @@ function fat { do echo fat $f done + + for f in aaa$@bbb + do + echo fat $f + done } fat @@ -106,6 +126,16 @@ function fdqat { do echo fdqat $f done + + for f in aaa"$@"bbb + do + echo fdqat $f + done + + for f in "aaa$@bbb" + do + echo fdqat $f + done } # fdqat # this case needs special handling, lets ignore till we really need it. From dada803720619685c1a56bd9c42c108d6d87eece Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 19 May 2010 10:15:48 +0530 Subject: [PATCH 10/34] allocate memory in sizes of two powers --- script/argv.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/script/argv.c b/script/argv.c index 1ac81f4b8..4974178cc 100644 --- a/script/argv.c +++ b/script/argv.c @@ -20,8 +20,23 @@ #include #include -#define ARG_ALLOCATION_UNIT (32 * sizeof (char)) -#define ARGV_ALLOCATION_UNIT (8 * sizeof (void*)) +static unsigned +round_up_exp (unsigned v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + if (sizeof (v) > 4) + v |= v >> 32; + + v++; + v += (v == 0); + + return v; +} void grub_script_argv_free (struct grub_script_argv *argv) @@ -48,7 +63,7 @@ grub_script_argv_next (struct grub_script_argv *argv) if (argv->argc == 0) { - p = grub_malloc (ALIGN_UP (2 * sizeof (char *), ARG_ALLOCATION_UNIT)); + p = grub_malloc (2 * sizeof (char *)); if (! p) return 1; @@ -62,8 +77,7 @@ grub_script_argv_next (struct grub_script_argv *argv) if (! argv->args[argv->argc - 1]) return 0; - p = grub_realloc (p, ALIGN_UP ((argv->argc + 1) * sizeof (char *), - ARG_ALLOCATION_UNIT)); + p = grub_realloc (p, round_up_exp ((argv->argc + 1) * sizeof (char *))); if (! p) return 1; @@ -86,8 +100,7 @@ grub_script_argv_append (struct grub_script_argv *argv, const char *s) a = p ? grub_strlen (p) : 0; b = grub_strlen (s); - p = grub_realloc (p, ALIGN_UP ((a + b + 1) * sizeof (char), - ARG_ALLOCATION_UNIT)); + p = grub_realloc (p, round_up_exp ((a + b + 1) * sizeof (char))); if (! p) return 1; From 0003008a588020db005454a02b5a192b93254e88 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 19 May 2010 10:25:41 +0530 Subject: [PATCH 11/34] memory leak fix in grub_script_execute_cmdline --- include/grub/script_sh.h | 2 +- script/argv.c | 3 ++- script/execute.c | 9 +++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 5455fc763..9199a539e 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -66,7 +66,7 @@ struct grub_script_arg /* An argument vector. */ struct grub_script_argv { - int argc; + unsigned argc; char **args; }; diff --git a/script/argv.c b/script/argv.c index 4974178cc..56274f263 100644 --- a/script/argv.c +++ b/script/argv.c @@ -29,6 +29,7 @@ round_up_exp (unsigned v) v |= v >> 4; v |= v >> 8; v |= v >> 16; + if (sizeof (v) > 4) v |= v >> 32; @@ -41,7 +42,7 @@ round_up_exp (unsigned v) void grub_script_argv_free (struct grub_script_argv *argv) { - int i; + unsigned i; if (argv->args) { diff --git a/script/execute.c b/script/execute.c index 2040be13c..6a755a040 100644 --- a/script/execute.c +++ b/script/execute.c @@ -77,7 +77,7 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else if (grub_strcmp (name, "*") == 0) { - int i; + unsigned i; for (i = 0; ! errors && i < scope->argv.argc; i++) if (type == GRUB_SCRIPT_ARG_TYPE_VAR) @@ -97,7 +97,7 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else if (grub_strcmp (name, "@") == 0) { - int i; + unsigned i; for (i = 0; ! errors && i < scope->argv.argc; i++) { @@ -287,6 +287,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno); grub_env_set ("?", errnobuf); + grub_script_argv_free (&argv); grub_print_error (); return 0; @@ -353,8 +354,8 @@ grub_script_execute_cmdif (struct grub_script_cmd *cmd) grub_err_t grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { - int i; - int result; + unsigned i; + grub_err_t result; struct grub_script_argv argv; struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd; From f532a574a6b4bd9feb6f17fac74ea64e6244a079 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 21 May 2010 15:34:36 +0530 Subject: [PATCH 12/34] write overflow bug fix with cleanup --- script/argv.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/script/argv.c b/script/argv.c index 56274f263..69322779d 100644 --- a/script/argv.c +++ b/script/argv.c @@ -62,28 +62,18 @@ grub_script_argv_next (struct grub_script_argv *argv) { char **p = argv->args; - if (argv->argc == 0) - { - p = grub_malloc (2 * sizeof (char *)); - if (! p) - return 1; - - argv->argc = 1; - argv->args = p; - argv->args[0] = 0; - argv->args[1] = 0; - return 0; - } - - if (! argv->args[argv->argc - 1]) + if (argv->args && argv->args[argv->argc - 1] == 0) return 0; - p = grub_realloc (p, round_up_exp ((argv->argc + 1) * sizeof (char *))); + p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *))); if (! p) return 1; argv->argc++; argv->args = p; + + if (argv->argc == 1) + argv->args[0] = 0; argv->args[argv->argc] = 0; return 0; } From 1702fbc15de595722b8f1c03181ccbaf364a1337 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 21 May 2010 15:43:24 +0530 Subject: [PATCH 13/34] replace error handling with goto --- script/execute.c | 117 +++++++++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 50 deletions(-) diff --git a/script/execute.c b/script/execute.c index 6a755a040..4a3f249b0 100644 --- a/script/execute.c +++ b/script/execute.c @@ -51,65 +51,77 @@ grub_env_special (const char *name) static char ** grub_script_env_get (const char *name, grub_script_arg_type_t type) { - int errors = 0; struct grub_script_argv result = { 0, 0 }; - errors += grub_script_argv_next (&result); + if (grub_script_argv_next (&result)) + goto fail; + if (! grub_env_special (name)) { char *v = grub_env_get (name); if (v && v[0]) { if (type == GRUB_SCRIPT_ARG_TYPE_VAR) - errors += grub_script_argv_split_append (&result, v); + { + if (grub_script_argv_split_append (&result, v)) + goto fail; + } else - errors += grub_script_argv_append (&result, v); + if (grub_script_argv_append (&result, v)) + goto fail; } } else if (! scope) - errors += grub_script_argv_append (&result, 0); - + { + if (grub_script_argv_append (&result, 0)) + goto fail; + } else if (grub_strcmp (name, "#") == 0) { char buffer[ERRNO_DIGITS_MAX + 1]; grub_snprintf (buffer, sizeof (buffer), "%u", scope->argv.argc); - errors += grub_script_argv_append (&result, buffer); + if (grub_script_argv_append (&result, buffer)) + goto fail; } else if (grub_strcmp (name, "*") == 0) { unsigned i; - for (i = 0; ! errors && i < scope->argv.argc; i++) + for (i = 0; i < scope->argv.argc; i++) if (type == GRUB_SCRIPT_ARG_TYPE_VAR) { - if (i != 0) - errors += grub_script_argv_next (&result); - errors += grub_script_argv_split_append (&result, - scope->argv.args[i]); + if (i != 0 && grub_script_argv_next (&result)) + goto fail; + + if (grub_script_argv_split_append (&result, scope->argv.args[i])) + goto fail; } else { - if (i != 0) - errors += grub_script_argv_append (&result, " "); - errors += grub_script_argv_append (&result, - scope->argv.args[i]); + if (i != 0 && grub_script_argv_append (&result, " ")) + goto fail; + + if (grub_script_argv_append (&result, scope->argv.args[i])) + goto fail; } } else if (grub_strcmp (name, "@") == 0) { unsigned i; - for (i = 0; ! errors && i < scope->argv.argc; i++) + for (i = 0; i < scope->argv.argc; i++) { - if (i != 0) - errors += grub_script_argv_next (&result); + if (i != 0 && grub_script_argv_next (&result)) + goto fail; if (type == GRUB_SCRIPT_ARG_TYPE_VAR) - errors += grub_script_argv_split_append (&result, - scope->argv.args[i]); + { + if (grub_script_argv_split_append (&result, scope->argv.args[i])) + goto fail; + } else - errors += grub_script_argv_append (&result, - scope->argv.args[i]); + if (grub_script_argv_append (&result, scope->argv.args[i])) + goto fail; } } else @@ -121,21 +133,23 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) else if (num <= scope->argv.argc) { if (type == GRUB_SCRIPT_ARG_TYPE_VAR) - errors += grub_script_argv_split_append (&result, - scope->argv.args[num - 1]); + { + if (grub_script_argv_split_append (&result, + scope->argv.args[num - 1])) + goto fail; + } else - errors += grub_script_argv_append (&result, - scope->argv.args[num - 1]); + if (grub_script_argv_append (&result, scope->argv.args[num - 1])) + goto fail; } } - if (errors) - { - grub_script_argv_free (&result); - return 0; - } - return result.args; + + fail: + + grub_script_argv_free (&result); + return 0; } static grub_err_t @@ -153,21 +167,18 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, struct grub_script_argv *argv) { int i; - int error = 0; char **values = 0; struct grub_script_arg *arg = 0; struct grub_script_argv result = { 0, 0 }; - for (; error == 0 && arglist && arglist->arg; arglist = arglist->next) + for (; arglist && arglist->arg; arglist = arglist->next) { - error += grub_script_argv_next (&result); + if (grub_script_argv_next (&result)) + goto fail; arg = arglist->arg; while (arg) { - if (error) - break; - switch (arg->type) { case GRUB_SCRIPT_ARG_TYPE_VAR: @@ -175,35 +186,41 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, values = grub_script_env_get (arg->str, arg->type); for (i = 0; values && values[i]; i++) { - if (i != 0) - error += grub_script_argv_next (&result); - error += grub_script_argv_append (&result, values[i]); + if (i != 0 && grub_script_argv_next (&result)) + goto fail; + + if (grub_script_argv_append (&result, values[i])) + goto fail; } grub_free (values); break; case GRUB_SCRIPT_ARG_TYPE_TEXT: - if (grub_strlen (arg->str)) - error += grub_script_argv_append (&result, arg->str); + if (grub_strlen (arg->str) && + grub_script_argv_append (&result, arg->str)) + goto fail; break; case GRUB_SCRIPT_ARG_TYPE_DQSTR: case GRUB_SCRIPT_ARG_TYPE_SQSTR: - error += grub_script_argv_append (&result, arg->str); + if (grub_script_argv_append (&result, arg->str)) + goto fail; break; } arg = arg->next; } } - if (error) - return 1; - if (! result.args[result.argc - 1]) result.argc--; *argv = result; return 0; + + fail: + + grub_script_argv_free (&result); + return 1; } static grub_err_t @@ -356,7 +373,7 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { unsigned i; grub_err_t result; - struct grub_script_argv argv; + struct grub_script_argv argv = { 0, 0 }; struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd; if (grub_script_arglist_to_argv (cmdfor->words, &argv)) @@ -398,7 +415,7 @@ 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}; + struct grub_script_argv argv = { 0, 0 }; cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd; From 6c9aa3df16e5add2b88b96556b5e0d0ba8ce9475 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 9 Jun 2010 11:29:11 +0530 Subject: [PATCH 14/34] block params are grub_script with independent memory --- include/grub/script_sh.h | 2 +- script/parser.y | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index e1bf6f22e..9eccb9028 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -61,7 +61,7 @@ struct grub_script_arg char *str; /* Parsed block argument. */ - struct grub_script_cmd *block; + struct grub_script block; /* Next argument part. */ struct grub_script_arg *next; diff --git a/script/parser.y b/script/parser.y index 9d256a153..6669b783c 100644 --- a/script/parser.y +++ b/script/parser.y @@ -33,7 +33,10 @@ struct grub_script_arglist *arglist; struct grub_script_arg *arg; char *string; - unsigned offset; + struct { + unsigned offset; + struct grub_script_mem *memory; + }; } %token GRUB_PARSER_TOKEN_BAD @@ -147,24 +150,30 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } | word { $$ = $1; } ; -block: "{" +block: "{" { grub_script_lexer_ref (state->lexerstate); $$ = grub_script_lexer_record_start (state); + $$ = grub_script_mem_record (state); } commands1 delimiters0 "}" { char *p; struct grub_script_arg *arg; + struct grub_script_mem *memory; - grub_script_lexer_deref (state->lexerstate); - if (p = grub_script_lexer_record_stop (state, $2)) + memory = grub_script_mem_record_stop (state, $2); + if ((p = grub_script_lexer_record_stop (state, $2))) *grub_strrchr (p, '}') = '\0'; if (arg = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p)) - arg->block = $3; + { + arg->block.cmd = $3; + arg->block.mem = memory; + } $$ = grub_script_add_arglist (state, 0, arg); + grub_script_lexer_deref (state->lexerstate); } ; From 28be0e94db5c92202a94fe204beb5d0ea0936771 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 10 Jun 2010 12:12:03 +0530 Subject: [PATCH 15/34] add example usage to hello command --- commands/acpi.c | 5 ++--- commands/echo.c | 4 ++-- commands/extcmd.c | 23 ++++++++++++++----- commands/hashsum.c | 6 ++--- commands/hdparm.c | 4 ++-- commands/help.c | 2 +- commands/hexdump.c | 4 ++-- commands/i386/cpuid.c | 2 +- commands/i386/pc/drivemap.c | 12 +++++----- commands/i386/pc/halt.c | 4 ++-- commands/iorw.c | 8 +++---- commands/keystatus.c | 4 ++-- commands/loadenv.c | 12 +++++----- commands/ls.c | 4 ++-- commands/lspci.c | 4 ++-- commands/memrw.c | 8 +++---- commands/probe.c | 4 ++-- commands/search_wrap.c | 4 ++-- commands/setpci.c | 16 ++++++------- commands/sleep.c | 4 ++-- disk/loopback.c | 4 ++-- hello/hello.c | 38 ++++++++++++++++++++++++++----- include/grub/command.h | 2 ++ include/grub/extcmd.h | 22 +++++++++++++++--- include/grub/script_sh.h | 3 +++ loader/i386/bsd.c | 20 ++++++++--------- loader/xnu.c | 6 ++--- script/argv.c | 45 +++++++++++++++++++++++++++++++++++-- script/execute.c | 25 ++++++++++++++++----- script/parser.y | 2 +- script/script.c | 8 ++++++- term/gfxterm.c | 7 +++--- term/serial.c | 4 ++-- tests/lib/functional_test.c | 2 +- 34 files changed, 220 insertions(+), 102 deletions(-) diff --git a/commands/acpi.c b/commands/acpi.c index 5bbfd008b..bdfdea073 100644 --- a/commands/acpi.c +++ b/commands/acpi.c @@ -456,10 +456,9 @@ free_tables (void) } static grub_err_t -grub_cmd_acpi (struct grub_extcmd *cmd, - int argc, char **args) +grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; struct grub_acpi_rsdp_v10 *rsdp; struct efiemu_acpi_table *cur, *t; grub_err_t err; diff --git a/commands/echo.c b/commands/echo.c index 4fea091cb..6bc00eae8 100644 --- a/commands/echo.c +++ b/commands/echo.c @@ -30,9 +30,9 @@ static const struct grub_arg_option options[] = }; static grub_err_t -grub_cmd_echo (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_echo (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; int newline = 1; int i; diff --git a/commands/extcmd.c b/commands/extcmd.c index 16796febf..76cbe4e26 100644 --- a/commands/extcmd.c +++ b/commands/extcmd.c @@ -21,15 +21,17 @@ #include #include #include +#include -static grub_err_t -grub_extcmd_dispatcher (struct grub_command *cmd, - int argc, char **args) +grub_err_t +grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, + struct grub_script **scripts) { 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; @@ -44,8 +46,11 @@ grub_extcmd_dispatcher (struct grub_command *cmd, if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc)) { - ext->state = state; - ret = (ext->func) (ext, new_argc, new_args); + context.extcmd = ext; + context.state = state; + context.script_params = scripts; + + ret = (ext->func) (&context, new_argc, new_args); grub_free (new_args); } else @@ -56,6 +61,12 @@ grub_extcmd_dispatcher (struct grub_command *cmd, return ret; } +static grub_err_t +grub_extcmd_dispatch (struct grub_command *cmd, int argc, char **args) +{ + return grub_extcmd_dispatcher (cmd, argc, args, 0); +} + grub_extcmd_t grub_register_extcmd (const char *name, grub_extcmd_func_t func, unsigned flags, const char *summary, @@ -69,7 +80,7 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func, if (! ext) return 0; - cmd = grub_register_command_prio (name, grub_extcmd_dispatcher, + cmd = grub_register_command_prio (name, grub_extcmd_dispatch, summary, description, 1); if (! cmd) { diff --git a/commands/hashsum.c b/commands/hashsum.c index d5f551dbb..df85015a6 100644 --- a/commands/hashsum.c +++ b/commands/hashsum.c @@ -165,10 +165,10 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, } static grub_err_t -grub_cmd_hashsum (struct grub_extcmd *cmd, +grub_cmd_hashsum (struct grub_extcmd_context *ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; const char *hashname = NULL; const char *prefix = NULL; const gcry_md_spec_t *hash; @@ -177,7 +177,7 @@ grub_cmd_hashsum (struct grub_extcmd *cmd, unsigned unread = 0; for (i = 0; i < ARRAY_SIZE (aliases); i++) - if (grub_strcmp (cmd->cmd->name, aliases[i].name) == 0) + if (grub_strcmp (ctxt->extcmd->cmd->name, aliases[i].name) == 0) hashname = aliases[i].hashname; if (state[0].set) hashname = state[0].arg; diff --git a/commands/hdparm.c b/commands/hdparm.c index a3f8bbff0..54724077d 100644 --- a/commands/hdparm.c +++ b/commands/hdparm.c @@ -270,9 +270,9 @@ static int get_int_arg (const struct grub_arg_list *state) } static grub_err_t -grub_cmd_hdparm (grub_extcmd_t cmd, int argc, char **args) // state???? +grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state???? { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; /* Check command line. */ if (argc != 1) diff --git a/commands/help.c b/commands/help.c index c2aad03b2..2b2eeaa84 100644 --- a/commands/help.c +++ b/commands/help.c @@ -27,7 +27,7 @@ #include static grub_err_t -grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc, +grub_cmd_help (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc, char **args) { int cnt = 0; diff --git a/commands/hexdump.c b/commands/hexdump.c index c1d4ecba9..6c518f649 100644 --- a/commands/hexdump.c +++ b/commands/hexdump.c @@ -34,9 +34,9 @@ static const struct grub_arg_option options[] = { }; static grub_err_t -grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_hexdump (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; char buf[GRUB_DISK_SECTOR_SIZE * 4]; grub_ssize_t size, length; grub_disk_addr_t skip; diff --git a/commands/i386/cpuid.c b/commands/i386/cpuid.c index 6eebf91a1..412b284d0 100644 --- a/commands/i386/cpuid.c +++ b/commands/i386/cpuid.c @@ -43,7 +43,7 @@ static const struct grub_arg_option options[] = unsigned char grub_cpuid_has_longmode = 0; static grub_err_t -grub_cmd_cpuid (grub_extcmd_t cmd __attribute__ ((unused)), +grub_cmd_cpuid (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { diff --git a/commands/i386/pc/drivemap.c b/commands/i386/pc/drivemap.c index 4afc43358..7ecfe7454 100644 --- a/commands/i386/pc/drivemap.c +++ b/commands/i386/pc/drivemap.c @@ -196,13 +196,13 @@ list_mappings (void) } static grub_err_t -grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args) +grub_cmd_drivemap (struct grub_extcmd_context *ctxt, int argc, char **args) { - if (cmd->state[OPTIDX_LIST].set) + if (ctxt->state[OPTIDX_LIST].set) { return list_mappings (); } - else if (cmd->state[OPTIDX_RESET].set) + else if (ctxt->state[OPTIDX_RESET].set) { /* Reset: just delete all mappings, freeing their memory. */ drivemap_node_t *curnode = map_head; @@ -216,7 +216,7 @@ grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args) map_head = 0; return GRUB_ERR_NONE; } - else if (!cmd->state[OPTIDX_SWAP].set && argc == 0) + else if (!ctxt->state[OPTIDX_SWAP].set && argc == 0) { /* No arguments */ return list_mappings (); @@ -248,11 +248,11 @@ grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args) } /* Set the mapping for the disk (overwrites any existing mapping). */ grub_dprintf ("drivemap", "%s %s (%02x) = %s (%02x)\n", - cmd->state[OPTIDX_SWAP].set ? "Swapping" : "Mapping", + ctxt->state[OPTIDX_SWAP].set ? "Swapping" : "Mapping", args[1], mapto, args[0], mapfrom); err = drivemap_set (mapto, mapfrom); /* If -s, perform the reverse mapping too (only if the first was OK). */ - if (cmd->state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE) + if (ctxt->state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE) err = drivemap_set (mapfrom, mapto); return err; } diff --git a/commands/i386/pc/halt.c b/commands/i386/pc/halt.c index 4c39612ae..10b298644 100644 --- a/commands/i386/pc/halt.c +++ b/commands/i386/pc/halt.c @@ -29,12 +29,12 @@ static const struct grub_arg_option options[] = }; static grub_err_t -grub_cmd_halt (grub_extcmd_t cmd, +grub_cmd_halt (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; int no_apm = 0; if (state[0].set) no_apm = 1; diff --git a/commands/iorw.c b/commands/iorw.c index 474c8712e..bd0183794 100644 --- a/commands/iorw.c +++ b/commands/iorw.c @@ -36,7 +36,7 @@ static const struct grub_arg_option options[] = static grub_err_t -grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) +grub_cmd_read (grub_extcmd_context_t ctxt, int argc, char **argv) { grub_target_addr_t addr; grub_uint32_t value = 0; @@ -46,7 +46,7 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments"); addr = grub_strtoul (argv[0], 0, 0); - switch (cmd->cmd->name[sizeof ("in") - 1]) + switch (ctxt->extcmd->cmd->name[sizeof ("in") - 1]) { case 'l': value = grub_inl (addr); @@ -61,10 +61,10 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) break; } - if (cmd->state[0].set) + if (ctxt->state[0].set) { grub_snprintf (buf, sizeof (buf), "%x", value); - grub_env_set (cmd->state[0].arg, buf); + grub_env_set (ctxt->state[0].arg, buf); } else grub_printf ("0x%x\n", value); diff --git a/commands/keystatus.c b/commands/keystatus.c index 838792889..c83c00560 100644 --- a/commands/keystatus.c +++ b/commands/keystatus.c @@ -34,11 +34,11 @@ static const struct grub_arg_option options[] = #define grub_cur_term_input grub_term_get_current_input () static grub_err_t -grub_cmd_keystatus (grub_extcmd_t cmd, +grub_cmd_keystatus (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; int expect_mods = 0; int mods; diff --git a/commands/loadenv.c b/commands/loadenv.c index d763b2d5e..381810a92 100644 --- a/commands/loadenv.c +++ b/commands/loadenv.c @@ -111,11 +111,11 @@ read_envblk_file (grub_file_t file) } static grub_err_t -grub_cmd_load_env (grub_extcmd_t cmd, +grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; grub_file_t file; grub_envblk_t envblk; @@ -143,11 +143,11 @@ grub_cmd_load_env (grub_extcmd_t cmd, } static grub_err_t -grub_cmd_list_env (grub_extcmd_t cmd, +grub_cmd_list_env (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; grub_file_t file; grub_envblk_t envblk; @@ -280,9 +280,9 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, } static grub_err_t -grub_cmd_save_env (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; grub_file_t file; grub_envblk_t envblk; struct blocklist *head = 0; diff --git a/commands/ls.c b/commands/ls.c index eb1049617..6b2f63c19 100644 --- a/commands/ls.c +++ b/commands/ls.c @@ -248,9 +248,9 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) } static grub_err_t -grub_cmd_ls (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_ls (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; if (argc == 0) grub_ls_list_devices (state[0].set); diff --git a/commands/lspci.c b/commands/lspci.c index a69bb35ad..bc52e060a 100644 --- a/commands/lspci.c +++ b/commands/lspci.c @@ -211,11 +211,11 @@ grub_lspci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) } static grub_err_t -grub_cmd_lspci (grub_extcmd_t cmd, +grub_cmd_lspci (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - iospace = cmd->state[0].set; + iospace = ctxt->state[0].set; grub_pci_iterate (grub_lspci_iter); return GRUB_ERR_NONE; } diff --git a/commands/memrw.c b/commands/memrw.c index 6a4d43be2..d28f45ec1 100644 --- a/commands/memrw.c +++ b/commands/memrw.c @@ -35,7 +35,7 @@ static const struct grub_arg_option options[] = static grub_err_t -grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) +grub_cmd_read (grub_extcmd_context_t ctxt, int argc, char **argv) { grub_target_addr_t addr; grub_uint32_t value = 0; @@ -45,7 +45,7 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments"); addr = grub_strtoul (argv[0], 0, 0); - switch (cmd->cmd->name[sizeof ("read_") - 1]) + switch (ctxt->extcmd->cmd->name[sizeof ("read_") - 1]) { case 'd': value = *((volatile grub_uint32_t *) addr); @@ -60,10 +60,10 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) break; } - if (cmd->state[0].set) + if (ctxt->state[0].set) { grub_snprintf (buf, sizeof (buf), "%x", value); - grub_env_set (cmd->state[0].arg, buf); + grub_env_set (ctxt->state[0].arg, buf); } else grub_printf ("0x%x\n", value); diff --git a/commands/probe.c b/commands/probe.c index c2cc599e9..f3941e029 100644 --- a/commands/probe.c +++ b/commands/probe.c @@ -45,9 +45,9 @@ static const struct grub_arg_option options[] = }; static grub_err_t -grub_cmd_probe (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; grub_device_t dev; grub_fs_t fs; char *ptr; diff --git a/commands/search_wrap.c b/commands/search_wrap.c index 2891d85d7..fff3fb47a 100644 --- a/commands/search_wrap.c +++ b/commands/search_wrap.c @@ -50,9 +50,9 @@ enum options }; static grub_err_t -grub_cmd_search (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; const char *var = 0; if (argc == 0) diff --git a/commands/setpci.c b/commands/setpci.c index fbc7c214e..89a0085d8 100644 --- a/commands/setpci.c +++ b/commands/setpci.c @@ -155,7 +155,7 @@ grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) } static grub_err_t -grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) +grub_cmd_setpci (grub_extcmd_context_t ctxt, int argc, char **argv) { const char *ptr; unsigned i; @@ -163,14 +163,14 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) pciid_check_value = 0; pciid_check_mask = 0; - if (cmd->state[0].set) + if (ctxt->state[0].set) { - ptr = cmd->state[0].arg; + ptr = ctxt->state[0].arg; pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff); if (grub_errno == GRUB_ERR_BAD_NUMBER) { grub_errno = GRUB_ERR_NONE; - ptr = cmd->state[0].arg; + ptr = ctxt->state[0].arg; } else pciid_check_mask |= 0xffff; @@ -191,11 +191,11 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) check_bus = check_device = check_function = 0; - if (cmd->state[1].set) + if (ctxt->state[1].set) { const char *optr; - ptr = cmd->state[1].arg; + ptr = ctxt->state[1].arg; optr = ptr; bus = grub_strtoul (ptr, (char **) &ptr, 16); if (grub_errno == GRUB_ERR_BAD_NUMBER) @@ -229,8 +229,8 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) } } - if (cmd->state[2].set) - varname = cmd->state[2].arg; + if (ctxt->state[2].set) + varname = ctxt->state[2].arg; else varname = NULL; diff --git a/commands/sleep.c b/commands/sleep.c index ead279506..ee0875cf7 100644 --- a/commands/sleep.c +++ b/commands/sleep.c @@ -60,9 +60,9 @@ grub_interruptible_millisleep (grub_uint32_t ms) } static grub_err_t -grub_cmd_sleep (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_sleep (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; int n; if (argc != 1) diff --git a/disk/loopback.c b/disk/loopback.c index 1b525e05f..52929e765 100644 --- a/disk/loopback.c +++ b/disk/loopback.c @@ -71,9 +71,9 @@ delete_loopback (const char *name) /* The command to add and remove loopback devices. */ static grub_err_t -grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = state = cmd->state; + struct grub_arg_list *state = ctxt->state; grub_file_t file; struct grub_loopback *newdev; diff --git a/hello/hello.c b/hello/hello.c index eff07d941..16c3bb5ce 100644 --- a/hello/hello.c +++ b/hello/hello.c @@ -26,12 +26,36 @@ #include #include +static struct grub_script *script; + static grub_err_t -grub_cmd_hello (struct grub_extcmd *cmd __attribute__ ((unused)), - int argc __attribute__ ((unused)), - char **args __attribute__ ((unused))) +grub_cmd_hello (grub_extcmd_context_t ctxt, + int argc, char **args __attribute__ ((unused))) { - grub_printf ("Hello World\n"); + if (argc == 0 && script == 0) + grub_printf ("Hello World\n"); + + else if (argc == 0) + grub_script_execute (script); + + else + { + if (! ctxt->script_params || ! ctxt->script_params[0]) + return 1; + + if (script) + grub_script_free (script); + + script = grub_malloc (sizeof (*script)); + if (! script) + return 1; + + script->cmd = ctxt->script_params[0]->cmd; + script->mem = ctxt->script_params[0]->mem; + ctxt->script_params[0]->cmd = 0; + ctxt->script_params[0]->mem = 0; + } + return 0; } @@ -39,11 +63,15 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(hello) { - cmd = grub_register_extcmd ("hello", grub_cmd_hello, GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("hello", grub_cmd_hello, + GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS, 0, N_("Say \"Hello World\"."), 0); } GRUB_MOD_FINI(hello) { + if (script) + grub_script_free (script); + grub_unregister_extcmd (cmd); } diff --git a/include/grub/command.h b/include/grub/command.h index 6e9942b60..c2523f288 100644 --- a/include/grub/command.h +++ b/include/grub/command.h @@ -37,6 +37,8 @@ #define GRUB_COMMAND_FLAG_EXTCMD 0x10 /* This is an dynamic command. */ #define GRUB_COMMAND_FLAG_DYNCMD 0x20 +/* This command accepts block arguments. */ +#define GRUB_COMMAND_FLAG_BLOCKS 0x40 struct grub_command; diff --git a/include/grub/extcmd.h b/include/grub/extcmd.h index 03eaba8f8..54f0958fe 100644 --- a/include/grub/extcmd.h +++ b/include/grub/extcmd.h @@ -21,10 +21,12 @@ #include #include +#include struct grub_extcmd; +struct grub_extcmd_context; -typedef grub_err_t (*grub_extcmd_func_t) (struct grub_extcmd *cmd, +typedef grub_err_t (*grub_extcmd_func_t) (struct grub_extcmd_context *ctxt, int argc, char **args); /* The argcmd description. */ @@ -38,11 +40,21 @@ struct grub_extcmd const struct grub_arg_option *options; void *data; - - struct grub_arg_list *state; }; typedef struct grub_extcmd *grub_extcmd_t; +/* Command context for each instance of execution. */ +struct grub_extcmd_context +{ + struct grub_extcmd *extcmd; + + struct grub_arg_list *state; + + /* Script parameters, if any. */ + struct grub_script **script_params; +}; +typedef struct grub_extcmd_context *grub_extcmd_context_t; + grub_extcmd_t grub_register_extcmd (const char *name, grub_extcmd_func_t func, unsigned flags, @@ -52,4 +64,8 @@ grub_extcmd_t grub_register_extcmd (const char *name, void grub_unregister_extcmd (grub_extcmd_t cmd); +grub_err_t +grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, + struct grub_script **scripts); + #endif /* ! GRUB_EXTCMD_HEADER */ diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 87fb26f93..a17dcca70 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -72,6 +72,7 @@ struct grub_script_argv { unsigned argc; char **args; + struct grub_script **scripts; }; /* A complete argument. It consists of a list of one or more `struct @@ -230,6 +231,8 @@ void grub_script_argv_free (struct grub_script_argv *argv); 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); +int grub_script_argv_script_append (struct grub_script_argv *argv, + struct grub_script *s); struct grub_script_arglist * grub_script_create_arglist (struct grub_parser_param *state); diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c index 3c7fe2fee..c92712562 100644 --- a/loader/i386/bsd.c +++ b/loader/i386/bsd.c @@ -946,10 +946,10 @@ grub_bsd_parse_flags (const struct grub_arg_list *state, } static grub_err_t -grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[]) +grub_cmd_freebsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) { kernel_type = KERNEL_TYPE_FREEBSD; - bootflags = grub_bsd_parse_flags (cmd->state, freebsd_flags); + bootflags = grub_bsd_parse_flags (ctxt->state, freebsd_flags); if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) { @@ -1009,16 +1009,16 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[]) } static grub_err_t -grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[]) +grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) { grub_uint32_t bootdev; kernel_type = KERNEL_TYPE_OPENBSD; - bootflags = grub_bsd_parse_flags (cmd->state, openbsd_flags); + bootflags = grub_bsd_parse_flags (ctxt->state, openbsd_flags); - if (cmd->state[OPENBSD_ROOT_ARG].set) + if (ctxt->state[OPENBSD_ROOT_ARG].set) { - const char *arg = cmd->state[OPENBSD_ROOT_ARG].arg; + const char *arg = ctxt->state[OPENBSD_ROOT_ARG].arg; int unit, part; if (*(arg++) != 'w' || *(arg++) != 'd') return grub_error (GRUB_ERR_BAD_ARGUMENT, @@ -1049,16 +1049,16 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[]) } static grub_err_t -grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[]) +grub_cmd_netbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) { kernel_type = KERNEL_TYPE_NETBSD; - bootflags = grub_bsd_parse_flags (cmd->state, netbsd_flags); + bootflags = grub_bsd_parse_flags (ctxt->state, netbsd_flags); if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) { grub_loader_set (grub_netbsd_boot, grub_bsd_unload, 1); - if (cmd->state[NETBSD_ROOT_ARG].set) - netbsd_root = grub_strdup (cmd->state[NETBSD_ROOT_ARG].arg); + if (ctxt->state[NETBSD_ROOT_ARG].set) + netbsd_root = grub_strdup (ctxt->state[NETBSD_ROOT_ARG].arg); } return grub_errno; diff --git a/loader/xnu.c b/loader/xnu.c index 8f1d0c641..5c7bd50be 100644 --- a/loader/xnu.c +++ b/loader/xnu.c @@ -1368,15 +1368,15 @@ static const struct grub_arg_option xnu_splash_cmd_options[] = }; static grub_err_t -grub_cmd_xnu_splash (grub_extcmd_t cmd, +grub_cmd_xnu_splash (grub_extcmd_context_t ctxt, int argc, char *args[]) { grub_err_t err; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); - if (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set && - grub_strcmp (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg, + if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set && + grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg, "stretch") == 0) grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH; else diff --git a/script/argv.c b/script/argv.c index 69322779d..f962556d8 100644 --- a/script/argv.c +++ b/script/argv.c @@ -52,8 +52,17 @@ grub_script_argv_free (struct grub_script_argv *argv) grub_free (argv->args); } + if (argv->scripts) + { + for (i = 0; i < argv->argc; i++) + grub_script_free (argv->scripts[i]); + + grub_free (argv->scripts); + } + argv->argc = 0; argv->args = 0; + argv->scripts = 0; } /* Prepare for next argc. */ @@ -61,20 +70,33 @@ int grub_script_argv_next (struct grub_script_argv *argv) { char **p = argv->args; + struct grub_script **q = argv->scripts; - if (argv->args && argv->args[argv->argc - 1] == 0) + if (argv->args && argv->argc && argv->args[argv->argc - 1] == 0) return 0; p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *))); if (! p) return 1; + q = grub_realloc (q, round_up_exp ((argv->argc + 2) * sizeof (struct grub_script *))); + if (! q) + { + grub_free (p); + return 1; + } + argv->argc++; argv->args = p; + argv->scripts = q; if (argv->argc == 1) - argv->args[0] = 0; + { + argv->args[0] = 0; + argv->scripts[0] = 0; + } argv->args[argv->argc] = 0; + argv->scripts[argv->argc] = 0; return 0; } @@ -100,6 +122,25 @@ grub_script_argv_append (struct grub_script_argv *argv, const char *s) return 0; } +/* Append grub_script `s' as the last argument. */ +int +grub_script_argv_script_append (struct grub_script_argv *argv, + struct grub_script *script) +{ + struct grub_script *s; + + s = grub_malloc (sizeof (*s)); + if (! s) + return 1; + + if (argv->scripts[argv->argc - 1]) + grub_script_free (argv->scripts[argv->argc - 1]); + + *s = *script; + argv->scripts[argv->argc - 1] = s; + return 0; +} + /* Split `s' and append words as multiple arguments. */ int grub_script_argv_split_append (struct grub_script_argv *argv, char *s) diff --git a/script/execute.c b/script/execute.c index 691b3c893..0ac42cf4a 100644 --- a/script/execute.c +++ b/script/execute.c @@ -25,6 +25,7 @@ #include #include #include +#include /* Max digits for a char is 3 (0xFF is 255), similarly for an int it is sizeof (int) * 3, and one extra for a possible -ve sign. */ @@ -51,7 +52,7 @@ grub_env_special (const char *name) static char ** grub_script_env_get (const char *name, grub_script_arg_type_t type) { - struct grub_script_argv result = { 0, 0 }; + struct grub_script_argv result = { 0, 0, 0 }; if (grub_script_argv_next (&result)) goto fail; @@ -169,7 +170,7 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, int i; char **values = 0; struct grub_script_arg *arg = 0; - struct grub_script_argv result = { 0, 0 }; + struct grub_script_argv result = { 0, 0, 0 }; for (; arglist && arglist->arg; arglist = arglist->next) { @@ -196,6 +197,11 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, break; case GRUB_SCRIPT_ARG_TYPE_BLOCK: + if (grub_script_argv_append (&result, arg->str) || + grub_script_argv_script_append (&result, &arg->block)) + goto fail; + break; + case GRUB_SCRIPT_ARG_TYPE_TEXT: if (grub_strlen (arg->str) && grub_script_argv_append (&result, arg->str)) @@ -270,7 +276,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) grub_script_function_t func = 0; char errnobuf[18]; char *cmdname; - struct grub_script_argv argv = { 0, 0 }; + struct grub_script_argv argv = { 0, 0, 0 }; /* Lookup the command. */ if (grub_script_arglist_to_argv (cmdline->arglist, &argv)) @@ -314,7 +320,14 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) /* Execute the GRUB command or function. */ if (grubcmd) - ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1); + { + if ((grubcmd->flags & GRUB_COMMAND_FLAG_BLOCKS) && + (grubcmd->flags & GRUB_COMMAND_FLAG_EXTCMD)) + ret = grub_extcmd_dispatcher (grubcmd, argv.argc - 1, argv.args + 1, + argv.scripts + 1); + else + ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1); + } else ret = grub_script_function_call (func, argv.argc - 1, argv.args + 1); @@ -374,7 +387,7 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { unsigned i; grub_err_t result; - struct grub_script_argv argv = { 0, 0 }; + struct grub_script_argv argv = { 0, 0, 0 }; struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd; if (grub_script_arglist_to_argv (cmdfor->words, &argv)) @@ -416,7 +429,7 @@ 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 }; + struct grub_script_argv argv = { 0, 0, 0 }; cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd; diff --git a/script/parser.y b/script/parser.y index 653e2bc84..d774ca918 100644 --- a/script/parser.y +++ b/script/parser.y @@ -164,7 +164,7 @@ block: "{" if ((p = grub_script_lexer_record_stop (state, $2))) *grub_strrchr (p, '}') = '\0'; - if (arg = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p)) + if ((arg = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p))) { arg->block.cmd = $3; arg->block.mem = memory; diff --git a/script/script.c b/script/script.c index 9cee40dcb..9017a08e8 100644 --- a/script/script.c +++ b/script/script.c @@ -96,7 +96,10 @@ grub_script_free (struct grub_script *script) { if (!script) return; - grub_script_mem_free (script->mem); + + if (script->mem) + grub_script_mem_free (script->mem); + grub_free (script); } @@ -119,6 +122,9 @@ grub_script_arg_add (struct grub_parser_param *state, return arg; argpart->type = type; + argpart->block.mem = 0; + argpart->block.cmd = 0; + len = grub_strlen (str) + 1; argpart->str = grub_script_malloc (state, len); if (!argpart->str) diff --git a/term/gfxterm.c b/term/gfxterm.c index ecfe4ff3b..ffded5e6b 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -1091,11 +1091,10 @@ static const struct grub_arg_option background_image_cmd_options[] = }; static grub_err_t -grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), - int argc, - char **args) +grub_gfxterm_background_image_cmd (grub_extcmd_context_t ctxt, + int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; /* Check that we have video adapter active. */ if (grub_video_get_info(NULL) != GRUB_ERR_NONE) diff --git a/term/serial.c b/term/serial.c index 2347bb3ee..168e40bad 100644 --- a/term/serial.c +++ b/term/serial.c @@ -497,11 +497,11 @@ static struct grub_term_output grub_serial_term_output = static grub_err_t -grub_cmd_serial (grub_extcmd_t cmd, +grub_cmd_serial (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; struct serial_port backup_settings = serial_settings; grub_err_t hwiniterr; diff --git a/tests/lib/functional_test.c b/tests/lib/functional_test.c index 8ff08cf8a..8be6c8e89 100644 --- a/tests/lib/functional_test.c +++ b/tests/lib/functional_test.c @@ -22,7 +22,7 @@ #include static grub_err_t -grub_functional_test (struct grub_extcmd *cmd __attribute__ ((unused)), +grub_functional_test (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { From ead4142900803233bc8cc34eac9fe98ab30833ea Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 10 Jun 2010 12:26:07 +0530 Subject: [PATCH 16/34] fix hello help msg --- hello/hello.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hello/hello.c b/hello/hello.c index 16c3bb5ce..992c99f71 100644 --- a/hello/hello.c +++ b/hello/hello.c @@ -65,7 +65,7 @@ GRUB_MOD_INIT(hello) { cmd = grub_register_extcmd ("hello", grub_cmd_hello, GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS, - 0, N_("Say \"Hello World\"."), 0); + N_("[BLOCK]"), N_("Say \"Hello World\"."), 0); } GRUB_MOD_FINI(hello) From 9d0bd7407d9355ef73d63384959b7a89e76b33b1 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 10 Jun 2010 18:15:38 +0530 Subject: [PATCH 17/34] 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 a992a71ed8df5188e9cdb3d2f5f502c2cc2e6417 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 10 Jun 2010 20:49:57 +0530 Subject: [PATCH 18/34] fix memory issues when used inside loops --- hello/hello.c | 14 ++++---------- include/grub/script_sh.h | 21 ++++++++++++++++++++- script/argv.c | 14 ++++---------- script/execute.c | 2 +- script/parser.y | 14 +++++++------- script/script.c | 17 ++++++----------- 6 files changed, 42 insertions(+), 40 deletions(-) diff --git a/hello/hello.c b/hello/hello.c index 992c99f71..118966291 100644 --- a/hello/hello.c +++ b/hello/hello.c @@ -44,16 +44,9 @@ grub_cmd_hello (grub_extcmd_context_t ctxt, return 1; if (script) - grub_script_free (script); + grub_script_put (script); - script = grub_malloc (sizeof (*script)); - if (! script) - return 1; - - script->cmd = ctxt->script_params[0]->cmd; - script->mem = ctxt->script_params[0]->mem; - ctxt->script_params[0]->cmd = 0; - ctxt->script_params[0]->mem = 0; + script = grub_script_get (ctxt->script_params[0]); } return 0; @@ -71,7 +64,8 @@ GRUB_MOD_INIT(hello) GRUB_MOD_FINI(hello) { if (script) - grub_script_free (script); + grub_script_put (script); + script = 0; grub_unregister_extcmd (cmd); } diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index a17dcca70..2ada5d474 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -39,6 +39,7 @@ struct grub_script_cmd struct grub_script { + unsigned refcnt; struct grub_script_mem *mem; struct grub_script_cmd *cmd; }; @@ -61,7 +62,7 @@ struct grub_script_arg char *str; /* Parsed block argument. */ - struct grub_script block; + struct grub_script *block; /* Next argument part. */ struct grub_script_arg *next; @@ -227,6 +228,8 @@ struct grub_parser_param struct grub_lexer_param *lexerstate; }; +void grub_script_mem_free (struct grub_script_mem *mem); + void grub_script_argv_free (struct grub_script_argv *argv); int grub_script_argv_next (struct grub_script_argv *argv); int grub_script_argv_append (struct grub_script_argv *argv, const char *s); @@ -354,4 +357,20 @@ grub_err_t grub_script_function_call (grub_script_function_t func, char ** grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *count); +static inline struct grub_script * +grub_script_get (struct grub_script *script) +{ + script->refcnt++; + return script; +} + +static inline void +grub_script_put (struct grub_script *script) +{ + if (script->refcnt == 0) + grub_script_free (script); + else + script->refcnt--; +} + #endif /* ! GRUB_NORMAL_PARSER_HEADER */ diff --git a/script/argv.c b/script/argv.c index f962556d8..8dd563345 100644 --- a/script/argv.c +++ b/script/argv.c @@ -55,7 +55,8 @@ grub_script_argv_free (struct grub_script_argv *argv) if (argv->scripts) { for (i = 0; i < argv->argc; i++) - grub_script_free (argv->scripts[i]); + if (argv->scripts[i]) + grub_script_put (argv->scripts[i]); grub_free (argv->scripts); } @@ -127,17 +128,10 @@ int grub_script_argv_script_append (struct grub_script_argv *argv, struct grub_script *script) { - struct grub_script *s; - - s = grub_malloc (sizeof (*s)); - if (! s) - return 1; - if (argv->scripts[argv->argc - 1]) - grub_script_free (argv->scripts[argv->argc - 1]); + grub_script_put (argv->scripts[argv->argc - 1]); - *s = *script; - argv->scripts[argv->argc - 1] = s; + argv->scripts[argv->argc - 1] = grub_script_get (script); return 0; } diff --git a/script/execute.c b/script/execute.c index 0ac42cf4a..c6a6c2484 100644 --- a/script/execute.c +++ b/script/execute.c @@ -198,7 +198,7 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, case GRUB_SCRIPT_ARG_TYPE_BLOCK: if (grub_script_argv_append (&result, arg->str) || - grub_script_argv_script_append (&result, &arg->block)) + grub_script_argv_script_append (&result, arg->block)) goto fail; break; diff --git a/script/parser.y b/script/parser.y index d774ca918..1202fef29 100644 --- a/script/parser.y +++ b/script/parser.y @@ -164,11 +164,9 @@ block: "{" if ((p = grub_script_lexer_record_stop (state, $2))) *grub_strrchr (p, '}') = '\0'; - if ((arg = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p))) - { - arg->block.cmd = $3; - arg->block.mem = memory; - } + arg = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p); + if (! arg || ! (arg->block = grub_script_create ($3, memory))) + grub_script_mem_free (memory); $$ = grub_script_add_arglist (state, 0, arg); grub_script_lexer_deref (state->lexerstate); @@ -256,8 +254,10 @@ function: "function" "name" state->func_mem = grub_script_mem_record_stop (state, state->func_mem); script = grub_script_create ($6, state->func_mem); - if (script) - grub_script_function_create ($2, script); + if (! script) + grub_script_mem_free (state->func_mem); + else + grub_script_function_create ($2, script); grub_script_lexer_deref (state->lexerstate); } diff --git a/script/script.c b/script/script.c index 9017a08e8..b7cbdff1d 100644 --- a/script/script.c +++ b/script/script.c @@ -54,7 +54,7 @@ grub_script_malloc (struct grub_parser_param *state, grub_size_t size) } /* Free all memory described by MEM. */ -static void +void grub_script_mem_free (struct grub_script_mem *mem) { struct grub_script_mem *memfree; @@ -122,8 +122,7 @@ grub_script_arg_add (struct grub_parser_param *state, return arg; argpart->type = type; - argpart->block.mem = 0; - argpart->block.cmd = 0; + argpart->block = 0; len = grub_strlen (str) + 1; argpart->str = grub_script_malloc (state, len); @@ -341,16 +340,12 @@ grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem) struct grub_script *parsed; parsed = grub_malloc (sizeof (*parsed)); - if (!parsed) - { - grub_script_mem_free (mem); - grub_free (cmd); - - return 0; - } + if (! parsed) + return 0; parsed->mem = mem; parsed->cmd = cmd; + parsed->refcnt = 0; return parsed; } @@ -365,7 +360,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline) struct grub_lexer_param *lexstate; struct grub_parser_param *parsestate; - parsed = grub_malloc (sizeof (*parsed)); + parsed = grub_script_create (0, 0); if (!parsed) return 0; From 627c30f7f1f6053b5a7e68cc568c921dca745ee6 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 10 Jun 2010 20:50:49 +0530 Subject: [PATCH 19/34] 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 20/34] 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 f6e59c46e1a32e38e0dc73e417db3cafab54668a Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Sun, 18 Jul 2010 20:46:21 +0530 Subject: [PATCH 21/34] update dynamic cmd dispatch with scripts support --- commands/extcmd.c | 21 ++++++++++++++++----- include/grub/extcmd.h | 8 ++++++++ normal/dyncmd.c | 36 ++++++++++++++++++++++++++---------- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/commands/extcmd.c b/commands/extcmd.c index 76cbe4e26..173dea193 100644 --- a/commands/extcmd.c +++ b/commands/extcmd.c @@ -68,10 +68,11 @@ grub_extcmd_dispatch (struct grub_command *cmd, int argc, char **args) } grub_extcmd_t -grub_register_extcmd (const char *name, grub_extcmd_func_t func, - unsigned flags, const char *summary, - const char *description, - const struct grub_arg_option *parser) +grub_register_extcmd_prio (const char *name, grub_extcmd_func_t func, + unsigned flags, const char *summary, + const char *description, + const struct grub_arg_option *parser, + int prio) { grub_extcmd_t ext; grub_command_t cmd; @@ -81,7 +82,7 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func, return 0; cmd = grub_register_command_prio (name, grub_extcmd_dispatch, - summary, description, 1); + summary, description, prio); if (! cmd) { grub_free (ext); @@ -99,6 +100,16 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func, return ext; } +grub_extcmd_t +grub_register_extcmd (const char *name, grub_extcmd_func_t func, + unsigned flags, const char *summary, + const char *description, + const struct grub_arg_option *parser) +{ + return grub_register_extcmd_prio (name, func, flags, + summary, description, parser, 1); +} + void grub_unregister_extcmd (grub_extcmd_t ext) { diff --git a/include/grub/extcmd.h b/include/grub/extcmd.h index 54f0958fe..a5e4d18fe 100644 --- a/include/grub/extcmd.h +++ b/include/grub/extcmd.h @@ -62,6 +62,14 @@ grub_extcmd_t grub_register_extcmd (const char *name, const char *description, const struct grub_arg_option *parser); +grub_extcmd_t grub_register_extcmd_prio (const char *name, + grub_extcmd_func_t func, + unsigned flags, + const char *summary, + const char *description, + const struct grub_arg_option *parser, + int prio); + void grub_unregister_extcmd (grub_extcmd_t cmd); grub_err_t diff --git a/normal/dyncmd.c b/normal/dyncmd.c index a3cafa514..172baa44e 100644 --- a/normal/dyncmd.c +++ b/normal/dyncmd.c @@ -23,16 +23,21 @@ #include #include #include +#include +#include #include static grub_err_t -grub_dyncmd_dispatcher (struct grub_command *cmd, +grub_dyncmd_dispatcher (struct grub_extcmd_context *ctxt, int argc, char **args) { - char *modname = cmd->data; + char *modname; grub_dl_t mod; grub_err_t ret; + grub_extcmd_t extcmd = ctxt->extcmd; + grub_command_t cmd = extcmd->cmd; + modname = extcmd->data; mod = grub_dl_load (modname); if (mod) { @@ -42,11 +47,18 @@ grub_dyncmd_dispatcher (struct grub_command *cmd, grub_dl_ref (mod); name = (char *) cmd->name; - grub_unregister_command (cmd); + grub_unregister_extcmd (extcmd); cmd = grub_command_find (name); if (cmd) - ret = (cmd->func) (cmd, argc, args); + { + if (cmd->flags & GRUB_COMMAND_FLAG_BLOCKS && + cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) + ret = grub_extcmd_dispatcher (cmd, argc, args, + ctxt->script_params); + else + ret = (cmd->func) (cmd, argc, args); + } else ret = grub_errno; @@ -81,13 +93,14 @@ read_command_list (const char *prefix) for (ptr = grub_command_list; ptr; ptr = next) { next = ptr->next; - if (ptr->func == grub_dyncmd_dispatcher) + if (ptr->flags & GRUB_COMMAND_FLAG_DYNCMD) { if (last) last->next = ptr->next; else grub_command_list = ptr->next; grub_free (ptr); + grub_free (ptr->data); /* extcmd struct */ } else last = ptr; @@ -96,7 +109,7 @@ read_command_list (const char *prefix) for (;; grub_free (buf)) { char *p, *name, *modname; - grub_command_t cmd; + grub_extcmd_t cmd; int prio = 0; buf = grub_file_getline (file); @@ -139,16 +152,19 @@ read_command_list (const char *prefix) continue; } - cmd = grub_register_command_prio (name, - grub_dyncmd_dispatcher, - 0, N_("not loaded"), prio); + cmd = grub_register_extcmd_prio (name, + grub_dyncmd_dispatcher, + GRUB_COMMAND_FLAG_BLOCKS + | GRUB_COMMAND_FLAG_EXTCMD + | GRUB_COMMAND_FLAG_DYNCMD, + 0, N_("not loaded"), 0, + prio); if (! cmd) { grub_free (name); grub_free (modname); continue; } - cmd->flags |= GRUB_COMMAND_FLAG_DYNCMD; cmd->data = modname; /* Update the active flag. */ From 93889c47179b98729f7f501901d4e670ab7d5d2a Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Sun, 18 Jul 2010 21:00:58 +0530 Subject: [PATCH 22/34] undo changes to hello command --- hello/hello.c | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/hello/hello.c b/hello/hello.c index 118966291..183ee7798 100644 --- a/hello/hello.c +++ b/hello/hello.c @@ -26,29 +26,12 @@ #include #include -static struct grub_script *script; - static grub_err_t -grub_cmd_hello (grub_extcmd_context_t ctxt, - int argc, char **args __attribute__ ((unused))) +grub_cmd_hello (grub_extcmd_context_t ctxt __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) { - if (argc == 0 && script == 0) - grub_printf ("Hello World\n"); - - else if (argc == 0) - grub_script_execute (script); - - else - { - if (! ctxt->script_params || ! ctxt->script_params[0]) - return 1; - - if (script) - grub_script_put (script); - - script = grub_script_get (ctxt->script_params[0]); - } - + grub_printf ("Hello World\n"); return 0; } @@ -56,16 +39,11 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(hello) { - cmd = grub_register_extcmd ("hello", grub_cmd_hello, - GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS, - N_("[BLOCK]"), N_("Say \"Hello World\"."), 0); + cmd = grub_register_extcmd ("hello", grub_cmd_hello, GRUB_COMMAND_FLAG_BOTH, + 0, N_("Say \"Hello World\"."), 0); } GRUB_MOD_FINI(hello) { - if (script) - grub_script_put (script); - - script = 0; grub_unregister_extcmd (cmd); } From 9b65d8c4f50e6c9a244895837a2843f2e926af6b Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Mon, 19 Jul 2010 00:44:21 +0530 Subject: [PATCH 23/34] fix automatic option parsing for dynamic commands --- commands/extcmd.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/commands/extcmd.c b/commands/extcmd.c index 173dea193..349e9bfc7 100644 --- a/commands/extcmd.c +++ b/commands/extcmd.c @@ -34,9 +34,20 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, struct grub_extcmd_context context; int maxargs = 0; grub_err_t ret; - grub_extcmd_t ext; + grub_extcmd_t ext = cmd->data; + + context.state = 0; + 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) + { + ret = (ext->func) (&context, argc, args); + return ret; + } - ext = cmd->data; parser = (struct grub_arg_option *) ext->options; while (parser && (parser++)->doc) maxargs++; @@ -46,10 +57,7 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc)) { - context.extcmd = ext; context.state = state; - context.script_params = scripts; - ret = (ext->func) (&context, new_argc, new_args); grub_free (new_args); } From 57a095bc01f08d2e803331d521c09a90f8e33970 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Mon, 19 Jul 2010 01:01:53 +0530 Subject: [PATCH 24/34] 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 15ee6f9dc7744859d494ca69a6c9738ed7721138 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Tue, 20 Jul 2010 00:10:44 +0530 Subject: [PATCH 25/34] add {} around block-arg that is passed through argv --- script/execute.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/script/execute.c b/script/execute.c index c6a6c2484..1e9cd00b7 100644 --- a/script/execute.c +++ b/script/execute.c @@ -197,7 +197,9 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, break; case GRUB_SCRIPT_ARG_TYPE_BLOCK: - if (grub_script_argv_append (&result, arg->str) || + if (grub_script_argv_append (&result, "{") || + grub_script_argv_append (&result, arg->str) || + grub_script_argv_append (&result, "}") || grub_script_argv_script_append (&result, arg->block)) goto fail; break; From b14906860b578b5911cf35bfa10c93182fd62efb Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Tue, 20 Jul 2010 02:33:57 +0530 Subject: [PATCH 26/34] 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 9ebedc24f2e7f3e5d63b18e9db226bdc15445ec5 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 21 Jul 2010 03:47:30 +0530 Subject: [PATCH 27/34] restrict to only one block-arg (as last) param per command --- commands/extcmd.c | 4 ++-- include/grub/extcmd.h | 6 +++--- include/grub/script_sh.h | 6 ++---- normal/dyncmd.c | 3 +-- script/argv.c | 38 ++------------------------------------ script/execute.c | 6 +++--- script/parser.y | 37 +++++++++++++++++-------------------- script/script.c | 2 +- 8 files changed, 31 insertions(+), 71 deletions(-) diff --git a/commands/extcmd.c b/commands/extcmd.c index 349e9bfc7..cc0362e14 100644 --- a/commands/extcmd.c +++ b/commands/extcmd.c @@ -25,7 +25,7 @@ grub_err_t grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, - struct grub_script **scripts) + struct grub_script *script) { int new_argc; char **new_args; @@ -38,7 +38,7 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, context.state = 0; context.extcmd = ext; - context.script_params = scripts; + context.script = script; /* Dynamic commands should not perform option parsing before corresponding module gets loaded. */ diff --git a/include/grub/extcmd.h b/include/grub/extcmd.h index a5e4d18fe..773e47854 100644 --- a/include/grub/extcmd.h +++ b/include/grub/extcmd.h @@ -50,8 +50,8 @@ struct grub_extcmd_context struct grub_arg_list *state; - /* Script parameters, if any. */ - struct grub_script **script_params; + /* Script parameter, if any. */ + struct grub_script *script; }; typedef struct grub_extcmd_context *grub_extcmd_context_t; @@ -74,6 +74,6 @@ void grub_unregister_extcmd (grub_extcmd_t cmd); grub_err_t grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, - struct grub_script **scripts); + struct grub_script *script); #endif /* ! GRUB_EXTCMD_HEADER */ diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 6471c7de3..43791d040 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -62,7 +62,7 @@ struct grub_script_arg char *str; /* Parsed block argument. */ - struct grub_script *block; + struct grub_script *script; /* Next argument part. */ struct grub_script_arg *next; @@ -73,7 +73,7 @@ struct grub_script_argv { unsigned argc; char **args; - struct grub_script **scripts; + struct grub_script *script; }; /* A complete argument. It consists of a list of one or more `struct @@ -234,8 +234,6 @@ void grub_script_argv_free (struct grub_script_argv *argv); 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); -int grub_script_argv_script_append (struct grub_script_argv *argv, - struct grub_script *s); struct grub_script_arglist * grub_script_create_arglist (struct grub_parser_param *state); diff --git a/normal/dyncmd.c b/normal/dyncmd.c index 172baa44e..ed98855eb 100644 --- a/normal/dyncmd.c +++ b/normal/dyncmd.c @@ -54,8 +54,7 @@ grub_dyncmd_dispatcher (struct grub_extcmd_context *ctxt, { if (cmd->flags & GRUB_COMMAND_FLAG_BLOCKS && cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) - ret = grub_extcmd_dispatcher (cmd, argc, args, - ctxt->script_params); + ret = grub_extcmd_dispatcher (cmd, argc, args, ctxt->script); else ret = (cmd->func) (cmd, argc, args); } diff --git a/script/argv.c b/script/argv.c index 8dd563345..42d573a0a 100644 --- a/script/argv.c +++ b/script/argv.c @@ -18,6 +18,7 @@ */ #include +#include #include static unsigned @@ -52,18 +53,8 @@ grub_script_argv_free (struct grub_script_argv *argv) grub_free (argv->args); } - if (argv->scripts) - { - for (i = 0; i < argv->argc; i++) - if (argv->scripts[i]) - grub_script_put (argv->scripts[i]); - - grub_free (argv->scripts); - } - argv->argc = 0; argv->args = 0; - argv->scripts = 0; } /* Prepare for next argc. */ @@ -71,7 +62,6 @@ int grub_script_argv_next (struct grub_script_argv *argv) { char **p = argv->args; - struct grub_script **q = argv->scripts; if (argv->args && argv->argc && argv->args[argv->argc - 1] == 0) return 0; @@ -80,24 +70,12 @@ grub_script_argv_next (struct grub_script_argv *argv) if (! p) return 1; - q = grub_realloc (q, round_up_exp ((argv->argc + 2) * sizeof (struct grub_script *))); - if (! q) - { - grub_free (p); - return 1; - } - argv->argc++; argv->args = p; - argv->scripts = q; if (argv->argc == 1) - { - argv->args[0] = 0; - argv->scripts[0] = 0; - } + argv->args[0] = 0; argv->args[argv->argc] = 0; - argv->scripts[argv->argc] = 0; return 0; } @@ -123,18 +101,6 @@ grub_script_argv_append (struct grub_script_argv *argv, const char *s) return 0; } -/* Append grub_script `s' as the last argument. */ -int -grub_script_argv_script_append (struct grub_script_argv *argv, - struct grub_script *script) -{ - if (argv->scripts[argv->argc - 1]) - grub_script_put (argv->scripts[argv->argc - 1]); - - argv->scripts[argv->argc - 1] = grub_script_get (script); - return 0; -} - /* Split `s' and append words as multiple arguments. */ int grub_script_argv_split_append (struct grub_script_argv *argv, char *s) diff --git a/script/execute.c b/script/execute.c index 1e9cd00b7..932be6635 100644 --- a/script/execute.c +++ b/script/execute.c @@ -199,9 +199,9 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, case GRUB_SCRIPT_ARG_TYPE_BLOCK: if (grub_script_argv_append (&result, "{") || grub_script_argv_append (&result, arg->str) || - grub_script_argv_append (&result, "}") || - grub_script_argv_script_append (&result, arg->block)) + grub_script_argv_append (&result, "}")) goto fail; + result.script = arg->script; break; case GRUB_SCRIPT_ARG_TYPE_TEXT: @@ -326,7 +326,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) if ((grubcmd->flags & GRUB_COMMAND_FLAG_BLOCKS) && (grubcmd->flags & GRUB_COMMAND_FLAG_EXTCMD)) ret = grub_extcmd_dispatcher (grubcmd, argv.argc - 1, argv.args + 1, - argv.scripts + 1); + argv.script); else ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1); } diff --git a/script/parser.y b/script/parser.y index eea7ba111..76dc3fbca 100644 --- a/script/parser.y +++ b/script/parser.y @@ -79,7 +79,8 @@ %token GRUB_PARSER_TOKEN_NAME "name" %token GRUB_PARSER_TOKEN_WORD "word" -%type word argument block parameters0 parameters1 arguments0 arguments1 +%type block block0 +%type word argument parameters0 parameters1 arguments0 arguments1 %type script_init script %type grubcmd ifclause ifcmd forcmd whilecmd untilcmd @@ -160,21 +161,22 @@ block: "{" commands1 delimiters0 "}" { char *p; - struct grub_script_arg *arg; struct grub_script_mem *memory; memory = grub_script_mem_record_stop (state, $2); if ((p = grub_script_lexer_record_stop (state, $2))) *grub_strrchr (p, '}') = '\0'; - arg = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p); - if (! arg || ! (arg->block = grub_script_create ($3, memory))) + $$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p); + if (! $$ || ! ($$->script = grub_script_create ($3, memory))) grub_script_mem_free (memory); - $$ = grub_script_add_arglist (state, 0, arg); grub_script_lexer_deref (state->lexerstate); } ; +block0: /* Empty */ { $$ = 0; } + | block { $$ = $1; } +; arguments0: /* Empty */ { $$ = 0; } | arguments1 { $$ = $1; } @@ -201,27 +203,22 @@ parameters1: argument parameters0 } $$ = $1; } - | block parameters0 - { - if ($1 && $2) - { - $1->next = $2; - $1->argcount += $2->argcount; - $2->argcount = 0; - } - $$ = $1; - } ; parameters0: /* Empty */ { $$ = 0; } | parameters1 { $$ = $1; } ; -grubcmd: word parameters0 +grubcmd: word parameters0 block0 { - if ($1 && $2) { - $1->next = $2; - $1->argcount += $2->argcount; - $2->argcount = 0; + struct grub_script_arglist *x = $2; + + if ($3) + x = grub_script_add_arglist (state, $2, $3); + + if ($1 && x) { + $1->next = x; + $1->argcount += x->argcount; + x->argcount = 0; } $$ = grub_script_create_cmdline (state, $1); } diff --git a/script/script.c b/script/script.c index b7cbdff1d..7cf2f6bae 100644 --- a/script/script.c +++ b/script/script.c @@ -122,7 +122,7 @@ grub_script_arg_add (struct grub_parser_param *state, return arg; argpart->type = type; - argpart->block = 0; + argpart->script = 0; len = grub_strlen (str) + 1; argpart->str = grub_script_malloc (state, len); From 3a082b7f2a92bad9630fd931fff58e33057e537c Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 22 Jul 2010 04:49:05 +0530 Subject: [PATCH 28/34] memory management for block parameters --- include/grub/script_sh.h | 13 +++++++++- script/argv.c | 3 +++ script/execute.c | 2 +- script/main.c | 2 +- script/parser.y | 53 ++++++++++++++++++++++++++++++++++++++-- script/script.c | 10 ++++++++ 6 files changed, 78 insertions(+), 5 deletions(-) diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 43791d040..7618633ad 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -42,6 +42,10 @@ struct grub_script unsigned refcnt; struct grub_script_mem *mem; struct grub_script_cmd *cmd; + + /* Other grub_script's from block arguments. */ + struct grub_script *siblings; + struct grub_script *children; }; typedef enum @@ -222,6 +226,9 @@ struct grub_parser_param /* The memory that was used while parsing and scanning. */ struct grub_script_mem *memused; + /* The block argument scripts. */ + struct grub_script *scripts; + /* The result of the parser. */ struct grub_script_cmd *parsed; @@ -365,13 +372,17 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline); static inline struct grub_script * grub_script_get (struct grub_script *script) { - script->refcnt++; + if (script) + script->refcnt++; return script; } static inline void grub_script_put (struct grub_script *script) { + if (! script) + return; + if (script->refcnt == 0) grub_script_free (script); else diff --git a/script/argv.c b/script/argv.c index 42d573a0a..a7acbc23e 100644 --- a/script/argv.c +++ b/script/argv.c @@ -52,9 +52,12 @@ grub_script_argv_free (struct grub_script_argv *argv) grub_free (argv->args); } + if (argv->script) + grub_script_put (argv->script); argv->argc = 0; argv->args = 0; + argv->script = 0; } /* Prepare for next argc. */ diff --git a/script/execute.c b/script/execute.c index 932be6635..b9538c29b 100644 --- a/script/execute.c +++ b/script/execute.c @@ -201,7 +201,7 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, grub_script_argv_append (&result, arg->str) || grub_script_argv_append (&result, "}")) goto fail; - result.script = arg->script; + result.script = grub_script_get (arg->script); break; case GRUB_SCRIPT_ARG_TYPE_TEXT: diff --git a/script/main.c b/script/main.c index 752a8cd8a..19ce88c43 100644 --- a/script/main.c +++ b/script/main.c @@ -34,7 +34,7 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline) grub_script_execute (parsed_script); /* The parsed script was executed, throw it away. */ - grub_script_free (parsed_script); + grub_script_put (parsed_script); } return grub_errno; diff --git a/script/parser.y b/script/parser.y index 76dc3fbca..4f57ea4ff 100644 --- a/script/parser.y +++ b/script/parser.y @@ -38,6 +38,7 @@ struct { unsigned offset; struct grub_script_mem *memory; + struct grub_script *scripts; }; } @@ -152,16 +153,45 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } | word { $$ = $1; } ; +/* + Block parameter is passed to commands in two forms: as unparsed + string and as pre-parsed grub_script object. Passing as grub_script + object makes memory management difficult, because: + + (1) Command may want to keep a reference to grub_script objects for + later use, so script framework may not free the grub_script + object after command completes. + + (2) Command may get called multiple times with same grub_script + object under loops, so we should not let command implementation + to free the grub_script object. + + To solve above problems, we rely on reference counting for + grub_script objects. Commands that want to keep the grub_script + object must take a reference to it. + + Other complexity comes with arbitrary nesting of grub_script + objects: a grub_script object may have commands with several block + parameters, and each block parameter may further contain multiple + block parameters nested. We use temporary variable, state->scripts + to collect nested child scripts (that are linked by siblings and + children members), and will build grub_scripts tree from bottom. + */ block: "{" { grub_script_lexer_ref (state->lexerstate); $$ = grub_script_lexer_record_start (state); $$ = grub_script_mem_record (state); + + /* save currently known scripts. */ + $$ = state->scripts; + state->scripts = 0; } commands1 delimiters0 "}" { char *p; struct grub_script_mem *memory; + struct grub_script *s = $2; memory = grub_script_mem_record_stop (state, $2); if ((p = grub_script_lexer_record_stop (state, $2))) @@ -171,6 +201,19 @@ block: "{" if (! $$ || ! ($$->script = grub_script_create ($3, memory))) grub_script_mem_free (memory); + else { + /* attach nested scripts to $$->script as children */ + $$->script->children = state->scripts; + + /* restore old scripts; append $$->script to siblings. */ + state->scripts = $2 ?: $$->script; + if (s) { + while (s->siblings) + s = s->siblings; + s->siblings = $$->script; + } + } + grub_script_lexer_deref (state->lexerstate); } ; @@ -243,10 +286,13 @@ commands1: newlines0 command } ; -function: "function" "name" +function: "function" "name" { grub_script_lexer_ref (state->lexerstate); state->func_mem = grub_script_mem_record (state); + + $$ = state->scripts; + state->scripts = 0; } delimiters0 "{" commands1 delimiters1 "}" { @@ -256,9 +302,12 @@ function: "function" "name" script = grub_script_create ($6, state->func_mem); if (! script) grub_script_mem_free (state->func_mem); - else + else { + script->children = state->scripts; grub_script_function_create ($2, script); + } + state->scripts = $3; grub_script_lexer_deref (state->lexerstate); } ; diff --git a/script/script.c b/script/script.c index 7cf2f6bae..6509b5f5d 100644 --- a/script/script.c +++ b/script/script.c @@ -94,12 +94,19 @@ grub_script_mem_record_stop (struct grub_parser_param *state, void grub_script_free (struct grub_script *script) { + struct grub_script *s; + if (!script) return; if (script->mem) grub_script_mem_free (script->mem); + s = script->children; + while (s) { + grub_script_put (s); + s = s->siblings; + } grub_free (script); } @@ -346,6 +353,8 @@ grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem) parsed->mem = mem; parsed->cmd = cmd; parsed->refcnt = 0; + parsed->siblings = 0; + parsed->children = 0; return parsed; } @@ -394,6 +403,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline) parsed->mem = grub_script_mem_record_stop (parsestate, membackup); parsed->cmd = parsestate->parsed; + parsed->children = parsestate->scripts; grub_script_lexer_fini (lexstate); grub_free (parsestate); From 1d0546767810ccce6c2090b675f6b5006f2b307a Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 22 Jul 2010 05:05:49 +0530 Subject: [PATCH 29/34] simplify --- commands/extcmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/commands/extcmd.c b/commands/extcmd.c index cc0362e14..ecf2d4133 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 = script; - /* 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; From 639cc5ab447f41f2d4e3c325ca7acb25c84ec598 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 22 Jul 2010 19:01:40 +0530 Subject: [PATCH 30/34] 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 70abc7023b42b2e19cc41760df09cf9a82bded6e Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 22 Jul 2010 21:13:45 +0530 Subject: [PATCH 31/34] fix a memory issue --- script/script.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/script/script.c b/script/script.c index 6509b5f5d..8d856c493 100644 --- a/script/script.c +++ b/script/script.c @@ -95,8 +95,9 @@ void grub_script_free (struct grub_script *script) { struct grub_script *s; + struct grub_script *t; - if (!script) + if (! script) return; if (script->mem) @@ -104,8 +105,9 @@ grub_script_free (struct grub_script *script) s = script->children; while (s) { + t = s->siblings; grub_script_put (s); - s = s->siblings; + s = t; } 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 32/34] 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 88513a523636adfd76db27cdab93ad183fd1d2d2 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 22 Jul 2010 22:50:04 +0530 Subject: [PATCH 33/34] removed unnecessary grammar rules --- script/parser.y | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/script/parser.y b/script/parser.y index 4f57ea4ff..ce97ab174 100644 --- a/script/parser.y +++ b/script/parser.y @@ -81,7 +81,7 @@ %token GRUB_PARSER_TOKEN_WORD "word" %type block block0 -%type word argument parameters0 parameters1 arguments0 arguments1 +%type word argument arguments0 arguments1 %type script_init script %type grubcmd ifclause ifcmd forcmd whilecmd untilcmd @@ -236,22 +236,7 @@ arguments1: argument arguments0 } ; -parameters1: argument parameters0 - { - if ($1 && $2) - { - $1->next = $2; - $1->argcount += $2->argcount; - $2->argcount = 0; - } - $$ = $1; - } -; -parameters0: /* Empty */ { $$ = 0; } - | parameters1 { $$ = $1; } -; - -grubcmd: word parameters0 block0 +grubcmd: word arguments0 block0 { struct grub_script_arglist *x = $2; From 1a60d363b0808700bfaa8b475852c5063eda7f21 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 22 Jul 2010 23:22:36 +0530 Subject: [PATCH 34/34] 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; }