]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
merge mainline into asprintf
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 20 Jan 2010 06:36:17 +0000 (07:36 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 20 Jan 2010 06:36:17 +0000 (07:36 +0100)
51 files changed:
1  2 
commands/hashsum.c
commands/help.c
commands/ls.c
commands/memrw.c
commands/parttool.c
commands/search.c
commands/xnu_uuid.c
disk/ata.c
disk/i386/pc/biosdisk.c
disk/raid.c
disk/scsi.c
fs/ext2.c
fs/hfs.c
fs/iso9660.c
fs/ntfs.c
fs/ufs.c
fs/xfs.c
gettext/gettext.c
include/grub/font.h
include/grub/misc.h
kern/device.c
kern/dl.c
kern/efi/init.c
kern/env.c
kern/err.c
kern/i386/pc/init.c
kern/ieee1275/init.c
kern/misc.c
lib/hexdump.c
loader/i386/bsd.c
loader/i386/linux.c
loader/i386/multiboot.c
loader/i386/multiboot_mbi.c
loader/i386/pc/xnu.c
loader/i386/xnu.c
loader/mips/linux.c
loader/xnu.c
normal/autofs.c
normal/completion.c
normal/crypto.c
normal/dyncmd.c
normal/main.c
normal/menu.c
normal/menu_text.c
normal/term.c
partmap/apple.c
term/gfxterm.c
term/ieee1275/ofconsole.c
tests/lib/test.c
util/grub-fstest.c
util/grub-mkpasswd-pbkdf2.c

index 0000000000000000000000000000000000000000,60e17447b6136dacc1f2e1b276003c4fc7425737..a098ab7af7050a9ccb386ae9f776882509e8308a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,278 +1,276 @@@
 -        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);
+ }
diff --cc commands/help.c
index 9f0ee752829b1aedbbe7d95f25f11746e4428969,9234a3697da75886a166f1719b39960d10a4670e..a19b395cde7e88c171a0ea445aff7ad94e9ba651
@@@ -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/ls.c
Simple merge
Simple merge
Simple merge
Simple merge
index 735d999a207af632d57cfc4f8957d4fe8d043c2b,b6f2b260493ad5d7cb5671468c135a8c7fa016bf..382d3196b779db4eba0dfa58572315f064d850c5
@@@ -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 disk/ata.c
Simple merge
Simple merge
diff --cc disk/raid.c
Simple merge
diff --cc disk/scsi.c
Simple merge
diff --cc fs/ext2.c
Simple merge
diff --cc fs/hfs.c
Simple merge
diff --cc fs/iso9660.c
Simple merge
diff --cc fs/ntfs.c
Simple merge
diff --cc fs/ufs.c
Simple merge
diff --cc fs/xfs.c
Simple merge
Simple merge
index 8a5f3ac7dce87f7264f3835052e94e52b22b4039,2129c30b30f3e7e418c2ddb8475231a9a0f79f27..333d3e2b06b1008c06c6876a5ed61db00de8a6c4
@@@ -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.
index f4d722081166019a91ac67258c39a1b1d1dbc2d8,48eb1fcddc91ed84cd3aab6ead23cc6bad009d8f..2c1817492dcc00ea71f271f08db251cf988aa5e6
@@@ -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 d1692baa0971e25e9456ae9cf6587ba1efb02641,7d3577051ba016211efe67cb81dc20cceb880501..3727ddcd9fddd39d9676b78f6b2e8c0f7e8ba94a
@@@ -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/dl.c
Simple merge
diff --cc kern/efi/init.c
Simple merge
diff --cc kern/env.c
Simple merge
diff --cc kern/err.c
index 5a63b41876ae012b1e0b50b853e8126c48865a50,1a881db25d7fd28b3eff4c7aee22c578162c704e..8272467f5e5dee58dee43cb1325d29194c347dd8
@@@ -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;
Simple merge
Simple merge
diff --cc kern/misc.c
Simple merge
diff --cc lib/hexdump.c
Simple merge
Simple merge
index 93f3da058dbcdd4ccf424d63a1d475d6b7c0fbbc,a81e841359a6795cd044724a0821ee31ea46f2e0..c764dad251e0da1309f333ed1fb015c3d6595e72
@@@ -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
index a52b8d5d6c45cdcb389b4df2ad792881d04af40e,d06f18692488adccc11420305ffcff4d50b5880c..16c19b6d177205376fee68238568cc1e8de37376
@@@ -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)
index 0000000000000000000000000000000000000000,5154a64dfecaaa972a6ea680309be471dc8d9f15..4493c03c7ad74df254457544fab3a911f1c0c1a0
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,475 +1,473 @@@
 -        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;
+ }
index 07c1ee37e44704da270f4167f115bb9265b44582,839d0ad44d82f5ac9c43021856185fbb13dfc96e..1c8b1ddec532b6d3f1178e54b7fbcf02c121b5b7
@@@ -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);
      }
  
Simple merge
index 0000000000000000000000000000000000000000,b52f098acf999b786888ce0db89340da7cd6f2da..847044955bbcbe508659ccf0b3548c596eb4b538
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,389 +1,397 @@@
 -  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);
+ }
diff --cc loader/xnu.c
Simple merge
diff --cc normal/autofs.c
index d1a6d21108b4ef79f8063d1651154928fd0ddb03,d1ef761fb2e30467580cec37cccb0da4d5a0eb18..94c08c59e3fea9ddaf2567e998503b03785031ce
@@@ -67,6 -61,14 +61,12 @@@ read_fs_list (void
        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)
Simple merge
diff --cc normal/crypto.c
index 0000000000000000000000000000000000000000,67330272a764ac674850bd1bc214ed35f0241abb..7ca0de90099537c5a0eb91cabb26d75049acfff7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,153 +1,152 @@@
 -  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;
+ }
diff --cc normal/dyncmd.c
Simple merge
diff --cc normal/main.c
index 7aeba37cabba49de5e86614a04410f506a18f012,7a5e3ee8e037bc187cddd9f1afb9513fb5ecda32..555d56aba5671447bfe38d3d670f5780e1fac71f
@@@ -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.c
Simple merge
index 3bcf35a938a853d657a39ce4f7f298807dde12c3,cab1d22f86d92cacb554c48cc5581da32177ba0e..f7a1358f49bee99d12d7105d8e02122afc7f8292
@@@ -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 0000000000000000000000000000000000000000,667d27ee90fa7fe4d84a1d2fc53461943c849f99..86902c7a10baf78f66114626559e6304befa0093
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,252 +1,251 @@@
 -  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;
+ }
diff --cc partmap/apple.c
Simple merge
diff --cc term/gfxterm.c
index 7c99ae053fcd5c217fe578a418bb0024426be7e1,94aacee885846ab6aed4a1e1a2355cd60715add2..50752bf89cc7cd445ab4a7638a846554b0f5dcab
@@@ -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);
      }
  
Simple merge
index 0000000000000000000000000000000000000000,cd0799f563b94509486a19bf05ae3b80910d9749..a90a9972c9753af911498d3093cbcf55393f51bf
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,164 +1,161 @@@
 -  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;
+ }
index d33ecb7642bbb29d0c7d7db1d7a13b229a6ac9de,4470cbfa549e546fa8032057ae6a44e33633658f..e249920fe91a469c061c808ffded7083f4e6c910
@@@ -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 ();
index 0000000000000000000000000000000000000000,82437fdcaa2ef919e67f56c9eea28e152e090185..a00b1e99072f0566bab8b6c353c48a5974b3e7df
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,341 +1,341 @@@
 -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;
+ }