All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] GRUB script shell expansion for *
@ 2010-05-18 16:07 BVK Chaitanya
  2010-05-18 17:22 ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 1 reply; 3+ messages in thread
From: BVK Chaitanya @ 2010-05-18 16:07 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 232 bytes --]

Hi,


Attached patch adds support for path name expansion for * in
grub-script.  So, we can now use *, (*,msdos*), */boot/grub/*.mod,
etc. in grub scripts.  It is available in people/bvk/shell-expansion
branch.



-- 
bvk.chaitanya

[-- Attachment #2: shell-expansion.patch --]
[-- Type: text/x-diff, Size: 23372 bytes --]

# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: bvk.groups@gmail.com-20100518153335-a1fw3v34xm56zdpu
# target_branch: ../cmdlist/
# testament_sha1: d7f4cd00982ced62f3dc9a8e039ca883acc23046
# timestamp: 2010-05-18 21:26:14 +0530
# base_revision_id: bvk.groups@gmail.com-20100512082350-\
#   en6z2k5s1ux46lg3
# 
# Begin patch
=== modified file 'conf/tests.rmk'
--- conf/tests.rmk	2010-05-05 09:17:50 +0000
+++ conf/tests.rmk	2010-05-18 15:33:35 +0000
@@ -74,6 +74,9 @@
 check_SCRIPTS += grub_script_functions
 grub_script_functions_SOURCES = tests/grub_script_functions.in
 
+check_SCRIPTS += grub_script_expansion
+grub_script_expansion_SOURCES = tests/grub_script_expansion.in
+
 # List of tests to execute on "make check"
 # SCRIPTED_TESTS    = example_scripted_test
 # SCRIPTED_TESTS   += example_grub_script_test
@@ -91,6 +94,7 @@
 SCRIPTED_TESTS += grub_script_dollar
 SCRIPTED_TESTS += grub_script_comments
 SCRIPTED_TESTS += grub_script_functions
+SCRIPTED_TESTS += grub_script_expansion
 
 # dependencies between tests and testing-tools
 $(SCRIPTED_TESTS): grub-shell grub-shell-tester

=== modified file 'include/grub/script_sh.h'
--- include/grub/script_sh.h	2010-05-12 04:49:12 +0000
+++ include/grub/script_sh.h	2010-05-18 15:33:35 +0000
@@ -225,7 +225,12 @@
 void grub_script_argv_free    (struct grub_script_argv *argv);
 int grub_script_argv_next     (struct grub_script_argv *argv);
 int grub_script_argv_append   (struct grub_script_argv *argv, const char *s);
+int grub_script_argv_append_escaped (struct grub_script_argv *argv,
+				     const char *s);
+int grub_script_argv_append_unescaped (struct grub_script_argv *argv,
+				       const char *s);
 int grub_script_argv_split_append (struct grub_script_argv *argv, char *s);
+int grub_script_argv_expand   (struct grub_script_argv *argv);
 
 struct grub_script_arglist *
 grub_script_create_arglist (struct grub_parser_param *state);

=== modified file 'script/argv.c'
--- script/argv.c	2010-05-12 04:49:12 +0000
+++ script/argv.c	2010-05-18 15:33:35 +0000
@@ -18,11 +18,32 @@
  */
 
 #include <grub/mm.h>
+#include <grub/fs.h>
+#include <grub/env.h>
+#include <grub/file.h>
+#include <grub/device.h>
 #include <grub/script_sh.h>
 
+#include <regex.h>
+
 #define ARG_ALLOCATION_UNIT  (32 * sizeof (char))
 #define ARGV_ALLOCATION_UNIT (8 * sizeof (void*))
 
+static inline int regexop (char ch);
+static char ** merge (char **lhs, char **rhs);
+static char *make_dir (const char *prefix, const char *start, const char *end);
+static int make_regex (const char *regex_start, const char *regex_end,
+		       regex_t *regexp);
+static void split_path (char *path, char **suffix_end, char **regex_end);
+static char ** match_devices (const regex_t *regexp);
+static char ** match_files (const char *prefix, const char *suffix_start,
+			    const char *suffix_end, const regex_t *regexp);
+static char ** match_paths_with_escaped_suffix (char **paths,
+						const char *suffix_start,
+						const char *suffix_end,
+						const regex_t *regexp);
+static int expand (char *arg, struct grub_script_argv *argv);
+
 void
 grub_script_argv_free (struct grub_script_argv *argv)
 {
@@ -73,29 +94,85 @@
   return 0;
 }
 
