]> git.proxmox.com Git - grub2.git/commitdiff
merge with mainline
authorBVK Chaitanya <bvk@dbook>
Wed, 25 Aug 2010 09:15:56 +0000 (14:45 +0530)
committerBVK Chaitanya <bvk@dbook>
Wed, 25 Aug 2010 09:15:56 +0000 (14:45 +0530)
1  2 
Makefile.util.def
grub-core/script/argv.c
grub-core/script/execute.c
grub-core/script/main.c

index 0000000000000000000000000000000000000000,fd3428e766f9c7ac08838c0da9784a1f8e267027..87c33c05ecdf23404fc36f1d33ddabd71b024812
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,510 +1,516 @@@
+ AutoGen definitions Makefile.tpl;
+ library = {
+   name = libgrub.a;
+   cflags = '$(CFLAGS_GCRY)';
+   cppflags = '$(CPPFLAGS_GCRY)';
+   common_nodist = grub_script.tab.c;
+   common_nodist = grub_script.yy.c;
+   common_nodist = libgrub_a_init.c;
+   common_nodist = grub_script.yy.h;
+   common_nodist = grub_script.tab.h;
+   common = grub-core/gnulib/error.c;
+   common = grub-core/gnulib/fnmatch.c;
+   common = grub-core/gnulib/getdelim.c;
+   common = grub-core/gnulib/getline.c;
+   common = grub-core/gnulib/getopt1.c;
+   common = grub-core/gnulib/getopt.c;
+   common = grub-core/gnulib/progname.c;
+   common = util/misc.c;
+   common = grub-core/kern/misc.c;
+   common = grub-core/kern/emu/mm.c;
+   common = grub-core/kern/emu/misc.c;
+   common = grub-core/kern/emu/hostfs.c;
+   common = grub-core/kern/emu/getroot.c;
+   common = grub-core/kern/emu/hostdisk.c;
+   common = grub-core/commands/blocklist.c;
+   common = grub-core/commands/extcmd.c;
+   common = grub-core/commands/ls.c;
+   common = grub-core/disk/dmraid_nvidia.c;
+   common = grub-core/disk/host.c;
+   common = grub-core/disk/loopback.c;
+   common = grub-core/disk/lvm.c;
+   common = grub-core/disk/mdraid_linux.c;
+   common = grub-core/disk/raid5_recover.c;
+   common = grub-core/disk/raid6_recover.c;
+   common = grub-core/disk/raid.c;
+   common = grub-core/fs/affs.c;
+   common = grub-core/fs/afs_be.c;
+   common = grub-core/fs/afs.c;
+   common = grub-core/fs/befs_be.c;
+   common = grub-core/fs/befs.c;
+   common = grub-core/fs/cpio.c;
+   common = grub-core/fs/ext2.c;
+   common = grub-core/fs/fat.c;
+   common = grub-core/fs/fshelp.c;
+   common = grub-core/fs/hfs.c;
+   common = grub-core/fs/hfsplus.c;
+   common = grub-core/fs/iso9660.c;
+   common = grub-core/fs/jfs.c;
+   common = grub-core/fs/minix.c;
+   common = grub-core/fs/nilfs2.c;
+   common = grub-core/fs/ntfs.c;
+   common = grub-core/fs/ntfscomp.c;
+   common = grub-core/fs/reiserfs.c;
+   common = grub-core/fs/sfs.c;
+   common = grub-core/fs/tar.c;
+   common = grub-core/fs/udf.c;
+   common = grub-core/fs/ufs2.c;
+   common = grub-core/fs/ufs.c;
+   common = grub-core/fs/xfs.c;
+   common = grub-core/kern/command.c;
+   common = grub-core/kern/device.c;
+   common = grub-core/kern/disk.c;
+   common = grub-core/kern/env.c;
+   common = grub-core/kern/err.c;
+   common = grub-core/kern/file.c;
+   common = grub-core/kern/fs.c;
+   common = grub-core/kern/list.c;
+   common = grub-core/kern/partition.c;
+   common = grub-core/lib/arg.c;
+   common = grub-core/lib/crc.c;
+   common = grub-core/lib/crypto.c;
+   common = grub-core/lib/envblk.c;
+   common = grub-core/lib/hexdump.c;
+   common = grub-core/lib/libgcrypt-grub/cipher/sha512.c;
+   common = grub-core/lib/LzFind.c;
+   common = grub-core/lib/LzmaEnc.c;
+   common = grub-core/lib/pbkdf2.c;
+   common = grub-core/normal/datetime.c;
+   common = grub-core/normal/misc.c;
+   common = grub-core/partmap/acorn.c;
+   common = grub-core/partmap/amiga.c;
+   common = grub-core/partmap/apple.c;
+   common = grub-core/partmap/gpt.c;
+   common = grub-core/partmap/msdos.c;
+   common = grub-core/partmap/sun.c;
+   common = grub-core/script/function.c;
+   common = grub-core/script/lexer.c;
+   common = grub-core/script/main.c;
+   common = grub-core/script/script.c;
+   common = grub-core/script/argv.c;
+ };
+ program = {
+   name = grub-bin2h;
+   common = util/bin2h.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER)';
+   mansection = 1;
+ };
+ program = {
+   name = grub-mkimage;
+   mansection = 1;
+   common = util/grub-mkimage.c;
+   common = util/resolve.c;
+   extra_dist = util/grub-mkimagexx.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER)';
+   cppflags = '-DGRUB_PKGLIBROOTDIR=\"$(pkglibrootdir)\"';
+ };
+ program = {
+   name = grub-mkrelpath;
+   mansection = 1;
+   common = util/grub-mkrelpath.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER)';
+ };
+ program = {
+   name = grub-script-check;
+   mansection = 1;
+   common = util/grub-script-check.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER)';
+ };
+ program = {
+   name = grub-editenv;
+   mansection = 1;
+   common = util/grub-editenv.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER)';
+ };
+ program = {
+   name = grub-mkpasswd-pbkdf2;
+   mansection = 1;
+   common = util/grub-mkpasswd-pbkdf2.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER)';
+   cflags = '$(CFLAGS_GCRY)';
+   cppflags = '$(CPPFLAGS_GCRY)';
+ };
+ program = {
+   name = grub-macho2img;
+   mansection = 1;
+   common = util/grub-macho2img.c;
+   condition = COND_APPLE_CC;
+ };
+ program = {
+   name = grub-pe2elf;
+   mansection = 1;
+   common = util/grub-pe2elf.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL)';
+   condition = COND_GRUB_PE2ELF;
+ };
+ program = {
+   name = grub-fstest;
+   mansection = 1;
+   common = util/grub-fstest.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER)';
+   condition = COND_GRUB_FSTEST;
+ };
+ program = {
+   name = grub-mkfont;
+   mansection = 1;
+   common = util/grub-mkfont.c;
+   common = grub-core/unidata.c;
+   cflags = '$(freetype_cflags)';
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER)';
+   ldflags = '$(freetype_libs)';
+   condition = COND_GRUB_MKFONT;
+ };
+ program = {
+   name = grub-mkdevicemap;
+   installdir = sbin;
+   mansection = 8;
+   common = util/grub-mkdevicemap.c;
+   common = util/deviceiter.c;
+   nosparc64 = util/devicemap.c;
+   sparc64_ieee1275 = util/ieee1275/ofpath.c;
+   sparc64_ieee1275 = util/ieee1275/devicemap.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)';
+ };
+ program = {
+   name = grub-probe;
+   installdir = sbin;
+   mansection = 8;
+   common = util/grub-probe.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)';
+ };
+ program = {
+   name = grub-setup;
+   installdir = sbin;
+   mansection = 8;
+   i386_pc = util/i386/pc/grub-setup.c;
+   i386_pc = util/raid.c;
+   i386_pc = util/lvm.c;
+   sparc64_ieee1275 = util/ieee1275/ofpath.c;
+   sparc64_ieee1275 = util/sparc64/ieee1275/grub-setup.c;
+   sparc64_ieee1275 = util/raid.c;
+   sparc64_ieee1275 = util/lvm.c;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)';
+   enable = i386_pc;
+   enable = sparc64_ieee1275;
+ };
+ program = {
+   name = grub-ofpathname;
+   installdir = sbin;
+   ieee1275 = util/ieee1275/grub-ofpathname.c;
+   ieee1275 = util/ieee1275/ofpath.c;
+   ldadd = libgrub.a;
+   enable = sparc64_ieee1275;
+ };
+ data = {
+   common = util/grub.d/README;
+   installdir = grubconf;
+ };
+ script = {
+   name = '00_header';
+   common = util/grub.d/00_header.in;
+   installdir = grubconf;
+ };
+ script = {
+   name = '10_windows';
+   common = util/grub.d/10_windows.in;
+   installdir = grubconf;
+   condition = COND_HOST_WINDOWS;
+ };
+ script = {
+   name = '10_hurd';
+   common = util/grub.d/10_hurd.in;
+   installdir = grubconf;
+   condition = COND_HOST_HURD;
+ };
+ script = {
+   name = '10_kfreebsd';
+   common = util/grub.d/10_kfreebsd.in;
+   installdir = grubconf;
+   condition = COND_HOST_KFREEBSD;
+ };
+ script = {
+   name = '10_netbsd';
+   common = util/grub.d/10_netbsd.in;
+   installdir = grubconf;
+   condition = COND_HOST_NETBSD;
+ };
+ script = {
+   name = '10_linux';
+   common = util/grub.d/10_linux.in;
+   installdir = grubconf;
+   condition = COND_HOST_LINUX;
+ };
+ script = {
+   name = '20_linux_xen';
+   common = util/grub.d/20_linux_xen.in;
+   installdir = grubconf;
+   condition = COND_HOST_LINUX;
+ };
+ script = {
+   name = '30_os-prober';
+   common = util/grub.d/30_os-prober.in;
+   installdir = grubconf;
+ };
+ script = {
+   name = '40_custom';
+   common = util/grub.d/40_custom.in;
+   installdir = grubconf;
+ };
+ script = {
+   name = '41_custom';
+   common = util/grub.d/41_custom.in;
+   installdir = grubconf;
+ };
+ script = {
+   mansection = 1;
+   name = grub-mkrescue;
+   x86_noieee1275 = util/grub-mkrescue.in;
+   powerpc_ieee1275 = util/powerpc/ieee1275/grub-mkrescue.in;
+   enable = i386_pc;
+   enable = x86_efi;
+   enable = i386_qemu;
+   enable = i386_coreboot;
+   enable = powerpc_ieee1275;
+ };
+ script = {
+   mansection = 8;
+   installdir = sbin;
+   name = grub-install;
+   mips = util/grub-install.in;
+   i386_noefi_noieee1275 = util/grub-install.in;
+   x86_efi = util/i386/efi/grub-install.in;
+   i386_ieee1275 = util/ieee1275/grub-install.in;
+   powerpc_ieee1275 = util/ieee1275/grub-install.in;
+   enable = x86;
+   enable = mips;
+   enable = powerpc_ieee1275;
+ };
+ script = {
+   name = grub-mkconfig;
+   common = util/grub-mkconfig.in;
+   mansection = 8;
+   installdir = sbin;
+ };
+ script = {
+   name = grub-set-default;
+   common = util/grub-set-default.in;
+   mansection = 8;
+   installdir = sbin;
+ };
+ script = {
+   name = grub-reboot;
+   common = util/grub-reboot.in;
+   mansection = 8;
+   installdir = sbin;
+ };
+ script = {
+   name = grub-mkconfig_lib;
+   common = util/grub-mkconfig_lib.in;
+   installdir = noinst;
+ };
+ script = {
+   name = update-grub_lib;
+   common = util/update-grub_lib.in;
+   installdir = noinst;
+ };
+ script = {
+   name = grub-shell;
+   common = tests/util/grub-shell.in;
+   installdir = noinst;
+ };
+ script = {
+   name = grub-shell-tester;
+   common = tests/util/grub-shell-tester.in;
+   installdir = noinst;
+ };
+ script = {
+   testcase;
+   name = example_scripted_test;
+   common = tests/example_scripted_test.in;
+ };
+ script = {
+   testcase;
+   name = example_grub_script_test;
+   common = tests/example_grub_script_test.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_echo1;
+   common = tests/grub_script_echo1.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_echo_keywords;
+   common = tests/grub_script_echo_keywords.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_vars1;
+   common = tests/grub_script_vars1.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_for1;
+   common = tests/grub_script_for1.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_while1;
+   common = tests/grub_script_while1.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_if;
+   common = tests/grub_script_if.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_blanklines;
+   common = tests/grub_script_blanklines.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_final_semicolon;
+   common = tests/grub_script_final_semicolon.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_dollar;
+   common = tests/grub_script_dollar.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_comments;
+   common = tests/grub_script_comments.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_functions;
+   common = tests/grub_script_functions.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_break;
+   common = tests/grub_script_break.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_continue;
+   common = tests/grub_script_continue.in;
+ };
+ script = {
+   testcase;
+   name = grub_script_shift;
+   common = tests/grub_script_shift.in;
+ };
++script = {
++  testcase;
++  name = grub_script_setparams;
++  common = tests/grub_script_setparams.in;
++};
++
+ program = {
+   testcase;
+   name = example_unit_test;
+   common = tests/example_unit_test.c;
+   common = tests/lib/unit_test.c;
+   common = grub-core/kern/list.c;
+   common = grub-core/kern/misc.c;
+   common = grub-core/tests/lib/test.c;
+   cflags = -Wno-format;
+   ldadd = libgrub.a;
+   ldflags = '$(LIBDEVMAPPER)';
+ };
index 0000000000000000000000000000000000000000,b69ee39c57be092dbbe358cf9879a0fc16bf98fe..c642ea9c59594fa7d59eb1a153dccf78a77c6865
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,133 +1,150 @@@
+ /* argv.c - methods for constructing argument vector */
+ /*
+  *  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/script_sh.h>
+ /* Return nearest power of two that is >= v.  */
+ static unsigned
+ round_up_exp (unsigned v)
+ {
+   v--;
+   v |= v >> 1;
+   v |= v >> 2;
+   v |= v >> 4;
+   v |= v >> 8;
+   v |= v >> 16;
+   if (sizeof (v) > 4)
+     v |= v >> 32;
+   v++;
+   v += (v == 0);
+   return v;
+ }
+ void
+ grub_script_argv_free (struct grub_script_argv *argv)
+ {
+   unsigned i;
+   if (argv->args)
+     {
+       for (i = 0; i < argv->argc; i++)
+       grub_free (argv->args[i]);
+       grub_free (argv->args);
+     }
+   argv->argc = 0;
+   argv->args = 0;
+ }
++/* Make argv from argc, args pair.  */
++int
++grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args)
++{
++  int i;
++  struct grub_script_argv r = { 0, 0};
++
++  for (i = 0; i < argc; i++)
++    if (grub_script_argv_next (&r) || grub_script_argv_append (&r, args[i]))
++      {
++      grub_script_argv_free (&r);
++      return 1;
++      }
++  *argv = r;
++  return 0;
++}
++
+ /* Prepare for next argc.  */
+ int
+ grub_script_argv_next (struct grub_script_argv *argv)
+ {
+   char **p = argv->args;
+   if (argv->args && argv->args[argv->argc - 1] == 0)
+     return 0;
+   p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *)));
+   if (! p)
+     return 1;
+   argv->argc++;
+   argv->args = p;
+   if (argv->argc == 1)
+     argv->args[0] = 0;
+   argv->args[argv->argc] = 0;
+   return 0;
+ }
+ /* Append `s' to the last argument.  */
+ int
+ grub_script_argv_append (struct grub_script_argv *argv, const char *s)
+ {
+   int a, b;
+   char *p = argv->args[argv->argc - 1];
+   if (! s)
+     return 0;
+   a = p ? grub_strlen (p) : 0;
+   b = grub_strlen (s);
+   p = grub_realloc (p, round_up_exp ((a + b + 1) * sizeof (char)));
+   if (! p)
+     return 1;
+   grub_strcpy (p + a, s);
+   argv->args[argv->argc - 1] = p;
+   return 0;
+ }
+ /* Split `s' and append words as multiple arguments.  */
+ int
+ grub_script_argv_split_append (struct grub_script_argv *argv, char *s)
+ {
+   char ch;
+   char *p;
+   int errors = 0;
+   if (! s)
+     return 0;
+   while (! errors && *s)
+     {
+       p = s;
+       while (*s && ! grub_isspace (*s))
+       s++;
+       ch = *s;
+       *s = '\0';
+       errors += grub_script_argv_append (argv, p);
+       *s = ch;
+       while (*s && grub_isspace (*s))
+       s++;
+       if (*s)
+       errors += grub_script_argv_next (argv);
+     }
+   return errors;
+ }
index 0000000000000000000000000000000000000000,26a46b12b0d48d94dffa41f233fac7387b23e519..b911163f7bd67f4f38e1b0b828f5eaea89dffbdb
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,527 +1,578 @@@
 -      unsigned i;
 -
