Support for passing block of commands as an argument to

extcmds.

	* Makefile.util.def: Rules for new test.
	* tests/grub_script_blockarg.in: New test.
	* grub-core/tests/test_blockarg.c: New file, block argument
	command used in the test.

	* include/grub/extcmd.h (grub_extcmd_context): New struct.
	(grub_register_extcmd_prio): New function prototype.
	(grub_extcmd_dispatcher): New function prototype.
	* include/grub/command.h (GRUB_COMMAND_FLAG_BLOCKS): New command
	type.
	* include/grub/script_sh.h (struct grub_script): New members
	`children', `next_siblings' and `refcnt' for block arguments and
	reference counting.
	(GRUB_SCRIPT_ARG_TYPE_BLOCK): New argument type.
	(grub_script_arg): New member `script' for block argument.
	(grub_script_argv): New member `script' for block argument.
	(grub_parser_param): New member `scripts' for block argument.
	(grub_script_mem_free): New extern function prototype.
	(grub_script_ref): New function prototype.
	(grub_script_unref): New function prototype.

	* grub-core/normal/dyncmd.c (grub_dyncmd_dispatcher): Moved to
	extcmd form to support block arguments.
	* grub-core/script/argv.c: Block arguments support.
	* grub-core/script/execute.c: Likewise.
	* grub-core/script/lexer.c: Likewise.
	* grub-core/script/main.c: Likewise.
	* grub-core/script/script.c: Likewise.
	* grub-core/script/parser.y: Likewise.  New `block' and `block0'
	non-terminals.

	* grub-core/commands/acpi.c: Update extcmd implementations with
	grub_extcmd_context_t.
	* grub-core/commands/cat.c: Likewise.
	* grub-core/commands/echo.c: Likewise.
	* grub-core/commands/extcmd.c: Likewise.
	* grub-core/commands/hashsum.c: Likewise.
	* grub-core/commands/hdparm.c: Likewise.
	* grub-core/commands/help.c: Likewise.
	* grub-core/commands/hexdump.c: Likewise.
	* grub-core/commands/i386/cpuid.c: Likewise.
	* grub-core/commands/i386/pc/drivemap.c: Likewise.
	* grub-core/commands/i386/pc/halt.c: Likewise.
	* grub-core/commands/i386/pc/sendkey.c: Likewise.
	* grub-core/commands/iorw.c: Likewise.
	* grub-core/commands/keystatus.c: Likewise.
	* grub-core/commands/loadenv.c: Likewise.
	* grub-core/commands/ls.c: Likewise.
	* grub-core/commands/lspci.c: Likewise.
	* grub-core/commands/memrw.c: Likewise.
	* grub-core/commands/probe.c: Likewise.
	* grub-core/commands/search_wrap.c: Likewise.
	* grub-core/commands/setpci.c: Likewise.
	* grub-core/commands/sleep.c: Likewise.
	* grub-core/disk/loopback.c: Likewise.
	* grub-core/hello/hello.c: Likewise.
	* grub-core/loader/i386/bsd.c: Likewise.
	* grub-core/loader/xnu.c: Likewise.
	* grub-core/term/gfxterm.c: Likewise.
	* grub-core/term/serial.c: Likewise.
	* grub-core/tests/lib/functional_test.c: Likewise.
This commit is contained in:
BVK Chaitanya 2010-09-04 09:13:30 +05:30
commit 37e7bf68c5
44 changed files with 573 additions and 189 deletions

View file

@ -1,3 +1,69 @@
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
Support for passing block of commands as an argument to extcmds.
* Makefile.util.def: Rules for new test.
* tests/grub_script_blockarg.in: New test.
* grub-core/tests/test_blockarg.c: New file, block argument
command used in the test.
* include/grub/extcmd.h (grub_extcmd_context): New struct.
(grub_register_extcmd_prio): New function prototype.
(grub_extcmd_dispatcher): New function prototype.
* include/grub/command.h (GRUB_COMMAND_FLAG_BLOCKS): New command
type.
* include/grub/script_sh.h (struct grub_script): New members
`children', `next_siblings' and `refcnt' for block arguments and
reference counting.
(GRUB_SCRIPT_ARG_TYPE_BLOCK): New argument type.
(grub_script_arg): New member `script' for block argument.
(grub_script_argv): New member `script' for block argument.
(grub_parser_param): New member `scripts' for block argument.
(grub_script_mem_free): New extern function prototype.
(grub_script_ref): New function prototype.
(grub_script_unref): New function prototype.
* grub-core/normal/dyncmd.c (grub_dyncmd_dispatcher): Moved to
extcmd form to support block arguments.
* grub-core/script/argv.c: Block arguments support.
* grub-core/script/execute.c: Likewise.
* grub-core/script/lexer.c: Likewise.
* grub-core/script/main.c: Likewise.
* grub-core/script/script.c: Likewise.
* grub-core/script/parser.y: Likewise. New `block' and `block0'
non-terminals.
* grub-core/commands/acpi.c: Update extcmd implementations with
grub_extcmd_context_t.
* grub-core/commands/cat.c: Likewise.
* grub-core/commands/echo.c: Likewise.
* grub-core/commands/extcmd.c: Likewise.
* grub-core/commands/hashsum.c: Likewise.
* grub-core/commands/hdparm.c: Likewise.
* grub-core/commands/help.c: Likewise.
* grub-core/commands/hexdump.c: Likewise.
* grub-core/commands/i386/cpuid.c: Likewise.
* grub-core/commands/i386/pc/drivemap.c: Likewise.
* grub-core/commands/i386/pc/halt.c: Likewise.
* grub-core/commands/i386/pc/sendkey.c: Likewise.
* grub-core/commands/iorw.c: Likewise.
* grub-core/commands/keystatus.c: Likewise.
* grub-core/commands/loadenv.c: Likewise.
* grub-core/commands/ls.c: Likewise.
* grub-core/commands/lspci.c: Likewise.
* grub-core/commands/memrw.c: Likewise.
* grub-core/commands/probe.c: Likewise.
* grub-core/commands/search_wrap.c: Likewise.
* grub-core/commands/setpci.c: Likewise.
* grub-core/commands/sleep.c: Likewise.
* grub-core/disk/loopback.c: Likewise.
* grub-core/hello/hello.c: Likewise.
* grub-core/loader/i386/bsd.c: Likewise.
* grub-core/loader/xnu.c: Likewise.
* grub-core/term/gfxterm.c: Likewise.
* grub-core/term/serial.c: Likewise.
* grub-core/tests/lib/functional_test.c: Likewise.
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com> 2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
Multi-line quoted strings support. Multi-line quoted strings support.

View file