-/* Append `s' to the last argument.  */
-int
-grub_script_argv_append (struct grub_script_argv *argv, const char *s)
+enum append_type {
+  APPEND_RAW,
+  APPEND_ESCAPED,
+  APPEND_UNESCAPED
+};
+
+static int
+append (struct grub_script_argv *argv, const char *s, enum append_type type)
 {
-  int a, b;
+  int a;
+  int b;
+  char ch;
   char *p = argv->args[argv->argc - 1];
 
   if (! s)
     return 0;
 
   a = p ? grub_strlen (p) : 0;
-  b = grub_strlen (s);
+  b = grub_strlen (s) * (type == APPEND_ESCAPED ? 2 : 1);
 
   p = grub_realloc (p, ALIGN_UP ((a + b + 1) * sizeof (char),
 				 ARG_ALLOCATION_UNIT));
   if (! p)
     return 1;
 
-  grub_strcpy (p + a, s);
+  switch (type)
+    {
+    case APPEND_RAW:
+      grub_strcpy (p + a, s);
+      break;
+
+    case APPEND_ESCAPED:
+      while ((ch = *s++))
+	{
+	  if (regexop (ch))
+	    p[a++] = '\\';
+	  p[a++] = ch;
+	}
+      p[a] = '\0';
+      break;
+
+    case APPEND_UNESCAPED:
+      while ((ch = *s++))
+	{
+	  if (ch == '\\' && regexop (*s))
+	    p[a++] = *s++;
+	  else
+	    p[a++] = ch;
+	}
+      p[a] = '\0';
+      break;
+    }
+
   argv->args[argv->argc - 1] = p;
   return 0;
 }
 
+
+/* Append `s' to the last argument.  */
+int
+grub_script_argv_append (struct grub_script_argv *argv, const char *s)
+{
+  return append (argv, s, APPEND_RAW);
+}
+
+/* Append `s' to the last argument, but escape any shell regex ops.  */
+int
+grub_script_argv_append_escaped (struct grub_script_argv *argv, const char *s)
+{
+  return append (argv, s, APPEND_ESCAPED);
+}
+
+/* Append `s' to the last argument, but unescape any escaped shell regex ops.  */
+int
+grub_script_argv_append_unescaped (struct grub_script_argv *argv, const char *s)
+{
+  return append (argv, s, APPEND_UNESCAPED);
+}
+
 /* Split `s' and append words as multiple arguments.  */
 int
 grub_script_argv_split_append (struct grub_script_argv *argv, char *s)
@@ -126,3 +203,452 @@
     }
   return errors;
 }
+
+/* Expand `argv' as per shell expansion rules.  */
+int
+grub_script_argv_expand (struct grub_script_argv *argv)
+{
+  int i;
+  struct grub_script_argv result = { 0, 0 };
+
+  for (i = 0; argv->args[i]; i++)
+    if (expand (argv->args[i], &result))
+      goto fail;
+
+  grub_script_argv_free (argv);
+  *argv = result;
+  return 0;
+
+ fail:
+
+  grub_script_argv_free (&result);
+  return 1;
+}
+
+static char **
+merge (char **dest, char **ps)
+{
+  int i;
+  int j;
+  char **p;
+
+  if (! dest)
+    return ps;
+
+  if (! ps)
+    return dest;
+
+  for (i = 0; dest[i]; i++)
+    ;
+  for (j = 0; ps[j]; j++)
+    ;
+
+  p = grub_realloc (dest, sizeof (char*) * (i + j + 1));
+  if (! p)
+    {
+      grub_free (dest);
+      grub_free (ps);
+      return 0;
+    }
+
+  for (j = 0; ps[j]; j++)
+    dest[i++] = ps[j];
+  dest[i] = 0;
+
+  grub_free (ps);
+  return dest;
+}
+
+static inline int
+regexop (char ch)
+{
+  return grub_strchr ("*.\\", ch) ? 1 : 0;
+}
+
+static char *
+make_dir (const char *prefix, const char *start, const char *end)
+{
+  char ch;
+  unsigned i;
+  unsigned n;
+  char *result;
+
+  i = grub_strlen (prefix);
+  n = i + end - start;
+
+  result = grub_malloc (n + 1);
+  if (! result)
+    return 0;
+
+  grub_strcpy (result, prefix);
+  while (start < end && (ch = *start++))
+    if (ch == '\\' && regexop (*start))
+      result[i++] = *start++;
+    else
+      result[i++] = ch;
+
+  result[i] = '\0';
+  return result;
+}
+
+static int
+make_regex (const char *start, const char *end, regex_t *regexp)
+{
+  char ch;
+  int i = 0;
+  unsigned len = end - start;
+  char *buffer = grub_malloc (len * 2 + 1); /* worst case size. */
+
+  while (start < end)
+    {
+      /* XXX Only * expansion for now.  */
+      switch ((ch = *start++))
+	{
+	case '\\':
+	  buffer[i++] = ch;
+	  if (*start != '\0')
+	    buffer[i++] = *start++;
+	  break;
+
+	case '.':
+	  buffer[i++] = '\\';
+	  buffer[i++] = '.';
+	  break;
+
+	case '*':
+	  buffer[i++] = '.';
+	  buffer[i++] = '*';
+	  break;
+
+	default:
+	  buffer[i++] = ch;
+	}
+    }
+  buffer[i] = '\0';
+
+  if (regcomp (regexp, buffer, RE_SYNTAX_GNU_AWK))
+    {
+      grub_free (buffer);
+      return 1;
+    }
+
+  grub_free (buffer);
+  return 0;
+}
+
+static void
+split_path (char *str, char **suffix_end, char **regex_end)
+{
+  char ch = 0;
+  int regex = 0;
+
+  char *end;
+  char *split;
+
+  split = end = str;
+  while ((ch = *end))
+    {
+      if (ch == '\\' && end[1])
+	end++;
+      else if (regexop (ch))
+	regex = 1;
+      else if (ch == '/' && ! regex)
+	split = end + 1;
+      else if (ch == '/' && regex)
+	break;
+
+      end++;
+    }
+
+  *regex_end = end;
+  if (! regex)
+    *suffix_end = end;
+  else
+    *suffix_end = split;
+}
+
+static char **
+match_devices (const regex_t *regexp)
+{
+  int i;
+  int ndev;
+  char **devs;
+  char *buffer;
+
+  auto int match (const char *name);
+  int match (const char *name)
+  {
+    void *t;
+    unsigned n;
+
+    n = grub_strlen (name);
+    t = grub_realloc (buffer, n + 3);
+    if (! t)
+      return 1;
+
+    buffer = (char *) t;
+    grub_snprintf (buffer, n + 3, "(%s)", name);
+
+    grub_dprintf ("expand", "matching: %s\n", buffer);
+    if (regexec (regexp, buffer, 0, 0, 0))
+      return 0;
+
+    t = grub_realloc (devs, sizeof (char*) * (ndev + 2));
+    if (! t)
+      return 1;
+
+    devs = (char **) t;
+    devs[ndev++] = buffer;
+    devs[ndev] = 0;
+    buffer = 0;
+    return 0;
+  }
+
+  ndev = 0;
+  devs = 0;
+  buffer = 0;
+
+  if (grub_device_iterate (match))
+    goto fail;
+
+  if (buffer)
+    grub_free (buffer);
+
+  return devs;
+
+ fail:
+
+  for (i = 0; devs && devs[i]; i++)
+    grub_free (devs[i]);
+
+  if (devs)
+    grub_free (devs);
+
+  if (buffer)
+    grub_free (buffer);
+
+  return 0;
+}
+
+static char **
+match_files (const char *prefix, const char *suffix, const char *end,
+	     const regex_t *regexp)
+{
+  int i;
+  int error;
+  char **files;
+  char *buffer;
+  unsigned nfile;
+  char *dir;
+  unsigned dirlen;
+  const char *path;
+  char *device_name;
+  grub_fs_t fs;
+  grub_device_t dev;
+
+  auto int match (const char *name, const struct grub_dirhook_info *info);
+  int match (const char *name, const struct grub_dirhook_info *info)
+  {
+    void *t;
+    unsigned n;
+
+    /* skip hidden files, . and .. */
+    if (name[0] == '.')
+      return 0;
+
+    grub_dprintf ("expand", "matching: %s in %s\n", name, dir);
+    if (regexec (regexp, name, 0, 0, 0))
+      return 0;
+
+    n = dirlen + grub_strlen (name);
+    t = grub_realloc (buffer, n + 1);
+    if (! t)
+      return 1;
+
+    buffer = (char *) t;
+    grub_snprintf (buffer, n + 1, "%s%s", dir, name);
+
+    t = grub_realloc (files, sizeof (char*) * (nfile + 2));
+    if (! t)
+      return 1;
+
+    files = (char **) t;
+    files[nfile++] = buffer;
+    files[nfile] = 0;
+    buffer = 0;
+    return 0;
+  }
+
+  nfile = 0;
+  files = 0;
+  dev = 0;
+  buffer = 0;
+  device_name = 0;
+  grub_error_push ();
+
+  dir = make_dir (prefix, suffix, end);
+  if (! dir)
+    goto fail;
+  dirlen = grub_strlen (dir);
+
+  device_name = grub_file_get_device_name (dir);
+  dev = grub_device_open (device_name);
+  if (! dev)
+    goto fail;
+
+  fs = grub_fs_probe (dev);
+  if (! fs)
+    goto fail;
+
+  path = grub_strchr (dir, ')');
+  if (! path)
+    goto fail;
+  path++;
+
+  if (fs->dir (dev, path, match))
+    goto fail;
+
+  if (buffer)
+    grub_free (buffer);
+
+  grub_free (dir);
+  grub_device_close (dev);
+  grub_free (device_name);
+  grub_error_pop ();
+  return files;
+
+ fail:
+
+  if (dir)
+    grub_free (dir);
+
+  for (i = 0; files && files[i]; i++)
+    grub_free (files[i]);
+
+  if (files)
+    grub_free (files);
+
+  if (dev)
+    grub_device_close (dev);
+
+  if (device_name)
+    grub_free (device_name);
+
+  if (buffer)
+    grub_free (buffer);
+
+  grub_error_pop ();
+  return 0;
+}
+
+static char **
+match_paths_with_escaped_suffix (char **paths,
+				 const char *suffix, const char *end,
+				 const regex_t *regexp)
+{
+  if (paths == 0 && suffix == end)
+    return match_devices (regexp);
+
+  else if (paths == 0 && suffix[0] == '(')
+    return match_files ("", suffix, end, regexp);
+
+  else if (paths == 0 && suffix[0] == '/')
+    {
+      char **r;
+      unsigned n;
+      char *root;
+      char *prefix;
+
+      root = grub_env_get ("root");
+      if (! root)
+	return 0;
+
+      n = grub_strlen (root) + 2;
+      prefix = grub_malloc (n + 1);
+      if (! prefix)
+	return 0;
+
+      grub_snprintf (prefix, n + 1, "(%s)", root);
+      r = match_files (prefix, suffix, end, regexp);
+      grub_free (prefix);
+      return r;
+    }
+  else if (paths)
+    {
+      int i, j;
+      char **r = 0;
+
+      for (i = 0; paths[i]; i++)
+	{
+	  char **p;
+
+	  p = match_files (paths[i], suffix, end, regexp);
+	  if (! p)
+	    continue;
+
+	  r = merge (r, p);
+	  if (! r)
+	    return 0;
+	}
+      return r;
+    }
+
+  return 0;
+}
+
+static int
+expand (char *arg, struct grub_script_argv *argv)
+{
+  char *p;
+  char *dir;
+  char *reg;
+  char **paths = 0;
+
+  unsigned i;
+  regex_t regex;
+
+  p = arg;
+  while (*p)
+    {
+      /* split `p' into two components: (p..dir), (dir...reg)
+
+	 (p...dir):  path that doesn't need expansion
+
+	 (dir...reg): part of path that needs expansion
+       */
+      split_path (p, &dir, &reg);
+      if (dir < reg)
+	{
+	  if (make_regex (dir, reg, &regex))
+	    goto fail;
+
+	  paths = match_paths_with_escaped_suffix (paths, p, dir, &regex);
+	  regfree (&regex);
+
+	  if (! paths)
+	    goto done;
+	}
+      p = reg;
+    }
+
+  if (! paths)
+    {
+      grub_script_argv_next (argv);
+      grub_script_argv_append_unescaped (argv, arg);
+    }
+  else
+    for (i = 0; paths[i]; i++)
+      {
+	grub_script_argv_next (argv);
+	grub_script_argv_append (argv, paths[i]);
+      }
+
+ done:
+
+  return 0;
+
+ fail:
+
+  regfree (&regex);
+  return 1;
+}