+ /* execute.c -- Execute a GRUB script.  */
+ /*
+  *  GRUB  --  GRand Unified Bootloader
+  *  Copyright (C) 2005,2007,2008,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/misc.h>
+ #include <grub/mm.h>
+ #include <grub/env.h>
+ #include <grub/script_sh.h>
+ #include <grub/command.h>
+ #include <grub/menu.h>
+ #include <grub/lib/arg.h>
+ #include <grub/normal.h>
+ /* Max digits for a char is 3 (0xFF is 255), similarly for an int it
+    is sizeof (int) * 3, and one extra for a possible -ve sign.  */
+ #define ERRNO_DIGITS_MAX  (sizeof (int) * 3 + 1)
+ static unsigned long is_continue;
+ static unsigned long active_loops;
+ static unsigned long active_breaks;
++#define GRUB_SCRIPT_SCOPE_MALLOCED      1
++#define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2
++
+ /* Scope for grub script functions.  */
+ struct grub_script_scope
+ {
++  unsigned flags;
++  unsigned shifts;
+   struct grub_script_argv argv;
+ };
+ static struct grub_script_scope *scope = 0;
++static void
++replace_scope (struct grub_script_scope *new_scope)
++{
++  if (scope)
++    {
++      scope->argv.argc += scope->shifts;
++      scope->argv.args -= scope->shifts;
++
++      if (scope->flags & GRUB_SCRIPT_SCOPE_ARGS_MALLOCED)
++      grub_script_argv_free (&scope->argv);
++
++      if (scope->flags & GRUB_SCRIPT_SCOPE_MALLOCED)
++      grub_free (scope);
++    }
++  scope = new_scope;
++}
++
+ grub_err_t
+ grub_script_break (grub_command_t cmd, int argc, char *argv[])
+ {
+   char *p = 0;
+   unsigned long count;
+   if (argc == 0)
+     count = 1;
+   else if ((argc > 1) || (count = grub_strtoul (argv[0], &p, 10)) == 0 ||
+          (*p != '\0'))
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad break");
+   is_continue = grub_strcmp (cmd->name, "break") ? 1 : 0;
+   active_breaks = grub_min (active_loops, count);
+   return GRUB_ERR_NONE;
+ }
+ grub_err_t
+ grub_script_shift (grub_command_t cmd __attribute__((unused)),
+                  int argc, char *argv[])
+ {
+   char *p = 0;
+   unsigned long n = 0;
+   if (! scope)
+     return GRUB_ERR_NONE;
+   if (argc == 0)
+     n = 1;
+   else if (argc > 1)
+     return GRUB_ERR_BAD_ARGUMENT;
+   else
+     {
+       n = grub_strtoul (argv[0], &p, 10);
+       if (*p != '\0')
+       return GRUB_ERR_BAD_ARGUMENT;
+     }
+   if (n > scope->argv.argc)
+     return GRUB_ERR_BAD_ARGUMENT;
++  scope->shifts += n;
+   scope->argv.argc -= n;
+   scope->argv.args += n;
+   return GRUB_ERR_NONE;
+ }
++grub_err_t
++grub_script_setparams (grub_command_t cmd __attribute__((unused)),
++                     int argc, char **args)
++{
++  struct grub_script_scope *new_scope;
++  struct grub_script_argv argv = { 0, 0 };
++
++  if (! scope)
++    return GRUB_ERR_INVALID_COMMAND;
++
++  new_scope = grub_malloc (sizeof (*new_scope));
++  if (! new_scope)
++    return grub_errno;
++
++  if (grub_script_argv_make (&argv, argc, args))
++    {
++      grub_free (new_scope);
++      return grub_errno;
++    }
++
++  new_scope->shifts = 0;
++  new_scope->argv = argv;
++  new_scope->flags = GRUB_SCRIPT_SCOPE_MALLOCED |
++    GRUB_SCRIPT_SCOPE_ARGS_MALLOCED;
++
++  replace_scope (new_scope);
++  return GRUB_ERR_NONE;
++}
++
+ static int
+ grub_env_special (const char *name)
+ {
+   if (grub_isdigit (name[0]) ||
+       grub_strcmp (name, "#") == 0 ||
+       grub_strcmp (name, "*") == 0 ||
+       grub_strcmp (name, "@") == 0)
+     return 1;
+   return 0;
+ }
+ static char **
+ grub_script_env_get (const char *name, grub_script_arg_type_t type)
+ {
++  unsigned i;
+   struct grub_script_argv result = { 0, 0 };
+   if (grub_script_argv_next (&result))
+     goto fail;
+   if (! grub_env_special (name))
+     {
+       char *v = grub_env_get (name);
+       if (v && v[0])
+       {
+         if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
+           {
+             if (grub_script_argv_split_append (&result, v))
+               goto fail;
+           }
+         else
+           if (grub_script_argv_append (&result, v))
+             goto fail;
+       }
+     }
+   else if (! scope)
+     {
+       if (grub_script_argv_append (&result, 0))
+       goto fail;
+     }
+   else if (grub_strcmp (name, "#") == 0)
+     {
+       char buffer[ERRNO_DIGITS_MAX + 1];
+       grub_snprintf (buffer, sizeof (buffer), "%u", scope->argv.argc);
+       if (grub_script_argv_append (&result, buffer))
+       goto fail;
+     }
+   else if (grub_strcmp (name, "*") == 0)
+     {
 -      unsigned i;
 -
+       for (i = 0; i < scope->argv.argc; i++)
+       if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
+         {
+           if (i != 0 && grub_script_argv_next (&result))
+             goto fail;
+           if (grub_script_argv_split_append (&result, scope->argv.args[i]))
+             goto fail;
+         }
+       else
+         {
+           if (i != 0 && grub_script_argv_append (&result, " "))
+             goto fail;
+           if (grub_script_argv_append (&result, scope->argv.args[i]))
+             goto fail;
+         }
+     }
+   else if (grub_strcmp (name, "@") == 0)
+     {
 -  scope = old_scope;
+       for (i = 0; i < scope->argv.argc; i++)
+       {
+         if (i != 0 && grub_script_argv_next (&result))
+           goto fail;
+         if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
+           {
+             if (grub_script_argv_split_append (&result, scope->argv.args[i]))
+               goto fail;
+           }
+         else
+           if (grub_script_argv_append (&result, scope->argv.args[i]))
+             goto fail;
+       }
+     }
+   else
+     {
+       unsigned long num = grub_strtoul (name, 0, 10);
+       if (num == 0)
+       ; /* XXX no file name, for now.  */
+       else if (num <= scope->argv.argc)
+       {
+         if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
+           {
+             if (grub_script_argv_split_append (&result,
+                                                scope->argv.args[num - 1]))
+               goto fail;
+           }
+         else
+           if (grub_script_argv_append (&result, scope->argv.args[num - 1]))
+             goto fail;
+       }
+     }
+   return result.args;
+  fail:
+   grub_script_argv_free (&result);
+   return 0;
+ }
+ static grub_err_t
+ grub_script_env_set (const char *name, const char *val)
+ {
+   if (grub_env_special (name))
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad variable name");
+   return grub_env_set (name, val);
+ }
+ /* Expand arguments in ARGLIST into multiple arguments.  */
+ static int
+ grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
+                            struct grub_script_argv *argv)
+ {
+   int i;
+   char **values = 0;
+   struct grub_script_arg *arg = 0;
+   struct grub_script_argv result = { 0, 0 };
+   for (; arglist && arglist->arg; arglist = arglist->next)
+     {
+       if (grub_script_argv_next (&result))
+       goto fail;
+       arg = arglist->arg;
+       while (arg)
+       {
+         switch (arg->type)
+           {
+           case GRUB_SCRIPT_ARG_TYPE_VAR:
+           case GRUB_SCRIPT_ARG_TYPE_DQVAR:
+             values = grub_script_env_get (arg->str, arg->type);
+             for (i = 0; values && values[i]; i++)
+               {
+                 if (i != 0 && grub_script_argv_next (&result))
+                   goto fail;
+                 if (grub_script_argv_append (&result, values[i]))
+                   goto fail;
+               }
+             grub_free (values);
+             break;
+           case GRUB_SCRIPT_ARG_TYPE_TEXT:
+             if (grub_strlen (arg->str) &&
+                 grub_script_argv_append (&result, arg->str))
+               goto fail;
+             break;
+           case GRUB_SCRIPT_ARG_TYPE_DQSTR:
+           case GRUB_SCRIPT_ARG_TYPE_SQSTR:
+             if (grub_script_argv_append (&result, arg->str))
+               goto fail;
+             break;
+           }
+         arg = arg->next;
+       }
+     }
+   if (! result.args[result.argc - 1])
+     result.argc--;
+   *argv = result;
+   return 0;
+  fail:
+   grub_script_argv_free (&result);
+   return 1;
+ }
+ static grub_err_t
+ grub_script_execute_cmd (struct grub_script_cmd *cmd)
+ {
+   int ret;
+   char errnobuf[ERRNO_DIGITS_MAX + 1];
+   if (cmd == 0)
+     return 0;
+   ret = cmd->exec (cmd);
+   grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
+   grub_env_set ("?", errnobuf);
+   return ret;
+ }
+ /* Execute a function call.  */
+ grub_err_t
+ grub_script_function_call (grub_script_function_t func, int argc, char **args)
+ {
+   grub_err_t ret = 0;
+   unsigned long loops = active_loops;
+   struct grub_script_scope *old_scope;
+   struct grub_script_scope new_scope;
+   active_loops = 0;
++  new_scope.flags = 0;
++  new_scope.shifts = 0;
+   new_scope.argv.argc = argc;
+   new_scope.argv.args = args;
+   old_scope = scope;
+   scope = &new_scope;
+   ret = grub_script_execute (func->func);
+   active_loops = loops;
++  replace_scope (old_scope); /* free any scopes by setparams */
+   return ret;
+ }
+ /* Execute a single command line.  */
+ grub_err_t
+ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
+ {
+   struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd;
+   grub_command_t grubcmd;
+   grub_err_t ret = 0;
+   grub_script_function_t func = 0;
+   char errnobuf[18];
+   char *cmdname;
+   struct grub_script_argv argv = { 0, 0 };
+   /* Lookup the command.  */
+   if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0])
+     return grub_errno;
+   cmdname = argv.args[0];
+   grubcmd = grub_command_find (cmdname);
+   if (! grubcmd)
+     {
+       grub_errno = GRUB_ERR_NONE;
+       /* It's not a GRUB command, try all functions.  */
+       func = grub_script_function_find (cmdname);
+       if (! func)
+       {
+         /* As a last resort, try if it is an assignment.  */
+         char *assign = grub_strdup (cmdname);
+         char *eq = grub_strchr (assign, '=');
+         if (eq)
+           {
+             /* This was set because the command was not found.  */
+             grub_errno = GRUB_ERR_NONE;
+             /* Create two strings and set the variable.  */
+             *eq = '\0';
+             eq++;
+             grub_script_env_set (assign, eq);
+           }
+         grub_free (assign);
+         grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno);
+         grub_script_env_set ("?", errnobuf);
+         grub_script_argv_free (&argv);
+         grub_print_error ();
+         return 0;
+       }
+     }
+   /* Execute the GRUB command or function.  */
+   if (grubcmd)
+     ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1);
+   else
+     ret = grub_script_function_call (func, argv.argc - 1, argv.args + 1);
+   /* Free arguments.  */
+   grub_script_argv_free (&argv);
+   if (grub_errno == GRUB_ERR_TEST_FAILURE)
+     grub_errno = GRUB_ERR_NONE;
+   grub_print_error ();
+   grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret);
+   grub_env_set ("?", errnobuf);
+   return ret;
+ }
+ /* Execute a block of one or more commands.  */
+ grub_err_t
+ grub_script_execute_cmdlist (struct grub_script_cmd *list)
+ {
+   int ret = 0;
+   struct grub_script_cmd *cmd;
+   /* Loop over every command and execute it.  */
+   for (cmd = list->next; cmd && ! active_breaks; cmd = cmd->next)
+     ret = grub_script_execute_cmd (cmd);
+   return ret;
+ }
+ /* Execute an if statement.  */
+ grub_err_t
+ grub_script_execute_cmdif (struct grub_script_cmd *cmd)
+ {
+   struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
+   char *result;
+   /* Check if the commands results in a true or a false.  The value is
+      read from the env variable `?'.  */
+   grub_script_execute_cmd (cmdif->exec_to_evaluate);
+   result = grub_env_get ("?");
+   grub_errno = GRUB_ERR_NONE;
+   /* Execute the `if' or the `else' part depending on the value of
+      `?'.  */
+   if (result && ! grub_strcmp (result, "0"))
+     return grub_script_execute_cmd (cmdif->exec_on_true);
+   else
+     return grub_script_execute_cmd (cmdif->exec_on_false);
+ }
+ /* Execute a for statement.  */
+ grub_err_t
+ grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
+ {
+   unsigned i;
+   grub_err_t result;
+   struct grub_script_argv argv = { 0, 0 };
+   struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd;
+   if (grub_script_arglist_to_argv (cmdfor->words, &argv))
+     return grub_errno;
+   active_loops++;
+   result = 0;
+   for (i = 0; i < argv.argc; i++)
+     {
+       if (is_continue && active_breaks == 1)
+       active_breaks = 0;
+       if (! active_breaks)
+       {
+         grub_script_env_set (cmdfor->name->str, argv.args[i]);
+         result = grub_script_execute_cmd (cmdfor->list);
+       }
+     }
+   if (active_breaks)
+     active_breaks--;
+   active_loops--;
+   grub_script_argv_free (&argv);
+   return result;
+ }
+ /* Execute a "while" or "until" command.  */
+ grub_err_t
+ grub_script_execute_cmdwhile (struct grub_script_cmd *cmd)
+ {
+   int cond;
+   int result;
+   struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd;
+   active_loops++;
+   result = 0;
+   do {
+     cond = grub_script_execute_cmd (cmdwhile->cond);
+     if (cmdwhile->until ? !cond : cond)
+       break;
+     result = grub_script_execute_cmd (cmdwhile->list);
+     if (active_breaks == 1 && is_continue)
+       active_breaks = 0;
+     if (active_breaks)
+       break;
+   } while (1); /* XXX Put a check for ^C here */
+   if (active_breaks)
+     active_breaks--;
+   active_loops--;
+   return result;
+ }
+ /* Execute the menu entry generate statement.  */
+ grub_err_t
+ grub_script_execute_menuentry (struct grub_script_cmd *cmd)
+ {
+   struct grub_script_cmd_menuentry *cmd_menuentry;
+   struct grub_script_argv argv = { 0, 0 };
+   cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd;
+   if (cmd_menuentry->arglist)
+     {
+       if (grub_script_arglist_to_argv (cmd_menuentry->arglist, &argv))
+       return grub_errno;
+     }
+   grub_normal_add_menu_entry (argv.argc, (const char **) argv.args,
+                             cmd_menuentry->sourcecode);
+   grub_script_argv_free (&argv);
+   return grub_errno;
+ }
+ /* Execute any GRUB pre-parsed command or script.  */
+ grub_err_t
+ grub_script_execute (struct grub_script *script)
+ {
+   if (script == 0)
+     return 0;
+   return grub_script_execute_cmd (script->cmd);
+ }
index 0000000000000000000000000000000000000000,ff714d060f28567a17a4492807a3240237b9d3c9..a16a65c13c47fd298e7990e724fea1d60f2f270c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,73 +1,81 @@@
+ /*
+  *  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/i18n.h>
+ #include <grub/parser.h>
+ #include <grub/script_sh.h>
+ grub_err_t
+ grub_normal_parse_line (char *line, grub_reader_getline_t getline)
+ {
+   struct grub_script *parsed_script;
+   /* Parse the script.  */
+   parsed_script = grub_script_parse (line, getline);
+   if (parsed_script)
+     {
+       /* Execute the command(s).  */
+       grub_script_execute (parsed_script);
+       /* The parsed script was executed, throw it away.  */
+       grub_script_free (parsed_script);
+     }
+   return grub_errno;
+ }
+ static grub_command_t cmd_break;
+ static grub_command_t cmd_continue;
+ static grub_command_t cmd_shift;
++static grub_command_t cmd_setparams;
+ void
+ grub_script_init (void)
+ {
+   cmd_break = grub_register_command ("break", grub_script_break,
+                                    N_("[n]"), N_("Exit from loops"));
+   cmd_continue = grub_register_command ("continue", grub_script_break,
+                                       N_("[n]"), N_("Continue loops"));
+   cmd_shift = grub_register_command ("shift", grub_script_shift,
+                                    N_("[n]"), N_("Shift positional parameters."));
++  cmd_setparams = grub_register_command ("setparams", grub_script_setparams,
++                                       N_("[VALUE]..."),
++                                       N_("Set positional parameters."));
+ }
+ void
+ grub_script_fini (void)
+ {
+   if (cmd_break)
+     grub_unregister_command (cmd_break);
+   cmd_break = 0;
+   if (cmd_continue)
+     grub_unregister_command (cmd_continue);
+   cmd_continue = 0;
+   if (cmd_shift)
+     grub_unregister_command (cmd_shift);
+   cmd_shift = 0;
++
++  if (cmd_setparams)
++    grub_unregister_command (cmd_setparams);
++  cmd_setparams = 0;
+ }