@ -501,6 +501,12 @@ script = {
common = tests/grub_script_shift.in; common = tests/grub_script_shift.in;
}; };
script = {
testcase;
name = grub_script_blockarg;
common = tests/grub_script_blockarg.in;
};
program = { program = {
testcase; testcase;
name = example_unit_test; name = example_unit_test;

View file

@ -1380,3 +1380,8 @@ module = {
name = datehook; name = datehook;
common = hook/datehook.c; common = hook/datehook.c;
}; };
module = {
name = test_blockarg;
common = tests/test_blockarg.c;
};

View file

@ -458,10 +458,9 @@ free_tables (void)
} }
static grub_err_t static grub_err_t
grub_cmd_acpi (struct grub_extcmd *cmd, grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
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 grub_acpi_rsdp_v10 *rsdp;
struct efiemu_acpi_table *cur, *t; struct efiemu_acpi_table *cur, *t;
grub_err_t err; grub_err_t err;

View file

@ -33,9 +33,9 @@ static const struct grub_arg_option options[] =
}; };
static grub_err_t static grub_err_t
grub_cmd_cat (grub_extcmd_t cmd, int argc, char **args) grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args)
{ {
struct grub_arg_list *state = cmd->state; struct grub_arg_list *state = ctxt->state;
int dos = 0; int dos = 0;
grub_file_t file; grub_file_t file;
char buf[GRUB_DISK_SECTOR_SIZE]; char buf[GRUB_DISK_SECTOR_SIZE];

View file

@ -30,9 +30,9 @@ static const struct grub_arg_option options[] =
}; };
static grub_err_t 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 newline = 1;
int i; int i;

View file

