2009-05-02 Bean <bean123ch@gmail.com>
* conf/common.rmk (grub_script.tab.c): Change normal/parser.y to script/sh/parser.y. (pkglib_MODULES): Add normal.mod and sh.mod. (normal_SOURCES): New variable. (normal_mod_CFLAGS): Likewise. (normal_mod_LDFLAGS): Likewise. (sh_mod_SOURCES): Likewise. (sh_mod_CFLAGS): Likewise. (sh_mod_LDFLAGS): Likewise. * conf/i386-pc.rmk (normal/lexer.c_DEPENDENCIES): Changed to script/sh/lexer.c_DEPENDENCIES. (kernel_img_SOURCES): Remove kern/rescue.c, and kern/reader.c, kern/rescue_reader.c and kern/rescue_parser.c. (kernel_img_HEADERS): Remove rescue.h, add reader.h. (grub_emu_SOURCES): Change source files. (pkglib_MODULES): Remove normal.mod. (normal_SOURCES): Removed. (normal_mod_CFLAGS): Likewise. (normal_mod_LDFLAGS): Likewise. * conf/i386-coreboot.rmk: Likewise. * conf/i386-efi.rmk: Likewise. * conf/i386-ieee1276.rmk: Likewise. * conf/powerpc-ieee1275.rmk: Likewise. * conf/sparc64-ieee1275.rmk: Likewise. * conf/x86_64-efi.rmk: Likewise. * include/grub/command.h (grub_command_execute): New inline function. * include/grub/menu.h (grub_menu_entry): Removed commands field. * include/grub/normal.h: Remove <grub/setjmp.h>. (grub_fs_module_list): Moved to normal/autofs.c. (grub_exit_env): Removed. (grub_command_execute): Likewise. (grub_normal_menu_addentry): Renamed to grub_menu_addentry, removed parameter script. (read_command_list): New function declaration. (read_fs_list): Likewise. * include/parser.h: Include <grub/reader.h>. (grub_parser_split_cmdline): Change type of getline parameter. (grub_parser): New structure. (grub_parser_class): New variable. (grub_parser_execute): New function declaration. (grub_register_rescue_parser): Likewise. (grub_parser_register): New inline function. (grub_parser_unregister): Likewise. (grub_parser_get_current): Likewise. (grub_parser_set_current): Likewise. * include/grub/reader.h: New file. * kern/reader.c: Likewise. * kern/rescue_parser.c: Likewise. * kern/rescue_reader.c: Likewise. * normal/autofs.c: Likewise. * normal/dyncmd.c: Likewise. * include/grub/rescue.h: Removed. * normal/command.h: Likewise. * include/grub/script.h: Moved to ... * include/grub/script_sh.h: ... Moved here. * normal/execute.c: Moved to ... * script/sh/execute.c: ... Moved here. * normal/function.c: Moved to ... * script/sh/function.c: ... Moved here. * normal/lexer.c: Moved to ... * script/sh/lexer.c: ... Moved here. * normal/parser.y: Moved to ... * script/sh/parser.y: ... Moved here. * normal/script.c: Moved to ... * script/sh/script.c: ... Moved here. * normal/main.c: Remove <grub/rescue.h> and <grub/script.h>, include <grub/reader.h>. (grub_exit_env): Removed. (fs_module_list): Moved to normal/autofs.c. (grub_file_getline): Don't handle comment here. (free_menu): Skip removed field entry->commands. (grub_normal_menu_addentry): Removed as grub_menu_entry, removed script parameter. (read_config_file): Removed nested parameter, change getline function. (grub_enter_normal_mode): Removed. (grub_dyncmd_dispatcher): Moved to normal/dyncmd.c. (read_command_list): Likewise. (autoload_fs_module): Moved to normal/autofs.c. (read_fs_list): Likewise. (reader_nested): New variable. (grub_normal_execute): Run parser.sh to switch to sh parser. (grub_cmd_rescue): Removed. (cmd_normal): Removed. (grub_cmd_normal): Unregister itself at the beginning. Don't register rescue command. (grub_cmdline_run): New function. (grub_normal_reader_init): Likewise. (grub_normal_read_line): Likewise. (grub_env_write_pager): Likewise. (cmdline): New variable. (grub_normal_reader): Likewise. (GRUB_MOD_INIT): Register normal reader and set as current, register pager hook, register normal command with grub_register_command_prio, so that it won't show up in command.lst. (GRUB_MOD_FINI): Unregister normal reader, unhook pager, clear grub_fs_autoload_hook. * normal/menu.c: Remove <grub/script.h>, add <grub/command.h>. (grub_menu_execute_entry): Replace grub_script_execute with grub_parser_execute, change parameter to grub_command_execute. * normal/menu_text.c: Remove <grub/script.h>. * normal/menu_entry.c: Remove <grub/script.h>, add <grub/command.h> and <grub/parser.h>. (run): Change editor_getline to use new parser interface. Change parameter to grub_command_execute. * kern/main.c: Remove <grub/rescue.h>, include <grub/command.h>, <grub/reader.h> and <grub/parser.h>. (grub_load_normal_mode): Execute normal command. (grub_main): Call grub_register_core_commands, grub_register_rescue_parser and grub_register_rescue_reader, use grub_reader_loop to enter input loop. * kern/parser.c (grub_parser_spli_cmdline): Change type of getline parameter. (grub_parser_class): New variable. (grub_parser_execute): New function. * loader/i386/multiboot.c: Remove <grub/rescue.h>. * loader/multiboot2.c: Likewise. * loader/sparc64/ieee1275/linux.c: Likewise. * util/grub-emu.c (read_command_list): New dummy function.
This commit is contained in:
parent
18db813d65
commit
d558e6b5ac
39 changed files with 1132 additions and 877 deletions
134
normal/autofs.c
Normal file
134
normal/autofs.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
/* autofs.c - support auto-loading from fs.lst */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2009 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/mm.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/normal.h>
|
||||
|
||||
/* This is used to store the names of filesystem modules for auto-loading. */
|
||||
struct grub_fs_module_list
|
||||
{
|
||||
char *name;
|
||||
struct grub_fs_module_list *next;
|
||||
};
|
||||
typedef struct grub_fs_module_list *grub_fs_module_list_t;
|
||||
|
||||
static grub_fs_module_list_t fs_module_list = 0;
|
||||
|
||||
/* The auto-loading hook for filesystems. */
|
||||
static int
|
||||
autoload_fs_module (void)
|
||||
{
|
||||
grub_fs_module_list_t p;
|
||||
|
||||
while ((p = fs_module_list) != 0)
|
||||
{
|
||||
if (! grub_dl_get (p->name) && grub_dl_load (p->name))
|
||||
return 1;
|
||||
|
||||
fs_module_list = p->next;
|
||||
grub_free (p->name);
|
||||
grub_free (p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the file fs.lst for auto-loading. */
|
||||
void
|
||||
read_fs_list (void)
|
||||
{
|
||||
const char *prefix;
|
||||
static int first_time = 1;
|
||||
|
||||
/* Make sure that this function does not get executed twice. */
|
||||
if (! first_time)
|
||||
return;
|
||||
first_time = 0;
|
||||
|
||||
prefix = grub_env_get ("prefix");
|
||||
if (prefix)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
filename = grub_malloc (grub_strlen (prefix) + sizeof ("/fs.lst"));
|
||||
if (filename)
|
||||
{
|
||||
grub_file_t file;
|
||||
|
||||
grub_sprintf (filename, "%s/fs.lst", prefix);
|
||||
file = grub_file_open (filename);
|
||||
if (file)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
char *buf;
|
||||
char *p;
|
||||
char *q;
|
||||
grub_fs_module_list_t fs_mod;
|
||||
|
||||
buf = grub_file_getline (file);
|
||||
if (! buf)
|
||||
break;
|
||||
|
||||
p = buf;
|
||||
q = buf + grub_strlen (buf) - 1;
|
||||
|
||||
/* Ignore space. */
|
||||
while (grub_isspace (*p))
|
||||
p++;
|
||||
|
||||
while (p < q && grub_isspace (*q))
|
||||
*q-- = '\0';
|
||||
|
||||
/* If the line is empty, skip it. */
|
||||
if (p >= q)
|
||||
continue;
|
||||
|
||||
fs_mod = grub_malloc (sizeof (*fs_mod));
|
||||
if (! fs_mod)
|
||||
continue;
|
||||
|
||||
fs_mod->name = grub_strdup (p);
|
||||
if (! fs_mod->name)
|
||||
{
|
||||
grub_free (fs_mod);
|
||||
continue;
|
||||
}
|
||||
|
||||
fs_mod->next = fs_module_list;
|
||||
fs_module_list = fs_mod;
|
||||
}
|
||||
|
||||
grub_file_close (file);
|
||||
}
|
||||
|
||||
grub_free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ignore errors. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* Set the hook. */
|
||||
grub_fs_autoload_hook = autoload_fs_module;
|
||||
}
|
|
@ -132,37 +132,6 @@ grub_history_replace (int pos, char *s)
|
|||
hist_lines[pos] = grub_strdup (s);
|
||||
}
|
||||
|
||||
void
|
||||
grub_cmdline_run (int nested)
|
||||
{
|
||||
grub_normal_init_page ();
|
||||
grub_setcursor (1);
|
||||
|
||||
grub_printf ("\
|
||||
[ Minimal BASH-like line editing is supported. For the first word, TAB\n\
|
||||
lists possible command completions. Anywhere else TAB lists possible\n\
|
||||
device/file completions.%s ]\n\n",
|
||||
nested ? " ESC at any time exits." : "");
|
||||
|
||||
while (1)
|
||||
{
|
||||
static char cmdline[GRUB_MAX_CMDLINE];
|
||||
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
cmdline[0] = '\0';
|
||||
|
||||
if (! grub_cmdline_get ("grub> ", cmdline, sizeof (cmdline), 0, 1)
|
||||
&& nested)
|
||||
return;
|
||||
|
||||
if (! *cmdline)
|
||||
continue;
|
||||
|
||||
grub_command_execute (cmdline, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* A completion hook to print items. */
|
||||
static void
|
||||
print_completion (const char *item, grub_completion_type_t type, int count)
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2005,2006,2007 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/normal.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/parser.h>
|
||||
#include <grub/script.h>
|
||||
#include <grub/list.h>
|
||||
#include <grub/command.h>
|
||||
|
||||
int
|
||||
grub_command_execute (char *cmdline, int interactive)
|
||||
{
|
||||
auto grub_err_t cmdline_get (char **s);
|
||||
grub_err_t cmdline_get (char **s)
|
||||
{
|
||||
*s = grub_malloc (GRUB_MAX_CMDLINE);
|
||||
*s[0] = '\0';
|
||||
return grub_cmdline_get (">", *s, GRUB_MAX_CMDLINE, 0, 1);
|
||||
}
|
||||
|
||||
grub_err_t ret = 0;
|
||||
char *pager;
|
||||
struct grub_script *parsed_script;
|
||||
|
||||
/* Enable the pager if the environment pager is set to 1. */
|
||||
if (interactive)
|
||||
pager = grub_env_get ("pager");
|
||||
else
|
||||
pager = NULL;
|
||||
if (pager && (! grub_strcmp (pager, "1")))
|
||||
grub_set_more (1);
|
||||
|
||||
/* Parse the script. */
|
||||
parsed_script = grub_script_parse (cmdline, cmdline_get);
|
||||
|
||||
if (parsed_script)
|
||||
{
|
||||
/* Execute the command(s). */
|
||||
grub_script_execute (parsed_script);
|
||||
|
||||
/* The parsed script was executed, throw it away. */
|
||||
grub_script_free (parsed_script);
|
||||
}
|
||||
|
||||
if (pager && (! grub_strcmp (pager, "1")))
|
||||
grub_set_more (0);
|
||||
|
||||
return ret;
|
||||
}
|
158
normal/dyncmd.c
Normal file
158
normal/dyncmd.c
Normal file
|
@ -0,0 +1,158 @@
|
|||
/* dyncmd.c - support dynamic command */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2009 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/mm.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/normal.h>
|
||||
|
||||
static grub_err_t
|
||||
grub_dyncmd_dispatcher (struct grub_command *cmd,
|
||||
int argc, char **args)
|
||||
{
|
||||
char *modname = cmd->data;
|
||||
grub_dl_t mod;
|
||||
grub_err_t ret;
|
||||
|
||||
mod = grub_dl_load (modname);
|
||||
if (mod)
|
||||
{
|
||||
char *name;
|
||||
|
||||
grub_free (modname);
|
||||
grub_dl_ref (mod);
|
||||
|
||||
name = (char *) cmd->name;
|
||||
grub_unregister_command (cmd);
|
||||
|
||||
cmd = grub_command_find (name);
|
||||
if (cmd)
|
||||
ret = (cmd->func) (cmd, argc, args);
|
||||
else
|
||||
ret = grub_errno;
|
||||
|
||||
grub_free (name);
|
||||
}
|
||||
else
|
||||
ret = grub_errno;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read the file command.lst for auto-loading. */
|
||||
void
|
||||
read_command_list (void)
|
||||
{
|
||||
const char *prefix;
|
||||
static int first_time = 1;
|
||||
|
||||
/* Make sure that this function does not get executed twice. */
|
||||
if (! first_time)
|
||||
return;
|
||||
first_time = 0;
|
||||
|
||||
prefix = grub_env_get ("prefix");
|
||||
if (prefix)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
filename = grub_malloc (grub_strlen (prefix) + sizeof ("/command.lst"));
|
||||
if (filename)
|
||||
{
|
||||
grub_file_t file;
|
||||
|
||||
grub_sprintf (filename, "%s/command.lst", prefix);
|
||||
file = grub_file_open (filename);
|
||||
if (file)
|
||||
{
|
||||
char *buf = 0;
|
||||
for (;; grub_free(buf))
|
||||
{
|
||||
char *p, *name, *modname;
|
||||
grub_command_t cmd;
|
||||
int prio = 0;
|
||||
|
||||
buf = grub_file_getline (file);
|
||||
|
||||
if (! buf)
|
||||
break;
|
||||
|
||||
name = buf;
|
||||
if (*name == '*')
|
||||
{
|
||||
name++;
|
||||
prio++;
|
||||
}
|
||||
|
||||
if (! grub_isgraph (name[0]))
|
||||
continue;
|
||||
|
||||
p = grub_strchr (name, ':');
|
||||
if (! p)
|
||||
continue;
|
||||
|
||||
*p = '\0';
|
||||
while (*++p == ' ')
|
||||
;
|
||||
|
||||
if (! grub_isgraph (*p))
|
||||
continue;
|
||||
|
||||
if (grub_dl_get (p))
|
||||
continue;
|
||||
|
||||
name = grub_strdup (name);
|
||||
if (! name)
|
||||
continue;
|
||||
|
||||
modname = grub_strdup (p);
|
||||
if (! modname)
|
||||
{
|
||||
grub_free (name);
|
||||
continue;
|
||||
}
|
||||
|
||||
cmd = grub_register_command_prio (name,
|
||||
grub_dyncmd_dispatcher,
|
||||
0, "not loaded", prio);
|
||||
if (! cmd)
|
||||
{
|
||||
grub_free (name);
|
||||
grub_free (modname);
|
||||
continue;
|
||||
}
|
||||
cmd->flags |= GRUB_COMMAND_FLAG_DYNCMD;
|
||||
cmd->data = modname;
|
||||
|
||||
/* Update the active flag. */
|
||||
grub_command_find (name);
|
||||
}
|
||||
|
||||
grub_file_close (file);
|
||||
}
|
||||
|
||||
grub_free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ignore errors. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
251
normal/execute.c
251
normal/execute.c
|
@ -1,251 +0,0 @@
|
|||
/* execute.c -- Execute a GRUB script. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2005,2007,2008,2009 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/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/script.h>
|
||||
#include <grub/lib/arg.h>
|
||||
|
||||
static grub_err_t
|
||||
grub_script_execute_cmd (struct grub_script_cmd *cmd)
|
||||
{
|
||||
if (cmd == 0)
|
||||
return 0;
|
||||
|
||||
return cmd->exec (cmd);
|
||||
}
|
||||
|
||||
/* Parse ARG and return the textual representation. Add strings are
|
||||
concatenated and all values of the variables are filled in. */
|
||||
static char *
|
||||
grub_script_execute_argument_to_string (struct grub_script_arg *arg)
|
||||
{
|
||||
int size = 0;
|
||||
char *val;
|
||||
char *chararg;
|
||||
struct grub_script_arg *argi;
|
||||
|
||||
/* First determine the size of the argument. */
|
||||
for (argi = arg; argi; argi = argi->next)
|
||||
{
|
||||
if (argi->type == 1)
|
||||
{
|
||||
val = grub_env_get (argi->str);
|
||||
if (val)
|
||||
size += grub_strlen (val);
|
||||
}
|
||||
else
|
||||
size += grub_strlen (argi->str);
|
||||
}
|
||||
|
||||
/* Create the argument. */
|
||||
chararg = grub_malloc (size + 1);
|
||||
if (! chararg)
|
||||
return 0;
|
||||
|
||||
*chararg = '\0';
|
||||
/* First determine the size of the argument. */
|
||||
for (argi = arg; argi; argi = argi->next)
|
||||
{
|
||||
if (argi->type == 1)
|
||||
{
|
||||
val = grub_env_get (argi->str);
|
||||
if (val)
|
||||
grub_strcat (chararg, val);
|
||||
}
|
||||
else
|
||||
grub_strcat (chararg, argi->str);
|
||||
}
|
||||
|
||||
return chararg;
|
||||
}
|
||||
|
||||
/* Execute a single command line. */
|
||||
grub_err_t
|
||||
grub_script_execute_cmdline (struct grub_script_cmd *cmd)
|
||||
{
|
||||
struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd;
|
||||
struct grub_script_arglist *arglist;
|
||||
char **args = 0;
|
||||
int i = 0;
|
||||
grub_command_t grubcmd;
|
||||
grub_err_t ret = 0;
|
||||
int argcount = 0;
|
||||
grub_script_function_t func = 0;
|
||||
char errnobuf[6];
|
||||
|
||||
/* Lookup the command. */
|
||||
grubcmd = grub_command_find (cmdline->cmdname);
|
||||
if (! grubcmd)
|
||||
{
|
||||
/* Ignore errors. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* It's not a GRUB command, try all functions. */
|
||||
func = grub_script_function_find (cmdline->cmdname);
|
||||
if (! func)
|
||||
{
|
||||
/* As a last resort, try if it is an assignment. */
|
||||
char *assign = grub_strdup (cmdline->cmdname);
|
||||
char *eq = grub_strchr (assign, '=');
|
||||
|
||||
if (eq)
|
||||
{
|
||||
/* Create two strings and set the variable. */
|
||||
*eq = '\0';
|
||||
eq++;
|
||||
grub_env_set (assign, eq);
|
||||
|
||||
/* This was set because the command was not found. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
grub_free (assign);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmdline->arglist)
|
||||
{
|
||||
argcount = cmdline->arglist->argcount;
|
||||
|
||||
/* Create argv from the arguments. */
|
||||
args = grub_malloc (sizeof (char *) * argcount);
|
||||
for (arglist = cmdline->arglist; arglist; arglist = arglist->next)
|
||||
{
|
||||
char *str;
|
||||
str = grub_script_execute_argument_to_string (arglist->arg);
|
||||
args[i++] = str;
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute the GRUB command or function. */
|
||||
if (grubcmd)
|
||||
ret = (grubcmd->func) (grubcmd, argcount, args);
|
||||
else
|
||||
ret = grub_script_function_call (func, argcount, args);
|
||||
|
||||
/* Free arguments. */
|
||||
for (i = 0; i < argcount; i++)
|
||||
grub_free (args[i]);
|
||||
grub_free (args);
|
||||
|
||||
grub_sprintf (errnobuf, "%d", ret);
|
||||
grub_env_set ("?", errnobuf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Execute a block of one or more commands. */
|
||||
grub_err_t
|
||||
grub_script_execute_cmdblock (struct grub_script_cmd *cmd)
|
||||
{
|
||||
struct grub_script_cmdblock *cmdblock = (struct grub_script_cmdblock *) cmd;
|
||||
|
||||
/* Loop over every command and execute it. */
|
||||
for (cmd = cmdblock->cmdlist; cmd; cmd = cmd->next)
|
||||
grub_script_execute_cmd (cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Execute an if statement. */
|
||||
grub_err_t
|
||||
grub_script_execute_cmdif (struct grub_script_cmd *cmd)
|
||||
{
|
||||
struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
|
||||
char *result;
|
||||
|
||||
/* Check if the commands results in a true or a false. The value is
|
||||
read from the env variable `?'. */
|
||||
grub_script_execute_cmd (cmdif->exec_to_evaluate);
|
||||
result = grub_env_get ("?");
|
||||
|
||||
/* Execute the `if' or the `else' part depending on the value of
|
||||
`?'. */
|
||||
if (result && ! grub_strcmp (result, "0"))
|
||||
return grub_script_execute_cmd (cmdif->exec_on_true);
|
||||
else
|
||||
return grub_script_execute_cmd (cmdif->exec_on_false);
|
||||
}
|
||||
|
||||
/* Execute the menu entry generate statement. */
|
||||
grub_err_t
|
||||
grub_script_execute_menuentry (struct grub_script_cmd *cmd)
|
||||
{
|
||||
struct grub_script_cmd_menuentry *cmd_menuentry;
|
||||
struct grub_script_arglist *arglist;
|
||||
struct grub_script *script;
|
||||
char **args = 0;
|
||||
int argcount = 0;
|
||||
int i = 0;
|
||||
|
||||
cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd;
|
||||
|
||||
if (cmd_menuentry->arglist)
|
||||
{
|
||||
argcount = cmd_menuentry->arglist->argcount;
|
||||
|
||||
/* Create argv from the arguments. */
|
||||
args = grub_malloc (sizeof (char *) * argcount);
|
||||
|
||||
if (! args)
|
||||
{
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
for (arglist = cmd_menuentry->arglist; arglist; arglist = arglist->next)
|
||||
{
|
||||
char *str;
|
||||
str = grub_script_execute_argument_to_string (arglist->arg);
|
||||
args[i++] = str;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the menu entry *again*. */
|
||||
script = grub_script_parse ((char *) cmd_menuentry->sourcecode, 0);
|
||||
|
||||
/* Add new menu entry. */
|
||||
if (script)
|
||||
{
|
||||
grub_normal_menu_addentry (argcount, (const char **)args,
|
||||
script, cmd_menuentry->sourcecode);
|
||||
}
|
||||
|
||||
/* Free arguments. */
|
||||
for (i = 0; i < argcount; i++)
|
||||
grub_free (args[i]);
|
||||
grub_free (args);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Execute any GRUB pre-parsed command or script. */
|
||||
grub_err_t
|
||||
grub_script_execute (struct grub_script *script)
|
||||
{
|
||||
if (script == 0)
|
||||
return 0;
|
||||
|
||||
return grub_script_execute_cmd (script->cmd);
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2005,2007 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/misc.h>
|
||||
#include <grub/script.h>
|
||||
#include <grub/parser.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
static grub_script_function_t grub_script_function_list;
|
||||
|
||||
grub_script_function_t
|
||||
grub_script_function_create (char *functionname, struct grub_script *cmd)
|
||||
{
|
||||
grub_script_function_t func;
|
||||
grub_script_function_t *p;
|
||||
|
||||
func = (grub_script_function_t) grub_malloc (sizeof (*func));
|
||||
if (! func)
|
||||
return 0;
|
||||
|
||||
func->name = grub_strdup (functionname);
|
||||
if (! func->name)
|
||||
{
|
||||
grub_free (func);
|
||||
return 0;
|
||||
}
|
||||
|
||||
func->func = cmd;
|
||||
|
||||
/* Keep the list sorted for simplicity. */
|
||||
p = &grub_script_function_list;
|
||||
while (*p)
|
||||
{
|
||||
if (grub_strcmp ((*p)->name, functionname) >= 0)
|
||||
break;
|
||||
|
||||
p = &((*p)->next);
|
||||
}
|
||||
|
||||
/* If the function already exists, overwrite the old function. */
|
||||
if (*p && grub_strcmp ((*p)->name, functionname) == 0)
|
||||
{
|
||||
grub_script_function_t q;
|
||||
|
||||
q = *p;
|
||||
grub_script_free (q->func);
|
||||
q->func = cmd;
|
||||
grub_free (func);
|
||||
func = q;
|
||||
}
|
||||
else
|
||||
{
|
||||
func->next = *p;
|
||||
*p = func;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
void
|
||||
grub_script_function_remove (const char *name)
|
||||
{
|
||||
grub_script_function_t *p, q;
|
||||
|
||||
for (p = &grub_script_function_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (grub_strcmp (name, q->name) == 0)
|
||||
{
|
||||
*p = q->next;
|
||||
grub_free (q->name);
|
||||
grub_script_free (q->func);
|
||||
grub_free (q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
grub_script_function_t
|
||||
grub_script_function_find (char *functionname)
|
||||
{
|
||||
grub_script_function_t func;
|
||||
|
||||
for (func = grub_script_function_list; func; func = func->next)
|
||||
if (grub_strcmp (functionname, func->name) == 0)
|
||||
break;
|
||||
|
||||
if (! func)
|
||||
grub_error (GRUB_ERR_UNKNOWN_COMMAND, "unknown command `%s'", functionname);
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
int
|
||||
grub_script_function_iterate (int (*iterate) (grub_script_function_t))
|
||||
{
|
||||
grub_script_function_t func;
|
||||
|
||||
for (func = grub_script_function_list; func; func = func->next)
|
||||
if (iterate (func))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
grub_script_function_call (grub_script_function_t func,
|
||||
int argc __attribute__((unused)),
|
||||
char **args __attribute__((unused)))
|
||||
{
|
||||
/* XXX: Arguments are not supported yet. */
|
||||
return grub_script_execute (func->func);
|
||||
}
|
364
normal/lexer.c
364
normal/lexer.c
|
@ -1,364 +0,0 @@
|
|||
/* lexer.c - The scripting lexer. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2005,2006,2007,2008 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/parser.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/script.h>
|
||||
|
||||
#include "grub_script.tab.h"
|
||||
|
||||
static int
|
||||
check_varstate (grub_parser_state_t state)
|
||||
{
|
||||
return (state == GRUB_PARSER_STATE_VARNAME
|
||||
|| state == GRUB_PARSER_STATE_VAR
|
||||
|| state == GRUB_PARSER_STATE_QVAR
|
||||
|| state == GRUB_PARSER_STATE_VARNAME2
|
||||
|| state == GRUB_PARSER_STATE_QVARNAME
|
||||
|| state == GRUB_PARSER_STATE_QVARNAME2);
|
||||
}
|
||||
|
||||
static int
|
||||
check_textstate (grub_parser_state_t state)
|
||||
{
|
||||
return (state == GRUB_PARSER_STATE_TEXT
|
||||
|| state == GRUB_PARSER_STATE_QUOTE
|
||||
|| state == GRUB_PARSER_STATE_DQUOTE);
|
||||
}
|
||||
|
||||
struct grub_lexer_param *
|
||||
grub_script_lexer_init (char *script, grub_err_t (*getline) (char **))
|
||||
{
|
||||
struct grub_lexer_param *param;
|
||||
|
||||
param = grub_malloc (sizeof (*param));
|
||||
if (! param)
|
||||
return 0;
|
||||
|
||||
param->state = GRUB_PARSER_STATE_TEXT;
|
||||
param->getline = getline;
|
||||
param->refs = 0;
|
||||
param->done = 0;
|
||||
param->newscript = 0;
|
||||
param->script = script;
|
||||
param->record = 0;
|
||||
param->recording = 0;
|
||||
param->recordpos = 0;
|
||||
param->recordlen = 0;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
void
|
||||
grub_script_lexer_ref (struct grub_lexer_param *state)
|
||||
{
|
||||
state->refs++;
|
||||
}
|
||||
|
||||
void
|
||||
grub_script_lexer_deref (struct grub_lexer_param *state)
|
||||
{
|
||||
state->refs--;
|
||||
}
|
||||
|
||||
/* Start recording all characters passing through the lexer. */
|
||||
void
|
||||
grub_script_lexer_record_start (struct grub_lexer_param *state)
|
||||
{
|
||||
state->record = 1;
|
||||
state->recordlen = 100;
|
||||
state->recording = grub_malloc (state->recordlen);
|
||||
state->recordpos = 0;
|
||||
}
|
||||
|
||||
char *
|
||||
grub_script_lexer_record_stop (struct grub_lexer_param *state)
|
||||
{
|
||||
state->record = 0;
|
||||
|
||||
/* Delete the last character, it is a `}'. */
|
||||
if (state->recordpos > 0)
|
||||
{
|
||||
if (state->recording[--state->recordpos] != '}')
|
||||
{
|
||||
grub_printf ("Internal error while parsing menu entry");
|
||||
for (;;); /* XXX */
|
||||
}
|
||||
state->recording[state->recordpos] = '\0';
|
||||
}
|
||||
|
||||
return state->recording;
|
||||
}
|
||||
|
||||
/* When recording is enabled, record the character C as the next item
|
||||
in the character stream. */
|
||||
static void
|
||||
recordchar (struct grub_lexer_param *state, char c)
|
||||
{
|
||||
if (state->recordpos == state->recordlen)
|
||||
{
|
||||
char *old = state->recording;
|
||||
state->recordlen += 100;
|
||||
state->recording = grub_realloc (state->recording, state->recordlen);
|
||||
if (! state->recording)
|
||||
{
|
||||
grub_free (old);
|
||||
state->record = 0;
|
||||
}
|
||||
}
|
||||
state->recording[state->recordpos++] = c;
|
||||
}
|
||||
|
||||
/* Fetch the next character for the lexer. */
|
||||
static void
|
||||
nextchar (struct grub_lexer_param *state)
|
||||
{
|
||||
if (state->record)
|
||||
recordchar (state, *state->script);
|
||||
state->script++;
|
||||
}
|
||||
|
||||
int
|
||||
grub_script_yylex2 (union YYSTYPE *yylval,
|
||||
struct grub_parser_param *parsestate);
|
||||
|
||||
int
|
||||
grub_script_yylex (union YYSTYPE *yylval, struct grub_parser_param *parsestate)
|
||||
{
|
||||
int r = -1;
|
||||
|
||||
while (r == -1)
|
||||
{
|
||||
r = grub_script_yylex2 (yylval, parsestate);
|
||||
if (r == ' ')
|
||||
r = -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
grub_script_yylex2 (union YYSTYPE *yylval, struct grub_parser_param *parsestate)
|
||||
{
|
||||
grub_parser_state_t newstate;
|
||||
char use;
|
||||
char *buffer;
|
||||
char *bp;
|
||||
struct grub_lexer_param *state = parsestate->lexerstate;
|
||||
|
||||
if (state->done)
|
||||
return 0;
|
||||
|
||||
if (! *state->script)
|
||||
{
|
||||
/* Check if more tokens are requested by the parser. */
|
||||
if ((state->refs
|
||||
|| state->state == GRUB_PARSER_STATE_ESC)
|
||||
&& state->getline)
|
||||
{
|
||||
while (!state->script || ! grub_strlen (state->script))
|
||||
{
|
||||
grub_free (state->newscript);
|
||||
state->newscript = 0;
|
||||
state->getline (&state->newscript);
|
||||
state->script = state->newscript;
|
||||
if (! state->script)
|
||||
return 0;
|
||||
}
|
||||
grub_dprintf ("scripting", "token=`\\n'\n");
|
||||
recordchar (state, '\n');
|
||||
if (state->state != GRUB_PARSER_STATE_ESC)
|
||||
return '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_free (state->newscript);
|
||||
state->newscript = 0;
|
||||
state->done = 1;
|
||||
grub_dprintf ("scripting", "token=`\\n'\n");
|
||||
return '\n';
|
||||
}
|
||||
}
|
||||
|
||||
newstate = grub_parser_cmdline_state (state->state, *state->script, &use);
|
||||
|
||||
/* Check if it is a text. */
|
||||
if (check_textstate (newstate))
|
||||
{
|
||||
/* In case the string is not quoted, this can be a one char
|
||||
length symbol. */
|
||||
if (newstate == GRUB_PARSER_STATE_TEXT)
|
||||
{
|
||||
switch (*state->script)
|
||||
{
|
||||
case ' ':
|
||||
while (*state->script)
|
||||
{
|
||||
newstate = grub_parser_cmdline_state (state->state,
|
||||
*state->script, &use);
|
||||
if (! (state->state == GRUB_PARSER_STATE_TEXT
|
||||
&& *state->script == ' '))
|
||||
{
|
||||
grub_dprintf ("scripting", "token=` '\n");
|
||||
return ' ';
|
||||
}
|
||||
state->state = newstate;
|
||||
nextchar (state);
|
||||
}
|
||||
grub_dprintf ("scripting", "token=` '\n");
|
||||
return ' ';
|
||||
case '{':
|
||||
case '}':
|
||||
case ';':
|
||||
case '\n':
|
||||
{
|
||||
char c;
|
||||
grub_dprintf ("scripting", "token=`%c'\n", *state->script);
|
||||
c = *state->script;;
|
||||
nextchar (state);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: Use a better size. */
|
||||
buffer = grub_script_malloc (parsestate, 2048);
|
||||
if (! buffer)
|
||||
return 0;
|
||||
|
||||
bp = buffer;
|
||||
|
||||
/* Read one token, possible quoted. */
|
||||
while (*state->script)
|
||||
{
|
||||
newstate = grub_parser_cmdline_state (state->state,
|
||||
*state->script, &use);
|
||||
|
||||
/* Check if a variable name starts. */
|
||||
if (check_varstate (newstate))
|
||||
break;
|
||||
|
||||
/* If the string is not quoted or escaped, stop processing
|
||||
when a special token was found. It will be recognized
|
||||
next time when this function is called. */
|
||||
if (newstate == GRUB_PARSER_STATE_TEXT
|
||||
&& state->state != GRUB_PARSER_STATE_ESC)
|
||||
{
|
||||
int breakout = 0;
|
||||
|
||||
switch (use)
|
||||
{
|
||||
case ' ':
|
||||
case '{':
|
||||
case '}':
|
||||
case ';':
|
||||
case '\n':
|
||||
breakout = 1;
|
||||
}
|
||||
if (breakout)
|
||||
break;
|
||||
*(bp++) = use;
|
||||
}
|
||||
else if (use)
|
||||
*(bp++) = use;
|
||||
|
||||
state->state = newstate;
|
||||
nextchar (state);
|
||||
}
|
||||
|
||||
/* A string of text was read in. */
|
||||
*bp = '\0';
|
||||
grub_dprintf ("scripting", "token=`%s'\n", buffer);
|
||||
yylval->string = buffer;
|
||||
|
||||
/* Detect some special tokens. */
|
||||
if (! grub_strcmp (buffer, "while"))
|
||||
return GRUB_PARSER_TOKEN_WHILE;
|
||||
else if (! grub_strcmp (buffer, "if"))
|
||||
return GRUB_PARSER_TOKEN_IF;
|
||||
else if (! grub_strcmp (buffer, "function"))
|
||||
return GRUB_PARSER_TOKEN_FUNCTION;
|
||||
else if (! grub_strcmp (buffer, "menuentry"))
|
||||
return GRUB_PARSER_TOKEN_MENUENTRY;
|
||||
else if (! grub_strcmp (buffer, "@"))
|
||||
return GRUB_PARSER_TOKEN_MENUENTRY;
|
||||
else if (! grub_strcmp (buffer, "else"))
|
||||
return GRUB_PARSER_TOKEN_ELSE;
|
||||
else if (! grub_strcmp (buffer, "then"))
|
||||
return GRUB_PARSER_TOKEN_THEN;
|
||||
else if (! grub_strcmp (buffer, "fi"))
|
||||
return GRUB_PARSER_TOKEN_FI;
|
||||
else
|
||||
return GRUB_PARSER_TOKEN_NAME;
|
||||
}
|
||||
else if (newstate == GRUB_PARSER_STATE_VAR
|
||||
|| newstate == GRUB_PARSER_STATE_QVAR)
|
||||
{
|
||||
/* XXX: Use a better size. */
|
||||
buffer = grub_script_malloc (parsestate, 2096);
|
||||
if (! buffer)
|
||||
return 0;
|
||||
|
||||
bp = buffer;
|
||||
|
||||
/* This is a variable, read the variable name. */
|
||||
while (*state->script)
|
||||
{
|
||||
newstate = grub_parser_cmdline_state (state->state,
|
||||
*state->script, &use);
|
||||
|
||||
/* Check if this character is not part of the variable name
|
||||
anymore. */
|
||||
if (! (check_varstate (newstate)))
|
||||
{
|
||||
if (state->state == GRUB_PARSER_STATE_VARNAME2
|
||||
|| state->state == GRUB_PARSER_STATE_QVARNAME2)
|
||||
nextchar (state);
|
||||
state->state = newstate;
|
||||
break;
|
||||
}
|
||||
|
||||
if (use)
|
||||
*(bp++) = use;
|
||||
nextchar (state);
|
||||
state->state = newstate;
|
||||
}
|
||||
|
||||
*bp = '\0';
|
||||
state->state = newstate;
|
||||
yylval->string = buffer;
|
||||
grub_dprintf ("scripting", "vartoken=`%s'\n", buffer);
|
||||
|
||||
return GRUB_PARSER_TOKEN_VAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There is either text or a variable name. In the case you
|
||||
arrive here there is a serious problem with the lexer. */
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "Internal error\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grub_script_yyerror (struct grub_parser_param *lex __attribute__ ((unused)),
|
||||
char const *err)
|
||||
{
|
||||
grub_printf ("%s\n", err);
|
||||
}
|
491
normal/main.c
491
normal/main.c
|
@ -20,20 +20,15 @@
|
|||
#include <grub/kernel.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/rescue.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/parser.h>
|
||||
#include <grub/script.h>
|
||||
#include <grub/reader.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
|
||||
grub_jmp_buf grub_exit_env;
|
||||
|
||||
static grub_fs_module_list_t fs_module_list = 0;
|
||||
|
||||
#define GRUB_DEFAULT_HISTORY_SIZE 50
|
||||
|
||||
/* Read a line from the file FILE. */
|
||||
|
@ -43,7 +38,6 @@ grub_file_getline (grub_file_t file)
|
|||
char c;
|
||||
int pos = 0;
|
||||
int literal = 0;
|
||||
int comment = 0;
|
||||
char *cmdline;
|
||||
int max_len = 64;
|
||||
|
||||
|
@ -84,16 +78,9 @@ grub_file_getline (grub_file_t file)
|
|||
if (c == '\\')
|
||||
literal = 1;
|
||||
|
||||
if (comment)
|
||||
if (pos == 0)
|
||||
{
|
||||
if (c == '\n')
|
||||
comment = 0;
|
||||
}
|
||||
else if (pos == 0)
|
||||
{
|
||||
if (c == '#')
|
||||
comment = 1;
|
||||
else if (! grub_isspace (c))
|
||||
if (! grub_isspace (c))
|
||||
cmdline[pos++] = c;
|
||||
}
|
||||
else
|
||||
|
@ -138,7 +125,6 @@ free_menu (grub_menu_t menu)
|
|||
{
|
||||
grub_menu_entry_t next_entry = entry->next;
|
||||
|
||||
grub_script_free (entry->commands);
|
||||
grub_free ((void *) entry->title);
|
||||
grub_free ((void *) entry->sourcecode);
|
||||
entry = next_entry;
|
||||
|
@ -164,8 +150,8 @@ free_menu_entry_classes (struct grub_menu_entry_class *head)
|
|||
}
|
||||
|
||||
grub_err_t
|
||||
grub_normal_menu_addentry (int argc, const char **args,
|
||||
struct grub_script *script, const char *sourcecode)
|
||||
grub_menu_addentry (int argc, const char **args,
|
||||
const char *sourcecode)
|
||||
{
|
||||
const char *menutitle = 0;
|
||||
const char *menusourcecode;
|
||||
|
@ -237,7 +223,7 @@ grub_normal_menu_addentry (int argc, const char **args,
|
|||
/* Handle invalid argument. */
|
||||
failed = 1;
|
||||
grub_error (GRUB_ERR_MENU,
|
||||
"invalid argument for menuentry: %s", args[i]);
|
||||
"invalid argument for menuentry: %s", args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +237,7 @@ grub_normal_menu_addentry (int argc, const char **args,
|
|||
{
|
||||
failed = 1;
|
||||
grub_error (GRUB_ERR_MENU,
|
||||
"too many titles for menuentry: %s", args[i]);
|
||||
"too many titles for menuentry: %s", args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -287,7 +273,6 @@ grub_normal_menu_addentry (int argc, const char **args,
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
(*last)->commands = script;
|
||||
(*last)->title = menutitle;
|
||||
(*last)->classes = classes_head;
|
||||
(*last)->next = 0;
|
||||
|
@ -299,20 +284,56 @@ grub_normal_menu_addentry (int argc, const char **args,
|
|||
}
|
||||
|
||||
static grub_menu_t
|
||||
read_config_file (const char *config, int nested)
|
||||
read_config_file (const char *config)
|
||||
{
|
||||
grub_file_t file;
|
||||
auto grub_err_t getline (char **line);
|
||||
int currline = 0;
|
||||
int errors = 0;
|
||||
grub_parser_t old_parser = 0;
|
||||
|
||||
grub_err_t getline (char **line)
|
||||
auto grub_err_t getline (char **line, int cont);
|
||||
grub_err_t getline (char **line, int cont __attribute__ ((unused)))
|
||||
{
|
||||
currline++;
|
||||
while (1)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
*line = grub_file_getline (file);
|
||||
if (! *line)
|
||||
return grub_errno;
|
||||
*line = buf = grub_file_getline (file);
|
||||
if (! buf)
|
||||
return grub_errno;
|
||||
|
||||
if (buf[0] == '#')
|
||||
{
|
||||
if (buf[1] == '!')
|
||||
{
|
||||
grub_parser_t parser;
|
||||
grub_named_list_t list;
|
||||
|
||||
buf += 2;
|
||||
while (grub_isspace (*buf))
|
||||
buf++;
|
||||
|
||||
if (! old_parser)
|
||||
old_parser = grub_parser_get_current ();
|
||||
|
||||
list = GRUB_AS_NAMED_LIST (grub_parser_class.handler_list);
|
||||
parser = grub_named_list_find (list, buf);
|
||||
if (parser)
|
||||
grub_parser_set_current (parser);
|
||||
else
|
||||
{
|
||||
char cmd_name[8 + grub_strlen (buf)];
|
||||
|
||||
/* Perhaps it's not loaded yet, try the autoload
|
||||
command. */
|
||||
grub_strcpy (cmd_name, "parser.");
|
||||
grub_strcat (cmd_name, buf);
|
||||
grub_command_execute (cmd_name, 0, 0);
|
||||
}
|
||||
}
|
||||
grub_free (*line);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
@ -320,14 +341,15 @@ read_config_file (const char *config, int nested)
|
|||
grub_menu_t newmenu;
|
||||
|
||||
newmenu = grub_env_get_data_slot ("menu");
|
||||
|
||||
if (nested || ! newmenu)
|
||||
if (! newmenu)
|
||||
{
|
||||
newmenu = grub_malloc (sizeof (*newmenu));
|
||||
if (! newmenu)
|
||||
return 0;
|
||||
newmenu->size = 0;
|
||||
newmenu->entry_list = 0;
|
||||
|
||||
grub_env_set_data_slot ("menu", newmenu);
|
||||
}
|
||||
|
||||
/* Try to open the config file. */
|
||||
|
@ -335,58 +357,15 @@ read_config_file (const char *config, int nested)
|
|||
if (! file)
|
||||
return 0;
|
||||
|
||||
grub_env_set_data_slot ("menu", newmenu);
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct grub_script *parsed_script;
|
||||
int startline;
|
||||
char *cmdline;
|
||||
|
||||
cmdline = grub_file_getline (file);
|
||||
if (!cmdline)
|
||||
break;
|
||||
|
||||
startline = ++currline;
|
||||
|
||||
/* Execute the script, line for line. */
|
||||
parsed_script = grub_script_parse (cmdline, getline);
|
||||
|
||||
grub_free (cmdline);
|
||||
|
||||
if (! parsed_script)
|
||||
{
|
||||
grub_printf ("(line %d-%d)\n", startline, currline);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Execute the command(s). */
|
||||
grub_script_execute (parsed_script);
|
||||
|
||||
/* Ignore errors. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* The parsed script was executed, throw it away. */
|
||||
grub_script_free (parsed_script);
|
||||
}
|
||||
|
||||
grub_reader_loop (getline);
|
||||
grub_file_close (file);
|
||||
|
||||
if (errors > 0)
|
||||
grub_wait_after_message ();
|
||||
if (old_parser)
|
||||
grub_parser_set_current (old_parser);
|
||||
|
||||
return newmenu;
|
||||
}
|
||||
|
||||
/* This starts the normal mode. */
|
||||
void
|
||||
grub_enter_normal_mode (const char *config)
|
||||
{
|
||||
if (grub_setjmp (grub_exit_env) == 0)
|
||||
grub_normal_execute (config, 0, 0);
|
||||
}
|
||||
|
||||
/* Initialize the screen. */
|
||||
void
|
||||
grub_normal_init_page (void)
|
||||
|
@ -409,237 +388,7 @@ grub_normal_init_page (void)
|
|||
#undef TITLE
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_dyncmd_dispatcher (struct grub_command *cmd,
|
||||
int argc, char **args)
|
||||
{
|
||||
char *modname = cmd->data;
|
||||
grub_dl_t mod;
|
||||
grub_err_t ret;
|
||||
|
||||
mod = grub_dl_load (modname);
|
||||
if (mod)
|
||||
{
|
||||
char *name;
|
||||
|
||||
grub_free (modname);
|
||||
grub_dl_ref (mod);
|
||||
|
||||
name = (char *) cmd->name;
|
||||
grub_unregister_command (cmd);
|
||||
|
||||
cmd = grub_command_find (name);
|
||||
if (cmd)
|
||||
ret = (cmd->func) (cmd, argc, args);
|
||||
else
|
||||
ret = grub_errno;
|
||||
|
||||
grub_free (name);
|
||||
}
|
||||
else
|
||||
ret = grub_errno;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read the file command.lst for auto-loading. */
|
||||
static void
|
||||
read_command_list (void)
|
||||
{
|
||||
const char *prefix;
|
||||
static int first_time = 1;
|
||||
|
||||
/* Make sure that this function does not get executed twice. */
|
||||
if (! first_time)
|
||||
return;
|
||||
first_time = 0;
|
||||
|
||||
prefix = grub_env_get ("prefix");
|
||||
if (prefix)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
filename = grub_malloc (grub_strlen (prefix) + sizeof ("/command.lst"));
|
||||
if (filename)
|
||||
{
|
||||
grub_file_t file;
|
||||
|
||||
grub_sprintf (filename, "%s/command.lst", prefix);
|
||||
file = grub_file_open (filename);
|
||||
if (file)
|
||||
{
|
||||
char *buf = 0;
|
||||
for (;; grub_free(buf))
|
||||
{
|
||||
char *p, *name, *modname;
|
||||
grub_command_t cmd;
|
||||
int prio = 0;
|
||||
|
||||
buf = grub_file_getline (file);
|
||||
|
||||
if (! buf)
|
||||
break;
|
||||
|
||||
name = buf;
|
||||
if (*name == '*')
|
||||
{
|
||||
name++;
|
||||
prio++;
|
||||
}
|
||||
|
||||
if (! grub_isgraph (name[0]))
|
||||
continue;
|
||||
|
||||
p = grub_strchr (name, ':');
|
||||
if (! p)
|
||||
continue;
|
||||
|
||||
*p = '\0';
|
||||
while (*++p == ' ')
|
||||
;
|
||||
|
||||
if (! grub_isgraph (*p))
|
||||
continue;
|
||||
|
||||
if (grub_dl_get (p))
|
||||
continue;
|
||||
|
||||
name = grub_strdup (name);
|
||||
if (! name)
|
||||
continue;
|
||||
|
||||
modname = grub_strdup (p);
|
||||
if (! modname)
|
||||
{
|
||||
grub_free (name);
|
||||
continue;
|
||||
}
|
||||
|
||||
cmd = grub_register_command_prio (name,
|
||||
grub_dyncmd_dispatcher,
|
||||
0, "not loaded", prio);
|
||||
if (! cmd)
|
||||
{
|
||||
grub_free (name);
|
||||
grub_free (modname);
|
||||
continue;
|
||||
}
|
||||
cmd->flags |= GRUB_COMMAND_FLAG_DYNCMD;
|
||||
cmd->data = modname;
|
||||
|
||||
/* Update the active flag. */
|
||||
grub_command_find (name);
|
||||
}
|
||||
|
||||
grub_file_close (file);
|
||||
}
|
||||
|
||||
grub_free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ignore errors. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* The auto-loading hook for filesystems. */
|
||||
static int
|
||||
autoload_fs_module (void)
|
||||
{
|
||||
grub_fs_module_list_t p;
|
||||
|
||||
while ((p = fs_module_list) != 0)
|
||||
{
|
||||
if (! grub_dl_get (p->name) && grub_dl_load (p->name))
|
||||
return 1;
|
||||
|
||||
fs_module_list = p->next;
|
||||
grub_free (p->name);
|
||||
grub_free (p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the file fs.lst for auto-loading. */
|
||||
static void
|
||||
read_fs_list (void)
|
||||
{
|
||||
const char *prefix;
|
||||
static int first_time = 1;
|
||||
|
||||
/* Make sure that this function does not get executed twice. */
|
||||
if (! first_time)
|
||||
return;
|
||||
first_time = 0;
|
||||
|
||||
prefix = grub_env_get ("prefix");
|
||||
if (prefix)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
filename = grub_malloc (grub_strlen (prefix) + sizeof ("/fs.lst"));
|
||||
if (filename)
|
||||
{
|
||||
grub_file_t file;
|
||||
|
||||
grub_sprintf (filename, "%s/fs.lst", prefix);
|
||||
file = grub_file_open (filename);
|
||||
if (file)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
char *buf;
|
||||
char *p;
|
||||
char *q;
|
||||
grub_fs_module_list_t fs_mod;
|
||||
|
||||
buf = grub_file_getline (file);
|
||||
if (! buf)
|
||||
break;
|
||||
|
||||
p = buf;
|
||||
q = buf + grub_strlen (buf) - 1;
|
||||
|
||||
/* Ignore space. */
|
||||
while (grub_isspace (*p))
|
||||
p++;
|
||||
|
||||
while (p < q && grub_isspace (*q))
|
||||
*q-- = '\0';
|
||||
|
||||
/* If the line is empty, skip it. */
|
||||
if (p >= q)
|
||||
continue;
|
||||
|
||||
fs_mod = grub_malloc (sizeof (*fs_mod));
|
||||
if (! fs_mod)
|
||||
continue;
|
||||
|
||||
fs_mod->name = grub_strdup (p);
|
||||
if (! fs_mod->name)
|
||||
{
|
||||
grub_free (fs_mod);
|
||||
continue;
|
||||
}
|
||||
|
||||
fs_mod->next = fs_module_list;
|
||||
fs_module_list = fs_mod;
|
||||
}
|
||||
|
||||
grub_file_close (file);
|
||||
}
|
||||
|
||||
grub_free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ignore errors. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* Set the hook. */
|
||||
grub_fs_autoload_hook = autoload_fs_module;
|
||||
}
|
||||
static int reader_nested;
|
||||
|
||||
/* Read the config file COFIG, and execute the menu interface or
|
||||
the command-line interface if BATCH is false. */
|
||||
|
@ -651,10 +400,13 @@ grub_normal_execute (const char *config, int nested, int batch)
|
|||
read_command_list ();
|
||||
read_fs_list ();
|
||||
read_handler_list ();
|
||||
grub_command_execute ("parser.sh", 0, 0);
|
||||
|
||||
reader_nested = nested;
|
||||
|
||||
if (config)
|
||||
{
|
||||
menu = read_config_file (config, nested);
|
||||
menu = read_config_file (config);
|
||||
|
||||
/* Ignore any error. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
@ -663,39 +415,27 @@ grub_normal_execute (const char *config, int nested, int batch)
|
|||
if (! batch)
|
||||
{
|
||||
if (menu && menu->size)
|
||||
{
|
||||
grub_menu_viewer_show_menu (menu, nested);
|
||||
if (nested)
|
||||
free_menu (menu);
|
||||
}
|
||||
else
|
||||
grub_cmdline_run (nested);
|
||||
{
|
||||
grub_menu_viewer_show_menu (menu, nested);
|
||||
if (nested)
|
||||
free_menu (menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_rescue (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
/* This starts the normal mode. */
|
||||
void
|
||||
grub_enter_normal_mode (const char *config)
|
||||
{
|
||||
grub_longjmp (grub_exit_env, 0);
|
||||
|
||||
/* Never reach here. */
|
||||
return 0;
|
||||
grub_normal_execute (config, 0, 0);
|
||||
}
|
||||
|
||||
static grub_command_t cmd_normal;
|
||||
|
||||
/* Enter normal mode from rescue mode. */
|
||||
static grub_err_t
|
||||
grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
|
||||
grub_cmd_normal (struct grub_command *cmd,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
grub_command_t cmd_rescue;
|
||||
|
||||
grub_unregister_command (cmd_normal);
|
||||
cmd_rescue = grub_register_command ("rescue", grub_cmd_rescue,
|
||||
0, "enter rescue mode");
|
||||
grub_unregister_command (cmd);
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
|
@ -722,12 +462,77 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
|
|||
grub_enter_normal_mode (argv[0]);
|
||||
|
||||
quit:
|
||||
grub_unregister_command (cmd_rescue);
|
||||
cmd_normal = grub_register_command_prio ("normal", grub_cmd_normal,
|
||||
0, "enter normal mode", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
grub_cmdline_run (int nested)
|
||||
{
|
||||
grub_reader_t reader = grub_reader_get_current ();
|
||||
|
||||
reader_nested = nested;
|
||||
if (reader->init)
|
||||
reader->init ();
|
||||
grub_reader_loop (0);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_normal_reader_init (void)
|
||||
{
|
||||
grub_normal_init_page ();
|
||||
grub_setcursor (1);
|
||||
|
||||
grub_printf ("\
|
||||
[ Minimal BASH-like line editing is supported. For the first word, TAB\n\
|
||||
lists possible command completions. Anywhere else TAB lists possible\n\
|
||||
device/file completions.%s ]\n\n",
|
||||
reader_nested ? " ESC at any time exits." : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char cmdline[GRUB_MAX_CMDLINE];
|
||||
|
||||
static grub_err_t
|
||||
grub_normal_read_line (char **line, int cont)
|
||||
{
|
||||
grub_parser_t parser = grub_parser_get_current ();
|
||||
char prompt[8 + grub_strlen (parser->name)];
|
||||
|
||||
grub_sprintf (prompt, "%s:%s> ", parser->name, (cont) ? "" : "grub");
|
||||
|
||||
while (1)
|
||||
{
|
||||
cmdline[0] = 0;
|
||||
if (grub_cmdline_get (prompt, cmdline, sizeof (cmdline), 0, 1))
|
||||
break;
|
||||
|
||||
if ((reader_nested) || (cont))
|
||||
{
|
||||
*line = 0;
|
||||
return grub_errno;
|
||||
}
|
||||
}
|
||||
|
||||
*line = grub_strdup (cmdline);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct grub_reader grub_normal_reader =
|
||||
{
|
||||
.name = "normal",
|
||||
.init = grub_normal_reader_init,
|
||||
.read_line = grub_normal_read_line
|
||||
};
|
||||
|
||||
static char *
|
||||
grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
grub_set_more ((*val == '1'));
|
||||
return grub_strdup (val);
|
||||
}
|
||||
|
||||
GRUB_MOD_INIT(normal)
|
||||
{
|
||||
/* Normal mode shouldn't be unloaded. */
|
||||
|
@ -738,9 +543,13 @@ GRUB_MOD_INIT(normal)
|
|||
|
||||
grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
|
||||
|
||||
grub_reader_register ("normal", &grub_normal_reader);
|
||||
grub_reader_set_current (&grub_normal_reader);
|
||||
grub_register_variable_hook ("pager", 0, grub_env_write_pager);
|
||||
|
||||
/* Register a command "normal" for the rescue mode. */
|
||||
cmd_normal = grub_register_command ("normal", grub_cmd_normal,
|
||||
0, "enter normal mode");
|
||||
grub_register_command_prio ("normal", grub_cmd_normal,
|
||||
0, "Enter normal mode", 0);
|
||||
|
||||
/* Reload terminal colors when these variables are written to. */
|
||||
grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
|
||||
|
@ -754,6 +563,8 @@ GRUB_MOD_INIT(normal)
|
|||
GRUB_MOD_FINI(normal)
|
||||
{
|
||||
grub_set_history (0);
|
||||
grub_unregister_command (cmd_normal);
|
||||
grub_reader_unregister (&grub_normal_reader);
|
||||
grub_register_variable_hook ("pager", 0, 0);
|
||||
grub_fs_autoload_hook = 0;
|
||||
free_handler_list ();
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/script.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
#include <grub/command.h>
|
||||
|
||||
/* Get a menu entry by its index in the entry list. */
|
||||
grub_menu_entry_t
|
||||
|
@ -123,11 +123,11 @@ get_and_remove_first_entry_number (const char *name)
|
|||
void
|
||||
grub_menu_execute_entry(grub_menu_entry_t entry)
|
||||
{
|
||||
grub_script_execute (entry->commands);
|
||||
grub_parser_execute ((char *) entry->sourcecode);
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
|
||||
/* Implicit execution of boot, only if something is loaded. */
|
||||
grub_command_execute ("boot", 0);
|
||||
grub_command_execute ("boot", 0, 0);
|
||||
}
|
||||
|
||||
/* Execute ENTRY from the menu MENU, falling back to entries specified
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/script.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/parser.h>
|
||||
|
||||
enum update_mode
|
||||
{
|
||||
|
@ -970,12 +971,11 @@ clear_completions (void)
|
|||
static int
|
||||
run (struct screen *screen)
|
||||
{
|
||||
struct grub_script *parsed_script = 0;
|
||||
int currline = 0;
|
||||
char *nextline;
|
||||
|
||||
auto grub_err_t editor_getline (char **line);
|
||||
grub_err_t editor_getline (char **line)
|
||||
auto grub_err_t editor_getline (char **line, int cont);
|
||||
grub_err_t editor_getline (char **line, int cont __attribute__ ((unused)))
|
||||
{
|
||||
struct line *linep = screen->lines + currline;
|
||||
char *p;
|
||||
|
@ -1008,23 +1008,14 @@ run (struct screen *screen)
|
|||
/* Execute the script, line for line. */
|
||||
while (currline < screen->num_lines)
|
||||
{
|
||||
editor_getline (&nextline);
|
||||
parsed_script = grub_script_parse (nextline, editor_getline);
|
||||
if (parsed_script)
|
||||
{
|
||||
/* Execute the command(s). */
|
||||
grub_script_execute (parsed_script);
|
||||
|
||||
/* The parsed script was executed, throw it away. */
|
||||
grub_script_free (parsed_script);
|
||||
}
|
||||
else
|
||||
editor_getline (&nextline, 0);
|
||||
if (grub_parser_get_current ()->parse_line (nextline, editor_getline))
|
||||
break;
|
||||
}
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
|
||||
/* Implicit execution of boot, only if something is loaded. */
|
||||
grub_command_execute ("boot", 0);
|
||||
grub_command_execute ("boot", 0, 0);
|
||||
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/script.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
|
||||
/* Time to delay after displaying an error message about a default/fallback
|
||||
|
|
238
normal/parser.y
238
normal/parser.y
|
@ -1,238 +0,0 @@
|
|||
/* parser.y - The scripting parser. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2005,2006,2007,2008,2009 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/script.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
#define YYFREE grub_free
|
||||
#define YYMALLOC grub_malloc
|
||||
#define YYLTYPE_IS_TRIVIAL 0
|
||||
#define YYENABLE_NLS 0
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
struct grub_script_cmd *cmd;
|
||||
struct grub_script_arglist *arglist;
|
||||
struct grub_script_arg *arg;
|
||||
char *string;
|
||||
}
|
||||
|
||||
%token GRUB_PARSER_TOKEN_IF "if"
|
||||
%token GRUB_PARSER_TOKEN_WHILE "while"
|
||||
%token GRUB_PARSER_TOKEN_FUNCTION "function"
|
||||
%token GRUB_PARSER_TOKEN_MENUENTRY "menuentry"
|
||||
%token GRUB_PARSER_TOKEN_ELSE "else"
|
||||
%token GRUB_PARSER_TOKEN_THEN "then"
|
||||
%token GRUB_PARSER_TOKEN_FI "fi"
|
||||
%token GRUB_PARSER_TOKEN_NAME
|
||||
%token GRUB_PARSER_TOKEN_VAR
|
||||
%type <cmd> script_init script grubcmd command commands commandblock menuentry if
|
||||
%type <arglist> arguments;
|
||||
%type <arg> argument;
|
||||
%type <string> "if" "while" "function" "else" "then" "fi"
|
||||
%type <string> text GRUB_PARSER_TOKEN_NAME GRUB_PARSER_TOKEN_VAR
|
||||
|
||||
%pure-parser
|
||||
%lex-param { struct grub_parser_param *state };
|
||||
%parse-param { struct grub_parser_param *state };
|
||||
|
||||
%%
|
||||
/* It should be possible to do this in a clean way... */
|
||||
script_init: { state->err = 0; } script
|
||||
{
|
||||
state->parsed = $2;
|
||||
}
|
||||
;
|
||||
|
||||
script: commands { $$ = $1; }
|
||||
| function '\n' { $$ = 0; }
|
||||
| menuentry '\n' { $$ = $1; }
|
||||
;
|
||||
|
||||
delimiter: '\n'
|
||||
| ';'
|
||||
| delimiter '\n'
|
||||
;
|
||||
|
||||
newlines: /* Empty */
|
||||
| newlines '\n'
|
||||
;
|
||||
|
||||
/* Some tokens are both used as token or as plain text. XXX: Add all
|
||||
tokens without causing conflicts. */
|
||||
text: GRUB_PARSER_TOKEN_NAME
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| "if"
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| "while"
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
/* An argument can consist of some static text mixed with variables,
|
||||
for example: `foo${bar}baz'. */
|
||||
argument: GRUB_PARSER_TOKEN_VAR
|
||||
{
|
||||
$$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_VAR, $1);
|
||||
}
|
||||
| text
|
||||
{
|
||||
$$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_STR, $1);
|
||||
}
|
||||
/* XXX: Currently disabled to simplify the parser. This should be
|
||||
parsed by yet another parser for readability. */
|
||||
/* | argument GRUB_PARSER_TOKEN_VAR */
|
||||
/* { */
|
||||
/* $$ = grub_script_arg_add ($1, GRUB_SCRIPT_ARG_TYPE_VAR, $2); */
|
||||
/* } */
|
||||
/* | argument text */
|
||||
/* { */
|
||||
/* $$ = grub_script_arg_add ($1, GRUB_SCRIPT_ARG_TYPE_STR, $2); */
|
||||
/* } */
|
||||
;
|
||||
|
||||
arguments: argument
|
||||
{
|
||||
$$ = grub_script_add_arglist (state, 0, $1);
|
||||
}
|
||||
| arguments argument
|
||||
{
|
||||
$$ = grub_script_add_arglist (state, $1, $2);
|
||||
}
|
||||
;
|
||||
|
||||
grubcmd: GRUB_PARSER_TOKEN_NAME arguments
|
||||
{
|
||||
$$ = grub_script_create_cmdline (state, $1, $2);
|
||||
}
|
||||
| GRUB_PARSER_TOKEN_NAME
|
||||
{
|
||||
$$ = grub_script_create_cmdline (state, $1, 0);
|
||||
}
|
||||
;
|
||||
|
||||
/* A single command. */
|
||||
command: grubcmd delimiter { $$ = $1; }
|
||||
| if delimiter { $$ = $1; }
|
||||
| commandblock delimiter { $$ = $1; }
|
||||
| error delimiter
|
||||
{
|
||||
$$ = 0;
|
||||
yyerror (state, "Incorrect command");
|
||||
state->err = 1;
|
||||
yyerrok;
|
||||
}
|
||||
;
|
||||
|
||||
/* A block of commands. */
|
||||
commands: command
|
||||
{
|
||||
$$ = grub_script_add_cmd (state, 0, $1);
|
||||
}
|
||||
| command commands
|
||||
{
|
||||
struct grub_script_cmdblock *cmd;
|
||||
cmd = (struct grub_script_cmdblock *) $2;
|
||||
$$ = grub_script_add_cmd (state, cmd, $1);
|
||||
}
|
||||
;
|
||||
|
||||
/* A function. Carefully save the memory that is allocated. Don't
|
||||
change any stuff because it might seem like a fun thing to do!
|
||||
Special care was take to make sure the mid-rule actions are
|
||||
executed on the right moment. So the `commands' rule should be
|
||||
recognized after executing the `grub_script_mem_record; and before
|
||||
`grub_script_mem_record_stop'. */
|
||||
function: "function" GRUB_PARSER_TOKEN_NAME
|
||||
{
|
||||
grub_script_lexer_ref (state->lexerstate);
|
||||
} newlines '{'
|
||||
{
|
||||
/* The first part of the function was recognized.
|
||||
Now start recording the memory usage to store
|
||||
this function. */
|
||||
state->func_mem = grub_script_mem_record (state);
|
||||
} newlines commands '}'
|
||||
{
|
||||
struct grub_script *script;
|
||||
|
||||
/* All the memory usage for parsing this function
|
||||
was recorded. */
|
||||
state->func_mem = grub_script_mem_record_stop (state,
|
||||
state->func_mem);
|
||||
script = grub_script_create ($8, state->func_mem);
|
||||
if (script)
|
||||
grub_script_function_create ($2, script);
|
||||
grub_script_lexer_deref (state->lexerstate);
|
||||
}
|
||||
;
|
||||
|
||||
/* Carefully designed, together with `menuentry' so everything happens
|
||||
just in the expected order. */
|
||||
commandblock: '{'
|
||||
{
|
||||
grub_script_lexer_ref (state->lexerstate);
|
||||
}
|
||||
newlines commands '}'
|
||||
{
|
||||
grub_script_lexer_deref (state->lexerstate);
|
||||
$$ = $4;
|
||||
}
|
||||
;
|
||||
|
||||
/* A menu entry. Carefully save the memory that is allocated. */
|
||||
menuentry: "menuentry" arguments
|
||||
{
|
||||
grub_script_lexer_ref (state->lexerstate);
|
||||
} newlines '{'
|
||||
{
|
||||
grub_script_lexer_record_start (state->lexerstate);
|
||||
} newlines commands '}'
|
||||
{
|
||||
char *menu_entry;
|
||||
menu_entry = grub_script_lexer_record_stop (state->lexerstate);
|
||||
grub_script_lexer_deref (state->lexerstate);
|
||||
$$ = grub_script_create_cmdmenu (state, $2, menu_entry, 0);
|
||||
}
|
||||
;
|
||||
|
||||
/* The first part of the if statement. It's used to switch the lexer
|
||||
to a state in which it demands more tokens. */
|
||||
if_statement: "if" { grub_script_lexer_ref (state->lexerstate); }
|
||||
;
|
||||
|
||||
/* The if statement. */
|
||||
if: if_statement commands "then" newlines commands "fi"
|
||||
{
|
||||
$$ = grub_script_create_cmdif (state, $2, $5, 0);
|
||||
grub_script_lexer_deref (state->lexerstate);
|
||||
}
|
||||
| if_statement commands "then" newlines commands "else" newlines commands "fi"
|
||||
{
|
||||
$$ = grub_script_create_cmdif (state, $2, $5, $8);
|
||||
grub_script_lexer_deref (state->lexerstate);
|
||||
}
|
||||
;
|
348
normal/script.c
348
normal/script.c
|
@ -1,348 +0,0 @@
|
|||
/* script.c -- Functions to create an in memory description of the script. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2005,2006,2007,2009 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/misc.h>
|
||||
#include <grub/script.h>
|
||||
#include <grub/parser.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
/* It is not possible to deallocate the memory when a syntax error was
|
||||
found. Because of that it is required to keep track of all memory
|
||||
allocations. The memory is freed in case of an error, or
|
||||
assigned to the parsed script when parsing was successful. */
|
||||
|
||||
/* XXX */
|
||||
|
||||
/* In case of the normal malloc, some additional bytes are allocated
|
||||
for this datastructure. All reserved memory is stored in a linked
|
||||
list so it can be easily freed. The original memory can be found
|
||||
from &mem. */
|
||||
struct grub_script_mem
|
||||
{
|
||||
struct grub_script_mem *next;
|
||||
char mem;
|
||||
};
|
||||
|
||||
/* Return malloc'ed memory and keep track of the allocation. */
|
||||
void *
|
||||
grub_script_malloc (struct grub_parser_param *state, grub_size_t size)
|
||||
{
|
||||
struct grub_script_mem *mem;
|
||||
mem = (struct grub_script_mem *) grub_malloc (size + sizeof (*mem)
|
||||
- sizeof (char));
|
||||
|
||||
grub_dprintf ("scripting", "malloc %p\n", mem);
|
||||
mem->next = state->memused;
|
||||
state->memused = mem;
|
||||
return (void *) &mem->mem;
|
||||
}
|
||||
|
||||
/* Free all memory described by MEM. */
|
||||
static void
|
||||
grub_script_mem_free (struct grub_script_mem *mem)
|
||||
{
|
||||
struct grub_script_mem *memfree;
|
||||
|
||||
while (mem)
|
||||
{
|
||||
memfree = mem->next;
|
||||
grub_dprintf ("scripting", "free %p\n", mem);
|
||||
grub_free (mem);
|
||||
mem = memfree;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start recording memory usage. Returns the memory that should be
|
||||
restored when calling stop. */
|
||||
struct grub_script_mem *
|
||||
grub_script_mem_record (struct grub_parser_param *state)
|
||||
{
|
||||
struct grub_script_mem *mem = state->memused;
|
||||
state->memused = 0;
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
/* Stop recording memory usage. Restore previous recordings using
|
||||
RESTORE. Return the recorded memory. */
|
||||
struct grub_script_mem *
|
||||
grub_script_mem_record_stop (struct grub_parser_param *state,
|
||||
struct grub_script_mem *restore)
|
||||
{
|
||||
struct grub_script_mem *mem = state->memused;
|
||||
state->memused = restore;
|
||||
return mem;
|
||||
}
|
||||
|
||||
/* Free the memory reserved for CMD and all of it's children. */
|
||||
void
|
||||
grub_script_free (struct grub_script *script)
|
||||
{
|
||||
if (! script)
|
||||
return;
|
||||
grub_script_mem_free (script->mem);
|
||||
grub_free (script);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Extend the argument arg with a variable or string of text. If ARG
|
||||
is zero a new list is created. */
|
||||
struct grub_script_arg *
|
||||
grub_script_arg_add (struct grub_parser_param *state, struct grub_script_arg *arg,
|
||||
grub_script_arg_type_t type, char *str)
|
||||
{
|
||||
struct grub_script_arg *argpart;
|
||||
struct grub_script_arg *ll;
|
||||
|
||||
argpart = (struct grub_script_arg *) grub_script_malloc (state, sizeof (*arg));
|
||||
argpart->type = type;
|
||||
argpart->str = str;
|
||||
argpart->next = 0;
|
||||
|
||||
if (! arg)
|
||||
return argpart;
|
||||
|
||||
for (ll = arg; ll->next; ll = ll->next);
|
||||
ll->next = argpart;
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
/* Add the argument ARG to the end of the argument list LIST. If LIST
|
||||
is zero, a new list will be created. */
|
||||
struct grub_script_arglist *
|
||||
grub_script_add_arglist (struct grub_parser_param *state,
|
||||
struct grub_script_arglist *list, struct grub_script_arg *arg)
|
||||
{
|
||||
struct grub_script_arglist *link;
|
||||
struct grub_script_arglist *ll;
|
||||
|
||||
grub_dprintf ("scripting", "arglist\n");
|
||||
|
||||
link = (struct grub_script_arglist *) grub_script_malloc (state, sizeof (*link));
|
||||
link->next = 0;
|
||||
link->arg = arg;
|
||||
link->argcount = 0;
|
||||
|
||||
if (! list)
|
||||
{
|
||||
link->argcount++;
|
||||
return link;
|
||||
}
|
||||
|
||||
list->argcount++;
|
||||
|
||||
/* Look up the last link in the chain. */
|
||||
for (ll = list; ll->next; ll = ll->next);
|
||||
ll->next = link;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/* Create a command that describes a single command line. CMDLINE
|
||||
contains the name of the command that should be executed. ARGLIST
|
||||
holds all arguments for this command. */
|
||||
struct grub_script_cmd *
|
||||
grub_script_create_cmdline (struct grub_parser_param *state,
|
||||
char *cmdname, struct grub_script_arglist *arglist)
|
||||
{
|
||||
struct grub_script_cmdline *cmd;
|
||||
|
||||
grub_dprintf ("scripting", "cmdline\n");
|
||||
|
||||
cmd = grub_script_malloc (state, sizeof (*cmd));
|
||||
cmd->cmd.exec = grub_script_execute_cmdline;
|
||||
cmd->cmd.next = 0;
|
||||
cmd->arglist = arglist;
|
||||
cmd->cmdname = cmdname;
|
||||
|
||||
return (struct grub_script_cmd *) cmd;
|
||||
}
|
||||
|
||||
/* Create a command that functions as an if statement. If BOOL is
|
||||
evaluated to true (the value is returned in envvar '?'), the
|
||||
interpreter will run the command TRUE, otherwise the interpreter
|
||||
runs the command FALSE. */
|
||||
struct grub_script_cmd *
|
||||
grub_script_create_cmdif (struct grub_parser_param *state,
|
||||
struct grub_script_cmd *exec_to_evaluate,
|
||||
struct grub_script_cmd *exec_on_true,
|
||||
struct grub_script_cmd *exec_on_false)
|
||||
{
|
||||
struct grub_script_cmdif *cmd;
|
||||
|
||||
grub_dprintf ("scripting", "cmdif\n");
|
||||
|
||||
cmd = grub_script_malloc (state, sizeof (*cmd));
|
||||
cmd->cmd.exec = grub_script_execute_cmdif;
|
||||
cmd->cmd.next = 0;
|
||||
cmd->exec_to_evaluate = exec_to_evaluate;
|
||||
cmd->exec_on_true = exec_on_true;
|
||||
cmd->exec_on_false = exec_on_false;
|
||||
|
||||
return (struct grub_script_cmd *) cmd;
|
||||
}
|
||||
|
||||
/* Create a command that adds a menu entry to the menu. Title is an
|
||||
argument that is parsed to generate a string that can be used as
|
||||
the title. The sourcecode for this entry is passed in SOURCECODE.
|
||||
The options for this entry are passed in OPTIONS. */
|
||||
struct grub_script_cmd *
|
||||
grub_script_create_cmdmenu (struct grub_parser_param *state,
|
||||
struct grub_script_arglist *arglist,
|
||||
char *sourcecode,
|
||||
int options)
|
||||
{
|
||||
struct grub_script_cmd_menuentry *cmd;
|
||||
int i;
|
||||
|
||||
/* Skip leading newlines to make the sourcecode better readable when
|
||||
using the editor. */
|
||||
while (*sourcecode == '\n')
|
||||
sourcecode++;
|
||||
|
||||
/* Having trailing returns can some some annoying conflicts, remove
|
||||
them. XXX: Can the parser be improved to handle this? */
|
||||
for (i = grub_strlen (sourcecode) - 1; i > 0; i--)
|
||||
{
|
||||
if (sourcecode[i] != '\n')
|
||||
break;
|
||||
sourcecode[i] = '\0';
|
||||
}
|
||||
|
||||
cmd = grub_script_malloc (state, sizeof (*cmd));
|
||||
cmd->cmd.exec = grub_script_execute_menuentry;
|
||||
cmd->cmd.next = 0;
|
||||
/* XXX: Check if this memory is properly freed. */
|
||||
cmd->sourcecode = sourcecode;
|
||||
cmd->arglist = arglist;
|
||||
cmd->options = options;
|
||||
|
||||
return (struct grub_script_cmd *) cmd;
|
||||
}
|
||||
|
||||
/* Create a block of commands. CMD contains the command that should
|
||||
be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new
|
||||
cmdblock will be created. */
|
||||
struct grub_script_cmd *
|
||||
grub_script_add_cmd (struct grub_parser_param *state,
|
||||
struct grub_script_cmdblock *cmdblock,
|
||||
struct grub_script_cmd *cmd)
|
||||
{
|
||||
grub_dprintf ("scripting", "cmdblock\n");
|
||||
|
||||
if (! cmd)
|
||||
return (struct grub_script_cmd *) cmdblock;
|
||||
|
||||
if (! cmdblock)
|
||||
{
|
||||
cmdblock = (struct grub_script_cmdblock *) grub_script_malloc (state,
|
||||
sizeof (*cmdblock));
|
||||
cmdblock->cmd.exec = grub_script_execute_cmdblock;
|
||||
cmdblock->cmd.next = 0;
|
||||
cmdblock->cmdlist = cmd;
|
||||
cmd->next = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->next = cmdblock->cmdlist;
|
||||
cmdblock->cmdlist = cmd;
|
||||
}
|
||||
|
||||
return (struct grub_script_cmd *) cmdblock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct grub_script *
|
||||
grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem)
|
||||
{
|
||||
struct grub_script *parsed;
|
||||
|
||||
parsed = grub_malloc (sizeof (*parsed));
|
||||
if (! parsed)
|
||||
{
|
||||
grub_script_mem_free (mem);
|
||||
grub_free (cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
parsed->mem = mem;
|
||||
parsed->cmd = cmd;
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/* Parse the script passed in SCRIPT and return the parsed
|
||||
datastructure that is ready to be interpreted. */
|
||||
struct grub_script *
|
||||
grub_script_parse (char *script, grub_err_t (*getline) (char **))
|
||||
{
|
||||
struct grub_script *parsed;
|
||||
struct grub_script_mem *membackup;
|
||||
struct grub_lexer_param *lexstate;
|
||||
struct grub_parser_param *parsestate;
|
||||
|
||||
parsed = grub_malloc (sizeof (*parsed));
|
||||
if (! parsed)
|
||||
return 0;
|
||||
|
||||
parsestate = grub_malloc (sizeof (*parsestate));
|
||||
if (! parsestate)
|
||||
return 0;
|
||||
|
||||
parsestate->err = 0;
|
||||
parsestate->func_mem = 0;
|
||||
parsestate->memused = 0;
|
||||
parsestate->parsed = 0;
|
||||
|
||||
/* Initialize the lexer. */
|
||||
lexstate = grub_script_lexer_init (script, getline);
|
||||
if (! lexstate)
|
||||
{
|
||||
grub_free (parsed);
|
||||
grub_free (parsestate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
parsestate->lexerstate = lexstate;
|
||||
|
||||
membackup = grub_script_mem_record (parsestate);
|
||||
|
||||
/* Parse the script. */
|
||||
if (grub_script_yyparse (parsestate) || parsestate->err)
|
||||
{
|
||||
struct grub_script_mem *memfree;
|
||||
memfree = grub_script_mem_record_stop (parsestate, membackup);
|
||||
grub_script_mem_free (memfree);
|
||||
grub_free (lexstate);
|
||||
grub_free (parsestate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
parsed->mem = grub_script_mem_record_stop (parsestate, membackup);
|
||||
parsed->cmd = parsestate->parsed;
|
||||
|
||||
grub_free (lexstate);
|
||||
grub_free (parsestate);
|
||||
|
||||
return parsed;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue