merge mainline into newenv

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-01-20 21:31:39 +01:00
commit 61c501a941
415 changed files with 17977 additions and 6997 deletions

View file

@ -36,58 +36,6 @@ struct grub_auth_user
struct grub_auth_user *users = NULL;
int
grub_auth_strcmp (const char *s1, const char *s2)
{
int ret;
grub_uint64_t end;
end = grub_get_time_ms () + 100;
ret = grub_strcmp (s1, s2);
/* This prevents an attacker from deriving information about the
password from the time it took to execute this function. */
while (grub_get_time_ms () < end);
return ret;
}
static int
grub_iswordseparator (int c)
{
return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
}
int
grub_auth_strword (const char *haystack, const char *needle)
{
const char *n_pos = needle;
int found = 0;
while (grub_iswordseparator (*haystack))
haystack++;
while (*haystack)
{
int ok = 1;
/* Crawl both the needle and the haystack word we're on. */
while(*haystack && !grub_iswordseparator (*haystack))
{
if (*haystack == *n_pos && ok)
n_pos++;
else
ok = 0;
haystack++;
}
if (ok)
found = 1;
}
return found;
}
grub_err_t
grub_auth_register_authentication (const char *user,
grub_auth_callback_t callback,
@ -194,8 +142,8 @@ is_authenticated (const char *userlist)
return 0;
name = ((struct grub_auth_user *) item)->name;
return (userlist && grub_auth_strword (userlist, name))
|| grub_auth_strword (superusers, name);
return (userlist && grub_strword (userlist, name))
|| grub_strword (superusers, name);
}
superusers = grub_env_get ("superusers");
@ -206,6 +154,49 @@ is_authenticated (const char *userlist)
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)
{
@ -213,11 +204,12 @@ grub_auth_check_authentication (const char *userlist)
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_auth_strcmp (login, ((struct grub_auth_user *) item)->name) == 0)
if (grub_strcmp (login, ((struct grub_auth_user *) item)->name) == 0)
cur = (struct grub_auth_user *) item;
return 0;
}
@ -238,26 +230,22 @@ grub_auth_check_authentication (const char *userlist)
return GRUB_ERR_NONE;
}
if (!grub_cmdline_get (N_("Enter username:"), login, sizeof (login) - 1,
0, 0, 0))
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)
{
grub_list_iterate (GRUB_AS_LIST (users), hook_any);
goto access_denied;
/* No users present at all. */
if (!cur)
goto access_denied;
/* Display any of available authentication schemes. */
err = cur->callback (login, 0);
goto access_denied;
}
err = cur->callback (login, cur->arg);
err = cur->callback (login, entered, cur->arg);
if (is_authenticated (userlist))
{
punishment_delay = 1;

View file

@ -51,27 +51,35 @@ void
read_fs_list (void)
{
const char *prefix;
static int first_time = 1;
/* Make sure that this function does not get executed twice. */
if (! first_time)
return;
first_time = 0;
prefix = grub_env_get ("prefix");
if (prefix)
{
char *filename;
filename = grub_malloc (grub_strlen (prefix) + sizeof ("/fs.lst"));
filename = grub_xasprintf ("%s/fs.lst", prefix);
if (filename)
{
grub_file_t file;
grub_fs_autoload_hook_t tmp_autoload_hook;
/* 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;
grub_sprintf (filename, "%s/fs.lst", prefix);
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;
@ -113,6 +121,7 @@ read_fs_list (void)
}
grub_file_close (file);
grub_fs_autoload_hook = tmp_autoload_hook;
}
grub_free (filename);

View file

@ -27,11 +27,12 @@
#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;
@ -39,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)
@ -67,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 *));
}
}
@ -90,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. */
@ -121,16 +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);
grub_history_set ((hist_pos + pos) % hist_size, s, len);
}
/* A completion hook to print items. */
@ -140,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)
@ -176,75 +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, int history)
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)
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);
}
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)
{
xpos = (plen + lpos) % 79;
ypos = ystart + (plen + lpos) / 79;
grub_gotoxy (xpos, ypos);
grub_uint32_t *p;
grub_refresh ();
}
void cl_print (int pos, int c)
{
char *p;
for (p = buf + pos; *p; 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)
@ -254,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 ();
cl_set_pos_all ();
grub_memmove (buf + lpos, buf + lpos + len, llen - lpos + 1);
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_translated);
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_term_output_t term;
grub_printf ("%s", prompt_translated);
FOR_ACTIVE_TERM_OUTPUTS(term)
if ((grub_term_getxy (term) >> 8) != 0)
grub_putcode ('\n', term);
}
grub_printf ("%s ", prompt_translated);
xpos = plen;
ystart = ypos = (grub_getxy () & 0xFF);
{
struct cmdline_term *cl_term_cur;
struct grub_term_output *cur;
nterms = 0;
FOR_ACTIVE_TERM_OUTPUTS(cur)
nterms++;
cl_insert (cmdline);
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 (history && hist_used == 0)
grub_history_add (buf);
if (hist_used == 0)
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_translated, 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;
@ -437,7 +571,7 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
if (lpos > 0)
{
lpos--;
cl_set_pos ();
cl_set_pos_all ();
}
else
break;
@ -451,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';
@ -459,28 +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++;
if (history)
histpos = 0;
if (strlen_ucs4 (buf) > 0)
{
histpos = 0;
if (grub_strlen (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;
}

View file

@ -103,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);
}
@ -129,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);
}

