]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Merge mainline into legacy_parser
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 11 Sep 2010 20:39:55 +0000 (22:39 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sat, 11 Sep 2010 20:39:55 +0000 (22:39 +0200)
1  2 
Makefile.util.def
grub-core/Makefile.core.def
grub-core/commands/legacycfg.c
grub-core/commands/menuentry.c
grub-core/lib/legacy_parse.c
include/grub/normal.h

Simple merge
index a72f61b6661aaab75052aaddd3325c1eb299f1d3,53ad9c262e460d5734ad91499e37fdddd22454c9..cbc5b74386123523595760274752b111021dff9f
@@@ -1384,13 -1406,6 +1406,13 @@@ module = 
    common = hook/datehook.c;
  };
  
- }
 +module = {
 +  name = legacycfg;
 +  common = commands/legacycfg.c;
 +  common = lib/legacy_parse.c;
 +  enable = i386_pc;
++};
 +
  module = {
    name = test_blockarg;
    common = tests/test_blockarg.c;
index 100464e69e1dd364e74490167ed61b9c0f789205,0000000000000000000000000000000000000000..b0253e7074b1d2030d1a51786a360c81cf621390
mode 100644,000000..100644
--- /dev/null
@@@ -1,421 -1,0 +1,421 @@@
- #include <grub/gzio.h>
 +/*
 + *  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/types.h>
 +#include <grub/misc.h>
 +#include <grub/command.h>
 +#include <grub/mm.h>
 +#include <grub/err.h>
 +#include <grub/dl.h>
 +#include <grub/file.h>
-   file = grub_gzfile_open (filename, 1);
 +#include <grub/normal.h>
 +#include <grub/script_sh.h>
 +#include <grub/i18n.h>
 +#include <grub/term.h>
 +#include <grub/legacy_parse.h>
 +
 +static grub_err_t
 +legacy_file (const char *filename)
 +{
 +  grub_file_t file;
 +  char *entryname = NULL, *entrysrc = NULL;
 +  grub_menu_t menu;
 +
-           grub_normal_add_menu_entry (1, args, entrysrc);
++  file = grub_file_open (filename);
 +  if (! file)
 +    return grub_errno;
 +
 +  menu = grub_env_get_menu ();
 +  if (! menu)
 +    {
 +      menu = grub_zalloc (sizeof (*menu));
 +      if (! menu)
 +      return grub_errno;
 +
 +      grub_env_set_menu (menu);
 +    }
 +
 +  while (1)
 +    {
 +      char *buf = grub_file_getline (file);
 +      char *parsed;
 +
 +      if (!buf && grub_errno)
 +      {
 +        grub_file_close (file);
 +        return grub_errno;
 +      }
 +
 +      if (!buf)
 +      break;
 +
 +      {
 +      char *oldname = NULL;
 +
 +      oldname = entryname;
 +      parsed = grub_legacy_parse (buf, &entryname);
 +      grub_free (buf);
 +      if (oldname != entryname && oldname)
 +        {
 +          const char **args = grub_malloc (sizeof (args[0]));
 +          if (!args)
 +            {
 +              grub_file_close (file);
 +              return grub_errno;
 +            }
 +          args[0] = oldname;
-       grub_normal_add_menu_entry (1, args, entrysrc);
++          grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, NULL,
++                                      entrysrc);
 +        }
 +      }
 +
 +      if (parsed && !entryname)
 +      {
 +        auto grub_err_t getline (char **line, int cont);
 +        grub_err_t getline (char **line __attribute__ ((unused)), 
 +                            int cont __attribute__ ((unused)))
 +        {
 +          return GRUB_ERR_NONE;
 +        }
 +
 +        grub_normal_parse_line (parsed, getline);
 +        grub_print_error ();
 +        grub_free (parsed);
 +      }
 +      else if (parsed)
 +      {
 +        if (!entrysrc)
 +          entrysrc = parsed;
 +        else
 +          {
 +            char *t;
 +
 +            t = entrysrc;
 +            entrysrc = grub_realloc (entrysrc, grub_strlen (entrysrc)
 +                                     + grub_strlen (parsed) + 1);
 +            if (!entrysrc)
 +              {
 +                grub_free (t);
 +                grub_free (parsed);
 +                return grub_errno;
 +              }
 +            grub_memcpy (entrysrc + grub_strlen (entrysrc), parsed,
 +                         grub_strlen (parsed) + 1);
 +            grub_free (parsed);
 +            parsed = NULL;
 +          }
 +      }
 +    }
 +  grub_file_close (file);
 +
 +  if (entryname)
 +    {
 +      const char **args = grub_malloc (sizeof (args[0]));
 +      if (!args)
 +      {
 +        grub_file_close (file);
 +        return grub_errno;
 +      }
 +      args[0] = entryname;
-   cutargs = grub_malloc (sizeof (cutargsp[0]) * (argc - 1));
++      grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, NULL, entrysrc);
 +    }
 +
 +  if (menu && menu->size)
 +    grub_show_menu (menu, 1);
 +
 +  return GRUB_ERR_NONE;
 +}
 +
 +static grub_err_t
 +grub_cmd_legacy_source (struct grub_command *cmd __attribute__ ((unused)),
 +                      int argc, char **args)
 +{
 +  if (argc != 1)
 +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
 +  return legacy_file (args[0]);
 +}
 +
 +static grub_err_t
 +grub_cmd_legacy_configfile (struct grub_command *cmd __attribute__ ((unused)),
 +                          int argc, char **args)
 +{
 +  grub_err_t ret;
 +  if (argc != 1)
 +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
 +
 +  grub_cls ();
 +  grub_env_context_open (1);
 +
 +  ret = legacy_file (args[0]);
 +  grub_env_context_close ();
 +
 +  return ret;
 +}
 +
 +static enum
 +  { 
 +    GUESS_IT, LINUX, MULTIBOOT, KFREEBSD, KNETBSD, KOPENBSD 
 +  } kernel_type;
 +
 +static grub_err_t
 +grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)),
 +                      int argc, char **args)
 +{
 +  int i;
 +  int no_mem_option = 0;
 +  struct grub_command *cmd;
 +  char **cutargs;
 +  int cutargc;
 +  for (i = 0; i < 2; i++)
 +    {
 +      /* FIXME: really support this.  */
 +      if (argc >= 1 && grub_strcmp (args[0], "--no-mem-option") == 0)
 +      {
 +        no_mem_option = 1;
 +        argc--;
 +        args++;
 +        continue;
 +      }
 +
 +      /* linux16 handles both zImages and bzImages.   */
 +      if (argc >= 1 && (grub_strcmp (args[0], "--type=linux") == 0
 +                      || grub_strcmp (args[0], "--type=biglinux") == 0))
 +      {
 +        kernel_type = LINUX;
 +        argc--;
 +        args++;
 +        continue;
 +      }
 +
 +      if (argc >= 1 && grub_strcmp (args[0], "--type=multiboot") == 0)
 +      {
 +        kernel_type = MULTIBOOT;
 +        argc--;
 +        args++;
 +        continue;
 +      }
 +
 +      if (argc >= 1 && grub_strcmp (args[0], "--type=freebsd") == 0)
 +      {
 +        kernel_type = KFREEBSD;
 +        argc--;
 +        args++;
 +        continue;
 +      }
 +
 +      if (argc >= 1 && grub_strcmp (args[0], "--type=openbsd") == 0)
 +      {
 +        kernel_type = KOPENBSD;
 +        argc--;
 +        args++;
 +        continue;
 +      }
 +
 +      if (argc >= 1 && grub_strcmp (args[0], "--type=netbsd") == 0)
 +      {
 +        kernel_type = KNETBSD;
 +        argc--;
 +        args++;
 +        continue;
 +      }
 +    }
 +
 +  if (argc < 2)
 +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "filename required");
 +
