From: Vladimir 'phcoder' Serbinenko Date: Wed, 20 Jan 2010 06:36:17 +0000 (+0100) Subject: merge mainline into asprintf X-Git-Tag: 1.98~151^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2d49abe9e7f4fe15cac238575423975577d106e6;p=thirdparty%2Fgrub.git merge mainline into asprintf --- 2d49abe9e7f4fe15cac238575423975577d106e6 diff --cc commands/hashsum.c index 000000000,60e17447b..a098ab7af mode 000000,100644..100644 --- a/commands/hashsum.c +++ b/commands/hashsum.c @@@ -1,0 -1,278 +1,276 @@@ + /* + * 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); ++ filename = grub_asprintf ("%s/%s", prefix, p); + 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 --cc commands/help.c index 9f0ee7528,9234a3697..a19b395cd --- a/commands/help.c +++ b/commands/help.c @@@ -38,19 -41,51 +41,49 @@@ grub_cmd_help (grub_extcmd_t ext __attr if ((cmd->prio & GRUB_PRIO_LIST_FLAG_ACTIVE) && (cmd->flags & GRUB_COMMAND_FLAG_CMDLINE)) { - char description[GRUB_TERM_WIDTH / 2]; - const char* summary_translated = _(cmd->summary); - int desclen = grub_strlen (summary_translated); - - /* 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, summary_translated, - (desclen < GRUB_TERM_WIDTH / 2 - 1 - ? desclen : GRUB_TERM_WIDTH / 2 - 1)); - - grub_printf ("%s%s", description, (cnt++) % 2 ? "\n" : " "); + struct grub_term_output *term; + const char *summary_translated = _(cmd->summary); + char *command_help; + grub_uint32_t *unicode_command_help; + grub_uint32_t *unicode_last_position; - - command_help = grub_malloc (grub_strlen (cmd->name) + - sizeof (" ") - 1 + - grub_strlen (summary_translated)); + - grub_sprintf(command_help, "%s %s", cmd->name, summary_translated); ++ command_help = grub_asprintf ("%s %s", cmd->name, summary_translated); ++ if (!command_help) ++ return 1; + + grub_utf8_to_ucs4_alloc (command_help, &unicode_command_help, + &unicode_last_position); + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + unsigned stringwidth; + grub_uint32_t *unicode_last_screen_position; + + unicode_last_screen_position = unicode_command_help; + + stringwidth = 0; + + while (unicode_last_screen_position < unicode_last_position && + stringwidth < ((grub_term_width (term) / 2) - 2)) + { + stringwidth + += grub_term_getcharwidth (term, + *unicode_last_screen_position); + unicode_last_screen_position++; + } + + grub_print_ucs4 (unicode_command_help, + unicode_last_screen_position, term); + if (!(cnt % 2)) + grub_print_spaces (term, grub_term_width (term) / 2 + - stringwidth); + } + if (cnt % 2) + grub_printf ("\n"); + cnt++; + + grub_free (command_help); + grub_free (unicode_command_help); } return 0; } diff --cc commands/xnu_uuid.c index 735d999a2,b6f2b2604..382d3196b --- a/commands/xnu_uuid.c +++ b/commands/xnu_uuid.c @@@ -345,22 -53,26 +53,26 @@@ grub_cmd_xnu_uuid (grub_command_t cmd _ 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, + grub_snprintf (uuid_string, sizeof (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], - (unsigned int) xnu_uuid[2], (unsigned int) xnu_uuid[3], - (unsigned int) xnu_uuid[4], (unsigned int) xnu_uuid[5], - (unsigned int) ((xnu_uuid[6] & 0xf) | 0x30), - (unsigned int) xnu_uuid[7], - (unsigned int) ((xnu_uuid[8] & 0x3f) | 0x80), - (unsigned int) xnu_uuid[9], - (unsigned int) xnu_uuid[10], (unsigned int) xnu_uuid[11], - (unsigned int) xnu_uuid[12], (unsigned int) xnu_uuid[13], - (unsigned int) xnu_uuid[14], (unsigned int) xnu_uuid[15]); + "%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], + (unsigned int) xnu_uuid[2], (unsigned int) xnu_uuid[3], + (unsigned int) xnu_uuid[4], (unsigned int) xnu_uuid[5], + (unsigned int) ((xnu_uuid[6] & 0xf) | 0x30), + (unsigned int) xnu_uuid[7], + (unsigned int) ((xnu_uuid[8] & 0x3f) | 0x80), + (unsigned int) xnu_uuid[9], + (unsigned int) xnu_uuid[10], (unsigned int) xnu_uuid[11], + (unsigned int) xnu_uuid[12], (unsigned int) xnu_uuid[13], + (unsigned int) xnu_uuid[14], (unsigned int) xnu_uuid[15]); for (ptr = uuid_string; *ptr; ptr++) *ptr = grub_toupper (*ptr); if (argc == 1) diff --cc include/grub/font.h index 8a5f3ac7d,2129c30b3..333d3e2b0 --- a/include/grub/font.h +++ b/include/grub/font.h @@@ -74,7 -75,7 +75,8 @@@ void grub_font_loader_init (void) /* Load a font and add it to the beginning of the global font list. Returns: 0 upon success; nonzero upon failure. */ - int grub_font_load (const char *filename); -int grub_font_load (grub_file_t file); ++int ++grub_font_load (const char *filename); /* Get the font that has the specified name. Font names are in the form "Family Name Bold Italic 14", where Bold and Italic are optional. diff --cc include/grub/misc.h index f4d722081,48eb1fcdd..2c1817492 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@@ -179,20 -195,15 +195,20 @@@ void EXPORT_FUNC(grub_real_dprintf) (co const char *condition, const char *fmt, ...) __attribute__ ((format (printf, 4, 5))); int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args); -int EXPORT_FUNC(grub_sprintf) (char *str, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); -int EXPORT_FUNC(grub_vsprintf) (char *str, const char *fmt, va_list args); +int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...) + __attribute__ ((format (printf, 3, 4))); +int EXPORT_FUNC(grub_vsnprintf) (char *str, grub_size_t n, const char *fmt, + va_list args); +char *EXPORT_FUNC(grub_asprintf) (const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); +char *EXPORT_FUNC(grub_avsprintf) (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 --cc kern/device.c index d1692baa0,7d3577051..3727ddcd9 --- a/kern/device.c +++ b/kern/device.c @@@ -139,7 -138,8 +139,7 @@@ grub_device_iterate (int (*hook) (cons if (! partition_name) return 1; - p = grub_malloc (sizeof (p->next)); - p = grub_malloc (sizeof (*p) + grub_strlen (disk->name) + 1 + - grub_strlen (partition_name) + 1); ++ p = grub_malloc (sizeof (*p)); if (!p) { grub_free (partition_name); diff --cc kern/err.c index 5a63b4187,1a881db25..8272467f5 --- a/kern/err.c +++ b/kern/err.c @@@ -44,7 -45,7 +45,7 @@@ grub_error (grub_err_t n, const char *f grub_errno = n; va_start (ap, fmt); - grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), fmt, ap); - grub_vsprintf (grub_errmsg, _(fmt), ap); ++ grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap); va_end (ap); return n; diff --cc loader/i386/linux.c index 93f3da058,a81e84135..c764dad25 --- a/loader/i386/linux.c +++ b/loader/i386/linux.c @@@ -517,10 -519,12 +519,10 @@@ grub_linux_boot (void May change in future if we have modes without framebuffer. */ if (modevar && *modevar != 0) { - tmp = grub_malloc (grub_strlen (modevar) - + sizeof (";text")); + tmp = grub_asprintf ("%s;text", modevar); if (! tmp) return grub_errno; - err = grub_video_set_mode (tmp, 0); - grub_sprintf (tmp, "%s;text", modevar); + err = grub_video_set_mode (tmp, 0, 0); grub_free (tmp); } else diff --cc loader/i386/multiboot.c index a52b8d5d6,d06f18692..16c19b6d1 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@@ -335,53 -240,37 +240,40 @@@ grub_multiboot (int argc, char *argv[] else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) goto fail; - /* This provides alignment for the MBI, the memory map and the backward relocator. */ - boot_loader_name_length += (0x04 - ((unsigned long) mbi_addr (grub_multiboot_payload_dest) & 0x03)); - - mbi = mbi_addr (grub_multiboot_payload_orig); - mbi_dest = mbi_addr (grub_multiboot_payload_dest); - grub_memset (mbi, 0, sizeof (struct multiboot_info)); - mbi->mmap_length = mmap_length; - - grub_fill_multiboot_mmap (mmap_addr (grub_multiboot_payload_orig)); - - /* FIXME: grub_uint32_t will break for addresses above 4 GiB, but is mandated - by the spec. Is there something we can do about it? */ - mbi->mmap_addr = (grub_uint32_t) mmap_addr (grub_multiboot_payload_dest); - mbi->flags |= MULTIBOOT_INFO_MEM_MAP; - - /* Convert from bytes to kilobytes. */ - mbi->mem_lower = grub_mmap_get_lower () / 1024; - mbi->mem_upper = grub_mmap_get_upper () / 1024; - mbi->flags |= MULTIBOOT_INFO_MEMORY; - - cmdline = p = cmdline_addr (grub_multiboot_payload_orig); - if (! cmdline) - goto fail; - - for (i = 0; i < cmdline_argc; i++) + if (header->flags & MULTIBOOT_VIDEO_MODE) { - p = grub_stpcpy (p, cmdline_argv[i]); - *(p++) = ' '; + switch (header->mode_type) + { + case 1: + grub_env_set ("gfxpayload", "text"); + break; + + case 0: + { - char buf[sizeof ("XXXXXXXXXXxXXXXXXXXXXxXXXXXXXXXX,XXXXXXXXXXxXXXXXXXXXX,auto")]; ++ char *buf; + if (header->depth && header->width && header->height) - grub_sprintf (buf, "%dx%dx%d,%dx%d,auto", header->width, - header->height, header->depth, header->width, - header->height); ++ buf = grub_asprintf ("%dx%dx%d,%dx%d,auto", header->width, ++ header->height, header->depth, header->width, ++ header->height); + else if (header->width && header->height) - grub_sprintf (buf, "%dx%d,auto", header->width, header->height); ++ buf = grub_asprintf ("%dx%d,auto", header->width, header->height); + else - grub_sprintf (buf, "auto"); ++ buf = grub_strdup ("auto"); + ++ if (!buf) ++ goto fail; + grub_env_set ("gfxpayload", buf); ++ grub_free (buf); + break; + } + } } - /* Remove the space after the last word. */ - if (p != cmdline) - p--; - *p = 0; - - mbi->flags |= MULTIBOOT_INFO_CMDLINE; - mbi->cmdline = (grub_uint32_t) cmdline_addr (grub_multiboot_payload_dest); + grub_multiboot_set_accepts_video (!!(header->flags & MULTIBOOT_VIDEO_MODE)); + grub_multiboot_set_bootdev (); - grub_strcpy (boot_loader_name_addr (grub_multiboot_payload_orig), PACKAGE_STRING); - mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; - mbi->boot_loader_name = (grub_uint32_t) boot_loader_name_addr (grub_multiboot_payload_dest); - - if (grub_multiboot_get_bootdev (&mbi->boot_device)) - mbi->flags |= MULTIBOOT_INFO_BOOTDEV; - - grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1); + grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0); fail: if (file) diff --cc loader/i386/multiboot_mbi.c index 000000000,5154a64df..4493c03c7 mode 000000,100644..100644 --- a/loader/i386/multiboot_mbi.c +++ b/loader/i386/multiboot_mbi.c @@@ -1,0 -1,475 +1,473 @@@ + /* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 + #ifdef GRUB_MACHINE_PCBIOS + #include + #endif + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) + #include + #define DEFAULT_VIDEO_MODE "text" + #define HAS_VGA_TEXT 1 + #else + #define DEFAULT_VIDEO_MODE "auto" + #define HAS_VGA_TEXT 0 + #endif + + struct module + { + struct module *next; + grub_addr_t start; + grub_size_t size; + char *cmdline; + int cmdline_size; + }; + + struct module *modules, *modules_last; + static grub_size_t cmdline_size; + static grub_size_t total_modcmd; + static unsigned modcnt; + static char *cmdline = NULL; + static grub_uint32_t bootdev; + static int bootdev_set; + static int accepts_video; + + void + grub_multiboot_set_accepts_video (int val) + { + accepts_video = val; + } + + /* Return the length of the Multiboot mmap that will be needed to allocate + our platform's map. */ + static grub_uint32_t + grub_get_multiboot_mmap_len (void) + { + grub_size_t count = 0; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + grub_uint32_t type __attribute__ ((unused))) + { + count++; + return 0; + } + + grub_mmap_iterate (hook); + + return count * sizeof (struct multiboot_mmap_entry); + } + + grub_size_t + grub_multiboot_get_mbi_size (void) + { + return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4) + + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd + + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_len () + + 256 * sizeof (struct multiboot_color); + } + + /* Fill previously allocated Multiboot mmap. */ + static void + grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) + { + struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + { + mmap_entry->addr = addr; + mmap_entry->len = size; + switch (type) + { + case GRUB_MACHINE_MEMORY_AVAILABLE: + mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE; + break; + + #ifdef GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE + case GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE: + mmap_entry->type = MULTIBOOT_MEMORY_ACPI_RECLAIMABLE; + break; + #endif + + #ifdef GRUB_MACHINE_MEMORY_NVS + case GRUB_MACHINE_MEMORY_NVS: + mmap_entry->type = MULTIBOOT_MEMORY_NVS; + break; + #endif + + default: + mmap_entry->type = MULTIBOOT_MEMORY_RESERVED; + break; + } + mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size); + mmap_entry++; + + return 0; + } + + grub_mmap_iterate (hook); + } + + static grub_err_t + set_video_mode (void) + { + grub_err_t err; + const char *modevar; + + if (accepts_video || !HAS_VGA_TEXT) + { + modevar = grub_env_get ("gfxpayload"); + if (! modevar || *modevar == 0) + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); + else + { + char *tmp; - tmp = grub_malloc (grub_strlen (modevar) - + sizeof (DEFAULT_VIDEO_MODE) + 1); ++ tmp = grub_asprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); + if (! tmp) + return grub_errno; - grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); + err = grub_video_set_mode (tmp, 0, 0); + grub_free (tmp); + } + } + else + err = grub_video_set_mode ("text", 0, 0); + + return err; + } + + static grub_err_t + retrieve_video_parameters (struct multiboot_info *mbi, + grub_uint8_t *ptrorig, grub_uint32_t ptrdest) + { + grub_err_t err; + struct grub_video_mode_info mode_info; + void *framebuffer; + grub_video_driver_id_t driv_id; + struct grub_video_palette_data palette[256]; + + err = set_video_mode (); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + + grub_video_get_palette (0, ARRAY_SIZE (palette), palette); + + driv_id = grub_video_get_driver_id (); + if (driv_id == GRUB_VIDEO_DRIVER_NONE) + return GRUB_ERR_NONE; + + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); + if (err) + return err; + + mbi->framebuffer_addr = (grub_addr_t) framebuffer; + mbi->framebuffer_pitch = mode_info.pitch; + + mbi->framebuffer_width = mode_info.width; + mbi->framebuffer_height = mode_info.height; + + mbi->framebuffer_bpp = mode_info.bpp; + + if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) + { + struct multiboot_color *mb_palette; + unsigned i; + mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED; + mbi->framebuffer_palette_addr = ptrdest; + mbi->framebuffer_palette_num_colors = mode_info.number_of_colors; + if (mbi->framebuffer_palette_num_colors > ARRAY_SIZE (palette)) + mbi->framebuffer_palette_num_colors = ARRAY_SIZE (palette); + mb_palette = (struct multiboot_color *) ptrorig; + for (i = 0; i < mbi->framebuffer_palette_num_colors; i++) + { + mb_palette[i].red = palette[i].r; + mb_palette[i].green = palette[i].g; + mb_palette[i].blue = palette[i].b; + } + ptrorig += mbi->framebuffer_palette_num_colors + * sizeof (struct multiboot_color); + ptrdest += mbi->framebuffer_palette_num_colors + * sizeof (struct multiboot_color); + } + else + { + mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + mbi->framebuffer_red_field_position = mode_info.green_field_pos; + mbi->framebuffer_red_mask_size = mode_info.green_mask_size; + mbi->framebuffer_green_field_position = mode_info.green_field_pos; + mbi->framebuffer_green_mask_size = mode_info.green_mask_size; + mbi->framebuffer_blue_field_position = mode_info.blue_field_pos; + mbi->framebuffer_blue_mask_size = mode_info.blue_mask_size; + } + + mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO; + + return GRUB_ERR_NONE; + } + + grub_err_t + grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, + grub_size_t bufsize) + { + grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off; + grub_uint32_t ptrdest = dest + buf_off; + struct multiboot_info *mbi; + struct multiboot_mod_list *modlist; + unsigned i; + struct module *cur; + grub_size_t mmap_size; + grub_err_t err; + + if (bufsize < grub_multiboot_get_mbi_size ()) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + + mbi = (struct multiboot_info *) ptrorig; + ptrorig += sizeof (*mbi); + ptrdest += sizeof (*mbi); + grub_memset (mbi, 0, sizeof (*mbi)); + + grub_memcpy (ptrorig, cmdline, cmdline_size); + mbi->flags |= MULTIBOOT_INFO_CMDLINE; + mbi->cmdline = ptrdest; + ptrorig += ALIGN_UP (cmdline_size, 4); + ptrdest += ALIGN_UP (cmdline_size, 4); + + grub_memcpy (ptrorig, PACKAGE_STRING, sizeof(PACKAGE_STRING)); + mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; + mbi->boot_loader_name = ptrdest; + ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4); + ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4); + + if (modcnt) + { + mbi->flags |= MULTIBOOT_INFO_MODS; + mbi->mods_addr = ptrdest; + mbi->mods_count = modcnt; + modlist = (struct multiboot_mod_list *) ptrorig; + ptrorig += modcnt * sizeof (struct multiboot_mod_list); + ptrdest += modcnt * sizeof (struct multiboot_mod_list); + + for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) + { + modlist[i].mod_start = cur->start; + modlist[i].mod_end = modlist[i].mod_start + cur->size; + modlist[i].cmdline = ptrdest; + grub_memcpy (ptrorig, cur->cmdline, cur->cmdline_size); + ptrorig += ALIGN_UP (cur->cmdline_size, 4); + ptrdest += ALIGN_UP (cur->cmdline_size, 4); + } + } + else + { + mbi->mods_addr = 0; + mbi->mods_count = 0; + } + + mmap_size = grub_get_multiboot_mmap_len (); + grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig); + mbi->mmap_length = mmap_size; + mbi->mmap_addr = ptrdest; + mbi->flags |= MULTIBOOT_INFO_MEM_MAP; + ptrorig += mmap_size; + ptrdest += mmap_size; + + /* Convert from bytes to kilobytes. */ + mbi->mem_lower = grub_mmap_get_lower () / 1024; + mbi->mem_upper = grub_mmap_get_upper () / 1024; + mbi->flags |= MULTIBOOT_INFO_MEMORY; + + if (bootdev_set) + { + mbi->boot_device = bootdev; + mbi->flags |= MULTIBOOT_INFO_BOOTDEV; + } + + err = retrieve_video_parameters (mbi, ptrorig, ptrdest); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + + return GRUB_ERR_NONE; + } + + void + grub_multiboot_free_mbi (void) + { + struct module *cur, *next; + + cmdline_size = 0; + total_modcmd = 0; + modcnt = 0; + grub_free (cmdline); + cmdline = NULL; + bootdev_set = 0; + + for (cur = modules; cur; cur = next) + { + next = cur->next; + grub_free (cur->cmdline); + grub_free (cur); + } + modules = NULL; + modules_last = NULL; + } + + grub_err_t + grub_multiboot_init_mbi (int argc, char *argv[]) + { + grub_ssize_t len = 0; + char *p; + int i; + + grub_multiboot_free_mbi (); + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + if (len == 0) + len = 1; + + cmdline = p = grub_malloc (len); + if (! cmdline) + return grub_errno; + cmdline_size = len; + + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + if (p != cmdline) + p--; + *p = '\0'; + + return GRUB_ERR_NONE; + } + + grub_err_t + grub_multiboot_add_module (grub_addr_t start, grub_size_t size, + int argc, char *argv[]) + { + struct module *newmod; + char *p; + grub_ssize_t len = 0; + int i; + + newmod = grub_malloc (sizeof (*newmod)); + if (!newmod) + return grub_errno; + newmod->start = start; + newmod->size = size; + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + + if (len == 0) + len = 1; + + newmod->cmdline = p = grub_malloc (len); + if (! newmod->cmdline) + { + grub_free (newmod); + return grub_errno; + } + newmod->cmdline_size = len; + total_modcmd += ALIGN_UP (len, 4); + + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + if (p != newmod->cmdline) + p--; + *p = '\0'; + + if (modules_last) + modules_last->next = newmod; + else + { + modules = newmod; + modules_last->next = NULL; + } + modules_last = newmod; + + modcnt++; + + return GRUB_ERR_NONE; + } + + void + grub_multiboot_set_bootdev (void) + { + char *p; + grub_uint32_t biosdev, slice = ~0, part = ~0; + grub_device_t dev; + + #ifdef GRUB_MACHINE_PCBIOS + biosdev = grub_get_root_biosnumber (); + #else + biosdev = 0xffffffff; + #endif + + dev = grub_device_open (0); + if (dev && dev->disk && dev->disk->partition) + { + + p = dev->disk->partition->partmap->get_name (dev->disk->partition); + if (p) + { + if ((p[0] >= '0') && (p[0] <= '9')) + { + slice = grub_strtoul (p, &p, 0) - 1; + + if ((p) && (p[0] == ',')) + p++; + } + + if ((p[0] >= 'a') && (p[0] <= 'z')) + part = p[0] - 'a'; + } + } + if (dev) + grub_device_close (dev); + + bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) + | ((part & 0xff) << 8) | 0xff; + bootdev_set = 1; + } diff --cc loader/i386/pc/xnu.c index 07c1ee37e,839d0ad44..1c8b1ddec --- a/loader/i386/pc/xnu.c +++ b/loader/i386/pc/xnu.c @@@ -48,15 -39,24 +39,22 @@@ grub_xnu_set_video (struct grub_xnu_boo grub_err_t err; modevar = grub_env_get ("gfxpayload"); + /* Consider only graphical 32-bit deep modes. */ if (! modevar || *modevar == 0) - err = grub_video_set_mode (DEFAULT_VIDEO_MODE, video_hook); + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT + | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK, + 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS); else { - tmp = grub_malloc (grub_strlen (modevar) - + sizeof (DEFAULT_VIDEO_MODE) + 1); + tmp = grub_asprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); if (! tmp) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate temporary storag"); - err = grub_video_set_mode (tmp, video_hook); - grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); + err = grub_video_set_mode (tmp, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT + | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK, + 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS); grub_free (tmp); } diff --cc loader/mips/linux.c index 000000000,b52f098ac..847044955 mode 000000,100644..100644 --- a/loader/mips/linux.c +++ b/loader/mips/linux.c @@@ -1,0 -1,389 +1,397 @@@ + /* linux.c - boot Linux */ + /* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005,2007,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 + + /* For frequencies. */ + #include + #include + + #define ELF32_LOADMASK (0x00000000UL) + #define ELF64_LOADMASK (0x0000000000000000ULL) + + static grub_dl_t my_mod; + + static int loaded; + + static grub_size_t linux_size; + + static grub_uint8_t *playground; + static grub_addr_t target_addr, entry_addr; + static int linux_argc; + static grub_off_t argv_off, envp_off; + static grub_off_t rd_addr_arg_off, rd_size_arg_off; + static int initrd_loaded = 0; + + static grub_err_t + grub_linux_boot (void) + { + struct grub_relocator32_state state; + + /* Boot the kernel. */ + state.gpr[1] = entry_addr; + state.gpr[4] = linux_argc; + state.gpr[5] = target_addr + argv_off; + state.gpr[6] = target_addr + envp_off; + state.jumpreg = 1; + grub_relocator32_boot (playground, target_addr, state); + + return GRUB_ERR_NONE; + } + + static grub_err_t + grub_linux_release_mem (void) + { + grub_relocator32_free (playground); + + return GRUB_ERR_NONE; + } + + static grub_err_t + grub_linux_unload (void) + { + grub_err_t err; + + err = grub_linux_release_mem (); + grub_dl_unref (my_mod); + + loaded = 0; + + return err; + } + + static grub_err_t + grub_linux_load32 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) + { + Elf32_Addr base; + int extraoff; + + /* Linux's entry point incorrectly contains a virtual address. */ + entry_addr = elf->ehdr.ehdr32.e_entry & ~ELF32_LOADMASK; + + linux_size = grub_elf32_size (elf, &base); + if (linux_size == 0) + return grub_errno; + target_addr = base; + /* Pad it; the kernel scribbles over memory beyond its load address. */ + linux_size += 0x100000; + linux_size = ALIGN_UP (base + linux_size, 4) - base; + extraoff = linux_size; + linux_size += extra_size; + + playground = grub_relocator32_alloc (linux_size); + if (!playground) + return grub_errno; + + *extra_mem = playground + extraoff; + + /* Now load the segments into the area we claimed. */ + auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load); + grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load) + { + if (phdr->p_type != PT_LOAD) + { + *do_load = 0; + return 0; + } + *do_load = 1; + + /* Linux's program headers incorrectly contain virtual addresses. + * Translate those to physical, and offset to the area we claimed. */ + *addr = (grub_addr_t) (phdr->p_paddr - base + playground); + return 0; + } + return grub_elf32_load (elf, offset_phdr, 0, 0); + } + + static grub_err_t + grub_linux_load64 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) + { + Elf64_Addr base; + int extraoff; + + /* Linux's entry point incorrectly contains a virtual address. */ + entry_addr = elf->ehdr.ehdr64.e_entry & ~ELF64_LOADMASK; + + linux_size = grub_elf64_size (elf, &base); + if (linux_size == 0) + return grub_errno; + target_addr = base; + /* Pad it; the kernel scribbles over memory beyond its load address. */ + linux_size += 0x100000; + linux_size = ALIGN_UP (base + linux_size, 4) - base; + extraoff = linux_size; + linux_size += extra_size; + + playground = grub_relocator32_alloc (linux_size); + if (!playground) + return grub_errno; + + *extra_mem = playground + extraoff; + + /* Now load the segments into the area we claimed. */ + auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load); + grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load) + { + if (phdr->p_type != PT_LOAD) + { + *do_load = 0; + return 0; + } + *do_load = 1; + /* Linux's program headers incorrectly contain virtual addresses. + * Translate those to physical, and offset to the area we claimed. */ + *addr = (grub_addr_t) (phdr->p_paddr - base + playground); + return 0; + } + return grub_elf64_load (elf, offset_phdr, 0, 0); + } + + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_elf_t elf = 0; + int i; + int size; + void *extra = NULL; + grub_uint32_t *linux_argv, *linux_envp; + char *linux_args, *linux_envs; + grub_err_t err; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); + + elf = grub_elf_open (argv[0]); + if (! elf) + return grub_errno; + + if (elf->ehdr.ehdr32.e_type != ET_EXEC) + { + grub_elf_close (elf); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "This ELF file is not of the right type\n"); + } + + /* Release the previously used memory. */ + grub_loader_unset (); + loaded = 0; + + /* For arguments. */ + linux_argc = argc; + /* Main arguments. */ + size = (linux_argc) * sizeof (grub_uint32_t); + /* Initrd address and size. */ + size += 2 * sizeof (grub_uint32_t); + /* NULL terminator. */ + size += sizeof (grub_uint32_t); + + /* First argument is always "a0". */ + size += ALIGN_UP (sizeof ("a0"), 4); + /* Normal arguments. */ + for (i = 1; i < argc; i++) + size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); + + /* rd arguments. */ + size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); + size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); + + /* For the environment. */ + size += sizeof (grub_uint32_t); + size += 4 * sizeof (grub_uint32_t); + size += ALIGN_UP (sizeof ("memsize=XXXXXXXXXXXXXXXXXXXX"), 4) + + ALIGN_UP (sizeof ("highmemsize=XXXXXXXXXXXXXXXXXXXX"), 4) + + ALIGN_UP (sizeof ("busclock=XXXXXXXXXX"), 4) + + ALIGN_UP (sizeof ("cpuclock=XXXXXXXXXX"), 4); + + if (grub_elf_is_elf32 (elf)) + err = grub_linux_load32 (elf, &extra, size); + else + if (grub_elf_is_elf64 (elf)) + err = grub_linux_load64 (elf, &extra, size); + else + err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unknown ELF class"); + + grub_elf_close (elf); + + if (err) + return err; + + linux_argv = extra; + argv_off = (grub_uint8_t *) linux_argv - (grub_uint8_t *) playground; + extra = linux_argv + (linux_argc + 1 + 2); + linux_args = extra; + + grub_memcpy (linux_args, "a0", sizeof ("a0")); + *linux_argv = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground + + target_addr; + linux_argv++; + linux_args += ALIGN_UP (sizeof ("a0"), 4); + + for (i = 1; i < argc; i++) + { + grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1); + *linux_argv = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground + + target_addr; + linux_argv++; + linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); + } + + /* Reserve space for rd arguments. */ + rd_addr_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground; + linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); + *linux_argv = 0; + linux_argv++; + + rd_size_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground; + linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); + *linux_argv = 0; + linux_argv++; + + *linux_argv = 0; + + extra = linux_args; + + linux_envp = extra; + envp_off = (grub_uint8_t *) linux_envp - (grub_uint8_t *) playground; + linux_envs = (char *) (linux_envp + 5); - grub_sprintf (linux_envs, "memsize=%lld", (unsigned long long) grub_mmap_get_lower () >> 20); ++ grub_snprintf (linux_envs, sizeof ("memsize=XXXXXXXXXXXXXXXXXXXX"), ++ "memsize=%lld", ++ (unsigned long long) grub_mmap_get_lower () >> 20); + linux_envp[0] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground + + target_addr; + linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); - grub_sprintf (linux_envs, "highmemsize=%lld", (unsigned long long) grub_mmap_get_upper () >> 20); ++ grub_snprintf (linux_envs, sizeof ("highmemsize=XXXXXXXXXXXXXXXXXXXX"), ++ "highmemsize=%lld", ++ (unsigned long long) grub_mmap_get_upper () >> 20); + linux_envp[1] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground + + target_addr; + linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); + - grub_sprintf (linux_envs, "busclock=%d", grub_arch_busclock); ++ grub_snprintf (linux_envs, sizeof ("busclock=XXXXXXXXXXXXXXXXXXXX"), ++ "busclock=%d", grub_arch_busclock); + linux_envp[2] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground + + target_addr; + linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); - grub_sprintf (linux_envs, "cpuclock=%d", grub_arch_cpuclock); ++ grub_snprintf (linux_envs, sizeof ("cpuclock=XXXXXXXXXXXXXXXXXXXX"), ++ "cpuclock=%d", grub_arch_cpuclock); + linux_envp[3] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground + + target_addr; + linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); + + + linux_envp[4] = 0; + + grub_loader_set (grub_linux_boot, grub_linux_unload, 1); + initrd_loaded = 0; + loaded = 1; + grub_dl_ref (my_mod); + + return GRUB_ERR_NONE; + } + + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; + grub_ssize_t size; + grub_size_t overhead; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "No initrd specified"); + + if (!loaded) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load Linux first."); + + if (initrd_loaded) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Only one initrd can be loaded."); + + file = grub_file_open (argv[0]); + if (! file) + return grub_errno; + + size = grub_file_size (file); + + overhead = ALIGN_UP (target_addr + linux_size + 0x10000, 0x10000) + - (target_addr + linux_size); + + playground = grub_relocator32_realloc (playground, + linux_size + overhead + size); + + if (!playground) + { + grub_file_close (file); + return grub_errno; + } + + if (grub_file_read (file, playground + linux_size + overhead, size) != size) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_file_close (file); + + return grub_errno; + } + - grub_sprintf ((char *) playground + rd_addr_arg_off, "rd_start=0x%llx", ++ grub_snprintf ((char *) playground + rd_addr_arg_off, ++ sizeof ("rd_start=XXXXXXXXXXXXXXXXXXXX"), "rd_start=0x%llx", + (unsigned long long) target_addr + linux_size + overhead); + ((grub_uint32_t *) (playground + argv_off))[linux_argc] + = target_addr + rd_addr_arg_off; + linux_argc++; + - grub_sprintf ((char *) playground + rd_size_arg_off, "rd_size=0x%llx", ++ grub_snprintf ((char *) playground + rd_size_arg_off, ++ sizeof ("rd_size=XXXXXXXXXXXXXXXXXXXX"), "rd_size=0x%llx", + (unsigned long long) size); + ((grub_uint32_t *) (playground + argv_off))[linux_argc] + = target_addr + rd_size_arg_off; + linux_argc++; + + initrd_loaded = 1; + + grub_file_close (file); + + return GRUB_ERR_NONE; + } + + static grub_command_t cmd_linux, cmd_initrd; + + GRUB_MOD_INIT(linux) + { + cmd_linux = grub_register_command ("linux", grub_cmd_linux, + 0, N_("Load Linux.")); + cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, + 0, N_("Load initrd.")); + my_mod = mod; + } + + GRUB_MOD_FINI(linux) + { + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_initrd); + } diff --cc normal/autofs.c index d1a6d2110,d1ef761fb..94c08c59e --- a/normal/autofs.c +++ b/normal/autofs.c @@@ -67,6 -61,14 +61,12 @@@ read_fs_list (void if (filename) { grub_file_t file; + grub_fs_autoload_hook_t tmp_autoload_hook; + - grub_sprintf (filename, "%s/fs.lst", prefix); - + /* This rules out the possibility that read_fs_list() is invoked + recursively when we call grub_file_open() below. */ + tmp_autoload_hook = grub_fs_autoload_hook; + grub_fs_autoload_hook = NULL; file = grub_file_open (filename); if (file) diff --cc normal/crypto.c index 000000000,67330272a..7ca0de900 mode 000000,100644..100644 --- a/normal/crypto.c +++ b/normal/crypto.c @@@ -1,0 -1,153 +1,152 @@@ + /* crypto.c - support crypto autoload */ + /* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + + #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")); ++ filename = grub_asprintf ("%s/crypto.lst", prefix); + 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 --cc normal/main.c index 7aeba37ca,7a5e3ee8e..555d56aba --- a/normal/main.c +++ b/normal/main.c @@@ -388,17 -406,15 +406,15 @@@ grub_normal_init_page (struct grub_term int msg_len; int posx; const char *msg = _("GNU GRUB version %s"); -- - char *msg_formatted = grub_malloc (grub_strlen(msg) + - grub_strlen(PACKAGE_VERSION)); + char *msg_formatted; - grub_uint32_t *unicode_msg; grub_uint32_t *last_position; - grub_cls (); + grub_term_cls (term); - grub_sprintf (msg_formatted, msg, PACKAGE_VERSION); + msg_formatted = grub_asprintf (msg, PACKAGE_VERSION); + if (!msg_formatted) + return; msg_len = grub_utf8_to_ucs4_alloc (msg_formatted, &unicode_msg, &last_position); @@@ -525,33 -539,36 +538,37 @@@ grub_normal_reader_init (int nested 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)); + char *msg_formatted; - msg_formatted = grub_asprintf (msg, reader_nested ? msg_esc : ""); - grub_sprintf (msg_formatted, msg, nested ? msg_esc : ""); ++ msg_formatted = grub_asprintf (msg, nested ? msg_esc : ""); + if (!msg_formatted) + return grub_errno; - grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN); - grub_puts ("\n"); + 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 char cmdline[GRUB_MAX_CMDLINE]; static grub_err_t - grub_normal_read_line (char **line, int cont) + 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)]; + char *prompt; - prompt = grub_asprintf ("%s>", parser->name); - if (!prompt) - return grub_errno; + if (cont) - grub_sprintf (prompt, ">"); ++ prompt = grub_asprintf (">"); + else - grub_sprintf (prompt, "%s>", parser->name); ++ prompt = grub_asprintf ("%s>", parser->name); while (1) { diff --cc normal/menu_text.c index 3bcf35a93,cab1d22f8..f7a1358f4 --- a/normal/menu_text.c +++ b/normal/menu_text.c @@@ -210,16 -183,16 +183,17 @@@ command-line or ESC to return menu."), } else { - const char *msg = _("Use the %C and %C keys to select which \ -entry is highlighted.\n"); - char *msg_translated = - grub_malloc (sizeof (char) * grub_strlen (msg) + 1); - - grub_sprintf (msg_translated, msg, (grub_uint32_t) GRUB_TERM_DISP_UP, - (grub_uint32_t) GRUB_TERM_DISP_DOWN); + const char *msg = _("Use the %C and %C keys to select which " + "entry is highlighted.\n"); + char *msg_translated; + + msg_translated = grub_asprintf (msg, (grub_uint32_t) GRUB_TERM_DISP_UP, + (grub_uint32_t) GRUB_TERM_DISP_DOWN); + if (!msg_translated) + return; grub_putchar ('\n'); - grub_print_message_indented (msg_translated, STANDARD_MARGIN, STANDARD_MARGIN); + grub_print_message_indented (msg_translated, STANDARD_MARGIN, + STANDARD_MARGIN, term); grub_free (msg_translated); @@@ -391,352 -356,132 +357,131 @@@ grub_menu_init_page (int nested, int ed } 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."); + _("The highlighted entry will be executed automatically in %ds."); + struct menu_viewer_data *data = dataptr; char *msg_translated; + int posx; - grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); + grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3); - msg_translated = grub_malloc (sizeof (char) * grub_strlen (msg) + 5); + msg_translated = grub_asprintf (msg, timeout); if (!msg_translated) - return; - grub_print_message_indented (msg_translated, 3, 0); + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } + - grub_sprintf (msg_translated, msg, timeout); + grub_print_message_indented (msg_translated, 3, 0, data->term); - int posx; - posx = grub_getxy() >> 8; - print_spaces (GRUB_TERM_WIDTH - posx - 1); + posx = grub_term_getxy (data->term) >> 8; + print_spaces (grub_term_width (data->term) - posx - 1, data->term); - grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset); - grub_refresh (); + grub_term_gotoxy (data->term, + grub_term_cursor_x (data->term), + GRUB_TERM_FIRST_ENTRY_Y + data->offset); + grub_term_refresh (data->term); } - /* 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) + static void + menu_text_set_chosen_entry (int entry, void *dataptr) { - int first, offset; - grub_uint64_t saved_time; - int default_entry; - int timeout; - - first = 0; + struct menu_viewer_data *data = dataptr; + int oldoffset = data->offset; + int complete_redraw = 0; - default_entry = get_entry_number ("default"); - - /* If DEFAULT_ENTRY is not within the menu entries, fall back to - the first entry. */ - if (default_entry < 0 || default_entry >= menu->size) - default_entry = 0; - - /* If timeout is 0, drawing is pointless (and ugly). */ - if (grub_menu_get_timeout () == 0) + data->offset = entry - data->first; + if (data->offset > grub_term_num_entries (data->term) - 1) { - *auto_boot = 1; - return default_entry; + data->first = entry - (grub_term_num_entries (data->term) - 1); + data->offset = grub_term_num_entries (data->term) - 1; + complete_redraw = 1; } - - offset = default_entry; - if (offset > GRUB_TERM_NUM_ENTRIES - 1) + if (data->offset < 0) { - first = offset - (GRUB_TERM_NUM_ENTRIES - 1); - offset = GRUB_TERM_NUM_ENTRIES - 1; + data->offset = 0; + data->first = entry; + complete_redraw = 1; } - - /* Initialize the time. */ - saved_time = grub_get_time_ms (); - - refresh: - grub_setcursor (0); - grub_menu_init_page (nested, 0); - print_entries (menu, first, offset); - grub_refresh (); - - timeout = grub_menu_get_timeout (); - - if (timeout > 0) - print_timeout (timeout, offset); - - while (1) + if (complete_redraw) + print_entries (data->menu, data->first, data->offset, data->term); + else { - int c; - timeout = grub_menu_get_timeout (); - - if (timeout > 0) - { - grub_uint64_t current_time; - - current_time = grub_get_time_ms (); - if (current_time - saved_time >= 1000) - { - timeout--; - grub_menu_set_timeout (timeout); - saved_time = current_time; - print_timeout (timeout, offset); - } - } - - if (timeout == 0) - { - grub_env_unset ("timeout"); - *auto_boot = 1; - return default_entry; - } - - if (grub_checkkey () >= 0 || timeout < 0) - { - c = GRUB_TERM_ASCII_CHAR (grub_getkey ()); - - if (timeout >= 0) - { - grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); - print_spaces (GRUB_TERM_WIDTH - 1); - - grub_env_unset ("timeout"); - grub_env_unset ("fallback"); - grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset); - } - - switch (c) - { - case GRUB_TERM_HOME: - first = 0; - offset = 0; - print_entries (menu, first, offset); - break; - - case GRUB_TERM_END: - offset = menu->size - 1; - if (offset > GRUB_TERM_NUM_ENTRIES - 1) - { - first = offset - (GRUB_TERM_NUM_ENTRIES - 1); - offset = GRUB_TERM_NUM_ENTRIES - 1; - } - print_entries (menu, first, offset); - break; - - case GRUB_TERM_UP: - case '^': - if (offset > 0) - { - print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0, - grub_menu_get_entry (menu, first + offset)); - offset--; - print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1, - grub_menu_get_entry (menu, first + offset)); - } - else if (first > 0) - { - first--; - print_entries (menu, first, offset); - } - break; - - case GRUB_TERM_DOWN: - case 'v': - if (menu->size > first + offset + 1) - { - if (offset < GRUB_TERM_NUM_ENTRIES - 1) - { - print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0, - grub_menu_get_entry (menu, first + offset)); - offset++; - print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1, - grub_menu_get_entry (menu, first + offset)); - } - else - { - first++; - print_entries (menu, first, offset); - } - } - break; - - case GRUB_TERM_PPAGE: - if (first == 0) - { - offset = 0; - } - else - { - first -= GRUB_TERM_NUM_ENTRIES; - - if (first < 0) - { - offset += first; - first = 0; - } - } - print_entries (menu, first, offset); - break; - - case GRUB_TERM_NPAGE: - if (offset == 0) - { - offset += GRUB_TERM_NUM_ENTRIES - 1; - if (first + offset >= menu->size) - { - offset = menu->size - first - 1; - } - } - else - { - first += GRUB_TERM_NUM_ENTRIES; - - if (first + offset >= menu->size) - { - first -= GRUB_TERM_NUM_ENTRIES; - offset += GRUB_TERM_NUM_ENTRIES; - - if (offset > menu->size - 1 || - offset > GRUB_TERM_NUM_ENTRIES - 1) - { - offset = menu->size - first - 1; - } - if (offset > GRUB_TERM_NUM_ENTRIES) - { - first += offset - GRUB_TERM_NUM_ENTRIES + 1; - offset = GRUB_TERM_NUM_ENTRIES - 1; - } - } - } - print_entries (menu, first, offset); - break; - - case '\n': - case '\r': - case 6: - grub_setcursor (1); - *auto_boot = 0; - return first + offset; - - case '\e': - if (nested) - { - grub_setcursor (1); - return -1; - } - break; - - case 'c': - grub_cmdline_run (1); - goto refresh; - - case 'e': - { - grub_menu_entry_t e = grub_menu_get_entry (menu, first + offset); - if (e) - grub_menu_entry_run (e); - } - goto refresh; - - default: - break; - } - - grub_refresh (); - } + 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); } - - /* Never reach here. */ - return -1; + grub_term_refresh (data->term); } - /* Callback invoked immediately before a menu entry is executed. */ static void - notify_booting (grub_menu_entry_t entry, - void *userdata __attribute__((unused))) + menu_text_fini (void *dataptr) { - grub_printf (" "); - grub_printf_ (N_("Booting \'%s\'"), entry->title); - grub_printf ("\n\n"); - } + struct menu_viewer_data *data = dataptr; + + grub_term_setcursor (data->term, 1); + grub_term_cls (data->term); - /* 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))) + menu_text_clear_timeout (void *dataptr) { - 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 (); + 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); } - /* Callbacks used by the text menu to provide user feedback when menu entries - are executed. */ - static struct grub_menu_execute_callback execution_callback = + grub_err_t + grub_menu_try_text (struct grub_term_output *term, + int entry, grub_menu_t menu, int nested) { - .notify_booting = notify_booting, - .notify_fallback = notify_fallback, - .notify_failure = notify_execution_failure - }; + struct menu_viewer_data *data; + struct grub_menu_viewer *instance; - static grub_err_t - show_text_menu (grub_menu_t menu, int nested) - { - while (1) - { - int boot_entry; - grub_menu_entry_t e; - int auto_boot; + instance = grub_zalloc (sizeof (*instance)); + if (!instance) + return grub_errno; - boot_entry = run_menu (menu, nested, &auto_boot); - if (boot_entry < 0) - break; + data = grub_zalloc (sizeof (*data)); + if (!data) + { + grub_free (instance); + return grub_errno; + } - e = grub_menu_get_entry (menu, boot_entry); - if (! e) - continue; /* Menu is empty. */ + 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; - grub_cls (); - grub_setcursor (1); + data->menu = menu; - 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->offset = entry; + data->first = 0; + if (data->offset > grub_term_num_entries (data->term) - 1) + { + data->first = data->offset - (grub_term_num_entries (data->term) - 1); + data->offset = grub_term_num_entries (data->term) - 1; } + grub_term_setcursor (data->term, 0); + grub_menu_init_page (nested, 0, data->term); + print_entries (menu, data->first, data->offset, data->term); + grub_term_refresh (data->term); + grub_menu_register_viewer (instance); + return GRUB_ERR_NONE; } - - struct grub_menu_viewer grub_normal_text_menu_viewer = - { - .name = "text", - .show_menu = show_text_menu - }; diff --cc normal/term.c index 000000000,667d27ee9..86902c7a1 mode 000000,100644..100644 --- a/normal/term.c +++ b/normal/term.c @@@ -1,0 -1,252 +1,251 @@@ + /* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + + #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 ("/terminal.lst")); ++ filename = grub_asprintf ("%s/terminal.lst", prefix); + 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 --cc term/gfxterm.c index 7c99ae053,94aacee88..50752bf89 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@@ -269,13 -266,15 +266,14 @@@ grub_gfxterm_init (void /* Parse gfxmode environment variable if set. */ modevar = grub_env_get ("gfxmode"); if (! modevar || *modevar == 0) - err = grub_video_set_mode (DEFAULT_VIDEO_MODE, video_hook); + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); else { - tmp = grub_malloc (grub_strlen (modevar) - + sizeof (DEFAULT_VIDEO_MODE) + 1); - grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); - err = grub_video_set_mode (tmp, - GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); + tmp = grub_asprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); + if (!tmp) + return grub_errno; - err = grub_video_set_mode (tmp, video_hook); ++ err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); grub_free (tmp); } diff --cc tests/lib/test.c index 000000000,cd0799f56..a90a9972c mode 000000,100644..100644 --- a/tests/lib/test.c +++ b/tests/lib/test.c @@@ -1,0 -1,164 +1,161 @@@ + /* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + + #include + #include + #include + + struct grub_test_failure + { + /* The next failure. */ + struct grub_test_failure *next; + + /* The test source file name. */ + char *file; + + /* The test function name. */ + char *funp; + + /* The test call line number. */ + grub_uint32_t line; + + /* The test failure message. */ + char *message; + }; + typedef struct grub_test_failure *grub_test_failure_t; + + grub_test_t grub_test_list; + static grub_test_failure_t failure_list; + + static void + add_failure (const char *file, + const char *funp, + grub_uint32_t line, const char *fmt, va_list args) + { - char buf[1024]; + grub_test_failure_t failure; + + failure = (grub_test_failure_t) grub_malloc (sizeof (*failure)); + if (!failure) + return; + - grub_vsprintf (buf, fmt, args); - + failure->file = grub_strdup (file ? : ""); + failure->funp = grub_strdup (funp ? : ""); + failure->line = line; - failure->message = grub_strdup (buf); ++ failure->message = grub_avsprintf (fmt, args); + + grub_list_push (GRUB_AS_LIST_P (&failure_list), GRUB_AS_LIST (failure)); + } + + static void + free_failures (void) + { + grub_test_failure_t item; + + while ((item = grub_list_pop (GRUB_AS_LIST_P (&failure_list))) != 0) + { + if (item->message) + grub_free (item->message); + + if (item->funp) + grub_free (item->funp); + + if (item->file) + grub_free (item->file); + + grub_free (item); + } + failure_list = 0; + } + + void + grub_test_nonzero (int cond, + const char *file, + const char *funp, grub_uint32_t line, const char *fmt, ...) + { + va_list ap; + + if (cond) + return; + + va_start (ap, fmt); + add_failure (file, funp, line, fmt, ap); + va_end (ap); + } + + void + grub_test_register (const char *name, void (*test_main) (void)) + { + grub_test_t test; + + test = (grub_test_t) grub_malloc (sizeof (*test)); + if (!test) + return; + + test->name = grub_strdup (name); + test->main = test_main; + + grub_list_push (GRUB_AS_LIST_P (&grub_test_list), GRUB_AS_LIST (test)); + } + + void + grub_test_unregister (const char *name) + { + grub_test_t test; + + test = (grub_test_t) grub_named_list_find + (GRUB_AS_NAMED_LIST (grub_test_list), name); + + if (test) + { + grub_list_remove (GRUB_AS_LIST_P (&grub_test_list), GRUB_AS_LIST (test)); + + if (test->name) + grub_free (test->name); + + grub_free (test); + } + } + + int + grub_test_run (grub_test_t test) + { + auto int print_failure (grub_test_failure_t item); + int print_failure (grub_test_failure_t item) + { + grub_test_failure_t failure = (grub_test_failure_t) item; + + grub_printf (" %s:%s:%u: %s\n", + (failure->file ? : ""), + (failure->funp ? : ""), + failure->line, (failure->message ? : "")); + return 0; + } + + test->main (); + + grub_printf ("%s:\n", test->name); + grub_list_iterate (GRUB_AS_LIST (failure_list), + (grub_list_hook_t) print_failure); + if (!failure_list) + grub_printf ("%s: PASS\n", test->name); + else + grub_printf ("%s: FAIL\n", test->name); + + free_failures (); + return GRUB_ERR_NONE; + } diff --cc util/grub-fstest.c index d33ecb764,4470cbfa5..e249920fe --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@@ -285,22 -285,14 +285,22 @@@ fstest (char **images, int num_disks, i for (i = 0; i < num_disks; i++) { - if (grub_strlen (images[i]) + 7 > sizeof (host_file)) - grub_util_error ("pathname %s too long", images[i]); + loop_name = grub_asprintf ("loop%d", i); + host_file = grub_asprintf ("(host)%s", images[i]); - grub_sprintf (loop_name, "loop%d", i); - grub_sprintf (host_file, "(host)%s", images[i]); + if (!loop_name || !host_file) + { + grub_free (loop_name); + grub_free (host_file); + grub_util_error (grub_errmsg); + return; + } + + argv[1] = loop_name; + argv[2] = host_file; if (execute_command ("loopback", 3, argv)) - grub_util_error ("loopback command fails."); + grub_util_error ("loopback command fails"); } grub_lvm_fini (); diff --cc util/grub-mkpasswd-pbkdf2.c index 000000000,82437fdca..a00b1e990 mode 000000,100644..100644 --- a/util/grub-mkpasswd-pbkdf2.c +++ b/util/grub-mkpasswd-pbkdf2.c @@@ -1,0 -1,341 +1,341 @@@ + /* + * 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) ++grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list args) + { - return vsprintf (str, fmt, args); ++ return vsnprintf (str, n, 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 `%s --help' for more information.\n", program_name); + else + printf ("\ + Usage: %s [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", program_name, 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]); + + grub_util_init_nls (); + + /* 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; + }