@ -21,20 +21,31 @@
#include <grub/list.h> #include <grub/list.h>
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/extcmd.h> #include <grub/extcmd.h>
#include <grub/script_sh.h>
static grub_err_t grub_err_t
grub_extcmd_dispatcher (struct grub_command *cmd, grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args,
int argc, char **args) struct grub_script *script)
{ {
int new_argc; int new_argc;
char **new_args; char **new_args;
struct grub_arg_option *parser; struct grub_arg_option *parser;
struct grub_arg_list *state; struct grub_arg_list *state;
struct grub_extcmd_context context;
int maxargs = 0; int maxargs = 0;
grub_err_t ret; grub_err_t ret;
grub_extcmd_t ext; grub_extcmd_t ext = cmd->data;
context.state = 0;
context.extcmd = ext;
context.script = script;
if (! ext->options)
{
ret = (ext->func) (&context, argc, args);
return ret;
}
ext = cmd->data;
parser = (struct grub_arg_option *) ext->options; parser = (struct grub_arg_option *) ext->options;
while (parser && (parser++)->doc) while (parser && (parser++)->doc)
maxargs++; maxargs++;
@ -44,8 +55,8 @@ grub_extcmd_dispatcher (struct grub_command *cmd,
if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc)) if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc))
{ {
ext->state = state; context.state = state;
ret = (ext->func) (ext, new_argc, new_args); ret = (ext->func) (&context, new_argc, new_args);
grub_free (new_args); grub_free (new_args);
} }
else else
@ -56,11 +67,18 @@ grub_extcmd_dispatcher (struct grub_command *cmd,
return ret; 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_extcmd_t
grub_register_extcmd (const char *name, grub_extcmd_func_t func, grub_register_extcmd_prio (const char *name, grub_extcmd_func_t func,
unsigned flags, const char *summary, unsigned flags, const char *summary,
const char *description, const char *description,
const struct grub_arg_option *parser) const struct grub_arg_option *parser,
int prio)
{ {
grub_extcmd_t ext; grub_extcmd_t ext;
grub_command_t cmd; grub_command_t cmd;
@ -69,8 +87,8 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func,
if (! ext) if (! ext)
return 0; return 0;
cmd = grub_register_command_prio (name, grub_extcmd_dispatcher, cmd = grub_register_command_prio (name, grub_extcmd_dispatch,
summary, description, 1); summary, description, prio);
if (! cmd) if (! cmd)
{ {
grub_free (ext); grub_free (ext);
@ -88,6 +106,16 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func,
return ext; 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 void
grub_unregister_extcmd (grub_extcmd_t ext) grub_unregister_extcmd (grub_extcmd_t ext)
{ {

View file

@ -165,10 +165,10 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
} }
static grub_err_t static grub_err_t
grub_cmd_hashsum (struct grub_extcmd *cmd, grub_cmd_hashsum (struct grub_extcmd_context *ctxt,
int argc, char **args) int argc, char **args)
{ {
struct grub_arg_list *state = cmd->state; struct grub_arg_list *state = ctxt->state;
const char *hashname = NULL; const char *hashname = NULL;
const char *prefix = NULL; const char *prefix = NULL;
const gcry_md_spec_t *hash; const gcry_md_spec_t *hash;
@ -177,7 +177,7 @@ grub_cmd_hashsum (struct grub_extcmd *cmd,
unsigned unread = 0; unsigned unread = 0;
for (i = 0; i < ARRAY_SIZE (aliases); i++) 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; hashname = aliases[i].hashname;
if (state[0].set) if (state[0].set)
hashname = state[0].arg; hashname = state[0].arg;

View file

@ -270,9 +270,9 @@ static int get_int_arg (const struct grub_arg_list *state)
} }
static grub_err_t 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. */ /* Check command line. */
if (argc != 1) if (argc != 1)

View file

@ -27,7 +27,7 @@
#include <grub/charset.h> #include <grub/charset.h>
static grub_err_t 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) char **args)
{ {
int cnt = 0; int cnt = 0;
@ -112,7 +112,8 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc,
if (cnt++ > 0) if (cnt++ > 0)
grub_printf ("\n\n"); grub_printf ("\n\n");
if (cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) if ((cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) &&
! (cmd->flags & GRUB_COMMAND_FLAG_DYNCMD))
grub_arg_show_help ((grub_extcmd_t) cmd->data); grub_arg_show_help ((grub_extcmd_t) cmd->data);
else else
grub_printf ("%s %s %s\n%s\n", _("Usage:"), cmd->name, _(cmd->summary), grub_printf ("%s %s %s\n%s\n", _("Usage:"), cmd->name, _(cmd->summary),

View file

@ -34,9 +34,9 @@ static const struct grub_arg_option options[] = {
}; };
static grub_err_t 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]; char buf[GRUB_DISK_SECTOR_SIZE * 4];
grub_ssize_t size, length; grub_ssize_t size, length;
grub_disk_addr_t skip; grub_disk_addr_t skip;

View file

@ -43,7 +43,7 @@ static const struct grub_arg_option options[] =
unsigned char grub_cpuid_has_longmode = 0; unsigned char grub_cpuid_has_longmode = 0;
static grub_err_t 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)), int argc __attribute__ ((unused)),
char **args __attribute__ ((unused))) char **args __attribute__ ((unused)))
{ {

View file

@ -196,13 +196,13 @@ list_mappings (void)
} }
static grub_err_t 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 (); 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. */ /* Reset: just delete all mappings, freeing their memory. */
drivemap_node_t *curnode = map_head; drivemap_node_t *curnode = map_head;
@ -216,7 +216,7 @@ grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args)
map_head = 0; map_head = 0;
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
else if (!cmd->state[OPTIDX_SWAP].set && argc == 0) else if (!ctxt->state[OPTIDX_SWAP].set && argc == 0)
{ {
/* No arguments */ /* No arguments */
return list_mappings (); 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). */ /* Set the mapping for the disk (overwrites any existing mapping). */
grub_dprintf ("drivemap", "%s %s (%02x) = %s (%02x)\n", 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); args[1], mapto, args[0], mapfrom);
err = drivemap_set (mapto, mapfrom); err = drivemap_set (mapto, mapfrom);
/* If -s, perform the reverse mapping too (only if the first was OK). */ /* 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); err = drivemap_set (mapfrom, mapto);
return err; return err;
} }

View file

@ -93,12 +93,12 @@ grub_halt (int no_apm)
} }
static grub_err_t static grub_err_t
grub_cmd_halt (grub_extcmd_t cmd, grub_cmd_halt (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)), int argc __attribute__ ((unused)),
char **args __attribute__ ((unused))) char **args __attribute__ ((unused)))
{ {
struct grub_arg_list *state = cmd->state; struct grub_arg_list *state = ctxt->state;
int no_apm = 0; int no_apm = 0;
if (state[0].set) if (state[0].set)
no_apm = 1; no_apm = 1;

View file

@ -284,9 +284,9 @@ grub_sendkey_preboot (int noret __attribute__ ((unused)))
} }
static grub_err_t static grub_err_t
grub_cmd_sendkey (grub_extcmd_t cmd, int argc, char **args) grub_cmd_sendkey (grub_extcmd_context_t ctxt, int argc, char **args)
{ {
struct grub_arg_list *state = cmd->state; struct grub_arg_list *state = ctxt->state;
auto int find_key_code (char *key); auto int find_key_code (char *key);
auto int find_ascii_code (char *key); auto int find_ascii_code (char *key);

View file

@ -36,7 +36,7 @@ static const struct grub_arg_option options[] =
static grub_err_t 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_target_addr_t addr;
grub_uint32_t value = 0; 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"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments");
addr = grub_strtoul (argv[0], 0, 0); addr = grub_strtoul (argv[0], 0, 0);
switch (cmd->cmd->name[sizeof ("in") - 1]) switch (ctxt->extcmd->cmd->name[sizeof ("in") - 1])
{ {
case 'l': case 'l':
value = grub_inl (addr); value = grub_inl (addr);
@ -61,10 +61,10 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
break; break;
} }
if (cmd->state[0].set) if (ctxt->state[0].set)
{ {
grub_snprintf (buf, sizeof (buf), "%x", value); grub_snprintf (buf, sizeof (buf), "%x", value);
grub_env_set (cmd->state[0].arg, buf); grub_env_set (ctxt->state[0].arg, buf);
} }
else else
grub_printf ("0x%x\n", value); grub_printf ("0x%x\n", value);

View file

@ -34,11 +34,11 @@ static const struct grub_arg_option options[] =
#define grub_cur_term_input grub_term_get_current_input () #define grub_cur_term_input grub_term_get_current_input ()
static grub_err_t static grub_err_t
grub_cmd_keystatus (grub_extcmd_t cmd, grub_cmd_keystatus (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)), int argc __attribute__ ((unused)),
char **args __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 expect_mods = 0;
int mods; int mods;

View file

@ -111,11 +111,11 @@ read_envblk_file (grub_file_t file)
} }
static grub_err_t 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)), int argc __attribute__ ((unused)),
char **args __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_file_t file;
grub_envblk_t envblk; grub_envblk_t envblk;
@ -143,11 +143,11 @@ grub_cmd_load_env (grub_extcmd_t cmd,
} }
static grub_err_t 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)), int argc __attribute__ ((unused)),
char **args __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_file_t file;
grub_envblk_t envblk; grub_envblk_t envblk;
@ -280,9 +280,9 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
} }
static grub_err_t 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_file_t file;
grub_envblk_t envblk; grub_envblk_t envblk;
struct blocklist *head = 0; struct blocklist *head = 0;

View file

@ -248,9 +248,9 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
} }
static grub_err_t 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) if (argc == 0)
grub_ls_list_devices (state[0].set); grub_ls_list_devices (state[0].set);

View file

@ -211,11 +211,11 @@ grub_lspci_iter (grub_pci_device_t dev, grub_pci_id_t pciid)
} }
static grub_err_t static grub_err_t
grub_cmd_lspci (grub_extcmd_t cmd, grub_cmd_lspci (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)), int argc __attribute__ ((unused)),
char **args __attribute__ ((unused))) char **args __attribute__ ((unused)))
{ {
iospace = cmd->state[0].set; iospace = ctxt->state[0].set;
grub_pci_iterate (grub_lspci_iter); grub_pci_iterate (grub_lspci_iter);
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }

View file

@ -35,7 +35,7 @@ static const struct grub_arg_option options[] =
static grub_err_t 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_target_addr_t addr;
grub_uint32_t value = 0; 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"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments");
addr = grub_strtoul (argv[0], 0, 0); addr = grub_strtoul (argv[0], 0, 0);
switch (cmd->cmd->name[sizeof ("read_") - 1]) switch (ctxt->extcmd->cmd->name[sizeof ("read_") - 1])
{ {
case 'd': case 'd':
value = *((volatile grub_uint32_t *) addr); value = *((volatile grub_uint32_t *) addr);
@ -60,10 +60,10 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
break; break;
} }
if (cmd->state[0].set) if (ctxt->state[0].set)
{ {
grub_snprintf (buf, sizeof (buf), "%x", value); grub_snprintf (buf, sizeof (buf), "%x", value);
grub_env_set (cmd->state[0].arg, buf); grub_env_set (ctxt->state[0].arg, buf);
} }
else else
grub_printf ("0x%x\n", value); grub_printf ("0x%x\n", value);

View file

@ -45,9 +45,9 @@ static const struct grub_arg_option options[] =
}; };
static grub_err_t 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_device_t dev;
grub_fs_t fs; grub_fs_t fs;
char *ptr; char *ptr;

View file

@ -50,9 +50,9 @@ enum options
}; };
static grub_err_t 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; const char *var = 0;
if (argc == 0) if (argc == 0)

View file

@ -155,7 +155,7 @@ grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid)
} }
static grub_err_t 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; const char *ptr;
unsigned i; unsigned i;
@ -163,14 +163,14 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv)
pciid_check_value = 0; pciid_check_value = 0;
pciid_check_mask = 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); pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff);
if (grub_errno == GRUB_ERR_BAD_NUMBER) if (grub_errno == GRUB_ERR_BAD_NUMBER)
{ {
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
ptr = cmd->state[0].arg; ptr = ctxt->state[0].arg;
} }
else else
pciid_check_mask |= 0xffff; 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; check_bus = check_device = check_function = 0;
if (cmd->state[1].set) if (ctxt->state[1].set)
{ {
const char *optr; const char *optr;
ptr = cmd->state[1].arg; ptr = ctxt->state[1].arg;
optr = ptr; optr = ptr;
bus = grub_strtoul (ptr, (char **) &ptr, 16); bus = grub_strtoul (ptr, (char **) &ptr, 16);
if (grub_errno == GRUB_ERR_BAD_NUMBER) 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) if (ctxt->state[2].set)
varname = cmd->state[2].arg; varname = ctxt->state[2].arg;
else else
varname = NULL; varname = NULL;

View file

@ -60,9 +60,9 @@ grub_interruptible_millisleep (grub_uint32_t ms)
} }
static grub_err_t 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; int n;
if (argc != 1) if (argc != 1)

View file

@ -71,9 +71,9 @@ delete_loopback (const char *name)
/* The command to add and remove loopback devices. */ /* The command to add and remove loopback devices. */
static grub_err_t 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; grub_file_t file;
struct grub_loopback *newdev; struct grub_loopback *newdev;
grub_err_t ret; grub_err_t ret;

View file

@ -27,7 +27,7 @@
#include <grub/i18n.h> #include <grub/i18n.h>
static grub_err_t static grub_err_t
grub_cmd_hello (struct grub_extcmd *cmd __attribute__ ((unused)), grub_cmd_hello (grub_extcmd_context_t ctxt __attribute__ ((unused)),
int argc __attribute__ ((unused)), int argc __attribute__ ((unused)),
char **args __attribute__ ((unused))) char **args __attribute__ ((unused)))
{ {

View file

@ -1372,10 +1372,10 @@ grub_bsd_parse_flags (const struct grub_arg_list *state,
} }
static grub_err_t 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; 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) if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
{ {
@ -1429,16 +1429,16 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[])
} }
static grub_err_t 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; grub_uint32_t bootdev;
kernel_type = KERNEL_TYPE_OPENBSD; 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; int unit, part;
if (*(arg++) != 'w' || *(arg++) != 'd') if (*(arg++) != 'w' || *(arg++) != 'd')
return grub_error (GRUB_ERR_BAD_ARGUMENT, return grub_error (GRUB_ERR_BAD_ARGUMENT,
@ -1459,7 +1459,7 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
else else
bootdev = 0; bootdev = 0;
if (cmd->state[OPENBSD_SERIAL_ARG].set) if (ctxt->state[OPENBSD_SERIAL_ARG].set)
{ {
struct grub_openbsd_bootarg_console serial; struct grub_openbsd_bootarg_console serial;
char *ptr; char *ptr;
@ -1468,9 +1468,9 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
grub_memset (&serial, 0, sizeof (serial)); grub_memset (&serial, 0, sizeof (serial));
if (cmd->state[OPENBSD_SERIAL_ARG].arg) if (ctxt->state[OPENBSD_SERIAL_ARG].arg)
{ {
ptr = cmd->state[OPENBSD_SERIAL_ARG].arg; ptr = ctxt->state[OPENBSD_SERIAL_ARG].arg;
if (grub_memcmp (ptr, "com", sizeof ("com") - 1) != 0) if (grub_memcmp (ptr, "com", sizeof ("com") - 1) != 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, return grub_error (GRUB_ERR_BAD_ARGUMENT,
"only com0-com3 are supported"); "only com0-com3 are supported");
@ -1514,11 +1514,11 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
} }
static grub_err_t 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[])
{ {
grub_err_t err; grub_err_t err;
kernel_type = KERNEL_TYPE_NETBSD; 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) if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
{ {
@ -1551,15 +1551,15 @@ grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[])
grub_bsd_add_meta (NETBSD_BTINFO_BOOTPATH, bootpath, sizeof (bootpath)); grub_bsd_add_meta (NETBSD_BTINFO_BOOTPATH, bootpath, sizeof (bootpath));
} }
if (cmd->state[NETBSD_ROOT_ARG].set) if (ctxt->state[NETBSD_ROOT_ARG].set)
{ {
char root[GRUB_NETBSD_MAX_ROOTDEVICE_LEN]; char root[GRUB_NETBSD_MAX_ROOTDEVICE_LEN];
grub_memset (root, 0, sizeof (root)); grub_memset (root, 0, sizeof (root));
grub_strncpy (root, cmd->state[NETBSD_ROOT_ARG].arg, grub_strncpy (root, ctxt->state[NETBSD_ROOT_ARG].arg,
sizeof (root) - 1); sizeof (root) - 1);
grub_bsd_add_meta (NETBSD_BTINFO_ROOTDEVICE, root, sizeof (root)); grub_bsd_add_meta (NETBSD_BTINFO_ROOTDEVICE, root, sizeof (root));
} }
if (cmd->state[NETBSD_SERIAL_ARG].set) if (ctxt->state[NETBSD_SERIAL_ARG].set)
{ {
struct grub_netbsd_btinfo_serial serial; struct grub_netbsd_btinfo_serial serial;
char *ptr; char *ptr;
@ -1567,9 +1567,9 @@ grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[])
grub_memset (&serial, 0, sizeof (serial)); grub_memset (&serial, 0, sizeof (serial));
grub_strcpy (serial.devname, "com"); grub_strcpy (serial.devname, "com");
if (cmd->state[NETBSD_SERIAL_ARG].arg) if (ctxt->state[NETBSD_SERIAL_ARG].arg)
{ {
ptr = cmd->state[NETBSD_SERIAL_ARG].arg; ptr = ctxt->state[NETBSD_SERIAL_ARG].arg;
if (grub_memcmp (ptr, "com", sizeof ("com") - 1) == 0) if (grub_memcmp (ptr, "com", sizeof ("com") - 1) == 0)
{ {
ptr += sizeof ("com") - 1; ptr += sizeof ("com") - 1;

View file

@ -1364,15 +1364,15 @@ static const struct grub_arg_option xnu_splash_cmd_options[] =
}; };
static grub_err_t 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[]) int argc, char *args[])
{ {
grub_err_t err; grub_err_t err;
if (argc != 1) if (argc != 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
if (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set && if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set &&
grub_strcmp (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg, grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg,
"stretch") == 0) "stretch") == 0)
grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH; grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH;
else else

View file

@ -23,16 +23,21 @@
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/command.h> #include <grub/command.h>
#include <grub/normal.h> #include <grub/normal.h>
#include <grub/extcmd.h>
#include <grub/script_sh.h>
#include <grub/i18n.h> #include <grub/i18n.h>
static grub_err_t static grub_err_t
grub_dyncmd_dispatcher (struct grub_command *cmd, grub_dyncmd_dispatcher (struct grub_extcmd_context *ctxt,
int argc, char **args) int argc, char **args)
{ {
char *modname = cmd->data; char *modname;
grub_dl_t mod; grub_dl_t mod;
grub_err_t ret; grub_err_t ret;
grub_extcmd_t extcmd = ctxt->extcmd;
grub_command_t cmd = extcmd->cmd;
modname = extcmd->data;
mod = grub_dl_load (modname); mod = grub_dl_load (modname);
if (mod) if (mod)
{ {
@ -42,11 +47,17 @@ grub_dyncmd_dispatcher (struct grub_command *cmd,
grub_dl_ref (mod); grub_dl_ref (mod);
name = (char *) cmd->name; name = (char *) cmd->name;
grub_unregister_command (cmd); grub_unregister_extcmd (extcmd);
cmd = grub_command_find (name); cmd = grub_command_find (name);
if (cmd) if (cmd)
{
if (cmd->flags & GRUB_COMMAND_FLAG_BLOCKS &&
cmd->flags & GRUB_COMMAND_FLAG_EXTCMD)
ret = grub_extcmd_dispatcher (cmd, argc, args, ctxt->script);
else
ret = (cmd->func) (cmd, argc, args); ret = (cmd->func) (cmd, argc, args);
}
else else
ret = grub_errno; ret = grub_errno;
@ -81,13 +92,14 @@ read_command_list (const char *prefix)
for (ptr = grub_command_list; ptr; ptr = next) for (ptr = grub_command_list; ptr; ptr = next)
{ {
next = ptr->next; next = ptr->next;
if (ptr->func == grub_dyncmd_dispatcher) if (ptr->flags & GRUB_COMMAND_FLAG_DYNCMD)
{ {
if (last) if (last)
last->next = ptr->next; last->next = ptr->next;
else else
grub_command_list = ptr->next; grub_command_list = ptr->next;
grub_free (ptr); grub_free (ptr);
grub_free (ptr->data); /* extcmd struct */
} }
else else
last = ptr; last = ptr;
@ -96,7 +108,7 @@ read_command_list (const char *prefix)
for (;; grub_free (buf)) for (;; grub_free (buf))
{ {
char *p, *name, *modname; char *p, *name, *modname;
grub_command_t cmd; grub_extcmd_t cmd;
int prio = 0; int prio = 0;
buf = grub_file_getline (file); buf = grub_file_getline (file);
@ -139,16 +151,20 @@ read_command_list (const char *prefix)
continue; continue;
} }
cmd = grub_register_command_prio (name, cmd = grub_register_extcmd_prio (name,
grub_dyncmd_dispatcher, grub_dyncmd_dispatcher,
0, N_("not loaded"), prio); GRUB_COMMAND_FLAG_BLOCKS
| GRUB_COMMAND_FLAG_EXTCMD
| GRUB_COMMAND_FLAG_CMDLINE
| GRUB_COMMAND_FLAG_DYNCMD,
0, N_("not loaded"), 0,
prio);
if (! cmd) if (! cmd)
{ {
grub_free (name); grub_free (name);
grub_free (modname); grub_free (modname);
continue; continue;
} }
cmd->flags |= GRUB_COMMAND_FLAG_DYNCMD;
cmd->data = modname; cmd->data = modname;
/* Update the active flag. */ /* Update the active flag. */

View file

@ -18,6 +18,7 @@
*/ */
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/misc.h>
#include <grub/script_sh.h> #include <grub/script_sh.h>
/* Return nearest power of two that is >= v. */ /* Return nearest power of two that is >= v. */
@ -55,6 +56,7 @@ grub_script_argv_free (struct grub_script_argv *argv)
argv->argc = 0; argv->argc = 0;
argv->args = 0; argv->args = 0;
argv->script = 0;
} }
/* Prepare for next argc. */ /* Prepare for next argc. */
@ -63,7 +65,7 @@ grub_script_argv_next (struct grub_script_argv *argv)
{ {
char **p = argv->args; char **p = argv->args;
if (argv->args && argv->args[argv->argc - 1] == 0) if (argv->args && argv->argc && argv->args[argv->argc - 1] == 0)
return 0; return 0;
p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *))); p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *)));

View file

@ -25,6 +25,7 @@
#include <grub/menu.h> #include <grub/menu.h>
#include <grub/lib/arg.h> #include <grub/lib/arg.h>
#include <grub/normal.h> #include <grub/normal.h>
#include <grub/extcmd.h>
/* Max digits for a char is 3 (0xFF is 255), similarly for an int it /* 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. */ is sizeof (int) * 3, and one extra for a possible -ve sign. */
@ -104,7 +105,7 @@ grub_env_special (const char *name)
static char ** static char **
grub_script_env_get (const char *name, grub_script_arg_type_t type) 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)) if (grub_script_argv_next (&result))
goto fail; goto fail;
@ -222,7 +223,7 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
int i; int i;
char **values = 0; char **values = 0;
struct grub_script_arg *arg = 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) for (; arglist && arglist->arg; arglist = arglist->next)
{ {
@ -248,6 +249,14 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
grub_free (values); grub_free (values);
break; break;
case GRUB_SCRIPT_ARG_TYPE_BLOCK:
if (grub_script_argv_append (&result, "{") ||
grub_script_argv_append (&result, arg->str) ||
grub_script_argv_append (&result, "}"))
goto fail;
result.script = arg->script;
break;
case GRUB_SCRIPT_ARG_TYPE_TEXT: case GRUB_SCRIPT_ARG_TYPE_TEXT:
if (grub_strlen (arg->str) && if (grub_strlen (arg->str) &&
grub_script_argv_append (&result, arg->str)) grub_script_argv_append (&result, arg->str))
@ -325,7 +334,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
grub_script_function_t func = 0; grub_script_function_t func = 0;
char errnobuf[18]; char errnobuf[18];
char *cmdname; char *cmdname;
struct grub_script_argv argv = { 0, 0 }; struct grub_script_argv argv = { 0, 0, 0 };
/* Lookup the command. */ /* Lookup the command. */
if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0]) if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0])
@ -369,7 +378,14 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
/* Execute the GRUB command or function. */ /* Execute the GRUB command or function. */
if (grubcmd) if (grubcmd)
{
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.script);
else
ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1); ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1);
}
else else
ret = grub_script_function_call (func, argv.argc - 1, argv.args + 1); ret = grub_script_function_call (func, argv.argc - 1, argv.args + 1);
@ -429,8 +445,7 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
{ {
unsigned i; unsigned i;
grub_err_t result; 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; struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd;
if (grub_script_arglist_to_argv (cmdfor->words, &argv)) if (grub_script_arglist_to_argv (cmdfor->words, &argv))
@ -495,7 +510,7 @@ grub_err_t
grub_script_execute_menuentry (struct grub_script_cmd *cmd) grub_script_execute_menuentry (struct grub_script_cmd *cmd)
{ {
struct grub_script_cmd_menuentry *cmd_menuentry; 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; cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd;

View file

@ -38,63 +38,54 @@ grub_script_lexer_deref (struct grub_lexer_param *state)
} }
/* Start recording all characters passing through the lexer. */ /* Start recording all characters passing through the lexer. */
void unsigned
grub_script_lexer_record_start (struct grub_parser_param *parser) grub_script_lexer_record_start (struct grub_parser_param *parser)
{ {
struct grub_lexer_param *lexer = parser->lexerstate; struct grub_lexer_param *lexer = parser->lexerstate;
lexer->record = 1; lexer->record++;
lexer->recordpos = 0; if (lexer->recording)
if (lexer->recording) /* reuse last record */ return lexer->recordpos;
return;
lexer->recordpos = 0;
lexer->recordlen = GRUB_LEXER_INITIAL_RECORD_SIZE; lexer->recordlen = GRUB_LEXER_INITIAL_RECORD_SIZE;
lexer->recording = grub_malloc (lexer->recordlen); lexer->recording = grub_malloc (lexer->recordlen);
if (!lexer->recording) if (!lexer->recording)
{ {
grub_script_yyerror (parser, 0); grub_script_yyerror (parser, 0);
lexer->record = 0;
lexer->recordlen = 0; lexer->recordlen = 0;
} }
return lexer->recordpos;
} }
char * 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; char *result;
struct grub_lexer_param *lexer = parser->lexerstate; struct grub_lexer_param *lexer = parser->lexerstate;
auto char *compact (char *start, char *end); if (!lexer->record)
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)
return 0; 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); count = lexer->recordpos - offset;
lexer->record = 0; 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; 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);
return result; return result;
} }
@ -106,7 +97,7 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str)
char *old; char *old;
struct grub_lexer_param *lexer = parser->lexerstate; struct grub_lexer_param *lexer = parser->lexerstate;
if (!lexer->record) if (!lexer->record || !lexer->recording)
return; return;
len = grub_strlen (str); len = grub_strlen (str);
@ -118,9 +109,8 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str)
if (!lexer->recording) if (!lexer->recording)
{ {
grub_free (old); grub_free (old);
lexer->record = 0;
lexer->recordpos = 0; lexer->recordpos = 0;
lexer->recordlen /= 2; lexer->recordlen = 0;
grub_script_yyerror (parser, 0); grub_script_yyerror (parser, 0);
return; return;
} }

