legacy parser prototype
This commit is contained in:
parent
d499b13371
commit
092fd48a25
2 changed files with 527 additions and 0 deletions
521
commands/legacycfg.c
Normal file
521
commands/legacycfg.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue