From a0b20aad47ff02c7a1a0cd38a0407c4f2564cc08 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Tue, 18 May 2010 21:03:35 +0530 Subject: [PATCH 01/12] some shell expansion features into grub-script --- conf/tests.rmk | 4 + include/grub/script_sh.h | 5 + script/argv.c | 538 ++++++++++++++++++++++++++++++++- script/execute.c | 22 +- tests/grub_script_expansion.in | 35 +++ tests/util/grub-shell.in | 2 +- 6 files changed, 593 insertions(+), 13 deletions(-) create mode 100644 tests/grub_script_expansion.in diff --git a/conf/tests.rmk b/conf/tests.rmk index 9144e5528..94187f150 100644 --- a/conf/tests.rmk +++ b/conf/tests.rmk @@ -74,6 +74,9 @@ grub_script_comments_SOURCES = tests/grub_script_comments.in 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_final_semicolon 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 diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 5455fc763..cdf9b731d 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -225,7 +225,12 @@ struct grub_parser_param 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); diff --git a/script/argv.c b/script/argv.c index 1ac81f4b8..8446ded3d 100644 --- a/script/argv.c +++ b/script/argv.c @@ -18,11 +18,32 @@ */ #include +#include +#include +#include +#include #include +#include + #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 @@ grub_script_argv_next (struct grub_script_argv *argv) 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 @@ grub_script_argv_split_append (struct grub_script_argv *argv, char *s) } 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, ®); + if (dir < reg) + { + if (make_regex (dir, reg, ®ex)) + goto fail; + + paths = match_paths_with_escaped_suffix (paths, p, dir, ®ex); + regfree (®ex); + + 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 (®ex); + return 1; +} diff --git a/script/execute.c b/script/execute.c index 2040be13c..0f31cdc6e 100644 --- a/script/execute.c +++ b/script/execute.c @@ -177,7 +177,13 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, { 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 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, 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_script_execute_cmdline (struct grub_script_cmd *cmd) 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 @@ grub_script_execute_menuentry (struct grub_script_cmd *cmd) cmd_menuentry->sourcecode); grub_script_argv_free (&argv); - return grub_errno; } diff --git a/tests/grub_script_expansion.in b/tests/grub_script_expansion.in new file mode 100644 index 000000000..80f0a6afa --- /dev/null +++ b/tests/grub_script_expansion.in @@ -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 . + +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 + diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in index a41a6f6f4..a28786057 100644 --- a/tests/util/grub-shell.in +++ b/tests/util/grub-shell.in @@ -95,7 +95,7 @@ done if [ "x${source}" = x ] ; then tmpfile=`mktemp` while read; do - echo $REPLY >> ${tmpfile} + echo "$REPLY" >> ${tmpfile} done source=${tmpfile} fi From 50cd44693d2d3949c5e18f2fdf8ea2b3af511471 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Wed, 19 May 2010 20:53:20 +0530 Subject: [PATCH 02/12] minor fixes --- conf/common.rmk | 2 +- script/argv.c | 62 ++++++++++++++----------------------------------- 2 files changed, 19 insertions(+), 45 deletions(-) diff --git a/conf/common.rmk b/conf/common.rmk index 54146904b..886d10e58 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -662,7 +662,7 @@ normal_mod_LDFLAGS = $(COMMON_LDFLAGS) # For sh.mod. sh_mod_SOURCES = script/main.c script/script.c script/argv.c script/execute.c \ script/function.c script/lexer.c grub_script.tab.c grub_script.yy.c -sh_mod_CFLAGS = $(COMMON_CFLAGS) $(POSIX_CFLAGS) -Wno-error +sh_mod_CFLAGS = $(COMMON_CFLAGS) $(POSIX_CFLAGS) $(GNULIB_CFLAGS) -Wno-error sh_mod_LDFLAGS = $(COMMON_LDFLAGS) ifneq (, $(FONT_SOURCE)) diff --git a/script/argv.c b/script/argv.c index 8446ded3d..369be49b8 100644 --- a/script/argv.c +++ b/script/argv.c @@ -373,47 +373,38 @@ 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) + char **t; + char *buffer = grub_xasprintf ("(%s)", name); + if (! buffer) 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; + { + grub_free (buffer); + return 0; + } t = grub_realloc (devs, sizeof (char*) * (ndev + 2)); if (! t) return 1; - devs = (char **) t; + devs = 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: @@ -424,9 +415,6 @@ match_devices (const regex_t *regexp) if (devs) grub_free (devs); - if (buffer) - grub_free (buffer); - return 0; } @@ -437,10 +425,8 @@ match_files (const char *prefix, const char *suffix, const char *end, int i; int error; char **files; - char *buffer; unsigned nfile; char *dir; - unsigned dirlen; const char *path; char *device_name; grub_fs_t fs; @@ -449,8 +435,8 @@ match_files (const char *prefix, const char *suffix, const char *end, 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; + char **t; + char *buffer; /* skip hidden files, . and .. */ if (name[0] == '.') @@ -460,36 +446,32 @@ match_files (const char *prefix, const char *suffix, const char *end, if (regexec (regexp, name, 0, 0, 0)) return 0; - n = dirlen + grub_strlen (name); - t = grub_realloc (buffer, n + 1); - if (! t) + buffer = grub_xasprintf ("%s%s", dir, name); + if (! buffer) 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; + { + grub_free (buffer); + return 1; + } - files = (char **) t; + files = 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); @@ -508,9 +490,6 @@ match_files (const char *prefix, const char *suffix, const char *end, if (fs->dir (dev, path, match)) goto fail; - if (buffer) - grub_free (buffer); - grub_free (dir); grub_device_close (dev); grub_free (device_name); @@ -534,9 +513,6 @@ match_files (const char *prefix, const char *suffix, const char *end, if (device_name) grub_free (device_name); - if (buffer) - grub_free (buffer); - grub_error_pop (); return 0; } @@ -563,12 +539,10 @@ match_paths_with_escaped_suffix (char **paths, if (! root) return 0; - n = grub_strlen (root) + 2; - prefix = grub_malloc (n + 1); + prefix = grub_xasprintf ("(%s)", root); if (! prefix) return 0; - grub_snprintf (prefix, n + 1, "(%s)", root); r = match_files (prefix, suffix, end, regexp); grub_free (prefix); return r; From 645505004e6f935ea3221bbf3750b9ee27a877be Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 23 Jul 2010 02:57:02 +0530 Subject: [PATCH 03/12] suppress unwanted shell expansion --- tests/util/grub-shell.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in index 2cd256131..3ad658438 100644 --- a/tests/util/grub-shell.in +++ b/tests/util/grub-shell.in @@ -95,7 +95,7 @@ done if [ "x${source}" = x ] ; then tmpfile=`mktemp` while read REPLY; do - echo $REPLY >> ${tmpfile} + echo "$REPLY" >> ${tmpfile} done source=${tmpfile} fi From 31784795aac5370ee65a23aea91d2bd47cec3006 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 23 Jul 2010 03:30:26 +0530 Subject: [PATCH 04/12] separate expansions for disks and partitions --- script/argv.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/script/argv.c b/script/argv.c index 8fe8971d3..1941b5672 100644 --- a/script/argv.c +++ b/script/argv.c @@ -54,7 +54,7 @@ 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_devices (const regex_t *regexp, int noparts); 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, @@ -375,7 +375,7 @@ split_path (char *str, char **suffix_end, char **regex_end) } static char ** -match_devices (const regex_t *regexp) +match_devices (const regex_t *regexp, int noparts) { int i; int ndev; @@ -385,7 +385,13 @@ match_devices (const regex_t *regexp) int match (const char *name) { char **t; - char *buffer = grub_xasprintf ("(%s)", name); + char *buffer; + + /* skip partitions if asked to. */ + if (noparts && grub_strchr(name, ',')) + return 0; + + buffer = grub_xasprintf ("(%s)", name); if (! buffer) return 1; @@ -530,7 +536,7 @@ match_paths_with_escaped_suffix (char **paths, const regex_t *regexp) { if (paths == 0 && suffix == end) - return match_devices (regexp); + return match_devices (regexp, *suffix != '('); else if (paths == 0 && suffix[0] == '(') return match_files ("", suffix, end, regexp); From 1c24bab4be20965548a5118236ae1b89900c3cb7 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 29 Jul 2010 16:59:49 +0530 Subject: [PATCH 05/12] updated testcase --- tests/grub_script_expansion.in | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/tests/grub_script_expansion.in b/tests/grub_script_expansion.in index 1ec58e3a9..11aafc853 100644 --- a/tests/grub_script_expansion.in +++ b/tests/grub_script_expansion.in @@ -17,19 +17,26 @@ # along with GRUB. If not, see . disks=`echo ls | @builddir@/grub-shell` -other=`echo echo \\* | @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 + if echo "$d" |grep ',' >/dev/null; then + if echo "$other" | grep "$d" >/dev/null; then + echo "$d should not occur in * expansion" >&2 + exit 1 + fi + else + if ! echo "$other" | grep "$d" >/dev/null; then + echo "$d missing from * expansion" >&2 + exit 1 + fi + 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 + if ! echo "$other" | grep "$d" >/dev/null; then + echo "$d missing from (*) expansion" >&2 + exit 1 + fi done From 8c184ffa19676b52dab8cd5b8e82e5beb21f8c29 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 29 Jul 2010 21:09:18 +0530 Subject: [PATCH 06/12] cleanup --- include/grub/wildcard.h | 34 +++++ script/argv.c | 316 +++++++++++++++++++++++----------------- 2 files changed, 218 insertions(+), 132 deletions(-) create mode 100644 include/grub/wildcard.h diff --git a/include/grub/wildcard.h b/include/grub/wildcard.h new file mode 100644 index 000000000..8157b9db6 --- /dev/null +++ b/include/grub/wildcard.h @@ -0,0 +1,34 @@ +/* wildcard.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 . + */ + +#ifndef GRUB_WILDCARD_HEADER +#define GRUB_WILDCARD_HEADER + +/* Pluggable wildcard expansion engine. */ +struct grub_wildcard_translator +{ + char *(*escape) (const char *str); + char *(*unescape) (const char *str); + + grub_err_t (*expand) (const char *str, char ***expansions); + + struct grub_wildcard_translator *next; +}; + +#endif /* GRUB_WILDCARD_HEADER */ diff --git a/script/argv.c b/script/argv.c index 1941b5672..10e180457 100644 --- a/script/argv.c +++ b/script/argv.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -48,20 +49,26 @@ round_up_exp (unsigned v) return v; } -static inline int regexop (char ch); +static inline int isregexop (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 void split_path (const char *path, const char **suffix_end, const char **regex_end); static char ** match_devices (const regex_t *regexp, int noparts); 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); + +static char* wildcard_escape (const char *s); +static char* wildcard_unescape (const char *s); +static grub_err_t wildcard_expand (const char *s, char ***strs); + +static struct grub_wildcard_translator foo = { + .expand = wildcard_expand, + .escape = wildcard_escape, + .unescape = wildcard_unescape +}; + void grub_script_argv_free (struct grub_script_argv *argv) @@ -109,7 +116,7 @@ enum append_type { }; static int -append (struct grub_script_argv *argv, const char *s, enum append_type type) +append (struct grub_script_argv *argv, const char *s) { int a; int b; @@ -120,41 +127,15 @@ append (struct grub_script_argv *argv, const char *s, enum append_type type) return 0; a = p ? grub_strlen (p) : 0; - b = grub_strlen (s) * (type == APPEND_ESCAPED ? 2 : 1); + b = grub_strlen (s); p = grub_realloc (p, round_up_exp ((a + b + 1) * sizeof (char))); if (! p) return 1; - 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; - } - + grub_strcpy (p + a, s); argv->args[argv->argc - 1] = p; + return 0; } @@ -163,21 +144,37 @@ append (struct grub_script_argv *argv, const char *s, enum append_type type) int grub_script_argv_append (struct grub_script_argv *argv, const char *s) { - return append (argv, s, APPEND_RAW); + return append (argv, s); } /* 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); + int r; + char *p = wildcard_escape (s); + + if (! p) + return 1; + + r = append (argv, p); + grub_free (p); + return r; } /* 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); + int r; + char *p = wildcard_unescape (s); + + if (! p) + return 1; + + r = append (argv, p); + grub_free (p); + return r; } /* Split `s' and append words as multiple arguments. */ @@ -216,11 +213,33 @@ int grub_script_argv_expand (struct grub_script_argv *argv) { int i; + int j; + char *p; + char **expansions; struct grub_script_argv result = { 0, 0 }; for (i = 0; argv->args[i]; i++) - if (expand (argv->args[i], &result)) - goto fail; + { + expansions = 0; + if (wildcard_expand (argv->args[i], &expansions)) + goto fail; + + if (! expansions) + { + grub_script_argv_next (&result); + grub_script_argv_append_unescaped (&result, argv->args[i]); + } + else + { + for (j = 0; expansions[j]; j++) + { + grub_script_argv_next (&result); + grub_script_argv_append (&result, expansions[j]); + grub_free (expansions[j]); + } + grub_free (expansions); + } + } grub_script_argv_free (argv); *argv = result; @@ -267,7 +286,7 @@ merge (char **dest, char **ps) } static inline int -regexop (char ch) +isregexop (char ch) { return grub_strchr ("*.\\", ch) ? 1 : 0; } @@ -289,7 +308,7 @@ make_dir (const char *prefix, const char *start, const char *end) grub_strcpy (result, prefix); while (start < end && (ch = *start++)) - if (ch == '\\' && regexop (*start)) + if (ch == '\\' && isregexop (*start)) result[i++] = *start++; else result[i++] = ch; @@ -343,35 +362,41 @@ make_regex (const char *start, const char *end, regex_t *regexp) return 0; } +/* Split `str' into two parts: (1) dirname that is regexop free (2) + dirname that has a regexop. */ static void -split_path (char *str, char **suffix_end, char **regex_end) +split_path (const char *str, const char **noregexop, const char **regexop) { char ch = 0; int regex = 0; - char *end; - char *split; + const char *end; + const char *split; /* points till the end of dirnaname that doesn't + need expansion. */ split = end = str; while ((ch = *end)) { if (ch == '\\' && end[1]) end++; - else if (regexop (ch)) + + else if (isregexop (ch)) regex = 1; + else if (ch == '/' && ! regex) - split = end + 1; + split = end + 1; /* forward to next regexop-free dirname */ + else if (ch == '/' && regex) - break; + break; /* stop at the first dirname with a regexop */ end++; } - *regex_end = end; + *regexop = end; if (! regex) - *suffix_end = end; + *noregexop = end; else - *suffix_end = split; + *noregexop = split; } static char ** @@ -530,112 +555,139 @@ match_files (const char *prefix, const char *suffix, const char *end, return 0; } -static char ** -match_paths_with_escaped_suffix (char **paths, - const char *suffix, const char *end, - const regex_t *regexp) +static char* +wildcard_escape (const char *s) { - if (paths == 0 && suffix == end) - return match_devices (regexp, *suffix != '('); + int i; + int len; + char ch; + char *p; - else if (paths == 0 && suffix[0] == '(') - return match_files ("", suffix, end, regexp); + len = grub_strlen (s); + p = grub_malloc (len * 2 + 1); + if (! p) + return NULL; - else if (paths == 0 && suffix[0] == '/') + i = 0; + while ((ch = *s++)) { - char **r; - unsigned n; - char *root; - char *prefix; - - root = grub_env_get ("root"); - if (! root) - return 0; - - prefix = grub_xasprintf ("(%s)", root); - if (! prefix) - return 0; - - r = match_files (prefix, suffix, end, regexp); - grub_free (prefix); - return r; + if (isregexop (ch)) + p[i++] = '\\'; + p[i++] = ch; } - 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; + p[i] = '\0'; + return p; } -static int -expand (char *arg, struct grub_script_argv *argv) +static char* +wildcard_unescape (const char *s) { + int i; + int len; + char ch; char *p; - char *dir; - char *reg; + + len = grub_strlen (s); + p = grub_malloc (len + 1); + if (! p) + return NULL; + + i = 0; + while ((ch = *s++)) + { + if (ch == '\\' && isregexop (*s)) + p[i++] = *s++; + else + p[i++] = ch; + } + p[i] = '\0'; + return p; +} + +static grub_err_t +wildcard_expand (const char *s, char ***strs) +{ + const char *start; + const char *regexop; + const char *noregexop; char **paths = 0; unsigned i; - regex_t regex; + regex_t regexp; - p = arg; - while (*p) + start = s; + while (*start) { - /* split `p' into two components: (p..dir), (dir...reg) + split_path (start, &noregexop, ®exop); + if (noregexop >= regexop) /* no more wildcards */ + break; - (p...dir): path that doesn't need expansion + if (make_regex (noregexop, regexop, ®exp)) + goto fail; - (dir...reg): part of path that needs expansion - */ - split_path (p, &dir, ®); - if (dir < reg) + if (paths == 0) { - if (make_regex (dir, reg, ®ex)) - goto fail; + if (start == noregexop) /* device part has regexop */ + paths = match_devices (®exp, *start != '('); - paths = match_paths_with_escaped_suffix (paths, p, dir, ®ex); - regfree (®ex); + else if (*start == '(') /* device part explicit wo regexop */ + paths = match_files ("", start, noregexop, ®exp); - if (! paths) - goto done; + else if (*start == '/') /* no device part */ + { + char **r; + unsigned n; + char *root; + char *prefix; + + root = grub_env_get ("root"); + if (! root) + goto fail; + + prefix = grub_xasprintf ("(%s)", root); + if (! prefix) + goto fail; + + paths = match_files (prefix, start, noregexop, ®exp); + grub_free (prefix); + } } - p = reg; - } + else + { + char **r = 0; - if (! paths) - { - grub_script_argv_next (argv); - grub_script_argv_append_unescaped (argv, arg); + for (i = 0; paths[i]; i++) + { + char **p; + + p = match_files (paths[i], start, noregexop, ®exp); + if (! p) + continue; + + r = merge (r, p); + if (! r) + goto fail; + } + paths = r; + } + + regfree (®exp); + if (! paths) + goto done; + + start = regexop; } - else - for (i = 0; paths[i]; i++) - { - grub_script_argv_next (argv); - grub_script_argv_append (argv, paths[i]); - } done: + *strs = paths; return 0; fail: - regfree (®ex); - return 1; + for (i = 0; paths && paths[i]; i++) + grub_free (paths[i]); + grub_free (paths[i]); + regfree (®exp); + return grub_errno; } From 9e3e24e47fca36b1a00b4cbe0a98527b2dd9d3c2 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 29 Jul 2010 22:52:09 +0530 Subject: [PATCH 07/12] cleanup --- include/grub/script_sh.h | 14 +++--- include/grub/wildcard.h | 34 -------------- script/argv.c | 97 +++------------------------------------- script/execute.c | 71 +++++++++++++++++++++++++++-- 4 files changed, 81 insertions(+), 135 deletions(-) delete mode 100644 include/grub/wildcard.h diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index d79fc048a..1564799f6 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -70,6 +70,15 @@ struct grub_script_argv char **args; }; +/* Pluggable wildcard translator. */ +struct grub_script_wildcard_translator +{ + char *(*escape) (const char *str); + char *(*unescape) (const char *str); + grub_err_t (*expand) (const char *str, char ***expansions); +}; +extern struct grub_script_wildcard_translator *wildcard_translator; + /* A complete argument. It consists of a list of one or more `struct grub_script_arg's. */ struct grub_script_arglist @@ -225,12 +234,7 @@ struct grub_parser_param 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); diff --git a/include/grub/wildcard.h b/include/grub/wildcard.h deleted file mode 100644 index 8157b9db6..000000000 --- a/include/grub/wildcard.h +++ /dev/null @@ -1,34 +0,0 @@ -/* wildcard.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 . - */ - -#ifndef GRUB_WILDCARD_HEADER -#define GRUB_WILDCARD_HEADER - -/* Pluggable wildcard expansion engine. */ -struct grub_wildcard_translator -{ - char *(*escape) (const char *str); - char *(*unescape) (const char *str); - - grub_err_t (*expand) (const char *str, char ***expansions); - - struct grub_wildcard_translator *next; -}; - -#endif /* GRUB_WILDCARD_HEADER */ diff --git a/script/argv.c b/script/argv.c index 10e180457..3294a90ad 100644 --- a/script/argv.c +++ b/script/argv.c @@ -23,7 +23,6 @@ #include #include #include -#include #include @@ -63,12 +62,12 @@ static char* wildcard_escape (const char *s); static char* wildcard_unescape (const char *s); static grub_err_t wildcard_expand (const char *s, char ***strs); -static struct grub_wildcard_translator foo = { +static struct grub_script_wildcard_translator translator = { .expand = wildcard_expand, .escape = wildcard_escape, .unescape = wildcard_unescape }; - +struct grub_script_wildcard_translator *wildcard_translator = &translator; void grub_script_argv_free (struct grub_script_argv *argv) @@ -109,14 +108,9 @@ grub_script_argv_next (struct grub_script_argv *argv) return 0; } -enum append_type { - APPEND_RAW, - APPEND_ESCAPED, - APPEND_UNESCAPED -}; - -static int -append (struct grub_script_argv *argv, const char *s) +/* Append `s' to the last argument. */ +int +grub_script_argv_append (struct grub_script_argv *argv, const char *s) { int a; int b; @@ -139,44 +133,6 @@ append (struct grub_script_argv *argv, const char *s) 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 `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) -{ - int r; - char *p = wildcard_escape (s); - - if (! p) - return 1; - - r = append (argv, p); - grub_free (p); - return r; -} - -/* 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) -{ - int r; - char *p = wildcard_unescape (s); - - if (! p) - return 1; - - r = append (argv, p); - grub_free (p); - return r; -} - /* Split `s' and append words as multiple arguments. */ int grub_script_argv_split_append (struct grub_script_argv *argv, char *s) @@ -208,49 +164,6 @@ grub_script_argv_split_append (struct grub_script_argv *argv, char *s) return errors; } -/* Expand `argv' as per shell expansion rules. */ -int -grub_script_argv_expand (struct grub_script_argv *argv) -{ - int i; - int j; - char *p; - char **expansions; - struct grub_script_argv result = { 0, 0 }; - - for (i = 0; argv->args[i]; i++) - { - expansions = 0; - if (wildcard_expand (argv->args[i], &expansions)) - goto fail; - - if (! expansions) - { - grub_script_argv_next (&result); - grub_script_argv_append_unescaped (&result, argv->args[i]); - } - else - { - for (j = 0; expansions[j]; j++) - { - grub_script_argv_next (&result); - grub_script_argv_append (&result, expansions[j]); - grub_free (expansions[j]); - } - grub_free (expansions); - } - } - - grub_script_argv_free (argv); - *argv = result; - return 0; - - fail: - - grub_script_argv_free (&result); - return 1; -} - static char ** merge (char **dest, char **ps) { diff --git a/script/execute.c b/script/execute.c index 47e47b6eb..a41719091 100644 --- a/script/execute.c +++ b/script/execute.c @@ -161,7 +161,7 @@ grub_script_env_set (const char *name, const char *val) return grub_env_set (name, val); } -/* Expand arguments in ARGLIST into multiple arguments. */ +/* Convert arguments in ARGLIST into ARGV form. */ static int grub_script_arglist_to_argv (struct grub_script_arglist *arglist, struct grub_script_argv *argv) @@ -171,6 +171,28 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, struct grub_script_arg *arg = 0; struct grub_script_argv result = { 0, 0 }; + auto int append (char *s, int escape_type); + int append (char *s, int escape_type) + { + int r; + char *p = 0; + + if (! wildcard_translator || escape_type == 0) + return grub_script_argv_append (&result, s); + + if (escape_type > 0) + p = wildcard_translator->escape (s); + else if (escape_type < 0) + p = wildcard_translator->unescape (s); + + if (! p) + return 1; + + r = grub_script_argv_append (&result, p); + grub_free (p); + return r; + } + for (; arglist && arglist->arg; arglist = arglist->next) { if (grub_script_argv_next (&result)) @@ -196,7 +218,7 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, } else { - if (grub_script_argv_append_escaped (&result, values[i])) + if (append (values[i], 1)) goto fail; } @@ -224,8 +246,49 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, if (! result.args[result.argc - 1]) result.argc--; - if (grub_script_argv_expand (&result)) - goto fail; + /* Perform wildcard expansion. */ + + if (wildcard_translator) + { + int j; + int failed = 0; + char **expansions = 0; + struct grub_script_argv unexpanded = result; + + result.argc = 0; + result.args = 0; + for (i = 0; unexpanded.args[i]; i++) + { + if (wildcard_translator->expand (unexpanded.args[i], &expansions)) + { + grub_script_argv_free (&unexpanded); + goto fail; + } + + if (! expansions) + { + grub_script_argv_next (&result); + append (unexpanded.args[i], -1); + } + else + { + for (j = 0; expansions[j]; j++) + { + failed = (failed || grub_script_argv_next (&result) || + append (expansions[j], -1)); + grub_free (expansions[j]); + } + grub_free (expansions); + + if (failed) + { + grub_script_argv_free (&unexpanded); + goto fail; + } + } + } + grub_script_argv_free (&unexpanded); + } *argv = result; return 0; From 479a8efacacfbadd242a89e5c750726a61d79a65 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 29 Jul 2010 22:54:07 +0530 Subject: [PATCH 08/12] removed an unused variabled --- script/argv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/script/argv.c b/script/argv.c index 3294a90ad..15c6c6ed4 100644 --- a/script/argv.c +++ b/script/argv.c @@ -114,7 +114,6 @@ grub_script_argv_append (struct grub_script_argv *argv, const char *s) { int a; int b; - char ch; char *p = argv->args[argv->argc - 1]; if (! s) From 3c6a9151ad2a27c4729a0ac20db0fa38d5a20cd7 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 29 Jul 2010 23:32:56 +0530 Subject: [PATCH 09/12] move wildcard translator into regexp module --- commands/regexp.c | 6 + commands/wildcard.c | 493 +++++++++++++++++++++++++++++++++ conf/common.rmk | 4 +- script/argv.c | 472 +------------------------------ script/execute.c | 3 + tests/grub_script_expansion.in | 4 +- 6 files changed, 507 insertions(+), 475 deletions(-) create mode 100644 commands/wildcard.c diff --git a/commands/regexp.c b/commands/regexp.c index e8e8243b5..05f6d55ad 100644 --- a/commands/regexp.c +++ b/commands/regexp.c @@ -22,6 +22,7 @@ #include #include #include +#include #include static grub_err_t @@ -69,9 +70,14 @@ static grub_command_t cmd; GRUB_MOD_INIT(regexp) { + extern struct grub_script_wildcard_translator translator; + cmd = grub_register_command ("regexp", grub_cmd_regexp, N_("REGEXP STRING"), N_("Test if REGEXP matches STRING.")); + + /* Setup GRUB script wildcard translator. */ + wildcard_translator = &translator; } GRUB_MOD_FINI(regexp) diff --git a/commands/wildcard.c b/commands/wildcard.c new file mode 100644 index 000000000..7f37c84eb --- /dev/null +++ b/commands/wildcard.c @@ -0,0 +1,493 @@ +/* wildcard.c - Wildcard character expansion for GRUB script. */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +#include + +static inline int isregexop (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 (const char *path, const char **suffix_end, const char **regex_end); +static char ** match_devices (const regex_t *regexp, int noparts); +static char ** match_files (const char *prefix, const char *suffix_start, + const char *suffix_end, const regex_t *regexp); + +static char* wildcard_escape (const char *s); +static char* wildcard_unescape (const char *s); +static grub_err_t wildcard_expand (const char *s, char ***strs); + +struct grub_script_wildcard_translator translator = { + .expand = wildcard_expand, + .escape = wildcard_escape, + .unescape = wildcard_unescape +}; + +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 +isregexop (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 == '\\' && isregexop (*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 + 2 + 1); /* worst case size. */ + + if (! buffer) + return 1; + + buffer[i++] = '^'; + 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++] = '$'; + buffer[i] = '\0'; + + if (regcomp (regexp, buffer, RE_SYNTAX_GNU_AWK)) + { + grub_free (buffer); + return 1; + } + + grub_free (buffer); + return 0; +} + +/* Split `str' into two parts: (1) dirname that is regexop free (2) + dirname that has a regexop. */ +static void +split_path (const char *str, const char **noregexop, const char **regexop) +{ + char ch = 0; + int regex = 0; + + const char *end; + const char *split; /* points till the end of dirnaname that doesn't + need expansion. */ + + split = end = str; + while ((ch = *end)) + { + if (ch == '\\' && end[1]) + end++; + + else if (isregexop (ch)) + regex = 1; + + else if (ch == '/' && ! regex) + split = end + 1; /* forward to next regexop-free dirname */ + + else if (ch == '/' && regex) + break; /* stop at the first dirname with a regexop */ + + end++; + } + + *regexop = end; + if (! regex) + *noregexop = end; + else + *noregexop = split; +} + +static char ** +match_devices (const regex_t *regexp, int noparts) +{ + int i; + int ndev; + char **devs; + + auto int match (const char *name); + int match (const char *name) + { + char **t; + char *buffer; + + /* skip partitions if asked to. */ + if (noparts && grub_strchr(name, ',')) + return 0; + + buffer = grub_xasprintf ("(%s)", name); + if (! buffer) + return 1; + + grub_dprintf ("expand", "matching: %s\n", buffer); + if (regexec (regexp, buffer, 0, 0, 0)) + { + grub_free (buffer); + return 0; + } + + t = grub_realloc (devs, sizeof (char*) * (ndev + 2)); + if (! t) + return 1; + + devs = t; + devs[ndev++] = buffer; + devs[ndev] = 0; + return 0; + } + + ndev = 0; + devs = 0; + + if (grub_device_iterate (match)) + goto fail; + + return devs; + + fail: + + for (i = 0; devs && devs[i]; i++) + grub_free (devs[i]); + + if (devs) + grub_free (devs); + + 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; + unsigned nfile; + char *dir; + 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) + { + char **t; + char *buffer; + + /* 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; + + buffer = grub_xasprintf ("%s%s", dir, name); + if (! buffer) + return 1; + + t = grub_realloc (files, sizeof (char*) * (nfile + 2)); + if (! t) + { + grub_free (buffer); + return 1; + } + + files = t; + files[nfile++] = buffer; + files[nfile] = 0; + return 0; + } + + nfile = 0; + files = 0; + dev = 0; + device_name = 0; + grub_error_push (); + + dir = make_dir (prefix, suffix, end); + if (! dir) + goto fail; + + 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; + + 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); + + grub_error_pop (); + return 0; +} + +static char* +wildcard_escape (const char *s) +{ + int i; + int len; + char ch; + char *p; + + len = grub_strlen (s); + p = grub_malloc (len * 2 + 1); + if (! p) + return NULL; + + i = 0; + while ((ch = *s++)) + { + if (isregexop (ch)) + p[i++] = '\\'; + p[i++] = ch; + } + p[i] = '\0'; + return p; +} + +static char* +wildcard_unescape (const char *s) +{ + int i; + int len; + char ch; + char *p; + + len = grub_strlen (s); + p = grub_malloc (len + 1); + if (! p) + return NULL; + + i = 0; + while ((ch = *s++)) + { + if (ch == '\\' && isregexop (*s)) + p[i++] = *s++; + else + p[i++] = ch; + } + p[i] = '\0'; + return p; +} + +static grub_err_t +wildcard_expand (const char *s, char ***strs) +{ + const char *start; + const char *regexop; + const char *noregexop; + char **paths = 0; + + unsigned i; + regex_t regexp; + + start = s; + while (*start) + { + split_path (start, &noregexop, ®exop); + if (noregexop >= regexop) /* no more wildcards */ + break; + + if (make_regex (noregexop, regexop, ®exp)) + goto fail; + + if (paths == 0) + { + if (start == noregexop) /* device part has regexop */ + paths = match_devices (®exp, *start != '('); + + else if (*start == '(') /* device part explicit wo regexop */ + paths = match_files ("", start, noregexop, ®exp); + + else if (*start == '/') /* no device part */ + { + char **r; + unsigned n; + char *root; + char *prefix; + + root = grub_env_get ("root"); + if (! root) + goto fail; + + prefix = grub_xasprintf ("(%s)", root); + if (! prefix) + goto fail; + + paths = match_files (prefix, start, noregexop, ®exp); + grub_free (prefix); + } + } + else + { + char **r = 0; + + for (i = 0; paths[i]; i++) + { + char **p; + + p = match_files (paths[i], start, noregexop, ®exp); + if (! p) + continue; + + r = merge (r, p); + if (! r) + goto fail; + } + paths = r; + } + + regfree (®exp); + if (! paths) + goto done; + + start = regexop; + } + + done: + + *strs = paths; + return 0; + + fail: + + for (i = 0; paths && paths[i]; i++) + grub_free (paths[i]); + grub_free (paths[i]); + regfree (®exp); + return grub_errno; +} diff --git a/conf/common.rmk b/conf/common.rmk index 24d7921f5..24baa3bfc 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -638,7 +638,7 @@ normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \ normal/misc.c normal/crypto.c normal/term.c normal/context.c \ script/main.c script/script.c script/execute.c script/argv.c unidata.c \ script/function.c script/lexer.c grub_script.tab.c grub_script.yy.c -normal_mod_CFLAGS = $(COMMON_CFLAGS) $(POSIX_CFLAGS) $(GNULIB_CFLAGS) -Wno-error +normal_mod_CFLAGS = $(COMMON_CFLAGS) $(POSIX_CFLAGS) -Wno-error normal_mod_LDFLAGS = $(COMMON_LDFLAGS) ifneq (, $(FONT_SOURCE)) @@ -764,7 +764,7 @@ setjmp_mod_ASFLAGS = $(COMMON_ASFLAGS) setjmp_mod_LDFLAGS = $(COMMON_LDFLAGS) pkglib_MODULES += regexp.mod -regexp_mod_SOURCES = gnulib/regex.c commands/regexp.c +regexp_mod_SOURCES = gnulib/regex.c commands/regexp.c commands/wildcard.c regexp_mod_CFLAGS = $(COMMON_CFLAGS) $(GNULIB_CFLAGS) regexp_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/script/argv.c b/script/argv.c index 15c6c6ed4..6e93edaee 100644 --- a/script/argv.c +++ b/script/argv.c @@ -18,17 +18,9 @@ */ #include -#include -#include -#include -#include +#include #include -#include - -#define ARG_ALLOCATION_UNIT (32 * sizeof (char)) -#define ARGV_ALLOCATION_UNIT (8 * sizeof (void*)) - static unsigned round_up_exp (unsigned v) { @@ -48,27 +40,6 @@ round_up_exp (unsigned v) return v; } -static inline int isregexop (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 (const char *path, const char **suffix_end, const char **regex_end); -static char ** match_devices (const regex_t *regexp, int noparts); -static char ** match_files (const char *prefix, const char *suffix_start, - const char *suffix_end, const regex_t *regexp); - -static char* wildcard_escape (const char *s); -static char* wildcard_unescape (const char *s); -static grub_err_t wildcard_expand (const char *s, char ***strs); - -static struct grub_script_wildcard_translator translator = { - .expand = wildcard_expand, - .escape = wildcard_escape, - .unescape = wildcard_unescape -}; -struct grub_script_wildcard_translator *wildcard_translator = &translator; - void grub_script_argv_free (struct grub_script_argv *argv) { @@ -162,444 +133,3 @@ grub_script_argv_split_append (struct grub_script_argv *argv, char *s) } return errors; } - -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 -isregexop (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 == '\\' && isregexop (*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; -} - -/* Split `str' into two parts: (1) dirname that is regexop free (2) - dirname that has a regexop. */ -static void -split_path (const char *str, const char **noregexop, const char **regexop) -{ - char ch = 0; - int regex = 0; - - const char *end; - const char *split; /* points till the end of dirnaname that doesn't - need expansion. */ - - split = end = str; - while ((ch = *end)) - { - if (ch == '\\' && end[1]) - end++; - - else if (isregexop (ch)) - regex = 1; - - else if (ch == '/' && ! regex) - split = end + 1; /* forward to next regexop-free dirname */ - - else if (ch == '/' && regex) - break; /* stop at the first dirname with a regexop */ - - end++; - } - - *regexop = end; - if (! regex) - *noregexop = end; - else - *noregexop = split; -} - -static char ** -match_devices (const regex_t *regexp, int noparts) -{ - int i; - int ndev; - char **devs; - - auto int match (const char *name); - int match (const char *name) - { - char **t; - char *buffer; - - /* skip partitions if asked to. */ - if (noparts && grub_strchr(name, ',')) - return 0; - - buffer = grub_xasprintf ("(%s)", name); - if (! buffer) - return 1; - - grub_dprintf ("expand", "matching: %s\n", buffer); - if (regexec (regexp, buffer, 0, 0, 0)) - { - grub_free (buffer); - return 0; - } - - t = grub_realloc (devs, sizeof (char*) * (ndev + 2)); - if (! t) - return 1; - - devs = t; - devs[ndev++] = buffer; - devs[ndev] = 0; - return 0; - } - - ndev = 0; - devs = 0; - - if (grub_device_iterate (match)) - goto fail; - - return devs; - - fail: - - for (i = 0; devs && devs[i]; i++) - grub_free (devs[i]); - - if (devs) - grub_free (devs); - - 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; - unsigned nfile; - char *dir; - 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) - { - char **t; - char *buffer; - - /* 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; - - buffer = grub_xasprintf ("%s%s", dir, name); - if (! buffer) - return 1; - - t = grub_realloc (files, sizeof (char*) * (nfile + 2)); - if (! t) - { - grub_free (buffer); - return 1; - } - - files = t; - files[nfile++] = buffer; - files[nfile] = 0; - return 0; - } - - nfile = 0; - files = 0; - dev = 0; - device_name = 0; - grub_error_push (); - - dir = make_dir (prefix, suffix, end); - if (! dir) - goto fail; - - 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; - - 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); - - grub_error_pop (); - return 0; -} - -static char* -wildcard_escape (const char *s) -{ - int i; - int len; - char ch; - char *p; - - len = grub_strlen (s); - p = grub_malloc (len * 2 + 1); - if (! p) - return NULL; - - i = 0; - while ((ch = *s++)) - { - if (isregexop (ch)) - p[i++] = '\\'; - p[i++] = ch; - } - p[i] = '\0'; - return p; -} - -static char* -wildcard_unescape (const char *s) -{ - int i; - int len; - char ch; - char *p; - - len = grub_strlen (s); - p = grub_malloc (len + 1); - if (! p) - return NULL; - - i = 0; - while ((ch = *s++)) - { - if (ch == '\\' && isregexop (*s)) - p[i++] = *s++; - else - p[i++] = ch; - } - p[i] = '\0'; - return p; -} - -static grub_err_t -wildcard_expand (const char *s, char ***strs) -{ - const char *start; - const char *regexop; - const char *noregexop; - char **paths = 0; - - unsigned i; - regex_t regexp; - - start = s; - while (*start) - { - split_path (start, &noregexop, ®exop); - if (noregexop >= regexop) /* no more wildcards */ - break; - - if (make_regex (noregexop, regexop, ®exp)) - goto fail; - - if (paths == 0) - { - if (start == noregexop) /* device part has regexop */ - paths = match_devices (®exp, *start != '('); - - else if (*start == '(') /* device part explicit wo regexop */ - paths = match_files ("", start, noregexop, ®exp); - - else if (*start == '/') /* no device part */ - { - char **r; - unsigned n; - char *root; - char *prefix; - - root = grub_env_get ("root"); - if (! root) - goto fail; - - prefix = grub_xasprintf ("(%s)", root); - if (! prefix) - goto fail; - - paths = match_files (prefix, start, noregexop, ®exp); - grub_free (prefix); - } - } - else - { - char **r = 0; - - for (i = 0; paths[i]; i++) - { - char **p; - - p = match_files (paths[i], start, noregexop, ®exp); - if (! p) - continue; - - r = merge (r, p); - if (! r) - goto fail; - } - paths = r; - } - - regfree (®exp); - if (! paths) - goto done; - - start = regexop; - } - - done: - - *strs = paths; - return 0; - - fail: - - for (i = 0; paths && paths[i]; i++) - grub_free (paths[i]); - grub_free (paths[i]); - regfree (®exp); - return grub_errno; -} diff --git a/script/execute.c b/script/execute.c index a41719091..20ad42add 100644 --- a/script/execute.c +++ b/script/execute.c @@ -37,6 +37,9 @@ struct grub_script_scope }; static struct grub_script_scope *scope = 0; +/* Wildcard translator for GRUB script. */ +struct grub_script_wildcard_translator *wildcard_translator; + static int grub_env_special (const char *name) { diff --git a/tests/grub_script_expansion.in b/tests/grub_script_expansion.in index 11aafc853..d1e8d55c9 100644 --- a/tests/grub_script_expansion.in +++ b/tests/grub_script_expansion.in @@ -17,7 +17,7 @@ # along with GRUB. If not, see . disks=`echo ls | @builddir@/grub-shell` -other=`echo echo \* | @builddir@/grub-shell` +other=`echo insmod regexp\; echo \* | @builddir@/grub-shell` for d in $disks; do if echo "$d" |grep ',' >/dev/null; then if echo "$other" | grep "$d" >/dev/null; then @@ -32,7 +32,7 @@ for d in $disks; do fi done -other=`echo echo '(*)' | @builddir@/grub-shell` +other=`echo insmod regexp\; echo '(*)' | @builddir@/grub-shell` for d in $disks; do if ! echo "$other" | grep "$d" >/dev/null; then echo "$d missing from (*) expansion" >&2 From 530a9ff6bc825e9a616ae4de157cdac170988662 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 30 Jul 2010 03:40:33 +0530 Subject: [PATCH 10/12] includes hidden files --- commands/wildcard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/wildcard.c b/commands/wildcard.c index 7f37c84eb..2eec9631d 100644 --- a/commands/wildcard.c +++ b/commands/wildcard.c @@ -277,7 +277,7 @@ match_files (const char *prefix, const char *suffix, const char *end, char *buffer; /* skip hidden files, . and .. */ - if (name[0] == '.') + if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0) return 0; grub_dprintf ("expand", "matching: %s in %s\n", name, dir); From cc7b1ab4d6c17b4f698a8c2a0107cf14adead9c4 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Fri, 3 Sep 2010 20:35:23 +0530 Subject: [PATCH 11/12] review comments --- grub-core/commands/regexp.c | 5 ++--- grub-core/commands/wildcard.c | 4 ++-- grub-core/script/execute.c | 13 +++++++------ include/grub/script_sh.h | 3 ++- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/grub-core/commands/regexp.c b/grub-core/commands/regexp.c index 05f6d55ad..8e0ec5a3a 100644 --- a/grub-core/commands/regexp.c +++ b/grub-core/commands/regexp.c @@ -70,17 +70,16 @@ static grub_command_t cmd; GRUB_MOD_INIT(regexp) { - extern struct grub_script_wildcard_translator translator; - cmd = grub_register_command ("regexp", grub_cmd_regexp, N_("REGEXP STRING"), N_("Test if REGEXP matches STRING.")); /* Setup GRUB script wildcard translator. */ - wildcard_translator = &translator; + grub_wildcard_translator = &grub_filename_translator; } GRUB_MOD_FINI(regexp) { grub_unregister_command (cmd); + grub_wildcard_translator = 0; } diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c index 2eec9631d..bba99dcc8 100644 --- a/grub-core/commands/wildcard.c +++ b/grub-core/commands/wildcard.c @@ -40,7 +40,7 @@ static char* wildcard_escape (const char *s); static char* wildcard_unescape (const char *s); static grub_err_t wildcard_expand (const char *s, char ***strs); -struct grub_script_wildcard_translator translator = { +struct grub_script_wildcard_translator grub_filename_translator = { .expand = wildcard_expand, .escape = wildcard_escape, .unescape = wildcard_unescape @@ -276,7 +276,7 @@ match_files (const char *prefix, const char *suffix, const char *end, char **t; char *buffer; - /* skip hidden files, . and .. */ + /* skip . and .. names */ if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0) return 0; diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index 108e5cc5d..056110fd5 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -42,7 +42,7 @@ struct grub_script_scope static struct grub_script_scope *scope = 0; /* Wildcard translator for GRUB script. */ -struct grub_script_wildcard_translator *wildcard_translator; +struct grub_script_wildcard_translator *grub_wildcard_translator; grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]) @@ -233,13 +233,13 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, int r; char *p = 0; - if (! wildcard_translator || escape_type == 0) + if (! grub_wildcard_translator || escape_type == 0) return grub_script_argv_append (&result, s); if (escape_type > 0) - p = wildcard_translator->escape (s); + p = grub_wildcard_translator->escape (s); else if (escape_type < 0) - p = wildcard_translator->unescape (s); + p = grub_wildcard_translator->unescape (s); if (! p) return 1; @@ -304,7 +304,7 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, /* Perform wildcard expansion. */ - if (wildcard_translator) + if (grub_wildcard_translator) { int j; int failed = 0; @@ -315,7 +315,8 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, result.args = 0; for (i = 0; unexpanded.args[i]; i++) { - if (wildcard_translator->expand (unexpanded.args[i], &expansions)) + if (grub_wildcard_translator->expand (unexpanded.args[i], + &expansions)) { grub_script_argv_free (&unexpanded); goto fail; diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 9140d280a..e33739b41 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -78,7 +78,8 @@ struct grub_script_wildcard_translator char *(*unescape) (const char *str); grub_err_t (*expand) (const char *str, char ***expansions); }; -extern struct grub_script_wildcard_translator *wildcard_translator; +extern struct grub_script_wildcard_translator *grub_wildcard_translator; +extern struct grub_script_wildcard_translator *grub_filename_translator; /* A complete argument. It consists of a list of one or more `struct grub_script_arg's. */ From 854bd47cb875c9b0127cf23c5a95163e4f991cbf Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Sat, 4 Sep 2010 14:22:51 +0530 Subject: [PATCH 12/12] fix memory leak and out-of-range writes --- grub-core/commands/wildcard.c | 1 + 1 file changed, 1 insertion(+) diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c index bba99dcc8..cbe32e0ff 100644 --- a/grub-core/commands/wildcard.c +++ b/grub-core/commands/wildcard.c @@ -72,6 +72,7 @@ merge (char **dest, char **ps) return 0; } + dest = p; for (j = 0; ps[j]; j++) dest[i++] = ps[j]; dest[i] = 0;