-   grub_memcpy (cutargs + 1, args + 2, sizeof (cutargsp[0]) * (argc - 2));
++  cutargs = grub_malloc (sizeof (cutargs[0]) * (argc - 1));
 +  cutargc = argc - 1;
++  grub_memcpy (cutargs + 1, args + 2, sizeof (cutargs[0]) * (argc - 2));
 +  cutargs[0] = args[0];
 +
 +  do
 +    {
 +      /* First try Linux.  */
 +      if (kernel_type == GUESS_IT || kernel_type == LINUX)
 +      {
 +        cmd = grub_command_find ("linux16");
 +        if (cmd)
 +          {
 +            if (!(cmd->func) (cmd, cutargc, cutargs))
 +              {
 +                kernel_type = LINUX;
 +                return GRUB_ERR_NONE;
 +              }
 +          }
 +        grub_errno = GRUB_ERR_NONE;
 +      }
 +
 +      /* Then multiboot.  */
 +      /* FIXME: dublicate multiboot filename. */
 +      if (kernel_type == GUESS_IT || kernel_type == MULTIBOOT)
 +      {
 +        cmd = grub_command_find ("multiboot");
 +        if (cmd)
 +          {
 +            if (!(cmd->func) (cmd, argc, args))
 +              {
 +                kernel_type = MULTIBOOT;
 +                return GRUB_ERR_NONE;
 +              }
 +          }
 +        grub_errno = GRUB_ERR_NONE;
 +      }
 +
 +      /* k*BSD didn't really work well with grub-legacy.  */
 +      if (kernel_type == GUESS_IT || kernel_type == KFREEBSD)
 +      {
 +        cmd = grub_command_find ("kfreebsd");
 +        if (cmd)
 +          {
 +            if (!(cmd->func) (cmd, cutargc, cutargs))
 +              {
 +                kernel_type = KFREEBSD;
 +                return GRUB_ERR_NONE;
 +              }
 +          }
 +        grub_errno = GRUB_ERR_NONE;
 +      }
 +      if (kernel_type == GUESS_IT || kernel_type == KNETBSD)
 +      {
 +        cmd = grub_command_find ("knetbsd");
 +        if (cmd)
 +          {
 +            if (!(cmd->func) (cmd, cutargc, cutargs))
 +              {
 +                kernel_type = KNETBSD;
 +                return GRUB_ERR_NONE;
 +              }
 +          }
 +        grub_errno = GRUB_ERR_NONE;
 +      }
 +      if (kernel_type == GUESS_IT || kernel_type == KOPENBSD)
 +      {
 +        cmd = grub_command_find ("kopenbsd");
 +        if (cmd)
 +          {
 +            if (!(cmd->func) (cmd, cutargc, cutargs))
 +              {
 +                kernel_type = KOPENBSD;
 +                return GRUB_ERR_NONE;
 +              }
 +          }
 +        grub_errno = GRUB_ERR_NONE;
 +      }
 +    }
 +  while (0);
 +
 +  return grub_error (GRUB_ERR_BAD_OS, "couldn't load file %s\n",
 +                   args[0]);
 +}
 +
 +static grub_err_t
 +grub_cmd_legacy_initrd (struct grub_command *mycmd __attribute__ ((unused)),
 +                      int argc, char **args)
 +{
 +  struct grub_command *cmd;
 +
 +  if (kernel_type == LINUX)
 +    {
 +      cmd = grub_command_find ("initrd16");
 +      if (!cmd)
 +      return grub_error (GRUB_ERR_BAD_ARGUMENT, "command initrd16 not found");
 +
 +      return cmd->func (cmd, argc, args);
 +    }
 +  if (kernel_type == MULTIBOOT)
 +    {
 +      /* FIXME: dublicate module filename. */
 +      cmd = grub_command_find ("module");
 +      if (!cmd)
 +      return grub_error (GRUB_ERR_BAD_ARGUMENT, "command module not found");
 +
 +      return cmd->func (cmd, argc, args);
 +    }
 +
 +  return grub_error (GRUB_ERR_BAD_ARGUMENT,
 +                   "no kernel with module support is loaded in legacy way");
 +}
 +
 +static grub_err_t
 +grub_cmd_legacy_color (struct grub_command *mycmd __attribute__ ((unused)),
 +                      int argc, char **args)
 +{
 +  if (argc < 1)
 +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "color required");
 +  grub_env_set ("color_normal", args[0]);
 +  if (argc >= 2)
 +    grub_env_set ("color_highlight", args[1]);
 +  else
 +    {
 +      char *slash = grub_strchr (args[0], '/');
 +      char *invert;
 +      grub_size_t len;
 +
 +      len = grub_strlen (args[0]);
 +      if (!slash)
 +      return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad color specification %s",
 +                         args[0]);
 +      invert = grub_malloc (len + 1);
 +      if (!invert)
 +      return grub_errno;
 +      grub_memcpy (invert, slash + 1, len - (slash - args[0]) - 1);
 +      invert[len - (slash - args[0]) - 1] = '/'; 
 +      grub_memcpy (invert + len - (slash - args[0]), args[0], slash - args[0]);
 +      invert[len] = 0;
 +      grub_env_set ("color_highlight", invert);
 +      grub_free (invert);
 +    }
 +
 +  return grub_errno;
 +}
 +
 +static grub_command_t cmd_source, cmd_configfile, cmd_kernel, cmd_initrd;
 +static grub_command_t cmd_color;
 +
 +GRUB_MOD_INIT(legacycfg)
 +{
 +  cmd_source = grub_register_command ("legacy_source",
 +                                    grub_cmd_legacy_source,
 +                                    N_("FILE"), N_("Parse legacy config"));
 +  cmd_kernel = grub_register_command ("legacy_kernel",
 +                                    grub_cmd_legacy_kernel,
 +                                    N_("[--no-mem-option] [--type=TYPE] FILE [ARG ...]"),
 +                                    N_("Simulate grub-legacy kernel command"));
 +
 +  cmd_initrd = grub_register_command ("legacy_initrd",
 +                                    grub_cmd_legacy_initrd,
 +                                    N_("FILE [ARG ...]"),
 +                                    N_("Simulate grub-legacy initrd command"));
 +  cmd_configfile = grub_register_command ("legacy_configfile",
 +                                        grub_cmd_legacy_configfile,
 +                                        N_("FILE"),
 +                                        N_("Parse legacy config"));
 +  cmd_color = grub_register_command ("legacy_color",
 +                                   grub_cmd_legacy_color,
 +                                   N_("NORMAL [HIGHLIGHT]"),
 +                                   N_("Simulate grub-legacy color command"));
 +}
 +
 +GRUB_MOD_FINI(legacycfg)
 +{
 +  grub_unregister_command (cmd_source);
 +  grub_unregister_command (cmd_configfile);
 +  grub_unregister_command (cmd_kernel);
 +  grub_unregister_command (cmd_initrd);
 +  grub_unregister_command (cmd_color);
 +}
