Resync with trunk
This commit is contained in:
commit
e68d3b243f
706 changed files with 157184 additions and 45875 deletions
408
normal/arg.c
408
normal/arg.c
|
@ -1,408 +0,0 @@
|
|||
/* arg.c - argument parser */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2004,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/arg.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/term.h>
|
||||
|
||||
/* Built-in parser for default options. */
|
||||
#define SHORT_ARG_HELP -100
|
||||
#define SHORT_ARG_USAGE -101
|
||||
|
||||
static const struct grub_arg_option help_options[] =
|
||||
{
|
||||
{"help", SHORT_ARG_HELP, 0,
|
||||
"display this help and exit", 0, ARG_TYPE_NONE},
|
||||
{"usage", SHORT_ARG_USAGE, 0,
|
||||
"display the usage of this command and exit", 0, ARG_TYPE_NONE},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static struct grub_arg_option *
|
||||
find_short (const struct grub_arg_option *options, char c)
|
||||
{
|
||||
struct grub_arg_option *found = 0;
|
||||
auto struct grub_arg_option *fnd_short (const struct grub_arg_option *opt);
|
||||
|
||||
struct grub_arg_option *fnd_short (const struct grub_arg_option *opt)
|
||||
{
|
||||
while (opt->doc)
|
||||
{
|
||||
if (opt->shortarg == c)
|
||||
return (struct grub_arg_option *) opt;
|
||||
opt++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options)
|
||||
found = fnd_short (options);
|
||||
|
||||
if (! found)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'h':
|
||||
found = (struct grub_arg_option *) help_options;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
found = (struct grub_arg_option *) (help_options + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static char *
|
||||
find_long_option (char *s)
|
||||
{
|
||||
char *argpos = grub_strchr (s, '=');
|
||||
|
||||
if (argpos)
|
||||
{
|
||||
*argpos = '\0';
|
||||
return ++argpos;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct grub_arg_option *
|
||||
find_long (const struct grub_arg_option *options, char *s)
|
||||
{
|
||||
struct grub_arg_option *found = 0;
|
||||
auto struct grub_arg_option *fnd_long (const struct grub_arg_option *opt);
|
||||
|
||||
struct grub_arg_option *fnd_long (const struct grub_arg_option *opt)
|
||||
{
|
||||
while (opt->doc)
|
||||
{
|
||||
if (opt->longarg && ! grub_strcmp (opt->longarg, s))
|
||||
return (struct grub_arg_option *) opt;
|
||||
opt++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options)
|
||||
found = fnd_long (options);
|
||||
|
||||
if (! found)
|
||||
found = fnd_long (help_options);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static void
|
||||
show_usage (grub_command_t cmd)
|
||||
{
|
||||
grub_printf ("Usage: %s\n", cmd->summary);
|
||||
}
|
||||
|
||||
void
|
||||
grub_arg_show_help (grub_command_t cmd)
|
||||
{
|
||||
auto void showargs (const struct grub_arg_option *opt);
|
||||
int h_is_used = 0;
|
||||
int u_is_used = 0;
|
||||
|
||||
auto void showargs (const struct grub_arg_option *opt)
|
||||
{
|
||||
for (; opt->doc; opt++)
|
||||
{
|
||||
int spacing = 20;
|
||||
|
||||
if (opt->shortarg && grub_isgraph (opt->shortarg))
|
||||
grub_printf ("-%c%c ", opt->shortarg, opt->longarg ? ',':' ');
|
||||
else if (opt->shortarg == SHORT_ARG_HELP && ! h_is_used)
|
||||
grub_printf ("-h, ");
|
||||
else if (opt->shortarg == SHORT_ARG_USAGE && ! u_is_used)
|
||||
grub_printf ("-u, ");
|
||||
else
|
||||
grub_printf (" ");
|
||||
|
||||
if (opt->longarg)
|
||||
{
|
||||
grub_printf ("--%s", opt->longarg);
|
||||
spacing -= grub_strlen (opt->longarg);
|
||||
|
||||
if (opt->arg)
|
||||
{
|
||||
grub_printf ("=%s", opt->arg);
|
||||
spacing -= grub_strlen (opt->arg) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (spacing-- > 0)
|
||||
grub_putchar (' ');
|
||||
|
||||
grub_printf ("%s\n", opt->doc);
|
||||
|
||||
switch (opt->shortarg)
|
||||
{
|
||||
case 'h':
|
||||
h_is_used = 1;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
u_is_used = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
show_usage (cmd);
|
||||
grub_printf ("%s\n\n", cmd->description);
|
||||
if (cmd->options)
|
||||
showargs (cmd->options);
|
||||
showargs (help_options);
|
||||
#if 0
|
||||
grub_printf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
parse_option (grub_command_t cmd, int key, char *arg, struct grub_arg_list *usr)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case SHORT_ARG_HELP:
|
||||
grub_arg_show_help (cmd);
|
||||
return -1;
|
||||
|
||||
case SHORT_ARG_USAGE:
|
||||
show_usage (cmd);
|
||||
return -1;
|
||||
|
||||
default:
|
||||
{
|
||||
int found = -1;
|
||||
int i = 0;
|
||||
const struct grub_arg_option *opt = cmd->options;
|
||||
|
||||
while (opt->doc)
|
||||
{
|
||||
if (opt->shortarg && key == opt->shortarg)
|
||||
{
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
opt++;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (found == -1)
|
||||
return -1;
|
||||
|
||||
usr[found].set = 1;
|
||||
usr[found].arg = arg;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
grub_arg_parse (grub_command_t cmd, int argc, char **argv,
|
||||
struct grub_arg_list *usr, char ***args, int *argnum)
|
||||
{
|
||||
int curarg;
|
||||
char *longarg = 0;
|
||||
int complete = 0;
|
||||
char **argl = 0;
|
||||
int num = 0;
|
||||
auto grub_err_t add_arg (char *s);
|
||||
|
||||
grub_err_t add_arg (char *s)
|
||||
{
|
||||
argl = grub_realloc (argl, (++num) * sizeof (char *));
|
||||
if (! argl)
|
||||
return grub_errno;
|
||||
argl[num - 1] = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
for (curarg = 0; curarg < argc; curarg++)
|
||||
{
|
||||
char *arg = argv[curarg];
|
||||
struct grub_arg_option *opt;
|
||||
char *option = 0;
|
||||
|
||||
/* No option is used. */
|
||||
if (arg[0] != '-' || grub_strlen (arg) == 1)
|
||||
{
|
||||
if (add_arg (arg) != 0)
|
||||
goto fail;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* One or more short options. */
|
||||
if (arg[1] != '-')
|
||||
{
|
||||
char *curshort = arg + 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
opt = find_short (cmd->options, *curshort);
|
||||
if (! opt)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"Unknown argument `-%c'\n", *curshort);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
curshort++;
|
||||
|
||||
/* Parse all arguments here except the last one because
|
||||
it can have an argument value. */
|
||||
if (*curshort)
|
||||
{
|
||||
if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno)
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opt->type != ARG_TYPE_NONE)
|
||||
{
|
||||
if (curarg + 1 < argc)
|
||||
{
|
||||
char *nextarg = argv[curarg + 1];
|
||||
if (!(opt->flags & GRUB_ARG_OPTION_OPTIONAL)
|
||||
|| (grub_strlen (nextarg) < 2 || nextarg[0] != '-'))
|
||||
option = argv[++curarg];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else /* The argument starts with "--". */
|
||||
{
|
||||
/* If the argument "--" is used just pass the other
|
||||
arguments. */
|
||||
if (grub_strlen (arg) == 2)
|
||||
{
|
||||
for (curarg++; curarg < argc; curarg++)
|
||||
if (add_arg (arg) != 0)
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
|
||||
longarg = (char *) grub_strdup (arg);
|
||||
if (! longarg)
|
||||
goto fail;
|
||||
|
||||
option = find_long_option (longarg);
|
||||
arg = longarg;
|
||||
|
||||
opt = find_long (cmd->options, arg + 2);
|
||||
if (! opt)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown argument `%s'\n", arg);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (! (opt->type == ARG_TYPE_NONE
|
||||
|| (! option && (opt->flags & GRUB_ARG_OPTION_OPTIONAL))))
|
||||
{
|
||||
if (! option)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"Missing mandatory option for `%s'\n", opt->longarg);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch (opt->type)
|
||||
{
|
||||
case ARG_TYPE_NONE:
|
||||
/* This will never happen. */
|
||||
break;
|
||||
|
||||
case ARG_TYPE_STRING:
|
||||
/* No need to do anything. */
|
||||
break;
|
||||
|
||||
case ARG_TYPE_INT:
|
||||
{
|
||||
char *tail;
|
||||
|
||||
grub_strtoul (option, &tail, 0);
|
||||
if (tail == 0 || tail == option || *tail != '\0' || grub_errno)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"The argument `%s' requires an integer.",
|
||||
arg);
|
||||
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_TYPE_DEVICE:
|
||||
case ARG_TYPE_DIR:
|
||||
case ARG_TYPE_FILE:
|
||||
case ARG_TYPE_PATHNAME:
|
||||
/* XXX: Not implemented. */
|
||||
break;
|
||||
}
|
||||
if (parse_option (cmd, opt->shortarg, option, usr) || grub_errno)
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (option)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"A value was assigned to the argument `%s' while it "
|
||||
"doesn't require an argument\n", arg);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno)
|
||||
goto fail;
|
||||
}
|
||||
grub_free (longarg);
|
||||
longarg = 0;
|
||||
}
|
||||
|
||||
complete = 1;
|
||||
|
||||
*args = argl;
|
||||
*argnum = num;
|
||||
|
||||
fail:
|
||||
grub_free (longarg);
|
||||
|
||||
return complete;
|
||||
}
|
262
normal/auth.c
Normal file
262
normal/auth.c
Normal file
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* 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/auth.h>
|
||||
#include <grub/list.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
struct grub_auth_user
|
||||
{
|
||||
struct grub_auth_user *next;
|
||||
char *name;
|
||||
grub_auth_callback_t callback;
|
||||
void *arg;
|
||||
int authenticated;
|
||||
};
|
||||
|
||||
struct grub_auth_user *users = NULL;
|
||||
|
||||
grub_err_t
|
||||
grub_auth_register_authentication (const char *user,
|
||||
grub_auth_callback_t callback,
|
||||
void *arg)
|
||||
{
|
||||
struct grub_auth_user *cur;
|
||||
|
||||
cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user);
|
||||
if (!cur)
|
||||
cur = grub_zalloc (sizeof (*cur));
|
||||
if (!cur)
|
||||
return grub_errno;
|
||||
cur->callback = callback;
|
||||
cur->arg = arg;
|
||||
if (! cur->name)
|
||||
{
|
||||
cur->name = grub_strdup (user);
|
||||
if (!cur->name)
|
||||
{
|
||||
grub_free (cur);
|
||||
return grub_errno;
|
||||
}
|
||||
grub_list_push (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur));
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_auth_unregister_authentication (const char *user)
|
||||
{
|
||||
struct grub_auth_user *cur;
|
||||
cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user);
|
||||
if (!cur)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "user '%s' not found", user);
|
||||
if (!cur->authenticated)
|
||||
{
|
||||
grub_free (cur->name);
|
||||
grub_list_remove (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur));
|
||||
grub_free (cur);
|
||||
}
|
||||
else
|
||||
{
|
||||
cur->callback = NULL;
|
||||
cur->arg = NULL;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_auth_authenticate (const char *user)
|
||||
{
|
||||
struct grub_auth_user *cur;
|
||||
|
||||
cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user);
|
||||
if (!cur)
|
||||
cur = grub_zalloc (sizeof (*cur));
|
||||
if (!cur)
|
||||
return grub_errno;
|
||||
|
||||
cur->authenticated = 1;
|
||||
|
||||
if (! cur->name)
|
||||
{
|
||||
cur->name = grub_strdup (user);
|
||||
if (!cur->name)
|
||||
{
|
||||
grub_free (cur);
|
||||
return grub_errno;
|
||||
}
|
||||
grub_list_push (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur));
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_auth_deauthenticate (const char *user)
|
||||
{
|
||||
struct grub_auth_user *cur;
|
||||
cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user);
|
||||
if (!cur)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "user '%s' not found", user);
|
||||
if (!cur->callback)
|
||||
{
|
||||
grub_free (cur->name);
|
||||
grub_list_remove (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur));
|
||||
grub_free (cur);
|
||||
}
|
||||
else
|
||||
cur->authenticated = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
is_authenticated (const char *userlist)
|
||||
{
|
||||
const char *superusers;
|
||||
|
||||
auto int hook (grub_list_t item);
|
||||
int hook (grub_list_t item)
|
||||
{
|
||||
const char *name;
|
||||
if (!((struct grub_auth_user *) item)->authenticated)
|
||||
return 0;
|
||||
name = ((struct grub_auth_user *) item)->name;
|
||||
|
||||
return (userlist && grub_strword (userlist, name))
|
||||
|| grub_strword (superusers, name);
|
||||
}
|
||||
|
||||
superusers = grub_env_get ("superusers");
|
||||
|
||||
if (!superusers)
|
||||
return 1;
|
||||
|
||||
return grub_list_iterate (GRUB_AS_LIST (users), hook);
|
||||
}
|
||||
|
||||
static int
|
||||
grub_username_get (char buf[], unsigned buf_size)
|
||||
{
|
||||
unsigned cur_len = 0;
|
||||
int key;
|
||||
|
||||
while (1)
|
||||
{
|
||||
key = GRUB_TERM_ASCII_CHAR (grub_getkey ());
|
||||
if (key == '\n' || key == '\r')
|
||||
break;
|
||||
|
||||
if (key == '\e')
|
||||
{
|
||||
cur_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (key == '\b')
|
||||
{
|
||||
cur_len--;
|
||||
grub_printf ("\b");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!grub_isprint (key))
|
||||
continue;
|
||||
|
||||
if (cur_len + 2 < buf_size)
|
||||
{
|
||||
buf[cur_len++] = key;
|
||||
grub_putchar (key);
|
||||
}
|
||||
}
|
||||
|
||||
grub_memset (buf + cur_len, 0, buf_size - cur_len);
|
||||
|
||||
grub_putchar ('\n');
|
||||
grub_refresh ();
|
||||
|
||||
return (key != '\e');
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_auth_check_authentication (const char *userlist)
|
||||
{
|
||||
char login[1024];
|
||||
struct grub_auth_user *cur = NULL;
|
||||
grub_err_t err;
|
||||
static unsigned long punishment_delay = 1;
|
||||
char entered[GRUB_AUTH_MAX_PASSLEN];
|
||||
|
||||
auto int hook (grub_list_t item);
|
||||
int hook (grub_list_t item)
|
||||
{
|
||||
if (grub_strcmp (login, ((struct grub_auth_user *) item)->name) == 0)
|
||||
cur = (struct grub_auth_user *) item;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto int hook_any (grub_list_t item);
|
||||
int hook_any (grub_list_t item)
|
||||
{
|
||||
if (((struct grub_auth_user *) item)->callback)
|
||||
cur = (struct grub_auth_user *) item;
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_memset (login, 0, sizeof (login));
|
||||
|
||||
if (is_authenticated (userlist))
|
||||
{
|
||||
punishment_delay = 1;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_puts_ (N_("Enter username: "));
|
||||
|
||||
if (!grub_username_get (login, sizeof (login) - 1))
|
||||
goto access_denied;
|
||||
|
||||
grub_puts_ (N_("Enter password: "));
|
||||
|
||||
if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN))
|
||||
goto access_denied;
|
||||
|
||||
grub_list_iterate (GRUB_AS_LIST (users), hook);
|
||||
|
||||
if (!cur || ! cur->callback)
|
||||
goto access_denied;
|
||||
|
||||
err = cur->callback (login, entered, cur->arg);
|
||||
if (is_authenticated (userlist))
|
||||
{
|
||||
punishment_delay = 1;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
access_denied:
|
||||
grub_sleep (punishment_delay);
|
||||
|
||||
if (punishment_delay < GRUB_ULONG_MAX / 2)
|
||||
punishment_delay *= 2;
|
||||
|
||||
return GRUB_ACCESS_DENIED;
|
||||
}
|
138
normal/autofs.c
Normal file
138
normal/autofs.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/* 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. */
|
||||
static grub_named_list_t fs_module_list;
|
||||
|
||||
/* The auto-loading hook for filesystems. */
|
||||
static int
|
||||
autoload_fs_module (void)
|
||||
{
|
||||
grub_named_list_t p;
|
||||
|
||||
while ((p = fs_module_list) != NULL)
|
||||
{
|
||||
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;
|
||||
|
||||
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_fs_autoload_hook_t tmp_autoload_hook;
|
||||
|
||||
grub_sprintf (filename, "%s/fs.lst", prefix);
|
||||
|
||||
/* This rules out the possibility that read_fs_list() is invoked
|
||||
recursively when we call grub_file_open() below. */
|
||||
tmp_autoload_hook = grub_fs_autoload_hook;
|
||||
grub_fs_autoload_hook = NULL;
|
||||
|
||||
file = grub_file_open (filename);
|
||||
if (file)
|
||||
{
|
||||
/* Override previous fs.lst. */
|
||||
while (fs_module_list)
|
||||
{
|
||||
grub_named_list_t tmp;
|
||||
tmp = fs_module_list->next;
|
||||
grub_free (fs_module_list);
|
||||
fs_module_list = tmp;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *buf;
|
||||
char *p;
|
||||
char *q;
|
||||
grub_named_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_fs_autoload_hook = tmp_autoload_hook;
|
||||
}
|
||||
|
||||
grub_free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ignore errors. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* Set the hook. */
|
||||
grub_fs_autoload_hook = autoload_fs_module;
|
||||
}
|
664
normal/cmdline.c
664
normal/cmdline.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007 Free Software Foundation, Inc.
|
||||
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,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
|
||||
|
@ -26,11 +26,13 @@
|
|||
#include <grub/disk.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/charset.h>
|
||||
|
||||
static char *kill_buf;
|
||||
static grub_uint32_t *kill_buf;
|
||||
|
||||
static int hist_size;
|
||||
static char **hist_lines = 0;
|
||||
static grub_uint32_t **hist_lines = 0;
|
||||
static int hist_pos = 0;
|
||||
static int hist_end = 0;
|
||||
static int hist_used = 0;
|
||||
|
@ -38,8 +40,8 @@ static int hist_used = 0;
|
|||
grub_err_t
|
||||
grub_set_history (int newsize)
|
||||
{
|
||||
char **old_hist_lines = hist_lines;
|
||||
hist_lines = grub_malloc (sizeof (char *) * newsize);
|
||||
grub_uint32_t **old_hist_lines = hist_lines;
|
||||
hist_lines = grub_malloc (sizeof (grub_uint32_t *) * newsize);
|
||||
|
||||
/* Copy the old lines into the new buffer. */
|
||||
if (old_hist_lines)
|
||||
|
@ -66,16 +68,16 @@ grub_set_history (int newsize)
|
|||
|
||||
if (hist_pos < hist_end)
|
||||
grub_memmove (hist_lines, old_hist_lines + hist_pos,
|
||||
(hist_end - hist_pos) * sizeof (char *));
|
||||
(hist_end - hist_pos) * sizeof (grub_uint32_t *));
|
||||
else if (hist_used)
|
||||
{
|
||||
/* Copy the older part. */
|
||||
grub_memmove (hist_lines, old_hist_lines + hist_pos,
|
||||
(hist_size - hist_pos) * sizeof (char *));
|
||||
|
||||
(hist_size - hist_pos) * sizeof (grub_uint32_t *));
|
||||
|
||||
/* Copy the newer part. */
|
||||
grub_memmove (hist_lines + hist_size - hist_pos, old_hist_lines,
|
||||
hist_end * sizeof (char *));
|
||||
hist_end * sizeof (grub_uint32_t *));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,17 +91,43 @@ grub_set_history (int newsize)
|
|||
|
||||
/* Get the entry POS from the history where `0' is the newest
|
||||
entry. */
|
||||
static char *
|
||||
static grub_uint32_t *
|
||||
grub_history_get (int pos)
|
||||
{
|
||||
pos = (hist_pos + pos) % hist_size;
|
||||
return hist_lines[pos];
|
||||
}
|
||||
|
||||
static grub_size_t
|
||||
strlen_ucs4 (const grub_uint32_t *s)
|
||||
{
|
||||
const grub_uint32_t *p = s;
|
||||
|
||||
while (*p)
|
||||
p++;
|
||||
|
||||
return p - s;
|
||||
}
|
||||
|
||||
/* Replace the history entry on position POS with the string S. */
|
||||
static void
|
||||
grub_history_set (int pos, grub_uint32_t *s, grub_size_t len)
|
||||
{
|
||||
grub_free (hist_lines[pos]);
|
||||
hist_lines[pos] = grub_malloc ((len + 1) * sizeof (grub_uint32_t));
|
||||
if (!hist_lines[pos])
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return ;
|
||||
}
|
||||
grub_memcpy (hist_lines[pos], s, len * sizeof (grub_uint32_t));
|
||||
hist_lines[pos][len] = 0;
|
||||
}
|
||||
|
||||
/* Insert a new history line S on the top of the history. */
|
||||
static void
|
||||
grub_history_add (char *s)
|
||||
grub_history_add (grub_uint32_t *s, grub_size_t len)
|
||||
{
|
||||
/* Remove the oldest entry in the history to make room for a new
|
||||
entry. */
|
||||
|
@ -120,47 +148,15 @@ grub_history_add (char *s)
|
|||
hist_pos = hist_size + hist_pos;
|
||||
|
||||
/* Insert into history. */
|
||||
hist_lines[hist_pos] = grub_strdup (s);
|
||||
hist_lines[hist_pos] = NULL;
|
||||
grub_history_set (hist_pos, s, len);
|
||||
}
|
||||
|
||||
/* Replace the history entry on position POS with the string S. */
|
||||
static void
|
||||
grub_history_replace (int pos, char *s)
|
||||
grub_history_replace (int pos, grub_uint32_t *s, grub_size_t len)
|
||||
{
|
||||
pos = (hist_pos + pos) % hist_size;
|
||||
grub_free (hist_lines[pos]);
|
||||
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);
|
||||
}
|
||||
grub_history_set ((hist_pos + pos) % hist_size, s, len);
|
||||
}
|
||||
|
||||
/* A completion hook to print items. */
|
||||
|
@ -170,31 +166,30 @@ print_completion (const char *item, grub_completion_type_t type, int count)
|
|||
if (count == 0)
|
||||
{
|
||||
/* If this is the first time, print a label. */
|
||||
const char *what;
|
||||
|
||||
|
||||
grub_puts ("");
|
||||
switch (type)
|
||||
{
|
||||
case GRUB_COMPLETION_TYPE_COMMAND:
|
||||
what = "commands";
|
||||
grub_puts_ (N_("Possible commands are:"));
|
||||
break;
|
||||
case GRUB_COMPLETION_TYPE_DEVICE:
|
||||
what = "devices";
|
||||
grub_puts_ (N_("Possible devices are:"));
|
||||
break;
|
||||
case GRUB_COMPLETION_TYPE_FILE:
|
||||
what = "files";
|
||||
grub_puts_ (N_("Possible files are:"));
|
||||
break;
|
||||
case GRUB_COMPLETION_TYPE_PARTITION:
|
||||
what = "partitions";
|
||||
grub_puts_ (N_("Possible partitions are:"));
|
||||
break;
|
||||
case GRUB_COMPLETION_TYPE_ARGUMENT:
|
||||
what = "arguments";
|
||||
grub_puts_ (N_("Possible arguments are:"));
|
||||
break;
|
||||
default:
|
||||
what = "things";
|
||||
grub_puts_ (N_("Possible things are:"));
|
||||
break;
|
||||
}
|
||||
|
||||
grub_printf ("\nPossible %s are:\n", what);
|
||||
grub_puts ("");
|
||||
}
|
||||
|
||||
if (type == GRUB_COMPLETION_TYPE_PARTITION)
|
||||
|
@ -206,74 +201,112 @@ print_completion (const char *item, grub_completion_type_t type, int count)
|
|||
grub_printf (" %s", item);
|
||||
}
|
||||
|
||||
/* Get a command-line. If ECHO_CHAR is not zero, echo it instead of input
|
||||
characters. If READLINE is non-zero, readline-like key bindings are
|
||||
available. If ESC is pushed, return zero, otherwise return non-zero. */
|
||||
/* FIXME: The dumb interface is not supported yet. */
|
||||
int
|
||||
grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
|
||||
int echo_char, int readline)
|
||||
struct cmdline_term
|
||||
{
|
||||
unsigned xpos, ypos, ystart, width, height;
|
||||
struct grub_term_output *term;
|
||||
};
|
||||
|
||||
/* Get a command-line. If ESC is pushed, return zero,
|
||||
otherwise return command line. */
|
||||
/* FIXME: The dumb interface is not supported yet. */
|
||||
char *
|
||||
grub_cmdline_get (const char *prompt)
|
||||
{
|
||||
unsigned xpos, ypos, ystart;
|
||||
grub_size_t lpos, llen;
|
||||
grub_size_t plen;
|
||||
char buf[max_len];
|
||||
grub_uint32_t *buf;
|
||||
grub_size_t max_len = 256;
|
||||
int key;
|
||||
int histpos = 0;
|
||||
auto void cl_insert (const char *str);
|
||||
auto void cl_insert (const grub_uint32_t *str);
|
||||
auto void cl_delete (unsigned len);
|
||||
auto void cl_print (int pos, int c);
|
||||
auto void cl_set_pos (void);
|
||||
auto inline void __attribute__ ((always_inline)) cl_print (struct cmdline_term *cl_term, int pos,
|
||||
grub_uint32_t c);
|
||||
auto void cl_set_pos (struct cmdline_term *cl_term);
|
||||
auto void cl_print_all (int pos, grub_uint32_t c);
|
||||
auto void cl_set_pos_all (void);
|
||||
auto void init_clterm (struct cmdline_term *cl_term_cur);
|
||||
auto void init_clterm_all (void);
|
||||
const char *prompt_translated = _(prompt);
|
||||
struct cmdline_term *cl_terms;
|
||||
char *ret;
|
||||
unsigned nterms;
|
||||
|
||||
void cl_set_pos (void)
|
||||
{
|
||||
xpos = (plen + lpos) % 79;
|
||||
ypos = ystart + (plen + lpos) / 79;
|
||||
grub_gotoxy (xpos, ypos);
|
||||
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
void cl_print (int pos, int c)
|
||||
{
|
||||
char *p;
|
||||
void cl_set_pos (struct cmdline_term *cl_term)
|
||||
{
|
||||
cl_term->xpos = (plen + lpos) % (cl_term->width - 1);
|
||||
cl_term->ypos = cl_term->ystart + (plen + lpos) / (cl_term->width - 1);
|
||||
grub_term_gotoxy (cl_term->term, cl_term->xpos, cl_term->ypos);
|
||||
}
|
||||
|
||||
for (p = buf + pos; *p; p++)
|
||||
void cl_set_pos_all ()
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < nterms; i++)
|
||||
cl_set_pos (&cl_terms[i]);
|
||||
}
|
||||
|
||||
inline void __attribute__ ((always_inline)) cl_print (struct cmdline_term *cl_term, int pos, grub_uint32_t c)
|
||||
{
|
||||
grub_uint32_t *p;
|
||||
|
||||
for (p = buf + pos; p < buf + llen; p++)
|
||||
{
|
||||
if (xpos++ > 78)
|
||||
{
|
||||
grub_putchar ('\n');
|
||||
|
||||
xpos = 1;
|
||||
if (ypos == (unsigned) (grub_getxy () & 0xFF))
|
||||
ystart--;
|
||||
else
|
||||
ypos++;
|
||||
}
|
||||
|
||||
if (c)
|
||||
grub_putchar (c);
|
||||
grub_putcode (c, cl_term->term);
|
||||
else
|
||||
grub_putchar (*p);
|
||||
grub_putcode (*p, cl_term->term);
|
||||
cl_term->xpos++;
|
||||
if (cl_term->xpos >= cl_term->width - 1)
|
||||
{
|
||||
cl_term->xpos = 0;
|
||||
if (cl_term->ypos >= (unsigned) (cl_term->height - 1))
|
||||
cl_term->ystart--;
|
||||
else
|
||||
cl_term->ypos++;
|
||||
grub_putcode ('\n', cl_term->term);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cl_insert (const char *str)
|
||||
|
||||
void cl_print_all (int pos, grub_uint32_t c)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < nterms; i++)
|
||||
cl_print (&cl_terms[i], pos, c);
|
||||
}
|
||||
|
||||
void cl_insert (const grub_uint32_t *str)
|
||||
{
|
||||
grub_size_t len = grub_strlen (str);
|
||||
grub_size_t len = strlen_ucs4 (str);
|
||||
|
||||
if (len + llen >= max_len)
|
||||
{
|
||||
grub_uint32_t *nbuf;
|
||||
max_len *= 2;
|
||||
nbuf = grub_realloc (buf, sizeof (grub_uint32_t) * max_len);
|
||||
if (nbuf)
|
||||
buf = nbuf;
|
||||
else
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
max_len /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (len + llen < max_len)
|
||||
{
|
||||
grub_memmove (buf + lpos + len, buf + lpos, llen - lpos + 1);
|
||||
grub_memmove (buf + lpos, str, len);
|
||||
grub_memmove (buf + lpos + len, buf + lpos,
|
||||
(llen - lpos + 1) * sizeof (grub_uint32_t));
|
||||
grub_memmove (buf + lpos, str, len * sizeof (grub_uint32_t));
|
||||
|
||||
llen += len;
|
||||
lpos += len;
|
||||
cl_print (lpos - len, echo_char);
|
||||
cl_set_pos ();
|
||||
cl_print_all (lpos - len, 0);
|
||||
cl_set_pos_all ();
|
||||
}
|
||||
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
void cl_delete (unsigned len)
|
||||
|
@ -283,182 +316,254 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
|
|||
grub_size_t saved_lpos = lpos;
|
||||
|
||||
lpos = llen - len;
|
||||
cl_set_pos ();
|
||||
cl_print (lpos, ' ');
|
||||
cl_set_pos_all ();
|
||||
cl_print_all (lpos, ' ');
|
||||
lpos = saved_lpos;
|
||||
cl_set_pos ();
|
||||
|
||||
grub_memmove (buf + lpos, buf + lpos + len, llen - lpos + 1);
|
||||
cl_set_pos_all ();
|
||||
|
||||
grub_memmove (buf + lpos, buf + lpos + len,
|
||||
sizeof (grub_uint32_t) * (llen - lpos + 1));
|
||||
llen -= len;
|
||||
cl_print (lpos, echo_char);
|
||||
cl_set_pos ();
|
||||
cl_print_all (lpos, 0);
|
||||
cl_set_pos_all ();
|
||||
}
|
||||
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
plen = grub_strlen (prompt);
|
||||
|
||||
void init_clterm (struct cmdline_term *cl_term_cur)
|
||||
{
|
||||
cl_term_cur->xpos = plen;
|
||||
cl_term_cur->ypos = (grub_term_getxy (cl_term_cur->term) & 0xFF);
|
||||
cl_term_cur->ystart = cl_term_cur->ypos;
|
||||
cl_term_cur->width = grub_term_width (cl_term_cur->term);
|
||||
cl_term_cur->height = grub_term_height (cl_term_cur->term);
|
||||
}
|
||||
|
||||
void init_clterm_all (void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < nterms; i++)
|
||||
init_clterm (&cl_terms[i]);
|
||||
}
|
||||
|
||||
buf = grub_malloc (max_len * sizeof (grub_uint32_t));
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
plen = grub_strlen (prompt_translated) + sizeof (" ") - 1;
|
||||
lpos = llen = 0;
|
||||
buf[0] = '\0';
|
||||
|
||||
if ((grub_getxy () >> 8) != 0)
|
||||
grub_putchar ('\n');
|
||||
|
||||
grub_printf (prompt);
|
||||
|
||||
xpos = plen;
|
||||
ystart = ypos = (grub_getxy () & 0xFF);
|
||||
|
||||
cl_insert (cmdline);
|
||||
{
|
||||
grub_term_output_t term;
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(term)
|
||||
if ((grub_term_getxy (term) >> 8) != 0)
|
||||
grub_putcode ('\n', term);
|
||||
}
|
||||
grub_printf ("%s ", prompt_translated);
|
||||
|
||||
{
|
||||
struct cmdline_term *cl_term_cur;
|
||||
struct grub_term_output *cur;
|
||||
nterms = 0;
|
||||
FOR_ACTIVE_TERM_OUTPUTS(cur)
|
||||
nterms++;
|
||||
|
||||
cl_terms = grub_malloc (sizeof (cl_terms[0]) * nterms);
|
||||
if (!cl_terms)
|
||||
return 0;
|
||||
cl_term_cur = cl_terms;
|
||||
FOR_ACTIVE_TERM_OUTPUTS(cur)
|
||||
{
|
||||
cl_term_cur->term = cur;
|
||||
init_clterm (cl_term_cur);
|
||||
cl_term_cur++;
|
||||
}
|
||||
}
|
||||
|
||||
if (hist_used == 0)
|
||||
grub_history_add (buf);
|
||||
grub_history_add (buf, llen);
|
||||
|
||||
while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r')
|
||||
{
|
||||
if (readline)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case 1: /* Ctrl-a */
|
||||
lpos = 0;
|
||||
cl_set_pos ();
|
||||
break;
|
||||
|
||||
case 2: /* Ctrl-b */
|
||||
if (lpos > 0)
|
||||
{
|
||||
lpos--;
|
||||
cl_set_pos ();
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: /* Ctrl-e */
|
||||
lpos = llen;
|
||||
cl_set_pos ();
|
||||
break;
|
||||
|
||||
case 6: /* Ctrl-f */
|
||||
if (lpos < llen)
|
||||
{
|
||||
lpos++;
|
||||
cl_set_pos ();
|
||||
}
|
||||
break;
|
||||
|
||||
case 9: /* Ctrl-i or TAB */
|
||||
{
|
||||
char *insert;
|
||||
int restore;
|
||||
|
||||
/* Backup the next character and make it 0 so it will
|
||||
be easy to use string functions. */
|
||||
char backup = buf[lpos];
|
||||
buf[lpos] = '\0';
|
||||
|
||||
|
||||
insert = grub_normal_do_completion (buf, &restore,
|
||||
print_completion);
|
||||
/* Restore the original string. */
|
||||
buf[lpos] = backup;
|
||||
|
||||
if (restore)
|
||||
{
|
||||
/* Restore the prompt. */
|
||||
grub_printf ("\n%s%s", prompt, buf);
|
||||
xpos = plen;
|
||||
ystart = ypos = (grub_getxy () & 0xFF);
|
||||
}
|
||||
|
||||
if (insert)
|
||||
{
|
||||
cl_insert (insert);
|
||||
grub_free (insert);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 11: /* Ctrl-k */
|
||||
if (lpos < llen)
|
||||
{
|
||||
if (kill_buf)
|
||||
grub_free (kill_buf);
|
||||
|
||||
kill_buf = grub_strdup (buf + lpos);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
cl_delete (llen - lpos);
|
||||
}
|
||||
break;
|
||||
|
||||
case 14: /* Ctrl-n */
|
||||
{
|
||||
char *hist;
|
||||
|
||||
lpos = 0;
|
||||
|
||||
if (histpos > 0)
|
||||
{
|
||||
grub_history_replace (histpos, buf);
|
||||
histpos--;
|
||||
}
|
||||
|
||||
cl_delete (llen);
|
||||
hist = grub_history_get (histpos);
|
||||
cl_insert (hist);
|
||||
|
||||
break;
|
||||
}
|
||||
case 16: /* Ctrl-p */
|
||||
{
|
||||
char *hist;
|
||||
|
||||
lpos = 0;
|
||||
|
||||
if (histpos < hist_used - 1)
|
||||
{
|
||||
grub_history_replace (histpos, buf);
|
||||
histpos++;
|
||||
}
|
||||
|
||||
cl_delete (llen);
|
||||
hist = grub_history_get (histpos);
|
||||
|
||||
cl_insert (hist);
|
||||
}
|
||||
break;
|
||||
|
||||
case 21: /* Ctrl-u */
|
||||
if (lpos > 0)
|
||||
{
|
||||
grub_size_t n = lpos;
|
||||
|
||||
if (kill_buf)
|
||||
grub_free (kill_buf);
|
||||
|
||||
kill_buf = grub_malloc (n + 1);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
if (kill_buf)
|
||||
{
|
||||
grub_memcpy (kill_buf, buf, n);
|
||||
kill_buf[n] = '\0';
|
||||
}
|
||||
|
||||
lpos = 0;
|
||||
cl_set_pos ();
|
||||
cl_delete (n);
|
||||
}
|
||||
break;
|
||||
|
||||
case 25: /* Ctrl-y */
|
||||
if (kill_buf)
|
||||
cl_insert (kill_buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case 1: /* Ctrl-a */
|
||||
lpos = 0;
|
||||
cl_set_pos_all ();
|
||||
break;
|
||||
|
||||
case 2: /* Ctrl-b */
|
||||
if (lpos > 0)
|
||||
{
|
||||
lpos--;
|
||||
cl_set_pos_all ();
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: /* Ctrl-e */
|
||||
lpos = llen;
|
||||
cl_set_pos_all ();
|
||||
break;
|
||||
|
||||
case 6: /* Ctrl-f */
|
||||
if (lpos < llen)
|
||||
{
|
||||
lpos++;
|
||||
cl_set_pos_all ();
|
||||
}
|
||||
break;
|
||||
|
||||
case 9: /* Ctrl-i or TAB */
|
||||
{
|
||||
int restore;
|
||||
char *insertu8;
|
||||
char *bufu8;
|
||||
|
||||
buf[lpos] = '\0';
|
||||
|
||||
bufu8 = grub_ucs4_to_utf8_alloc (buf, lpos);
|
||||
if (!bufu8)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
insertu8 = grub_normal_do_completion (bufu8, &restore,
|
||||
print_completion);
|
||||
grub_free (bufu8);
|
||||
|
||||
if (restore)
|
||||
{
|
||||
/* Restore the prompt. */
|
||||
grub_printf ("\n%s ", prompt_translated);
|
||||
init_clterm_all ();
|
||||
cl_print_all (0, 0);
|
||||
}
|
||||
|
||||
if (insertu8)
|
||||
{
|
||||
grub_size_t insertlen;
|
||||
grub_ssize_t t;
|
||||
grub_uint32_t *insert;
|
||||
|
||||
insertlen = grub_strlen (insertu8);
|
||||
insert = grub_malloc ((insertlen + 1) * sizeof (grub_uint32_t));
|
||||
if (!insert)
|
||||
{
|
||||
grub_free (insertu8);
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
break;
|
||||
}
|
||||
t = grub_utf8_to_ucs4 (insert, insertlen,
|
||||
(grub_uint8_t *) insertu8,
|
||||
insertlen, 0);
|
||||
if (t > 0)
|
||||
{
|
||||
insert[t] = 0;
|
||||
cl_insert (insert);
|
||||
}
|
||||
|
||||
grub_free (insertu8);
|
||||
grub_free (insert);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 11: /* Ctrl-k */
|
||||
if (lpos < llen)
|
||||
{
|
||||
if (kill_buf)
|
||||
grub_free (kill_buf);
|
||||
|
||||
kill_buf = grub_malloc ((llen - lpos + 1)
|
||||
* sizeof (grub_uint32_t));
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_memcpy (kill_buf, buf + lpos,
|
||||
(llen - lpos + 1) * sizeof (grub_uint32_t));
|
||||
kill_buf[llen - lpos] = 0;
|
||||
}
|
||||
|
||||
cl_delete (llen - lpos);
|
||||
}
|
||||
break;
|
||||
|
||||
case 14: /* Ctrl-n */
|
||||
{
|
||||
grub_uint32_t *hist;
|
||||
|
||||
lpos = 0;
|
||||
|
||||
if (histpos > 0)
|
||||
{
|
||||
grub_history_replace (histpos, buf, llen);
|
||||
histpos--;
|
||||
}
|
||||
|
||||
cl_delete (llen);
|
||||
hist = grub_history_get (histpos);
|
||||
cl_insert (hist);
|
||||
|
||||
break;
|
||||
}
|
||||
case 16: /* Ctrl-p */
|
||||
{
|
||||
grub_uint32_t *hist;
|
||||
|
||||
lpos = 0;
|
||||
|
||||
if (histpos < hist_used - 1)
|
||||
{
|
||||
grub_history_replace (histpos, buf, llen);
|
||||
histpos++;
|
||||
}
|
||||
|
||||
cl_delete (llen);
|
||||
hist = grub_history_get (histpos);
|
||||
|
||||
cl_insert (hist);
|
||||
}
|
||||
break;
|
||||
|
||||
case 21: /* Ctrl-u */
|
||||
if (lpos > 0)
|
||||
{
|
||||
grub_size_t n = lpos;
|
||||
|
||||
if (kill_buf)
|
||||
grub_free (kill_buf);
|
||||
|
||||
kill_buf = grub_malloc (n + 1);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
if (kill_buf)
|
||||
{
|
||||
grub_memcpy (kill_buf, buf, n);
|
||||
kill_buf[n] = '\0';
|
||||
}
|
||||
|
||||
lpos = 0;
|
||||
cl_set_pos_all ();
|
||||
cl_delete (n);
|
||||
}
|
||||
break;
|
||||
|
||||
case 25: /* Ctrl-y */
|
||||
if (kill_buf)
|
||||
cl_insert (kill_buf);
|
||||
break;
|
||||
|
||||
case '\e':
|
||||
return 0;
|
||||
|
||||
|
@ -466,12 +571,12 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
|
|||
if (lpos > 0)
|
||||
{
|
||||
lpos--;
|
||||
cl_set_pos ();
|
||||
cl_set_pos_all ();
|
||||
}
|
||||
else
|
||||
break;
|
||||
/* fall through */
|
||||
|
||||
|
||||
case 4: /* Ctrl-d */
|
||||
if (lpos < llen)
|
||||
cl_delete (1);
|
||||
|
@ -480,7 +585,7 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
|
|||
default:
|
||||
if (grub_isprint (key))
|
||||
{
|
||||
char str[2];
|
||||
grub_uint32_t str[2];
|
||||
|
||||
str[0] = key;
|
||||
str[1] = '\0';
|
||||
|
@ -488,25 +593,26 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
|
|||
}
|
||||
break;
|
||||
}
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
grub_putchar ('\n');
|
||||
grub_refresh ();
|
||||
|
||||
/* If ECHO_CHAR is NUL, remove leading spaces. */
|
||||
/* Remove leading spaces. */
|
||||
lpos = 0;
|
||||
if (! echo_char)
|
||||
while (buf[lpos] == ' ')
|
||||
lpos++;
|
||||
while (buf[lpos] == ' ')
|
||||
lpos++;
|
||||
|
||||
histpos = 0;
|
||||
if (grub_strlen (buf) > 0)
|
||||
if (strlen_ucs4 (buf) > 0)
|
||||
{
|
||||
grub_history_replace (histpos, buf);
|
||||
grub_history_add ("");
|
||||
grub_uint32_t empty[] = { 0 };
|
||||
grub_history_replace (histpos, buf, llen);
|
||||
grub_history_add (empty, 0);
|
||||
}
|
||||
|
||||
grub_memcpy (cmdline, buf + lpos, llen - lpos + 1);
|
||||
|
||||
return 1;
|
||||
ret = grub_ucs4_to_utf8_alloc (buf + lpos, llen - lpos + 1);
|
||||
grub_free (buf);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
/* Borrowed from GRUB Legacy */
|
||||
static char *color_list[16] =
|
||||
|
@ -56,7 +57,7 @@ parse_color_name (grub_uint8_t *ret, char *name)
|
|||
}
|
||||
|
||||
void
|
||||
grub_parse_color_name_pair (grub_uint8_t *ret, char *name)
|
||||
grub_parse_color_name_pair (grub_uint8_t *ret, const char *name)
|
||||
{
|
||||
grub_uint8_t fg, bg;
|
||||
char *fg_name, *bg_name;
|
||||
|
@ -76,7 +77,7 @@ grub_parse_color_name_pair (grub_uint8_t *ret, char *name)
|
|||
bg_name = grub_strchr (fg_name, '/');
|
||||
if (bg_name == NULL)
|
||||
{
|
||||
grub_printf ("Warning: syntax error (missing slash) in `%s'\n", fg_name);
|
||||
grub_printf_ (N_("Warning: syntax error (missing slash) in `%s'\n"), fg_name);
|
||||
grub_wait_after_message ();
|
||||
goto free_and_return;
|
||||
}
|
||||
|
@ -85,13 +86,13 @@ grub_parse_color_name_pair (grub_uint8_t *ret, char *name)
|
|||
|
||||
if (parse_color_name (&fg, fg_name) == -1)
|
||||
{
|
||||
grub_printf ("Warning: invalid foreground color `%s'\n", fg_name);
|
||||
grub_printf_ (N_("Warning: invalid foreground color `%s'\n"), fg_name);
|
||||
grub_wait_after_message ();
|
||||
goto free_and_return;
|
||||
}
|
||||
if (parse_color_name (&bg, bg_name) == -1)
|
||||
{
|
||||
grub_printf ("Warning: invalid background color `%s'\n", bg_name);
|
||||
grub_printf_ (N_("Warning: invalid background color `%s'\n"), bg_name);
|
||||
grub_wait_after_message ();
|
||||
goto free_and_return;
|
||||
}
|
||||
|
@ -102,23 +103,31 @@ free_and_return:
|
|||
grub_free (fg_name);
|
||||
}
|
||||
|
||||
static grub_uint8_t color_normal, color_highlight;
|
||||
|
||||
static void
|
||||
set_colors (void)
|
||||
{
|
||||
struct grub_term_output *term;
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(term)
|
||||
{
|
||||
/* Reloads terminal `normal' and `highlight' colors. */
|
||||
grub_term_setcolor (term, color_normal, color_highlight);
|
||||
|
||||
/* Propagates `normal' color to terminal current color. */
|
||||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace default `normal' colors with the ones specified by user (if any). */
|
||||
char *
|
||||
grub_env_write_color_normal (struct grub_env_var *var __attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
grub_uint8_t color_normal, color_highlight;
|
||||
|
||||
/* Use old settings in case grub_parse_color_name_pair() has no effect. */
|
||||
grub_getcolor (&color_normal, &color_highlight);
|
||||
|
||||
grub_parse_color_name_pair (&color_normal, val);
|
||||
|
||||
/* Reloads terminal `normal' and `highlight' colors. */
|
||||
grub_setcolor (color_normal, color_highlight);
|
||||
|
||||
/* Propagates `normal' color to terminal current color. */
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
|
||||
set_colors ();
|
||||
|
||||
return grub_strdup (val);
|
||||
}
|
||||
|
@ -128,21 +137,9 @@ char *
|
|||
grub_env_write_color_highlight (struct grub_env_var *var __attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
grub_uint8_t color_normal, color_highlight;
|
||||
|
||||
/* Use old settings in case grub_parse_color_name_pair() has no effect. */
|
||||
grub_getcolor (&color_normal, &color_highlight);
|
||||
|
||||
grub_parse_color_name_pair (&color_highlight, val);
|
||||
|
||||
/* Reloads terminal `normal' and `highlight' colors. */
|
||||
grub_setcolor (color_normal, color_highlight);
|
||||
|
||||
/* Propagates `normal' color to terminal current color.
|
||||
Note: Using GRUB_TERM_COLOR_NORMAL here rather than
|
||||
GRUB_TERM_COLOR_HIGHLIGHT is intentional. We don't want to switch
|
||||
to highlight state just because color was reloaded. */
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
|
||||
set_colors ();
|
||||
|
||||
return grub_strdup (val);
|
||||
}
|
||||
|
|
394
normal/command.c
394
normal/command.c
|
@ -1,394 +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>
|
||||
|
||||
static grub_command_t grub_command_list;
|
||||
|
||||
grub_command_t
|
||||
grub_register_command (const char *name,
|
||||
grub_err_t (*func) (struct grub_arg_list *state,
|
||||
int argc, char **args),
|
||||
unsigned flags,
|
||||
const char *summary,
|
||||
const char *description,
|
||||
const struct grub_arg_option *options)
|
||||
{
|
||||
grub_command_t cmd, *p;
|
||||
|
||||
cmd = (grub_command_t) grub_malloc (sizeof (*cmd));
|
||||
if (! cmd)
|
||||
return 0;
|
||||
|
||||
cmd->name = grub_strdup (name);
|
||||
if (! cmd->name)
|
||||
{
|
||||
grub_free (cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd->func = func;
|
||||
cmd->flags = flags;
|
||||
cmd->summary = summary;
|
||||
cmd->description = description;
|
||||
cmd->options = options;
|
||||
cmd->module_name = 0;
|
||||
|
||||
/* Keep the list sorted for simplicity. */
|
||||
p = &grub_command_list;
|
||||
while (*p)
|
||||
{
|
||||
if (grub_strcmp ((*p)->name, name) >= 0)
|
||||
break;
|
||||
|
||||
p = &((*p)->next);
|
||||
}
|
||||
|
||||
if (*p && grub_strcmp ((*p)->name, name) == 0)
|
||||
{
|
||||
grub_command_t q;
|
||||
|
||||
q = *p;
|
||||
if (q->flags & GRUB_COMMAND_FLAG_NOT_LOADED)
|
||||
{
|
||||
q->func = cmd->func;
|
||||
q->flags = cmd->flags;
|
||||
q->summary = cmd->summary;
|
||||
q->description = cmd->description;
|
||||
q->options = cmd->options;
|
||||
grub_free (cmd->name);
|
||||
grub_free (cmd->module_name);
|
||||
grub_free (cmd);
|
||||
cmd = q;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_free (cmd->name);
|
||||
grub_free (cmd);
|
||||
cmd = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->next = *p;
|
||||
*p = cmd;
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void
|
||||
grub_unregister_command (const char *name)
|
||||
{
|
||||
grub_command_t *p, q;
|
||||
|
||||
for (p = &grub_command_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_free (q->module_name);
|
||||
grub_free (q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
grub_command_t
|
||||
grub_command_find (char *cmdline)
|
||||
{
|
||||
char *first_space;
|
||||
grub_command_t cmd;
|
||||
int count = 0;
|
||||
|
||||
first_space = grub_strchr (cmdline, ' ');
|
||||
if (first_space)
|
||||
*first_space = '\0';
|
||||
|
||||
again:
|
||||
|
||||
for (cmd = grub_command_list; cmd; cmd = cmd->next)
|
||||
if (grub_strcmp (cmdline, cmd->name) == 0)
|
||||
break;
|
||||
|
||||
if (! cmd)
|
||||
grub_error (GRUB_ERR_UNKNOWN_COMMAND, "unknown command `%s'", cmdline);
|
||||
else if (cmd->flags & GRUB_COMMAND_FLAG_NOT_LOADED)
|
||||
{
|
||||
/* Automatically load the command. */
|
||||
if (count == 0)
|
||||
{
|
||||
grub_dl_t mod;
|
||||
char *module_name;
|
||||
|
||||
module_name = grub_strdup (cmd->module_name);
|
||||
if (module_name)
|
||||
{
|
||||
mod = grub_dl_load (module_name);
|
||||
if (mod)
|
||||
{
|
||||
grub_dl_ref (mod);
|
||||
count++;
|
||||
grub_free (module_name);
|
||||
goto again;
|
||||
}
|
||||
|
||||
grub_free (module_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* This module seems broken. */
|
||||
grub_unregister_command (cmdline);
|
||||
grub_error (GRUB_ERR_UNKNOWN_COMMAND, "unknown command `%s'", cmdline);
|
||||
cmd = 0;
|
||||
}
|
||||
|
||||
if (first_space)
|
||||
*first_space = ' ';
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
int
|
||||
grub_iterate_commands (int (*iterate) (grub_command_t))
|
||||
{
|
||||
grub_command_t cmd;
|
||||
|
||||
for (cmd = grub_command_list; cmd; cmd = cmd->next)
|
||||
if (iterate (cmd))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
rescue_command (struct grub_arg_list *state __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
grub_longjmp (grub_exit_env, 0);
|
||||
|
||||
/* Never reach here. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
set_command (struct grub_arg_list *state __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
char *var;
|
||||
char *val;
|
||||
|
||||
auto int print_env (struct grub_env_var *env);
|
||||
int print_env (struct grub_env_var *env)
|
||||
{
|
||||
grub_printf ("%s=%s\n", env->name, env->value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! argc)
|
||||
{
|
||||
grub_env_iterate (print_env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
var = args[0];
|
||||
val = grub_strchr (var, '=');
|
||||
if (! val)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "not an assignment");
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
val[0] = 0;
|
||||
grub_env_set (var, val + 1);
|
||||
val[0] = '=';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
unset_command (struct grub_arg_list *state __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
if (argc < 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"no environment variable specified");
|
||||
|
||||
grub_env_unset (args[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
export_command (struct grub_arg_list *state __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
if (argc < 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"no environment variable specified");
|
||||
|
||||
grub_env_export (args[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
insmod_command (struct grub_arg_list *state __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
char *p;
|
||||
grub_dl_t mod;
|
||||
|
||||
if (argc == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
|
||||
|
||||
p = grub_strchr (args[0], '/');
|
||||
if (! p)
|
||||
mod = grub_dl_load (args[0]);
|
||||
else
|
||||
mod = grub_dl_load_file (args[0]);
|
||||
|
||||
if (mod)
|
||||
grub_dl_ref (mod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
rmmod_command (struct grub_arg_list *state __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
grub_dl_t mod;
|
||||
|
||||
if (argc == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
|
||||
|
||||
mod = grub_dl_get (args[0]);
|
||||
if (! mod)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such module");
|
||||
|
||||
if (! grub_dl_unref (mod))
|
||||
grub_dl_unload (mod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
lsmod_command (struct grub_arg_list *state __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
auto int print_module (grub_dl_t mod);
|
||||
|
||||
int print_module (grub_dl_t mod)
|
||||
{
|
||||
grub_dl_dep_t dep;
|
||||
|
||||
grub_printf ("%s\t%d\t\t", mod->name, mod->ref_count);
|
||||
for (dep = mod->dep; dep; dep = dep->next)
|
||||
{
|
||||
if (dep != mod->dep)
|
||||
grub_putchar (',');
|
||||
|
||||
grub_printf ("%s", dep->mod->name);
|
||||
}
|
||||
grub_putchar ('\n');
|
||||
grub_refresh ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_printf ("Name\tRef Count\tDependencies\n");
|
||||
grub_dl_iterate (print_module);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
grub_command_init (void)
|
||||
{
|
||||
grub_register_command ("rescue", rescue_command, GRUB_COMMAND_FLAG_BOTH,
|
||||
"rescue", "Go back to the rescue mode.", 0);
|
||||
|
||||
grub_register_command ("set", set_command, GRUB_COMMAND_FLAG_BOTH,
|
||||
"set [ENVVAR=VALUE]",
|
||||
"Set an environment variable.", 0);
|
||||
|
||||
grub_register_command ("unset", unset_command, GRUB_COMMAND_FLAG_BOTH,
|
||||
"unset ENVVAR", "Remove an environment variable.", 0);
|
||||
|
||||
grub_register_command ("export", export_command, GRUB_COMMAND_FLAG_BOTH,
|
||||
"export ENVVAR", "Export a variable.", 0);
|
||||
|
||||
grub_register_command ("insmod", insmod_command, GRUB_COMMAND_FLAG_BOTH,
|
||||
"insmod MODULE",
|
||||
"Insert a module. The argument can be a file or a module name.",
|
||||
0);
|
||||
|
||||
grub_register_command ("rmmod", rmmod_command, GRUB_COMMAND_FLAG_BOTH,
|
||||
"rmmod MODULE", "Remove a module.", 0);
|
||||
|
||||
grub_register_command ("lsmod", lsmod_command, GRUB_COMMAND_FLAG_BOTH,
|
||||
"lsmod", "Show loaded modules.", 0);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/* completion.c - complete a command, a disk, a partition or a file */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007 Free Software Foundation, Inc.
|
||||
* Copyright (C) 1999,2000,2001,2002,2003,2004,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
|
||||
|
@ -25,6 +25,7 @@
|
|||
#include <grub/disk.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/parser.h>
|
||||
#include <grub/extcmd.h>
|
||||
|
||||
/* The current word. */
|
||||
static char *current_word;
|
||||
|
@ -68,7 +69,7 @@ add_completion (const char *completion, const char *extra,
|
|||
case 2:
|
||||
if (print_func)
|
||||
print_func (match, type, 0);
|
||||
|
||||
|
||||
/* Fall through. */
|
||||
|
||||
default:
|
||||
|
@ -78,7 +79,7 @@ add_completion (const char *completion, const char *extra,
|
|||
|
||||
if (print_func)
|
||||
print_func (completion, type, num_found - 1);
|
||||
|
||||
|
||||
/* Detect the matched portion. */
|
||||
while (*s && *t && *s == *t)
|
||||
{
|
||||
|
@ -91,7 +92,7 @@ add_completion (const char *completion, const char *extra,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -102,7 +103,7 @@ iterate_partition (grub_disk_t disk, const grub_partition_t p)
|
|||
char *partition_name = grub_partition_get_name (p);
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
|
||||
if (! partition_name)
|
||||
return 1;
|
||||
|
||||
|
@ -116,16 +117,16 @@ iterate_partition (grub_disk_t disk, const grub_partition_t p)
|
|||
|
||||
grub_sprintf (name, "%s,%s", disk_name, partition_name);
|
||||
grub_free (partition_name);
|
||||
|
||||
|
||||
ret = add_completion (name, ")", GRUB_COMPLETION_TYPE_PARTITION);
|
||||
grub_free (name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
iterate_dir (const char *filename, int dir)
|
||||
iterate_dir (const char *filename, const struct grub_dirhook_info *info)
|
||||
{
|
||||
if (! dir)
|
||||
if (! info->dir)
|
||||
{
|
||||
const char *prefix;
|
||||
if (cmdline_state == GRUB_PARSER_STATE_DQUOTE)
|
||||
|
@ -146,7 +147,7 @@ iterate_dir (const char *filename, int dir)
|
|||
if (add_completion (fname, "", GRUB_COMPLETION_TYPE_FILE))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -154,10 +155,10 @@ static int
|
|||
iterate_dev (const char *devname)
|
||||
{
|
||||
grub_device_t dev;
|
||||
|
||||
|
||||
/* Complete the partition part. */
|
||||
dev = grub_device_open (devname);
|
||||
|
||||
|
||||
if (dev)
|
||||
{
|
||||
if (dev->disk && dev->disk->has_partitions)
|
||||
|
@ -171,7 +172,7 @@ iterate_dev (const char *devname)
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
@ -179,7 +180,7 @@ iterate_dev (const char *devname)
|
|||
static int
|
||||
iterate_command (grub_command_t cmd)
|
||||
{
|
||||
if (grub_command_find (cmd->name))
|
||||
if (cmd->prio & GRUB_PRIO_LIST_FLAG_ACTIVE)
|
||||
{
|
||||
if (cmd->flags & GRUB_COMMAND_FLAG_CMDLINE)
|
||||
{
|
||||
|
@ -187,7 +188,7 @@ iterate_command (grub_command_t cmd)
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -198,7 +199,7 @@ complete_device (void)
|
|||
/* Check if this is a device or a partition. */
|
||||
char *p = grub_strchr (++current_word, ',');
|
||||
grub_device_t dev;
|
||||
|
||||
|
||||
if (! p)
|
||||
{
|
||||
/* Complete the disk part. */
|
||||
|
@ -212,7 +213,7 @@ complete_device (void)
|
|||
dev = grub_device_open (current_word);
|
||||
*p = ',';
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
|
||||
if (dev)
|
||||
{
|
||||
if (dev->disk && dev->disk->has_partitions)
|
||||
|
@ -223,7 +224,7 @@ complete_device (void)
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
grub_device_close (dev);
|
||||
}
|
||||
else
|
||||
|
@ -243,18 +244,18 @@ complete_file (void)
|
|||
grub_fs_t fs;
|
||||
grub_device_t dev;
|
||||
int ret = 0;
|
||||
|
||||
|
||||
device = grub_file_get_device_name (current_word);
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
return 1;
|
||||
|
||||
|
||||
dev = grub_device_open (device);
|
||||
if (! dev)
|
||||
{
|
||||
ret = 1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
fs = grub_fs_probe (dev);
|
||||
if (! fs)
|
||||
{
|
||||
|
@ -267,25 +268,25 @@ complete_file (void)
|
|||
if (dir)
|
||||
{
|
||||
char *dirfile;
|
||||
|
||||
|
||||
current_word = last_dir + 1;
|
||||
|
||||
|
||||
dir = grub_strdup (dir);
|
||||
if (! dir)
|
||||
{
|
||||
ret = 1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* Cut away the filename part. */
|
||||
dirfile = grub_strrchr (dir, '/');
|
||||
dirfile[1] = '\0';
|
||||
|
||||
|
||||
/* Iterate the directory. */
|
||||
(fs->dir) (dev, dir, iterate_dir);
|
||||
|
||||
|
||||
grub_free (dir);
|
||||
|
||||
|
||||
if (grub_errno)
|
||||
{
|
||||
ret = 1;
|
||||
|
@ -301,7 +302,7 @@ complete_file (void)
|
|||
ret = 1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
suffix = "";
|
||||
num_found = 1;
|
||||
}
|
||||
|
@ -318,19 +319,24 @@ static int
|
|||
complete_arguments (char *command)
|
||||
{
|
||||
grub_command_t cmd;
|
||||
grub_extcmd_t ext;
|
||||
const struct grub_arg_option *option;
|
||||
char shortarg[] = "- ";
|
||||
|
||||
cmd = grub_command_find (command);
|
||||
cmd = grub_command_find (command);
|
||||
|
||||
if (!cmd || !cmd->options)
|
||||
if (!cmd || !(cmd->flags & GRUB_COMMAND_FLAG_EXTCMD))
|
||||
return 0;
|
||||
|
||||
ext = cmd->data;
|
||||
if (!ext->options)
|
||||
return 0;
|
||||
|
||||
if (add_completion ("-u", " ", GRUB_COMPLETION_TYPE_ARGUMENT))
|
||||
return 1;
|
||||
|
||||
/* Add the short arguments. */
|
||||
for (option = cmd->options; option->doc; option++)
|
||||
for (option = ext->options; option->doc; option++)
|
||||
{
|
||||
if (! option->shortarg)
|
||||
continue;
|
||||
|
@ -348,7 +354,7 @@ complete_arguments (char *command)
|
|||
return 1;
|
||||
|
||||
/* Add the long arguments. */
|
||||
for (option = cmd->options; option->doc; option++)
|
||||
for (option = ext->options; option->doc; option++)
|
||||
{
|
||||
char *longarg;
|
||||
if (!option->longarg)
|
||||
|
@ -403,16 +409,19 @@ grub_normal_do_completion (char *buf, int *restore,
|
|||
if (grub_parser_split_cmdline (buf, 0, &argc, &argv))
|
||||
return 0;
|
||||
|
||||
current_word = argv[argc];
|
||||
if (argc == 0)
|
||||
current_word = "";
|
||||
else
|
||||
current_word = argv[argc - 1];
|
||||
|
||||
/* Determine the state the command line is in, depending on the
|
||||
state, it can be determined how to complete. */
|
||||
cmdline_state = get_state (buf);
|
||||
|
||||
if (argc == 0)
|
||||
if (argc == 1 || argc == 0)
|
||||
{
|
||||
/* Complete a command. */
|
||||
if (grub_iterate_commands (iterate_command))
|
||||
if (grub_command_iterate (iterate_command))
|
||||
goto fail;
|
||||
}
|
||||
else if (*current_word == '-')
|
||||
|
@ -472,20 +481,22 @@ grub_normal_do_completion (char *buf, int *restore,
|
|||
|
||||
if (num_found == 1)
|
||||
grub_strcat (ret, suffix);
|
||||
|
||||
|
||||
if (*ret == '\0')
|
||||
{
|
||||
grub_free (ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
grub_free (argv[0]);
|
||||
|
||||
if (argc != 0)
|
||||
grub_free (argv[0]);
|
||||
grub_free (match);
|
||||
return ret;
|
||||
}
|
||||
|
||||
fail:
|
||||
grub_free (argv[0]);
|
||||
if (argc != 0)
|
||||
grub_free (argv[0]);
|
||||
grub_free (match);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
|
|
153
normal/crypto.c
Normal file
153
normal/crypto.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
/* crypto.c - support crypto autoload */
|
||||
/*
|
||||
* 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/crypto.h>
|
||||
#include <grub/normal.h>
|
||||
|
||||
struct load_spec
|
||||
{
|
||||
struct load_spec *next;
|
||||
char *name;
|
||||
char *modname;
|
||||
};
|
||||
|
||||
struct load_spec *crypto_specs = NULL;
|
||||
|
||||
static void
|
||||
grub_crypto_autoload (const char *name)
|
||||
{
|
||||
struct load_spec *cur;
|
||||
grub_dl_t mod;
|
||||
|
||||
for (cur = crypto_specs; cur; cur = cur->next)
|
||||
if (grub_strcasecmp (name, cur->name) == 0)
|
||||
{
|
||||
mod = grub_dl_load (cur->modname);
|
||||
if (mod)
|
||||
grub_dl_ref (mod);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
grub_crypto_spec_free (void)
|
||||
{
|
||||
struct load_spec *cur, *next;
|
||||
for (cur = crypto_specs; cur; cur = next)
|
||||
{
|
||||
next = cur->next;
|
||||
grub_free (cur->name);
|
||||
grub_free (cur->modname);
|
||||
grub_free (cur);
|
||||
}
|
||||
crypto_specs = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Read the file crypto.lst for auto-loading. */
|
||||
void
|
||||
read_crypto_list (void)
|
||||
{
|
||||
const char *prefix;
|
||||
char *filename;
|
||||
grub_file_t file;
|
||||
char *buf = NULL;
|
||||
|
||||
prefix = grub_env_get ("prefix");
|
||||
if (!prefix)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
filename = grub_malloc (grub_strlen (prefix) + sizeof ("/crypto.lst"));
|
||||
if (!filename)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
grub_sprintf (filename, "%s/crypto.lst", prefix);
|
||||
file = grub_file_open (filename);
|
||||
if (!file)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Override previous commands.lst. */
|
||||
grub_crypto_spec_free ();
|
||||
|
||||
for (;; grub_free (buf))
|
||||
{
|
||||
char *p, *name;
|
||||
struct load_spec *cur;
|
||||
|
||||
buf = grub_file_getline (file);
|
||||
|
||||
if (! buf)
|
||||
break;
|
||||
|
||||
name = buf;
|
||||
|
||||
p = grub_strchr (name, ':');
|
||||
if (! p)
|
||||
continue;
|
||||
|
||||
*p = '\0';
|
||||
while (*++p == ' ')
|
||||
;
|
||||
|
||||
cur = grub_malloc (sizeof (*cur));
|
||||
if (!cur)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
cur->name = grub_strdup (name);
|
||||
if (! name)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_free (cur);
|
||||
continue;
|
||||
}
|
||||
|
||||
cur->modname = grub_strdup (p);
|
||||
if (! cur->modname)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_free (cur);
|
||||
grub_free (cur->name);
|
||||
continue;
|
||||
}
|
||||
cur->next = crypto_specs;
|
||||
crypto_specs = cur;
|
||||
}
|
||||
|
||||
grub_file_close (file);
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
grub_crypto_autoload_hook = grub_crypto_autoload;
|
||||
}
|
100
normal/datetime.c
Normal file
100
normal/datetime.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
/* datetime.c - Module for common datetime function. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 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/datetime.h>
|
||||
|
||||
static char *grub_weekday_names[] =
|
||||
{
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
};
|
||||
|
||||
int
|
||||
grub_get_weekday (struct grub_datetime *datetime)
|
||||
{
|
||||
int a, y, m;
|
||||
|
||||
a = (14 - datetime->month) / 12;
|
||||
y = datetime->year - a;
|
||||
m = datetime->month + 12 * a - 2;
|
||||
|
||||
return (datetime->day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7;
|
||||
}
|
||||
|
||||
char *
|
||||
grub_get_weekday_name (struct grub_datetime *datetime)
|
||||
{
|
||||
return grub_weekday_names[grub_get_weekday (datetime)];
|
||||
}
|
||||
|
||||
#define SECPERMIN 60
|
||||
#define SECPERHOUR (60*SECPERMIN)
|
||||
#define SECPERDAY (24*SECPERHOUR)
|
||||
#define SECPERYEAR (365*SECPERDAY)
|
||||
#define SECPER4YEARS (4*SECPERYEAR+SECPERDAY)
|
||||
|
||||
|
||||
void
|
||||
grub_unixtime2datetime (grub_int32_t nix, struct grub_datetime *datetime)
|
||||
{
|
||||
int i;
|
||||
int div;
|
||||
grub_uint8_t months[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
/* In the period of validity of unixtime all years divisible by 4
|
||||
are bissextile*/
|
||||
/* Convenience: let's have 3 consecutive non-bissextile years
|
||||
at the beginning of the epoch. So count from 1973 instead of 1970 */
|
||||
nix -= 3*SECPERYEAR + SECPERDAY;
|
||||
/* Transform C divisions and modulos to mathematical ones */
|
||||
div = nix / SECPER4YEARS;
|
||||
if (nix < 0)
|
||||
div--;
|
||||
datetime->year = 1973 + 4 * div;
|
||||
nix -= div * SECPER4YEARS;
|
||||
|
||||
/* On 31st December of bissextile years 365 days from the beginning
|
||||
of the year elapsed but year isn't finished yet */
|
||||
if (nix / SECPERYEAR == 4)
|
||||
{
|
||||
datetime->year += 3;
|
||||
nix -= 3*SECPERYEAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
datetime->year += nix / SECPERYEAR;
|
||||
nix %= SECPERYEAR;
|
||||
}
|
||||
for (i = 0; i < 12
|
||||
&& nix >= ((grub_int32_t) (i==1 && datetime->year % 4 == 0
|
||||
? 29 : months[i]))*SECPERDAY; i++)
|
||||
nix -= ((grub_int32_t) (i==1 && datetime->year % 4 == 0
|
||||
? 29 : months[i]))*SECPERDAY;
|
||||
datetime->month = i + 1;
|
||||
datetime->day = 1 + (nix / SECPERDAY);
|
||||
nix %= SECPERDAY;
|
||||
datetime->hour = (nix / SECPERHOUR);
|
||||
nix %= SECPERHOUR;
|
||||
datetime->minute = nix / SECPERMIN;
|
||||
datetime->second = nix % SECPERMIN;
|
||||
}
|
171
normal/dyncmd.c
Normal file
171
normal/dyncmd.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/* 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>
|
||||
#include <grub/i18n.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;
|
||||
|
||||
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 = NULL;
|
||||
grub_command_t ptr, last = 0, next;
|
||||
|
||||
/* Override previous commands.lst. */
|
||||
for (ptr = grub_command_list; ptr; ptr = next)
|
||||
{
|
||||
next = ptr->next;
|
||||
if (ptr->func == grub_dyncmd_dispatcher)
|
||||
{
|
||||
if (last)
|
||||
last->next = ptr->next;
|
||||
else
|
||||
grub_command_list = ptr->next;
|
||||
grub_free (ptr);
|
||||
}
|
||||
else
|
||||
last = ptr;
|
||||
}
|
||||
|
||||
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, N_("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;
|
||||
}
|
254
normal/execute.c
254
normal/execute.c
|
@ -1,254 +0,0 @@
|
|||
/* execute.c -- Execute a GRUB script. */
|
||||
/*
|
||||
* 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/mm.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/arg.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/script.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;
|
||||
struct grub_arg_list *state;
|
||||
struct grub_arg_option *parser;
|
||||
int maxargs = 0;
|
||||
char **parsed_arglist;
|
||||
int numargs;
|
||||
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)
|
||||
{
|
||||
/* Count the amount of options the command has. */
|
||||
parser = (struct grub_arg_option *) grubcmd->options;
|
||||
while (parser && (parser++)->doc)
|
||||
maxargs++;
|
||||
|
||||
/* Set up the option state. */
|
||||
state = grub_malloc (sizeof (struct grub_arg_list) * maxargs);
|
||||
grub_memset (state, 0, sizeof (struct grub_arg_list) * maxargs);
|
||||
|
||||
/* Start the command. */
|
||||
if (! (grubcmd->flags & GRUB_COMMAND_FLAG_NO_ARG_PARSE))
|
||||
{
|
||||
if (grub_arg_parse (grubcmd, argcount, args, state, &parsed_arglist, &numargs))
|
||||
ret = (grubcmd->func) (state, numargs, parsed_arglist);
|
||||
}
|
||||
else
|
||||
ret = (grubcmd->func) (state, argcount, args);
|
||||
|
||||
grub_free (state);
|
||||
}
|
||||
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;
|
||||
char *title;
|
||||
struct grub_script *script;
|
||||
|
||||
cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd;
|
||||
|
||||
/* The title can contain variables, parse them and generate a string
|
||||
from it. */
|
||||
title = grub_script_execute_argument_to_string (cmd_menuentry->title);
|
||||
if (! title)
|
||||
return grub_errno;
|
||||
|
||||
/* Parse the menu entry *again*. */
|
||||
script = grub_script_parse ((char *) cmd_menuentry->sourcecode, 0);
|
||||
|
||||
if (! script)
|
||||
{
|
||||
grub_free (title);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* XXX: When this fails, the memory should be freed? */
|
||||
return grub_normal_menu_addentry (title, script,
|
||||
cmd_menuentry->sourcecode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 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);
|
||||
}
|
232
normal/handler.c
Normal file
232
normal/handler.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
/* handler.c - support handler loading */
|
||||
/*
|
||||
* 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/err.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/handler.h>
|
||||
#include <grub/normal.h>
|
||||
|
||||
struct grub_handler_list
|
||||
{
|
||||
struct grub_handler_list *next;
|
||||
char *name;
|
||||
grub_command_t cmd;
|
||||
};
|
||||
|
||||
static grub_list_t handler_list;
|
||||
|
||||
static grub_err_t
|
||||
grub_handler_cmd (struct grub_command *cmd,
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
char *p;
|
||||
grub_handler_class_t class;
|
||||
grub_handler_t handler;
|
||||
|
||||
p = grub_strchr (cmd->name, '.');
|
||||
if (! p)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid command name");
|
||||
|
||||
if (cmd->data)
|
||||
{
|
||||
if (! grub_dl_get (cmd->data))
|
||||
{
|
||||
grub_dl_t mod;
|
||||
|
||||
mod = grub_dl_load (cmd->data);
|
||||
if (mod)
|
||||
grub_dl_ref (mod);
|
||||
else
|
||||
return grub_errno;
|
||||
}
|
||||
grub_free (cmd->data);
|
||||
cmd->data = 0;
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
class = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_handler_class_list),
|
||||
cmd->name);
|
||||
*p = '.';
|
||||
|
||||
if (! class)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "class not found");
|
||||
|
||||
|
||||
handler = grub_named_list_find (GRUB_AS_NAMED_LIST (class->handler_list),
|
||||
p + 1);
|
||||
if (! handler)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "handler not found");
|
||||
|
||||
grub_handler_set_current (class, handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
insert_handler (char *name, char *module)
|
||||
{
|
||||
struct grub_handler_list *item;
|
||||
char *data;
|
||||
|
||||
if (grub_command_find (name))
|
||||
return;
|
||||
|
||||
item = grub_malloc (sizeof (*item));
|
||||
if (! item)
|
||||
return;
|
||||
|
||||
item->name = grub_strdup (name);
|
||||
if (! item->name)
|
||||
{
|
||||
grub_free (item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (module)
|
||||
{
|
||||
data = grub_strdup (module);
|
||||
if (! data)
|
||||
{
|
||||
grub_free (item->name);
|
||||
grub_free (item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
data = 0;
|
||||
|
||||
item->cmd = grub_register_command (item->name, grub_handler_cmd, 0,
|
||||
"Set active handler.");
|
||||
if (! item->cmd)
|
||||
{
|
||||
grub_free (data);
|
||||
grub_free (item->name);
|
||||
grub_free (item);
|
||||
return;
|
||||
}
|
||||
|
||||
item->cmd->data = data;
|
||||
grub_list_push (&handler_list, GRUB_AS_LIST (item));
|
||||
}
|
||||
|
||||
/* Read the file handler.lst for auto-loading. */
|
||||
void
|
||||
read_handler_list (void)
|
||||
{
|
||||
const char *prefix;
|
||||
static int first_time = 1;
|
||||
const char *class_name;
|
||||
|
||||
auto int iterate_handler (grub_handler_t handler);
|
||||
int iterate_handler (grub_handler_t handler)
|
||||
{
|
||||
char name[grub_strlen (class_name) + grub_strlen (handler->name) + 2];
|
||||
|
||||
grub_strcpy (name, class_name);
|
||||
grub_strcat (name, ".");
|
||||
grub_strcat (name, handler->name);
|
||||
|
||||
insert_handler (name, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto int iterate_class (grub_handler_class_t class);
|
||||
int iterate_class (grub_handler_class_t class)
|
||||
{
|
||||
class_name = class->name;
|
||||
grub_list_iterate (GRUB_AS_LIST (class->handler_list),
|
||||
(grub_list_hook_t) iterate_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 ("/handler.lst"));
|
||||
if (filename)
|
||||
{
|
||||
grub_file_t file;
|
||||
|
||||
grub_sprintf (filename, "%s/handler.lst", prefix);
|
||||
file = grub_file_open (filename);
|
||||
if (file)
|
||||
{
|
||||
char *buf = NULL;
|
||||
for (;; grub_free (buf))
|
||||
{
|
||||
char *p;
|
||||
|
||||
buf = grub_file_getline (file);
|
||||
|
||||
if (! buf)
|
||||
break;
|
||||
|
||||
if (! grub_isgraph (buf[0]))
|
||||
continue;
|
||||
|
||||
p = grub_strchr (buf, ':');
|
||||
if (! p)
|
||||
continue;
|
||||
|
||||
*p = '\0';
|
||||
while (*++p == ' ')
|
||||
;
|
||||
|
||||
insert_handler (buf, p);
|
||||
}
|
||||
grub_file_close (file);
|
||||
}
|
||||
grub_free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
grub_list_iterate (GRUB_AS_LIST (grub_handler_class_list),
|
||||
(grub_list_hook_t) iterate_class);
|
||||
|
||||
/* Ignore errors. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
free_handler_list (void)
|
||||
{
|
||||
struct grub_handler_list *item;
|
||||
|
||||
while ((item = grub_list_pop (&handler_list)) != 0)
|
||||
{
|
||||
grub_free (item->cmd->data);
|
||||
grub_unregister_command (item->cmd);
|
||||
grub_free (item->name);
|
||||
grub_free (item);
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,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/symbol.h>
|
||||
|
||||
.file "setjmp.S"
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
* int grub_setjmp (grub_jmp_buf env)
|
||||
*/
|
||||
FUNCTION(grub_setjmp)
|
||||
movl %ebx, 0(%eax) /* EBX */
|
||||
movl %esi, 4(%eax) /* ESI */
|
||||
movl %edi, 8(%eax) /* EDI */
|
||||
movl %ebp, 12(%eax) /* EBP */
|
||||
popl %ecx
|
||||
movl %esp, 16(%eax) /* ESP */
|
||||
movl %ecx, 20(%eax) /* EIP */
|
||||
xorl %eax, %eax
|
||||
jmp *%ecx
|
||||
|
||||
|
||||
/*
|
||||
* int grub_longjmp (grub_jmp_buf env, int val)
|
||||
*/
|
||||
FUNCTION(grub_longjmp)
|
||||
movl 0(%eax), %ebx
|
||||
movl 4(%eax), %esi
|
||||
movl 8(%eax), %edi
|
||||
movl 12(%eax), %ebp
|
||||
movl 16(%eax), %esp
|
||||
movl 20(%eax), %ecx
|
||||
|
||||
movl %edx, %eax
|
||||
testl %eax, %eax
|
||||
jnz 1f
|
||||
incl %eax
|
||||
1: jmp *%ecx
|
||||
|
363
normal/lexer.c
363
normal/lexer.c
|
@ -1,363 +0,0 @@
|
|||
/* lexer.c - The scripting lexer. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 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/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 (YYSTYPE *yylval, struct grub_parser_param *parsestate);
|
||||
|
||||
int
|
||||
grub_script_yylex (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 (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);
|
||||
}
|
716
normal/main.c
716
normal/main.c
|
@ -1,7 +1,7 @@
|
|||
/* main.c - the normal mode main routine */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2000,2001,2002,2003,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
|
||||
|
@ -20,29 +20,30 @@
|
|||
#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>
|
||||
|
||||
grub_jmp_buf grub_exit_env;
|
||||
|
||||
static grub_fs_module_list_t fs_module_list = 0;
|
||||
#include <grub/reader.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
#include <grub/auth.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/charset.h>
|
||||
|
||||
#define GRUB_DEFAULT_HISTORY_SIZE 50
|
||||
|
||||
static int nested_level = 0;
|
||||
int grub_normal_exit_level = 0;
|
||||
|
||||
/* Read a line from the file FILE. */
|
||||
static char *
|
||||
get_line (grub_file_t file)
|
||||
char *
|
||||
grub_file_getline (grub_file_t file)
|
||||
{
|
||||
char c;
|
||||
int pos = 0;
|
||||
int literal = 0;
|
||||
int comment = 0;
|
||||
char *cmdline;
|
||||
int max_len = 64;
|
||||
|
||||
|
@ -83,23 +84,13 @@ get_line (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
|
||||
{
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
if (pos >= max_len)
|
||||
{
|
||||
char *old_cmdline = cmdline;
|
||||
|
@ -112,6 +103,9 @@ get_line (grub_file_t file)
|
|||
}
|
||||
}
|
||||
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
cmdline[pos++] = c;
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +118,7 @@ get_line (grub_file_t file)
|
|||
grub_free (cmdline);
|
||||
cmdline = 0;
|
||||
}
|
||||
|
||||
|
||||
return cmdline;
|
||||
}
|
||||
|
||||
|
@ -137,7 +131,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;
|
||||
|
@ -147,16 +140,45 @@ free_menu (grub_menu_t menu)
|
|||
grub_env_unset_data_slot ("menu");
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_normal_menu_addentry (const char *title, struct grub_script *script,
|
||||
const char *sourcecode)
|
||||
static void
|
||||
free_menu_entry_classes (struct grub_menu_entry_class *head)
|
||||
{
|
||||
const char *menutitle;
|
||||
/* Free all the classes. */
|
||||
while (head)
|
||||
{
|
||||
struct grub_menu_entry_class *next;
|
||||
|
||||
grub_free (head->name);
|
||||
next = head->next;
|
||||
grub_free (head);
|
||||
head = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a menu entry to the current menu context (as given by the environment
|
||||
variable data slot `menu'). As the configuration file is read, the script
|
||||
parser calls this when a menu entry is to be created. */
|
||||
grub_err_t
|
||||
grub_normal_add_menu_entry (int argc, const char **args,
|
||||
const char *sourcecode)
|
||||
{
|
||||
const char *menutitle = 0;
|
||||
const char *menusourcecode;
|
||||
grub_menu_t menu;
|
||||
grub_menu_entry_t *last;
|
||||
int failed = 0;
|
||||
int i;
|
||||
struct grub_menu_entry_class *classes_head; /* Dummy head node for list. */
|
||||
struct grub_menu_entry_class *classes_tail;
|
||||
char *users = NULL;
|
||||
|
||||
menu = grub_env_get_data_slot("menu");
|
||||
/* Allocate dummy head node for class list. */
|
||||
classes_head = grub_zalloc (sizeof (struct grub_menu_entry_class));
|
||||
if (! classes_head)
|
||||
return grub_errno;
|
||||
classes_tail = classes_head;
|
||||
|
||||
menu = grub_env_get_data_slot ("menu");
|
||||
if (! menu)
|
||||
return grub_error (GRUB_ERR_MENU, "no menu context");
|
||||
|
||||
|
@ -166,10 +188,94 @@ grub_normal_menu_addentry (const char *title, struct grub_script *script,
|
|||
if (! menusourcecode)
|
||||
return grub_errno;
|
||||
|
||||
menutitle = grub_strdup (title);
|
||||
if (! menutitle)
|
||||
/* Parse menu arguments. */
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
/* Capture arguments. */
|
||||
if (grub_strncmp ("--", args[i], 2) == 0)
|
||||
{
|
||||
const char *arg = &args[i][2];
|
||||
|
||||
/* Handle menu class. */
|
||||
if (grub_strcmp(arg, "class") == 0)
|
||||
{
|
||||
char *class_name;
|
||||
struct grub_menu_entry_class *new_class;
|
||||
|
||||
i++;
|
||||
class_name = grub_strdup (args[i]);
|
||||
if (! class_name)
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Create a new class and add it at the tail of the list. */
|
||||
new_class = grub_zalloc (sizeof (struct grub_menu_entry_class));
|
||||
if (! new_class)
|
||||
{
|
||||
grub_free (class_name);
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
/* Fill in the new class node. */
|
||||
new_class->name = class_name;
|
||||
/* Link the tail to it, and make it the new tail. */
|
||||
classes_tail->next = new_class;
|
||||
classes_tail = new_class;
|
||||
continue;
|
||||
}
|
||||
else if (grub_strcmp(arg, "users") == 0)
|
||||
{
|
||||
i++;
|
||||
users = grub_strdup (args[i]);
|
||||
if (! users)
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle invalid argument. */
|
||||
failed = 1;
|
||||
grub_error (GRUB_ERR_MENU,
|
||||
"invalid argument for menuentry: %s", args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Capture title. */
|
||||
if (! menutitle)
|
||||
{
|
||||
menutitle = grub_strdup (args[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
failed = 1;
|
||||
grub_error (GRUB_ERR_MENU,
|
||||
"too many titles for menuentry: %s", args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Validate arguments. */
|
||||
if ((! failed) && (! menutitle))
|
||||
{
|
||||
grub_error (GRUB_ERR_MENU, "menuentry is missing title");
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
/* If argument parsing failed, free any allocated resources. */
|
||||
if (failed)
|
||||
{
|
||||
free_menu_entry_classes (classes_head);
|
||||
grub_free ((void *) menutitle);
|
||||
grub_free ((void *) menusourcecode);
|
||||
|
||||
/* Here we assume that grub_error has been used to specify failure details. */
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
@ -177,17 +283,20 @@ grub_normal_menu_addentry (const char *title, struct grub_script *script,
|
|||
while (*last)
|
||||
last = &(*last)->next;
|
||||
|
||||
*last = grub_malloc (sizeof (**last));
|
||||
*last = grub_zalloc (sizeof (**last));
|
||||
if (! *last)
|
||||
{
|
||||
free_menu_entry_classes (classes_head);
|
||||
grub_free ((void *) menutitle);
|
||||
grub_free ((void *) menusourcecode);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
(*last)->commands = script;
|
||||
(*last)->title = menutitle;
|
||||
(*last)->next = 0;
|
||||
(*last)->classes = classes_head;
|
||||
if (users)
|
||||
(*last)->restricted = 1;
|
||||
(*last)->users = users;
|
||||
(*last)->sourcecode = menusourcecode;
|
||||
|
||||
menu->size++;
|
||||
|
@ -196,20 +305,56 @@ grub_normal_menu_addentry (const char *title, struct grub_script *script,
|
|||
}
|
||||
|
||||
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_err_t getline (char **line)
|
||||
{
|
||||
currline++;
|
||||
grub_parser_t old_parser = 0;
|
||||
|
||||
*line = get_line (file);
|
||||
if (! *line)
|
||||
return grub_errno;
|
||||
auto grub_err_t getline (char **line, int cont);
|
||||
grub_err_t getline (char **line, int cont __attribute__ ((unused)))
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
*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;
|
||||
}
|
||||
|
@ -217,14 +362,13 @@ 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));
|
||||
newmenu = grub_zalloc (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. */
|
||||
|
@ -232,275 +376,135 @@ 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;
|
||||
char *line;
|
||||
|
||||
cmdline = get_line (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. */
|
||||
/* Print an error, if any. */
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* The parsed script was executed, throw it away. */
|
||||
grub_script_free (parsed_script);
|
||||
if ((getline (&line, 0)) || (! line))
|
||||
break;
|
||||
|
||||
grub_parser_get_current ()->parse_line (line, getline);
|
||||
grub_free (line);
|
||||
}
|
||||
|
||||
grub_file_close (file);
|
||||
|
||||
if (errors > 0)
|
||||
grub_wait_after_message ();
|
||||
if (old_parser)
|
||||
grub_parser_set_current (old_parser);
|
||||
|
||||
return newmenu;
|
||||
}
|
||||
|
||||
/* Initialize the screen. */
|
||||
void
|
||||
grub_normal_init_page (struct grub_term_output *term)
|
||||
{
|
||||
int msg_len;
|
||||
int posx;
|
||||
const char *msg = _("GNU GRUB version %s");
|
||||
|
||||
char *msg_formatted = grub_malloc (grub_strlen(msg) +
|
||||
grub_strlen(PACKAGE_VERSION));
|
||||
grub_uint32_t *unicode_msg;
|
||||
grub_uint32_t *last_position;
|
||||
|
||||
grub_term_cls (term);
|
||||
|
||||
grub_sprintf (msg_formatted, msg, PACKAGE_VERSION);
|
||||
|
||||
msg_len = grub_utf8_to_ucs4_alloc (msg_formatted,
|
||||
&unicode_msg, &last_position);
|
||||
|
||||
if (msg_len < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
posx = grub_getstringwidth (unicode_msg, last_position, term);
|
||||
posx = (grub_term_width (term) - posx) / 2;
|
||||
grub_term_gotoxy (term, posx, 1);
|
||||
|
||||
grub_print_ucs4 (unicode_msg, last_position, term);
|
||||
grub_printf("\n\n");
|
||||
grub_free (unicode_msg);
|
||||
}
|
||||
|
||||
static char *
|
||||
read_lists (struct grub_env_var *var __attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
read_command_list ();
|
||||
read_fs_list ();
|
||||
read_crypto_list ();
|
||||
read_terminal_list ();
|
||||
return val ? grub_strdup (val) : NULL;
|
||||
}
|
||||
|
||||
/* Read the config file CONFIG and execute the menu interface or
|
||||
the command line interface if BATCH is false. */
|
||||
void
|
||||
grub_normal_execute (const char *config, int nested, int batch)
|
||||
{
|
||||
grub_menu_t menu = 0;
|
||||
|
||||
read_lists (NULL, NULL);
|
||||
read_handler_list ();
|
||||
grub_register_variable_hook ("prefix", NULL, read_lists);
|
||||
grub_command_execute ("parser.grub", 0, 0);
|
||||
|
||||
if (config)
|
||||
{
|
||||
menu = read_config_file (config);
|
||||
|
||||
/* Ignore any error. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (! batch)
|
||||
{
|
||||
if (menu && menu->size)
|
||||
{
|
||||
grub_show_menu (menu, nested);
|
||||
if (nested)
|
||||
free_menu (menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Initialize the screen. */
|
||||
void
|
||||
grub_normal_init_page (void)
|
||||
{
|
||||
grub_cls ();
|
||||
grub_printf ("\n\
|
||||
GNU GRUB version %s\n\n",
|
||||
PACKAGE_VERSION);
|
||||
}
|
||||
|
||||
/* Read the file command.lst for auto-loading. */
|
||||
static void
|
||||
read_command_list (void)
|
||||
{
|
||||
const char *prefix;
|
||||
|
||||
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)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
char *p;
|
||||
grub_command_t cmd;
|
||||
char *buf = get_line (file);
|
||||
|
||||
if (! buf)
|
||||
break;
|
||||
|
||||
if (! grub_isgraph (buf[0]))
|
||||
continue;
|
||||
|
||||
p = grub_strchr (buf, ':');
|
||||
if (! p)
|
||||
continue;
|
||||
|
||||
*p = '\0';
|
||||
while (*++p == ' ')
|
||||
;
|
||||
|
||||
if (! grub_isgraph (*p))
|
||||
continue;
|
||||
|
||||
cmd = grub_register_command (buf, 0,
|
||||
GRUB_COMMAND_FLAG_NOT_LOADED,
|
||||
0, 0, 0);
|
||||
if (! cmd)
|
||||
{
|
||||
grub_free (buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
cmd->module_name = grub_strdup (p);
|
||||
if (! cmd->module_name)
|
||||
grub_unregister_command (buf);
|
||||
grub_free (buf);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 = get_line (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;
|
||||
}
|
||||
|
||||
/* Read the config file CONFIG and execute the menu interface or
|
||||
the command-line interface. */
|
||||
void
|
||||
grub_normal_execute (const char *config, int nested)
|
||||
{
|
||||
grub_menu_t menu = 0;
|
||||
|
||||
read_command_list ();
|
||||
read_fs_list ();
|
||||
|
||||
if (config)
|
||||
{
|
||||
menu = read_config_file (config, nested);
|
||||
|
||||
/* Ignore any error. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (menu)
|
||||
{
|
||||
grub_menu_run (menu, nested);
|
||||
if (nested)
|
||||
free_menu (menu);
|
||||
}
|
||||
else
|
||||
grub_cmdline_run (nested);
|
||||
nested_level++;
|
||||
grub_normal_execute (config, 0, 0);
|
||||
grub_cmdline_run (0);
|
||||
nested_level--;
|
||||
if (grub_normal_exit_level)
|
||||
grub_normal_exit_level--;
|
||||
}
|
||||
|
||||
/* Enter normal mode from rescue mode. */
|
||||
static void
|
||||
grub_rescue_cmd_normal (int argc, char *argv[])
|
||||
static grub_err_t
|
||||
grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
if (argc == 0)
|
||||
{
|
||||
/* Guess the config filename. It is necessary to make CONFIG static,
|
||||
so that it won't get broken by longjmp. */
|
||||
static char *config;
|
||||
char *config;
|
||||
const char *prefix;
|
||||
|
||||
|
||||
prefix = grub_env_get ("prefix");
|
||||
if (prefix)
|
||||
{
|
||||
config = grub_malloc (grub_strlen (prefix) + sizeof ("/grub.cfg"));
|
||||
if (! config)
|
||||
return;
|
||||
goto quit;
|
||||
|
||||
grub_sprintf (config, "%s/grub.cfg", prefix);
|
||||
grub_enter_normal_mode (config);
|
||||
|
@ -511,6 +515,126 @@ grub_rescue_cmd_normal (int argc, char *argv[])
|
|||
}
|
||||
else
|
||||
grub_enter_normal_mode (argv[0]);
|
||||
|
||||
quit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Exit from normal mode to rescue mode. */
|
||||
static grub_err_t
|
||||
grub_cmd_normal_exit (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char *argv[] __attribute__ ((unused)))
|
||||
{
|
||||
if (nested_level <= grub_normal_exit_level)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in normal environment");
|
||||
grub_normal_exit_level++;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_normal_reader_init (int nested)
|
||||
{
|
||||
struct grub_term_output *term;
|
||||
const char *msg = _("Minimal BASH-like line editing is supported. For "
|
||||
"the first word, TAB lists possible command completions. Anywhere "
|
||||
"else TAB lists possible device or file completions. %s");
|
||||
const char *msg_esc = _("ESC at any time exits.");
|
||||
char *msg_formatted = grub_malloc (sizeof (char) * (grub_strlen (msg) +
|
||||
grub_strlen(msg_esc) + 1));
|
||||
|
||||
grub_sprintf (msg_formatted, msg, nested ? msg_esc : "");
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(term)
|
||||
{
|
||||
grub_normal_init_page (term);
|
||||
grub_term_setcursor (term, 1);
|
||||
|
||||
grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term);
|
||||
grub_puts ("\n");
|
||||
}
|
||||
grub_free (msg_formatted);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_normal_read_line_real (char **line, int cont, int nested)
|
||||
{
|
||||
grub_parser_t parser = grub_parser_get_current ();
|
||||
char prompt[sizeof(">") + grub_strlen (parser->name)];
|
||||
|
||||
if (cont)
|
||||
grub_sprintf (prompt, ">");
|
||||
else
|
||||
grub_sprintf (prompt, "%s>", parser->name);
|
||||
|
||||
while (1)
|
||||
{
|
||||
*line = grub_cmdline_get (prompt);
|
||||
if (*line)
|
||||
break;
|
||||
|
||||
if (cont || nested)
|
||||
{
|
||||
grub_free (*line);
|
||||
*line = 0;
|
||||
return grub_errno;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_normal_read_line (char **line, int cont)
|
||||
{
|
||||
return grub_normal_read_line_real (line, cont, 0);
|
||||
}
|
||||
|
||||
void
|
||||
grub_cmdline_run (int nested)
|
||||
{
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
|
||||
err = grub_auth_check_authentication (NULL);
|
||||
|
||||
if (err)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
grub_normal_reader_init (nested);
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *line;
|
||||
|
||||
if (grub_normal_exit_level)
|
||||
break;
|
||||
|
||||
/* Print an error, if any. */
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
grub_normal_read_line_real (&line, 0, nested);
|
||||
if (! line)
|
||||
break;
|
||||
|
||||
grub_parser_get_current ()->parse_line (line, grub_normal_read_line);
|
||||
grub_free (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)
|
||||
|
@ -521,9 +645,13 @@ GRUB_MOD_INIT(normal)
|
|||
|
||||
grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
|
||||
|
||||
grub_register_variable_hook ("pager", 0, grub_env_write_pager);
|
||||
|
||||
/* Register a command "normal" for the rescue mode. */
|
||||
grub_rescue_register_command ("normal", grub_rescue_cmd_normal,
|
||||
"enter normal mode");
|
||||
grub_register_command ("normal", grub_cmd_normal,
|
||||
0, "Enter normal mode.");
|
||||
grub_register_command ("normal_exit", grub_cmd_normal_exit,
|
||||
0, "Exit from normal mode.");
|
||||
|
||||
/* Reload terminal colors when these variables are written to. */
|
||||
grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
|
||||
|
@ -532,14 +660,12 @@ GRUB_MOD_INIT(normal)
|
|||
/* Preserve hooks after context changes. */
|
||||
grub_env_export ("color_normal");
|
||||
grub_env_export ("color_highlight");
|
||||
|
||||
/* This registers some built-in commands. */
|
||||
grub_command_init ();
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(normal)
|
||||
{
|
||||
grub_set_history (0);
|
||||
grub_rescue_unregister_command ("normal");
|
||||
grub_register_variable_hook ("pager", 0, 0);
|
||||
grub_fs_autoload_hook = 0;
|
||||
free_handler_list ();
|
||||
}
|
||||
|
||||
|
|
749
normal/menu.c
749
normal/menu.c
|
@ -1,6 +1,7 @@
|
|||
/* menu.c - General supporting functionality for menus. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2003,2004,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
|
||||
|
@ -17,91 +18,39 @@
|
|||
*/
|
||||
|
||||
#include <grub/normal.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/machine/time.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/script.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/parser.h>
|
||||
#include <grub/auth.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/term.h>
|
||||
|
||||
static grub_uint8_t grub_color_menu_normal;
|
||||
static grub_uint8_t grub_color_menu_highlight;
|
||||
/* Time to delay after displaying an error message about a default/fallback
|
||||
entry failing to boot. */
|
||||
#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500
|
||||
|
||||
grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
|
||||
int nested) = NULL;
|
||||
|
||||
/* Wait until the user pushes any key so that the user
|
||||
can see what happened. */
|
||||
void
|
||||
grub_wait_after_message (void)
|
||||
{
|
||||
grub_printf ("\nPress any key to continue...");
|
||||
grub_putchar ('\n');
|
||||
grub_printf_ (N_("Press any key to continue..."));
|
||||
(void) grub_getkey ();
|
||||
grub_putchar ('\n');
|
||||
}
|
||||
|
||||
static void
|
||||
draw_border (void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y);
|
||||
grub_putcode (GRUB_TERM_DISP_UL);
|
||||
for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++)
|
||||
grub_putcode (GRUB_TERM_DISP_HLINE);
|
||||
grub_putcode (GRUB_TERM_DISP_UR);
|
||||
|
||||
for (i = 0; i < (unsigned) GRUB_TERM_NUM_ENTRIES; i++)
|
||||
{
|
||||
grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1);
|
||||
grub_putcode (GRUB_TERM_DISP_VLINE);
|
||||
grub_gotoxy (GRUB_TERM_MARGIN + GRUB_TERM_BORDER_WIDTH - 1,
|
||||
GRUB_TERM_TOP_BORDER_Y + i + 1);
|
||||
grub_putcode (GRUB_TERM_DISP_VLINE);
|
||||
}
|
||||
|
||||
grub_gotoxy (GRUB_TERM_MARGIN,
|
||||
GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES + 1);
|
||||
grub_putcode (GRUB_TERM_DISP_LL);
|
||||
for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++)
|
||||
grub_putcode (GRUB_TERM_DISP_HLINE);
|
||||
grub_putcode (GRUB_TERM_DISP_LR);
|
||||
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
grub_gotoxy (GRUB_TERM_MARGIN,
|
||||
(GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES
|
||||
+ GRUB_TERM_MARGIN + 1));
|
||||
}
|
||||
|
||||
static void
|
||||
print_message (int nested, int edit)
|
||||
{
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
if (edit)
|
||||
{
|
||||
grub_printf ("\n\
|
||||
Minimum Emacs-like screen editing is supported. TAB lists\n\
|
||||
available completions. Press C-x (\'x\' with Ctrl) to boot,\n\
|
||||
C-c (\'c\' with Ctrl) for a command-line or ESC to return menu.");
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_printf ("\n\
|
||||
Use the %C and %C keys to select which entry is highlighted.\n",
|
||||
(grub_uint32_t) GRUB_TERM_DISP_UP, (grub_uint32_t) GRUB_TERM_DISP_DOWN);
|
||||
grub_printf ("\
|
||||
Press enter to boot the selected OS, \'e\' to edit the\n\
|
||||
commands before booting or \'c\' for a command-line.");
|
||||
if (nested)
|
||||
grub_printf ("\n\
|
||||
ESC to return previous menu.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static grub_menu_entry_t
|
||||
get_entry (grub_menu_t menu, int no)
|
||||
/* Get a menu entry by its index in the entry list. */
|
||||
grub_menu_entry_t
|
||||
grub_menu_get_entry (grub_menu_t menu, int no)
|
||||
{
|
||||
grub_menu_entry_t e;
|
||||
|
||||
|
@ -111,148 +60,20 @@ get_entry (grub_menu_t menu, int no)
|
|||
return e;
|
||||
}
|
||||
|
||||
static void
|
||||
print_entry (int y, int highlight, grub_menu_entry_t entry)
|
||||
{
|
||||
int x;
|
||||
const char *title;
|
||||
grub_ssize_t len;
|
||||
grub_uint32_t *unicode_title;
|
||||
grub_ssize_t i;
|
||||
grub_uint8_t old_color_normal, old_color_highlight;
|
||||
|
||||
title = entry ? entry->title : "";
|
||||
unicode_title = grub_malloc (grub_strlen (title) * sizeof (*unicode_title));
|
||||
if (! unicode_title)
|
||||
/* XXX How to show this error? */
|
||||
return;
|
||||
|
||||
len = grub_utf8_to_ucs4 (unicode_title, (grub_uint8_t *) title,
|
||||
grub_strlen (title));
|
||||
if (len < 0)
|
||||
{
|
||||
/* It is an invalid sequence. */
|
||||
grub_free (unicode_title);
|
||||
return;
|
||||
}
|
||||
|
||||
grub_getcolor (&old_color_normal, &old_color_highlight);
|
||||
grub_setcolor (grub_color_menu_normal, grub_color_menu_highlight);
|
||||
grub_setcolorstate (highlight
|
||||
? GRUB_TERM_COLOR_HIGHLIGHT
|
||||
: GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
|
||||
|
||||
for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
|
||||
x < GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN;
|
||||
i++)
|
||||
{
|
||||
if (i < len
|
||||
&& x <= (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH
|
||||
- GRUB_TERM_MARGIN - 1))
|
||||
{
|
||||
grub_ssize_t width;
|
||||
|
||||
width = grub_getcharwidth (unicode_title[i]);
|
||||
|
||||
if (x + width > (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH
|
||||
- GRUB_TERM_MARGIN - 1))
|
||||
grub_putcode (GRUB_TERM_DISP_RIGHT);
|
||||
else
|
||||
grub_putcode (unicode_title[i]);
|
||||
|
||||
x += width;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_putchar (' ');
|
||||
x++;
|
||||
}
|
||||
}
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
|
||||
grub_putchar (' ');
|
||||
|
||||
grub_gotoxy (GRUB_TERM_CURSOR_X, y);
|
||||
|
||||
grub_setcolor (old_color_normal, old_color_highlight);
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
|
||||
grub_free (unicode_title);
|
||||
}
|
||||
|
||||
static void
|
||||
print_entries (grub_menu_t menu, int first, int offset)
|
||||
{
|
||||
grub_menu_entry_t e;
|
||||
int i;
|
||||
|
||||
grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
|
||||
GRUB_TERM_FIRST_ENTRY_Y);
|
||||
|
||||
if (first)
|
||||
grub_putcode (GRUB_TERM_DISP_UP);
|
||||
else
|
||||
grub_putchar (' ');
|
||||
|
||||
e = get_entry (menu, first);
|
||||
|
||||
for (i = 0; i < GRUB_TERM_NUM_ENTRIES; i++)
|
||||
{
|
||||
print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e);
|
||||
if (e)
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
|
||||
GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES);
|
||||
|
||||
if (e)
|
||||
grub_putcode (GRUB_TERM_DISP_DOWN);
|
||||
else
|
||||
grub_putchar (' ');
|
||||
|
||||
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
|
||||
}
|
||||
|
||||
/* Initialize the screen. If NESTED is non-zero, assume that this menu
|
||||
is run from another menu or a command-line. If EDIT is non-zero, show
|
||||
a message for the menu entry editor. */
|
||||
void
|
||||
grub_menu_init_page (int nested, int edit)
|
||||
{
|
||||
grub_uint8_t old_color_normal, old_color_highlight;
|
||||
|
||||
grub_getcolor (&old_color_normal, &old_color_highlight);
|
||||
|
||||
/* By default, use the same colors for the menu. */
|
||||
grub_color_menu_normal = old_color_normal;
|
||||
grub_color_menu_highlight = old_color_highlight;
|
||||
|
||||
/* Then give user a chance to replace them. */
|
||||
grub_parse_color_name_pair (&grub_color_menu_normal, grub_env_get ("menu_color_normal"));
|
||||
grub_parse_color_name_pair (&grub_color_menu_highlight, grub_env_get ("menu_color_highlight"));
|
||||
|
||||
grub_normal_init_page ();
|
||||
grub_setcolor (grub_color_menu_normal, grub_color_menu_highlight);
|
||||
draw_border ();
|
||||
grub_setcolor (old_color_normal, old_color_highlight);
|
||||
print_message (nested, edit);
|
||||
}
|
||||
|
||||
/* Return the current timeout. If the variable "timeout" is not set or
|
||||
invalid, return -1. */
|
||||
static int
|
||||
get_timeout (void)
|
||||
int
|
||||
grub_menu_get_timeout (void)
|
||||
{
|
||||
char *val;
|
||||
int timeout;
|
||||
|
||||
|
||||
val = grub_env_get ("timeout");
|
||||
if (! val)
|
||||
return -1;
|
||||
|
||||
|
||||
grub_error_push ();
|
||||
|
||||
|
||||
timeout = (int) grub_strtoul (val, 0, 0);
|
||||
|
||||
/* If the value is invalid, unset the variable. */
|
||||
|
@ -264,39 +85,231 @@ get_timeout (void)
|
|||
}
|
||||
|
||||
grub_error_pop ();
|
||||
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/* Set current timeout in the variable "timeout". */
|
||||
static void
|
||||
set_timeout (int timeout)
|
||||
void
|
||||
grub_menu_set_timeout (int timeout)
|
||||
{
|
||||
/* Ignore TIMEOUT if it is zero, because it will be unset really soon. */
|
||||
if (timeout > 0)
|
||||
{
|
||||
char buf[16];
|
||||
|
||||
|
||||
grub_sprintf (buf, "%d", timeout);
|
||||
grub_env_set ("timeout", buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the entry number from the variable NAME. */
|
||||
/* Get the first entry number from the value of the environment variable NAME,
|
||||
which is a space-separated list of non-negative integers. The entry number
|
||||
which is returned is stripped from the value of NAME. If no entry number
|
||||
can be found, -1 is returned. */
|
||||
static int
|
||||
get_entry_number (const char *name)
|
||||
get_and_remove_first_entry_number (const char *name)
|
||||
{
|
||||
char *val;
|
||||
char *tail;
|
||||
int entry;
|
||||
|
||||
|
||||
val = grub_env_get (name);
|
||||
if (! val)
|
||||
return -1;
|
||||
|
||||
|
||||
grub_error_push ();
|
||||
|
||||
|
||||
entry = (int) grub_strtoul (val, &tail, 0);
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
/* Skip whitespace to find the next digit. */
|
||||
while (*tail && grub_isspace (*tail))
|
||||
tail++;
|
||||
grub_env_set (name, tail);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_env_unset (name);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
entry = -1;
|
||||
}
|
||||
|
||||
grub_error_pop ();
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Run a menu entry. */
|
||||
void
|
||||
grub_menu_execute_entry(grub_menu_entry_t entry)
|
||||
{
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
|
||||
if (entry->restricted)
|
||||
err = grub_auth_check_authentication (entry->users);
|
||||
|
||||
if (err)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
grub_env_set ("chosen", entry->title);
|
||||
|
||||
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, 0);
|
||||
}
|
||||
|
||||
/* Execute ENTRY from the menu MENU, falling back to entries specified
|
||||
in the environment variable "fallback" if it fails. CALLBACK is a
|
||||
pointer to a struct of function pointers which are used to allow the
|
||||
caller provide feedback to the user. */
|
||||
void
|
||||
grub_menu_execute_with_fallback (grub_menu_t menu,
|
||||
grub_menu_entry_t entry,
|
||||
grub_menu_execute_callback_t callback,
|
||||
void *callback_data)
|
||||
{
|
||||
int fallback_entry;
|
||||
|
||||
callback->notify_booting (entry, callback_data);
|
||||
|
||||
grub_menu_execute_entry (entry);
|
||||
|
||||
/* Deal with fallback entries. */
|
||||
while ((fallback_entry = get_and_remove_first_entry_number ("fallback"))
|
||||
>= 0)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
entry = grub_menu_get_entry (menu, fallback_entry);
|
||||
callback->notify_fallback (entry, callback_data);
|
||||
grub_menu_execute_entry (entry);
|
||||
/* If the function call to execute the entry returns at all, then this is
|
||||
taken to indicate a boot failure. For menu entries that do something
|
||||
other than actually boot an operating system, this could assume
|
||||
incorrectly that something failed. */
|
||||
}
|
||||
|
||||
callback->notify_failure (callback_data);
|
||||
}
|
||||
|
||||
static struct grub_menu_viewer *viewers;
|
||||
|
||||
static void
|
||||
menu_set_chosen_entry (int entry)
|
||||
{
|
||||
struct grub_menu_viewer *cur;
|
||||
for (cur = viewers; cur; cur = cur->next)
|
||||
cur->set_chosen_entry (entry, cur->data);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_print_timeout (int timeout)
|
||||
{
|
||||
struct grub_menu_viewer *cur;
|
||||
for (cur = viewers; cur; cur = cur->next)
|
||||
cur->print_timeout (timeout, cur->data);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_fini (void)
|
||||
{
|
||||
struct grub_menu_viewer *cur, *next;
|
||||
for (cur = viewers; cur; cur = next)
|
||||
{
|
||||
next = cur->next;
|
||||
cur->fini (cur->data);
|
||||
grub_free (cur);
|
||||
}
|
||||
viewers = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
menu_init (int entry, grub_menu_t menu, int nested)
|
||||
{
|
||||
struct grub_term_output *term;
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(term)
|
||||
{
|
||||
grub_err_t err;
|
||||
|
||||
if (grub_gfxmenu_try_hook && grub_strcmp (term->name, "gfxterm") == 0)
|
||||
{
|
||||
err = grub_gfxmenu_try_hook (entry, menu, nested);
|
||||
if(!err)
|
||||
continue;
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
err = grub_menu_try_text (term, entry, menu, nested);
|
||||
if(!err)
|
||||
continue;
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clear_timeout (void)
|
||||
{
|
||||
struct grub_menu_viewer *cur;
|
||||
for (cur = viewers; cur; cur = cur->next)
|
||||
cur->clear_timeout (cur->data);
|
||||
}
|
||||
|
||||
void
|
||||
grub_menu_register_viewer (struct grub_menu_viewer *viewer)
|
||||
{
|
||||
viewer->next = viewers;
|
||||
viewers = viewer;
|
||||
}
|
||||
|
||||
/* Get the entry number from the variable NAME. */
|
||||
static int
|
||||
get_entry_number (grub_menu_t menu, const char *name)
|
||||
{
|
||||
char *val;
|
||||
int entry;
|
||||
|
||||
val = grub_env_get (name);
|
||||
if (! val)
|
||||
return -1;
|
||||
|
||||
grub_error_push ();
|
||||
|
||||
entry = (int) grub_strtoul (val, 0, 0);
|
||||
|
||||
if (grub_errno == GRUB_ERR_BAD_NUMBER)
|
||||
{
|
||||
/* See if the variable matches the title of a menu entry. */
|
||||
grub_menu_entry_t e = menu->entry_list;
|
||||
int i;
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
for (i = 0; e; i++)
|
||||
{
|
||||
if (grub_strcmp (e->title, val) == 0)
|
||||
{
|
||||
entry = i;
|
||||
break;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
if (! e)
|
||||
entry = -1;
|
||||
}
|
||||
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
@ -304,171 +317,167 @@ get_entry_number (const char *name)
|
|||
}
|
||||
|
||||
grub_error_pop ();
|
||||
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void
|
||||
print_timeout (int timeout, int offset, int second_stage)
|
||||
{
|
||||
/* NOTE: Do not remove the trailing space characters.
|
||||
They are required to clear the line. */
|
||||
char *msg = " The highlighted entry will be booted automatically in %ds. ";
|
||||
char *msg_end = grub_strchr (msg, '%');
|
||||
|
||||
grub_gotoxy (second_stage ? (msg_end - msg) : 0, GRUB_TERM_HEIGHT - 3);
|
||||
grub_printf (second_stage ? msg_end : msg, timeout);
|
||||
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
|
||||
grub_refresh ();
|
||||
};
|
||||
#define GRUB_MENU_PAGE_SIZE 10
|
||||
|
||||
/* Show the menu and handle menu entry selection. Returns the menu entry
|
||||
index that should be executed or -1 if no entry should be executed (e.g.,
|
||||
Esc pressed to exit a sub-menu or switching menu viewers).
|
||||
If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu
|
||||
entry to be executed is a result of an automatic default selection because
|
||||
of the timeout. */
|
||||
static int
|
||||
run_menu (grub_menu_t menu, int nested)
|
||||
run_menu (grub_menu_t menu, int nested, int *auto_boot)
|
||||
{
|
||||
int first, offset;
|
||||
unsigned long saved_time;
|
||||
int default_entry;
|
||||
grub_uint64_t saved_time;
|
||||
int default_entry, current_entry;
|
||||
int timeout;
|
||||
|
||||
first = 0;
|
||||
|
||||
default_entry = get_entry_number ("default");
|
||||
|
||||
default_entry = get_entry_number (menu, "default");
|
||||
|
||||
/* If DEFAULT_ENTRY is not within the menu entries, fall back to
|
||||
the first entry. */
|
||||
if (default_entry < 0 || default_entry >= menu->size)
|
||||
default_entry = 0;
|
||||
|
||||
offset = default_entry;
|
||||
if (offset > GRUB_TERM_NUM_ENTRIES - 1)
|
||||
/* If timeout is 0, drawing is pointless (and ugly). */
|
||||
if (grub_menu_get_timeout () == 0)
|
||||
{
|
||||
first = offset - (GRUB_TERM_NUM_ENTRIES - 1);
|
||||
offset = GRUB_TERM_NUM_ENTRIES - 1;
|
||||
*auto_boot = 1;
|
||||
return default_entry;
|
||||
}
|
||||
|
||||
current_entry = default_entry;
|
||||
|
||||
/* Initialize the time. */
|
||||
saved_time = grub_get_rtc ();
|
||||
saved_time = grub_get_time_ms ();
|
||||
|
||||
refresh:
|
||||
grub_setcursor (0);
|
||||
grub_menu_init_page (nested, 0);
|
||||
print_entries (menu, first, offset);
|
||||
grub_refresh ();
|
||||
menu_init (current_entry, menu, nested);
|
||||
|
||||
timeout = get_timeout ();
|
||||
timeout = grub_menu_get_timeout ();
|
||||
|
||||
if (timeout > 0)
|
||||
print_timeout (timeout, offset, 0);
|
||||
menu_print_timeout (timeout);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int c;
|
||||
timeout = get_timeout ();
|
||||
|
||||
timeout = grub_menu_get_timeout ();
|
||||
|
||||
if (grub_normal_exit_level)
|
||||
return -1;
|
||||
|
||||
if (timeout > 0)
|
||||
{
|
||||
unsigned long current_time;
|
||||
grub_uint64_t current_time;
|
||||
|
||||
current_time = grub_get_rtc ();
|
||||
if (current_time - saved_time >= GRUB_TICKS_PER_SECOND)
|
||||
current_time = grub_get_time_ms ();
|
||||
if (current_time - saved_time >= 1000)
|
||||
{
|
||||
timeout--;
|
||||
set_timeout (timeout);
|
||||
grub_menu_set_timeout (timeout);
|
||||
saved_time = current_time;
|
||||
print_timeout (timeout, offset, 1);
|
||||
menu_print_timeout (timeout);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
grub_env_unset ("timeout");
|
||||
*auto_boot = 1;
|
||||
menu_fini ();
|
||||
return default_entry;
|
||||
}
|
||||
|
||||
|
||||
if (grub_checkkey () >= 0 || timeout < 0)
|
||||
{
|
||||
c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
|
||||
|
||||
|
||||
if (timeout >= 0)
|
||||
{
|
||||
grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
|
||||
grub_printf ("\
|
||||
");
|
||||
grub_env_unset ("timeout");
|
||||
grub_env_unset ("fallback");
|
||||
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
|
||||
clear_timeout ();
|
||||
}
|
||||
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 16:
|
||||
case GRUB_TERM_HOME:
|
||||
current_entry = 0;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case GRUB_TERM_END:
|
||||
current_entry = menu->size - 1;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case GRUB_TERM_UP:
|
||||
case '^':
|
||||
if (offset > 0)
|
||||
{
|
||||
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
|
||||
get_entry (menu, first + offset));
|
||||
offset--;
|
||||
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
|
||||
get_entry (menu, first + offset));
|
||||
}
|
||||
else if (first > 0)
|
||||
{
|
||||
first--;
|
||||
print_entries (menu, first, offset);
|
||||
}
|
||||
if (current_entry > 0)
|
||||
current_entry--;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case 14:
|
||||
|
||||
case GRUB_TERM_DOWN:
|
||||
case 'v':
|
||||
if (menu->size > first + offset + 1)
|
||||
{
|
||||
if (offset < GRUB_TERM_NUM_ENTRIES - 1)
|
||||
{
|
||||
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
|
||||
get_entry (menu, first + offset));
|
||||
offset++;
|
||||
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
|
||||
get_entry (menu, first + offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
first++;
|
||||
print_entries (menu, first, offset);
|
||||
}
|
||||
}
|
||||
if (current_entry < menu->size - 1)
|
||||
current_entry++;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
|
||||
case GRUB_TERM_PPAGE:
|
||||
if (current_entry < GRUB_MENU_PAGE_SIZE)
|
||||
current_entry = 0;
|
||||
else
|
||||
current_entry -= GRUB_MENU_PAGE_SIZE;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case GRUB_TERM_NPAGE:
|
||||
if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size)
|
||||
current_entry += GRUB_MENU_PAGE_SIZE;
|
||||
else
|
||||
current_entry = menu->size - 1;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
case '\r':
|
||||
case 6:
|
||||
grub_setcursor (1);
|
||||
return first + offset;
|
||||
|
||||
menu_fini ();
|
||||
*auto_boot = 0;
|
||||
return current_entry;
|
||||
|
||||
case '\e':
|
||||
if (nested)
|
||||
{
|
||||
grub_setcursor (1);
|
||||
menu_fini ();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'c':
|
||||
menu_fini ();
|
||||
grub_cmdline_run (1);
|
||||
goto refresh;
|
||||
|
||||
case 'e':
|
||||
menu_fini ();
|
||||
{
|
||||
grub_menu_entry_t e = get_entry (menu, first + offset);
|
||||
grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
|
||||
if (e)
|
||||
grub_menu_entry_run (e);
|
||||
}
|
||||
goto refresh;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
grub_refresh ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,61 +485,115 @@ run_menu (grub_menu_t menu, int nested)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Run a menu entry. */
|
||||
/* Callback invoked immediately before a menu entry is executed. */
|
||||
static void
|
||||
run_menu_entry (grub_menu_entry_t entry)
|
||||
notify_booting (grub_menu_entry_t entry,
|
||||
void *userdata __attribute__((unused)))
|
||||
{
|
||||
grub_script_execute (entry->commands);
|
||||
|
||||
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_printf (" ");
|
||||
grub_printf_ (N_("Booting \'%s\'"), entry->title);
|
||||
grub_printf ("\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
grub_menu_run (grub_menu_t menu, int nested)
|
||||
/* Callback invoked when a default menu entry executed because of a timeout
|
||||
has failed and an attempt will be made to execute the next fallback
|
||||
entry, ENTRY. */
|
||||
static void
|
||||
notify_fallback (grub_menu_entry_t entry,
|
||||
void *userdata __attribute__((unused)))
|
||||
{
|
||||
grub_printf ("\n ");
|
||||
grub_printf_ (N_("Falling back to \'%s\'"), entry->title);
|
||||
grub_printf ("\n\n");
|
||||
grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS);
|
||||
}
|
||||
|
||||
/* Callback invoked when a menu entry has failed and there is no remaining
|
||||
fallback entry to attempt. */
|
||||
static void
|
||||
notify_execution_failure (void *userdata __attribute__((unused)))
|
||||
{
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
grub_printf ("\n ");
|
||||
grub_printf_ (N_("Failed to boot default entries.\n"));
|
||||
grub_wait_after_message ();
|
||||
}
|
||||
|
||||
/* Callbacks used by the text menu to provide user feedback when menu entries
|
||||
are executed. */
|
||||
static struct grub_menu_execute_callback execution_callback =
|
||||
{
|
||||
.notify_booting = notify_booting,
|
||||
.notify_fallback = notify_fallback,
|
||||
.notify_failure = notify_execution_failure
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
show_menu (grub_menu_t menu, int nested)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int boot_entry;
|
||||
grub_menu_entry_t e;
|
||||
int fallback_entry;
|
||||
|
||||
boot_entry = run_menu (menu, nested);
|
||||
int auto_boot;
|
||||
|
||||
boot_entry = run_menu (menu, nested, &auto_boot);
|
||||
if (boot_entry < 0)
|
||||
break;
|
||||
|
||||
e = get_entry (menu, boot_entry);
|
||||
e = grub_menu_get_entry (menu, boot_entry);
|
||||
if (! e)
|
||||
continue; /* Menu is empty. */
|
||||
|
||||
|
||||
grub_cls ();
|
||||
grub_setcursor (1);
|
||||
|
||||
grub_printf (" Booting \'%s\'\n\n", e->title);
|
||||
|
||||
run_menu_entry (e);
|
||||
|
||||
/* Deal with a fallback entry. */
|
||||
/* FIXME: Multiple fallback entries like GRUB Legacy. */
|
||||
fallback_entry = get_entry_number ("fallback");
|
||||
if (fallback_entry >= 0)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
e = get_entry (menu, fallback_entry);
|
||||
grub_env_unset ("fallback");
|
||||
grub_printf ("\n Falling back to \'%s\'\n\n", e->title);
|
||||
run_menu_entry (e);
|
||||
}
|
||||
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
grub_wait_after_message ();
|
||||
}
|
||||
if (auto_boot)
|
||||
{
|
||||
grub_menu_execute_with_fallback (menu, e, &execution_callback, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_menu_execute_entry (e);
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_wait_after_message ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_show_menu (grub_menu_t menu, int nested)
|
||||
{
|
||||
grub_err_t err1, err2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
err1 = show_menu (menu, nested);
|
||||
grub_print_error ();
|
||||
|
||||
if (grub_normal_exit_level)
|
||||
break;
|
||||
|
||||
err2 = grub_auth_check_authentication (NULL);
|
||||
if (err2)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return err1;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
487
normal/menu_text.c
Normal file
487
normal/menu_text.c
Normal file
|
@ -0,0 +1,487 @@
|
|||
/* menu_text.c - Basic text menu implementation. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2004,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/normal.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/charset.h>
|
||||
|
||||
static grub_uint8_t grub_color_menu_normal;
|
||||
static grub_uint8_t grub_color_menu_highlight;
|
||||
|
||||
struct menu_viewer_data
|
||||
{
|
||||
int first, offset;
|
||||
grub_menu_t menu;
|
||||
struct grub_term_output *term;
|
||||
};
|
||||
|
||||
static void
|
||||
print_spaces (int number_spaces, struct grub_term_output *term)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < number_spaces; i++)
|
||||
grub_putcode (' ', term);
|
||||
}
|
||||
|
||||
void
|
||||
grub_print_ucs4 (const grub_uint32_t * str,
|
||||
const grub_uint32_t * last_position,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
while (str < last_position)
|
||||
{
|
||||
grub_putcode (*str, term);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
grub_ssize_t
|
||||
grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
grub_ssize_t width = 0;
|
||||
|
||||
while (str < last_position)
|
||||
{
|
||||
width += grub_term_getcharwidth (term, *str);
|
||||
str++;
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
void
|
||||
grub_print_message_indented (const char *msg, int margin_left, int margin_right,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
int line_len;
|
||||
|
||||
grub_uint32_t *unicode_msg;
|
||||
grub_uint32_t *last_position;
|
||||
|
||||
int msg_len;
|
||||
|
||||
line_len = grub_term_width (term) - grub_term_getcharwidth (term, 'm') *
|
||||
(margin_left + margin_right);
|
||||
|
||||
msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position);
|
||||
|
||||
if (msg_len < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
grub_uint32_t *current_position = unicode_msg;
|
||||
|
||||
grub_uint32_t *next_new_line = unicode_msg;
|
||||
|
||||
int first_loop = 1;
|
||||
|
||||
while (current_position < last_position)
|
||||
{
|
||||
if (! first_loop)
|
||||
grub_putcode ('\n', term);
|
||||
|
||||
next_new_line = (grub_uint32_t *) last_position;
|
||||
|
||||
while (grub_getstringwidth (current_position, next_new_line,term)
|
||||
> line_len
|
||||
|| (next_new_line != last_position && *next_new_line != ' '
|
||||
&& next_new_line > current_position))
|
||||
{
|
||||
next_new_line--;
|
||||
}
|
||||
|
||||
if (next_new_line == current_position)
|
||||
{
|
||||
next_new_line = (next_new_line + line_len > last_position) ?
|
||||
(grub_uint32_t *) last_position : next_new_line + line_len;
|
||||
}
|
||||
|
||||
print_spaces (margin_left, term);
|
||||
grub_print_ucs4 (current_position, next_new_line, term);
|
||||
|
||||
next_new_line++;
|
||||
current_position = next_new_line;
|
||||
first_loop = 0;
|
||||
}
|
||||
grub_free (unicode_msg);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
draw_border (struct grub_term_output *term)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y);
|
||||
grub_putcode (GRUB_TERM_DISP_UL, term);
|
||||
for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++)
|
||||
grub_putcode (GRUB_TERM_DISP_HLINE, term);
|
||||
grub_putcode (GRUB_TERM_DISP_UR, term);
|
||||
|
||||
for (i = 0; i < (unsigned) grub_term_num_entries (term); i++)
|
||||
{
|
||||
grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1);
|
||||
grub_putcode (GRUB_TERM_DISP_VLINE, term);
|
||||
grub_term_gotoxy (term, GRUB_TERM_MARGIN + grub_term_border_width (term)
|
||||
- 1,
|
||||
GRUB_TERM_TOP_BORDER_Y + i + 1);
|
||||
grub_putcode (GRUB_TERM_DISP_VLINE, term);
|
||||
}
|
||||
|
||||
grub_term_gotoxy (term, GRUB_TERM_MARGIN,
|
||||
GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term) + 1);
|
||||
grub_putcode (GRUB_TERM_DISP_LL, term);
|
||||
for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++)
|
||||
grub_putcode (GRUB_TERM_DISP_HLINE, term);
|
||||
grub_putcode (GRUB_TERM_DISP_LR, term);
|
||||
|
||||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
grub_term_gotoxy (term, GRUB_TERM_MARGIN,
|
||||
(GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term)
|
||||
+ GRUB_TERM_MARGIN + 1));
|
||||
}
|
||||
|
||||
static void
|
||||
print_message (int nested, int edit, struct grub_term_output *term)
|
||||
{
|
||||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
if (edit)
|
||||
{
|
||||
grub_putcode ('\n', term);
|
||||
grub_print_message_indented (_("Minimum Emacs-like screen editing is \
|
||||
supported. TAB lists completions. Press Ctrl-x to boot, Ctrl-c for a \
|
||||
command-line or ESC to return menu."), STANDARD_MARGIN, STANDARD_MARGIN,
|
||||
term);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *msg = _("Use the %C and %C keys to select which \
|
||||
entry is highlighted.\n");
|
||||
char *msg_translated =
|
||||
grub_malloc (sizeof (char) * grub_strlen (msg) + 1);
|
||||
|
||||
grub_sprintf (msg_translated, msg, (grub_uint32_t) GRUB_TERM_DISP_UP,
|
||||
(grub_uint32_t) GRUB_TERM_DISP_DOWN);
|
||||
grub_putchar ('\n');
|
||||
grub_print_message_indented (msg_translated, STANDARD_MARGIN,
|
||||
STANDARD_MARGIN, term);
|
||||
|
||||
grub_free (msg_translated);
|
||||
|
||||
if (nested)
|
||||
{
|
||||
grub_print_message_indented
|
||||
(_("Press enter to boot the selected OS, "
|
||||
"\'e\' to edit the commands before booting "
|
||||
"or \'c\' for a command-line. ESC to return previous menu.\n"),
|
||||
STANDARD_MARGIN, STANDARD_MARGIN, term);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_print_message_indented
|
||||
(_("Press enter to boot the selected OS, "
|
||||
"\'e\' to edit the commands before booting "
|
||||
"or \'c\' for a command-line.\n"),
|
||||
STANDARD_MARGIN, STANDARD_MARGIN, term);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_entry (int y, int highlight, grub_menu_entry_t entry,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
int x;
|
||||
const char *title;
|
||||
grub_size_t title_len;
|
||||
grub_ssize_t len;
|
||||
grub_uint32_t *unicode_title;
|
||||
grub_ssize_t i;
|
||||
grub_uint8_t old_color_normal, old_color_highlight;
|
||||
|
||||
title = entry ? entry->title : "";
|
||||
title_len = grub_strlen (title);
|
||||
unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
|
||||
if (! unicode_title)
|
||||
/* XXX How to show this error? */
|
||||
return;
|
||||
|
||||
len = grub_utf8_to_ucs4 (unicode_title, title_len,
|
||||
(grub_uint8_t *) title, -1, 0);
|
||||
if (len < 0)
|
||||
{
|
||||
/* It is an invalid sequence. */
|
||||
grub_free (unicode_title);
|
||||
return;
|
||||
}
|
||||
|
||||
grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
|
||||
grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
|
||||
grub_term_setcolorstate (term, highlight
|
||||
? GRUB_TERM_COLOR_HIGHLIGHT
|
||||
: GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
|
||||
|
||||
for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
|
||||
x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
|
||||
- GRUB_TERM_MARGIN);
|
||||
i++)
|
||||
{
|
||||
if (i < len
|
||||
&& x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
|
||||
- GRUB_TERM_MARGIN - 1))
|
||||
{
|
||||
grub_ssize_t width;
|
||||
|
||||
width = grub_term_getcharwidth (term, unicode_title[i]);
|
||||
|
||||
if (x + width > (int) (GRUB_TERM_LEFT_BORDER_X
|
||||
+ grub_term_border_width (term)
|
||||
- GRUB_TERM_MARGIN - 1))
|
||||
grub_putcode (GRUB_TERM_DISP_RIGHT, term);
|
||||
else
|
||||
grub_putcode (unicode_title[i], term);
|
||||
|
||||
x += width;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_putcode (' ', term);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||||
grub_putcode (' ', term);
|
||||
|
||||
grub_term_gotoxy (term, grub_term_cursor_x (term), y);
|
||||
|
||||
grub_term_setcolor (term, old_color_normal, old_color_highlight);
|
||||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||||
grub_free (unicode_title);
|
||||
}
|
||||
|
||||
static void
|
||||
print_entries (grub_menu_t menu, int first, int offset,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
grub_menu_entry_t e;
|
||||
int i;
|
||||
|
||||
grub_term_gotoxy (term,
|
||||
GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term),
|
||||
GRUB_TERM_FIRST_ENTRY_Y);
|
||||
|
||||
if (first)
|
||||
grub_putcode (GRUB_TERM_DISP_UP, term);
|
||||
else
|
||||
grub_putcode (' ', term);
|
||||
|
||||
e = grub_menu_get_entry (menu, first);
|
||||
|
||||
for (i = 0; i < grub_term_num_entries (term); i++)
|
||||
{
|
||||
print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e, term);
|
||||
if (e)
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X
|
||||
+ grub_term_border_width (term),
|
||||
GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term));
|
||||
|
||||
if (e)
|
||||
grub_putcode (GRUB_TERM_DISP_DOWN, term);
|
||||
else
|
||||
grub_putcode (' ', term);
|
||||
|
||||
grub_term_gotoxy (term, grub_term_cursor_x (term),
|
||||
GRUB_TERM_FIRST_ENTRY_Y + offset);
|
||||
}
|
||||
|
||||
/* Initialize the screen. If NESTED is non-zero, assume that this menu
|
||||
is run from another menu or a command-line. If EDIT is non-zero, show
|
||||
a message for the menu entry editor. */
|
||||
void
|
||||
grub_menu_init_page (int nested, int edit,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
grub_uint8_t old_color_normal, old_color_highlight;
|
||||
|
||||
grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
|
||||
|
||||
/* By default, use the same colors for the menu. */
|
||||
grub_color_menu_normal = old_color_normal;
|
||||
grub_color_menu_highlight = old_color_highlight;
|
||||
|
||||
/* Then give user a chance to replace them. */
|
||||
grub_parse_color_name_pair (&grub_color_menu_normal,
|
||||
grub_env_get ("menu_color_normal"));
|
||||
grub_parse_color_name_pair (&grub_color_menu_highlight,
|
||||
grub_env_get ("menu_color_highlight"));
|
||||
|
||||
grub_normal_init_page (term);
|
||||
grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
|
||||
draw_border (term);
|
||||
grub_term_setcolor (term, old_color_normal, old_color_highlight);
|
||||
print_message (nested, edit, term);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_text_print_timeout (int timeout, void *dataptr)
|
||||
{
|
||||
const char *msg =
|
||||
_("The highlighted entry will be executed automatically in %ds.");
|
||||
struct menu_viewer_data *data = dataptr;
|
||||
char *msg_translated;
|
||||
int posx;
|
||||
|
||||
grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
|
||||
|
||||
msg_translated = grub_malloc (sizeof (char) * grub_strlen (msg) + 5);
|
||||
if (!msg_translated)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
grub_sprintf (msg_translated, msg, timeout);
|
||||
grub_print_message_indented (msg_translated, 3, 0, data->term);
|
||||
|
||||
posx = grub_term_getxy (data->term) >> 8;
|
||||
print_spaces (grub_term_width (data->term) - posx - 1, data->term);
|
||||
|
||||
grub_term_gotoxy (data->term,
|
||||
grub_term_cursor_x (data->term),
|
||||
GRUB_TERM_FIRST_ENTRY_Y + data->offset);
|
||||
grub_term_refresh (data->term);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_text_set_chosen_entry (int entry, void *dataptr)
|
||||
{
|
||||
struct menu_viewer_data *data = dataptr;
|
||||
int oldoffset = data->offset;
|
||||
int complete_redraw = 0;
|
||||
|
||||
data->offset = entry - data->first;
|
||||
if (data->offset > grub_term_num_entries (data->term) - 1)
|
||||
{
|
||||
data->first = entry - (grub_term_num_entries (data->term) - 1);
|
||||
data->offset = grub_term_num_entries (data->term) - 1;
|
||||
complete_redraw = 1;
|
||||
}
|
||||
if (data->offset < 0)
|
||||
{
|
||||
data->offset = 0;
|
||||
data->first = entry;
|
||||
complete_redraw = 1;
|
||||
}
|
||||
if (complete_redraw)
|
||||
print_entries (data->menu, data->first, data->offset, data->term);
|
||||
else
|
||||
{
|
||||
print_entry (GRUB_TERM_FIRST_ENTRY_Y + oldoffset, 0,
|
||||
grub_menu_get_entry (data->menu, data->first + oldoffset),
|
||||
data->term);
|
||||
print_entry (GRUB_TERM_FIRST_ENTRY_Y + data->offset, 1,
|
||||
grub_menu_get_entry (data->menu, data->first + data->offset),
|
||||
data->term);
|
||||
}
|
||||
grub_term_refresh (data->term);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_text_fini (void *dataptr)
|
||||
{
|
||||
struct menu_viewer_data *data = dataptr;
|
||||
|
||||
grub_term_setcursor (data->term, 1);
|
||||
grub_term_cls (data->term);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
menu_text_clear_timeout (void *dataptr)
|
||||
{
|
||||
struct menu_viewer_data *data = dataptr;
|
||||
|
||||
grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
|
||||
print_spaces (grub_term_width (data->term) - 1, data->term);
|
||||
grub_term_gotoxy (data->term, grub_term_cursor_x (data->term),
|
||||
GRUB_TERM_FIRST_ENTRY_Y + data->offset);
|
||||
grub_term_refresh (data->term);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_menu_try_text (struct grub_term_output *term,
|
||||
int entry, grub_menu_t menu, int nested)
|
||||
{
|
||||
struct menu_viewer_data *data;
|
||||
struct grub_menu_viewer *instance;
|
||||
|
||||
instance = grub_zalloc (sizeof (*instance));
|
||||
if (!instance)
|
||||
return grub_errno;
|
||||
|
||||
data = grub_zalloc (sizeof (*data));
|
||||
if (!data)
|
||||
{
|
||||
grub_free (instance);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
data->term = term;
|
||||
instance->data = data;
|
||||
instance->set_chosen_entry = menu_text_set_chosen_entry;
|
||||
instance->print_timeout = menu_text_print_timeout;
|
||||
instance->clear_timeout = menu_text_clear_timeout;
|
||||
instance->fini = menu_text_fini;
|
||||
|
||||
data->menu = menu;
|
||||
|
||||
data->offset = entry;
|
||||
data->first = 0;
|
||||
if (data->offset > grub_term_num_entries (data->term) - 1)
|
||||
{
|
||||
data->first = data->offset - (grub_term_num_entries (data->term) - 1);
|
||||
data->offset = grub_term_num_entries (data->term) - 1;
|
||||
}
|
||||
|
||||
grub_term_setcursor (data->term, 0);
|
||||
grub_menu_init_page (nested, 0, data->term);
|
||||
print_entries (menu, data->first, data->offset, data->term);
|
||||
grub_term_refresh (data->term);
|
||||
grub_menu_register_viewer (instance);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/* misc.c - miscellaneous functions */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2005,2007 Free Software Foundation, Inc.
|
||||
* 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
|
||||
|
@ -23,6 +23,9 @@
|
|||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/datetime.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
/* Print the information on the device NAME. */
|
||||
grub_err_t
|
||||
|
@ -33,16 +36,22 @@ grub_normal_print_device_info (const char *name)
|
|||
|
||||
p = grub_strchr (name, ',');
|
||||
if (p)
|
||||
grub_printf ("\tPartition %s: ", name);
|
||||
{
|
||||
grub_putchar ('\t');
|
||||
grub_printf_ (N_("Partition %s:"), name);
|
||||
grub_putchar (' ');
|
||||
}
|
||||
else
|
||||
grub_printf ("Device %s: ", name);
|
||||
|
||||
{
|
||||
grub_printf_ (N_("Device %s:"), name);
|
||||
grub_putchar (' ');
|
||||
}
|
||||
|
||||
dev = grub_device_open (name);
|
||||
if (! dev)
|
||||
grub_printf ("Filesystem cannot be accessed");
|
||||
grub_printf ("%s", _("Filesystem cannot be accessed"));
|
||||
else if (dev->disk)
|
||||
{
|
||||
char *label;
|
||||
grub_fs_t fs;
|
||||
|
||||
fs = grub_fs_probe (dev);
|
||||
|
@ -50,26 +59,62 @@ grub_normal_print_device_info (const char *name)
|
|||
grub_errno = 0;
|
||||
|
||||
if (fs)
|
||||
grub_printf ("Filesystem type %s", fs->name);
|
||||
else if (! dev->disk->has_partitions || dev->disk->partition)
|
||||
grub_printf ("Unknown filesystem");
|
||||
else
|
||||
grub_printf ("Partition table");
|
||||
|
||||
if (fs && fs->label)
|
||||
{
|
||||
(fs->label) (dev, &label);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
grub_printf_ (N_("Filesystem type %s"), fs->name);
|
||||
if (fs->label)
|
||||
{
|
||||
if (label && grub_strlen (label))
|
||||
grub_printf (", Label %s", label);
|
||||
grub_free (label);
|
||||
char *label;
|
||||
(fs->label) (dev, &label);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
if (label && grub_strlen (label))
|
||||
{
|
||||
grub_putchar (' ');
|
||||
grub_printf_ (N_("- Label \"%s\""), label);
|
||||
}
|
||||
grub_free (label);
|
||||
}
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
if (fs->mtime)
|
||||
{
|
||||
grub_int32_t tm;
|
||||
struct grub_datetime datetime;
|
||||
(fs->mtime) (dev, &tm);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
grub_unixtime2datetime (tm, &datetime);
|
||||
grub_putchar (' ');
|
||||
grub_printf_ (N_("- Last modification time %d-%02d-%02d "
|
||||
"%02d:%02d:%02d %s"),
|
||||
datetime.year, datetime.month, datetime.day,
|
||||
datetime.hour, datetime.minute, datetime.second,
|
||||
grub_get_weekday_name (&datetime));
|
||||
|
||||
}
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
if (fs->uuid)
|
||||
{
|
||||
char *uuid;
|
||||
(fs->uuid) (dev, &uuid);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
if (uuid && grub_strlen (uuid))
|
||||
grub_printf (", UUID %s", uuid);
|
||||
grub_free (uuid);
|
||||
}
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
else if (! dev->disk->has_partitions || dev->disk->partition)
|
||||
grub_printf ("%s", _("Unknown filesystem"));
|
||||
else
|
||||
grub_printf ("%s", _("Partition table"));
|
||||
|
||||
grub_device_close (dev);
|
||||
}
|
||||
|
||||
grub_printf ("\n");
|
||||
grub_putchar ('\n');
|
||||
return grub_errno;
|
||||
}
|
||||
|
|
237
normal/parser.y
237
normal/parser.y
|
@ -1,237 +0,0 @@
|
|||
/* parser.y - The scripting parser. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 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/script.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
#define YYFREE grub_free
|
||||
#define YYMALLOC grub_malloc
|
||||
#define YYLTYPE_IS_TRIVIAL 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" argument
|
||||
{
|
||||
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);
|
||||
}
|
||||
;
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2004,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/symbol.h>
|
||||
|
||||
.file "setjmp.S"
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
* int grub_setjmp (grub_jmp_buf env)
|
||||
*/
|
||||
FUNCTION(grub_setjmp)
|
||||
stw 1, 0(3)
|
||||
stw 14, 4(3)
|
||||
stw 15, 8(3)
|
||||
stw 16, 12(3)
|
||||
stw 17, 16(3)
|
||||
stw 18, 20(3)
|
||||
stw 19, 24(3)
|
||||
stw 20, 28(3)
|
||||
stw 21, 32(3)
|
||||
stw 22, 36(3)
|
||||
stw 23, 40(3)
|
||||
stw 24, 44(3)
|
||||
stw 25, 48(3)
|
||||
stw 26, 52(3)
|
||||
stw 27, 56(3)
|
||||
stw 28, 60(3)
|
||||
stw 29, 64(3)
|
||||
stw 30, 68(3)
|
||||
mflr 4
|
||||
stw 4, 72(3)
|
||||
mfcr 4
|
||||
stw 4, 76(3)
|
||||
li 3, 0
|
||||
blr
|
||||
|
||||
/*
|
||||
* int grub_longjmp (grub_jmp_buf env, int val)
|
||||
*/
|
||||
FUNCTION(grub_longjmp)
|
||||
lwz 1, 0(3)
|
||||
lwz 14, 4(3)
|
||||
lwz 15, 8(3)
|
||||
lwz 16, 12(3)
|
||||
lwz 17, 16(3)
|
||||
lwz 18, 20(3)
|
||||
lwz 19, 24(3)
|
||||
lwz 20, 28(3)
|
||||
lwz 21, 32(3)
|
||||
lwz 22, 36(3)
|
||||
lwz 23, 40(3)
|
||||
lwz 24, 44(3)
|
||||
lwz 25, 48(3)
|
||||
lwz 26, 52(3)
|
||||
lwz 27, 56(3)
|
||||
lwz 28, 60(3)
|
||||
lwz 29, 64(3)
|
||||
lwz 30, 68(3)
|
||||
lwz 5, 72(3)
|
||||
mtlr 5
|
||||
lwz 5, 76(3)
|
||||
mtcr 5
|
||||
mr. 3, 4
|
||||
bne 1f
|
||||
li 3, 1
|
||||
1: blr
|
||||
|
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 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_arg *title,
|
||||
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->title = title;
|
||||
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;
|
||||
}
|
|
@ -1,38 +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/symbol.h>
|
||||
|
||||
.file "setjmp.S"
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
* int grub_setjmp (grub_jmp_buf env)
|
||||
*/
|
||||
FUNCTION(grub_setjmp)
|
||||
ret
|
||||
nop
|
||||
|
||||
/*
|
||||
* int grub_longjmp (grub_jmp_buf env, int val)
|
||||
*/
|
||||
FUNCTION(grub_longjmp)
|
||||
ret
|
||||
nop
|
||||
|
252
normal/term.c
Normal file
252
normal/term.c
Normal file
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2003,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/term.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/normal.h>
|
||||
|
||||
/* The amount of lines counted by the pager. */
|
||||
static unsigned grub_more_lines;
|
||||
|
||||
/* If the more pager is active. */
|
||||
static int grub_more;
|
||||
|
||||
static void
|
||||
process_newline (void)
|
||||
{
|
||||
struct grub_term_output *cur;
|
||||
unsigned height = -1;
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(cur)
|
||||
if (grub_term_height (cur) < height)
|
||||
height = grub_term_height (cur);
|
||||
grub_more_lines++;
|
||||
|
||||
if (grub_more && grub_more_lines >= height - 1)
|
||||
{
|
||||
char key;
|
||||
grub_uint16_t *pos;
|
||||
|
||||
pos = grub_term_save_pos ();
|
||||
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
|
||||
grub_printf ("--MORE--");
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
|
||||
|
||||
key = grub_getkey ();
|
||||
|
||||
/* Remove the message. */
|
||||
grub_term_restore_pos (pos);
|
||||
grub_printf (" ");
|
||||
grub_term_restore_pos (pos);
|
||||
|
||||
/* Scroll one lines or an entire page, depending on the key. */
|
||||
if (key == '\r' || key =='\n')
|
||||
grub_more_lines = height - 2;
|
||||
else
|
||||
grub_more_lines = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grub_set_more (int onoff)
|
||||
{
|
||||
if (onoff == 1)
|
||||
grub_more++;
|
||||
else
|
||||
grub_more--;
|
||||
|
||||
grub_more_lines = 0;
|
||||
grub_newline_hook = process_newline;
|
||||
}
|
||||
|
||||
void
|
||||
grub_puts_terminal (const char *str, struct grub_term_output *term)
|
||||
{
|
||||
grub_uint32_t code;
|
||||
grub_ssize_t ret;
|
||||
const grub_uint8_t *ptr = (const grub_uint8_t *) str;
|
||||
const grub_uint8_t *end;
|
||||
end = (const grub_uint8_t *) (str + grub_strlen (str));
|
||||
|
||||
while (*ptr)
|
||||
{
|
||||
ret = grub_utf8_to_ucs4 (&code, 1, ptr, end - ptr, &ptr);
|
||||
grub_putcode (code, term);
|
||||
}
|
||||
}
|
||||
|
||||
grub_uint16_t *
|
||||
grub_term_save_pos (void)
|
||||
{
|
||||
struct grub_term_output *cur;
|
||||
unsigned cnt = 0;
|
||||
grub_uint16_t *ret, *ptr;
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(cur)
|
||||
cnt++;
|
||||
|
||||
ret = grub_malloc (cnt * sizeof (ret[0]));
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
ptr = ret;
|
||||
FOR_ACTIVE_TERM_OUTPUTS(cur)
|
||||
*ptr++ = grub_term_getxy (cur);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
grub_term_restore_pos (grub_uint16_t *pos)
|
||||
{
|
||||
struct grub_term_output *cur;
|
||||
grub_uint16_t *ptr = pos;
|
||||
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(cur)
|
||||
{
|
||||
grub_term_gotoxy (cur, (*ptr & 0xff00) >> 8, *ptr & 0xff);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
grub_terminal_autoload_free (void)
|
||||
{
|
||||
struct grub_term_autoload *cur, *next;
|
||||
unsigned i;
|
||||
for (i = 0; i < 2; i++)
|
||||
for (cur = i ? grub_term_input_autoload : grub_term_output_autoload;
|
||||
cur; cur = next)
|
||||
{
|
||||
next = cur->next;
|
||||
grub_free (cur->name);
|
||||
grub_free (cur->modname);
|
||||
grub_free (cur);
|
||||
}
|
||||
grub_term_input_autoload = NULL;
|
||||
grub_term_output_autoload = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Read the file terminal.lst for auto-loading. */
|
||||
void
|
||||
read_terminal_list (void)
|
||||
{
|
||||
const char *prefix;
|
||||
char *filename;
|
||||
grub_file_t file;
|
||||
char *buf = NULL;
|
||||
|
||||
prefix = grub_env_get ("prefix");
|
||||
if (!prefix)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
filename = grub_malloc (grub_strlen (prefix) + sizeof ("/terminal.lst"));
|
||||
if (!filename)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
grub_sprintf (filename, "%s/terminal.lst", prefix);
|
||||
file = grub_file_open (filename);
|
||||
if (!file)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Override previous terminal.lst. */
|
||||
grub_terminal_autoload_free ();
|
||||
|
||||
for (;; grub_free (buf))
|
||||
{
|
||||
char *p, *name;
|
||||
struct grub_term_autoload *cur;
|
||||
struct grub_term_autoload **target = NULL;
|
||||
|
||||
buf = grub_file_getline (file);
|
||||
|
||||
if (! buf)
|
||||
break;
|
||||
|
||||
switch (buf[0])
|
||||
{
|
||||
case 'i':
|
||||
target = &grub_term_input_autoload;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
target = &grub_term_output_autoload;
|
||||
break;
|
||||
}
|
||||
if (!target)
|
||||
continue;
|
||||
|
||||
name = buf + 1;
|
||||
|
||||
p = grub_strchr (name, ':');
|
||||
if (! p)
|
||||
continue;
|
||||
|
||||
*p = '\0';
|
||||
while (*++p == ' ')
|
||||
;
|
||||
|
||||
cur = grub_malloc (sizeof (*cur));
|
||||
if (!cur)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
cur->name = grub_strdup (name);
|
||||
if (! name)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_free (cur);
|
||||
continue;
|
||||
}
|
||||
|
||||
cur->modname = grub_strdup (p);
|
||||
if (! cur->modname)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_free (cur);
|
||||
grub_free (cur->name);
|
||||
continue;
|
||||
}
|
||||
cur->next = *target;
|
||||
*target = cur;
|
||||
}
|
||||
|
||||
grub_file_close (file);
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue