mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: barebox@lists.infradead.org
Subject: [PATCH 11/13] hush: Fix globbing
Date: Mon, 30 Apr 2012 13:19:26 +0200	[thread overview]
Message-ID: <1335784768-9189-12-git-send-email-s.hauer@pengutronix.de> (raw)
In-Reply-To: <1335784768-9189-1-git-send-email-s.hauer@pengutronix.de>

hush has a long standing and anoying glob bug. hush expands wildcards
during parsing of the script or command stream. When the command stream
begins to execute the wildcards are already expanded which leads to:

mkdir /tmp
cd /tmp
mkdir foo; ls *
ls: *: No such file or directory

To fix this expand wildcards right before executing the command. Since
'for' loops are not executed in commands, we have to keep the old behaviour
in here so that 'for i in *' still works.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/hush.c |  127 +++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 79 insertions(+), 48 deletions(-)

diff --git a/common/hush.c b/common/hush.c
index d7ed624..ab513af 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -497,7 +497,8 @@ static void setup_string_in_str(struct in_str *i, const char *s)
 }
 
 #ifdef CONFIG_HUSH_GETOPT
-static int builtin_getopt(struct p_context *ctx, struct child_prog *child)
+static int builtin_getopt(struct p_context *ctx, struct child_prog *child,
+		int argc, char *argv[])
 {
 	char *optstring, *var;
 	int opt, ret = 0;
@@ -505,11 +506,11 @@ static int builtin_getopt(struct p_context *ctx, struct child_prog *child)
 	struct option *o;
 	struct getopt_context gc;
 
-	if (child->argc != 3)
+	if (argc != 3)
 		return -2 - 1;
 
-	optstring = child->argv[1];
-	var = child->argv[2];
+	optstring = argv[1];
+	var = argv[2];
 
 	getopt_context_store(&gc);
 
@@ -546,6 +547,12 @@ out:
 }
 
 BAREBOX_MAGICVAR(OPTARG, "optarg for hush builtin getopt");
+#else
+static int builtin_getopt(struct p_context *ctx, struct child_prog *child,
+		int argc, char *argv[])
+{
+	return -1;
+}
 #endif
 
 static void remove_quotes_in_str(char *src)
@@ -601,6 +608,57 @@ static void remove_quotes(int argc, char *argv[])
 		remove_quotes_in_str(argv[i]);
 }
 
+static int fake_glob(const char *src, int flags,
+		int (*errfunc) (const char *epath, int eerrno),
+		glob_t *pglob)
+{
+	int pathc;
+
+	if (!(flags & GLOB_APPEND)) {
+		globfree(pglob);
+		pglob->gl_pathv = NULL;
+		pglob->gl_pathc = 0;
+		pglob->gl_offs = 0;
+	}
+	pathc = ++pglob->gl_pathc;
+	pglob->gl_pathv = xrealloc(pglob->gl_pathv, (pathc + 1) * sizeof(*pglob->gl_pathv));
+	pglob->gl_pathv[pathc - 1] = xstrdup(src);
+	pglob->gl_pathv[pathc] = NULL;
+
+	return 0;
+}
+
+#ifdef CONFIG_GLOB
+static int do_glob(const char *src, int flags,
+		int (*errfunc) (const char *epath, int eerrno),
+		glob_t *pglob)
+{
+	return glob(src, flags, errfunc, pglob);
+}
+#else
+static int do_glob(const char *src, int flags,
+		int (*errfunc) (const char *epath, int eerrno),
+		glob_t *pglob)
+{
+	return fake_glob(src, flags, errfunc, pglob);
+}
+#endif
+
+static void do_glob_in_argv(glob_t *globbuf, int argc, char **argv)
+{
+	int i;
+	int flags;
+
+	globbuf->gl_offs = 0;
+	flags = GLOB_DOOFFS | GLOB_NOCHECK;
+
+	for (i = 0; i < argc; i++) {
+		int ret;
+		ret = do_glob(argv[i], flags, NULL, globbuf);
+		flags |= GLOB_APPEND;
+	}
+}
+
 /* run_pipe_real() starts all the jobs, but doesn't wait for anything
  * to finish.  See checkjobs().
  *
@@ -623,6 +681,8 @@ static int run_pipe_real(struct p_context *ctx, struct pipe *pi)
 	int nextin;
 	struct child_prog *child;
 	char *p;
+	glob_t globbuf = {};
+	int ret;
 # if __GNUC__
 	/* Avoid longjmp clobbering */
 	(void) &i;
@@ -706,13 +766,18 @@ static int run_pipe_real(struct p_context *ctx, struct pipe *pi)
 		return last_return_code;
 	}
 
-	remove_quotes(child->argc - i, &child->argv[i]);
+	do_glob_in_argv(&globbuf, child->argc - i, &child->argv[i]);
 