index fc1ae71c7027d03bc10d83950744a173c965a873,fc1ae71c7027d03bc10d83950744a173c965a873..cd5f38f69be49b255ac55087f452dc87ea989437
@@@ -52,10 -52,10 +52,10 @@@ static struc
  /* Add a menu entry to the current menu context (as given by the environment
     variable data slot `menu').  As the configuration file is read, the script
     parser calls this when a menu entry is to be created.  */
--static grub_err_t
--append_menu_entry (int argc, const char **args, char **classes,
--                 const char *users, const char *hotkey,
--                 const char *prefix, const char *sourcecode)
++grub_err_t
++grub_normal_add_menu_entry (int argc, const char **args, char **classes,
++                          const char *users, const char *hotkey,
++                          const char *prefix, const char *sourcecode)
  {
    unsigned i;
    int menu_hotkey = 0;
@@@ -243,9 -243,9 +243,10 @@@ grub_cmd_menuentry (grub_extcmd_context
      return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
  
    if (! ctxt->script)
--    return append_menu_entry (argc, (const char **) args,
--                            ctxt->state[0].args, ctxt->state[1].arg,
--                            ctxt->state[2].arg, 0, ctxt->state[3].arg);
++    return grub_normal_add_menu_entry (argc, (const char **) args,
++                                     ctxt->state[0].args, ctxt->state[1].arg,
++                                     ctxt->state[2].arg, 0,
++                                     ctxt->state[3].arg);
  
    src = args[argc - 1];
    args[argc - 1] = NULL;
    if (! prefix)
      return grub_errno;
  
--  r = append_menu_entry (argc - 1, (const char **) args,
--                       ctxt->state[0].args, ctxt->state[1].arg,
--                       ctxt->state[2].arg, prefix, src + 1);
++  r = grub_normal_add_menu_entry (argc - 1, (const char **) args,
++                                ctxt->state[0].args, ctxt->state[1].arg,
++                                ctxt->state[2].arg, prefix, src + 1);
  
    src[len - 1] = ch;
    args[argc - 1] = src;
index 694de097bc063ad4b4ef353ba992ba047f63a9c7,0000000000000000000000000000000000000000..832b6cd1aeb7809a37f759051127d7f49d27c10b
mode 100644,000000..100644
--- /dev/null
@@@ -1,506 -1,0 +1,507 @@@
 +/*
 + *  GRUB  --  GRand Unified Bootloader
 + *  Copyright (C) 1999,2000,2001,2002,2003,2004,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/types.h>
 +#include <grub/misc.h>
 +#include <grub/mm.h>
 +#include <grub/err.h>
 +#include <grub/legacy_parse.h>
 +
 +struct legacy_command
 +{
 +  const char *name;
 +  const char *map;
 +  unsigned argc;
 +  enum arg_type {
 +    TYPE_VERBATIM,
 +    TYPE_FORCE_OPTION,
 +    TYPE_NOAPM_OPTION,
 +    TYPE_TYPE_OR_NOMEM_OPTION,
 +    TYPE_FILE,
 +    TYPE_FILE_NO_CONSUME,
 +    TYPE_PARTITION,
 +    TYPE_BOOL,
 +    TYPE_INT,
 +    TYPE_REST_VERBATIM
 +  } argt[4];
 +  enum {
 +    FLAG_IGNORE_REST = 1
 +  } flags;
 +  const char *shortdesc;
 +  const char *longdesc;
 +};
 +
 +struct legacy_command legacy_commands[] =
 +  {
 +    {"blocklist", "blocklist '%s'\n", 1, {TYPE_FILE}, 0, "FILE",
 +     "Print the blocklist notation of the file FILE."},
 +    {"boot", "boot\n", 0, {}, 0, 0,
 +     "Boot the OS/chain-loader which has been loaded."},
 +    /* bootp unsupported.  */
 +    {"cat", "cat '%s'\n", 1, {TYPE_FILE}, 0, "FILE",
 +     "Print the contents of the file FILE."},
 +    {"chainloader", "chainloader %s '%s'\n", 2, {TYPE_FORCE_OPTION, TYPE_FILE},
 +     0, "[--force] FILE",
 +     "Load the chain-loader FILE. If --force is specified, then load it"
 +     " forcibly, whether the boot loader signature is present or not."},
 +    {"cmp", "cmp '%s' '%s'\n", 2, {TYPE_FILE, TYPE_FILE}, FLAG_IGNORE_REST,
 +     "FILE1 FILE2",
 +     "Compare the file FILE1 with the FILE2 and inform the different values"
 +     " if any."},
 +    {"color", "legacy_color '%s' '%s'\n", 2, {TYPE_VERBATIM, TYPE_VERBATIM},
 +     FLAG_IGNORE_REST, "NORMAL [HIGHLIGHT]",
 +     "Change the menu colors. The color NORMAL is used for most"
 +     " lines in the menu, and the color HIGHLIGHT is used to highlight the"
 +     " line where the cursor points. If you omit HIGHLIGHT, then the"
 +     " inverted color of NORMAL is used for the highlighted line."
 +     " The format of a color is \"FG/BG\". FG and BG are symbolic color names."
 +     " A symbolic color name must be one of these: black, blue, green,"
 +     " cyan, red, magenta, brown, light-gray, dark-gray, light-blue,"
 +     " light-green, light-cyan, light-red, light-magenta, yellow and white."
 +     " But only the first eight names can be used for BG. You can prefix"
 +     " \"blink-\" to FG if you want a blinking foreground color."},
 +    {"configfile", "legacy_configfile '%s'\n", 1, {TYPE_FILE}, 0, "FILE",
 +     "Load FILE as the configuration file."},
 +    {"debug",
 +     "if [ -z \"$debug\" ]; then set debug=all; else set debug=; fi\n",
 +     0, {}, 0, 0, "Turn on/off the debug mode."},
 +    {"default",
 +     "set default='%s'; if [ x\"$default\" = xsaved ]; then load_env; "
 +     "set default=\"$saved_entry\"; fi\n", 1, {TYPE_VERBATIM}, 0, 
 +     "[NUM | `saved']",
 +     "Set the default entry to entry number NUM (if not specified, it is"
 +     " 0, the first entry) or the entry number saved by savedefault."},
 +    /* dhcp unsupported.  */
 +    /* displayapm unsupported.  */
 +    {"displaymem", "lsmmap\n", 0, {}, 0, 0, 
 +     "Display what GRUB thinks the system address space map of the"
 +     " machine is, including all regions of physical RAM installed."},
 +    /* embed unsupported.  */
 +    {"fallback", "set fallback='%s'\n", 1, {TYPE_VERBATIM}, 0, "NUM...",
 +     "Go into unattended boot mode: if the default boot entry has any"
 +     " errors, instead of waiting for the user to do anything, it"
 +     " immediately starts over using the NUM entry (same numbering as the"
 +     " `default' command). This obviously won't help if the machine"
 +     " was rebooted by a kernel that GRUB loaded."},
 +    {"find", "search -sf '%s'\n", 1, {TYPE_FILE}, 0, "FILENAME",
 +     "Search for the filename FILENAME in all of partitions and print the list of"
 +     " the devices which contain the file."},
 +    /* fstest unsupported.  */
 +    /* geometry unsupported.  */
 +    {"halt", "halt %s\n", 1, {TYPE_NOAPM_OPTION}, 0, "[--no-apm]",
 +     "Halt your system. If APM is available on it, turn off the power using"
 +     " the APM BIOS, unless you specify the option `--no-apm'."},
 +    /* help unsupported.  */    /* NUL_TERMINATE */
 +    /* hiddenmenu unsupported.  */
 +    {"hide", "parttool '%s' hidden+\n", 1, {TYPE_PARTITION}, 0, "PARTITION",
 +     "Hide PARTITION by setting the \"hidden\" bit in"
 +     " its partition type code."},
 +    /* ifconfig unsupported.  */
 +    /* impsprobe unsupported.  */
 +    /* FIXME: dublicate multiboot filename. */
 +    {"initrd", "legacy_initrd '%s' %s\n", 2, {TYPE_FILE_NO_CONSUME,
 +                                            TYPE_REST_VERBATIM}, 0,
 +     "FILE [ARG ...]",
 +     "Load an initial ramdisk FILE for a Linux format boot image and set the"
 +     " appropriate parameters in the Linux setup area in memory."},
 +    /* install unsupported.  */
 +    /* ioprobe unsupported.  */
 +    /* FIXME: really support --no-mem-option.  */
 +    /* FIXME: dublicate multiboot filename. */
 +    {"kernel", "legacy_kernel %s %s '%s' %s\n", 4, {TYPE_TYPE_OR_NOMEM_OPTION,
 +                                                  TYPE_TYPE_OR_NOMEM_OPTION,
 +                                                  TYPE_FILE_NO_CONSUME,
 +                                                  TYPE_REST_VERBATIM}, 0,
 +     "[--no-mem-option] [--type=TYPE] FILE [ARG ...]",
 +     "Attempt to load the primary boot image from FILE. The rest of the"
 +     " line is passed verbatim as the \"kernel command line\".  Any modules"
 +     " must be reloaded after using this command. The option --type is used"
 +     " to suggest what type of kernel to be loaded. TYPE must be either of"
 +     " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
 +     " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
 +     " Linux's mem option automatically."},
 +    /* lock is unsupported. */
 +    {"makeactive", "parttool \"$root\" boot+\n", 0, {}, 0, 0,
 +     "Set the active partition on the root disk to GRUB's root device."
 +     " This command is limited to _primary_ PC partitions on a hard disk."},
 +    {"map", "drivemap '%s' '%s'\n", 2, {TYPE_PARTITION, TYPE_PARTITION},
 +     FLAG_IGNORE_REST, "TO_DRIVE FROM_DRIVE",
 +     "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary"
 +     " when you chain-load some operating systems, such as DOS, if such an"
 +     " OS resides at a non-first drive."},
 +    /* md5crypt unsupported.  */
 +    {"module", "legacy_initrd '%s' %s\n", 1, {TYPE_FILE_NO_CONSUME,
 +                                            TYPE_REST_VERBATIM}, 0,
 +     "FILE [ARG ...]",
 +     "Load a boot module FILE for a Multiboot format boot image (no"
 +     " interpretation of the file contents is made, so users of this"
 +     " command must know what the kernel in question expects). The"
 +     " rest of the line is passed as the \"module command line\", like"
 +     " the `kernel' command."},
 +    /* modulenounzip unsupported.  */
 +    /* FIXME: allow toggle.  */
 +    {"pager", "set pager=%d\n", 1, {TYPE_BOOL}, 0, "[FLAG]",
 +     "Toggle pager mode with no argument. If FLAG is given and its value"
 +     " is `on', turn on the mode. If FLAG is `off', turn off the mode."},
 +    /* partnew unsupported.  */
 +    {"parttype", "parttool '%s' type=%s\n", 2, {TYPE_PARTITION, TYPE_INT}, 0,
 +     "PART TYPE", "Change the type of the partition PART to TYPE."},
 +    /* password unsupported.  */    /* NUL_TERMINATE */
 +    /* pause unsupported.  */
 +    /* rarp unsupported.  */
 +    {"read", "read_dword %s\n", 1, {TYPE_INT}, 0, "ADDR",
 +     "Read a 32-bit value from memory at address ADDR and"
 +     " display it in hex format."},
 +    {"reboot", "reboot\n", 0, {}, 0, 0, "Reboot your system."},
 +    /* FIXME: Support HDBIAS.  */
 +    /* FIXME: Support printing.  */
 +    {"root", "set root='%s'\n", 1, {TYPE_PARTITION}, 0, "[DEVICE [HDBIAS]]",
 +     "Set the current \"root device\" to the device DEVICE, then"
 +     " attempt to mount it to get the partition size (for passing the"
 +     " partition descriptor in `ES:ESI', used by some chain-loaded"
 +     " bootloaders), the BSD drive-type (for booting BSD kernels using"
 +     " their native boot format), and correctly determine "
 +     " the PC partition where a BSD sub-partition is located. The"
 +     " optional HDBIAS parameter is a number to tell a BSD kernel"
 +     " how many BIOS drive numbers are on controllers before the current"
 +     " one. For example, if there is an IDE disk and a SCSI disk, and your"
 +     " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."},
 +    {"rootnoverify", "set root='%s'\n", 1, {TYPE_PARTITION}, 0,
 +     "[DEVICE [HDBIAS]]",
 +     "Similar to `root', but don't attempt to mount the partition. This"
 +     " is useful for when an OS is outside of the area of the disk that"
 +     " GRUB can read, but setting the correct root device is still"
 +     " desired. Note that the items mentioned in `root' which"
 +     " derived from attempting the mount will NOT work correctly."},
 +    /* FIXME: support arguments.  */
 +    {"savedefault", "saved_entry=${chosen}; save_env saved_entry\n", 0, {}, 0,
 +     "[NUM | `fallback']",
 +     "Save the current entry as the default boot entry if no argument is"
 +     " specified. If a number is specified, this number is saved. If"
 +     " `fallback' is used, next fallback entry is saved."},
 +    {"serial", "serial %s\n", 1, {TYPE_REST_VERBATIM}, 0, 
 +     "[--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] "
 +     "[--parity=PARITY] [--stop=STOP] [--device=DEV]",
 +     "Initialize a serial device. UNIT is a digit that specifies which serial"
 +     " device is used (e.g. 0 == COM1). If you need to specify the port number,"
 +     " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length,"
 +     " PARITY is the type of parity, which is one of `no', `odd' and `even'."
 +     " STOP is the length of stop bit(s). The option --device can be used only"
 +     " in the grub shell, which specifies the file name of a tty device. The"
 +     " default values are COM1, 9600, 8N1."},
 +    /* setkey unsupported.  */    /* NUL_TERMINATE */
 +    /* setup unsupported.  */
 +    /* terminal unsupported.  */    /* NUL_TERMINATE */
 +    /* terminfo unsupported.  */    /* NUL_TERMINATE */
 +    {"testload", "cat '%s'\n", 1, {TYPE_FILE}, 0, "FILE",
 +     "Read the entire contents of FILE in several different ways and"
 +     " compares them, to test the filesystem code. "
 +     " If this test succeeds, then a good next"
 +     " step is to try loading a kernel."},
 +    /* testvbe unsupported.  */
 +    /* tftpserver unsupported.  */
 +    {"timeout", "set timeout=%s\n", 1, {TYPE_INT}, 0, "SEC",
 +     "Set a timeout, in SEC seconds, before automatically booting the"
 +     " default entry (normally the first entry defined)."},
 +    /* title is handled separately. */
 +    {"unhide", "parttool '%s' hidden-\n", 1, {TYPE_PARTITION}, 0, "PARTITION",
 +     "Unhide PARTITION by clearing the \"hidden\" bit in its"
 +     " partition type code."},
 +    /* uppermem unsupported.  */
 +    {"uuid", "search -u '%s'\n", 1, {TYPE_VERBATIM}, 0, "UUID",
 +     "Find root by UUID"},
 +    /* vbeprobe unsupported.  */
 +  };
 +
 +char *
 +grub_legacy_escape (const char *in, grub_size_t len)
 +{
 +  const char *ptr;
 +  char *ret, *outptr;
 +  int overhead = 0;
 +  for (ptr = in; ptr < in + len && *ptr; ptr++)
 +    if (*ptr == '\'' || *ptr == '\\')
 +      overhead++;
 +  ret = grub_malloc (ptr - in + overhead);
 +  if (!ret)
 +    return NULL;
 +  outptr = ret;
 +  for (ptr = in; ptr < in + len && *ptr; ptr++)
 +    {
 +      if (*ptr == '\'' || *ptr == '\\')
 +      *outptr++ = '\\';
 +      
 +      *outptr++ = *ptr;
 +    }
 +  *outptr++ = 0;
 +  return ret;
 +}
 +
 +static char *
 +adjust_file (const char *in, grub_size_t len)
 +{
 +  const char *comma, *ptr, *rest;
 +  char *ret, *outptr;
 +  int overhead = 0;
 +  int part;
 +  if (in[0] != '(')
 +    return grub_legacy_escape (in, len);
 +  for (ptr = in + 1; ptr < in + len && *ptr && *ptr != ')'
 +       && *ptr != ','; ptr++)
 +    if (*ptr == '\'' || *ptr == '\\')
 +      overhead++;
 +  comma = ptr;
 +  if (*comma != ',')
 +    return grub_legacy_escape (in, len);
 +  part = grub_strtoull (comma + 1, (char **) &rest, 0);
 +  for (ptr = rest; ptr < in + len && *ptr; ptr++)
 +    if (*ptr == '\'' || *ptr == '\\')
 +      overhead++;
 +
 +  /* 30 is enough for any number.  */
 +  ret = grub_malloc (ptr - in + overhead + 30);
 +  if (!ret)
 +    return NULL;
 +
 +  outptr = ret;
 +  for (ptr = in; ptr < in + len && ptr <= comma; ptr++)
 +    {
 +      if (*ptr == '\'' || *ptr == '\\')
 +      *outptr++ = '\\';
 +      
 +      *outptr++ = *ptr;
 +    }
 +  grub_snprintf (outptr, 30, "%d", part + 1);
 +  while (*outptr)
 +    outptr++;
 +  for (ptr = rest; ptr < in + len; ptr++)
 +    {
 +      if (*ptr == '\'' || *ptr == '\\')
 +      *outptr++ = '\\';
 +      
 +      *outptr++ = *ptr;
 +    }
++  *outptr = 0;
 +  return ret;
 +}
 +
 +static int
 +check_option (const char *a, char *b, grub_size_t len)
 +{
 +  if (grub_strlen (b) != len)
 +    return 0;
 +  return grub_strncmp (a, b, len) == 0;
 +}
 +
 +static int
 +is_option (enum arg_type opt, const char *curarg, grub_size_t len)
 +{
 +  switch (opt)
 +    {
 +    case TYPE_NOAPM_OPTION:
 +      return check_option (curarg, "--no-apm", len);
 +    case TYPE_FORCE_OPTION:
 +      return check_option (curarg, "--force", len);
 +    case TYPE_TYPE_OR_NOMEM_OPTION:
 +      return check_option (curarg, "--type=netbsd", len)
 +      || check_option (curarg, "--type=freebsd", len)
 +      || check_option (curarg, "--type=openbsd", len)
 +      || check_option (curarg, "--type=linux", len)
 +      || check_option (curarg, "--type=biglinux", len)
 +      || check_option (curarg, "--type=multiboot", len)
 +      || check_option (curarg, "--no-mem-option", len);
 +    default:
 +      return 0;
 +    } 
 +}
 +
 +char *
 +grub_legacy_parse (const char *buf, char **entryname)
 +{
 +  const char *ptr;
 +  const char *cmdname;
 +  unsigned i, cmdnum;
 +
 +  for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++);
 +  if (!*ptr || *ptr == '#')
 +    return grub_strdup (buf);
 +
 +  cmdname = ptr;
 +  for (ptr = buf; *ptr && !grub_isspace (*ptr) && *ptr != '='; ptr++);
 +
 +  if (entryname && grub_strncmp ("title", cmdname, ptr - cmdname) == 0
 +      && ptr - cmdname == sizeof ("title") - 1)
 +    {
 +      const char *ptr2;
 +      for (; grub_isspace (*ptr) || *ptr == '='; ptr++);
 +      ptr2 = ptr + grub_strlen (ptr);
 +      while (ptr2 > ptr && grub_isspace (*(ptr2 - 1)))
 +      ptr2--;
 +      *entryname = grub_strndup (ptr, ptr2 - ptr);
 +      return NULL;
 +    }
 +
 +  if (grub_strncmp ("lock", cmdname, ptr - cmdname) == 0
 +      && ptr - cmdname == sizeof ("lock") - 1)
 +    {
 +      /* FIXME */
 +    }
 +
 +  for (cmdnum = 0; cmdnum < ARRAY_SIZE (legacy_commands); cmdnum++)
 +    if (grub_strncmp (legacy_commands[cmdnum].name, cmdname, ptr - cmdname) == 0
 +      && legacy_commands[cmdnum].name[ptr - cmdname] == 0)
 +      break;
 +  if (cmdnum == ARRAY_SIZE (legacy_commands))
 +    return grub_xasprintf ("# Unsupported legacy command: %s\n", buf);
 +
 +  for (; grub_isspace (*ptr) || *ptr == '='; ptr++);
 +
 +  char *args[ARRAY_SIZE (legacy_commands[0].argt)];
 +  grub_memset (args, 0, sizeof (args));
 +
 +  {
 +    unsigned j = 0;
 +    int hold_arg = 0;
 +    for (i = 0; i < legacy_commands[cmdnum].argc; i++)
 +      {
 +      const char *curarg;
 +      grub_size_t curarglen;
 +      if (hold_arg)
 +        {
 +          ptr = curarg;
 +          hold_arg = 0;
 +        }
 +      for (; grub_isspace (*ptr); ptr++);
 +      curarg = ptr;
 +      for (; *ptr && !grub_isspace (*ptr); ptr++);
 +      if (i != legacy_commands[cmdnum].argc - 1
 +          || (legacy_commands[cmdnum].flags & FLAG_IGNORE_REST))
 +        curarglen = ptr - curarg;
 +      else
 +        {
 +          curarglen = grub_strlen (curarg);
 +          while (curarglen > 0 && grub_isspace (curarg[curarglen - 1]))
 +            curarglen--;
 +        }
 +      if (*ptr)
 +        ptr++;
 +      switch (legacy_commands[cmdnum].argt[i])
 +        {
 +        case TYPE_FILE_NO_CONSUME:
 +          hold_arg = 1;
 +        case TYPE_PARTITION:
 +        case TYPE_FILE:
 +          args[j++] = adjust_file (curarg, curarglen);
 +          break;
 +
 +        case TYPE_REST_VERBATIM:
 +          {
 +            char *outptr, *outptr0;
 +            int overhead = 3;
 +            ptr = curarg;
 +            while (*ptr)
 +              {
 +                for (; *ptr && grub_isspace (*ptr); ptr++);
 +                for (; *ptr && !grub_isspace (*ptr); ptr++)
 +                  if (*ptr == '\\' || *ptr == '\'')
 +                    overhead++;
 +                if (*ptr)
 +                  ptr++;
 +                overhead += 3;
 +              }
 +            outptr0 = args[j++] = grub_malloc (overhead + (ptr - curarg));
 +            if (!outptr0)
 +              return NULL;
 +            ptr = curarg;
 +            outptr = outptr0;
 +            while (*ptr)
 +              {
 +                for (; *ptr && grub_isspace (*ptr); ptr++);
 +                if (outptr != outptr0)
 +                  *outptr++ = ' ';
 +                *outptr++ = '\'';
 +                for (; *ptr && !grub_isspace (*ptr); ptr++)
 +                  {
 +                    if (*ptr == '\\' || *ptr == '\'')
 +                      *outptr++ = '\\';
 +                    *outptr++ = *ptr;
 +                  }
 +                *outptr++ = '\'';
 +                if (*ptr)
 +                  ptr++;
 +              }
 +            *outptr++ = 0;
 +          }
 +          break;
 +
 +        case TYPE_VERBATIM:
 +          args[j++] = grub_legacy_escape (curarg, curarglen);
 +          break;
 +        case TYPE_FORCE_OPTION:
 +        case TYPE_NOAPM_OPTION:
 +        case TYPE_TYPE_OR_NOMEM_OPTION:
 +          if (is_option (legacy_commands[cmdnum].argt[i], curarg, curarglen))
 +            {
 +              args[j++] = grub_strndup (curarg, curarglen);
 +              break;
 +            }
 +          args[j++] = "";
 +          hold_arg = 1;
 +          break;
 +        case TYPE_INT:
 +          {
 +            const char *brk;
 +            int base = 10;
 +            brk = curarg;
 +            if (curarglen < 1)
 +              args[j++] = grub_strdup ("0");
 +            if (brk[0] == '0' && brk[1] == 'x')
 +              base = 16;
 +            else if (brk[0] == '0')
 +              base = 8;
 +            for (; *brk && brk < curarg + curarglen; brk++)
 +              {
 +                if (base == 8 &&  (*brk == '8' || *brk == '9'))
 +                  break;
 +                if (grub_isdigit (*brk))
 +                  continue;
 +                if (base != 16)
 +                  break;
 +                if (!(*brk >= 'a' && *brk <= 'f')
 +                    && !(*brk >= 'A' && *brk <= 'F'))
 +                  break;
 +              }
 +            if (brk == curarg)
 +              args[j++] = grub_strdup ("0");
 +            else
 +              args[j++] = grub_strndup (curarg, brk - curarg);
 +          }
 +          break;
 +        case TYPE_BOOL:
 +          if (curarglen == 2 && curarg[0] == 'o' && curarg[1] == 'n')
 +            args[j++] = grub_strdup ("1");
 +          else
 +            args[j++] = grub_strdup ("0");
 +          break;
 +        }
 +      }
 +  }
 +  
 +  return grub_xasprintf (legacy_commands[cmdnum].map, args[0], args[1], args[2],
 +                       args[3]);
 +}
index 51ab46b12dab13764db612bb741a8f0bd5f39bb4,51ab46b12dab13764db612bb741a8f0bd5f39bb4..df7f70142e6c5d019979d28d171ebecb56dea03a
@@@ -115,4 -115,4 +115,9 @@@ void grub_normal_reset_more (void)
  
  void grub_xputs_normal (const char *str);
  
++grub_err_t
++grub_normal_add_menu_entry (int argc, const char **args, char **classes,
++                          const char *users, const char *hotkey,
++                          const char *prefix, const char *sourcecode);
++
  #endif /* ! GRUB_NORMAL_HEADER */