View file

@ -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,2008 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
@ -107,17 +107,12 @@ iterate_partition (grub_disk_t disk, const grub_partition_t p)
if (! partition_name)
return 1;
name = grub_malloc (grub_strlen (disk_name) + 1
+ grub_strlen (partition_name) + 1);
if (! name)
{
grub_free (partition_name);
return 1;
}
grub_sprintf (name, "%s,%s", disk_name, partition_name);
name = grub_xasprintf ("%s,%s", disk_name, partition_name);
grub_free (partition_name);
if (! name)
return 1;
ret = add_completion (name, ")", GRUB_COMPLETION_TYPE_PARTITION);
grub_free (name);
return ret;
@ -141,11 +136,15 @@ iterate_dir (const char *filename, const struct grub_dirhook_info *info)
}
else if (grub_strcmp (filename, ".") && grub_strcmp (filename, ".."))
{
char fname[grub_strlen (filename) + 2];
char *fname;
grub_sprintf (fname, "%s/", filename);
fname = grub_xasprintf ("%s/", filename);
if (add_completion (fname, "", GRUB_COMPLETION_TYPE_FILE))
return 1;
{
grub_free (fname);
return 1;
}
grub_free (fname);
}
return 0;
@ -360,8 +359,9 @@ complete_arguments (char *command)
if (!option->longarg)
continue;
longarg = grub_malloc (grub_strlen (option->longarg));
grub_sprintf (longarg, "--%s", option->longarg);
longarg = grub_xasprintf ("--%s", option->longarg);
if (!longarg)
return 1;
if (add_completion (longarg, " ", GRUB_COMPLETION_TYPE_ARGUMENT))
{

152
normal/crypto.c Normal file
View file

@ -0,0 +1,152 @@
/* 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_xasprintf ("%s/crypto.lst", prefix);
if (!filename)
{
grub_errno = GRUB_ERR_NONE;
return;
}
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;
}

View file

@ -23,6 +23,7 @@
#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,
@ -62,28 +63,39 @@ void
read_command_list (void)
{
const char *prefix;
static int first_time = 1;
/* Make sure that this function does not get executed twice. */
if (! first_time)
return;
first_time = 0;
prefix = grub_env_get ("prefix");
if (prefix)
{
char *filename;
filename = grub_malloc (grub_strlen (prefix) + sizeof ("/command.lst"));
filename = grub_xasprintf ("%s/command.lst", prefix);
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;
@ -132,7 +144,7 @@ read_command_list (void)
cmd = grub_register_command_prio (name,
grub_dyncmd_dispatcher,
0, "not loaded", prio);
0, N_("not loaded"), prio);
if (! cmd)
{
grub_free (name);

View file

@ -117,7 +117,7 @@ insert_handler (char *name, char *module)
data = 0;
item->cmd = grub_register_command (item->name, grub_handler_cmd, 0,
"Set active handler");
"Set active handler.");
if (! item->cmd)
{
grub_free (data);
@ -172,12 +172,11 @@ read_handler_list (void)
{
char *filename;
filename = grub_malloc (grub_strlen (prefix) + sizeof ("/handler.lst"));
filename = grub_xasprintf ("%s/handler.lst", prefix);
if (filename)
{
grub_file_t file;
grub_sprintf (filename, "%s/handler.lst", prefix);
file = grub_file_open (filename);
if (file)
{

View file

@ -30,9 +30,13 @@
#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. */
char *
grub_file_getline (grub_file_t file)
@ -372,7 +376,21 @@ read_config_file (const char *config)
if (! file)
return 0;
grub_reader_loop (getline);
while (1)
{
char *line;
/* Print an error, if any. */
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
if ((getline (&line, 0)) || (! line))
break;
grub_parser_get_current ()->parse_line (line, getline);
grub_free (line);
}
grub_file_close (file);
if (old_parser)
@ -383,40 +401,48 @@ read_config_file (const char *config)
/* Initialize the screen. */
void
grub_normal_init_page (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_cls ();
grub_sprintf (msg_formatted, msg, PACKAGE_VERSION);
char *msg_formatted;
grub_uint32_t *unicode_msg;
grub_uint32_t *last_position;
msg_len = grub_utf8_to_ucs4_alloc (msg_formatted,
grub_term_cls (term);
msg_formatted = grub_xasprintf (msg, PACKAGE_VERSION);
if (!msg_formatted)
return;
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);
posx = (GRUB_TERM_WIDTH - posx) / 2;
grub_gotoxy (posx, 1);
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);
grub_print_ucs4 (unicode_msg, last_position, term);
grub_printf("\n\n");
grub_free (unicode_msg);
}
static int reader_nested;
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. */
@ -425,13 +451,11 @@ grub_normal_execute (const char *config, int nested, int batch)
{
grub_menu_t menu = 0;
read_command_list ();
read_fs_list ();
read_lists (NULL, NULL);
read_handler_list ();
grub_register_variable_hook ("prefix", NULL, read_lists);
grub_command_execute ("parser.grub", 0, 0);
reader_nested = nested;
if (config)
{
menu = read_config_file (config);
@ -444,7 +468,7 @@ grub_normal_execute (const char *config, int nested, int batch)
{
if (menu && menu->size)
{
grub_menu_viewer_show_menu (menu, nested);
grub_show_menu (menu, nested);
if (nested)
free_menu (menu);
}
@ -455,31 +479,33 @@ grub_normal_execute (const char *config, int nested, int batch)
void
grub_enter_normal_mode (const char *config)
{
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 grub_err_t
grub_cmd_normal (struct grub_command *cmd,
grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_unregister_command (cmd);
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"));
config = grub_xasprintf ("%s/grub.cfg", prefix);
if (! config)
goto quit;
grub_sprintf (config, "%s/grub.cfg", prefix);
grub_enter_normal_mode (config);
grub_free (config);
}
@ -493,10 +519,86 @@ 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;
msg_formatted = grub_xasprintf (msg, nested ? msg_esc : "");
if (!msg_formatted)
return grub_errno;
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;
if (cont)
prompt = grub_xasprintf (">");
else
prompt = grub_xasprintf ("%s>", parser->name);
if (!prompt)
return grub_errno;
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_reader_t reader;
grub_err_t err = GRUB_ERR_NONE;
err = grub_auth_check_authentication (NULL);
@ -508,72 +610,28 @@ grub_cmdline_run (int nested)
return;
}
reader = grub_reader_get_current ();
reader_nested = nested;
if (reader->init)
reader->init ();
grub_reader_loop (0);
}
static grub_err_t
grub_normal_reader_init (void)
{
grub_normal_init_page ();
grub_setcursor (1);
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, reader_nested ? msg_esc : "");
grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN);
grub_puts ("\n");
grub_free (msg_formatted);
return 0;
}
static char cmdline[GRUB_MAX_CMDLINE];
static grub_err_t
grub_normal_read_line (char **line, int cont)
{
grub_parser_t parser = grub_parser_get_current ();
char prompt[sizeof("> ") + grub_strlen (parser->name)];
grub_sprintf (prompt, "%s> ", parser->name);
grub_normal_reader_init (nested);
while (1)
{
cmdline[0] = 0;
if (grub_cmdline_get (prompt, cmdline, sizeof (cmdline), 0, 1, 1))
char *line;
if (grub_normal_exit_level)
break;
if ((reader_nested) || (cont))
{
*line = 0;
return grub_errno;
}
/* 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);
}
*line = grub_strdup (cmdline);
return 0;
}
static struct grub_reader grub_normal_reader =
{
.name = "normal",
.init = grub_normal_reader_init,
.read_line = grub_normal_read_line
};
static char *
grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)),
const char *val)
@ -590,17 +648,15 @@ GRUB_MOD_INIT(normal)
if (mod)
grub_dl_ref (mod);
grub_menu_viewer_register (&grub_normal_text_menu_viewer);
grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
grub_reader_register ("normal", &grub_normal_reader);
grub_reader_set_current (&grub_normal_reader);
grub_register_variable_hook ("pager", 0, grub_env_write_pager);
/* Register a command "normal" for the rescue mode. */
grub_register_command_prio ("normal", grub_cmd_normal,
0, "Enter normal mode", 0);
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);
@ -616,7 +672,6 @@ GRUB_MOD_FINI(normal)
grub_context_fini ();
grub_set_history (0);
grub_reader_unregister (&grub_normal_reader);
grub_register_variable_hook ("pager", 0, 0);
grub_fs_autoload_hook = 0;
free_handler_list ();

View file

@ -1,7 +1,7 @@
/* menu.c - General supporting functionality for menus. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
* Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -27,6 +27,26 @@
#include <grub/command.h>
#include <grub/parser.h>
#include <grub/auth.h>
#include <grub/i18n.h>
#include <grub/term.h>
/* 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_putchar ('\n');
grub_printf_ (N_("Press any key to continue..."));
(void) grub_getkey ();
grub_putchar ('\n');
}
/* Get a menu entry by its index in the entry list. */
grub_menu_entry_t
@ -78,7 +98,7 @@ grub_menu_set_timeout (int timeout)
{
char buf[16];
grub_sprintf (buf, "%d", timeout);
grub_snprintf (buf, sizeof (buf), "%d", timeout);
grub_env_set ("timeout", buf);
}
}
@ -137,6 +157,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry)
return;
}
grub_env_set ("chosen", entry->title);
grub_parser_execute ((char *) entry->sourcecode);
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
@ -178,3 +200,400 @@ grub_menu_execute_with_fallback (grub_menu_t menu,
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;
entry = -1;
}
grub_error_pop ();
return entry;
}
#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, int *auto_boot)
{
grub_uint64_t saved_time;
int default_entry, current_entry;
int timeout;
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;
/* If timeout is 0, drawing is pointless (and ugly). */
if (grub_menu_get_timeout () == 0)
{
*auto_boot = 1;
return default_entry;
}
current_entry = default_entry;
/* Initialize the time. */
saved_time = grub_get_time_ms ();
refresh:
menu_init (current_entry, menu, nested);
timeout = grub_menu_get_timeout ();
if (timeout > 0)
menu_print_timeout (timeout);
while (1)
{
int c;
timeout = grub_menu_get_timeout ();
if (grub_normal_exit_level)
return -1;
if (timeout > 0)
{
grub_uint64_t current_time;
current_time = grub_get_time_ms ();
if (current_time - saved_time >= 1000)
{
timeout--;
grub_menu_set_timeout (timeout);
saved_time = current_time;
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_env_unset ("timeout");
grub_env_unset ("fallback");
clear_timeout ();
}
switch (c)
{
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 (current_entry > 0)
current_entry--;
menu_set_chosen_entry (current_entry);
break;
case GRUB_TERM_DOWN:
case 'v':
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:
menu_fini ();
*auto_boot = 0;
return current_entry;
case '\e':
if (nested)
{
menu_fini ();
return -1;
}
break;
case 'c':
menu_fini ();
grub_cmdline_run (1);
goto refresh;
case 'e':
menu_fini ();
{
grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
if (e)
grub_menu_entry_run (e);
}
goto refresh;
default:
break;
}
}
}
/* Never reach here. */
return -1;
}
/* Callback invoked immediately before a menu entry is executed. */
static void
notify_booting (grub_menu_entry_t entry,
void *userdata __attribute__((unused)))
{
grub_printf (" ");
grub_printf_ (N_("Booting \'%s\'"), entry->title);
grub_printf ("\n\n");
}
/* 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 both default and fallback 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 auto_boot;
boot_entry = run_menu (menu, nested, &auto_boot);
if (boot_entry < 0)
break;
e = grub_menu_get_entry (menu, boot_entry);
if (! e)
continue; /* Menu is empty. */
grub_cls ();
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

View file

@ -26,96 +26,66 @@
#include <grub/env.h>
#include <grub/menu_viewer.h>
#include <grub/i18n.h>
/* Time to delay after displaying an error message about a default/fallback
entry failing to boot. */
#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500
#include <grub/charset.h>
static grub_uint8_t grub_color_menu_normal;
static grub_uint8_t grub_color_menu_highlight;
/* Wait until the user pushes any key so that the user
can see what happened. */
void
grub_wait_after_message (void)
struct menu_viewer_data
{
grub_putchar ('\n');
grub_printf_ (N_("Press any key to continue..."));
(void) grub_getkey ();
grub_putchar ('\n');
}
int first, offset;
grub_menu_t menu;
struct grub_term_output *term;
};
static void
print_spaces (int number_spaces)
print_spaces (int number_spaces, struct grub_term_output *term)
{
int i;
for (i = 0; i < number_spaces; i++)
grub_putchar (' ');
grub_putcode (' ', term);
}
void
grub_print_ucs4 (const grub_uint32_t * str,
const grub_uint32_t * last_position)
const grub_uint32_t * last_position,
struct grub_term_output *term)
{
while (str < last_position)
{
grub_putcode (*str);
grub_putcode (*str, term);
str++;
}
}
int
grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
grub_uint32_t **last_position)
{
grub_ssize_t msg_len = grub_strlen (msg);
*unicode_msg = grub_malloc (grub_strlen (msg) * sizeof (grub_uint32_t));
if (!*unicode_msg)
{
grub_printf ("utf8_to_ucs4 ERROR1: %s", msg);
return -1;
}
msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len,
(grub_uint8_t *) msg, -1, 0);
*last_position = *unicode_msg + msg_len;
if (msg_len < 0)
{
grub_printf ("utf8_to_ucs4 ERROR2: %s", msg);
grub_free (*unicode_msg);
}
return msg_len;
}
grub_ssize_t
grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position)
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_getcharwidth (*str);
width += grub_term_getcharwidth (term, *str);
str++;
}
return width;
}
void
grub_print_message_indented (const char *msg, int margin_left, int margin_right)
grub_print_message_indented (const char *msg, int margin_left, int margin_right,
struct grub_term_output *term)
{
int line_len;
line_len = GRUB_TERM_WIDTH - grub_getcharwidth ('m') *
(margin_left + margin_right);
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)
@ -132,13 +102,14 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right)
while (current_position < last_position)
{
if (! first_loop)
grub_putchar ('\n');
grub_putcode ('\n', term);
next_new_line = (grub_uint32_t *) last_position;
while (grub_getstringwidth (current_position, next_new_line) > line_len
|| (*next_new_line != ' ' && next_new_line > current_position &&
next_new_line != 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--;
}
@ -149,8 +120,8 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right)
(grub_uint32_t *) last_position : next_new_line + line_len;
}
print_spaces (margin_left);
grub_print_ucs4 (current_position, next_new_line);
print_spaces (margin_left, term);
grub_print_ucs4 (current_position, next_new_line, term);
next_new_line++;
current_position = next_new_line;
@ -161,80 +132,93 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right)
static void
draw_border (void)
draw_border (struct grub_term_output *term)
{
unsigned i;
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
grub_term_setcolorstate (term, 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);
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; i++)
for (i = 0; i < (unsigned) grub_term_num_entries (term); 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_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_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_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_setcolorstate (GRUB_TERM_COLOR_NORMAL);
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
grub_gotoxy (GRUB_TERM_MARGIN,
(GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES
+ GRUB_TERM_MARGIN + 1));
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)
print_message (int nested, int edit, struct grub_term_output *term)
{
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
if (edit)
{
grub_putchar ('\n');
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);
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);
const char *msg = _("Use the %C and %C keys to select which "
"entry is highlighted.\n");
char *msg_translated;
grub_sprintf (msg_translated, msg, (grub_uint32_t) GRUB_TERM_DISP_UP,
(grub_uint32_t) GRUB_TERM_DISP_DOWN);
msg_translated = grub_xasprintf (msg, (grub_uint32_t) GRUB_TERM_DISP_UP,
(grub_uint32_t) GRUB_TERM_DISP_DOWN);
if (!msg_translated)
return;
grub_putchar ('\n');
grub_print_message_indented (msg_translated, STANDARD_MARGIN, STANDARD_MARGIN);
grub_print_message_indented (msg_translated, STANDARD_MARGIN,
STANDARD_MARGIN, term);
grub_free (msg_translated);
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);
if (nested)
{
grub_printf ("\n ");
grub_printf_ (N_("ESC to return previous menu."));
}
{
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)
print_entry (int y, int highlight, grub_menu_entry_t entry,
struct grub_term_output *term)
{
int x;
const char *title;
@ -260,482 +244,244 @@ print_entry (int y, int highlight, grub_menu_entry_t entry)
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_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_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
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 < GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN;
x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
- GRUB_TERM_MARGIN);
i++)
{
if (i < len
&& x <= (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH
- GRUB_TERM_MARGIN - 1))
&& x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
- GRUB_TERM_MARGIN - 1))
{
grub_ssize_t width;
width = grub_getcharwidth (unicode_title[i]);
width = grub_term_getcharwidth (term, 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);
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]);
grub_putcode (unicode_title[i], term);
x += width;
}
else
{
grub_putchar (' ');
grub_putcode (' ', term);
x++;
}
}
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
grub_putchar (' ');
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
grub_putcode (' ', term);
grub_gotoxy (GRUB_TERM_CURSOR_X, y);
grub_term_gotoxy (term, grub_term_cursor_x (term), y);
grub_setcolor (old_color_normal, old_color_highlight);
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
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)
print_entries (grub_menu_t menu, int first, int offset,
struct grub_term_output *term)
{
grub_menu_entry_t e;
int i;
grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
GRUB_TERM_FIRST_ENTRY_Y);
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);
grub_putcode (GRUB_TERM_DISP_UP, term);
else
grub_putchar (' ');
grub_putcode (' ', term);
e = grub_menu_get_entry (menu, first);
for (i = 0; i < GRUB_TERM_NUM_ENTRIES; i++)
for (i = 0; i < grub_term_num_entries (term); i++)
{
print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e);
print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e, term);
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);
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);
grub_putcode (GRUB_TERM_DISP_DOWN, term);
else
grub_putchar (' ');
grub_putcode (' ', term);
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
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)
grub_menu_init_page (int nested, int edit,
struct grub_term_output *term)
{
grub_uint8_t old_color_normal, old_color_highlight;
grub_getcolor (&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_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);
}
/* Get the entry number from the variable NAME. */
static int
get_entry_number (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_NONE)
{
grub_errno = GRUB_ERR_NONE;
entry = -1;
}
grub_error_pop ();
return entry;
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
print_timeout (int timeout, int offset)
menu_text_print_timeout (int timeout, void *dataptr)
{
const char *msg =
_("The highlighted entry will be booted automatically in %ds.");
grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
char *msg_translated =
grub_malloc (sizeof (char) * grub_strlen (msg) + 5);
grub_sprintf (msg_translated, msg, timeout);
grub_print_message_indented (msg_translated, 3, 0);
_("The highlighted entry will be executed automatically in %ds.");
struct menu_viewer_data *data = dataptr;
char *msg_translated;
int posx;
posx = grub_getxy() >> 8;
print_spaces (GRUB_TERM_WIDTH - posx - 1);
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
grub_refresh ();
}
grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
/* 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, int *auto_boot)
{
int first, offset;
grub_uint64_t saved_time;
int default_entry;
int timeout;
first = 0;
default_entry = get_entry_number ("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;
/* If timeout is 0, drawing is pointless (and ugly). */
if (grub_menu_get_timeout () == 0)
{
*auto_boot = 1;
return default_entry;
}
offset = default_entry;
if (offset > GRUB_TERM_NUM_ENTRIES - 1)
{
first = offset - (GRUB_TERM_NUM_ENTRIES - 1);
offset = GRUB_TERM_NUM_ENTRIES - 1;
}
/* Initialize the time. */
saved_time = grub_get_time_ms ();
refresh:
grub_setcursor (0);
grub_menu_init_page (nested, 0);
print_entries (menu, first, offset);
grub_refresh ();
timeout = grub_menu_get_timeout ();
if (timeout > 0)
print_timeout (timeout, offset);
while (1)
{
int c;
timeout = grub_menu_get_timeout ();
if (timeout > 0)
{
grub_uint64_t current_time;
current_time = grub_get_time_ms ();
if (current_time - saved_time >= 1000)
{
timeout--;
grub_menu_set_timeout (timeout);
saved_time = current_time;
print_timeout (timeout, offset);
}
}
if (timeout == 0)
{
grub_env_unset ("timeout");
*auto_boot = 1;
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);
print_spaces (GRUB_TERM_WIDTH - 1);
grub_env_unset ("timeout");
grub_env_unset ("fallback");
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
}
switch (c)
{
case GRUB_TERM_HOME:
first = 0;
offset = 0;
print_entries (menu, first, offset);
break;
case GRUB_TERM_END:
offset = menu->size - 1;
if (offset > GRUB_TERM_NUM_ENTRIES - 1)
{
first = offset - (GRUB_TERM_NUM_ENTRIES - 1);
offset = GRUB_TERM_NUM_ENTRIES - 1;
}
print_entries (menu, first, offset);
break;
case GRUB_TERM_UP:
case '^':
if (offset > 0)
{
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
grub_menu_get_entry (menu, first + offset));
offset--;
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
grub_menu_get_entry (menu, first + offset));
}
else if (first > 0)
{
first--;
print_entries (menu, first, offset);
}
break;
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,
grub_menu_get_entry (menu, first + offset));
offset++;
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
grub_menu_get_entry (menu, first + offset));
}
else
{
first++;
print_entries (menu, first, offset);
}
}
break;
case GRUB_TERM_PPAGE:
if (first == 0)
{
offset = 0;
}
else
{
first -= GRUB_TERM_NUM_ENTRIES;
if (first < 0)
{
offset += first;
first = 0;
}
}
print_entries (menu, first, offset);
break;
case GRUB_TERM_NPAGE:
if (offset == 0)
{
offset += GRUB_TERM_NUM_ENTRIES - 1;
if (first + offset >= menu->size)
{
offset = menu->size - first - 1;
}
}
else
{
first += GRUB_TERM_NUM_ENTRIES;
if (first + offset >= menu->size)
{
first -= GRUB_TERM_NUM_ENTRIES;
offset += GRUB_TERM_NUM_ENTRIES;
if (offset > menu->size - 1 ||
offset > GRUB_TERM_NUM_ENTRIES - 1)
{
offset = menu->size - first - 1;
}
if (offset > GRUB_TERM_NUM_ENTRIES)
{
first += offset - GRUB_TERM_NUM_ENTRIES + 1;
offset = GRUB_TERM_NUM_ENTRIES - 1;
}
}
}
print_entries (menu, first, offset);
break;
case '\n':
case '\r':
case 6:
grub_setcursor (1);
*auto_boot = 0;
return first + offset;
case '\e':
if (nested)
{
grub_setcursor (1);
return -1;
}
break;
case 'c':
grub_cmdline_run (1);
goto refresh;
case 'e':
{
grub_menu_entry_t e = grub_menu_get_entry (menu, first + offset);
if (e)
grub_menu_entry_run (e);
}
goto refresh;
default:
break;
}
grub_refresh ();
}
}
/* Never reach here. */
return -1;
}
/* Callback invoked immediately before a menu entry is executed. */
static void
notify_booting (grub_menu_entry_t entry,
void *userdata __attribute__((unused)))
{
grub_printf (" ");
grub_printf_ (N_("Booting \'%s\'"), entry->title);
grub_printf ("\n\n");
}
/* 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)
msg_translated = grub_xasprintf (msg, timeout);
if (!msg_translated)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
return;
}
grub_printf ("\n ");
grub_printf_ (N_("Failed to boot default entries.\n"));
grub_wait_after_message ();
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);
}
/* Callbacks used by the text menu to provide user feedback when menu entries
are executed. */
static struct grub_menu_execute_callback execution_callback =
static void
menu_text_set_chosen_entry (int entry, void *dataptr)
{
.notify_booting = notify_booting,
.notify_fallback = notify_fallback,
.notify_failure = notify_execution_failure
};
struct menu_viewer_data *data = dataptr;
int oldoffset = data->offset;
int complete_redraw = 0;
static grub_err_t
show_text_menu (grub_menu_t menu, int nested)
{
while (1)
data->offset = entry - data->first;
if (data->offset > grub_term_num_entries (data->term) - 1)
{
int boot_entry;
grub_menu_entry_t e;
int auto_boot;
boot_entry = run_menu (menu, nested, &auto_boot);
if (boot_entry < 0)
break;
e = grub_menu_get_entry (menu, boot_entry);
if (! e)
continue; /* Menu is empty. */
grub_cls ();
grub_setcursor (1);
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 ();
}
}
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;
}
struct grub_menu_viewer grub_normal_text_menu_viewer =
{
.name = "text",
.show_menu = show_text_menu
};