View file

@ -35,7 +35,7 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline)
grub_script_execute (parsed_script); grub_script_execute (parsed_script);
/* The parsed script was executed, throw it away. */ /* The parsed script was executed, throw it away. */
grub_script_free (parsed_script); grub_script_unref (parsed_script);
} }
return grub_errno; return grub_errno;

View file

@ -20,6 +20,7 @@
%{ %{
#include <grub/script_sh.h> #include <grub/script_sh.h>
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/misc.h>
#define YYFREE grub_free #define YYFREE grub_free
#define YYMALLOC grub_malloc #define YYMALLOC grub_malloc
@ -34,6 +35,11 @@
struct grub_script_arglist *arglist; struct grub_script_arglist *arglist;
struct grub_script_arg *arg; struct grub_script_arg *arg;
char *string; char *string;
struct {
unsigned offset;
struct grub_script_mem *memory;
struct grub_script *scripts;
};
} }
%token GRUB_PARSER_TOKEN_BAD %token GRUB_PARSER_TOKEN_BAD
@ -74,6 +80,7 @@
%token <arg> GRUB_PARSER_TOKEN_NAME "name" %token <arg> GRUB_PARSER_TOKEN_NAME "name"
%token <arg> GRUB_PARSER_TOKEN_WORD "word" %token <arg> GRUB_PARSER_TOKEN_WORD "word"
%type <arg> block block0
%type <arglist> word argument arguments0 arguments1 %type <arglist> word argument arguments0 arguments1
%type <cmd> script_init script %type <cmd> script_init script
@ -146,6 +153,74 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); }
| word { $$ = $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);
$<offset>$ = grub_script_lexer_record_start (state);
$<memory>$ = grub_script_mem_record (state);
/* save currently known scripts. */
$<scripts>$ = state->scripts;
state->scripts = 0;
}
commands1 delimiters0 "}"
{
char *p;
struct grub_script_mem *memory;
struct grub_script *s = $<scripts>2;
memory = grub_script_mem_record_stop (state, $<memory>2);
if ((p = grub_script_lexer_record_stop (state, $<offset>2)))
*grub_strrchr (p, '}') = '\0';
$$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p);
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 = $<scripts>2 ?: $$->script;
if (s) {
while (s->next_siblings)
s = s->next_siblings;
s->next_siblings = $$->script;
}
}
grub_script_lexer_deref (state->lexerstate);
}
;
block0: /* Empty */ { $$ = 0; }
| block { $$ = $1; }
;
arguments0: /* Empty */ { $$ = 0; } arguments0: /* Empty */ { $$ = 0; }
| arguments1 { $$ = $1; } | arguments1 { $$ = $1; }
; ;
@ -161,12 +236,18 @@ arguments1: argument arguments0
} }
; ;
grubcmd: word arguments0 grubcmd: word arguments0 block0
{ {
if ($1 && $2) { struct grub_script_arglist *x = $2;
$1->next = $2;
$1->argcount += $2->argcount; if ($3)
$2->argcount = 0; 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); $$ = grub_script_create_cmdline (state, $1);
} }
@ -195,6 +276,9 @@ function: "function" "name"
{ {
grub_script_lexer_ref (state->lexerstate); grub_script_lexer_ref (state->lexerstate);
state->func_mem = grub_script_mem_record (state); state->func_mem = grub_script_mem_record (state);
$<scripts>$ = state->scripts;
state->scripts = 0;
} }
delimiters0 "{" commands1 delimiters1 "}" delimiters0 "{" commands1 delimiters1 "}"
{ {
@ -202,9 +286,14 @@ function: "function" "name"
state->func_mem = grub_script_mem_record_stop (state, state->func_mem = grub_script_mem_record_stop (state,
state->func_mem); state->func_mem);
script = grub_script_create ($6, state->func_mem); script = grub_script_create ($6, state->func_mem);
if (script) if (! script)
grub_script_mem_free (state->func_mem);
else {
script->children = state->scripts;
grub_script_function_create ($2, script); grub_script_function_create ($2, script);
}
state->scripts = $<scripts>3;
grub_script_lexer_deref (state->lexerstate); grub_script_lexer_deref (state->lexerstate);
} }
; ;
@ -215,14 +304,16 @@ menuentry: "menuentry"
} }
arguments1 arguments1
{ {
grub_script_lexer_record_start (state); $<offset>$ = grub_script_lexer_record_start (state);
} }
delimiters0 "{" commands1 delimiters1 "}" delimiters0 "{" commands1 delimiters1 "}"
{ {
char *menu_entry; char *def;
menu_entry = grub_script_lexer_record_stop (state); def = grub_script_lexer_record_stop (state, $<offset>4);
*grub_strrchr(def, '}') = '\0';
grub_script_lexer_deref (state->lexerstate); grub_script_lexer_deref (state->lexerstate);
$$ = grub_script_create_cmdmenu (state, $3, menu_entry, 0); $$ = grub_script_create_cmdmenu (state, $3, def, 0);
} }
; ;

