From 8c184ffa19676b52dab8cd5b8e82e5beb21f8c29 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Thu, 29 Jul 2010 21:09:18 +0530 Subject: [PATCH] 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; }