=== modified file 'script/execute.c'
--- script/execute.c	2010-05-12 07:42:49 +0000
+++ script/execute.c	2010-05-18 15:33:35 +0000
@@ -177,7 +177,13 @@
 		{
 		  if (i != 0)
 		    error += grub_script_argv_next (&result);
-		  error += grub_script_argv_append (&result, values[i]);
+
+		  if (arg->type == GRUB_SCRIPT_ARG_TYPE_VAR)
+		    error += grub_script_argv_append (&result, values[i]);
+		  else
+		    error += grub_script_argv_append_escaped (&result, values[i]);
+
+		  grub_free (values[i]);
 		}
 	      grub_free (values);
 	      break;
@@ -189,19 +195,23 @@
 
 	    case GRUB_SCRIPT_ARG_TYPE_DQSTR:
 	    case GRUB_SCRIPT_ARG_TYPE_SQSTR:
-	      error += grub_script_argv_append (&result, arg->str);
+	      error += grub_script_argv_append_escaped (&result, arg->str);
 	      break;
 	    }
 	  arg = arg->next;
 	}
     }
 
-  if (error)
-    return 1;
-
   if (! result.args[result.argc - 1])
     result.argc--;
 
+  error += grub_script_argv_expand (&result);
+  if (error)
+    {
+      grub_script_argv_free (&result);
+      return 1;
+    }
+
   *argv = result;
   return 0;
 }