-#ifdef CONFIG_HUSH_GETOPT
-	if (!strcmp(child->argv[i], "getopt"))
-		return builtin_getopt(ctx, child);
-#endif
-	return execute_binfmt(child->argc - i, &child->argv[i]);
+	remove_quotes(globbuf.gl_pathc, globbuf.gl_pathv);
+
+	if (!strcmp(globbuf.gl_pathv[0], "getopt"))
+		ret = builtin_getopt(ctx, child, globbuf.gl_pathc, globbuf.gl_pathv);
+	else
+		ret = execute_binfmt(globbuf.gl_pathc, globbuf.gl_pathv);
+
+	globfree(&globbuf);
+
+	return ret;
 }
 
 static int run_list_real(struct p_context *ctx, struct pipe *pi)
@@ -911,41 +976,7 @@ static int free_pipe_list(struct pipe *head, int indent)
 	return rcode;
 }
 
-static int fake_glob(const char *src, int flags,
-		int (*errfunc) (const char *epath, int eerrno),
-		glob_t *pglob)
-{
-	int pathc;
-
-	if (!(flags & GLOB_APPEND)) {
-		globfree(pglob);
-		pglob->gl_pathv = NULL;
-		pglob->gl_pathc = 0;
-		pglob->gl_offs = 0;
-	}
-	pathc = ++pglob->gl_pathc;
-	pglob->gl_pathv = xrealloc(pglob->gl_pathv, (pathc + 1) * sizeof(*pglob->gl_pathv));
-	pglob->gl_pathv[pathc - 1] = xstrdup(src);
-	pglob->gl_pathv[pathc] = NULL;
-
-	return 0;
-}
-
-/* XXX broken if the last character is '\\', check that before calling */
-static int glob_needed(const char *s)
-{
-#ifdef CONFIG_GLOB
-	for (; *s; s++) {
-		if (*s == '\\')
-			s++;
-		if (strchr("*[?",*s))
-			return 1;
-	}
-#endif
-	return 0;
-}
-
-static int xglob(o_string *dest, int flags, glob_t *pglob)
+static int xglob(o_string *dest, int flags, glob_t *pglob, int glob_needed)
 {
 	int gr;
 
@@ -959,8 +990,8 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
 		} else {
 			return 0;
 		}
-	} else if (glob_needed(dest->data)) {
-		gr = glob(dest->data, flags, NULL, pglob);
+	} else if (glob_needed) {
+		gr = do_glob(dest->data, flags, NULL, pglob);
 		debug("glob returned %d\n",gr);
 	} else {
 		gr = fake_glob(dest->data, flags, NULL, pglob);
@@ -1188,7 +1219,7 @@ static int done_word(o_string *dest, struct p_context *ctx)
 	if (child->argv)
 		flags |= GLOB_APPEND;
 
-	gr = xglob(dest, flags, glob_target);
+	gr = xglob(dest, flags, glob_target, ctx->w == RES_IN ? 1 : 0);
 	if (gr)
 		return 1;
 
-- 
1.7.10


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

  parent reply	other threads:[~2012-04-30 11:19 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-30 11:19 hush fixes and cleanups Sascha Hauer
2012-04-30 11:19 ` [PATCH 01/13] hush: safe indention level by continueing a loop Sascha Hauer
2012-04-30 11:19 ` [PATCH 02/13] hush: safe an " Sascha Hauer
2012-04-30 11:19 ` [PATCH 03/13] hush: cleanup coding style Sascha Hauer
2012-04-30 11:19 ` [PATCH 04/13] hush: remove bogus 'else' Sascha Hauer
2012-04-30 11:19 ` [PATCH 05/13] hush: run_pipe_real must have num_progs == 1 Sascha Hauer
2012-04-30 11:19 ` [PATCH 06/13] hush: run_pipe_real: bail out early to safe an indention level Sascha Hauer
2012-04-30 11:19 ` [PATCH 07/13] hush: remove quotes at end of processing Sascha Hauer
2012-04-30 11:19 ` [PATCH 08/13] hush: simplify globhack Sascha Hauer
2012-04-30 11:19 ` [PATCH 09/13] hush: pass GLOB_NOCHECK to glob Sascha Hauer
2012-04-30 11:19 ` [PATCH 10/13] glob: activate GLOB_NOCHECK flag Sascha Hauer
2012-04-30 11:19 ` Sascha Hauer [this message]
2012-04-30 11:19 ` [PATCH 12/13] hush: allow to run interactive shell in do_sh Sascha Hauer
2012-04-30 11:19 ` [PATCH 13/13] defaultenv: remove now unnecessary hush-hack Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1335784768-9189-12-git-send-email-s.hauer@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox