diff --git a/.bzrignore b/.bzrignore index 56e3516b5..8cdc9d12d 100644 --- a/.bzrignore +++ b/.bzrignore @@ -35,6 +35,7 @@ grub_fstest_init.c grub_fstest_init.h grub-install grub-mk* +grub-pbkdf2 grub-pe2elf grub-probe grub_probe_init.c diff --git a/Makefile.in b/Makefile.in index 7f87cf40b..018bed733 100644 --- a/Makefile.in +++ b/Makefile.in @@ -171,7 +171,7 @@ endif ### General targets. CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA) po/*.mo -pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst +pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep.awk cat $(DEFSYMFILES) /dev/null \ | $(AWK) -f $(srcdir)/genmoddep.awk $(UNDSYMFILES) > $@ \ @@ -189,12 +189,18 @@ partmap.lst: $(PARTMAPFILES) handler.lst: $(HANDLERFILES) cat $^ /dev/null | sort > $@ +terminal.lst: $(TERMINALFILES) + cat $^ /dev/null | sort > $@ + parttool.lst: $(PARTTOOLFILES) cat $^ /dev/null | sort | uniq > $@ video.lst: $(VIDEOFILES) cat $^ /dev/null | sort | uniq > $@ +crypto.lst: lib/libgcrypt-grub/cipher/crypto.lst + cp $^ $@ + ifneq (true, $(MAKEINFO)) info_INFOS += docs/grub.info endif diff --git a/commands/handler.c b/commands/handler.c index d65a703e4..60889dd5e 100644 --- a/commands/handler.c +++ b/commands/handler.c @@ -25,10 +25,9 @@ #include static grub_err_t -grub_cmd_handler (struct grub_command *cmd, +grub_cmd_handler (struct grub_command *cmd __attribute__ ((unused)), int argc, char **args) { - char *class_name; void *curr_item = 0; grub_handler_class_t head; @@ -43,23 +42,19 @@ grub_cmd_handler (struct grub_command *cmd, return 0; } - class_name = (grub_strcmp (cmd->name, "handler")) ? (char *) cmd->name : 0; - head = grub_handler_class_list; - if ((argc == 0) && (class_name == 0)) + if (argc == 0) { grub_list_iterate (GRUB_AS_LIST (head), (grub_list_hook_t) list_item); } else { + char *class_name; grub_handler_class_t class; - if (class_name == 0) - { - class_name = args[0]; - argc--; - args++; - } + class_name = args[0]; + argc--; + args++; class = grub_named_list_find (GRUB_AS_NAMED_LIST (head), class_name); if (! class) @@ -89,7 +84,7 @@ grub_cmd_handler (struct grub_command *cmd, return 0; } -static grub_command_t cmd_handler, cmd_terminal_input, cmd_terminal_output; +static grub_command_t cmd_handler; GRUB_MOD_INIT(handler) { @@ -97,19 +92,9 @@ GRUB_MOD_INIT(handler) grub_register_command ("handler", grub_cmd_handler, "handler [class [handler]]", "List or select a handler."); - cmd_terminal_input = - grub_register_command ("terminal_input", grub_cmd_handler, - "terminal_input [handler]", - "List or select an input terminal."); - cmd_terminal_output = - grub_register_command ("terminal_output", grub_cmd_handler, - "terminal_output [handler]", - "List or select an output terminal."); } GRUB_MOD_FINI(handler) { grub_unregister_command (cmd_handler); - grub_unregister_command (cmd_terminal_input); - grub_unregister_command (cmd_terminal_output); } diff --git a/commands/hashsum.c b/commands/hashsum.c new file mode 100644 index 000000000..60e17447b --- /dev/null +++ b/commands/hashsum.c @@ -0,0 +1,278 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct grub_arg_option options[] = { + {"hash", 'h', 0, "Specify hash to use.", "HASH", ARG_TYPE_STRING}, + {"check", 'c', 0, "Check hash list file.", "FILE", ARG_TYPE_STRING}, + {"prefix", 'p', 0, "Base directory for hash list.", "DIRECTORY", + ARG_TYPE_STRING}, + {"keep-going", 'k', 0, "Don't stop after first error.", 0, 0}, + {0, 0, 0, 0, 0, 0} +}; + +struct { const char *name; const char *hashname; } aliases[] = + { + {"sha256sum", "sha256"}, + {"sha512sum", "sha512"}, + {"md5sum", "md5"}, + }; + +static inline int +hextoval (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +static grub_err_t +hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result) +{ + grub_uint8_t context[hash->contextsize]; + char *readbuf[4096]; + + grub_memset (context, 0, sizeof (context)); + hash->init (context); + while (1) + { + grub_ssize_t r; + r = grub_file_read (file, readbuf, sizeof (readbuf)); + if (r < 0) + return grub_errno; + if (r == 0) + break; + hash->write (context, readbuf, r); + } + hash->final (context); + grub_memcpy (result, hash->read (context), hash->mdlen); + + return GRUB_ERR_NONE; +} + +static grub_err_t +check_list (const gcry_md_spec_t *hash, const char *hashfilename, + const char *prefix, int keep) +{ + grub_file_t hashlist, file; + char *buf = NULL; + grub_uint8_t expected[hash->mdlen]; + grub_uint8_t actual[hash->mdlen]; + grub_err_t err; + unsigned i; + unsigned unread = 0, mismatch = 0; + + hashlist = grub_file_open (hashfilename); + if (!hashlist) + return grub_errno; + + while (grub_free (buf), (buf = grub_file_getline (hashlist))) + { + const char *p = buf; + for (i = 0; i < hash->mdlen; i++) + { + int high, low; + high = hextoval (*p++); + low = hextoval (*p++); + if (high < 0 || low < 0) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); + expected[i] = (high << 4) | low; + } + if (*p++ != ' ' || *p++ != ' ') + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); + if (prefix) + { + char *filename; + + filename = grub_malloc (grub_strlen (prefix) + + grub_strlen (p) + 2); + if (!filename) + return grub_errno; + grub_sprintf (filename, "%s/%s", prefix, p); + file = grub_file_open (filename); + grub_free (filename); + } + else + file = grub_file_open (p); + if (!file) + { + grub_file_close (hashlist); + grub_free (buf); + return grub_errno; + } + err = hash_file (file, hash, actual); + grub_file_close (file); + if (err) + { + grub_printf ("%s: READ ERROR\n", p); + if (!keep) + { + grub_file_close (hashlist); + grub_free (buf); + return err; + } + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0) + { + grub_printf ("%s: HASH MISMATCH\n", p); + if (!keep) + { + grub_file_close (hashlist); + grub_free (buf); + return grub_error (GRUB_ERR_TEST_FAILURE, + "hash of '%s' mismatches", p); + } + mismatch++; + continue; + } + grub_printf ("%s: OK\n", p); + } + if (mismatch || unread) + return grub_error (GRUB_ERR_TEST_FAILURE, + "%d files couldn't be read and hash " + "of %d files mismatches", unread, mismatch); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_hashsum (struct grub_extcmd *cmd, + int argc, char **args) +{ + struct grub_arg_list *state = cmd->state; + const char *hashname = NULL; + const char *prefix = NULL; + const gcry_md_spec_t *hash; + unsigned i; + int keep = state[3].set; + unsigned unread = 0; + + for (i = 0; i < ARRAY_SIZE (aliases); i++) + if (grub_strcmp (cmd->cmd->name, aliases[i].name) == 0) + hashname = aliases[i].hashname; + if (state[0].set) + hashname = state[0].arg; + + if (!hashname) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no hash specified"); + + hash = grub_crypto_lookup_md_by_name (hashname); + if (!hash) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown hash"); + + if (state[2].set) + prefix = state[2].arg; + + if (state[1].set) + { + if (argc != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "--check is incompatible with file list"); + return check_list (hash, state[1].arg, prefix, keep); + } + + for (i = 0; i < (unsigned) argc; i++) + { + grub_uint8_t result[hash->mdlen]; + grub_file_t file; + grub_err_t err; + unsigned j; + file = grub_file_open (args[i]); + if (!file) + { + if (!keep) + return grub_errno; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + err = hash_file (file, hash, result); + grub_file_close (file); + if (err) + { + if (!keep) + return err; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + for (j = 0; j < hash->mdlen; j++) + grub_printf ("%02x", result[j]); + grub_printf (" %s\n", args[i]); + } + + if (unread) + return grub_error (GRUB_ERR_TEST_FAILURE, "%d files couldn't be read.", + unread); + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd, cmd_md5, cmd_sha256, cmd_sha512; + +GRUB_MOD_INIT(hashsum) +{ + cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + "hashsum -h HASH [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]", + "Compute or check hash checksum.", + options); + cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + "md5sum [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]", + "Compute or check hash checksum.", + options); + cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + "sha256sum [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]", + "Compute or check hash checksum.", + options); + cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + "sha512sum [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]", + "Compute or check hash checksum.", + options); +} + +GRUB_MOD_FINI(hashsum) +{ + grub_unregister_extcmd (cmd); + grub_unregister_extcmd (cmd_md5); + grub_unregister_extcmd (cmd_sha256); + grub_unregister_extcmd (cmd_sha512); +} diff --git a/commands/help.c b/commands/help.c index c18ec6b83..bfca5e0cc 100644 --- a/commands/help.c +++ b/commands/help.c @@ -37,18 +37,26 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc, if ((cmd->prio & GRUB_PRIO_LIST_FLAG_ACTIVE) && (cmd->flags & GRUB_COMMAND_FLAG_CMDLINE)) { - char description[GRUB_TERM_WIDTH / 2]; + struct grub_term_output *cur; int desclen = grub_strlen (cmd->summary); + FOR_ACTIVE_TERM_OUTPUTS(cur) + { + int width = grub_term_width(cur); + char description[width / 2]; - /* Make a string with a length of GRUB_TERM_WIDTH / 2 - 1 filled - with the description followed by spaces. */ - grub_memset (description, ' ', GRUB_TERM_WIDTH / 2 - 1); - description[GRUB_TERM_WIDTH / 2 - 1] = '\0'; - grub_memcpy (description, cmd->summary, - (desclen < GRUB_TERM_WIDTH / 2 - 1 - ? desclen : GRUB_TERM_WIDTH / 2 - 1)); - - grub_printf ("%s%s", description, (cnt++) % 2 ? "\n" : " "); + /* Make a string with a length of GRUB_TERM_WIDTH / 2 - 1 filled + with the description followed by spaces. */ + grub_memset (description, ' ', width / 2 - 1); + description[width / 2 - 1] = '\0'; + grub_memcpy (description, cmd->summary, + (desclen < width / 2 - 1 + ? desclen : width / 2 - 1)); + grub_puts_terminal (description, cur); + } + if ((cnt++) % 2) + grub_printf ("\n"); + else + grub_printf (" "); } return 0; } @@ -73,7 +81,11 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc, } if (argc == 0) - grub_command_iterate (print_command_info); + { + grub_command_iterate (print_command_info); + if (!(cnt % 2)) + grub_printf ("\n"); + } else { int i; diff --git a/commands/keystatus.c b/commands/keystatus.c index 0a4667645..580e25f5d 100644 --- a/commands/keystatus.c +++ b/commands/keystatus.c @@ -48,13 +48,24 @@ grub_cmd_keystatus (grub_extcmd_t cmd, if (state[2].set) expect_mods |= GRUB_TERM_STATUS_ALT; + grub_dprintf ("keystatus", "expect_mods: %d\n", expect_mods); + /* Without arguments, just check whether getkeystatus is supported at all. */ - if (!grub_cur_term_input->getkeystatus) - return grub_error (GRUB_ERR_TEST_FAILURE, "false"); - grub_dprintf ("keystatus", "expect_mods: %d\n", expect_mods); - if (!expect_mods) - return 0; + if (expect_mods == 0) + { + grub_term_input_t term; + int nterms = 0; + + FOR_ACTIVE_TERM_INPUTS (term) + if (!term->getkeystatus) + return grub_error (GRUB_ERR_TEST_FAILURE, "false"); + else + nterms++; + if (!nterms) + return grub_error (GRUB_ERR_TEST_FAILURE, "false"); + return 0; + } mods = grub_getkeystatus (); grub_dprintf ("keystatus", "mods: %d\n", mods); diff --git a/commands/password.c b/commands/password.c index 0e048797e..7bb2f0ae5 100644 --- a/commands/password.c +++ b/commands/password.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -27,17 +28,10 @@ static grub_dl_t my_mod; static grub_err_t -check_password (const char *user, +check_password (const char *user, const char *entered, void *password) { - char entered[1024]; - - grub_memset (entered, 0, sizeof (entered)); - - if (!GRUB_GET_PASSWORD (entered, sizeof (entered) - 1)) - return GRUB_ACCESS_DENIED; - - if (grub_auth_strcmp (entered, password) != 0) + if (grub_crypto_memcmp (entered, password, GRUB_AUTH_MAX_PASSLEN) != 0) return GRUB_ACCESS_DENIED; grub_auth_authenticate (user); @@ -51,13 +45,18 @@ grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), { grub_err_t err; char *pass; + int copylen; if (argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected."); - pass = grub_strdup (args[1]); + pass = grub_zalloc (GRUB_AUTH_MAX_PASSLEN); if (!pass) return grub_errno; + copylen = grub_strlen (args[1]); + if (copylen >= GRUB_AUTH_MAX_PASSLEN) + copylen = GRUB_AUTH_MAX_PASSLEN - 1; + grub_memcpy (pass, args[1], copylen); err = grub_auth_register_authentication (args[0], check_password, pass); if (err) diff --git a/commands/password_pbkdf2.c b/commands/password_pbkdf2.c new file mode 100644 index 000000000..51c8ea794 --- /dev/null +++ b/commands/password_pbkdf2.c @@ -0,0 +1,196 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_dl_t my_mod; + +struct pbkdf2_password +{ + grub_uint8_t *salt; + grub_size_t saltlen; + unsigned int c; + grub_uint8_t *expected; + grub_size_t buflen; +}; + +static grub_err_t +check_password (const char *user, const char *entered, void *pin) +{ + grub_uint8_t *buf; + struct pbkdf2_password *pass = pin; + gcry_err_code_t err; + + buf = grub_malloc (pass->buflen); + if (!buf) + return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY); + + err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, (grub_uint8_t *) entered, + grub_strlen (entered), + pass->salt, pass->saltlen, pass->c, + buf, pass->buflen); + if (err) + { + grub_free (buf); + return grub_crypto_gcry_error (err); + } + + if (grub_crypto_memcmp (buf, pass->expected, pass->buflen) != 0) + return GRUB_ACCESS_DENIED; + + grub_auth_authenticate (user); + + return GRUB_ERR_NONE; +} + +static inline int +hex2val (char hex) +{ + if ('0' <= hex && hex <= '9') + return hex - '0'; + if ('a' <= hex && hex <= 'f') + return hex - 'a' + 10; + if ('A' <= hex && hex <= 'F') + return hex - 'A' + 10; + return -1; +} + +static grub_err_t +grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_err_t err; + char *ptr, *ptr2; + grub_uint8_t *ptro; + struct pbkdf2_password *pass; + + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected."); + + if (grub_memcmp (args[1], "grub.pbkdf2.sha512.", + sizeof ("grub.pbkdf2.sha512.") - 1) != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); + + ptr = args[1] + sizeof ("grub.pbkdf2.sha512.") - 1; + + pass = grub_malloc (sizeof (*pass)); + if (!pass) + return grub_errno; + + pass->c = grub_strtoul (ptr, &ptr, 0); + if (*ptr != '.') + { + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); + } + ptr++; + + ptr2 = grub_strchr (ptr, '.'); + if (!ptr2 || ((ptr2 - ptr) & 1) || grub_strlen (ptr2 + 1) & 1) + { + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); + } + + pass->saltlen = (ptr2 - ptr) >> 1; + pass->buflen = grub_strlen (ptr2 + 1) >> 1; + ptro = pass->salt = grub_malloc (pass->saltlen); + if (!ptro) + { + grub_free (pass); + return grub_errno; + } + while (ptr < ptr2) + { + int hex1, hex2; + hex1 = hex2val (*ptr); + ptr++; + hex2 = hex2val (*ptr); + ptr++; + if (hex1 < 0 || hex2 < 0) + { + grub_free (pass->salt); + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Incorrect PBKDF2 password."); + } + + *ptro = (hex1 << 4) | hex2; + ptro++; + } + + ptro = pass->expected = grub_malloc (pass->buflen); + if (!ptro) + { + grub_free (pass->salt); + grub_free (pass); + return grub_errno; + } + ptr = ptr2 + 1; + ptr2 += grub_strlen (ptr2); + while (ptr < ptr2) + { + int hex1, hex2; + hex1 = hex2val (*ptr); + ptr++; + hex2 = hex2val (*ptr); + ptr++; + if (hex1 < 0 || hex2 < 0) + { + grub_free (pass->expected); + grub_free (pass->salt); + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Incorrect PBKDF2 password."); + } + + *ptro = (hex1 << 4) | hex2; + ptro++; + } + + err = grub_auth_register_authentication (args[0], check_password, pass); + if (err) + { + grub_free (pass); + return err; + } + grub_dl_ref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(password_pbkdf2) +{ + my_mod = mod; + cmd = grub_register_command ("password_pbkdf2", grub_cmd_password, + "password_pbkdf2 USER PBKDF2_PASSWORD", + "Set user password (PBKDF2). "); +} + +GRUB_MOD_FINI(password_pbkdf2) +{ + grub_unregister_command (cmd); +} diff --git a/commands/sleep.c b/commands/sleep.c index 9207b60a7..aea7f2690 100644 --- a/commands/sleep.c +++ b/commands/sleep.c @@ -32,12 +32,12 @@ static const struct grub_arg_option options[] = {0, 0, 0, 0, 0, 0} }; -static grub_uint8_t x, y; +static grub_uint16_t *pos; static void do_print (int n) { - grub_gotoxy (x, y); + grub_term_restore_pos (pos); /* NOTE: Do not remove the trailing space characters. They are required to clear the line. */ grub_printf ("%d ", n); @@ -63,7 +63,6 @@ static grub_err_t grub_cmd_sleep (grub_extcmd_t cmd, int argc, char **args) { struct grub_arg_list *state = cmd->state; - grub_uint16_t xy; int n; if (argc != 1) @@ -77,9 +76,7 @@ grub_cmd_sleep (grub_extcmd_t cmd, int argc, char **args) return 0; } - xy = grub_getxy (); - x = xy >> 8; - y = xy & 0xff; + pos = grub_term_save_pos (); for (; n; n--) { diff --git a/commands/terminal.c b/commands/terminal.c new file mode 100644 index 000000000..5befecd31 --- /dev/null +++ b/commands/terminal.c @@ -0,0 +1,364 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +struct grub_term_autoload *grub_term_input_autoload = NULL; +struct grub_term_autoload *grub_term_output_autoload = NULL; + +grub_err_t +grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + int i; + grub_term_input_t term; + struct grub_term_autoload *aut; + + if (argc == 0) + { + grub_puts_ (N_ ("Active input terminals:")); + FOR_ACTIVE_TERM_INPUTS(term) + grub_printf ("%s ", term->name); + grub_printf ("\n"); + grub_puts_ (N_ ("Available input terminals:")); + FOR_DISABLED_TERM_INPUTS(term) + grub_printf ("%s ", term->name); + /* This is quadratic but we don't expect mode than 30 terminal + modules ever. */ + for (aut = grub_term_input_autoload; aut; aut = aut->next) + { + FOR_DISABLED_TERM_INPUTS(term) + if (grub_strcmp (term->name, aut->name) == 0) + break; + if (!term) + FOR_ACTIVE_TERM_INPUTS(term) + if (grub_strcmp (term->name, aut->name) == 0) + break; + if (!term) + grub_printf ("%s ", aut->name); + } + grub_printf ("\n"); + return GRUB_ERR_NONE; + } + i = 0; + + if (grub_strcmp (args[0], "--append") == 0 + || grub_strcmp (args[0], "--remove") == 0) + i++; + + if (i == argc) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no terminal specified")); + + for (; i < argc; i++) + { + int again = 0; + while (1) + { + FOR_DISABLED_TERM_INPUTS(term) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term == 0) + FOR_ACTIVE_TERM_INPUTS(term) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + break; + if (again) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n", + args[i]); + for (aut = grub_term_input_autoload; aut; aut = aut->next) + if (grub_strcmp (args[i], aut->name) == 0) + { + grub_dl_t mod; + mod = grub_dl_load (aut->modname); + if (mod) + grub_dl_ref (mod); + grub_errno = GRUB_ERR_NONE; + break; + } + if (!aut) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n", + args[i]); + again = 1; + } + } + + if (grub_strcmp (args[0], "--append") == 0) + { + for (i = 1; i < argc; i++) + { + FOR_DISABLED_TERM_INPUTS(term) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + { + grub_list_remove (GRUB_AS_LIST_P (&(grub_term_inputs_disabled)), + GRUB_AS_LIST (term)); + if (term->init) + term->init (); + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs), + GRUB_AS_LIST (term)); + } + } + return GRUB_ERR_NONE; + } + + if (grub_strcmp (args[0], "--remove") == 0) + { + for (i = 1; i < argc; i++) + { + FOR_ACTIVE_TERM_INPUTS(term) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + { + if (!term->next && term == grub_term_inputs) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "can't remove the last terminal"); + grub_list_remove (GRUB_AS_LIST_P (&(grub_term_inputs)), + GRUB_AS_LIST (term)); + if (term->fini) + term->fini (); + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); + } + } + return GRUB_ERR_NONE; + } + for (i = 0; i < argc; i++) + { + FOR_DISABLED_TERM_INPUTS(term) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + { + grub_list_remove (GRUB_AS_LIST_P (&(grub_term_inputs_disabled)), + GRUB_AS_LIST (term)); + if (term->init) + term->init (); + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs), + GRUB_AS_LIST (term)); + } + } + + FOR_ACTIVE_TERM_INPUTS(term) + { + for (i = 0; i < argc; i++) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (i == argc) + { + if (!term->next && term == grub_term_inputs) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "can't remove the last terminal"); + grub_list_remove (GRUB_AS_LIST_P (&(grub_term_inputs)), + GRUB_AS_LIST (term)); + if (term->fini) + term->fini (); + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); + } + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + int i; + grub_term_output_t term; + struct grub_term_autoload *aut; + + if (argc == 0) + { + grub_puts_ (N_ ("Active output terminals:")); + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_printf ("%s ", term->name); + grub_printf ("\n"); + grub_puts_ (N_ ("Available output terminals:")); + FOR_DISABLED_TERM_OUTPUTS(term) + grub_printf ("%s ", term->name); + /* This is quadratic but we don't expect mode than 30 terminal + modules ever. */ + for (aut = grub_term_output_autoload; aut; aut = aut->next) + { + FOR_DISABLED_TERM_OUTPUTS(term) + if (grub_strcmp (term->name, aut->name) == 0) + break; + if (!term) + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_strcmp (term->name, aut->name) == 0) + break; + if (!term) + grub_printf ("%s ", aut->name); + } + grub_printf ("\n"); + return GRUB_ERR_NONE; + } + i = 0; + + if (grub_strcmp (args[0], "--append") == 0 + || grub_strcmp (args[0], "--remove") == 0) + i++; + + if (i == argc) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no terminal specified")); + + for (; i < argc; i++) + { + int again = 0; + while (1) + { + FOR_DISABLED_TERM_OUTPUTS(term) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term == 0) + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + break; + if (again) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n", + args[i]); + for (aut = grub_term_output_autoload; aut; aut = aut->next) + if (grub_strcmp (args[i], aut->name) == 0) + { + grub_dl_t mod; + mod = grub_dl_load (aut->modname); + if (mod) + grub_dl_ref (mod); + grub_errno = GRUB_ERR_NONE; + break; + } + if (!aut) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n", + args[i]); + again = 1; + } + } + + if (grub_strcmp (args[0], "--append") == 0) + { + for (i = 1; i < argc; i++) + { + FOR_DISABLED_TERM_OUTPUTS(term) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + { + grub_list_remove (GRUB_AS_LIST_P (&(grub_term_outputs_disabled)), + GRUB_AS_LIST (term)); + if (term->init) + term->init (); + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs), + GRUB_AS_LIST (term)); + } + } + return GRUB_ERR_NONE; + } + + if (grub_strcmp (args[0], "--remove") == 0) + { + for (i = 1; i < argc; i++) + { + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + { + if (!term->next && term == grub_term_outputs) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "can't remove the last terminal"); + grub_list_remove (GRUB_AS_LIST_P (&(grub_term_outputs)), + GRUB_AS_LIST (term)); + if (term->fini) + term->fini (); + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs_disabled), + GRUB_AS_LIST (term)); + } + } + return GRUB_ERR_NONE; + } + + for (i = 0; i < argc; i++) + { + FOR_DISABLED_TERM_OUTPUTS(term) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + { + grub_list_remove (GRUB_AS_LIST_P (&(grub_term_outputs_disabled)), + GRUB_AS_LIST (term)); + if (term->init) + term->init (); + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs), + GRUB_AS_LIST (term)); + } + } + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + for (i = 0; i < argc; i++) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (i == argc) + { + if (!term->next && term == grub_term_outputs) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "can't remove the last terminal"); + grub_list_remove (GRUB_AS_LIST_P (&(grub_term_outputs)), + GRUB_AS_LIST (term)); + if (term->fini) + term->fini (); + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs_disabled), + GRUB_AS_LIST (term)); + } + } + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd_terminal_input, cmd_terminal_output; + +GRUB_MOD_INIT(terminal) +{ + cmd_terminal_input = + grub_register_command ("terminal_input", grub_cmd_terminal_input, + "terminal_input [--append|--remove] " + "[TERMINAL1] [TERMINAL2] ...", + "List or select an input terminal."); + cmd_terminal_output = + grub_register_command ("terminal_output", grub_cmd_terminal_output, + "terminal_output [--append|--remove] " + "[TERMINAL1] [TERMINAL2] ...", + "List or select an output terminal."); +} + +GRUB_MOD_FINI(terminal) +{ + grub_unregister_command (cmd_terminal_input); + grub_unregister_command (cmd_terminal_output); +} diff --git a/commands/xnu_uuid.c b/commands/xnu_uuid.c index 85c0e9ce4..c43c4bf37 100644 --- a/commands/xnu_uuid.c +++ b/commands/xnu_uuid.c @@ -31,12 +31,7 @@ #include #include #include - -struct tohash -{ - grub_uint8_t prefix[16]; - grub_uint64_t serial; -} __attribute__ ((packed)); +#include /* This prefix is used by xnu and boot-132 to hash together with volume serial. */ @@ -44,311 +39,27 @@ static grub_uint8_t hash_prefix[16] = {0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC}; -#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) -#define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) - -typedef struct { - grub_uint32_t A,B,C,D; /* chaining variables */ - grub_uint32_t nblocks; - grub_uint8_t buf[64]; - int count; -} MD5_CONTEXT; - -static void -md5_init( void *context ) -{ - MD5_CONTEXT *ctx = context; - - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - - ctx->nblocks = 0; - ctx->count = 0; -} - -/* These are the four functions used in the four steps of the MD5 algorithm - and defined in the RFC 1321. The first function is a little bit optimized - (as found in Colin Plumbs public domain implementation). */ -/* #define FF(b, c, d) ((b & c) | (~b & d)) */ -#define FF(b, c, d) (d ^ (b & (c ^ d))) -#define FG(b, c, d) FF (d, b, c) -#define FH(b, c, d) (b ^ c ^ d) -#define FI(b, c, d) (c ^ (b | ~d)) - - -/**************** - * transform n*64 grub_uint8_ts - */ -static void -transform ( MD5_CONTEXT *ctx, const unsigned char *data ) -{ - grub_uint32_t correct_words[16]; - register grub_uint32_t A = ctx->A; - register grub_uint32_t B = ctx->B; - register grub_uint32_t C = ctx->C; - register grub_uint32_t D = ctx->D; - grub_uint32_t *cwp = correct_words; - -#ifdef GRUB_CPU_WORDS_BIGENDIAN - { - int i; - const grub_uint32_t *p = (const grub_uint32_t *) data; - - for (i = 0; i < 16; i++) - correct_words[i] = grub_le_to_cpu32 (p[i]); - } -#else - grub_memcpy (correct_words, data, 64); -#endif - -#define OP(a, b, c, d, s, T) \ - do \ - { \ - a += FF (b, c, d) + (*cwp++) + T; \ - a = rol(a, s); \ - a += b; \ - } \ - while (0) - - /* Before we start, one word about the strange constants. - They are defined in RFC 1321 as - - T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 - */ - - /* Round 1. */ - OP (A, B, C, D, 7, 0xd76aa478); - OP (D, A, B, C, 12, 0xe8c7b756); - OP (C, D, A, B, 17, 0x242070db); - OP (B, C, D, A, 22, 0xc1bdceee); - OP (A, B, C, D, 7, 0xf57c0faf); - OP (D, A, B, C, 12, 0x4787c62a); - OP (C, D, A, B, 17, 0xa8304613); - OP (B, C, D, A, 22, 0xfd469501); - OP (A, B, C, D, 7, 0x698098d8); - OP (D, A, B, C, 12, 0x8b44f7af); - OP (C, D, A, B, 17, 0xffff5bb1); - OP (B, C, D, A, 22, 0x895cd7be); - OP (A, B, C, D, 7, 0x6b901122); - OP (D, A, B, C, 12, 0xfd987193); - OP (C, D, A, B, 17, 0xa679438e); - OP (B, C, D, A, 22, 0x49b40821); - -#undef OP -#define OP(f, a, b, c, d, k, s, T) \ - do \ - { \ - a += f (b, c, d) + correct_words[k] + T; \ - a = rol(a, s); \ - a += b; \ - } \ - while (0) - - /* Round 2. */ - OP (FG, A, B, C, D, 1, 5, 0xf61e2562); - OP (FG, D, A, B, C, 6, 9, 0xc040b340); - OP (FG, C, D, A, B, 11, 14, 0x265e5a51); - OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP (FG, A, B, C, D, 5, 5, 0xd62f105d); - OP (FG, D, A, B, C, 10, 9, 0x02441453); - OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP (FG, D, A, B, C, 14, 9, 0xc33707d6); - OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP (FG, B, C, D, A, 8, 20, 0x455a14ed); - OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP (FG, C, D, A, B, 7, 14, 0x676f02d9); - OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); - - /* Round 3. */ - OP (FH, A, B, C, D, 5, 4, 0xfffa3942); - OP (FH, D, A, B, C, 8, 11, 0x8771f681); - OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP (FH, B, C, D, A, 14, 23, 0xfde5380c); - OP (FH, A, B, C, D, 1, 4, 0xa4beea44); - OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP (FH, B, C, D, A, 6, 23, 0x04881d05); - OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); - - /* Round 4. */ - OP (FI, A, B, C, D, 0, 6, 0xf4292244); - OP (FI, D, A, B, C, 7, 10, 0x432aff97); - OP (FI, C, D, A, B, 14, 15, 0xab9423a7); - OP (FI, B, C, D, A, 5, 21, 0xfc93a039); - OP (FI, A, B, C, D, 12, 6, 0x655b59c3); - OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP (FI, C, D, A, B, 10, 15, 0xffeff47d); - OP (FI, B, C, D, A, 1, 21, 0x85845dd1); - OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP (FI, C, D, A, B, 6, 15, 0xa3014314); - OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP (FI, A, B, C, D, 4, 6, 0xf7537e82); - OP (FI, D, A, B, C, 11, 10, 0xbd3af235); - OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP (FI, B, C, D, A, 9, 21, 0xeb86d391); - - /* Put checksum in context given as argument. */ - ctx->A += A; - ctx->B += B; - ctx->C += C; - ctx->D += D; -} - -/* The routine updates the message-digest context to - * account for the presence of each of the characters inBuf[0..inLen-1] - * in the message whose digest is being computed. - */ -static void -md5_write( void *context, const void *inbuf_arg , grub_size_t inlen) -{ - const unsigned char *inbuf = inbuf_arg; - MD5_CONTEXT *hd = context; - - if( hd->count == 64 ) /* flush the buffer */ - { - transform( hd, hd->buf ); - // _gcry_burn_stack (80+6*sizeof(void*)); - hd->count = 0; - hd->nblocks++; - } - if( !inbuf ) - return; - - if( hd->count ) - { - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; - md5_write( hd, NULL, 0 ); - if( !inlen ) - return; - } - // _gcry_burn_stack (80+6*sizeof(void*)); - - while( inlen >= 64 ) - { - transform( hd, inbuf ); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; - -} - - - -/* The routine final terminates the message-digest computation and - * ends with the desired message digest in mdContext->digest[0...15]. - * The handle is prepared for a new MD5 cycle. - * Returns 16 grub_uint8_ts representing the digest. - */ -static void -md5_final( void *context) -{ - MD5_CONTEXT *hd = context; - grub_uint32_t t, msb, lsb; - grub_uint32_t *p; - - md5_write(hd, NULL, 0); /* flush */; - - t = hd->nblocks; - /* multiply by 64 to make a grub_uint8_t count */ - lsb = t << 6; - msb = t >> 26; - /* add the count */ - t = lsb; - if( (lsb += hd->count) < t ) - msb++; - /* multiply by 8 to make a bit count */ - t = lsb; - lsb <<= 3; - msb <<= 3; - msb |= t >> 29; - - if( hd->count < 56 ) /* enough room */ - { - hd->buf[hd->count++] = 0x80; /* pad */ - while( hd->count < 56 ) - hd->buf[hd->count++] = 0; /* pad */ - } - else /* need one extra block */ - { - hd->buf[hd->count++] = 0x80; /* pad character */ - while( hd->count < 64 ) - hd->buf[hd->count++] = 0; - md5_write(hd, NULL, 0); /* flush */; - grub_memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ - } - /* append the 64 bit count */ - hd->buf[56] = lsb ; - hd->buf[57] = lsb >> 8; - hd->buf[58] = lsb >> 16; - hd->buf[59] = lsb >> 24; - hd->buf[60] = msb ; - hd->buf[61] = msb >> 8; - hd->buf[62] = msb >> 16; - hd->buf[63] = msb >> 24; - transform( hd, hd->buf ); - // _gcry_burn_stack (80+6*sizeof(void*)); - - p = (grub_uint32_t *) hd->buf; -#define X(a) do { *p = grub_le_to_cpu32 (hd->a); p++; } while (0) - X(A); - X(B); - X(C); - X(D); -#undef X - -} - -/** - * GRUB2 Crypto Interface - * Written by Michael Gorven - */ -static grub_err_t -md5 (const char *in, grub_size_t insize, char *out) -{ - MD5_CONTEXT hd; - - md5_init (&hd); - md5_write (&hd, in, insize); - md5_final (&hd); - grub_memcpy (out, hd.buf, 16); - - return GRUB_ERR_NONE; -} - static grub_err_t grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { - struct tohash hashme; - grub_uint8_t xnu_uuid[16]; + grub_uint64_t serial; + grub_uint8_t *xnu_uuid; char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; char *ptr; + grub_uint8_t ctx[GRUB_MD_MD5->contextsize]; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required"); - hashme.serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); - grub_memcpy (hashme.prefix, hash_prefix, sizeof (hashme.prefix)); + serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); + + GRUB_MD_MD5->init (&ctx); + GRUB_MD_MD5->write (&ctx, hash_prefix, sizeof (hash_prefix)); + GRUB_MD_MD5->write (&ctx, &serial, sizeof (serial)); + GRUB_MD_MD5->final (&ctx); + xnu_uuid = GRUB_MD_MD5->read (&ctx); - md5 ((char *) &hashme, sizeof (hashme), (char *) xnu_uuid); grub_sprintf (uuid_string, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", (unsigned int) xnu_uuid[0], (unsigned int) xnu_uuid[1], diff --git a/conf/any-emu.rmk b/conf/any-emu.rmk index 76ca8e30e..f99b36c07 100644 --- a/conf/any-emu.rmk +++ b/conf/any-emu.rmk @@ -24,10 +24,10 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/partition.c kern/reader.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ lib/arg.c normal/cmdline.c normal/datetime.c normal/misc.c \ - normal/handler.c normal/auth.c normal/autofs.c \ + normal/handler.c normal/auth.c lib/crypto.c normal/autofs.c \ normal/completion.c normal/main.c normal/color.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ - normal/menu_text.c \ + normal/menu_text.c normal/crypto.c normal/term.c \ script/main.c script/execute.c script/function.c \ script/lexer.c script/script.c grub_script.tab.c \ partmap/amiga.c partmap/apple.c partmap/msdos.c partmap/sun.c \ @@ -59,7 +59,10 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ disk/raid.c disk/raid5_recover.c disk/raid6_recover.c \ disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ commands/parttool.c parttool/msdospart.c \ + lib/libgcrypt-grub/cipher/md5.c \ grub_emu_init.c gnulib/progname.c +grub_emu_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap + ifeq ($(target_cpu), i386) grub_emu_SOURCES += commands/i386/cpuid.c diff --git a/conf/common.rmk b/conf/common.rmk index f7d982f42..81e964ca4 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -579,7 +579,7 @@ normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \ normal/auth.c normal/autofs.c normal/handler.c \ normal/color.c normal/completion.c normal/datetime.c normal/menu.c \ normal/menu_entry.c normal/menu_text.c normal/menu_viewer.c \ - normal/misc.c + normal/misc.c normal/crypto.c normal/term.c normal_mod_CFLAGS = $(COMMON_CFLAGS) normal_mod_LDFLAGS = $(COMMON_LDFLAGS) @@ -697,3 +697,35 @@ pkglib_MODULES += charset.mod charset_mod_SOURCES = lib/charset.c charset_mod_CFLAGS = $(COMMON_CFLAGS) charset_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += terminal.mod +terminal_mod_SOURCES = commands/terminal.c +terminal_mod_CFLAGS = $(COMMON_CFLAGS) +terminal_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += crypto.mod +crypto_mod_SOURCES = lib/crypto.c +crypto_mod_CFLAGS = $(COMMON_CFLAGS) +crypto_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += hashsum.mod +hashsum_mod_SOURCES = commands/hashsum.c +hashsum_mod_CFLAGS = $(COMMON_CFLAGS) +hashsum_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += pbkdf2.mod +pbkdf2_mod_SOURCES = lib/pbkdf2.c +pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) +pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For password_pbkdf2.mod. +pkglib_MODULES += password_pbkdf2.mod +password_pbkdf2_mod_SOURCES = commands/password_pbkdf2.c +password_pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) +password_pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) + +bin_UTILITIES += grub-mkpasswd-pbkdf2 +grub_mkpasswd_pbkdf2_SOURCES = gnulib/progname.c util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c +grub_mkpasswd_pbkdf2_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap -DGRUB_MKPASSWD=1 + +include $(srcdir)/conf/gcry.mk diff --git a/genhandlerlist.sh b/genhandlerlist.sh index 6446a98ff..e4cb0d9de 100644 --- a/genhandlerlist.sh +++ b/genhandlerlist.sh @@ -16,8 +16,4 @@ module=$1 grep -v "^#" | sed -n \ - -e "/grub_parser_register *( *\"/{s/.*( *\"\([^\"]*\)\".*/parser.\1: $module/;p;}" \ - -e "/grub_reader_register *( *\"/{s/.*( *\"\([^\"]*\)\".*/reader.\1: $module/;p;}" \ - -e "/grub_term_register_input *( *\"/{s/.*( *\"\([^\"]*\)\".*/terminal_input.\1: $module/;p;}" \ - -e "/grub_term_register_output *( *\"/{s/.*( *\"\([^\"]*\)\".*/terminal_output.\1: $module/;p;}" \ - -e "/grub_menu_viewer_register *( *\"/{s/.*( *\"\([^\"]*\)\".*/menu_viewer.\1: $module/;p;}" + -e "/grub_parser_register *( *\"/{s/.*( *\"\([^\"]*\)\".*/parser.\1: $module/;p;}" diff --git a/genmk.rb b/genmk.rb index b3dbe8678..6cb7b5a89 100644 --- a/genmk.rb +++ b/genmk.rb @@ -192,6 +192,7 @@ endif fs = 'fs-' + obj.suffix('lst') partmap = 'partmap-' + obj.suffix('lst') handler = 'handler-' + obj.suffix('lst') + terminal = 'terminal-' + obj.suffix('lst') parttool = 'parttool-' + obj.suffix('lst') video = 'video-' + obj.suffix('lst') dep = deps[i] @@ -213,6 +214,7 @@ FSFILES += #{fs} PARTTOOLFILES += #{parttool} PARTMAPFILES += #{partmap} HANDLERFILES += #{handler} +TERMINALFILES += #{terminal} VIDEOFILES += #{video} #{command}: #{src} $(#{src}_DEPENDENCIES) gencmdlist.sh @@ -240,6 +242,11 @@ VIDEOFILES += #{video} $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \ | sh $(srcdir)/genhandlerlist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1) +#{terminal}: #{src} $(#{src}_DEPENDENCIES) genterminallist.sh + set -e; \ + $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \ + | sh $(srcdir)/genterminallist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1) + #{video}: #{src} $(#{src}_DEPENDENCIES) genvideolist.sh set -e; \ $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \ diff --git a/genterminallist.sh b/genterminallist.sh new file mode 100644 index 000000000..eb0de0c32 --- /dev/null +++ b/genterminallist.sh @@ -0,0 +1,22 @@ +#! /bin/sh +# +# Copyright (C) 2009 Free Software Foundation, Inc. +# +# This script is free software; the author +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Read source code from stdin and detect command names. + +module=$1 + +grep -v "^#" | sed -n \ + -e "/grub_term_register_input *( *\"/{s/.*( *\"\([^\"]*\)\".*/i\1: $module/;p;}" \ + -e "/grub_term_register_input_active *( *\"/{s/.*( *\"\([^\"]*\)\".*/i\1: $module/;p;}" \ + -e "/grub_term_register_output *( *\"/{s/.*( *\"\([^\"]*\)\".*/o\1: $module/;p;}" \ + -e "/grub_term_register_output_active *( *\"/{s/.*( *\"\([^\"]*\)\".*/o\1: $module/;p;}" diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c index 62ee34234..0d807914b 100644 --- a/gfxmenu/gfxmenu.c +++ b/gfxmenu/gfxmenu.c @@ -37,199 +37,58 @@ #include #include -static void switch_to_text_menu (void) +void +grub_gfxmenu_viewer_fini (void *data) { - grub_env_set ("menuviewer", "text"); + grub_gfxmenu_view_t view = data; + + grub_gfxmenu_view_destroy (view); } -static void -process_key_press (int c, - grub_gfxmenu_model_t model, - grub_gfxmenu_view_t view, - int nested, - int *should_exit) +/* FIXME: 't' and 'c'. */ +grub_err_t +grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) { - /* When a key is pressed, stop the timeout. */ - grub_gfxmenu_model_clear_timeout (model); - - switch (c) - { - case 'j': - case GRUB_TERM_DOWN: - { - int i = grub_gfxmenu_model_get_selected_index (model); - int num_items = grub_gfxmenu_model_get_num_entries (model); - if (i < num_items - 1) - { - i++; - grub_gfxmenu_model_set_selected_index (model, i); - grub_gfxmenu_redraw_menu (view); - } - } - break; - - case 'k': - case GRUB_TERM_UP: - { - int i = grub_gfxmenu_model_get_selected_index (model); - if (i > 0) - { - i--; - grub_gfxmenu_model_set_selected_index (model, i); - grub_gfxmenu_redraw_menu (view); - } - } - break; - - case '\r': - case '\n': - case GRUB_TERM_RIGHT: - { - int selected = grub_gfxmenu_model_get_selected_index (model); - int num_entries = grub_gfxmenu_model_get_num_entries (model); - if (selected >= 0 && selected < num_entries) - { - grub_menu_entry_t entry = - grub_gfxmenu_model_get_entry (model, selected); - grub_gfxmenu_view_execute_entry (view, entry); - } - } - break; - - case 'c': - grub_gfxmenu_view_run_terminal (view); - break; - - case 't': - /* The write hook for 'menuviewer' will cause - * grub_menu_viewer_should_return to return nonzero. */ - switch_to_text_menu (); - *should_exit = 1; - break; - - case GRUB_TERM_ESC: - if (nested) - *should_exit = 1; - break; - } - - if (grub_errno != GRUB_ERR_NONE) - *should_exit = 1; -} - -static void -handle_key_events (grub_gfxmenu_model_t model, - grub_gfxmenu_view_t view, - int nested, - int *should_exit) -{ - while ((! *should_exit) && (grub_checkkey () != -1)) - { - int key = grub_getkey (); - int c = GRUB_TERM_ASCII_CHAR (key); - process_key_press (c, model, view, nested, should_exit); - } -} - -static grub_err_t -show_menu (grub_menu_t menu, int nested) -{ - grub_gfxmenu_model_t model; grub_gfxmenu_view_t view; const char *theme_path; + struct grub_menu_viewer *instance; theme_path = grub_env_get ("theme"); if (! theme_path) - { - switch_to_text_menu (); - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified"); - } + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified"); - model = grub_gfxmenu_model_new (menu); - if (! model) - { - switch_to_text_menu (); - return grub_errno; - } + instance = grub_zalloc (sizeof (*instance)); + if (!instance) + return grub_errno; /* Create the view. */ - view = grub_gfxmenu_view_new (theme_path, model); + view = grub_gfxmenu_view_new (theme_path, menu, entry, nested); if (! view) { - grub_print_error (); - grub_gfxmenu_model_destroy (model); - switch_to_text_menu (); + grub_free (instance); return grub_errno; } - /* Initially select the default menu entry. */ - int default_index = grub_menu_get_default_entry_index (menu); - grub_gfxmenu_model_set_selected_index (model, default_index); - - /* Start the timer to execute the default entry. */ - grub_gfxmenu_model_set_timeout (model); - - /* Main event loop. */ - int exit_requested = 0; - grub_gfxmenu_view_draw (view); - grub_video_swap_buffers (); - if (view->double_repaint) - grub_gfxmenu_view_draw (view); - while ((! exit_requested) && (! grub_menu_viewer_should_return ())) - { - grub_gfxmenu_redraw_timeout (view); - if (grub_gfxmenu_model_timeout_expired (model)) - { - grub_gfxmenu_model_clear_timeout (model); - int i = grub_gfxmenu_model_get_selected_index (model); - grub_menu_entry_t e = grub_gfxmenu_model_get_entry (model, i); - grub_gfxmenu_view_execute_with_fallback (view, e); - continue; - } + instance->data = view; + instance->set_chosen_entry = grub_gfxmenu_set_chosen_entry; + instance->fini = grub_gfxmenu_viewer_fini; + instance->print_timeout = grub_gfxmenu_print_timeout; + instance->clear_timeout = grub_gfxmenu_clear_timeout; - handle_key_events (model, view, nested, &exit_requested); - grub_cpu_idle (); - } + grub_menu_register_viewer (instance); - grub_gfxmenu_view_destroy (view); - grub_gfxmenu_model_destroy (model); - - return grub_errno; + return GRUB_ERR_NONE; } -static grub_err_t -grub_cmd_gfxmenu (grub_command_t cmd __attribute__ ((unused)), - int argc __attribute__ ((unused)), - char **args __attribute__ ((unused))) -{ - grub_menu_t menu = grub_env_get_data_slot ("menu"); - if (! menu) - return grub_error (GRUB_ERR_MENU, "no menu context"); - - return show_menu (menu, 1); -} - -static struct grub_menu_viewer menu_viewer = -{ - .name = "gfxmenu", - .show_menu = show_menu -}; - -static grub_command_t cmd; - GRUB_MOD_INIT (gfxmenu) { - (void) mod; /* To stop warning. */ - grub_menu_viewer_register (&menu_viewer); - cmd = grub_register_command ("gfxmenu", grub_cmd_gfxmenu, - "gfxmenu", - "Show graphical menu interface"); + grub_gfxmenu_try_hook = grub_gfxmenu_try; } GRUB_MOD_FINI (gfxmenu) { - grub_unregister_command (cmd); + grub_gfxmenu_try_hook = NULL; } diff --git a/gfxmenu/gui_circular_progress.c b/gfxmenu/gui_circular_progress.c index f3c8bc3af..98d818558 100644 --- a/gfxmenu/gui_circular_progress.c +++ b/gfxmenu/gui_circular_progress.c @@ -140,11 +140,15 @@ circprog_paint (void *vself, const grub_video_rect_t *region) center_width, center_height); int radius = width / 2 - tick_width / 2 - 1; - int nticks = (self->num_ticks - * (self->value - self->start) - / (self->end - self->start)); + int nticks; int tick_begin; int tick_end; + if (self->end == self->start) + nticks = 0; + else + nticks = (self->num_ticks + * (self->value - self->start) + / (self->end - self->start)); /* Do ticks appear or disappear as the value approached the end? */ if (self->ticks_disappear) { diff --git a/gfxmenu/gui_list.c b/gfxmenu/gui_list.c index bf6d94657..68f19a3a6 100644 --- a/gfxmenu/gui_list.c +++ b/gfxmenu/gui_list.c @@ -67,7 +67,8 @@ struct grub_gui_list_impl grub_gfxmenu_box_t selected_item_box; grub_gfxmenu_icon_manager_t icon_manager; - grub_gfxmenu_model_t menu; + + grub_gfxmenu_view_t view; }; typedef struct grub_gui_list_impl *list_impl_t; @@ -93,7 +94,7 @@ list_destroy (void *vself) static int get_num_shown_items (list_impl_t self) { - int n = grub_gfxmenu_model_get_num_entries (self->menu); + int n = self->view->menu->size; if (self->min_items_shown != -1 && n < self->min_items_shown) n = self->min_items_shown; if (self->max_items_shown != -1 && n > self->max_items_shown) @@ -157,7 +158,7 @@ static struct grub_video_bitmap * get_item_icon (list_impl_t self, int item_index) { grub_menu_entry_t entry; - entry = grub_gfxmenu_model_get_entry (self->menu, item_index); + entry = grub_menu_get_entry (self->view->menu, item_index); if (! entry) return 0; @@ -167,7 +168,7 @@ get_item_icon (list_impl_t self, int item_index) static void make_selected_item_visible (list_impl_t self) { - int selected_index = grub_gfxmenu_model_get_selected_index (self->menu); + int selected_index = self->view->selected; if (selected_index < 0) return; /* No item is selected. */ int num_shown_items = get_num_shown_items (self); @@ -222,7 +223,7 @@ draw_menu (list_impl_t self) int descent = grub_font_get_descent (self->item_font); int item_height = self->item_height; - int total_num_items = grub_gfxmenu_model_get_num_entries (self->menu); + int total_num_items = self->view->menu->size; int num_shown_items = get_num_shown_items (self); grub_gfxmenu_box_t box = self->menu_box; int width = self->bounds.width; @@ -256,8 +257,7 @@ draw_menu (list_impl_t self) visible_index < num_shown_items && menu_index < total_num_items; visible_index++, menu_index++) { - int is_selected = - (menu_index == grub_gfxmenu_model_get_selected_index (self->menu)); + int is_selected = (menu_index == self->view->selected); if (is_selected) { @@ -282,7 +282,7 @@ draw_menu (list_impl_t self) 0, 0, self->icon_width, self->icon_height); const char *item_title = - grub_gfxmenu_model_get_entry_title (self->menu, menu_index); + grub_menu_get_entry (self->view->menu, menu_index)->title; grub_font_t font = (is_selected && self->selected_item_font ? self->selected_item_font @@ -530,12 +530,12 @@ list_set_property (void *vself, const char *name, const char *value) /* Set necessary information that the gfxmenu view provides. */ static void list_set_view_info (void *vself, - const char *theme_path, - grub_gfxmenu_model_t menu) + grub_gfxmenu_view_t view) { list_impl_t self = vself; - grub_gfxmenu_icon_manager_set_theme_path (self->icon_manager, theme_path); - self->menu = menu; + grub_gfxmenu_icon_manager_set_theme_path (self->icon_manager, + view->theme_path); + self->view = view; } static struct grub_gui_list_ops list_ops = diff --git a/gfxmenu/gui_progress_bar.c b/gfxmenu/gui_progress_bar.c index 498711169..c71997812 100644 --- a/gfxmenu/gui_progress_bar.c +++ b/gfxmenu/gui_progress_bar.c @@ -139,11 +139,16 @@ draw_pixmap_bar (grub_gui_progress_bar_t self) int bar_v_pad = bar_t_pad + bar_b_pad; int tracklen = w - bar_h_pad; int trackheight = h - bar_v_pad; + int barwidth; + + if (self->end == self->start) + return; + bar->set_content_size (bar, tracklen, trackheight); - int barwidth = (tracklen - * (self->value - self->start) - / (self->end - self->start)); + barwidth = (tracklen * (self->value - self->start) + / (self->end - self->start)); + hl->set_content_size (hl, barwidth, h - bar_v_pad); bar->draw (bar, 0, 0); @@ -174,12 +179,13 @@ static void progress_bar_paint (void *vself, const grub_video_rect_t *region) { grub_gui_progress_bar_t self = vself; + grub_video_rect_t vpsave; + if (! self->visible) return; if (!grub_video_have_common_points (region, &self->bounds)) return; - grub_video_rect_t vpsave; grub_gui_set_viewport (&self->bounds, &vpsave); if (check_pixmaps (self)) diff --git a/gfxmenu/model.c b/gfxmenu/model.c index 26490ea1f..e69de29bb 100644 --- a/gfxmenu/model.c +++ b/gfxmenu/model.c @@ -1,191 +0,0 @@ -/* model.c - Graphical menu interface MVC model. */ -/* - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Model type definition. */ -struct grub_gfxmenu_model -{ - grub_menu_t menu; - int num_entries; - grub_menu_entry_t *entries; - int selected_entry_index; - int timeout_set; - grub_uint64_t timeout_start; - grub_uint64_t timeout_at; -}; - - -grub_gfxmenu_model_t -grub_gfxmenu_model_new (grub_menu_t menu) -{ - grub_gfxmenu_model_t model; - - model = grub_malloc (sizeof (*model)); - if (! model) - return 0; - - model->menu = menu; - model->num_entries = menu->size; - model->entries = 0; - model->selected_entry_index = 0; - model->timeout_set = 0; - model->timeout_at = 0; - if (model->num_entries > 0) - { - model->entries = grub_malloc (model->num_entries - * sizeof (*model->entries)); - if (! model->entries) - goto fail_and_free; - - int i; - grub_menu_entry_t cur; - for (i = 0, cur = menu->entry_list; - i < model->num_entries; - i++, cur = cur->next) - { - model->entries[i] = cur; - } - } - - return model; - -fail_and_free: - grub_free (model->entries); - grub_free (model); - return 0; -} - -void -grub_gfxmenu_model_destroy (grub_gfxmenu_model_t model) -{ - if (! model) - return; - - grub_free (model->entries); - model->entries = 0; - - grub_free (model); -} - -grub_menu_t -grub_gfxmenu_model_get_menu (grub_gfxmenu_model_t model) -{ - return model->menu; -} - -void -grub_gfxmenu_model_set_timeout (grub_gfxmenu_model_t model) -{ - int timeout_sec = grub_menu_get_timeout (); - if (timeout_sec >= 0) - { - model->timeout_start = grub_get_time_ms (); - model->timeout_at = model->timeout_start + timeout_sec * 1000; - model->timeout_set = 1; - } - else - { - model->timeout_set = 0; - } -} - -void -grub_gfxmenu_model_clear_timeout (grub_gfxmenu_model_t model) -{ - model->timeout_set = 0; - grub_menu_set_timeout (-1); -} - -int -grub_gfxmenu_model_get_timeout_ms (grub_gfxmenu_model_t model) -{ - if (!model->timeout_set) - return -1; - - return model->timeout_at - model->timeout_start; -} - -int -grub_gfxmenu_model_get_timeout_remaining_ms (grub_gfxmenu_model_t model) -{ - if (!model->timeout_set) - return -1; - - return model->timeout_at - grub_get_time_ms (); -} - -int -grub_gfxmenu_model_timeout_expired (grub_gfxmenu_model_t model) -{ - if (model->timeout_set - && grub_get_time_ms () >= model->timeout_at) - return 1; - - return 0; -} - -int -grub_gfxmenu_model_get_num_entries (grub_gfxmenu_model_t model) -{ - return model->num_entries; -} - -int -grub_gfxmenu_model_get_selected_index (grub_gfxmenu_model_t model) -{ - return model->selected_entry_index; -} - -void -grub_gfxmenu_model_set_selected_index (grub_gfxmenu_model_t model, int index) -{ - model->selected_entry_index = index; -} - -const char * -grub_gfxmenu_model_get_entry_title (grub_gfxmenu_model_t model, int index) -{ - if (index < 0 || index >= model->num_entries) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid menu index"); - return 0; - } - - return model->entries[index]->title; -} - -grub_menu_entry_t -grub_gfxmenu_model_get_entry (grub_gfxmenu_model_t model, int index) -{ - if (index < 0 || index >= model->num_entries) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid menu index"); - return 0; - } - - return model->entries[index]; -} diff --git a/gfxmenu/view.c b/gfxmenu/view.c index 7d9bb1cd0..882469447 100644 --- a/gfxmenu/view.c +++ b/gfxmenu/view.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -35,24 +34,25 @@ #include #include #include -#include +#include #include /* The component ID identifying GUI components to be updated as the timeout status changes. */ #define TIMEOUT_COMPONENT_ID "__timeout__" +#if 0 static grub_gfxmenu_view_t term_view; +#endif -static void init_terminal (grub_gfxmenu_view_t view); -static void destroy_terminal (void); static grub_err_t set_graphics_mode (void); static grub_err_t set_text_mode (void); /* Create a new view object, loading the theme specified by THEME_PATH and associating MODEL with the view. */ grub_gfxmenu_view_t -grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model) +grub_gfxmenu_view_new (const char *theme_path, grub_menu_t menu, int entry, + int nested) { grub_gfxmenu_view_t view; grub_err_t err; @@ -96,8 +96,11 @@ grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model) default_fg_color = grub_gui_color_rgb (0, 0, 0); default_bg_color = grub_gui_color_rgb (255, 255, 255); - view->model = model; view->canvas = 0; + view->selected = entry; + view->menu = menu; + view->nested = nested; + view->first_timeout = -1; view->title_font = default_font; view->message_font = default_font; @@ -111,7 +114,6 @@ grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model) view->title_text = grub_strdup ("GRUB Boot Menu"); view->progress_message_text = 0; view->theme_path = 0; - view->last_seconds_remaining = -2; /* Set the timeout bar's frame. */ view->progress_message_frame.width = view->screen.width * 4 / 5; @@ -127,7 +129,9 @@ grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model) return 0; } +#if 0 init_terminal (view); +#endif return view; } @@ -148,9 +152,12 @@ grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view) grub_free (view); set_text_mode (); +#if 0 destroy_terminal (); +#endif } +#if 0 /* Sets MESSAGE as the progress message for the view. MESSAGE can be 0, in which case no message is displayed. */ static void @@ -162,6 +169,7 @@ set_progress_message (grub_gfxmenu_view_t view, const char *message) else view->progress_message_text = 0; } +#endif static void redraw_background (grub_gfxmenu_view_t view, @@ -224,18 +232,15 @@ update_timeout_visit (grub_gui_component_t component, component->ops->set_property (component, "text", pv->text); } - -static inline void -update_timeout (grub_gfxmenu_view_t view, int is_init) +void +grub_gfxmenu_print_timeout (int timeout, void *data) { - char startbuf[20]; - char valuebuf[20]; + char valuebuf[sizeof ("-XXXXXXXXXXX")]; + char startbuf[sizeof ("-XXXXXXXXXXX")]; char msgbuf[120]; + struct grub_gfxmenu_view *view = data; - int timeout; - int remaining; struct progress_value_data pv; - int seconds_remaining_rounded_up; auto void redraw_timeout_visit (grub_gui_component_t component, void *userdata __attribute__ ((unused))); @@ -248,52 +253,62 @@ update_timeout (grub_gfxmenu_view_t view, int is_init) grub_gfxmenu_view_redraw (view, &bounds); } - timeout = grub_gfxmenu_model_get_timeout_ms (view->model); - if (timeout > 0) - { - remaining = grub_gfxmenu_model_get_timeout_remaining_ms (view->model); - seconds_remaining_rounded_up = (remaining + 999) / 1000; - } - else - { - seconds_remaining_rounded_up = -1; - remaining = -1; - } + if (view->first_timeout == -1) + view->first_timeout = timeout; - if (view->last_seconds_remaining == seconds_remaining_rounded_up && !is_init) - return; - - view->last_seconds_remaining = seconds_remaining_rounded_up; - - pv.visible = timeout > 0 ? "true" : "false"; - grub_sprintf (startbuf, "%d", -timeout); + pv.visible = "true"; + grub_sprintf (startbuf, "%d", -(view->first_timeout + 1)); pv.start = startbuf; pv.end = "0"; - grub_sprintf (valuebuf, "%d", remaining > 0 ? -remaining : 0); + grub_sprintf (valuebuf, "%d", -timeout); pv.value = valuebuf; grub_sprintf (msgbuf, "The highlighted entry will be booted automatically in %d s.", - seconds_remaining_rounded_up); + timeout); pv.text = msgbuf; grub_gui_find_by_id ((grub_gui_component_t) view->canvas, TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv); - if (!is_init) - { - grub_gui_find_by_id ((grub_gui_component_t) view->canvas, - TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv); - grub_video_swap_buffers (); - if (view->double_repaint) - grub_gui_find_by_id ((grub_gui_component_t) view->canvas, - TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv); - } + grub_gui_find_by_id ((grub_gui_component_t) view->canvas, + TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gui_find_by_id ((grub_gui_component_t) view->canvas, + TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv); } -void -grub_gfxmenu_redraw_timeout (grub_gfxmenu_view_t view) +void +grub_gfxmenu_clear_timeout (void *data) { - update_timeout (view, 0); + struct progress_value_data pv; + struct grub_gfxmenu_view *view = data; + + auto void redraw_timeout_visit (grub_gui_component_t component, + void *userdata __attribute__ ((unused))); + + auto void redraw_timeout_visit (grub_gui_component_t component, + void *userdata __attribute__ ((unused))) + { + grub_video_rect_t bounds; + component->ops->get_bounds (component, &bounds); + grub_gfxmenu_view_redraw (view, &bounds); + } + + pv.visible = "false"; + pv.start = "1"; + pv.end = "0"; + pv.value = "0"; + pv.text = ""; + + grub_gui_find_by_id ((grub_gui_component_t) view->canvas, + TIMEOUT_COMPONENT_ID, update_timeout_visit, &pv); + grub_gui_find_by_id ((grub_gui_component_t) view->canvas, + TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gui_find_by_id ((grub_gui_component_t) view->canvas, + TIMEOUT_COMPONENT_ID, redraw_timeout_visit, &pv); } static void @@ -305,7 +320,7 @@ update_menu_visit (grub_gui_component_t component, if (component->ops->is_instance (component, "list")) { grub_gui_list_t list = (grub_gui_list_t) component; - list->ops->set_view_info (list, view->theme_path, view->model); + list->ops->set_view_info (list, view); } } @@ -361,7 +376,6 @@ grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view) { - update_timeout (view, 1); update_menu_components (view); grub_gfxmenu_view_redraw (view, &view->screen); @@ -402,6 +416,16 @@ grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view) } } +void +grub_gfxmenu_set_chosen_entry (int entry, void *data) +{ + grub_gfxmenu_view_t view = data; + + view->selected = entry; + grub_gfxmenu_redraw_menu (view); +} + + static grub_err_t set_graphics_mode (void) { @@ -417,6 +441,8 @@ set_text_mode (void) return grub_video_restore (); } +/* FIXME */ +#if 0 static int term_target_width; static int term_target_height; static int term_initialized; @@ -487,7 +513,6 @@ static void destroy_terminal (void) grub_term_set_current_output (term_original); } - static void notify_booting (grub_menu_entry_t entry, void *userdata) { @@ -537,59 +562,4 @@ static struct grub_menu_execute_callback execute_callback = .notify_failure = notify_execution_failure }; -int -grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view, - grub_menu_entry_t entry) -{ - draw_terminal_box (view); - - grub_menu_execute_with_fallback (grub_gfxmenu_model_get_menu (view->model), - entry, &execute_callback, (void *) view); - - if (set_graphics_mode () != GRUB_ERR_NONE) - return 0; /* Failure. */ - - /* If we returned, there was a failure. */ - set_progress_message (view, - "Unable to automatically boot. " - "Press SPACE to continue."); - grub_gfxmenu_view_draw (view); - while (GRUB_TERM_ASCII_CHAR(grub_getkey ()) != ' ') - { - /* Wait for SPACE to be pressed. */ - } - - set_progress_message (view, 0); /* Clear the message. */ - - grub_gfxmenu_view_redraw (view, &view->progress_message_frame); - grub_video_swap_buffers (); - if (view->double_repaint) - grub_gfxmenu_view_redraw (view, &view->progress_message_frame); - - return 1; /* Ok. */ -} - -int -grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view, - grub_menu_entry_t entry) -{ - draw_terminal_box (view); - - grub_menu_execute_entry (entry); - if (grub_errno != GRUB_ERR_NONE) - grub_wait_after_message (); - - if (set_graphics_mode () != GRUB_ERR_NONE) - return 0; /* Failure. */ - - grub_gfxmenu_view_draw (view); - return 1; /* Ok. */ -} - -void -grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view) -{ - draw_terminal_box (view); - grub_cmdline_run (1); - grub_gfxmenu_view_draw (view); -} +#endif diff --git a/include/grub/auth.h b/include/grub/auth.h index 823442941..747334451 100644 --- a/include/grub/auth.h +++ b/include/grub/auth.h @@ -15,24 +15,15 @@ * You should have received a copy of the GNU General Public License * along with GRUB. If not, see . */ -#ifndef GRUB_AURH_HEADER +#ifndef GRUB_AUTH_HEADER #define GRUB_AUTH_HEADER 1 #include -#include +#include -/* Macros for indistinguishibility. */ -#define GRUB_ACCESS_DENIED grub_error (GRUB_ERR_ACCESS_DENIED, "Access denied.") -#define GRUB_GET_PASSWORD(string, len) grub_cmdline_get (N_("Enter password:"), \ - string, len, \ - '*', 0, 0) +#define GRUB_AUTH_MAX_PASSLEN 1024 -/* Like strcmp but untimeable. Accepts NULL as second argument. */ -int grub_auth_strcmp (const char *user_input, const char *template); -/* Like strcmp but untimeable and ignores commas in needle. */ -int grub_auth_strword (const char *haystack, const char *needle); - -typedef grub_err_t (*grub_auth_callback_t) (const char*, void *); +typedef grub_err_t (*grub_auth_callback_t) (const char *, const char *, void *); grub_err_t grub_auth_register_authentication (const char *user, grub_auth_callback_t callback, diff --git a/include/grub/charset.h b/include/grub/charset.h index f85862f8b..fc050da24 100644 --- a/include/grub/charset.h +++ b/include/grub/charset.h @@ -109,4 +109,13 @@ grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src, return dest; } +/* Convert UCS-4 to UTF-8. */ +char *grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size); + +int +grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize); + +int grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, + grub_uint32_t **last_position); + #endif diff --git a/include/grub/crypto.h b/include/grub/crypto.h new file mode 100644 index 000000000..48b52ee65 --- /dev/null +++ b/include/grub/crypto.h @@ -0,0 +1,275 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 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 . + */ + +/* Contains elements based on gcrypt-module.h and gcrypt.h.in. + If it's changed please update this file. */ + +#ifndef GRUB_CRYPTO_HEADER +#define GRUB_CRYPTO_HEADER 1 + +#include +#include +#include + +typedef enum + { + GPG_ERR_NO_ERROR, + GPG_ERR_BAD_MPI, + GPG_ERR_BAD_SECKEY, + GPG_ERR_BAD_SIGNATURE, + GPG_ERR_CIPHER_ALGO, + GPG_ERR_CONFLICT, + GPG_ERR_DECRYPT_FAILED, + GPG_ERR_DIGEST_ALGO, + GPG_ERR_GENERAL, + GPG_ERR_INTERNAL, + GPG_ERR_INV_ARG, + GPG_ERR_INV_CIPHER_MODE, + GPG_ERR_INV_FLAG, + GPG_ERR_INV_KEYLEN, + GPG_ERR_INV_OBJ, + GPG_ERR_INV_OP, + GPG_ERR_INV_SEXP, + GPG_ERR_INV_VALUE, + GPG_ERR_MISSING_VALUE, + GPG_ERR_NO_ENCRYPTION_SCHEME, + GPG_ERR_NO_OBJ, + GPG_ERR_NO_PRIME, + GPG_ERR_NO_SIGNATURE_SCHEME, + GPG_ERR_NOT_FOUND, + GPG_ERR_NOT_IMPLEMENTED, + GPG_ERR_NOT_SUPPORTED, + GPG_ERROR_CFLAGS, + GPG_ERR_PUBKEY_ALGO, + GPG_ERR_SELFTEST_FAILED, + GPG_ERR_TOO_SHORT, + GPG_ERR_UNSUPPORTED, + GPG_ERR_WEAK_KEY, + GPG_ERR_WRONG_KEY_USAGE, + GPG_ERR_WRONG_PUBKEY_ALGO, + GPG_ERR_OUT_OF_MEMORY + } gcry_err_code_t; +#define gpg_err_code_t gcry_err_code_t +#define gpg_error_t gcry_err_code_t + +enum gcry_cipher_modes + { + GCRY_CIPHER_MODE_NONE = 0, /* Not yet specified. */ + GCRY_CIPHER_MODE_ECB = 1, /* Electronic codebook. */ + GCRY_CIPHER_MODE_CFB = 2, /* Cipher feedback. */ + GCRY_CIPHER_MODE_CBC = 3, /* Cipher block chaining. */ + GCRY_CIPHER_MODE_STREAM = 4, /* Used with stream ciphers. */ + GCRY_CIPHER_MODE_OFB = 5, /* Outer feedback. */ + GCRY_CIPHER_MODE_CTR = 6 /* Counter. */ + }; + +/* Type for the cipher_setkey function. */ +typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c, + const unsigned char *key, + unsigned keylen); + +/* Type for the cipher_encrypt function. */ +typedef void (*gcry_cipher_encrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf); + +/* Type for the cipher_decrypt function. */ +typedef void (*gcry_cipher_decrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf); + +/* Type for the cipher_stencrypt function. */ +typedef void (*gcry_cipher_stencrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf, + unsigned int n); + +/* Type for the cipher_stdecrypt function. */ +typedef void (*gcry_cipher_stdecrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf, + unsigned int n); + +typedef struct gcry_cipher_oid_spec +{ + const char *oid; + int mode; +} gcry_cipher_oid_spec_t; + +/* Module specification structure for ciphers. */ +typedef struct gcry_cipher_spec +{ + const char *name; + const char **aliases; + gcry_cipher_oid_spec_t *oids; + grub_size_t blocksize; + grub_size_t keylen; + grub_size_t contextsize; + gcry_cipher_setkey_t setkey; + gcry_cipher_encrypt_t encrypt; + gcry_cipher_decrypt_t decrypt; + gcry_cipher_stencrypt_t stencrypt; + gcry_cipher_stdecrypt_t stdecrypt; + struct gcry_cipher_spec *next; +} gcry_cipher_spec_t; + +/* Type for the md_init function. */ +typedef void (*gcry_md_init_t) (void *c); + +/* Type for the md_write function. */ +typedef void (*gcry_md_write_t) (void *c, const void *buf, grub_size_t nbytes); + +/* Type for the md_final function. */ +typedef void (*gcry_md_final_t) (void *c); + +/* Type for the md_read function. */ +typedef unsigned char *(*gcry_md_read_t) (void *c); + +typedef struct gcry_md_oid_spec +{ + const char *oidstring; +} gcry_md_oid_spec_t; + +/* Module specification structure for message digests. */ +typedef struct gcry_md_spec +{ + const char *name; + unsigned char *asnoid; + int asnlen; + gcry_md_oid_spec_t *oids; + grub_size_t mdlen; + gcry_md_init_t init; + gcry_md_write_t write; + gcry_md_final_t final; + gcry_md_read_t read; + grub_size_t contextsize; /* allocate this amount of context */ + /* Block size, needed for HMAC. */ + grub_size_t blocksize; + struct gcry_md_spec *next; +} gcry_md_spec_t; + +struct grub_crypto_cipher_handle +{ + const struct gcry_cipher_spec *cipher; + char ctx[0]; +}; + +typedef struct grub_crypto_cipher_handle *grub_crypto_cipher_handle_t; + +struct grub_crypto_hmac_handle; + +const gcry_cipher_spec_t * +grub_crypto_lookup_cipher_by_name (const char *name); + +grub_crypto_cipher_handle_t +grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher); + +gcry_err_code_t +grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, + const unsigned char *key, + unsigned keylen); + +void +grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher); + +void +grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size); + +gcry_err_code_t +grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size); + +gcry_err_code_t +grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size); +gcry_err_code_t +grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv_in); +gcry_err_code_t +grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv); +void +grub_cipher_register (gcry_cipher_spec_t *cipher); +void +grub_cipher_unregister (gcry_cipher_spec_t *cipher); +void +grub_md_register (gcry_md_spec_t *digest); +void +grub_md_unregister (gcry_md_spec_t *cipher); +void +grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, + grub_size_t inlen); +const gcry_md_spec_t * +grub_crypto_lookup_md_by_name (const char *name); + +grub_err_t +grub_crypto_gcry_error (gcry_err_code_t in); + +void grub_burn_stack (grub_size_t size); + +struct grub_crypto_hmac_handle * +grub_crypto_hmac_init (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen); +void +grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, void *data, + grub_size_t datalen); +gcry_err_code_t +grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out); + +gcry_err_code_t +grub_crypto_hmac_buffer (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen, + void *data, grub_size_t datalen, void *out); + +extern gcry_md_spec_t _gcry_digest_spec_md5; +extern gcry_md_spec_t _gcry_digest_spec_sha1; +extern gcry_md_spec_t _gcry_digest_spec_sha256; +extern gcry_md_spec_t _gcry_digest_spec_sha512; +#define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) +#define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1) +#define GRUB_MD_SHA256 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha256) +#define GRUB_MD_SHA512 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha512) + +/* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant + of digest supplied by MD. Inputs are the password P of length PLEN, + the salt S of length SLEN, the iteration counter C (> 0), and the + desired derived output length DKLEN. Output buffer is DK which + must have room for at least DKLEN octets. The output buffer will + be filled with the derived data. */ +gcry_err_code_t +grub_crypto_pbkdf2 (const struct gcry_md_spec *md, + const grub_uint8_t *P, grub_size_t Plen, + const grub_uint8_t *S, grub_size_t Slen, + unsigned int c, + grub_uint8_t *DK, grub_size_t dkLen); + +int +grub_crypto_memcmp (const void *a, const void *b, grub_size_t n); + +int +grub_password_get (char buf[], unsigned buf_size); + +/* For indistinguishibility. */ +#define GRUB_ACCESS_DENIED grub_error (GRUB_ERR_ACCESS_DENIED, "Access denied.") + +extern void (*grub_crypto_autoload_hook) (const char *name); + +#endif diff --git a/include/grub/disk.h b/include/grub/disk.h index de71bb588..cc801bc67 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -42,6 +42,7 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_PXE_ID, GRUB_DISK_DEVICE_SCSI_ID, GRUB_DISK_DEVICE_FILE_ID, + GRUB_DISK_DEVICE_LUKS_ID }; struct grub_disk; diff --git a/include/grub/gfxmenu_model.h b/include/grub/gfxmenu_model.h index e5c7da3ac..8b1378917 100644 --- a/include/grub/gfxmenu_model.h +++ b/include/grub/gfxmenu_model.h @@ -1,59 +1 @@ -/* gfxmenu_model.h - gfxmenu model interface. */ -/* - * 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 . - */ - -#ifndef GRUB_GFXMENU_MODEL_HEADER -#define GRUB_GFXMENU_MODEL_HEADER 1 - -#include - -struct grub_gfxmenu_model; /* Forward declaration of opaque type. */ -typedef struct grub_gfxmenu_model *grub_gfxmenu_model_t; - - -grub_gfxmenu_model_t grub_gfxmenu_model_new (grub_menu_t menu); - -void grub_gfxmenu_model_destroy (grub_gfxmenu_model_t model); - -grub_menu_t grub_gfxmenu_model_get_menu (grub_gfxmenu_model_t model); - -void grub_gfxmenu_model_set_timeout (grub_gfxmenu_model_t model); - -void grub_gfxmenu_model_clear_timeout (grub_gfxmenu_model_t model); - -int grub_gfxmenu_model_get_timeout_ms (grub_gfxmenu_model_t model); - -int grub_gfxmenu_model_get_timeout_remaining_ms (grub_gfxmenu_model_t model); - -int grub_gfxmenu_model_timeout_expired (grub_gfxmenu_model_t model); - -int grub_gfxmenu_model_get_num_entries (grub_gfxmenu_model_t model); - -int grub_gfxmenu_model_get_selected_index (grub_gfxmenu_model_t model); - -void grub_gfxmenu_model_set_selected_index (grub_gfxmenu_model_t model, - int index); - -const char *grub_gfxmenu_model_get_entry_title (grub_gfxmenu_model_t model, - int index); - -grub_menu_entry_t grub_gfxmenu_model_get_entry (grub_gfxmenu_model_t model, - int index); - -#endif /* GRUB_GFXMENU_MODEL_HEADER */ diff --git a/include/grub/gfxmenu_view.h b/include/grub/gfxmenu_view.h index c86334400..92cedc6a7 100644 --- a/include/grub/gfxmenu_view.h +++ b/include/grub/gfxmenu_view.h @@ -24,7 +24,6 @@ #include #include #include -#include #include struct grub_gfxmenu_view; /* Forward declaration of opaque type. */ @@ -32,7 +31,8 @@ typedef struct grub_gfxmenu_view *grub_gfxmenu_view_t; grub_gfxmenu_view_t grub_gfxmenu_view_new (const char *theme_path, - grub_gfxmenu_model_t model); + grub_menu_t menu, int entry, + int nested); void grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view); @@ -64,6 +64,13 @@ void grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, const grub_video_rect_t *region); +void +grub_gfxmenu_clear_timeout (void *data); +void +grub_gfxmenu_print_timeout (int timeout, void *data); +void +grub_gfxmenu_set_chosen_entry (int entry, void *data); + /* Implementation details -- this should not be used outside of the view itself. */ @@ -93,13 +100,17 @@ struct grub_gfxmenu_view grub_gui_container_t canvas; - grub_gfxmenu_model_t model; - - int last_seconds_remaining; - int double_repaint; + int selected; + grub_video_rect_t progress_message_frame; + + grub_menu_t menu; + + int nested; + + int first_timeout; }; #endif /* ! GRUB_GFXMENU_VIEW_HEADER */ diff --git a/include/grub/gui.h b/include/grub/gui.h index 385c0962b..605242da6 100644 --- a/include/grub/gui.h +++ b/include/grub/gui.h @@ -21,7 +21,7 @@ #include #include #include -#include +#include #ifndef GRUB_GUI_H #define GRUB_GUI_H 1 @@ -73,8 +73,7 @@ struct grub_gui_list_ops { struct grub_gui_component_ops component_ops; void (*set_view_info) (void *self, - const char *theme_path, - grub_gfxmenu_model_t menu); + grub_gfxmenu_view_t view); }; struct grub_gui_component diff --git a/include/grub/menu.h b/include/grub/menu.h index cfe7e7cec..20a1fc47f 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h @@ -83,6 +83,9 @@ typedef struct grub_menu_execute_callback } *grub_menu_execute_callback_t; +extern grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, + int nested); + grub_menu_entry_t grub_menu_get_entry (grub_menu_t menu, int no); int grub_menu_get_timeout (void); diff --git a/include/grub/menu_viewer.h b/include/grub/menu_viewer.h index 211f6e3e9..3821219a3 100644 --- a/include/grub/menu_viewer.h +++ b/include/grub/menu_viewer.h @@ -27,22 +27,18 @@ struct grub_menu_viewer { - /* The menu viewer name. */ - const char *name; - - grub_err_t (*show_menu) (grub_menu_t menu, int nested); - struct grub_menu_viewer *next; + void *data; + void (*set_chosen_entry) (int entry, void *data); + void (*print_timeout) (int timeout, void *data); + void (*clear_timeout) (void *data); + void (*fini) (void *fini); }; -typedef struct grub_menu_viewer *grub_menu_viewer_t; -void grub_menu_viewer_init (void); +void grub_menu_register_viewer (struct grub_menu_viewer *viewer); -void grub_menu_viewer_register (grub_menu_viewer_t viewer); - -grub_err_t grub_menu_viewer_show_menu (grub_menu_t menu, int nested); - -/* Return nonzero iff the menu viewer should clean up and return ASAP. */ -int grub_menu_viewer_should_return (void); +grub_err_t grub_menu_register_viewer_init (void (*callback) (int entry, + grub_menu_t menu, + int nested)); #endif /* GRUB_MENU_VIEWER_HEADER */ diff --git a/include/grub/misc.h b/include/grub/misc.h index 786ea5c4f..4accd061f 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -232,11 +232,11 @@ int EXPORT_FUNC(grub_sprintf) (char *str, const char *fmt, ...) __attribute__ (( int EXPORT_FUNC(grub_vsprintf) (char *str, const char *fmt, va_list args); void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn)); -grub_ssize_t EXPORT_FUNC(grub_utf8_to_ucs4) (grub_uint32_t *dest, - grub_size_t destsize, - const grub_uint8_t *src, - grub_size_t srcsize, - const grub_uint8_t **srcend); +grub_size_t EXPORT_FUNC(grub_utf8_to_ucs4) (grub_uint32_t *dest, + grub_size_t destsize, + const grub_uint8_t *src, + grub_size_t srcsize, + const grub_uint8_t **srcend); grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r); diff --git a/include/grub/normal.h b/include/grub/normal.h index e55553de5..58b2c7966 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -20,6 +20,7 @@ #ifndef GRUB_NORMAL_HEADER #define GRUB_NORMAL_HEADER 1 +#include #include #include #include @@ -45,21 +46,21 @@ enum grub_completion_type typedef enum grub_completion_type grub_completion_type_t; extern struct grub_menu_viewer grub_normal_text_menu_viewer; - +extern int grub_normal_exit_level; /* Defined in `main.c'. */ void grub_enter_normal_mode (const char *config); void grub_normal_execute (const char *config, int nested, int batch); -void grub_normal_init_page (void); -void grub_menu_init_page (int nested, int edit); +void grub_menu_init_page (int nested, int edit, + struct grub_term_output *term); +void grub_normal_init_page (struct grub_term_output *term); grub_err_t grub_normal_add_menu_entry (int argc, const char **args, const char *sourcecode); char *grub_file_getline (grub_file_t file); void grub_cmdline_run (int nested); /* Defined in `cmdline.c'. */ -int grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, - int echo_char, int readline, int history); +char *grub_cmdline_get (const char *prompt); grub_err_t grub_set_history (int newsize); /* Defined in `completion.c'. */ @@ -76,14 +77,19 @@ void grub_parse_color_name_pair (grub_uint8_t *ret, const char *name); /* Defined in `menu_text.c'. */ void grub_wait_after_message (void); -int grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, - grub_uint32_t **last_position); 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); grub_ssize_t grub_getstringwidth (grub_uint32_t * str, - const grub_uint32_t * last_position); + const grub_uint32_t * last_position, + struct grub_term_output *term); void grub_print_message_indented (const char *msg, int margin_left, - int margin_right); + int margin_right, + struct grub_term_output *term); +void +grub_menu_text_register_instances (int entry, grub_menu_t menu, int nested); +grub_err_t +grub_show_menu (grub_menu_t menu, int nested); /* Defined in `handler.c'. */ void read_handler_list (void); @@ -95,6 +101,11 @@ void read_command_list (void); /* Defined in `autofs.c'. */ void read_fs_list (void); +void read_crypto_list (void); + +void read_terminal_list (void); + +void grub_set_more (int onoff); #ifdef GRUB_UTIL void grub_normal_init (void); diff --git a/include/grub/parser.h b/include/grub/parser.h index 41f768bba..17f0c4303 100644 --- a/include/grub/parser.h +++ b/include/grub/parser.h @@ -22,6 +22,7 @@ #include #include +#include #include /* All the states for the command line. */ diff --git a/include/grub/reader.h b/include/grub/reader.h index c7e67bf5e..fd72a3252 100644 --- a/include/grub/reader.h +++ b/include/grub/reader.h @@ -20,60 +20,10 @@ #ifndef GRUB_READER_HEADER #define GRUB_READER_HEADER 1 -#include #include -#include typedef grub_err_t (*grub_reader_getline_t) (char **, int); -struct grub_reader -{ - /* The next reader. */ - struct grub_parser *next; - - /* The reader name. */ - const char *name; - - /* Initialize the reader. */ - grub_err_t (*init) (void); - - /* Clean up the reader. */ - grub_err_t (*fini) (void); - - grub_reader_getline_t read_line; -}; -typedef struct grub_reader *grub_reader_t; - -extern struct grub_handler_class EXPORT_VAR(grub_reader_class); - -grub_err_t EXPORT_FUNC(grub_reader_loop) (grub_reader_getline_t getline); - -static inline void -grub_reader_register (const char *name __attribute__ ((unused)), - grub_reader_t reader) -{ - grub_handler_register (&grub_reader_class, GRUB_AS_HANDLER (reader)); -} - -static inline void -grub_reader_unregister (grub_reader_t reader) -{ - grub_handler_unregister (&grub_reader_class, GRUB_AS_HANDLER (reader)); -} - -static inline grub_reader_t -grub_reader_get_current (void) -{ - return (grub_reader_t) grub_reader_class.cur_handler; -} - -static inline grub_err_t -grub_reader_set_current (grub_reader_t reader) -{ - return grub_handler_set_current (&grub_reader_class, - GRUB_AS_HANDLER (reader)); -} - -void grub_register_rescue_reader (void); +void grub_rescue_run (void); #endif /* ! GRUB_READER_HEADER */ diff --git a/include/grub/term.h b/include/grub/term.h index 20b85d1cd..922ccb2d2 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -68,8 +68,6 @@ grub_term_color_state; #define GRUB_TERM_NO_EDIT (1 << 1) /* Set when the terminal cannot do fancy things. */ #define GRUB_TERM_DUMB (1 << 2) -/* Set when the terminal needs to be initialized. */ -#define GRUB_TERM_NEED_INIT (1 << 16) /* Bitmasks for modifier keys returned by grub_getkeystatus. */ @@ -93,10 +91,6 @@ grub_term_color_state; /* Menu-related geometrical constants. */ -/* FIXME: Ugly way to get them form terminal. */ -#define GRUB_TERM_WIDTH ((grub_getwh()&0xFF00)>>8) -#define GRUB_TERM_HEIGHT (grub_getwh()&0xFF) - /* The number of lines of "GRUB version..." at the top. */ #define GRUB_TERM_INFO_HEIGHT 1 @@ -113,37 +107,12 @@ grub_term_color_state; /* The X position of the left border. */ #define GRUB_TERM_LEFT_BORDER_X GRUB_TERM_MARGIN -/* The width of the border. */ -#define GRUB_TERM_BORDER_WIDTH (GRUB_TERM_WIDTH \ - - GRUB_TERM_MARGIN * 3 \ - - GRUB_TERM_SCROLL_WIDTH) - /* The number of lines of messages at the bottom. */ #define GRUB_TERM_MESSAGE_HEIGHT 8 -/* The height of the border. */ -#define GRUB_TERM_BORDER_HEIGHT (GRUB_TERM_HEIGHT \ - - GRUB_TERM_TOP_BORDER_Y \ - - GRUB_TERM_MESSAGE_HEIGHT) - -/* The number of entries shown at a time. */ -#define GRUB_TERM_NUM_ENTRIES (GRUB_TERM_BORDER_HEIGHT - 2) - /* The Y position of the first entry. */ #define GRUB_TERM_FIRST_ENTRY_Y (GRUB_TERM_TOP_BORDER_Y + 1) -/* The max column number of an entry. The last "-1" is for a - continuation marker. */ -#define GRUB_TERM_ENTRY_WIDTH (GRUB_TERM_BORDER_WIDTH - 2 \ - - GRUB_TERM_MARGIN * 2 - 1) - -/* The standard X position of the cursor. */ -#define GRUB_TERM_CURSOR_X (GRUB_TERM_LEFT_BORDER_X \ - + GRUB_TERM_BORDER_WIDTH \ - - GRUB_TERM_MARGIN \ - - 1) - - struct grub_term_input { /* The next terminal. */ @@ -224,80 +193,217 @@ struct grub_term_output }; typedef struct grub_term_output *grub_term_output_t; -extern struct grub_handler_class EXPORT_VAR(grub_term_input_class); -extern struct grub_handler_class EXPORT_VAR(grub_term_output_class); +extern struct grub_term_output *EXPORT_VAR(grub_term_outputs_disabled); +extern struct grub_term_input *EXPORT_VAR(grub_term_inputs_disabled); +extern struct grub_term_output *EXPORT_VAR(grub_term_outputs); +extern struct grub_term_input *EXPORT_VAR(grub_term_inputs); + +static inline void +grub_term_register_input_active (const char *name __attribute__ ((unused)), + grub_term_input_t term) +{ + if (term->init) + term->init (); + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs), GRUB_AS_LIST (term)); +} static inline void grub_term_register_input (const char *name __attribute__ ((unused)), grub_term_input_t term) { - grub_handler_register (&grub_term_input_class, GRUB_AS_HANDLER (term)); + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); +} + +static inline void +grub_term_register_output_active (const char *name __attribute__ ((unused)), + grub_term_output_t term) +{ + if (term->init) + term->init (); + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs), GRUB_AS_LIST (term)); } static inline void grub_term_register_output (const char *name __attribute__ ((unused)), grub_term_output_t term) { - grub_handler_register (&grub_term_output_class, GRUB_AS_HANDLER (term)); + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs_disabled), + GRUB_AS_LIST (term)); } static inline void grub_term_unregister_input (grub_term_input_t term) { - grub_handler_unregister (&grub_term_input_class, GRUB_AS_HANDLER (term)); + grub_list_remove (GRUB_AS_LIST_P (&grub_term_inputs), GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); } static inline void grub_term_unregister_output (grub_term_output_t term) { - grub_handler_unregister (&grub_term_output_class, GRUB_AS_HANDLER (term)); + grub_list_remove (GRUB_AS_LIST_P (&grub_term_outputs), GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST_P (&(grub_term_outputs_disabled)), + GRUB_AS_LIST (term)); } -static inline grub_err_t -grub_term_set_current_input (grub_term_input_t term) -{ - return grub_handler_set_current (&grub_term_input_class, - GRUB_AS_HANDLER (term)); -} - -static inline grub_err_t -grub_term_set_current_output (const struct grub_term_output *term) -{ - return grub_handler_set_current (&grub_term_output_class, - GRUB_AS_HANDLER (term)); -} - -static inline grub_term_input_t -grub_term_get_current_input (void) -{ - return (grub_term_input_t) grub_term_input_class.cur_handler; -} - -static inline grub_term_output_t -grub_term_get_current_output (void) -{ - return (grub_term_output_t) grub_term_output_class.cur_handler; -} +#define FOR_ACTIVE_TERM_INPUTS(var) for (var = grub_term_inputs; var; var = var->next) +#define FOR_DISABLED_TERM_INPUTS(var) for (var = grub_term_inputs_disabled; var; var = var->next) +#define FOR_ACTIVE_TERM_OUTPUTS(var) for (var = grub_term_outputs; var; var = var->next) +#define FOR_DISABLED_TERM_OUTPUTS(var) for (var = grub_term_outputs_disabled; var; var = var->next) void EXPORT_FUNC(grub_putchar) (int c); -void EXPORT_FUNC(grub_putcode) (grub_uint32_t code); -grub_ssize_t EXPORT_FUNC(grub_getcharwidth) (grub_uint32_t code); +void EXPORT_FUNC(grub_putcode) (grub_uint32_t code, + struct grub_term_output *term); int EXPORT_FUNC(grub_getkey) (void); int EXPORT_FUNC(grub_checkkey) (void); int EXPORT_FUNC(grub_getkeystatus) (void); -grub_uint16_t EXPORT_FUNC(grub_getwh) (void); -grub_uint16_t EXPORT_FUNC(grub_getxy) (void); -void EXPORT_FUNC(grub_gotoxy) (grub_uint8_t x, grub_uint8_t y); void EXPORT_FUNC(grub_cls) (void); void EXPORT_FUNC(grub_setcolorstate) (grub_term_color_state state); -void EXPORT_FUNC(grub_setcolor) (grub_uint8_t normal_color, - grub_uint8_t highlight_color); -void EXPORT_FUNC(grub_getcolor) (grub_uint8_t *normal_color, - grub_uint8_t *highlight_color); -int EXPORT_FUNC(grub_setcursor) (int on); -int EXPORT_FUNC(grub_getcursor) (void); void EXPORT_FUNC(grub_refresh) (void); -void EXPORT_FUNC(grub_set_more) (int onoff); +void grub_puts_terminal (const char *str, struct grub_term_output *term); +grub_uint16_t *grub_term_save_pos (void); +void grub_term_restore_pos (grub_uint16_t *pos); + +static inline unsigned grub_term_width (struct grub_term_output *term) +{ + return ((term->getwh()&0xFF00)>>8); +} + +static inline unsigned grub_term_height (struct grub_term_output *term) +{ + return (term->getwh()&0xFF); +} + +/* The width of the border. */ +static inline unsigned +grub_term_border_width (struct grub_term_output *term) +{ + return grub_term_width (term) - GRUB_TERM_MARGIN * 3 - GRUB_TERM_SCROLL_WIDTH; +} + +/* The max column number of an entry. The last "-1" is for a + continuation marker. */ +static inline int +grub_term_entry_width (struct grub_term_output *term) +{ + return grub_term_border_width (term) - 2 - GRUB_TERM_MARGIN * 2 - 1; +} + +/* The height of the border. */ + +static inline unsigned +grub_term_border_height (struct grub_term_output *term) +{ + return grub_term_height (term) - GRUB_TERM_TOP_BORDER_Y + - GRUB_TERM_MESSAGE_HEIGHT; +} + +/* The number of entries shown at a time. */ +static inline int +grub_term_num_entries (struct grub_term_output *term) +{ + return grub_term_border_height (term) - 2; +} + +static inline int +grub_term_cursor_x (struct grub_term_output *term) +{ + return (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term) + - GRUB_TERM_MARGIN - 1); +} + +static inline grub_uint16_t +grub_term_getxy (struct grub_term_output *term) +{ + return term->getxy (); +} + +static inline void +grub_term_refresh (struct grub_term_output *term) +{ + if (term->refresh) + term->refresh (); +} + +static inline void +grub_term_gotoxy (struct grub_term_output *term, grub_uint8_t x, grub_uint8_t y) +{ + term->gotoxy (x, y); +} + +static inline void +grub_term_setcolorstate (struct grub_term_output *term, + grub_term_color_state state) +{ + if (term->setcolorstate) + term->setcolorstate (state); +} + + /* Set the normal color and the highlight color. The format of each + color is VGA's. */ +static inline void +grub_term_setcolor (struct grub_term_output *term, + grub_uint8_t normal_color, grub_uint8_t highlight_color) +{ + if (term->setcolor) + term->setcolor (normal_color, highlight_color); +} + +/* Turn on/off the cursor. */ +static inline void +grub_term_setcursor (struct grub_term_output *term, int on) +{ + if (term->setcursor) + term->setcursor (on); +} + +static inline void +grub_term_cls (struct grub_term_output *term) +{ + if (term->cls) + (term->cls) (); + else + { + grub_putcode ('\n', term); + grub_term_refresh (term); + } +} + +static inline grub_ssize_t +grub_term_getcharwidth (struct grub_term_output *term, grub_uint32_t c) +{ + if (term->getcharwidth) + return term->getcharwidth (c); + else + return 1; +} + +static inline void +grub_term_getcolor (struct grub_term_output *term, + grub_uint8_t *normal_color, grub_uint8_t *highlight_color) +{ + if (term->getcolor) + term->getcolor (normal_color, highlight_color); + else + { + *normal_color = 0x07; + *highlight_color = 0x07; + } +} + +extern void (*EXPORT_VAR (grub_newline_hook)) (void); + +struct grub_term_autoload +{ + struct grub_term_autoload *next; + char *name; + char *modname; +}; + +extern struct grub_term_autoload *grub_term_input_autoload; +extern struct grub_term_autoload *grub_term_output_autoload; /* For convenience. */ #define GRUB_TERM_ASCII_CHAR(c) ((c) & 0xff) diff --git a/include/grub/terminfo.h b/include/grub/terminfo.h index 1ea741e04..e3a2c170a 100644 --- a/include/grub/terminfo.h +++ b/include/grub/terminfo.h @@ -21,15 +21,17 @@ #include #include +#include char *grub_terminfo_get_current (void); grub_err_t grub_terminfo_set_current (const char *); -void grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y); -void grub_terminfo_cls (void); -void grub_terminfo_reverse_video_on (void); -void grub_terminfo_reverse_video_off (void); -void grub_terminfo_cursor_on (void); -void grub_terminfo_cursor_off (void); +void grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y, + grub_term_output_t oterm); +void grub_terminfo_cls (grub_term_output_t oterm); +void grub_terminfo_reverse_video_on (grub_term_output_t oterm); +void grub_terminfo_reverse_video_off (grub_term_output_t oterm); +void grub_terminfo_cursor_on (grub_term_output_t oterm); +void grub_terminfo_cursor_off (grub_term_output_t oterm); #endif /* ! GRUB_TERMINFO_HEADER */ diff --git a/kern/main.c b/kern/main.c index 9215d55e7..040f89e6d 100644 --- a/kern/main.c +++ b/kern/main.c @@ -169,9 +169,8 @@ grub_main (void) grub_register_core_commands (); grub_register_rescue_parser (); - grub_register_rescue_reader (); grub_load_config (); grub_load_normal_mode (); - grub_reader_loop (0); + grub_rescue_run (); } diff --git a/kern/misc.c b/kern/misc.c index 7a62386d1..da9c3650d 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -878,10 +878,10 @@ grub_sprintf (char *str, const char *fmt, ...) /* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string. Return the number of characters converted. DEST must be able to hold - at least DESTSIZE characters. If an invalid sequence is found, return -1. + at least DESTSIZE characters. If SRCEND is not NULL, then *SRCEND is set to the next byte after the last byte used in SRC. */ -grub_ssize_t +grub_size_t grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, const grub_uint8_t *src, grub_size_t srcsize, const grub_uint8_t **srcend) @@ -903,7 +903,8 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, if ((c & 0xc0) != 0x80) { /* invalid */ - return -1; + code = '?'; + count = 0; } else { @@ -945,7 +946,11 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, code = c & 0x01; } else - return -1; + { + /* invalid */ + code = '?'; + count = 0; + } } if (count == 0) @@ -964,15 +969,14 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, void grub_abort (void) { - if (grub_term_get_current_output ()) + grub_printf ("\nAborted."); + +#ifndef GRUB_UTIL + if (grub_term_inputs) +#endif { - grub_printf ("\nAborted."); - - if (grub_term_get_current_input ()) - { - grub_printf (" Press any key to exit."); - grub_getkey (); - } + grub_printf (" Press any key to exit."); + grub_getkey (); } grub_exit (); diff --git a/kern/reader.c b/kern/reader.c index 271a90f5a..74698d34b 100644 --- a/kern/reader.c +++ b/kern/reader.c @@ -22,28 +22,3 @@ #include #include -struct grub_handler_class grub_reader_class = - { - .name = "reader" - }; - -grub_err_t -grub_reader_loop (grub_reader_getline_t getline) -{ - while (1) - { - char *line; - grub_reader_getline_t func; - - /* Print an error, if any. */ - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - - func = (getline) ? : grub_reader_get_current ()->read_line; - if ((func (&line, 0)) || (! line)) - return grub_errno; - - grub_parser_get_current ()->parse_line (line, func); - grub_free (line); - } -} diff --git a/kern/rescue_reader.c b/kern/rescue_reader.c index 2a06f3fc2..732124b1a 100644 --- a/kern/rescue_reader.c +++ b/kern/rescue_reader.c @@ -19,20 +19,15 @@ #include #include +#include #include #include +#include #define GRUB_RESCUE_BUF_SIZE 256 static char linebuf[GRUB_RESCUE_BUF_SIZE]; -static grub_err_t -grub_rescue_init (void) -{ - grub_printf ("Entering rescue mode...\n"); - return 0; -} - /* Prompt to input a command and read the line. */ static grub_err_t grub_rescue_read_line (char **line, int cont) @@ -74,15 +69,24 @@ grub_rescue_read_line (char **line, int cont) return 0; } -static struct grub_reader grub_rescue_reader = - { - .name = "rescue", - .init = grub_rescue_init, - .read_line = grub_rescue_read_line - }; - void -grub_register_rescue_reader (void) +grub_rescue_run (void) { - grub_reader_register ("rescue", &grub_rescue_reader); + grub_printf ("Entering rescue mode...\n"); + + while (1) + { + char *line; + + /* Print an error, if any. */ + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + + grub_rescue_read_line (&line, 0); + if (! line) + continue; + + grub_parser_get_current ()->parse_line (line, grub_rescue_read_line); + grub_free (line); + } } diff --git a/kern/term.c b/kern/term.c index 8c4e1e339..b973f0b63 100644 --- a/kern/term.c +++ b/kern/term.c @@ -21,79 +21,33 @@ #include #include #include +#include -/* The amount of lines counted by the pager. */ -static int grub_more_lines; +struct grub_term_output *grub_term_outputs_disabled; +struct grub_term_input *grub_term_inputs_disabled; +struct grub_term_output *grub_term_outputs; +struct grub_term_input *grub_term_inputs; -/* If the more pager is active. */ -static int grub_more; - -/* The current cursor state. */ -static int cursor_state = 1; - -struct grub_handler_class grub_term_input_class = - { - .name = "terminal_input" - }; - -struct grub_handler_class grub_term_output_class = - { - .name = "terminal_output" - }; - -#define grub_cur_term_input grub_term_get_current_input () -#define grub_cur_term_output grub_term_get_current_output () +void (*grub_newline_hook) (void) = NULL; /* Put a Unicode character. */ void -grub_putcode (grub_uint32_t code) +grub_putcode (grub_uint32_t code, struct grub_term_output *term) { - int height = grub_getwh () & 255; - - if (code == '\t' && grub_cur_term_output->getxy) + if (code == '\t' && term->getxy) { int n; - n = 8 - ((grub_getxy () >> 8) & 7); + n = 8 - ((term->getxy () >> 8) & 7); while (n--) - grub_putcode (' '); + grub_putcode (' ', term); return; } - (grub_cur_term_output->putchar) (code); - if (code == '\n') - { - grub_putcode ('\r'); - - grub_more_lines++; - - if (grub_more && grub_more_lines == height - 1) - { - char key; - int pos = grub_getxy (); - - /* Show --MORE-- on the lower left side of the screen. */ - grub_gotoxy (1, height - 1); - grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); - grub_printf ("--MORE--"); - grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); - - key = grub_getkey (); - - /* Remove the message. */ - grub_gotoxy (1, height - 1); - grub_printf (" "); - grub_gotoxy (pos >> 8, pos & 0xFF); - - /* Scroll one lines or an entire page, depending on the key. */ - if (key == '\r' || key =='\n') - grub_more_lines--; - else - grub_more_lines = 0; - } - } + (term->putchar) ('\r'); + (term->putchar) (code); } /* Put a character. C is one byte of a UTF-8 stream. @@ -104,137 +58,103 @@ grub_putchar (int c) static grub_size_t size = 0; static grub_uint8_t buf[6]; grub_uint32_t code; - grub_ssize_t ret; + grub_size_t ret; buf[size++] = c; ret = grub_utf8_to_ucs4 (&code, 1, buf, size, 0); - if (ret > 0) + if (ret != 0) { + struct grub_term_output *term; size = 0; - grub_putcode (code); + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_putcode (code, term); + if (code == '\n' && grub_newline_hook) + grub_newline_hook (); } - else if (ret < 0) - { - size = 0; - grub_putcode ('?'); - } -} - -/* Return the number of columns occupied by the character code CODE. */ -grub_ssize_t -grub_getcharwidth (grub_uint32_t code) -{ - return (grub_cur_term_output->getcharwidth) (code); } int grub_getkey (void) { + grub_term_input_t term; + grub_refresh (); - return (grub_cur_term_input->getkey) (); + + while (1) + { + FOR_ACTIVE_TERM_INPUTS(term) + { + int key = term->checkkey (); + if (key != -1) + return term->getkey (); + } + + grub_cpu_idle (); + } } int grub_checkkey (void) { - return (grub_cur_term_input->checkkey) (); + grub_term_input_t term; + + FOR_ACTIVE_TERM_INPUTS(term) + { + int key = term->checkkey (); + if (key != -1) + return key; + } + + return -1; } int grub_getkeystatus (void) { - if (grub_cur_term_input->getkeystatus) - return (grub_cur_term_input->getkeystatus) (); - else - return 0; -} + int status = 0; + grub_term_input_t term; -grub_uint16_t -grub_getxy (void) -{ - return (grub_cur_term_output->getxy) (); -} + FOR_ACTIVE_TERM_INPUTS(term) + { + if (term->getkeystatus) + status |= term->getkeystatus (); + } -grub_uint16_t -grub_getwh (void) -{ - return (grub_cur_term_output->getwh) (); -} - -void -grub_gotoxy (grub_uint8_t x, grub_uint8_t y) -{ - (grub_cur_term_output->gotoxy) (x, y); + return status; } void grub_cls (void) { - if ((grub_cur_term_output->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug"))) - { - grub_putchar ('\n'); - grub_refresh (); - } - else - (grub_cur_term_output->cls) (); + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + if ((term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug"))) + { + grub_putcode ('\n', term); + grub_term_refresh (term); + } + else + (term->cls) (); + } } void grub_setcolorstate (grub_term_color_state state) { - if (grub_cur_term_output->setcolorstate) - (grub_cur_term_output->setcolorstate) (state); -} - -void -grub_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color) -{ - if (grub_cur_term_output->setcolor) - (grub_cur_term_output->setcolor) (normal_color, highlight_color); -} - -void -grub_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color) -{ - if (grub_cur_term_output->getcolor) - (grub_cur_term_output->getcolor) (normal_color, highlight_color); -} - -int -grub_setcursor (int on) -{ - int ret = cursor_state; - - if (grub_cur_term_output->setcursor) - { - (grub_cur_term_output->setcursor) (on); - cursor_state = on; - } - - return ret; -} - -int -grub_getcursor (void) -{ - return cursor_state; + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_term_setcolorstate (term, state); } void grub_refresh (void) { - if (grub_cur_term_output->refresh) - (grub_cur_term_output->refresh) (); -} + struct grub_term_output *term; -void -grub_set_more (int onoff) -{ - if (onoff == 1) - grub_more++; - else - grub_more--; - - grub_more_lines = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_term_refresh (term); } diff --git a/lib/charset.c b/lib/charset.c index 8bc5b9149..f2e1b036d 100644 --- a/lib/charset.c +++ b/lib/charset.c @@ -24,6 +24,8 @@ last byte used in SRC. */ #include +#include +#include grub_ssize_t grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, @@ -114,3 +116,154 @@ grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, *srcend = src; return p - dest; } + +/* Convert UCS-4 to UTF-8. */ +char * +grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size) +{ + grub_size_t remaining; + grub_uint32_t *ptr; + grub_size_t cnt = 0; + grub_uint8_t *ret, *dest; + + remaining = size; + ptr = src; + while (remaining--) + { + grub_uint32_t code = *ptr++; + + if (code <= 0x007F) + cnt++; + else if (code <= 0x07FF) + cnt += 2; + else if ((code >= 0xDC00 && code <= 0xDFFF) + || (code >= 0xD800 && code <= 0xDBFF)) + /* No surrogates in UCS-4... */ + cnt++; + else + cnt += 3; + } + cnt++; + + ret = grub_malloc (cnt); + if (!ret) + return 0; + + dest = ret; + remaining = size; + ptr = src; + while (remaining--) + { + grub_uint32_t code = *ptr++; + + if (code <= 0x007F) + *dest++ = code; + else if (code <= 0x07FF) + { + *dest++ = (code >> 6) | 0xC0; + *dest++ = (code & 0x3F) | 0x80; + } + else if ((code >= 0xDC00 && code <= 0xDFFF) + || (code >= 0xD800 && code <= 0xDBFF)) + { + /* No surrogates in UCS-4... */ + *dest++ = '?'; + } + else + { + *dest++ = (code >> 12) | 0xE0; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } + } + *dest = 0; + + return (char *) ret; +} + +int +grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize) +{ + grub_uint32_t code = 0; + int count = 0; + + while (srcsize) + { + grub_uint32_t c = *src++; + if (srcsize != (grub_size_t)-1) + srcsize--; + if (count) + { + if ((c & 0xc0) != 0x80) + { + /* invalid */ + return 0; + } + else + { + code <<= 6; + code |= (c & 0x3f); + count--; + } + } + else + { + if (c == 0) + break; + + if ((c & 0x80) == 0x00) + code = c; + else if ((c & 0xe0) == 0xc0) + { + count = 1; + code = c & 0x1f; + } + else if ((c & 0xf0) == 0xe0) + { + count = 2; + code = c & 0x0f; + } + else if ((c & 0xf8) == 0xf0) + { + count = 3; + code = c & 0x07; + } + else if ((c & 0xfc) == 0xf8) + { + count = 4; + code = c & 0x03; + } + else if ((c & 0xfe) == 0xfc) + { + count = 5; + code = c & 0x01; + } + else + return 0; + } + } + + return 1; +} + +int +grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, + grub_uint32_t **last_position) +{ + grub_size_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; + + return msg_len; +} diff --git a/lib/crypto.c b/lib/crypto.c new file mode 100644 index 000000000..021560d6c --- /dev/null +++ b/lib/crypto.c @@ -0,0 +1,447 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 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 . + */ + +#include +#include +#include +#include + +struct grub_crypto_hmac_handle +{ + const struct gcry_md_spec *md; + void *ctx; + void *opad; +}; + +static gcry_cipher_spec_t *grub_ciphers = NULL; +static gcry_md_spec_t *grub_digests = NULL; + +void (*grub_crypto_autoload_hook) (const char *name) = NULL; + +/* Based on libgcrypt-1.4.4/src/misc.c. */ +void +grub_burn_stack (grub_size_t size) +{ + char buf[64]; + + grub_memset (buf, 0, sizeof (buf)); + if (size > sizeof (buf)) + grub_burn_stack (size - sizeof (buf)); +} + + +void +grub_cipher_register (gcry_cipher_spec_t *cipher) +{ + cipher->next = grub_ciphers; + grub_ciphers = cipher; +} + +void +grub_cipher_unregister (gcry_cipher_spec_t *cipher) +{ + gcry_cipher_spec_t **ciph; + for (ciph = &grub_ciphers; *ciph; ciph = &((*ciph)->next)) + if (*ciph == cipher) + *ciph = (*ciph)->next; +} + +void +grub_md_register (gcry_md_spec_t *digest) +{ + digest->next = grub_digests; + grub_digests = digest; +} + +void +grub_md_unregister (gcry_md_spec_t *cipher) +{ + gcry_md_spec_t **ciph; + for (ciph = &grub_digests; *ciph; ciph = &((*ciph)->next)) + if (*ciph == cipher) + *ciph = (*ciph)->next; +} + +void +grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, + grub_size_t inlen) +{ + grub_uint8_t ctx[hash->contextsize]; + hash->init (&ctx); + hash->write (&ctx, in, inlen); + hash->final (&ctx); + grub_memcpy (out, hash->read (&ctx), hash->mdlen); +} + +const gcry_md_spec_t * +grub_crypto_lookup_md_by_name (const char *name) +{ + const gcry_md_spec_t *md; + int first = 1; + while (1) + { + for (md = grub_digests; md; md = md->next) + if (grub_strcasecmp (name, md->name) == 0) + return md; + if (grub_crypto_autoload_hook && first) + grub_crypto_autoload_hook (name); + else + return NULL; + first = 0; + } +} + +const gcry_cipher_spec_t * +grub_crypto_lookup_cipher_by_name (const char *name) +{ + const gcry_cipher_spec_t *ciph; + int first = 1; + while (1) + { + for (ciph = grub_ciphers; ciph; ciph = ciph->next) + { + const char **alias; + if (grub_strcasecmp (name, ciph->name) == 0) + return ciph; + if (!ciph->aliases) + continue; + for (alias = ciph->aliases; *alias; alias++) + if (grub_strcasecmp (name, *alias) == 0) + return ciph; + } + if (grub_crypto_autoload_hook && first) + grub_crypto_autoload_hook (name); + else + return NULL; + first = 0; + } +} + + +grub_crypto_cipher_handle_t +grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher) +{ + grub_crypto_cipher_handle_t ret; + ret = grub_malloc (sizeof (*ret) + cipher->contextsize); + if (!ret) + return NULL; + ret->cipher = cipher; + return ret; +} + +gcry_err_code_t +grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, + const unsigned char *key, + unsigned keylen) +{ + return cipher->cipher->setkey (cipher->ctx, key, keylen); +} + + +void +grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher) +{ + grub_free (cipher); +} + + +void +grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size) +{ + const grub_uint8_t *in1ptr = in1, *in2ptr = in2; + grub_uint8_t *outptr = out; + while (size--) + { + *outptr = *in1ptr ^ *in2ptr; + in1ptr++; + in2ptr++; + outptr++; + } +} + +gcry_err_code_t +grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size) +{ + grub_uint8_t *inptr, *outptr, *end; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; + if (size % cipher->cipher->blocksize != 0) + return GPG_ERR_INV_ARG; + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + return GPG_ERR_NO_ERROR; +} + +gcry_err_code_t +grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size) +{ + grub_uint8_t *inptr, *outptr, *end; + if (!cipher->cipher->encrypt) + return GPG_ERR_NOT_SUPPORTED; + if (size % cipher->cipher->blocksize != 0) + return GPG_ERR_INV_ARG; + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + cipher->cipher->encrypt (cipher->ctx, outptr, inptr); + return GPG_ERR_NO_ERROR; +} + +gcry_err_code_t +grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv_in) +{ + grub_uint8_t *inptr, *outptr, *end; + void *iv; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; + if (size % cipher->cipher->blocksize != 0) + return GPG_ERR_INV_ARG; + end = (grub_uint8_t *) in + size; + iv = iv_in; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_crypto_xor (outptr, inptr, iv, cipher->cipher->blocksize); + cipher->cipher->encrypt (cipher->ctx, outptr, outptr); + iv = outptr; + } + grub_memcpy (iv_in, iv, cipher->cipher->blocksize); + return GPG_ERR_NO_ERROR; +} + +gcry_err_code_t +grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv) +{ + grub_uint8_t *inptr, *outptr, *end; + grub_uint8_t ivt[cipher->cipher->blocksize]; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; + if (size % cipher->cipher->blocksize != 0) + return GPG_ERR_INV_ARG; + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_memcpy (ivt, inptr, cipher->cipher->blocksize); + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize); + grub_memcpy (iv, ivt, cipher->cipher->blocksize); + } + return GPG_ERR_NO_ERROR; +} + +/* Based on gcry/cipher/md.c. */ +struct grub_crypto_hmac_handle * +grub_crypto_hmac_init (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen) +{ + grub_uint8_t *helpkey = NULL; + grub_uint8_t *ipad = NULL, *opad = NULL; + void *ctx = NULL; + struct grub_crypto_hmac_handle *ret = NULL; + unsigned i; + + if (md->mdlen > md->blocksize) + return NULL; + + ctx = grub_malloc (md->contextsize); + if (!ctx) + goto err; + + if ( keylen > md->blocksize ) + { + helpkey = grub_malloc (md->mdlen); + if (!helpkey) + goto err; + grub_crypto_hash (md, helpkey, key, keylen); + + key = helpkey; + keylen = md->mdlen; + } + + ipad = grub_zalloc (md->blocksize); + if (!ipad) + goto err; + + opad = grub_zalloc (md->blocksize); + if (!opad) + goto err; + + grub_memcpy ( ipad, key, keylen ); + grub_memcpy ( opad, key, keylen ); + for (i=0; i < md->blocksize; i++ ) + { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + grub_free (helpkey); + helpkey = NULL; + + md->init (ctx); + + md->write (ctx, ipad, md->blocksize); /* inner pad */ + grub_memset (ipad, 0, md->blocksize); + grub_free (ipad); + ipad = NULL; + + ret = grub_malloc (sizeof (*ret)); + if (!ret) + goto err; + + ret->md = md; + ret->ctx = ctx; + ret->opad = opad; + + return ret; + + err: + grub_free (helpkey); + grub_free (ctx); + grub_free (ipad); + grub_free (opad); + return NULL; +} + +void +grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, void *data, + grub_size_t datalen) +{ + hnd->md->write (hnd->ctx, data, datalen); +} + +gcry_err_code_t +grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out) +{ + grub_uint8_t *p; + grub_uint8_t *ctx2; + + ctx2 = grub_malloc (hnd->md->contextsize); + if (!ctx2) + return GPG_ERR_OUT_OF_MEMORY; + + hnd->md->final (hnd->ctx); + hnd->md->read (hnd->ctx); + p = hnd->md->read (hnd->ctx); + + hnd->md->init (ctx2); + hnd->md->write (ctx2, hnd->opad, hnd->md->blocksize); + hnd->md->write (ctx2, p, hnd->md->mdlen); + hnd->md->final (ctx2); + grub_memset (hnd->opad, 0, hnd->md->blocksize); + grub_free (hnd->opad); + grub_memset (hnd->ctx, 0, hnd->md->contextsize); + grub_free (hnd->ctx); + + grub_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen); + grub_memset (ctx2, 0, hnd->md->contextsize); + grub_free (ctx2); + + grub_memset (hnd, 0, sizeof (*hnd)); + grub_free (hnd); + + return GPG_ERR_NO_ERROR; +} + +gcry_err_code_t +grub_crypto_hmac_buffer (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen, + void *data, grub_size_t datalen, void *out) +{ + struct grub_crypto_hmac_handle *hnd; + + hnd = grub_crypto_hmac_init (md, key, keylen); + if (!hnd) + return GPG_ERR_OUT_OF_MEMORY; + + grub_crypto_hmac_write (hnd, data, datalen); + return grub_crypto_hmac_fini (hnd, out); +} + + +grub_err_t +grub_crypto_gcry_error (gcry_err_code_t in) +{ + if (in == GPG_ERR_NO_ERROR) + return GRUB_ERR_NONE; + return GRUB_ACCESS_DENIED; +} + +int +grub_crypto_memcmp (const void *a, const void *b, grub_size_t n) +{ + register grub_size_t counter = 0; + const grub_uint8_t *pa, *pb; + + for (pa = a, pb = b; n; pa++, pb++, n--) + { + if (*pa != *pb) + counter++; + } + + return !!counter; +} + +#ifndef GRUB_MKPASSWD +int +grub_password_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--; + continue; + } + + if (!grub_isprint (key)) + continue; + + if (cur_len + 2 < buf_size) + buf[cur_len++] = key; + } + + grub_memset (buf + cur_len, 0, buf_size - cur_len); + + grub_putchar ('\n'); + grub_refresh (); + + return (key != '\e'); +} +#endif diff --git a/lib/libgcrypt_wrap/cipher_wrap.h b/lib/libgcrypt_wrap/cipher_wrap.h new file mode 100644 index 000000000..e05f0cda9 --- /dev/null +++ b/lib/libgcrypt_wrap/cipher_wrap.h @@ -0,0 +1,86 @@ +/* + * 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 . + */ + +#ifndef GRUB_GCRY_WRAP_HEADER +#define GRUB_GCRY_WRAP_HEADER 1 + +#include +#include +#include +#include +#include + +#define __GNU_LIBRARY__ + +#define DIM ARRAY_SIZE + +typedef grub_uint64_t u64; +typedef grub_uint32_t u32; +typedef grub_uint16_t u16; +typedef grub_uint8_t byte; +typedef grub_size_t size_t; + +#define U64_C(c) (c ## ULL) + +#define _gcry_burn_stack grub_burn_stack +#define log_error(fmt, args...) grub_dprintf ("crypto", fmt, ## args) + + +#define PUBKEY_FLAG_NO_BLINDING (1 << 0) + +#define CIPHER_INFO_NO_WEAK_KEY 1 + +#define HAVE_U64_TYPEDEF 1 + +typedef union { + int a; + short b; + char c[1]; + long d; +#ifdef HAVE_U64_TYPEDEF + u64 e; +#endif + float f; + double g; +} PROPERLY_ALIGNED_TYPE; + +#define gcry_assert(x) grub_assert_real(__FILE__, __LINE__, x) + +static inline void +grub_assert_real (const char *file, int line, int cond) +{ + if (!cond) + grub_fatal ("Assertion failed at %s:%d\n", file, line); +} + +/* Selftests are in separate modules. */ +static inline char * +selftest (void) +{ + return NULL; +} + +static inline int +fips_mode (void) +{ + return 0; +} + +#define memset grub_memset + +#endif diff --git a/lib/pbkdf2.c b/lib/pbkdf2.c new file mode 100644 index 000000000..083446ab9 --- /dev/null +++ b/lib/pbkdf2.c @@ -0,0 +1,102 @@ +/* gc-pbkdf2-sha1.c --- Password-Based Key Derivation Function a'la PKCS#5 + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2009 Free Software Foundation, Inc. + + This program 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 2, or (at your option) + any later version. + + This program 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 this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Simon Josefsson. */ +/* Imported from gnulib. */ + +#include +#include +#include + +/* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant + of digest supplied by MD. Inputs are the password P of length PLEN, + the salt S of length SLEN, the iteration counter C (> 0), and the + desired derived output length DKLEN. Output buffer is DK which + must have room for at least DKLEN octets. The output buffer will + be filled with the derived data. */ +gcry_err_code_t +grub_crypto_pbkdf2 (const struct gcry_md_spec *md, + const grub_uint8_t *P, grub_size_t Plen, + const grub_uint8_t *S, grub_size_t Slen, + unsigned int c, + grub_uint8_t *DK, grub_size_t dkLen) +{ + unsigned int hLen = md->mdlen; + grub_uint8_t U[md->mdlen]; + grub_uint8_t T[md->mdlen]; + unsigned int u; + unsigned int l; + unsigned int r; + unsigned int i; + unsigned int k; + gcry_err_code_t rc; + grub_uint8_t *tmp; + grub_size_t tmplen = Slen + 4; + + if (c == 0) + return GPG_ERR_INV_ARG; + + if (dkLen == 0) + return GPG_ERR_INV_ARG; + + if (dkLen > 4294967295U) + return GPG_ERR_INV_ARG; + + l = ((dkLen - 1) / hLen) + 1; + r = dkLen - (l - 1) * hLen; + + tmp = grub_malloc (tmplen); + if (tmp == NULL) + return GPG_ERR_OUT_OF_MEMORY; + + grub_memcpy (tmp, S, Slen); + + for (i = 1; i <= l; i++) + { + grub_memset (T, 0, hLen); + + for (u = 1; u <= c; u++) + { + if (u == 1) + { + tmp[Slen + 0] = (i & 0xff000000) >> 24; + tmp[Slen + 1] = (i & 0x00ff0000) >> 16; + tmp[Slen + 2] = (i & 0x0000ff00) >> 8; + tmp[Slen + 3] = (i & 0x000000ff) >> 0; + + rc = grub_crypto_hmac_buffer (md, P, Plen, tmp, tmplen, U); + } + else + rc = grub_crypto_hmac_buffer (md, P, Plen, U, hLen, U); + + if (rc != GPG_ERR_NO_ERROR) + { + grub_free (tmp); + return rc; + } + + for (k = 0; k < hLen; k++) + T[k] ^= U[k]; + } + + grub_memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen); + } + + grub_free (tmp); + + return GPG_ERR_NO_ERROR; +} diff --git a/loader/i386/linux.c b/loader/i386/linux.c index 2434df609..e6e337fdf 100644 --- a/loader/i386/linux.c +++ b/loader/i386/linux.c @@ -33,6 +33,7 @@ #include #include #include +#include #define GRUB_LINUX_CL_OFFSET 0x1000 #define GRUB_LINUX_CL_END_OFFSET 0x2000 @@ -547,8 +548,30 @@ grub_linux_boot (void) /* Initialize these last, because terminal position could be affected by printfs above. */ if (params->have_vga == GRUB_VIDEO_TYPE_TEXT) { - params->video_cursor_x = grub_getxy () >> 8; - params->video_cursor_y = grub_getxy () & 0xff; + grub_term_output_t term; + int found = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_strcmp (term->name, "vga_text") == 0) + { + grub_uint16_t pos = grub_term_getxy (term); + params->video_cursor_x = pos >> 8; + params->video_cursor_y = pos & 0xff; + found = 1; + } + if (!found) + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_strcmp (term->name, "console") == 0) + { + grub_uint16_t pos = grub_term_getxy (term); + params->video_cursor_x = pos >> 8; + params->video_cursor_y = pos & 0xff; + found = 1; + } + if (!found) + { + params->video_cursor_x = 0; + params->video_cursor_y = 0; + } } #ifdef __x86_64__ diff --git a/normal/auth.c b/normal/auth.c index 54107fe01..156b84c37 100644 --- a/normal/auth.c +++ b/normal/auth.c @@ -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; diff --git a/normal/cmdline.c b/normal/cmdline.c index a4cb6681f..a3c7a28ec 100644 --- a/normal/cmdline.c +++ b/normal/cmdline.c @@ -27,11 +27,12 @@ #include #include #include +#include -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. */ @@ -176,70 +202,109 @@ 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 void 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); 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]); + } + + void 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; - 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) + if (cl_term->xpos++ > cl_term->width - 2) { - grub_putchar ('\n'); + grub_putcode ('\n', cl_term->term); - xpos = 1; - if (ypos == (unsigned) (grub_getxy () & 0xFF)) - ystart--; + cl_term->xpos = 1; + if (cl_term->ypos == (unsigned) (cl_term->height)) + cl_term->ystart--; else - ypos++; + cl_term->ypos++; } if (c) - grub_putchar (c); + grub_putcode (c, cl_term->term); else - grub_putchar (*p); + grub_putcode (*p, 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 (); } } @@ -250,182 +315,256 @@ 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 (); } } + 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); lpos = llen = 0; buf[0] = '\0'; - if ((grub_getxy () >> 8) != 0) - grub_putchar ('\n'); + { + 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); - 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); grub_refresh (); 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; @@ -433,7 +572,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; @@ -447,7 +586,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'; @@ -462,23 +601,20 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, 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; } diff --git a/normal/color.c b/normal/color.c index 0b9868d3b..bae082911 100644 --- a/normal/color.c +++ b/normal/color.c @@ -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); } diff --git a/normal/crypto.c b/normal/crypto.c new file mode 100644 index 000000000..67330272a --- /dev/null +++ b/normal/crypto.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/normal/main.c b/normal/main.c index 245f20f30..14e8971b0 100644 --- a/normal/main.c +++ b/normal/main.c @@ -30,9 +30,13 @@ #include #include #include +#include #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,7 +401,7 @@ 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; @@ -391,14 +409,13 @@ grub_normal_init_page (void) char *msg_formatted = grub_malloc (grub_strlen(msg) + grub_strlen(PACKAGE_VERSION)); - - grub_cls (); - - grub_sprintf (msg_formatted, msg, 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); @@ -407,17 +424,15 @@ grub_normal_init_page (void) 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; - /* Read the config file CONFIG and execute the menu interface or the command line interface if BATCH is false. */ void @@ -428,10 +443,10 @@ grub_normal_execute (const char *config, int nested, int batch) read_command_list (); read_fs_list (); read_handler_list (); + read_crypto_list (); + read_terminal_list (); grub_command_execute ("parser.grub", 0, 0); - reader_nested = nested; - if (config) { menu = read_config_file (config); @@ -444,7 +459,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,21 +470,24 @@ 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"); @@ -493,10 +511,82 @@ 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_reader_t reader; grub_err_t err = GRUB_ERR_NONE; err = grub_auth_check_authentication (NULL); @@ -508,72 +598,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) @@ -588,17 +634,22 @@ 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_menu_register_viewer_init (grub_menu_text_register_instances); + if (grub_errno) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + 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); @@ -607,14 +658,11 @@ GRUB_MOD_INIT(normal) /* Preserve hooks after context changes. */ grub_env_export ("color_normal"); grub_env_export ("color_highlight"); - - grub_menu_viewer_init (); } GRUB_MOD_FINI(normal) { 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 (); diff --git a/normal/menu.c b/normal/menu.c index 282dddae5..d671cc9fd 100644 --- a/normal/menu.c +++ b/normal/menu.c @@ -27,6 +27,30 @@ #include #include #include +#include + +/* Time to delay after displaying an error message about a default/fallback + entry failing to boot. */ +#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500 + +struct menu_run_callback +{ + struct menu_run_callback *next; + void (*hook) (int entry, grub_menu_t menu, int nested); +}; + +struct menu_run_callback *callbacks = 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 @@ -181,6 +205,86 @@ 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; +} + +/* FIXME: allow text menu in parallel with gfxmenu. */ +grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, + int nested) = NULL; +static void +menu_init (int entry, grub_menu_t menu, int nested) +{ + struct menu_run_callback *cb; + + if (grub_gfxmenu_try_hook) + { + if(!grub_gfxmenu_try_hook (entry, menu, nested)) + return; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + + for (cb = callbacks; cb; cb = cb->next) + cb->hook (entry, menu, nested); +} + +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; +} + +grub_err_t +grub_menu_register_viewer_init (void (*callback) (int entry, grub_menu_t menu, + int nested)) +{ + struct menu_run_callback *cb; + cb = grub_malloc (sizeof (*cb)); + if (!cb) + return grub_errno; + cb->hook = callback; + cb->next = callbacks; + callbacks = cb; + return GRUB_ERR_NONE; +} + /* Get the entry number from the variable NAME. */ static int get_entry_number (grub_menu_t menu, const char *name) @@ -229,8 +333,279 @@ get_entry_number (grub_menu_t menu, const char *name) return entry; } -int -grub_menu_get_default_entry_index (grub_menu_t menu) +#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) { - return get_entry_number (menu, "default"); + 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 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 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; } diff --git a/normal/menu_entry.c b/normal/menu_entry.c index 7a31c27af..7236f78e1 100644 --- a/normal/menu_entry.c +++ b/normal/menu_entry.c @@ -43,6 +43,15 @@ struct line int max_len; }; +struct per_term_screen +{ + struct grub_term_output *term; + /* The X coordinate. */ + int x; + /* The Y coordinate. */ + int y; +}; + struct screen { /* The array of lines. */ @@ -55,18 +64,18 @@ struct screen int real_column; /* The current line. */ int line; - /* The X coordinate. */ - int x; - /* The Y coordinate. */ - int y; /* The kill buffer. */ char *killed_text; /* The flag of a completion window. */ int completion_shown; + + struct per_term_screen *terms; + unsigned nterms; }; /* Used for storing completion items temporarily. */ static struct line completion_buffer; +static int completion_type; /* Initialize a line. */ static int @@ -98,77 +107,95 @@ ensure_space (struct line *linep, int extra) /* Return the number of lines occupied by this line on the screen. */ static int -get_logical_num_lines (struct line *linep) +get_logical_num_lines (struct line *linep, struct per_term_screen *term_screen) { - return (linep->len / GRUB_TERM_ENTRY_WIDTH) + 1; + return (linep->len / grub_term_entry_width (term_screen->term)) + 1; } /* Print a line. */ static void -print_line (struct line *linep, int offset, int start, int y) +print_line (struct line *linep, int offset, int start, int y, + struct per_term_screen *term_screen) { - int i; - char *p; + grub_term_gotoxy (term_screen->term, + GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + start + 1, + y + GRUB_TERM_FIRST_ENTRY_Y); - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + start + 1, - y + GRUB_TERM_FIRST_ENTRY_Y); - - for (p = linep->buf + offset + start, i = start; - i < GRUB_TERM_ENTRY_WIDTH && offset + i < linep->len; - p++, i++) - grub_putchar (*p); - - for (; i < GRUB_TERM_ENTRY_WIDTH; i++) - grub_putchar (' '); - - if (linep->len >= offset + GRUB_TERM_ENTRY_WIDTH) - grub_putchar ('\\'); + if (linep->len >= offset + grub_term_entry_width (term_screen->term)) + { + char *p, c; + p = linep->buf + offset + grub_term_entry_width (term_screen->term); + c = *p; + *p = 0; + grub_puts_terminal (linep->buf + offset + start, term_screen->term); + *p = c; + grub_putcode ('\\', term_screen->term); + } else - grub_putchar (' '); + { + int i; + char *p, c; + + p = linep->buf + linep->len; + c = *p; + *p = 0; + grub_puts_terminal (linep->buf + offset + start, term_screen->term); + *p = c; + + for (i = 0; + i <= grub_term_entry_width (term_screen->term) - linep->len + offset; + i++) + grub_putcode (' ', term_screen->term); + } } /* Print an empty line. */ static void -print_empty_line (int y) +print_empty_line (int y, struct per_term_screen *term_screen) { int i; - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, - y + GRUB_TERM_FIRST_ENTRY_Y); + grub_term_gotoxy (term_screen->term, + GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, + y + GRUB_TERM_FIRST_ENTRY_Y); - for (i = 0; i < GRUB_TERM_ENTRY_WIDTH + 1; i++) - grub_putchar (' '); + for (i = 0; i < grub_term_entry_width (term_screen->term) + 1; i++) + grub_putcode (' ', term_screen->term); } /* Print an up arrow. */ static void -print_up (int flag) +print_up (int flag, struct per_term_screen *term_screen) { - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, - GRUB_TERM_FIRST_ENTRY_Y); + grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X + + grub_term_entry_width (term_screen->term), + GRUB_TERM_FIRST_ENTRY_Y); if (flag) - grub_putcode (GRUB_TERM_DISP_UP); + grub_putcode (GRUB_TERM_DISP_UP, term_screen->term); else - grub_putchar (' '); + grub_putcode (' ', term_screen->term); } /* Print a down arrow. */ static void -print_down (int flag) +print_down (int flag, struct per_term_screen *term_screen) { - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, - GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES); + grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X + + grub_term_border_width (term_screen->term), + GRUB_TERM_TOP_BORDER_Y + + grub_term_num_entries (term_screen->term)); if (flag) - grub_putcode (GRUB_TERM_DISP_DOWN); + grub_putcode (GRUB_TERM_DISP_DOWN, term_screen->term); else - grub_putchar (' '); + grub_putcode (' ', term_screen->term); } /* Draw the lines of the screen SCREEN. */ static void -update_screen (struct screen *screen, int region_start, int region_column, +update_screen (struct screen *screen, struct per_term_screen *term_screen, + int region_start, int region_column, int up, int down, enum update_mode mode) { int up_flag = 0; @@ -178,12 +205,13 @@ update_screen (struct screen *screen, int region_start, int region_column, struct line *linep; /* Check if scrolling is necessary. */ - if (screen->y < 0 || screen->y >= GRUB_TERM_NUM_ENTRIES) + if (term_screen->y < 0 || term_screen->y + >= grub_term_num_entries (term_screen->term)) { - if (screen->y < 0) - screen->y = 0; + if (term_screen->y < 0) + term_screen->y = 0; else - screen->y = GRUB_TERM_NUM_ENTRIES - 1; + term_screen->y = grub_term_num_entries (term_screen->term) - 1; region_start = 0; region_column = 0; @@ -196,14 +224,15 @@ update_screen (struct screen *screen, int region_start, int region_column, { /* Draw lines. This code is tricky, because this must calculate logical positions. */ - y = screen->y - screen->column / GRUB_TERM_ENTRY_WIDTH; + y = term_screen->y - screen->column + / grub_term_entry_width (term_screen->term); i = screen->line; linep = screen->lines + i; while (y > 0) { i--; linep--; - y -= get_logical_num_lines (linep); + y -= get_logical_num_lines (linep, term_screen); } if (y < 0 || i > 0) @@ -214,8 +243,9 @@ update_screen (struct screen *screen, int region_start, int region_column, int column; for (column = 0; - column <= linep->len && y < GRUB_TERM_NUM_ENTRIES; - column += GRUB_TERM_ENTRY_WIDTH, y++) + column <= linep->len + && y < grub_term_num_entries (term_screen->term); + column += grub_term_entry_width (term_screen->term), y++) { if (y < 0) continue; @@ -223,16 +253,19 @@ update_screen (struct screen *screen, int region_start, int region_column, if (i == region_start) { if (region_column >= column - && region_column < column + GRUB_TERM_ENTRY_WIDTH) - print_line (linep, column, region_column - column, y); + && region_column + < (column + + grub_term_entry_width (term_screen->term))) + print_line (linep, column, region_column - column, y, + term_screen); else if (region_column < column) - print_line (linep, column, 0, y); + print_line (linep, column, 0, y, term_screen); } else if (i > region_start && mode == ALL_LINES) - print_line (linep, column, 0, y); + print_line (linep, column, 0, y, term_screen); } - if (y == GRUB_TERM_NUM_ENTRIES) + if (y == grub_term_num_entries (term_screen->term)) { if (column <= linep->len || i + 1 < screen->num_lines) down_flag = 1; @@ -242,35 +275,53 @@ update_screen (struct screen *screen, int region_start, int region_column, i++; if (mode == ALL_LINES && i == screen->num_lines) - for (; y < GRUB_TERM_NUM_ENTRIES; y++) - print_empty_line (y); + for (; y < grub_term_num_entries (term_screen->term); y++) + print_empty_line (y, term_screen); } - while (y < GRUB_TERM_NUM_ENTRIES); + while (y < grub_term_num_entries (term_screen->term)); /* Draw up and down arrows. */ if (up) - print_up (up_flag); + print_up (up_flag, term_screen); if (down) - print_down (down_flag); + print_down (down_flag, term_screen); } /* Place the cursor. */ - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1 + screen->x, - GRUB_TERM_FIRST_ENTRY_Y + screen->y); + grub_term_gotoxy (term_screen->term, + GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1 + + term_screen->x, + GRUB_TERM_FIRST_ENTRY_Y + term_screen->y); - grub_refresh (); + grub_term_refresh (term_screen->term); +} + +static void +update_screen_all (struct screen *screen, + int region_start, int region_column, + int up, int down, enum update_mode mode) +{ + unsigned i; + for (i = 0; i < screen->nterms; i++) + update_screen (screen, &screen->terms[i], region_start, region_column, + up, down, mode); } -/* Insert the string S into the screen SCREEN. This updates the cursor - position and redraw the screen. Return zero if fails. */ static int insert_string (struct screen *screen, char *s, int update) { int region_start = screen->num_lines; int region_column = 0; - int down = 0; - enum update_mode mode = NO_LINE; + int down[screen->nterms]; + enum update_mode mode[screen->nterms]; + unsigned i; + + for (i = 0; i < screen->nterms; i++) + { + down[i] = 0; + mode[i] = NO_LINE; + } while (*s) { @@ -319,15 +370,20 @@ insert_string (struct screen *screen, char *s, int update) region_column = screen->column; } - mode = ALL_LINES; - down = 1; /* XXX not optimal. */ + for (i = 0; i < screen->nterms; i++) + { + mode[i] = ALL_LINES; + down[i] = 1; /* XXX not optimal. */ + } /* Move the cursor. */ screen->column = screen->real_column = 0; screen->line++; - screen->x = 0; - screen->y++; - + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x = 0; + screen->terms[i].y++; + } s++; } else @@ -336,7 +392,7 @@ insert_string (struct screen *screen, char *s, int update) char *p; struct line *current_linep; int size; - int orig_num, new_num; + int orig_num[screen->nterms], new_num[screen->nterms]; /* Find a string delimited by LF. */ p = grub_strchr (s, '\n'); @@ -355,9 +411,13 @@ insert_string (struct screen *screen, char *s, int update) grub_memmove (current_linep->buf + screen->column, s, size); - orig_num = get_logical_num_lines (current_linep); + for (i = 0; i < screen->nterms; i++) + orig_num[i] = get_logical_num_lines (current_linep, + &screen->terms[i]); current_linep->len += size; - new_num = get_logical_num_lines (current_linep); + for (i = 0; i < screen->nterms; i++) + new_num[i] = get_logical_num_lines (current_linep, + &screen->terms[i]); /* Update the dirty region. */ if (region_start > screen->line) @@ -366,27 +426,34 @@ insert_string (struct screen *screen, char *s, int update) region_column = screen->column; } - if (orig_num != new_num) - { - mode = ALL_LINES; - down = 1; /* XXX not optimal. */ - } - else if (mode != ALL_LINES) - mode = SINGLE_LINE; + for (i = 0; i < screen->nterms; i++) + if (orig_num[i] != new_num[i]) + { + mode[i] = ALL_LINES; + down[i] = 1; /* XXX not optimal. */ + } + else if (mode[i] != ALL_LINES) + mode[i] = SINGLE_LINE; /* Move the cursor. */ screen->column += size; screen->real_column = screen->column; - screen->x += size; - screen->y += screen->x / GRUB_TERM_ENTRY_WIDTH; - screen->x %= GRUB_TERM_ENTRY_WIDTH; - + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x += size; + screen->terms[i].y += screen->terms[i].x + / grub_term_entry_width (screen->terms[i].term); + screen->terms[i].x + %= grub_term_entry_width (screen->terms[i].term); + } s = p; } } if (update) - update_screen (screen, region_start, region_column, 0, down, mode); + for (i = 0; i < screen->nterms; i++) + update_screen (screen, &screen->terms[i], + region_start, region_column, 0, down[i], mode[i]); return 1; } @@ -408,6 +475,7 @@ destroy_screen (struct screen *screen) grub_free (screen->killed_text); grub_free (screen->lines); + grub_free (screen->terms); grub_free (screen); } @@ -416,6 +484,7 @@ static struct screen * make_screen (grub_menu_entry_t entry) { struct screen *screen; + unsigned i; /* Initialize the screen. */ screen = grub_zalloc (sizeof (*screen)); @@ -437,8 +506,11 @@ make_screen (grub_menu_entry_t entry) screen->column = 0; screen->real_column = 0; screen->line = 0; - screen->x = 0; - screen->y = 0; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x = 0; + screen->terms[i].y = 0; + } return screen; @@ -451,44 +523,58 @@ static int forward_char (struct screen *screen, int update) { struct line *linep; + unsigned i; linep = screen->lines + screen->line; if (screen->column < linep->len) { screen->column++; - screen->x++; - if (screen->x == GRUB_TERM_ENTRY_WIDTH) + for (i = 0; i < screen->nterms; i++) { - screen->x = 0; - screen->y++; + screen->terms[i].x++; + if (screen->terms[i].x + == grub_term_entry_width (screen->terms[i].term)) + { + screen->terms[i].x = 0; + screen->terms[i].y++; + } } } else if (screen->num_lines > screen->line + 1) { screen->column = 0; screen->line++; - screen->x = 0; - screen->y++; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x = 0; + screen->terms[i].y++; + } } screen->real_column = screen->column; if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } static int backward_char (struct screen *screen, int update) { + unsigned i; + if (screen->column > 0) { screen->column--; - screen->x--; - if (screen->x == -1) + for (i = 0; i < screen->nterms; i++) { - screen->x = GRUB_TERM_ENTRY_WIDTH - 1; - screen->y--; + screen->terms[i].x--; + if (screen->terms[i].x == -1) + { + screen->terms[i].x + = grub_term_entry_width (screen->terms[i].term) - 1; + screen->terms[i].y--; + } } } else if (screen->line > 0) @@ -498,14 +584,18 @@ backward_char (struct screen *screen, int update) screen->line--; linep = screen->lines + screen->line; screen->column = linep->len; - screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; - screen->y--; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x = screen->column + % grub_term_entry_width (screen->terms[i].term); + screen->terms[i].y--; + } } screen->real_column = screen->column; if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } @@ -513,14 +603,16 @@ backward_char (struct screen *screen, int update) static int previous_line (struct screen *screen, int update) { + unsigned i; + if (screen->line > 0) { struct line *linep; - int dy; + int col; /* How many physical lines from the current position to the first physical line? */ - dy = screen->column / GRUB_TERM_ENTRY_WIDTH; + col = screen->column; screen->line--; @@ -530,23 +622,35 @@ previous_line (struct screen *screen, int update) else screen->column = screen->real_column; - /* How many physical lines from the current position - to the last physical line? */ - dy += (linep->len / GRUB_TERM_ENTRY_WIDTH - - screen->column / GRUB_TERM_ENTRY_WIDTH); + for (i = 0; i < screen->nterms; i++) + { + int dy; + dy = col / grub_term_entry_width (screen->terms[i].term); - screen->y -= dy + 1; - screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + /* How many physical lines from the current position + to the last physical line? */ + dy += (linep->len / grub_term_entry_width (screen->terms[i].term) + - screen->column + / grub_term_entry_width (screen->terms[i].term)); + + screen->terms[i].y -= dy + 1; + screen->terms[i].x + = screen->column % grub_term_entry_width (screen->terms[i].term); + } } else { - screen->y -= screen->column / GRUB_TERM_ENTRY_WIDTH; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].y + -= screen->column / grub_term_entry_width (screen->terms[i].term); + screen->terms[i].x = 0; + } screen->column = 0; - screen->x = 0; } if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } @@ -554,16 +658,18 @@ previous_line (struct screen *screen, int update) static int next_line (struct screen *screen, int update) { + unsigned i; + if (screen->line < screen->num_lines - 1) { struct line *linep; - int dy; + int l1, c1; /* How many physical lines from the current position to the last physical line? */ linep = screen->lines + screen->line; - dy = (linep->len / GRUB_TERM_ENTRY_WIDTH - - screen->column / GRUB_TERM_ENTRY_WIDTH); + l1 = linep->len; + c1 = screen->column; screen->line++; @@ -573,26 +679,40 @@ next_line (struct screen *screen, int update) else screen->column = screen->real_column; - /* How many physical lines from the current position - to the first physical line? */ - dy += screen->column / GRUB_TERM_ENTRY_WIDTH; - - screen->y += dy + 1; - screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + for (i = 0; i < screen->nterms; i++) + { + int dy; + dy = l1 / grub_term_entry_width (screen->terms[i].term) + - c1 / grub_term_entry_width (screen->terms[i].term); + /* How many physical lines from the current position + to the first physical line? */ + dy += screen->column / grub_term_entry_width (screen->terms[i].term); + screen->terms[i].y += dy + 1; + screen->terms[i].x = screen->column + % grub_term_entry_width (screen->terms[i].term); + } } else { struct line *linep; - + int l, s; + linep = screen->lines + screen->line; - screen->y += (linep->len / GRUB_TERM_ENTRY_WIDTH - - screen->column / GRUB_TERM_ENTRY_WIDTH); + l = linep->len; + s = screen->column; screen->column = linep->len; - screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].y + += (l / grub_term_entry_width (screen->terms[i].term) + - s / grub_term_entry_width (screen->terms[i].term)); + screen->terms[i].x + = screen->column % grub_term_entry_width (screen->terms[i].term); + } } if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } @@ -600,12 +720,19 @@ next_line (struct screen *screen, int update) static int beginning_of_line (struct screen *screen, int update) { - screen->y -= screen->column / GRUB_TERM_ENTRY_WIDTH; + unsigned i; + int col; + + col = screen->column; screen->column = screen->real_column = 0; - screen->x = 0; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x = 0; + screen->terms[i].y -= col / grub_term_entry_width (screen->terms[i].term); + } if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } @@ -614,15 +741,23 @@ static int end_of_line (struct screen *screen, int update) { struct line *linep; + unsigned i; + int col; linep = screen->lines + screen->line; - screen->y += (linep->len / GRUB_TERM_ENTRY_WIDTH - - screen->column / GRUB_TERM_ENTRY_WIDTH); + col = screen->column; screen->column = screen->real_column = linep->len; - screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].y + += (linep->len / grub_term_entry_width (screen->terms->term) + - col / grub_term_entry_width (screen->terms->term)); + screen->terms[i].x + = screen->column % grub_term_entry_width (screen->terms->term); + } if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } @@ -631,32 +766,41 @@ static int delete_char (struct screen *screen, int update) { struct line *linep; - enum update_mode mode = NO_LINE; int start = screen->num_lines; int column = 0; - int down = 0; linep = screen->lines + screen->line; if (linep->len > screen->column) { - int orig_num, new_num; + int orig_num[screen->nterms], new_num; + unsigned i; - orig_num = get_logical_num_lines (linep); + for (i = 0; i < screen->nterms; i++) + orig_num[i] = get_logical_num_lines (linep, &screen->terms[i]); grub_memmove (linep->buf + screen->column, linep->buf + screen->column + 1, linep->len - screen->column - 1); linep->len--; - new_num = get_logical_num_lines (linep); - - if (orig_num != new_num) - mode = ALL_LINES; - else - mode = SINGLE_LINE; - start = screen->line; column = screen->column; + + screen->real_column = screen->column; + + if (update) + { + for (i = 0; i < screen->nterms; i++) + { + new_num = get_logical_num_lines (linep, &screen->terms[i]); + if (orig_num[i] != new_num) + update_screen (screen, &screen->terms[i], + start, column, 0, 0, ALL_LINES); + else + update_screen (screen, &screen->terms[i], + start, column, 0, 0, SINGLE_LINE); + } + } } else if (screen->num_lines > screen->line + 1) { @@ -676,17 +820,14 @@ delete_char (struct screen *screen, int update) * sizeof (struct line)); screen->num_lines--; - mode = ALL_LINES; start = screen->line; column = screen->column; - down = 1; + + screen->real_column = screen->column; + if (update) + update_screen_all (screen, start, column, 0, 1, ALL_LINES); } - screen->real_column = screen->column; - - if (update) - update_screen (screen, start, column, 0, down, mode); - return 1; } @@ -731,9 +872,8 @@ kill_line (struct screen *screen, int continuous, int update) if (size > 0) { - enum update_mode mode = SINGLE_LINE; - int down = 0; - int orig_num, new_num; + int orig_num[screen->nterms], new_num; + unsigned i; p = grub_realloc (p, offset + size + 1); if (! p) @@ -744,18 +884,23 @@ kill_line (struct screen *screen, int continuous, int update) screen->killed_text = p; - orig_num = get_logical_num_lines (linep); + for (i = 0; i < screen->nterms; i++) + orig_num[i] = get_logical_num_lines (linep, &screen->terms[i]); linep->len = screen->column; - new_num = get_logical_num_lines (linep); - - if (orig_num != new_num) - { - mode = ALL_LINES; - down = 1; - } if (update) - update_screen (screen, screen->line, screen->column, 0, down, mode); + { + new_num = get_logical_num_lines (linep, &screen->terms[i]); + for (i = 0; i < screen->nterms; i++) + { + if (orig_num[i] != new_num) + update_screen (screen, &screen->terms[i], + screen->line, screen->column, 0, 1, ALL_LINES); + else + update_screen (screen, &screen->terms[i], + screen->line, screen->column, 0, 0, SINGLE_LINE); + } + } } else if (screen->line + 1 < screen->num_lines) { @@ -786,7 +931,11 @@ yank (struct screen *screen, int update) static int open_line (struct screen *screen, int update) { - int saved_y = screen->y; + int saved_y[screen->nterms]; + unsigned i; + + for (i = 0; i < screen->nterms; i++) + saved_y[i] = screen->terms[i].y; if (! insert_string (screen, "\n", 0)) return 0; @@ -794,52 +943,23 @@ open_line (struct screen *screen, int update) if (! backward_char (screen, 0)) return 0; - screen->y = saved_y; + for (i = 0; i < screen->nterms; i++) + screen->terms[i].y = saved_y[i]; if (update) - update_screen (screen, screen->line, screen->column, 0, 1, ALL_LINES); + update_screen_all (screen, screen->line, screen->column, 0, 1, ALL_LINES); return 1; } /* A completion hook to print items. */ static void -store_completion (const char *item, grub_completion_type_t type, int count) +store_completion (const char *item, grub_completion_type_t type, + int count __attribute__ ((unused))) { char *p; - if (count == 0) - { - /* If this is the first time, print a label. */ - const char *what; - - switch (type) - { - case GRUB_COMPLETION_TYPE_COMMAND: - what = "commands"; - break; - case GRUB_COMPLETION_TYPE_DEVICE: - what = "devices"; - break; - case GRUB_COMPLETION_TYPE_FILE: - what = "files"; - break; - case GRUB_COMPLETION_TYPE_PARTITION: - what = "partitions"; - break; - case GRUB_COMPLETION_TYPE_ARGUMENT: - what = "arguments"; - break; - default: - what = "things"; - break; - } - - grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); - grub_printf (" "); - grub_printf_ (N_("Possible %s are:"), what); - grub_printf ("\n "); - } + completion_type = type; /* Make sure that the completion buffer has enough room. */ if (completion_buffer.max_len < (completion_buffer.len @@ -873,21 +993,21 @@ store_completion (const char *item, grub_completion_type_t type, int count) static int complete (struct screen *screen, int continuous, int update) { - grub_uint16_t pos; char saved_char; struct line *linep; int restore; char *insert; static int count = -1; + unsigned i; + grub_uint32_t *ucs4; + grub_size_t buflen; + grub_ssize_t ucs4len; if (continuous) count++; else count = 0; - pos = grub_getxy (); - grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); - completion_buffer.buf = 0; completion_buffer.len = 0; completion_buffer.max_len = 0; @@ -900,35 +1020,86 @@ complete (struct screen *screen, int continuous, int update) linep->buf[screen->column] = saved_char; - if (restore) + buflen = grub_strlen (completion_buffer.buf); + ucs4 = grub_malloc (sizeof (grub_uint32_t) * (buflen + 1)); + + if (!ucs4) { - char *p = completion_buffer.buf; - - screen->completion_shown = 1; - - if (p) - { - int num_sections = ((completion_buffer.len + GRUB_TERM_WIDTH - 8 - 1) - / (GRUB_TERM_WIDTH - 8)); - char *endp; - - p += (count % num_sections) * (GRUB_TERM_WIDTH - 8); - endp = p + (GRUB_TERM_WIDTH - 8); - - if (p != completion_buffer.buf) - grub_putcode (GRUB_TERM_DISP_LEFT); - else - grub_putchar (' '); - - while (*p && p < endp) - grub_putchar (*p++); - - if (*p) - grub_putcode (GRUB_TERM_DISP_RIGHT); - } + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return 1; } - grub_gotoxy (pos >> 8, pos & 0xFF); + ucs4len = grub_utf8_to_ucs4 (ucs4, buflen, + (grub_uint8_t *) completion_buffer.buf, + buflen, 0); + ucs4[ucs4len] = 0; + + if (restore) + for (i = 0; i < screen->nterms; i++) + { + int num_sections = ((completion_buffer.len + + grub_term_width (screen->terms[i].term) - 8 - 1) + / (grub_term_width (screen->terms[i].term) - 8)); + grub_uint32_t *endp; + grub_uint16_t pos; + grub_uint32_t *p = ucs4; + + pos = grub_term_getxy (screen->terms[i].term); + grub_term_gotoxy (screen->terms[i].term, 0, + grub_term_height (screen->terms[i].term) - 3); + + screen->completion_shown = 1; + + grub_term_gotoxy (screen->terms[i].term, 0, + grub_term_height (screen->terms[i].term) - 3); + grub_puts_terminal (" ", screen->terms[i].term); + switch (completion_type) + { + case GRUB_COMPLETION_TYPE_COMMAND: + grub_puts_terminal (_("Possible commands are:"), + screen->terms[i].term); + break; + case GRUB_COMPLETION_TYPE_DEVICE: + grub_puts_terminal (_("Possible devices are:"), + screen->terms[i].term); + break; + case GRUB_COMPLETION_TYPE_FILE: + grub_puts_terminal (_("Possible files are:"), + screen->terms[i].term); + break; + case GRUB_COMPLETION_TYPE_PARTITION: + grub_puts_terminal (_("Possible partitions are:"), + screen->terms[i].term); + break; + case GRUB_COMPLETION_TYPE_ARGUMENT: + grub_puts_terminal (_("Possible arguments are:"), + screen->terms[i].term); + break; + default: + grub_puts_terminal (_("Possible things are:"), + screen->terms[i].term); + break; + } + + grub_puts_terminal ("\n ", screen->terms[i].term); + + p += (count % num_sections) + * (grub_term_width (screen->terms[i].term) - 8); + endp = p + (grub_term_width (screen->terms[i].term) - 8); + + if (p != ucs4) + grub_putcode (GRUB_TERM_DISP_LEFT, screen->terms[i].term); + else + grub_putcode (' ', screen->terms[i].term); + + while (*p && p < endp) + grub_putcode (*p++, screen->terms[i].term); + + if (*p) + grub_putcode (GRUB_TERM_DISP_RIGHT, screen->terms[i].term); + grub_term_gotoxy (screen->terms[i].term, pos >> 8, pos & 0xFF); + } if (insert) { @@ -945,23 +1116,33 @@ complete (struct screen *screen, int continuous, int update) /* Clear displayed completions. */ static void -clear_completions (void) +clear_completions (struct per_term_screen *term_screen) { grub_uint16_t pos; - int i, j; + unsigned i, j; - pos = grub_getxy (); - grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); + pos = grub_term_getxy (term_screen->term); + grub_term_gotoxy (term_screen->term, 0, + grub_term_height (term_screen->term) - 3); for (i = 0; i < 2; i++) { - for (j = 0; j < GRUB_TERM_WIDTH - 1; j++) - grub_putchar (' '); - grub_putchar ('\n'); + for (j = 0; j < grub_term_width (term_screen->term) - 1; j++) + grub_putcode (' ', term_screen->term); + grub_putcode ('\n', term_screen->term); } - grub_gotoxy (pos >> 8, pos & 0xFF); - grub_refresh (); + grub_term_gotoxy (term_screen->term, pos >> 8, pos & 0xFF); + grub_term_refresh (term_screen->term); +} + +static void +clear_completions_all (struct screen *screen) +{ + unsigned i; + + for (i = 0; i < screen->nterms; i++) + clear_completions (&screen->terms[i]); } /* Execute the command list in the screen SCREEN. */ @@ -1033,6 +1214,8 @@ grub_menu_entry_run (grub_menu_entry_t entry) struct screen *screen; int prev_c; grub_err_t err = GRUB_ERR_NONE; + unsigned i; + grub_term_output_t term; err = grub_auth_check_authentication (NULL); @@ -1047,11 +1230,34 @@ grub_menu_entry_run (grub_menu_entry_t entry) if (! screen) return; + screen->terms = NULL; + refresh: + grub_free (screen->terms); + screen->nterms = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + screen->nterms++; + screen->terms = grub_malloc (screen->nterms * sizeof (screen->terms[0])); + if (!screen->terms) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } + i = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + { + screen->terms[i].term = term; + screen->terms[i].x = 0; + screen->terms[i].y = 0; + i++; + } /* Draw the screen. */ - grub_menu_init_page (0, 1); - update_screen (screen, 0, 0, 1, 1, ALL_LINES); - grub_setcursor (1); + for (i = 0; i < screen->nterms; i++) + grub_menu_init_page (0, 1, screen->terms[i].term); + update_screen_all (screen, 0, 0, 1, 1, ALL_LINES); + for (i = 0; i < screen->nterms; i++) + grub_term_setcursor (screen->terms[i].term, 1); prev_c = '\0'; while (1) @@ -1060,10 +1266,16 @@ grub_menu_entry_run (grub_menu_entry_t entry) if (screen->completion_shown) { - clear_completions (); + clear_completions_all (screen); screen->completion_shown = 0; } + if (grub_normal_exit_level) + { + destroy_screen (screen); + return; + } + switch (c) { case 16: /* C-p */ diff --git a/normal/menu_text.c b/normal/menu_text.c index 81bcad0f7..791f831a0 100644 --- a/normal/menu_text.c +++ b/normal/menu_text.c @@ -26,96 +26,66 @@ #include #include #include - -/* Time to delay after displaying an error message about a default/fallback - entry failing to boot. */ -#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500 +#include 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,11 +102,12 @@ 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 + while (grub_getstringwidth (current_position, next_new_line,term) + > line_len || (*next_new_line != ' ' && next_new_line > current_position && next_new_line != last_position)) { @@ -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,52 +132,54 @@ 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 { @@ -218,23 +191,33 @@ entry is highlighted.\n"); 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); + 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,461 +243,251 @@ 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); + 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); - + 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 = grub_menu_get_default_entry_index (menu); - - /* 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 (! grub_menu_viewer_should_return ()) - { - 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; - - case 't': - grub_env_set ("menuviewer", "gfxmenu"); - goto refresh; - - default: - break; - } - - grub_refresh (); - } - } - - /* Exit menu without activating an item. This occurs if the user presses - * 't', switching to the graphical menu viewer. */ - 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_malloc (sizeof (char) * grub_strlen (msg) + 5); + 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_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); } -/* 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; } - - return GRUB_ERR_NONE; + 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); } -struct grub_menu_viewer grub_normal_text_menu_viewer = +static void +menu_text_fini (void *dataptr) { - .name = "text", - .show_menu = show_text_menu -}; + 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); +} + +void +grub_menu_text_register_instances (int entry, grub_menu_t menu, int nested) +{ + struct menu_viewer_data *data; + struct grub_menu_viewer *instance; + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + instance = grub_zalloc (sizeof (*instance)); + if (!instance) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + continue; + } + data = grub_zalloc (sizeof (*data)); + if (!data) + { + grub_free (instance); + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + continue; + } + + 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); + } +} diff --git a/normal/menu_viewer.c b/normal/menu_viewer.c index 7a547a764..e69de29bb 100644 --- a/normal/menu_viewer.c +++ b/normal/menu_viewer.c @@ -1,112 +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 . - */ - -#include -#include -#include -#include -#include -#include - -/* The list of menu viewers. */ -static grub_menu_viewer_t menu_viewer_list; - -static int should_return; -static int menu_viewer_changed; - -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_err_t err1, err2; - - while (1) - { - grub_menu_viewer_t cur = get_current_menu_viewer (); - if (!cur) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available."); - - menu_viewer_changed = 0; - should_return = 0; - - err1 = cur->show_menu (menu, nested); - grub_print_error (); - - if (menu_viewer_changed) - continue; - - err2 = grub_auth_check_authentication (NULL); - if (err2) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - continue; - } - - break; - } - - return err1; -} - -int -grub_menu_viewer_should_return (void) -{ - return should_return; -} - -static char * -menuviewer_write_hook (struct grub_env_var *var __attribute__ ((unused)), - const char *val) -{ - menu_viewer_changed = 1; - should_return = 1; - return grub_strdup (val); -} - -void -grub_menu_viewer_init (void) -{ - grub_register_variable_hook ("menuviewer", 0, menuviewer_write_hook); -} - diff --git a/normal/term.c b/normal/term.c new file mode 100644 index 000000000..b099ae84c --- /dev/null +++ b/normal/term.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +/* 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 ("/crypto.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; +} diff --git a/term/efi/console.c b/term/efi/console.c index f3845089c..dc07c401e 100644 --- a/term/efi/console.c +++ b/term/efi/console.c @@ -351,8 +351,7 @@ static struct grub_term_output grub_console_term_output = .setcolorstate = grub_console_setcolorstate, .setcolor = grub_console_setcolor, .getcolor = grub_console_getcolor, - .setcursor = grub_console_setcursor, - .flags = 0, + .setcursor = grub_console_setcursor }; void @@ -366,8 +365,8 @@ grub_console_init (void) return; } - grub_term_register_input ("console", &grub_console_term_input); - grub_term_register_output ("console", &grub_console_term_output); + grub_term_register_input_active ("console", &grub_console_term_input); + grub_term_register_output_active ("console", &grub_console_term_output); } void diff --git a/term/i386/pc/at_keyboard.c b/term/i386/pc/at_keyboard.c index cf30e7242..379cb3a4b 100644 --- a/term/i386/pc/at_keyboard.c +++ b/term/i386/pc/at_keyboard.c @@ -233,7 +233,11 @@ static struct grub_term_input grub_at_keyboard_term = GRUB_MOD_INIT(at_keyboard) { +#if defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) + grub_term_register_input_active ("at_keyboard", &grub_at_keyboard_term); +#else grub_term_register_input ("at_keyboard", &grub_at_keyboard_term); +#endif } GRUB_MOD_FINI(at_keyboard) diff --git a/term/i386/pc/console.c b/term/i386/pc/console.c index 66475d456..3c0fcccad 100644 --- a/term/i386/pc/console.c +++ b/term/i386/pc/console.c @@ -65,24 +65,19 @@ static struct grub_term_output grub_console_term_output = .setcolorstate = grub_console_setcolorstate, .setcolor = grub_console_setcolor, .getcolor = grub_console_getcolor, - .setcursor = grub_console_setcursor, - .flags = 0, + .setcursor = grub_console_setcursor }; void grub_console_init (void) { - grub_term_register_output ("console", &grub_console_term_output); - grub_term_register_input ("console", &grub_console_term_input); + grub_term_register_output_active ("console", &grub_console_term_output); + grub_term_register_input_active ("console", &grub_console_term_input); } void grub_console_fini (void) { - /* This is to make sure the console is restored to text mode before - we boot. */ - grub_term_set_current_output (&grub_console_term_output); - grub_term_unregister_input (&grub_console_term_input); grub_term_unregister_output (&grub_console_term_output); } diff --git a/term/i386/pc/serial.c b/term/i386/pc/serial.c index 3f1c6d062..12612efcd 100644 --- a/term/i386/pc/serial.c +++ b/term/i386/pc/serial.c @@ -30,6 +30,7 @@ #define TEXT_WIDTH 80 #define TEXT_HEIGHT 25 +static struct grub_term_output grub_serial_term_output; static unsigned int xpos, ypos; static unsigned int keep_track = 1; static unsigned int registered = 0; @@ -413,7 +414,7 @@ grub_serial_gotoxy (grub_uint8_t x, grub_uint8_t y) else { keep_track = 0; - grub_terminfo_gotoxy (x, y); + grub_terminfo_gotoxy (x, y, &grub_serial_term_output); keep_track = 1; xpos = x; @@ -425,7 +426,7 @@ static void grub_serial_cls (void) { keep_track = 0; - grub_terminfo_cls (); + grub_terminfo_cls (&grub_serial_term_output); keep_track = 1; xpos = ypos = 0; @@ -439,10 +440,10 @@ grub_serial_setcolorstate (const grub_term_color_state state) { case GRUB_TERM_COLOR_STANDARD: case GRUB_TERM_COLOR_NORMAL: - grub_terminfo_reverse_video_off (); + grub_terminfo_reverse_video_off (&grub_serial_term_output); break; case GRUB_TERM_COLOR_HIGHLIGHT: - grub_terminfo_reverse_video_on (); + grub_terminfo_reverse_video_on (&grub_serial_term_output); break; default: break; @@ -454,9 +455,9 @@ static void grub_serial_setcursor (const int on) { if (on) - grub_terminfo_cursor_on (); + grub_terminfo_cursor_on (&grub_serial_term_output); else - grub_terminfo_cursor_off (); + grub_terminfo_cursor_off (&grub_serial_term_output); } static struct grub_term_input grub_serial_term_input = diff --git a/term/i386/pc/vga_text.c b/term/i386/pc/vga_text.c index 170f74de8..01191cef0 100644 --- a/term/i386/pc/vga_text.c +++ b/term/i386/pc/vga_text.c @@ -163,12 +163,16 @@ static struct grub_term_output grub_vga_text_term = .setcolorstate = grub_console_setcolorstate, .setcolor = grub_console_setcolor, .getcolor = grub_console_getcolor, - .setcursor = grub_vga_text_setcursor, + .setcursor = grub_vga_text_setcursor }; GRUB_MOD_INIT(vga_text) { +#if defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) + grub_term_register_output_active ("vga_text", &grub_vga_text_term); +#else grub_term_register_output ("vga_text", &grub_vga_text_term); +#endif } GRUB_MOD_FINI(vga_text) diff --git a/term/ieee1275/ofconsole.c b/term/ieee1275/ofconsole.c index ab11e9fb2..f5db7c146 100644 --- a/term/ieee1275/ofconsole.c +++ b/term/ieee1275/ofconsole.c @@ -414,15 +414,14 @@ static struct grub_term_output grub_ofconsole_term_output = .setcolor = grub_ofconsole_setcolor, .getcolor = grub_ofconsole_getcolor, .setcursor = grub_ofconsole_setcursor, - .refresh = grub_ofconsole_refresh, - .flags = 0, + .refresh = grub_ofconsole_refresh }; void grub_console_init (void) { - grub_term_register_input ("ofconsole", &grub_ofconsole_term_input); - grub_term_register_output ("ofconsole", &grub_ofconsole_term_output); + grub_term_register_input_active ("ofconsole", &grub_ofconsole_term_input); + grub_term_register_output_active ("ofconsole", &grub_ofconsole_term_output); } void diff --git a/term/terminfo.c b/term/terminfo.c index 80ae9b100..a793564fd 100644 --- a/term/terminfo.c +++ b/term/terminfo.c @@ -108,52 +108,52 @@ grub_terminfo_set_current (const char *str) /* Wrapper for grub_putchar to write strings. */ static void -putstr (const char *str) +putstr (const char *str, grub_term_output_t oterm) { while (*str) - grub_putchar (*str++); + grub_putcode (*str++, oterm); } /* Move the cursor to the given position starting with "0". */ void -grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y) +grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y, grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.gotoxy, y, x)); + putstr (grub_terminfo_tparm (term.gotoxy, y, x), oterm); } /* Clear the screen. */ void -grub_terminfo_cls (void) +grub_terminfo_cls (grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.cls)); + putstr (grub_terminfo_tparm (term.cls), oterm); } /* Set reverse video mode on. */ void -grub_terminfo_reverse_video_on (void) +grub_terminfo_reverse_video_on (grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.reverse_video_on)); + putstr (grub_terminfo_tparm (term.reverse_video_on), oterm); } /* Set reverse video mode off. */ void -grub_terminfo_reverse_video_off (void) +grub_terminfo_reverse_video_off (grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.reverse_video_off)); + putstr (grub_terminfo_tparm (term.reverse_video_off), oterm); } /* Show cursor. */ void -grub_terminfo_cursor_on (void) +grub_terminfo_cursor_on (grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.cursor_on)); + putstr (grub_terminfo_tparm (term.cursor_on), oterm); } /* Hide cursor. */ void -grub_terminfo_cursor_off (void) +grub_terminfo_cursor_off (grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.cursor_off)); + putstr (grub_terminfo_tparm (term.cursor_off), oterm); } /* GRUB Command. */ diff --git a/util/console.c b/util/console.c index 9d8bb1a63..40ee3a638 100644 --- a/util/console.c +++ b/util/console.c @@ -367,17 +367,14 @@ static struct grub_term_output grub_ncurses_term_output = .setcolor = grub_ncurses_setcolor, .getcolor = grub_ncurses_getcolor, .setcursor = grub_ncurses_setcursor, - .refresh = grub_ncurses_refresh, - .flags = 0, + .refresh = grub_ncurses_refresh }; void grub_console_init (void) { - grub_term_register_output ("console", &grub_ncurses_term_output); - grub_term_register_input ("console", &grub_ncurses_term_input); - grub_term_set_current_output (&grub_ncurses_term_output); - grub_term_set_current_input (&grub_ncurses_term_input); + grub_term_register_output_active ("console", &grub_ncurses_term_output); + grub_term_register_input_active ("console", &grub_ncurses_term_input); } void diff --git a/util/grub-editenv.c b/util/grub-editenv.c index 68fb23b15..e75892430 100644 --- a/util/grub-editenv.c +++ b/util/grub-editenv.c @@ -46,9 +46,6 @@ grub_refresh (void) fflush (stdout); } -struct grub_handler_class grub_term_input_class; -struct grub_handler_class grub_term_output_class; - int grub_getkey (void) { diff --git a/util/grub-mkpasswd-pbkdf2.c b/util/grub-mkpasswd-pbkdf2.c new file mode 100644 index 000000000..2f7c5efaa --- /dev/null +++ b/util/grub-mkpasswd-pbkdf2.c @@ -0,0 +1,342 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1992-1999,2001,2003,2004,2005,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 . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "progname.h" + +/* Few functions to make crypto happy. */ +void * +grub_memmove (void *dest, const void *src, grub_size_t n) +{ + return memmove (dest, src, n); +} + +void * +grub_memset (void *s, int c, grub_size_t n) +{ + return memset (s, c, n); +} + +int +grub_vprintf (const char *fmt, va_list args) +{ + return vprintf (fmt, args); +} + +int +grub_vsprintf (char *str, const char *fmt, va_list args) +{ + return vsprintf (str, fmt, args); +} + +void +grub_abort (void) +{ + abort (); +} + +static struct option options[] = + { + {"iteration_count", required_argument, 0, 'c'}, + {"buflen", required_argument, 0, 'l'}, + {"saltlen", required_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try ``grub-scrypt --help'' for more information.\n"); + else + printf ("\ +Usage: grub-scrypt [OPTIONS]\n\ +\nOptions:\n\ + -c number, --iteration-count=number Number of PBKDF2 iterations\n\ + -l number, --buflen=number Length of generated hash\n\ + -s number, --salt=number Length of salt\n\ +\n\ +Report bugs to <%s>.\n", PACKAGE_BUGREPORT); + + exit (status); +} + +static void +hexify (char *hex, grub_uint8_t *bin, grub_size_t n) +{ + while (n--) + { + if (((*bin & 0xf0) >> 4) < 10) + *hex = ((*bin & 0xf0) >> 4) + '0'; + else + *hex = ((*bin & 0xf0) >> 4) + 'A' - 10; + hex++; + + if ((*bin & 0xf) < 10) + *hex = (*bin & 0xf) + '0'; + else + *hex = (*bin & 0xf) + 'A' - 10; + hex++; + bin++; + } + *hex = 0; +} + +int +main (int argc, char *argv[]) +{ + unsigned int c = 10000, buflen = 64, saltlen = 64; + char *pass1, *pass2; + char *bufhex, *salthex; + gcry_err_code_t gcry_err; + grub_uint8_t *buf, *salt; + ssize_t nr; + FILE *in, *out; + struct termios s, t; + int tty_changed; + + set_program_name (argv[0]); + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "c:l:s:hvV", options, 0); + + if (c == -1) + break; + + switch (c) + { + case 'c': + c = strtoul (optarg, NULL, 0); + break; + + case 'l': + buflen = strtoul (optarg, NULL, 0); + break; + + case 's': + saltlen = strtoul (optarg, NULL, 0); + break; + + case 'h': + usage (0); + return 0; + + case 'V': + printf ("%s (%s) %s\n", program_name, + PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + default: + usage (1); + return 1; + } + } + + bufhex = malloc (buflen * 2 + 1); + if (!bufhex) + grub_util_error ("Out of memory"); + buf = malloc (buflen); + if (!buf) + { + free (bufhex); + grub_util_error ("Out of memory"); + } + + salt = malloc (saltlen); + if (!salt) + { + free (bufhex); + free (buf); + grub_util_error ("Out of memory"); + } + salthex = malloc (saltlen * 2 + 1); + if (!salthex) + { + free (salt); + free (bufhex); + free (buf); + grub_util_error ("Out of memory"); + } + + /* Disable echoing. Based on glibc. */ + in = fopen ("/dev/tty", "w+c"); + if (in == NULL) + { + in = stdin; + out = stderr; + } + else + out = in; + + if (tcgetattr (fileno (in), &t) == 0) + { + /* Save the old one. */ + s = t; + /* Tricky, tricky. */ + t.c_lflag &= ~(ECHO|ISIG); + tty_changed = (tcsetattr (fileno (in), TCSAFLUSH, &t) == 0); + } + else + tty_changed = 0; + + printf ("Enter password: "); + pass1 = NULL; + { + grub_size_t n; + nr = getline (&pass1, &n, stdin); + } + if (nr < 0 || !pass1) + { + free (buf); + free (bufhex); + free (salthex); + free (salt); + /* Restore the original setting. */ + if (tty_changed) + (void) tcsetattr (fileno (in), TCSAFLUSH, &s); + grub_util_error ("Failure to read password"); + } + if (nr >= 1 && pass1[nr-1] == '\n') + pass1[nr-1] = 0; + + printf ("\nReenter password: "); + pass2 = NULL; + { + grub_size_t n; + nr = getline (&pass2, &n, stdin); + } + /* Restore the original setting. */ + if (tty_changed) + (void) tcsetattr (fileno (in), TCSAFLUSH, &s); + printf ("\n"); + + if (nr < 0 || !pass2) + { + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + grub_util_error ("Failure to read password"); + } + if (nr >= 1 && pass2[nr-1] == '\n') + pass2[nr-1] = 0; + + if (strcmp (pass1, pass2) != 0) + { + memset (pass1, 0, strlen (pass1)); + memset (pass2, 0, strlen (pass2)); + free (pass1); + free (pass2); + free (buf); + free (bufhex); + free (salthex); + free (salt); + grub_util_error ("Passwords don't match"); + } + memset (pass2, 0, strlen (pass2)); + free (pass2); + +#if ! defined (__linux__) && ! defined (__FreeBSD__) + printf ("WARNING: your random generator isn't known to be secure\n"); +#endif + + { + FILE *f; + size_t rd; + f = fopen ("/dev/random", "rb"); + if (!f) + { + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + fclose (f); + grub_util_error ("Couldn't retrieve random data for salt"); + } + rd = fread (salt, 1, saltlen, f); + if (rd != saltlen) + { + fclose (f); + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + fclose (f); + grub_util_error ("Couldn't retrieve random data for salt"); + } + fclose (f); + } + + gcry_err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, + (grub_uint8_t *) pass1, strlen (pass1), + salt, saltlen, + c, buf, buflen); + memset (pass1, 0, strlen (pass1)); + free (pass1); + + if (gcry_err) + { + memset (buf, 0, buflen); + memset (bufhex, 0, 2 * buflen); + free (buf); + free (bufhex); + memset (salt, 0, saltlen); + memset (salthex, 0, 2 * saltlen); + free (salt); + free (salthex); + grub_util_error ("Cryptographic error number %d", gcry_err); + } + + hexify (bufhex, buf, buflen); + hexify (salthex, salt, saltlen); + + printf ("Your PBKDF2 is grub.pbkdf2.sha512.%d.%s.%s\n", c, salthex, bufhex); + memset (buf, 0, buflen); + memset (bufhex, 0, 2 * buflen); + free (buf); + free (bufhex); + memset (salt, 0, saltlen); + memset (salthex, 0, 2 * saltlen); + free (salt); + free (salthex); + + return 0; +} diff --git a/util/import_gcry.py b/util/import_gcry.py index 698e6cffe..d71924d53 100644 --- a/util/import_gcry.py +++ b/util/import_gcry.py @@ -61,12 +61,30 @@ mdblocksizes = {"_gcry_digest_spec_crc32" : 64, "_gcry_digest_spec_tiger" : 64, "_gcry_digest_spec_whirlpool" : 64} +cryptolist = open (os.path.join (cipher_dir_out, "crypto.lst"), "w") + +# rijndael is the only cipher using aliases. So no need for mangling, just +# hardcode it +cryptolist.write ("RIJNDAEL: gcry_rijndael\n"); +cryptolist.write ("RIJNDAEL192: gcry_rijndael\n"); +cryptolist.write ("RIJNDAEL256: gcry_rijndael\n"); +cryptolist.write ("AES128: gcry_rijndael\n"); +cryptolist.write ("AES-128: gcry_rijndael\n"); +cryptolist.write ("AES-192: gcry_rijndael\n"); +cryptolist.write ("AES-256: gcry_rijndael\n"); + for cipher_file in cipher_files: infile = os.path.join (cipher_dir_in, cipher_file) outfile = os.path.join (cipher_dir_out, cipher_file) if cipher_file == "ChangeLog": continue chlognew = " * %s" % cipher_file + if re.match ("(Manifest|Makefile\.am|ac\.c|cipher\.c|hash-common\.c|hmac-tests\.c|md\.c|pubkey\.c)$", cipher_file): + chlog = "%s%s: Removed\n" % (chlog, chlognew) + continue + # Autogenerated files. Not even worth mentionning in ChangeLog + if re.match ("Makefile\.in$", cipher_file): + continue nch = False if re.match (".*\.[ch]$", cipher_file): isc = re.match (".*\.c$", cipher_file) @@ -80,8 +98,21 @@ for cipher_file in cipher_files: skip = False skip2 = False ismd = False + iscryptostart = False iscomma = False + isglue = False + skip_statement = False + if isc: + modname = cipher_file [0:len(cipher_file) - 2] + if re.match (".*-glue$", modname): + modname = modname.replace ("-glue", "") + isglue = True + modname = "gcry_%s" % modname for line in f: + if skip_statement: + if not re.search (";", line) is None: + skip_statement = False + continue if skip: if line[0] == "}": skip = False @@ -90,6 +121,12 @@ for cipher_file in cipher_files: if not re.search (" *};", line) is None: skip2 = False continue + if iscryptostart: + s = re.search (" *\"([A-Z0-9_a-z]*)\"", line) + if not s is None: + sg = s.groups()[0] + cryptolist.write (("%s: %s\n") % (sg, modname)) + iscryptostart = False if ismd: if not re.search (" *};", line) is None: if not mdblocksizes.has_key (mdname): @@ -100,10 +137,22 @@ for cipher_file in cipher_files: fw.write (" .blocksize = %s\n" % mdblocksizes [mdname]) ismd = False iscomma = not re.search (",$", line) is None + # Used only for selftests. + m = re.match ("(static byte|static unsigned char) (weak_keys_chksum)\[[0-9]*\] =", line) + if not m is None: + skip = True + fname = m.groups ()[1] + chmsg = "(%s): Removed." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue if hold: hold = False # We're optimising for size. - if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer)", line) is None: + if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer|tripledes_set2keys|do_tripledes_set_extra_info)", line) is None: skip = True fname = re.match ("[a-zA-Z0-9_]*", line).group () chmsg = "(%s): Removed." % fname @@ -127,16 +176,20 @@ for cipher_file in cipher_files: continue m = re.match ("gcry_cipher_spec_t", line) if isc and not m is None: + assert (not iscryptostart) ciphername = line [len ("gcry_cipher_spec_t"):].strip () ciphername = re.match("[a-zA-Z0-9_]*",ciphername).group () ciphernames.append (ciphername) + iscryptostart = True m = re.match ("gcry_md_spec_t", line) if isc and not m is None: assert (not ismd) + assert (not iscryptostart) mdname = line [len ("gcry_md_spec_t"):].strip () mdname = re.match("[a-zA-Z0-9_]*",mdname).group () mdnames.append (mdname) ismd = True + iscryptostart = True m = re.match ("static const char \*selftest.*;$", line) if not m is None: fname = line[len ("static const char \*"):] @@ -148,11 +201,18 @@ for cipher_file in cipher_files: chlognew = "%s %s" % (chlognew, chmsg) nch = True continue - m = re.match ("(static const char( |)\*|static gpg_err_code_t|void)$", line) + m = re.match ("(static const char( |)\*|static gpg_err_code_t|void|static int|static gcry_err_code_t)$", line) if not m is None: hold = True holdline = line continue + m = re.match ("static int tripledes_set2keys \(.*\);", line) + if not m is None: + continue + m = re.match ("static int tripledes_set2keys \(", line) + if not m is None: + skip_statement = True + continue m = re.match ("cipher_extra_spec_t", line) if isc and not m is None: skip2 = True @@ -179,14 +239,11 @@ for cipher_file in cipher_files: continue fw.write (line) if len (ciphernames) > 0 or len (mdnames) > 0: - modname = cipher_file [0:len(cipher_file) - 2] - if re.match (".*-glue$", modname): - modfiles = "libgcrypt-grub/cipher/%s libgcrypt-grub/cipher/%s" \ + if isglue: + modfiles = "lib/libgcrypt-grub/cipher/%s lib/libgcrypt-grub/cipher/%s" \ % (cipher_file, cipher_file.replace ("-glue.c", ".c")) - modname = modname.replace ("-glue", "") else: - modfiles = "libgcrypt-grub/cipher/%s" % cipher_file - modname = "gcry_%s" % modname + modfiles = "lib/libgcrypt-grub/cipher/%s" % cipher_file chmsg = "(GRUB_MOD_INIT(%s)): New function\n" % modname if nch: chlognew = "%s\n %s" % (chlognew, chmsg) @@ -220,7 +277,7 @@ for cipher_file in cipher_files: conf.write ("pkglib_MODULES += %s.mod\n" % modname) conf.write ("%s_mod_SOURCES = %s\n" %\ (modname, modfiles)) - conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-missing-field-initializers -Wno-error\n" % modname) + conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap\n" % modname) conf.write ("%s_mod_LDFLAGS = $(COMMON_LDFLAGS)\n\n" % modname) elif isc and cipher_file != "camellia.c": print ("WARNING: C file isn't a module: %s" % cipher_file) @@ -229,26 +286,22 @@ for cipher_file in cipher_files: if nch: chlog = "%s%s\n" % (chlog, chlognew) continue - if re.match ("(Manifest|Makefile\.am)$", cipher_file): - chlog = "%s%sRemoved\n" % (chlog, chlognew) - continue - # Autogenerated files. Not even worth mentionning in ChangeLog - if re.match ("Makefile\.in$", cipher_file): - chlog = "%s%sRemoved\n" % (chlog, chlognew) - continue chlog = "%s%sSkipped unknown file\n" % (chlog, chlognew) print ("WARNING: unknown file %s" % cipher_file) +cryptolist.close () +chlog = "%s * crypto.lst: New file.\n" % chlog + outfile = os.path.join (cipher_dir_out, "types.h") fw=open (outfile, "w") fw.write ("#include \n") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * types.h: New file.\n" % chlog fw.close () outfile = os.path.join (cipher_dir_out, "memory.h") fw=open (outfile, "w") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * memory.h: New file.\n" % chlog fw.close () @@ -256,13 +309,13 @@ fw.close () outfile = os.path.join (cipher_dir_out, "cipher.h") fw=open (outfile, "w") fw.write ("#include \n") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * cipher.h: Likewise.\n" % chlog fw.close () outfile = os.path.join (cipher_dir_out, "g10lib.h") fw=open (outfile, "w") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * g10lib.h: Likewise.\n" % chlog fw.close ()