View file

@ -1,81 +0,0 @@
/*
* 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/misc.h>
#include <grub/env.h>
#include <grub/menu_viewer.h>
#include <grub/menu.h>
#include <grub/auth.h>
/* The list of menu viewers. */
static grub_menu_viewer_t menu_viewer_list;
void
grub_menu_viewer_register (grub_menu_viewer_t viewer)
{
viewer->next = menu_viewer_list;
menu_viewer_list = viewer;
}
static grub_menu_viewer_t get_current_menu_viewer (void)
{
const char *selected_name = grub_env_get ("menuviewer");
/* If none selected, pick the last registered one. */
if (selected_name == 0)
return menu_viewer_list;
grub_menu_viewer_t cur;
for (cur = menu_viewer_list; cur; cur = cur->next)
{
if (grub_strcmp (cur->name, selected_name) == 0)
return cur;
}
/* Fall back to the first entry (or null). */
return menu_viewer_list;
}
grub_err_t
grub_menu_viewer_show_menu (grub_menu_t menu, int nested)
{
grub_menu_viewer_t cur = get_current_menu_viewer ();
grub_err_t err1, err2;
if (!cur)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available.");
while (1)
{
err1 = cur->show_menu (menu, nested);
grub_print_error ();
err2 = grub_auth_check_authentication (NULL);
if (err2)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
continue;
}
break;
}
return err1;
}

View file

@ -68,7 +68,10 @@ grub_normal_print_device_info (const char *name)
if (grub_errno == GRUB_ERR_NONE)
{
if (label && grub_strlen (label))
grub_printf_ (N_("- Label %s"), label);
{
grub_putchar (' ');
grub_printf_ (N_("- Label \"%s\""), label);
}
grub_free (label);
}
grub_errno = GRUB_ERR_NONE;
@ -81,6 +84,7 @@ grub_normal_print_device_info (const char *name)
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,

251
normal/term.c Normal file
View file

@ -0,0 +1,251 @@
/*
* 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_xasprintf ("%s/terminal.lst", prefix);
if (!filename)
{
grub_errno = GRUB_ERR_NONE;
return;
}
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;
}