@@ -287,6 +297,7 @@
 	  grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno);
 	  grub_env_set ("?", errnobuf);
 
+	  grub_script_argv_free (&argv);
 	  grub_print_error ();
 
 	  return 0;
@@ -411,7 +422,6 @@
 			      cmd_menuentry->sourcecode);
 
   grub_script_argv_free (&argv);
-
   return grub_errno;
 }
 

=== added file 'tests/grub_script_expansion.in'
--- tests/grub_script_expansion.in	1970-01-01 00:00:00 +0000
+++ tests/grub_script_expansion.in	2010-05-18 15:33:35 +0000
@@ -0,0 +1,35 @@
+#! /bin/bash -e
+
+# Run GRUB script in a Qemu instance
+# 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/>.
+
+disks=`echo ls | @builddir@/grub-shell`
+other=`echo echo '*' | @builddir@/grub-shell`
+for d in $disks; do
+  if ! echo "$other" | grep "$d" >/dev/null; then
+    echo "$d missing from * expansion" >&2
+    exit 1
+  fi
+done
+
+other=`echo echo '(*)' | @builddir@/grub-shell`
+for d in $disks; do
+  if ! echo "$other" | grep "$d" >/dev/null; then
+    echo "$d missing from (*) expansion" >&2
+    exit 1
+  fi
+done
+

=== modified file 'tests/util/grub-shell.in'
--- tests/util/grub-shell.in	2010-04-06 06:51:11 +0000
+++ tests/util/grub-shell.in	2010-05-18 15:33:35 +0000
@@ -95,7 +95,7 @@
 if [ "x${source}" = x ] ; then
     tmpfile=`mktemp`
     while read; do
-	echo $REPLY >> ${tmpfile}
+	echo "$REPLY" >> ${tmpfile}
     done
     source=${tmpfile}
 fi

# Begin bundle
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

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-07-29 14:54 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-18 16:07 [PATCH] GRUB script shell expansion for * BVK Chaitanya
2010-05-18 17:22 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-07-29 14:53   ` BVK Chaitanya

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.