View file

@ -54,7 +54,7 @@ grub_script_malloc (struct grub_parser_param *state, grub_size_t size)
} }
/* Free all memory described by MEM. */ /* Free all memory described by MEM. */
static void void
grub_script_mem_free (struct grub_script_mem *mem) grub_script_mem_free (struct grub_script_mem *mem)
{ {
struct grub_script_mem *memfree; struct grub_script_mem *memfree;
@ -94,9 +94,21 @@ grub_script_mem_record_stop (struct grub_parser_param *state,
void void
grub_script_free (struct grub_script *script) grub_script_free (struct grub_script *script)
{ {
struct grub_script *s;
struct grub_script *t;
if (! script) if (! script)
return; return;
if (script->mem)
grub_script_mem_free (script->mem); grub_script_mem_free (script->mem);
s = script->children;
while (s) {
t = s->next_siblings;
grub_script_unref (s);
s = t;
}
grub_free (script); grub_free (script);
} }
@ -119,6 +131,8 @@ grub_script_arg_add (struct grub_parser_param *state,
return arg; return arg;
argpart->type = type; argpart->type = type;
argpart->script = 0;
len = grub_strlen (str) + 1; len = grub_strlen (str) + 1;
argpart->str = grub_script_malloc (state, len); argpart->str = grub_script_malloc (state, len);
if (!argpart->str) if (!argpart->str)
@ -336,15 +350,13 @@ grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem)
parsed = grub_malloc (sizeof (*parsed)); parsed = grub_malloc (sizeof (*parsed));
if (! parsed) if (! parsed)
{
grub_script_mem_free (mem);
grub_free (cmd);
return 0; return 0;
}
parsed->mem = mem; parsed->mem = mem;
parsed->cmd = cmd; parsed->cmd = cmd;
parsed->refcnt = 0;
parsed->children = 0;
parsed->next_siblings = 0;
return parsed; return parsed;
} }
@ -359,7 +371,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline)
struct grub_lexer_param *lexstate; struct grub_lexer_param *lexstate;
struct grub_parser_param *parsestate; struct grub_parser_param *parsestate;
parsed = grub_malloc (sizeof (*parsed)); parsed = grub_script_create (0, 0);
if (!parsed) if (!parsed)
return 0; return 0;
@ -397,6 +409,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline)
parsed->mem = grub_script_mem_record_stop (parsestate, membackup); parsed->mem = grub_script_mem_record_stop (parsestate, membackup);
parsed->cmd = parsestate->parsed; parsed->cmd = parsestate->parsed;
parsed->children = parsestate->scripts;
grub_script_lexer_fini (lexstate); grub_script_lexer_fini (lexstate);
grub_free (parsestate); grub_free (parsestate);

