--- /dev/null
- filename = grub_malloc (grub_strlen (prefix)
- + grub_strlen (p) + 2);
+ /*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/dl.h>
+ #include <grub/extcmd.h>
+ #include <grub/file.h>
+ #include <grub/disk.h>
+ #include <grub/mm.h>
+ #include <grub/misc.h>
+ #include <grub/crypto.h>
+ #include <grub/normal.h>
+
+ 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;
+
- grub_sprintf (filename, "%s/%s", prefix, p);
++ filename = grub_asprintf ("%s/%s", prefix, p);
+ if (!filename)
+ return grub_errno;
+ 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);
+ }
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;
}
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)
/* 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.
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);
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);
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;
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
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)
--- /dev/null
- tmp = grub_malloc (grub_strlen (modevar)
- + sizeof (DEFAULT_VIDEO_MODE) + 1);
+ /*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/machine/memory.h>
+ #include <grub/memory.h>
+ #ifdef GRUB_MACHINE_PCBIOS
+ #include <grub/machine/biosnum.h>
+ #endif
+ #include <grub/multiboot.h>
+ #include <grub/cpu/multiboot.h>
+ #include <grub/disk.h>
+ #include <grub/device.h>
+ #include <grub/partition.h>
+ #include <grub/mm.h>
+ #include <grub/misc.h>
+ #include <grub/env.h>
+ #include <grub/video.h>
+
+ #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
+ #include <grub/i386/pc/vbe.h>
+ #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;
- grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
++ tmp = grub_asprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
+ if (! tmp)
+ return grub_errno;
+ 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;
+ }
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);
}
--- /dev/null
- grub_sprintf (linux_envs, "memsize=%lld", (unsigned long long) grub_mmap_get_lower () >> 20);
+ /* 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 <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/elf.h>
+ #include <grub/elfload.h>
+ #include <grub/loader.h>
+ #include <grub/dl.h>
+ #include <grub/mm.h>
+ #include <grub/misc.h>
+ #include <grub/machine/loader.h>
+ #include <grub/command.h>
+ #include <grub/mips/relocator.h>
+ #include <grub/machine/memory.h>
+
+ /* For frequencies. */
+ #include <grub/pci.h>
+ #include <grub/machine/time.h>
+
+ #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, "highmemsize=%lld", (unsigned long long) grub_mmap_get_upper () >> 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, "busclock=%d", grub_arch_busclock);
++ 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, "cpuclock=%d", grub_arch_cpuclock);
++ 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 ((char *) playground + rd_addr_arg_off, "rd_start=0x%llx",
++ 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_size_arg_off, "rd_size=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_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;
+ \f
+ 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);
+ }
if (filename)
{
grub_file_t file;
- grub_sprintf (filename, "%s/fs.lst", prefix);
-
+ grub_fs_autoload_hook_t tmp_autoload_hook;
+
+ /* This rules out the possibility that read_fs_list() is invoked
+ recursively when we call grub_file_open() below. */
+ tmp_autoload_hook = grub_fs_autoload_hook;
+ grub_fs_autoload_hook = NULL;
file = grub_file_open (filename);
if (file)
--- /dev/null
- filename = grub_malloc (grub_strlen (prefix) + sizeof ("/crypto.lst"));
+ /* crypto.c - support crypto autoload */
+ /*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/dl.h>
+ #include <grub/mm.h>
+ #include <grub/env.h>
+ #include <grub/misc.h>
+ #include <grub/crypto.h>
+ #include <grub/normal.h>
+
+ struct load_spec
+ {
+ struct load_spec *next;
+ char *name;
+ char *modname;
+ };
+
+ struct load_spec *crypto_specs = NULL;
+
+ static void
+ grub_crypto_autoload (const char *name)
+ {
+ struct load_spec *cur;
+ grub_dl_t mod;
+
+ for (cur = crypto_specs; cur; cur = cur->next)
+ if (grub_strcasecmp (name, cur->name) == 0)
+ {
+ mod = grub_dl_load (cur->modname);
+ if (mod)
+ grub_dl_ref (mod);
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
+
+ static void
+ grub_crypto_spec_free (void)
+ {
+ struct load_spec *cur, *next;
+ for (cur = crypto_specs; cur; cur = next)
+ {
+ next = cur->next;
+ grub_free (cur->name);
+ grub_free (cur->modname);
+ grub_free (cur);
+ }
+ crypto_specs = NULL;
+ }
+
+
+ /* Read the file crypto.lst for auto-loading. */
+ void
+ read_crypto_list (void)
+ {
+ const char *prefix;
+ char *filename;
+ grub_file_t file;
+ char *buf = NULL;
+
+ prefix = grub_env_get ("prefix");
+ if (!prefix)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return;
+ }
+
- grub_sprintf (filename, "%s/crypto.lst", prefix);
++ filename = grub_asprintf ("%s/crypto.lst", prefix);
+ if (!filename)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return;
+ }
+
+ file = grub_file_open (filename);
+ if (!file)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return;
+ }
+
+ /* Override previous commands.lst. */
+ grub_crypto_spec_free ();
+
+ for (;; grub_free (buf))
+ {
+ char *p, *name;
+ struct load_spec *cur;
+
+ buf = grub_file_getline (file);
+
+ if (! buf)
+ break;
+
+ name = buf;
+
+ p = grub_strchr (name, ':');
+ if (! p)
+ continue;
+
+ *p = '\0';
+ while (*++p == ' ')
+ ;
+
+ cur = grub_malloc (sizeof (*cur));
+ if (!cur)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ continue;
+ }
+
+ cur->name = grub_strdup (name);
+ if (! name)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ grub_free (cur);
+ continue;
+ }
+
+ cur->modname = grub_strdup (p);
+ if (! cur->modname)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ grub_free (cur);
+ grub_free (cur->name);
+ continue;
+ }
+ cur->next = crypto_specs;
+ crypto_specs = cur;
+ }
+
+ grub_file_close (file);
+
+ grub_errno = GRUB_ERR_NONE;
+
+ grub_crypto_autoload_hook = grub_crypto_autoload;
+ }
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);
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)
{
}
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);
}
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
- };
--- /dev/null
- filename = grub_malloc (grub_strlen (prefix) + sizeof ("/terminal.lst"));
+ /*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2005,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/term.h>
+ #include <grub/misc.h>
+ #include <grub/mm.h>
+ #include <grub/file.h>
+ #include <grub/dl.h>
+ #include <grub/env.h>
+ #include <grub/normal.h>
+
+ /* The amount of lines counted by the pager. */
+ static unsigned grub_more_lines;
+
+ /* If the more pager is active. */
+ static int grub_more;
+
+ static void
+ process_newline (void)
+ {
+ struct grub_term_output *cur;
+ unsigned height = -1;
+
+ FOR_ACTIVE_TERM_OUTPUTS(cur)
+ if (grub_term_height (cur) < height)
+ height = grub_term_height (cur);
+ grub_more_lines++;
+
+ if (grub_more && grub_more_lines >= height - 1)
+ {
+ char key;
+ grub_uint16_t *pos;
+
+ pos = grub_term_save_pos ();
+
+ grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+ grub_printf ("--MORE--");
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+
+ key = grub_getkey ();
+
+ /* Remove the message. */
+ grub_term_restore_pos (pos);
+ grub_printf (" ");
+ grub_term_restore_pos (pos);
+
+ /* Scroll one lines or an entire page, depending on the key. */
+ if (key == '\r' || key =='\n')
+ grub_more_lines = height - 2;
+ else
+ grub_more_lines = 0;
+ }
+ }
+
+ void
+ grub_set_more (int onoff)
+ {
+ if (onoff == 1)
+ grub_more++;
+ else
+ grub_more--;
+
+ grub_more_lines = 0;
+ grub_newline_hook = process_newline;
+ }
+
+ void
+ grub_puts_terminal (const char *str, struct grub_term_output *term)
+ {
+ grub_uint32_t code;
+ grub_ssize_t ret;
+ const grub_uint8_t *ptr = (const grub_uint8_t *) str;
+ const grub_uint8_t *end;
+ end = (const grub_uint8_t *) (str + grub_strlen (str));
+
+ while (*ptr)
+ {
+ ret = grub_utf8_to_ucs4 (&code, 1, ptr, end - ptr, &ptr);
+ grub_putcode (code, term);
+ }
+ }
+
+ grub_uint16_t *
+ grub_term_save_pos (void)
+ {
+ struct grub_term_output *cur;
+ unsigned cnt = 0;
+ grub_uint16_t *ret, *ptr;
+
+ FOR_ACTIVE_TERM_OUTPUTS(cur)
+ cnt++;
+
+ ret = grub_malloc (cnt * sizeof (ret[0]));
+ if (!ret)
+ return NULL;
+
+ ptr = ret;
+ FOR_ACTIVE_TERM_OUTPUTS(cur)
+ *ptr++ = grub_term_getxy (cur);
+
+ return ret;
+ }
+
+ void
+ grub_term_restore_pos (grub_uint16_t *pos)
+ {
+ struct grub_term_output *cur;
+ grub_uint16_t *ptr = pos;
+
+ if (!pos)
+ return;
+
+ FOR_ACTIVE_TERM_OUTPUTS(cur)
+ {
+ grub_term_gotoxy (cur, (*ptr & 0xff00) >> 8, *ptr & 0xff);
+ ptr++;
+ }
+ }
+
+ static void
+ grub_terminal_autoload_free (void)
+ {
+ struct grub_term_autoload *cur, *next;
+ unsigned i;
+ for (i = 0; i < 2; i++)
+ for (cur = i ? grub_term_input_autoload : grub_term_output_autoload;
+ cur; cur = next)
+ {
+ next = cur->next;
+ grub_free (cur->name);
+ grub_free (cur->modname);
+ grub_free (cur);
+ }
+ grub_term_input_autoload = NULL;
+ grub_term_output_autoload = NULL;
+ }
+
+
+ /* Read the file terminal.lst for auto-loading. */
+ void
+ read_terminal_list (void)
+ {
+ const char *prefix;
+ char *filename;
+ grub_file_t file;
+ char *buf = NULL;
+
+ prefix = grub_env_get ("prefix");
+ if (!prefix)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return;
+ }
+
- grub_sprintf (filename, "%s/terminal.lst", prefix);
++ filename = grub_asprintf ("%s/terminal.lst", prefix);
+ if (!filename)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return;
+ }
+
+ file = grub_file_open (filename);
+ if (!file)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return;
+ }
+
+ /* Override previous terminal.lst. */
+ grub_terminal_autoload_free ();
+
+ for (;; grub_free (buf))
+ {
+ char *p, *name;
+ struct grub_term_autoload *cur;
+ struct grub_term_autoload **target = NULL;
+
+ buf = grub_file_getline (file);
+
+ if (! buf)
+ break;
+
+ switch (buf[0])
+ {
+ case 'i':
+ target = &grub_term_input_autoload;
+ break;
+
+ case 'o':
+ target = &grub_term_output_autoload;
+ break;
+ }
+ if (!target)
+ continue;
+
+ name = buf + 1;
+
+ p = grub_strchr (name, ':');
+ if (! p)
+ continue;
+
+ *p = '\0';
+ while (*++p == ' ')
+ ;
+
+ cur = grub_malloc (sizeof (*cur));
+ if (!cur)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ continue;
+ }
+
+ cur->name = grub_strdup (name);
+ if (! name)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ grub_free (cur);
+ continue;
+ }
+
+ cur->modname = grub_strdup (p);
+ if (! cur->modname)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ grub_free (cur);
+ grub_free (cur->name);
+ continue;
+ }
+ cur->next = *target;
+ *target = cur;
+ }
+
+ grub_file_close (file);
+
+ grub_errno = GRUB_ERR_NONE;
+ }
/* 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);
}
--- /dev/null
- char buf[1024];
+ /*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/mm.h>
+ #include <grub/misc.h>
+ #include <grub/test.h>
+
+ 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)
+ {
- grub_vsprintf (buf, fmt, args);
-
+ grub_test_failure_t failure;
+
+ failure = (grub_test_failure_t) grub_malloc (sizeof (*failure));
+ if (!failure)
+ return;
+
- failure->message = grub_strdup (buf);
+ failure->file = grub_strdup (file ? : "<unknown_file>");
+ failure->funp = grub_strdup (funp ? : "<unknown_function>");
+ failure->line = line;
++ 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 ? : "<unknown_file>"),
+ (failure->funp ? : "<unknown_function>"),
+ failure->line, (failure->message ? : "<no 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;
+ }
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 ();
--- /dev/null
-grub_vsprintf (char *str, const char *fmt, va_list args)
+ /*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+ #include <grub/types.h>
+ #include <grub/crypto.h>
+ #include <grub/util/misc.h>
+ #include <grub/i18n.h>
+
+ #include <unistd.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <getopt.h>
+ #include <termios.h>
+
+ #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
- return vsprintf (str, fmt, args);
++grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list 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;
+ }