]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
legacy parser prototype
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 12 May 2010 13:19:01 +0000 (15:19 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 12 May 2010 13:19:01 +0000 (15:19 +0200)
commands/legacycfg.c [new file with mode: 0644]
conf/i386-pc.rmk

diff --git a/commands/legacycfg.c b/commands/legacycfg.c
new file mode 100644 (file)
index 0000000..de46311
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ *  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>
+#include <grub/gzio.h>
+#include <grub/normal.h>
+#include <grub/script_sh.h>
+#include <grub/i18n.h>
+
+struct legacy_command
+{
+  const char *name;
+  const char *map;
+  unsigned argc;
+  enum {
+    TYPE_VERBATIM,
+    TYPE_FORCE_OPTION,
+    TYPE_NOAPM_OPTION,
+    TYPE_FILE,
+    TYPE_PARTITION,
+    TYPE_BOOL,
+    TYPE_INT
+  } argt[3];
+  enum {
+    FLAG_IGNORE_REST = 1,
+    FLAG_ALL_VERBATIM = 2
+  } flags;
+};
+
+struct legacy_command legacy_commands[] =
+  {
+    {"blocklist", "blocklist '%s'\n", 1, {TYPE_FILE}, 0},
+    {"boot", "boot\n", 0, {}, 0},
+    /* bootp unsupported.  */
+    {"cat", "cat '%s'\n", 1, {TYPE_FILE}, 0},
+    {"chainloader", "chainloader %s '%s'\n", 2, {TYPE_FORCE_OPTION, TYPE_FILE},
+     0},
+    {"cmp", "cmp '%s' '%s'\n", 2, {TYPE_FILE, TYPE_FILE}, FLAG_IGNORE_REST},
+    /* FIXME: Implement command.  */
+    {"color", "legacy_color '%s' '%s'\n", 2, {TYPE_VERBATIM, TYPE_VERBATIM},
+     FLAG_IGNORE_REST},
+    {"configfile", "legacy_configfile '%s'\n", 1, {TYPE_FILE}, 0},
+    {"debug",
+     "if [ -z \"$debug\" ]; then set debug=all; else set debug=; fi\n",
+     0, {}, 0},
+    /* FIXME: Implement command.  */
+    {"default", "legacy_default %s\n", 1, {TYPE_INT}, 0},
+    /* dhcp unsupported.  */
+    /* displayapm unsupported.  */
+    {"displaymem", "lsmem\n", 0, {}, 0},
+    /* embed unsupported.  */
+    {"fallback", "set fallback='%s'\n", 1, {TYPE_VERBATIM}, 0},
+    {"find", "search -f '%s'\n", 1, {TYPE_FILE}, 0},
+    /* fstest unsupported.  */
+    /* geometry unsupported.  */
+    {"halt", "halt %s\n", 1, {TYPE_NOAPM_OPTION}, 0},
+    /* help unsupported.  */    /* NUL_TERMINATE */
+    /* hiddenmenu unsupported.  */
+    {"hide", "parttool '%s' hidden+\n", 1, {TYPE_PARTITION}, 0},
+    /* ifconfig unsupported.  */
+    /* impsprobe unsupported.  */
+    /* FIXME: Implement command.  */
+    {"initrd", "legacy_initrd '%s'\n", 1, {TYPE_FILE}, 0},
+    /* install unsupported.  */
+    /* ioprobe unsupported.  */
+    /* FIXME: implement command. */
+    {"kernel", "legacy_kernel %s\n", 0, {}, FLAG_ALL_VERBATIM},
+    /* lock is handled separately. */
+    {"makeactive", "parttool '%s' boot+\n", 1, {TYPE_PARTITION}, 0},
+    {"map", "drivemap '%s' '%s'\n", 2, {TYPE_PARTITION, TYPE_PARTITION},
+     FLAG_IGNORE_REST},
+    /* md5crypt unsupported.  */
+    {"module", "legacy_initrd '%s'\n", 1, {TYPE_FILE}, 0},
+    /* modulenounzip unsupported.  */
+    {"pager", "set pager=%d\n", 1, {TYPE_BOOL}, 0},
+    /* partnew unsupported.  */
+    {"parttype", "parttool '%s' type=%s\n", 2, {TYPE_PARTITION, TYPE_INT}, 0},
+    /* password unsupported.  */    /* NUL_TERMINATE */
+    /* pause unsupported.  */
+    /* rarp unsupported.  */
+    {"read", "read_dword %s\n", 1, {TYPE_INT}, 0},
+    {"reboot", "reboot\n", 0, {}, 0},
+    {"root", "set root='%s'\n", 1, {TYPE_PARTITION}, 0},
+    {"rootnoverify", "set root='%s'\n", 1, {TYPE_PARTITION}, 0},
+    {"savedefault", "saved_entry=${chosen}; save_env saved_entry\n", 0, {}, 0},
+    /* serial unsupported.  */
+    /* setkey unsupported.  */    /* NUL_TERMINATE */
+    /* setup unsupported.  */
+    /* terminal unsupported.  */    /* NUL_TERMINATE */
+    /* terminfo unsupported.  */    /* NUL_TERMINATE */
+    /* testload unsupported.  */
+    /* testvbe unsupported.  */
+    /* tftpserver unsupported.  */
+    {"timeout", "set timeout=%s\n", 1, {TYPE_INT}, 0},
+    /* title is handled separately. */
+    {"unhide", "parttool '%s' hidden-\n", 1, {TYPE_PARTITION}, 0},
+    /* uppermem unsupported.  */
+    /* vbeprobe unsupported.  */
+  };
+
+static char *
+escape (const char *in)
+{
+  const char *ptr;
+  char *ret, *outptr;
+  int overhead = 0;
+  for (ptr = in; *ptr; ptr++)
+    if (*ptr == '\'' || *ptr == '\\')
+      overhead++;
+  ret = grub_malloc (ptr - in + overhead);
+  if (!ret)
+    return NULL;
+  outptr = ret;
+  for (ptr = in; *ptr; ptr++)
+    {
+      if (*ptr == '\'' || *ptr == '\\')
+       *outptr++ = '\\';
+      
+      *outptr++ = *ptr;
+    }
+  return ret;
+}
+
+static char *
+adjust_file (const char *in)
+{
+  const char *comma, *ptr, *rest;
+  char *ret, *outptr;
+  int overhead = 0;
+  int part;
+  if (in[0] != '(')
+    return escape (in);
+  for (ptr = in + 1; *ptr && *ptr != ')' && *ptr != ','; ptr++)
+    if (*ptr == '\'' || *ptr == '\\')
+      overhead++;
+  comma = ptr;
+  if (*comma != ',')
+    return escape (in);
+  part = grub_strtoull (comma + 1, (char **) &rest, 0);
+  for (ptr = rest; *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 <= comma; ptr++)
+    {
+      if (*ptr == '\'' || *ptr == '\\')
+       *outptr++ = '\\';
+      
+      *outptr++ = *ptr;
+    }
+  grub_snprintf (outptr, 30, "%d", part + 1);
+  while (*outptr)
+    outptr++;
+  for (ptr = rest; ptr <= comma; ptr++)
+    {
+      if (*ptr == '\'' || *ptr == '\\')
+       *outptr++ = '\\';
+      
+      *outptr++ = *ptr;
+    }
+  return ret;
+}
+
+static char *
+legacy_parse (char *buf, char **entryname)
+{
+  char *ptr;
+  char *cmdname;
+  unsigned i, cmdnum;
+
+  for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++);
+  if ((!*ptr || *ptr == '#') && entryname && *entryname)
+    return buf;
+  if (!*ptr || *ptr == '#')
+    {
+      grub_free (buf);
+      return NULL;
+    }
+
+  cmdname = ptr;
+  for (ptr = buf; !grub_isspace (*ptr) && *ptr != '='; ptr++);
+
+  if (entryname && grub_strncmp ("title", cmdname, ptr - cmdname) == 0
+      && ptr - cmdname == sizeof ("title") - 1)
+    {
+      for (; grub_isspace (*ptr) || *ptr == '='; ptr++);
+      *entryname = grub_strdup (ptr);
+      grub_free (buf);
+      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)];
+  memset (args, 0, sizeof (args));
+
+  if (legacy_commands[cmdnum].flags & FLAG_ALL_VERBATIM)
+    {
+      char *arg0 = ptr, *outptr;
+      int overhead = 3;
+      while (*ptr)
+       {
+         char *curarg;
+         for (; grub_isspace (*ptr); ptr++);
+         curarg = ptr;
+         for (; *ptr && !grub_isspace (*ptr); ptr++)
+           if (*ptr == '\\' || *ptr == '\'')
+             overhead++;
+         if (ptr)
+           ptr++;
+         overhead += 3;
+       }
+      args[0] = grub_malloc (overhead + (ptr - arg0));
+      if (!args[0])
+       {
+         grub_free (buf);
+         return NULL;
+       }
+      ptr = arg0;
+      outptr = args[0];
+      while (*ptr)
+       {
+         char *curarg;
+         for (; grub_isspace (*ptr); ptr++);
+         curarg = ptr;
+         if (outptr != args[0])
+           *outptr++ = ' ';
+         *outptr++ = '\'';
+         for (; *ptr && !grub_isspace (*ptr); ptr++)
+           {
+             if (*ptr == '\\' || *ptr == '\'')
+               *outptr++ = '\\';
+             *outptr++ = *ptr;
+           }
+         *outptr++ = '\'';
+         if (ptr)
+           ptr++;
+         overhead += 3;
+       }
+    }
+
+  {
+    unsigned j = 0;
+    for (i = 0; i < legacy_commands[cmdnum].argc; i++)
+      {
+       char *curarg, *cptr = NULL, c;
+       for (; grub_isspace (*ptr); ptr++);
+       curarg = ptr;
+       for (; !grub_isspace (*ptr); ptr++);
+       if (i != legacy_commands[cmdnum].argc - 1
+           || (legacy_commands[cmdnum].flags & FLAG_IGNORE_REST))
+         {
+           cptr = ptr;
+           c = *cptr;
+           *ptr = 0;
+         }
+       ptr++;
+       switch (legacy_commands[cmdnum].argt[i])
+         {
+         case TYPE_PARTITION:
+         case TYPE_FILE:
+           args[j++] = adjust_file (curarg);
+           break;
+
+         case TYPE_VERBATIM:
+           args[j++] = escape (curarg);
+           break;
+         case TYPE_FORCE_OPTION:
+           if (grub_strcmp (curarg, "--force") == 0)
+             {
+               args[j++] = grub_strdup ("--force");
+               break;
+             }
+           if (cptr)
+             *cptr = c;
+           ptr = curarg;
+           break;
+         case TYPE_NOAPM_OPTION:
+           if (grub_strcmp (curarg, "--no-apm") == 0)
+             {
+               args[j++] = grub_strdup ("--no-apm");
+               break;
+             }
+           if (cptr)
+             *cptr = c;
+           ptr = curarg;
+           break;
+         case TYPE_INT:
+           {
+             char *brk;
+             int base = 10;
+             brk = curarg;
+             if (brk[0] == '0' && brk[1] == 'x')
+               base = 16;
+             else if (brk[0] == '0')
+               base = 8;
+             for (; *brk; 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 (curarg[0] == 'o' && curarg[1] == 'n'
+               && (curarg[2] == 0 || grub_isspace (curarg[2])))
+             args[j++] = grub_strdup ("1");
+           else
+             args[j++] = grub_strdup ("0");
+           break;
+         }
+      }
+  }
+  grub_free (buf);
+  return grub_xasprintf (legacy_commands[cmdnum].map, args[0], args[1], args[2]);
+}
+
+static grub_err_t
+legacy_file (const char *filename)
+{
+  grub_file_t file;
+  char *entryname = NULL, *entrysrc = NULL;
+  grub_menu_t menu;
+
+  file = grub_gzfile_open (filename, 1);
+  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 = legacy_parse (buf, &entryname);
+       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);
+         }
+      }
+
+      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_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), buf,
+                          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;
+      grub_normal_add_menu_entry (1, args, 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 grub_command_t cmd_source, cmd_configfile;
+
+GRUB_MOD_INIT(legacycfg)
+{
+  cmd_source = grub_register_command ("legacy_source",
+                                     grub_cmd_legacy_source,
+                                     N_("FILE"), N_("Parse legacy config"));
+  cmd_configfile = grub_register_command ("legacy_configfile",
+                                         grub_cmd_legacy_configfile,
+                                         N_("FILE"),
+                                         N_("Parse legacy config"));
+}
+
+GRUB_MOD_FINI(legacycfg)
+{
+  grub_unregister_command (cmd_source);
+  grub_unregister_command (cmd_configfile);
+}
index 5ff852f2edc2942c63df1e57c2550b25f52db98f..791d64349acbda53eb2f65962b78903b73fc9041 100644 (file)
@@ -255,6 +255,12 @@ hdparm_mod_SOURCES = commands/hdparm.c lib/hexdump.c
 hdparm_mod_CFLAGS = $(COMMON_CFLAGS)
 hdparm_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# grub legacy ever supported only i386-pc.
+pkglib_MODULES += legacycfg.mod
+legacycfg_mod_SOURCES = commands/legacycfg.c
+legacycfg_mod_CFLAGS = $(COMMON_CFLAGS)
+legacycfg_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 ifeq ($(enable_efiemu), yes)
 
 efiemu32.o: efiemu/runtime/efiemu.c $(TARGET_OBJ2ELF)