View file

@ -1113,11 +1113,10 @@ static const struct grub_arg_option background_image_cmd_options[] =
}; };
static grub_err_t static grub_err_t
grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), grub_gfxterm_background_image_cmd (grub_extcmd_context_t ctxt,
int argc, int argc, char **args)
char **args)
{ {
struct grub_arg_list *state = cmd->state; struct grub_arg_list *state = ctxt->state;
/* Check that we have video adapter active. */ /* Check that we have video adapter active. */
if (grub_video_get_info(NULL) != GRUB_ERR_NONE) if (grub_video_get_info(NULL) != GRUB_ERR_NONE)

View file

@ -150,9 +150,9 @@ grub_serial_find (char *name)
} }
static grub_err_t static grub_err_t
grub_cmd_serial (grub_extcmd_t cmd, int argc, char **args) grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args)
{ {
struct grub_arg_list *state = cmd->state; struct grub_arg_list *state = ctxt->state;
char pname[40]; char pname[40];
char *name = NULL; char *name = NULL;
struct grub_serial_port *port; struct grub_serial_port *port;

View file

@ -22,7 +22,7 @@
#include <grub/test.h> #include <grub/test.h>
static grub_err_t 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)), int argc __attribute__ ((unused)),
char **args __attribute__ ((unused))) char **args __attribute__ ((unused)))
{ {

View file

@ -0,0 +1,51 @@
/* test_blockarg.c - print and execute block argument */
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/i18n.h>
#include <grub/extcmd.h>
#include <grub/script_sh.h>
static grub_err_t
test_blockarg (grub_extcmd_context_t ctxt, int argc, char **args)
{
if (! ctxt->script)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no block parameter");
grub_printf ("%s\n", args[argc - 1]);
grub_script_execute (ctxt->script);
return GRUB_ERR_NONE;
}
static grub_extcmd_t cmd;
GRUB_MOD_INIT(test_blockarg)
{
cmd = grub_register_extcmd ("test_blockarg", test_blockarg,
GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS,
N_("BLOCK"),
N_("Print and execute block argument."), 0);
}
GRUB_MOD_FINI(test_blockarg)
{
grub_unregister_extcmd (cmd);
}

View file

@ -37,6 +37,8 @@
#define GRUB_COMMAND_FLAG_EXTCMD 0x10 #define GRUB_COMMAND_FLAG_EXTCMD 0x10
/* This is an dynamic command. */ /* This is an dynamic command. */
#define GRUB_COMMAND_FLAG_DYNCMD 0x20 #define GRUB_COMMAND_FLAG_DYNCMD 0x20
/* This command accepts block arguments. */
#define GRUB_COMMAND_FLAG_BLOCKS 0x40
struct grub_command; struct grub_command;

View file

@ -21,10 +21,12 @@
#include <grub/lib/arg.h> #include <grub/lib/arg.h>
#include <grub/command.h> #include <grub/command.h>
#include <grub/script_sh.h>
struct grub_extcmd; 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); int argc, char **args);
/* The argcmd description. */ /* The argcmd description. */
@ -38,11 +40,21 @@ struct grub_extcmd
const struct grub_arg_option *options; const struct grub_arg_option *options;
void *data; void *data;
struct grub_arg_list *state;
}; };
typedef struct grub_extcmd *grub_extcmd_t; 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 parameter, if any. */
struct grub_script *script;
};
typedef struct grub_extcmd_context *grub_extcmd_context_t;
grub_extcmd_t grub_register_extcmd (const char *name, grub_extcmd_t grub_register_extcmd (const char *name,
grub_extcmd_func_t func, grub_extcmd_func_t func,
unsigned flags, unsigned flags,
@ -50,6 +62,18 @@ grub_extcmd_t grub_register_extcmd (const char *name,
const char *description, const char *description,
const struct grub_arg_option *parser); 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); 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 *script);
#endif /* ! GRUB_EXTCMD_HEADER */ #endif /* ! GRUB_EXTCMD_HEADER */

