# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: address@hidden # target_branch: ../cmdlist/ # testament_sha1: bd241888d9f50f96d4ac8e8a3349ab1715b244f1 # timestamp: 2010-06-10 20:58:07 +0530 # base_revision_id: address@hidden # qr58e8hf6tmt6xkm # # Begin patch === modified file 'commands/acpi.c' --- commands/acpi.c 2010-01-05 21:04:15 +0000 +++ commands/acpi.c 2010-06-10 06:42:03 +0000 @@ -456,10 +456,9 @@ } 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; === modified file 'commands/echo.c' --- commands/echo.c 2010-01-03 18:24:22 +0000 +++ commands/echo.c 2010-06-10 06:42:03 +0000 @@ -30,9 +30,9 @@ }; 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; === modified file 'commands/extcmd.c' --- commands/extcmd.c 2009-07-16 22:14:09 +0000 +++ commands/extcmd.c 2010-06-10 06:42:03 +0000 @@ -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 @@ 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 @@ 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 @@ 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) { === modified file 'commands/hashsum.c' --- commands/hashsum.c 2010-05-01 18:28:07 +0000 +++ commands/hashsum.c 2010-06-10 06:42:03 +0000 @@ -165,10 +165,10 @@ } 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 @@ 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; === modified file 'commands/hdparm.c' --- commands/hdparm.c 2010-01-03 18:24:22 +0000 +++ commands/hdparm.c 2010-06-10 06:42:03 +0000 @@ -270,9 +270,9 @@ } 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) === modified file 'commands/help.c' --- commands/help.c 2010-05-01 19:31:45 +0000 +++ commands/help.c 2010-06-10 06:42:03 +0000 @@ -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; === modified file 'commands/hexdump.c' --- commands/hexdump.c 2010-01-03 22:05:07 +0000 +++ commands/hexdump.c 2010-06-10 06:42:03 +0000 @@ -34,9 +34,9 @@ }; 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; === modified file 'commands/i386/cpuid.c' --- commands/i386/cpuid.c 2010-01-03 18:24:22 +0000 +++ commands/i386/cpuid.c 2010-06-10 06:42:03 +0000 @@ -43,7 +43,7 @@ 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))) { === modified file 'commands/i386/pc/drivemap.c' --- commands/i386/pc/drivemap.c 2010-05-01 18:28:07 +0000 +++ commands/i386/pc/drivemap.c 2010-06-10 06:42:03 +0000 @@ -196,13 +196,13 @@ } 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 @@ 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 @@ } /* 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; } === modified file 'commands/i386/pc/halt.c' --- commands/i386/pc/halt.c 2010-01-03 22:05:07 +0000 +++ commands/i386/pc/halt.c 2010-06-10 06:42:03 +0000 @@ -29,12 +29,12 @@ }; 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; === modified file 'commands/iorw.c' --- commands/iorw.c 2010-05-01 18:28:07 +0000 +++ commands/iorw.c 2010-06-10 06:42:03 +0000 @@ -36,7 +36,7 @@ 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 @@ 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 @@ 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); === modified file 'commands/keystatus.c' --- commands/keystatus.c 2010-01-05 15:27:41 +0000 +++ commands/keystatus.c 2010-06-10 06:42:03 +0000 @@ -34,11 +34,11 @@ #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; === modified file 'commands/loadenv.c' --- commands/loadenv.c 2010-02-06 17:43:37 +0000 +++ commands/loadenv.c 2010-06-10 06:42:03 +0000 @@ -111,11 +111,11 @@ } 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 @@ } 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 @@ } 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; === modified file 'commands/ls.c' --- commands/ls.c 2010-02-06 19:52:11 +0000 +++ commands/ls.c 2010-06-10 06:42:03 +0000 @@ -248,9 +248,9 @@ } 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); === modified file 'commands/lspci.c' --- commands/lspci.c 2010-01-20 19:40:30 +0000 +++ commands/lspci.c 2010-06-10 06:42:03 +0000 @@ -211,11 +211,11 @@ } 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; } === modified file 'commands/memrw.c' --- commands/memrw.c 2010-01-20 06:36:17 +0000 +++ commands/memrw.c 2010-06-10 06:42:03 +0000 @@ -35,7 +35,7 @@ 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 @@ 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 @@ 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); === modified file 'commands/probe.c' --- commands/probe.c 2010-01-03 18:24:22 +0000 +++ commands/probe.c 2010-06-10 06:42:03 +0000 @@ -45,9 +45,9 @@ }; 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; === modified file 'commands/search_wrap.c' --- commands/search_wrap.c 2009-12-25 22:06:52 +0000 +++ commands/search_wrap.c 2010-06-10 06:42:03 +0000 @@ -50,9 +50,9 @@ }; 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) === modified file 'commands/setpci.c' --- commands/setpci.c 2010-05-01 18:28:07 +0000 +++ commands/setpci.c 2010-06-10 06:42:03 +0000 @@ -155,7 +155,7 @@ } 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 @@ 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 @@ 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 @@ } } - if (cmd->state[2].set) - varname = cmd->state[2].arg; + if (ctxt->state[2].set) + varname = ctxt->state[2].arg; else varname = NULL; === modified file 'commands/sleep.c' --- commands/sleep.c 2010-02-07 02:06:33 +0000 +++ commands/sleep.c 2010-06-10 06:42:03 +0000 @@ -60,9 +60,9 @@ } 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) === modified file 'disk/loopback.c' --- disk/loopback.c 2010-02-07 02:06:33 +0000 +++ disk/loopback.c 2010-06-10 06:42:03 +0000 @@ -71,9 +71,9 @@ /* 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; === modified file 'hello/hello.c' --- hello/hello.c 2010-01-03 18:50:51 +0000 +++ hello/hello.c 2010-06-10 15:19:57 +0000 @@ -26,12 +26,29 @@ #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_put (script); + + script = grub_script_get (ctxt->script_params[0]); + } + return 0; } @@ -39,11 +56,16 @@ GRUB_MOD_INIT(hello) { - cmd = grub_register_extcmd ("hello", grub_cmd_hello, GRUB_COMMAND_FLAG_BOTH, - 0, N_("Say \"Hello World\"."), 0); + cmd = grub_register_extcmd ("hello", grub_cmd_hello, + GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS, + N_("[BLOCK]"), N_("Say \"Hello World\"."), 0); } GRUB_MOD_FINI(hello) { + if (script) + grub_script_put (script); + + script = 0; grub_unregister_extcmd (cmd); } === modified file 'include/grub/command.h' --- include/grub/command.h 2009-05-04 20:06:05 +0000 +++ include/grub/command.h 2010-06-10 06:42:03 +0000 @@ -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; === modified file 'include/grub/extcmd.h' --- include/grub/extcmd.h 2009-03-21 08:39:59 +0000 +++ include/grub/extcmd.h 2010-06-10 06:42:03 +0000 @@ -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,10 +40,20 @@ const struct grub_arg_option *options; void *data; +}; +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 *grub_extcmd_t; +typedef struct grub_extcmd_context *grub_extcmd_context_t; grub_extcmd_t grub_register_extcmd (const char *name, grub_extcmd_func_t func, @@ -52,4 +64,8 @@ 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 */ === modified file 'include/grub/script_sh.h' --- include/grub/script_sh.h 2010-05-19 04:55:41 +0000 +++ include/grub/script_sh.h 2010-06-10 15:19:57 +0000 @@ -39,6 +39,7 @@ struct grub_script { + unsigned refcnt; struct grub_script_mem *mem; struct grub_script_cmd *cmd; }; @@ -49,7 +50,8 @@ 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 +61,9 @@ char *str; + /* Parsed block argument. */ + struct grub_script *block; + /* Next argument part. */ struct grub_script_arg *next; }; @@ -68,6 +73,7 @@ { unsigned argc; char **args; + struct grub_script **scripts; }; /* A complete argument. It consists of a list of one or more `struct @@ -222,10 +228,14 @@ 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); 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); @@ -283,8 +293,8 @@ 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 *); @@ -347,4 +357,20 @@ 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 */ === modified file 'loader/i386/bsd.c' --- loader/i386/bsd.c 2010-03-26 14:44:13 +0000 +++ loader/i386/bsd.c 2010-06-10 06:42:03 +0000 @@ -946,10 +946,10 @@ } 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 @@ } 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 @@ } 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; === modified file 'loader/xnu.c' --- loader/xnu.c 2010-02-07 03:23:44 +0000 +++ loader/xnu.c 2010-06-10 06:42:03 +0000 @@ -1368,15 +1368,15 @@ }; 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 === modified file 'script/argv.c' --- script/argv.c 2010-05-21 10:04:36 +0000 +++ script/argv.c 2010-06-10 15:19:57 +0000 @@ -52,8 +52,18 @@ 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. */ @@ -61,20 +71,33 @@ 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 +123,18 @@ 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) === modified file 'script/execute.c' --- script/execute.c 2010-05-21 10:13:24 +0000 +++ script/execute.c 2010-06-10 15:19:57 +0000 @@ -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 @@ 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 @@ 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) { @@ -195,6 +196,12 @@ grub_free (values); 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)) @@ -269,7 +276,7 @@ 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)) @@ -313,7 +320,14 @@ /* 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); @@ -373,7 +387,7 @@ { 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)) @@ -415,7 +429,7 @@ 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; === modified file 'script/lexer.c' --- script/lexer.c 2010-02-11 13:19:57 +0000 +++ script/lexer.c 2010-04-29 12:40:22 +0000 @@ -38,68 +38,57 @@ } /* 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->record++; + if (lexer->recording) + return lexer->recordpos; + lexer->recordpos = 0; - if (lexer->recording) /* reuse last record */ - return; - 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) + return 0; + + lexer->record--; + if (!lexer->recording) + return 0; + + 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 || !lexer->recording) - return 0; - - /* XXX This is not necessary in BASH. */ - - 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); - + 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 @@ 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; } === modified file 'script/parser.y' --- script/parser.y 2010-05-05 08:35:06 +0000 +++ script/parser.y 2010-06-10 15:19:57 +0000 @@ -33,6 +33,10 @@ struct grub_script_arglist *arglist; struct grub_script_arg *arg; char *string; + struct { + unsigned offset; + struct grub_script_mem *memory; + }; } %token GRUB_PARSER_TOKEN_BAD @@ -73,7 +77,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 @@ -144,6 +148,31 @@ | word { $$ = $1; } ; +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; + + 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_mem_free (memory); + + $$ = grub_script_add_arglist (state, 0, arg); + grub_script_lexer_deref (state->lexerstate); + } +; + arguments0: /* Empty */ { $$ = 0; } | arguments1 { $$ = $1; } ; @@ -159,7 +188,32 @@ } ; -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; @@ -200,8 +254,10 @@ 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); } @@ -213,14 +269,16 @@ } 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); } ; === modified file 'script/script.c' --- script/script.c 2010-05-05 08:35:06 +0000 +++ script/script.c 2010-06-10 15:19:57 +0000 @@ -54,7 +54,7 @@ } /* Free all memory described by MEM. */ -static void +void grub_script_mem_free (struct grub_script_mem *mem) { struct grub_script_mem *memfree; @@ -96,7 +96,10 @@ { if (!script) return; - grub_script_mem_free (script->mem); + + if (script->mem) + grub_script_mem_free (script->mem); + grub_free (script); } @@ -119,6 +122,8 @@ return arg; argpart->type = type; + argpart->block = 0; + len = grub_strlen (str) + 1; argpart->str = grub_script_malloc (state, len); if (!argpart->str) @@ -335,16 +340,12 @@ 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; } @@ -359,7 +360,7 @@ 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; === modified file 'term/gfxterm.c' --- term/gfxterm.c 2010-05-01 18:28:07 +0000 +++ term/gfxterm.c 2010-06-10 06:42:03 +0000 @@ -1091,11 +1091,10 @@ }; 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) === modified file 'term/serial.c' --- term/serial.c 2010-05-01 18:28:07 +0000 +++ term/serial.c 2010-06-10 06:42:03 +0000 @@ -497,11 +497,11 @@ 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; === modified file 'tests/lib/functional_test.c' --- tests/lib/functional_test.c 2010-01-17 17:29:57 +0000 +++ tests/lib/functional_test.c 2010-06-10 06:42:03 +0000 @@ -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))) { # Begin bundle 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 UJAXBjjn