View file

@ -40,8 +40,13 @@ struct grub_script_cmd
struct grub_script struct grub_script
{ {
unsigned refcnt;
struct grub_script_mem *mem; struct grub_script_mem *mem;
struct grub_script_cmd *cmd; struct grub_script_cmd *cmd;
/* grub_scripts from block arguments. */
struct grub_script *next_siblings;
struct grub_script *children;
}; };
typedef enum typedef enum
@ -50,7 +55,8 @@ typedef enum
GRUB_SCRIPT_ARG_TYPE_TEXT, GRUB_SCRIPT_ARG_TYPE_TEXT,
GRUB_SCRIPT_ARG_TYPE_DQVAR, GRUB_SCRIPT_ARG_TYPE_DQVAR,
GRUB_SCRIPT_ARG_TYPE_DQSTR, 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; } grub_script_arg_type_t;
/* A part of an argument. */ /* A part of an argument. */
@ -60,6 +66,9 @@ struct grub_script_arg
char *str; char *str;
/* Parsed block argument. */
struct grub_script *script;
/* Next argument part. */ /* Next argument part. */
struct grub_script_arg *next; struct grub_script_arg *next;
}; };
@ -69,6 +78,7 @@ struct grub_script_argv
{ {
unsigned argc; unsigned argc;
char **args; char **args;
struct grub_script *script;
}; };
/* A complete argument. It consists of a list of one or more `struct /* A complete argument. It consists of a list of one or more `struct
@ -223,6 +233,9 @@ struct grub_parser_param
/* The memory that was used while parsing and scanning. */ /* The memory that was used while parsing and scanning. */
struct grub_script_mem *memused; struct grub_script_mem *memused;
/* The block argument scripts. */
struct grub_script *scripts;
/* The result of the parser. */ /* The result of the parser. */
struct grub_script_cmd *parsed; struct grub_script_cmd *parsed;
@ -232,6 +245,8 @@ struct grub_parser_param
void grub_script_init (void); void grub_script_init (void);
void grub_script_fini (void); void grub_script_fini (void);
void grub_script_mem_free (struct grub_script_mem *mem);
void grub_script_argv_free (struct grub_script_argv *argv); void grub_script_argv_free (struct grub_script_argv *argv);
int grub_script_argv_next (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_append (struct grub_script_argv *argv, const char *s);
@ -293,8 +308,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_fini (struct grub_lexer_param *);
void grub_script_lexer_ref (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_deref (struct grub_lexer_param *);
void grub_script_lexer_record_start (struct grub_parser_param *); unsigned grub_script_lexer_record_start (struct grub_parser_param *);
char *grub_script_lexer_record_stop (struct grub_parser_param *); char *grub_script_lexer_record_stop (struct grub_parser_param *, unsigned);
int grub_script_lexer_yywrap (struct grub_parser_param *, const char *input); int grub_script_lexer_yywrap (struct grub_parser_param *, const char *input);
void grub_script_lexer_record (struct grub_parser_param *, char *); void grub_script_lexer_record (struct grub_parser_param *, char *);
@ -371,4 +386,24 @@ grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *c
grub_err_t grub_err_t
grub_normal_parse_line (char *line, grub_reader_getline_t getline); grub_normal_parse_line (char *line, grub_reader_getline_t getline);
static inline struct grub_script *
grub_script_ref (struct grub_script *script)
{
if (script)
script->refcnt++;
return script;
}
static inline void
grub_script_unref (struct grub_script *script)
{
if (! script)
return;
if (script->refcnt == 0)
grub_script_free (script);
else
script->refcnt--;
}
#endif /* ! GRUB_NORMAL_PARSER_HEADER */ #endif /* ! GRUB_NORMAL_PARSER_HEADER */

View file

@ -0,0 +1,41 @@
#! /bin/bash
# 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 <http://www.gnu.org/licenses/>.
error_if_not () {
if test "$1" != "$2"; then
echo "[$1]" != "[$2]"
exit 1
fi
}
cmd='test_blockarg { true }'
v=`echo "$cmd" | @builddir@/grub-shell`
error_if_not "$v" '{ true }'
tmp=`mktemp`
cmd='test_blockarg { test_blockarg { true } }'
echo "$cmd" | @builddir@/grub-shell >$tmp
error_if_not "`head -n1 $tmp|tail -n1`" '{ test_blockarg { true } }'
error_if_not "`head -n2 $tmp|tail -n1`" '{ true }'
cmd='test_blockarg { test_blockarg { test_blockarg { true } }; test_blockarg { true } }'
echo "$cmd" | @builddir@/grub-shell >$tmp
error_if_not "`head -n1 $tmp|tail -n1`" '{ test_blockarg { test_blockarg { true } }; test_blockarg { true } }'
error_if_not "`head -n2 $tmp|tail -n1`" '{ test_blockarg { true } }'
error_if_not "`head -n3 $tmp|tail -n1`" '{ true }'
error_if_not "`head -n4 $tmp|tail -n1`" '{ true }'