[BusyBox] [PATCH] msh backtick problems solved

Robert Schwebel robert at schwebel.de
Tue Mar 11 14:49:04 UTC 2003


Hi, 

Thanks to Jonas Holmberg's working port of the original minix shell I
was able to fix busybox-msh's backtick expansion problems. A patch is
attached. 

I assume somebody with more shell experience than myself should have a
look at the patch before adding it, as I'm not really sure what I did... 

The only problem which I found to be left is that the basename magic
doesn't work properly; if you start 'busybox msh' I still get this 'not
found' error. If you add a link for msh it works. But that's definitely
something I'll not have a look at anymore tonight....

Robert
-- 
 Dipl.-Ing. Robert Schwebel | http://www.pengutronix.de
 Pengutronix - Linux Solutions for Science and Industry
   Braunschweiger Str. 79,  31134 Hildesheim, Germany
   Handelsregister:  Amtsgericht Hildesheim, HRA 2686
    Phone: +49-5121-28619-0 |  Fax: +49-5121-28619-4
-------------- next part --------------
--- msh-orig.c	Tue Mar 11 12:29:45 2003
+++ msh.c	Tue Mar 11 22:45:59 2003
@@ -5,6 +5,10 @@
  * This version of the Minix shell was adapted for use in busybox
  * by Erik Andersen <andersee at debian.org>
  *
+ * - backtick expansion did not work properly
+ *   Jonas Holmberg <jonas.holmberg at axis.com>
+ *   Robert Schwebel <r.schwebel at pengutronix.de>
+ *
  * This program 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 2 of the License, or
@@ -250,10 +254,10 @@
 /*
  * error handling
  */
-static void leave (void); /* abort shell (or fail in subshell) */
-static void fail (void);	 /* fail but return to process next command */
+static void leave (void); 	/* abort shell (or fail in subshell) */
+static void fail (void);	/* fail but return to process next command */
 static void warn (char *s );
-static void sig (int i );	 /* default signal handler */
+static void sig (int i );	/* default signal handler */
 
 
 
@@ -536,6 +540,7 @@
 static void glob1 (char *base, char *lim );
 static void glob2 (char *i, char *j );
 static void glob3 (char *i, char *j, char *k );
+static char * memcopy (char *ato, char *from, int nb );
 static void readhere (char **name, char *s, int ec );
 static void pushio (struct ioarg *argp, int (*f)(struct ioarg *));
 static int xxchar(struct ioarg *ap );
@@ -687,6 +692,7 @@
 static char * current_prompt;
 #endif
 
+static char *subshellname;
 
 /* -------- sh.c -------- */
 /*
@@ -712,6 +718,36 @@
 	closeall();
 	areanum = 1;
 
+	/* FIXME: make this compatible to busybox's naming scheme */
+	/* 'busybox msh' does not work, you have to create a link */
+	if ((argv[0][0] == '-') && (argv[0][1] != '\0')) {
+		if (!(subshellname = space(strlen(argv[0]))))
+			err("out of memory\n");
+		else {
+			memcopy(subshellname, argv[0] + 1, strlen(argv[0]));
+		}
+	} else {
+		if ((argv[0][0] != '/') && strchr(argv[0], '/')) {
+			char *cwd = getcwd(NULL, 0);
+			if (!(subshellname = space(strlen(cwd) + 1 +
+					           strlen(argv[0]) + 1)))
+				err("out of memory\n");
+			else {
+				memcopy(subshellname, cwd, strlen(cwd));
+				subshellname[strlen(cwd)] = '/';
+				memcopy(subshellname + strlen(cwd) + 1,
+					argv[0], strlen(argv[0]) + 1);
+				free(cwd);
+			}
+			
+		} else {
+		if (!(subshellname = space(strlen(argv[0]) + 1)))
+			err("out of memory\n");
+		else
+			memcopy(subshellname, argv[0], strlen(argv[0]) + 1);
+		}
+	}
+	
 	shell = lookup("SHELL");
 	if (shell->value == null)
 		setval(shell, shellname);
@@ -722,11 +758,15 @@
 		setval(homedir, "/");
 	export(homedir);
 
-	setval(lookup("$"), itoa(getpid(), 5));
+	setval(lookup("$"), putn(getpid()));
 
 	path = lookup("PATH");
-	if (path->value == null)
-		setval(path, search);
+	if (path->value == null) {
+		if (geteuid() == 0)
+			setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
+		else
+			setval(path, "/bin:/usr/bin");
+	}
 	export(path);
 
 	ifs = lookup("IFS");
@@ -858,7 +898,7 @@
 
 	cp = m;
 	for (c='a'; c<='z'; c++)
-		if (flag[c])
+		if (flag[(int)c])
 			*cp++ = c;
 	*cp = 0;
 	setval(lookup("-"), m);
@@ -2326,6 +2366,9 @@
 
 	switch(t->type) {
 	case TPAREN:
+		rv = execute(t->left, pin, pout, 0);
+		break;
+			
 	case TCOM:
 		{
 			int child;
@@ -3643,7 +3686,7 @@
  */
 static int
 subgetc(ec, quoted)
-register int ec;
+register char ec;
 int quoted;
 {
 	register char c;
@@ -3675,7 +3718,7 @@
 	int otask;
 	struct io *oiop;
 	char *dolp;
-	register char *s, c, *cp=NULL;
+	register char *s, c, *cp = NULL;
 	struct var *vp;
 
 	c = readc();
@@ -3770,59 +3813,154 @@
 /*
  * Run the command in `...` and read its output.
  */
+
 static int
 grave(quoted)
 int quoted;
 {
-	register int i;
 	char *cp;
+	register int i;
+	int j;
 	int pf[2];
+	static char child_cmd[LINELIM];
+	char *src;
+	char *dest;
+	int count;
+	int ignore;
+	int ignore_once;
+	char *argument_list[4];
 
 #if __GNUC__
 	/* Avoid longjmp clobbering */
 	(void) &cp;
 #endif
+	
 	for (cp = e.iop->argp->aword; *cp != '`'; cp++)
 		if (*cp == 0) {
 			err("no closing `");
 			return(0);
 		}
+
+	/* string copy with dollar expansion */
+	src = e.iop->argp->aword;
+	dest = child_cmd;
+	count = 0;
+	ignore = 0;
+	ignore_once = 0;
+	while ((*src != '`') && (count < LINELIM)) {
+		if (*src == '\'')
+			ignore = !ignore;
+		if (*src == '\\')
+			ignore_once = 1;
+		if (*src == '$' && !ignore && !ignore_once) {
+			struct var *vp;
+			char var_name[LINELIM];
+			char alt_value[LINELIM];
+			int var_index = 0;
+			int alt_index = 0;
+			char operator = 0;
+			int braces = 0;
+			char *value;
+
+			src++;
+			if (*src == '{') {
+				braces = 1;
+				src++;
+			}
+
+			var_name[var_index++] = *src++;
+			while (isalnum(*src))
+				var_name[var_index++] = *src++;
+			var_name[var_index] = 0;
+
+			if (braces) {
+				switch (*src) {
+				case '}':
+					break;
+				case '-':
+				case '=':
+				case '+':
+				case '?':
+					operator = *src;
+					break;
+				default:
+					err("unclosed ${\n");
+					return(0);
+				}
+				if (operator) {	
+					src++;
+					while (*src && (*src != '}')) {
+						alt_value[alt_index++] = *src++;
+					}
+					alt_value[alt_index] = 0;
+					if (*src != '}') {
+						err("unclosed ${\n");
+						return(0);
+					}
+				}
+				src++;
+			}
+
+			vp = lookup(var_name);
+			if (vp->value != null)
+				value = (operator == '+')? alt_value : vp->value;
+			else if (operator == '?') {
+				err(alt_value);
+				return(0);
+			} else if (alt_index && (operator != '+')) {
+				value = alt_value;
+				if (operator == '=')
+					setval(vp, value);
+			} else
+				continue;
+
+			while (*value && (count < LINELIM)) {
+				*dest++ = *value++;
+				count++;
+			}
+		} else {
+			*dest++ = *src++;
+			count++;
+			ignore_once = 0;
+		}
+	}
+	*dest = '\0';
+	
 	if (openpipe(pf) < 0)
 		return(0);
-	if ((i = vfork()) == -1) {
+	while ((i = vfork()) == EAGAIN)
+		;
+	if (i < 0) {
 		closepipe(pf);
-		err("try again");
+		err("Out of memory");
 		return(0);
 	}
 	if (i != 0) {
+		waitpid(i, NULL, 0);
 		e.iop->argp->aword = ++cp;
 		close(pf[1]);
 		PUSHIO(afile, remap(pf[0]), (int(*)(struct ioarg *))((quoted)? qgravechar: gravechar));
 		return(1);
 	}
-	*cp = 0;
 	/* allow trapped signals */
-	for (i=0; i<=_NSIG; i++)
-		if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN)
-			signal(i, SIG_DFL);
+	/* XXX - Maybe this signal stuff should go as well? */
+	for (j=0; j<=_NSIG; j++)
+		if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
+			signal(j, SIG_DFL);
+	
 	dup2(pf[1], 1);
 	closepipe(pf);
-	flag['e'] = 0;
-	flag['v'] = 0;
-	flag['n'] = 0;
-	cp = strsave(e.iop->argp->aword, 0);
-	areanum = 1;
-	freehere(areanum);
-	freearea(areanum);	/* free old space */
-	e.oenv = NULL;
-	e.iop = (e.iobase = iostack) - 1;
-	unquote(cp);
-	interactive = 0;
-	PUSHIO(aword, cp, nlchar);
-	onecommand();
-	exit(1);
+
+	argument_list[0] = subshellname;
+	argument_list[1] = "-c";
+	argument_list[2] = child_cmd;
+	argument_list[3] = 0;
+
+	prs(rexecve(argument_list[0], argument_list, makenv()));
+	_exit(1);
 }
 
+
 static char *
 unquote(as)
 register char *as;
@@ -4176,6 +4314,20 @@
 	} while(--m);
 }
 
+char *
+memcopy(ato, from, nb)
+register char *ato, *from;
+register int nb;
+{
+	register char *to;
+
+	to = ato;
+	while (--nb >= 0)
+		*to++ = *from++;
+	return(ato);
+}
+
+
 /* -------- io.c -------- */
 
 /*
@@ -4194,7 +4346,7 @@
 		return(c);
 	}
 	c = readc();
- 	if (ec != '\'' && e.iop->task != XGRAVE) {
+	if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
 		if(c == '\\') {
 			c = readc();
 			if (c == '\n' && ec != '\"')
@@ -4444,7 +4596,9 @@
 	  if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
 	    if (i)
 	      lseek(ap->afile, ap->afpos, 0);
-	    i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
+		do {
+			i = read(ap->afile, bp->buf, sizeof(bp->buf));
+		} while (i < 0 && errno == EINTR);
 	    if (i <= 0) {
 	      closef(ap->afile);
 	      return 0;
@@ -4457,22 +4611,24 @@
 	}
 
 #ifdef CONFIG_FEATURE_COMMAND_EDITING
-	if (interactive) {
+	if (interactive && isatty(ap->afile)) {
 	    static char mycommand[BUFSIZ];
 	    static int position = 0, size = 0;
 
 	    while (size == 0 || position >= size) {
-		cmdedit_read_input(current_prompt, mycommand);
-		size = strlen(mycommand);
-		position = 0;
+			cmdedit_read_input(current_prompt, mycommand);
+			size = strlen(mycommand);
+			position = 0;
 	    }
-	    c = mycommand[position];
-	    position++;
+	    c = mycommand[position++];
 	    return(c);
 	} else 
 #endif
 	{
-		i = safe_read(ap->afile, &c, sizeof(c));
+		do {
+			i = read(ap->afile, &c, sizeof(c));
+		} while (i < 0 && errno == EINTR);
+		
 		return(i == sizeof(c)? c&0177: (closef(ap->afile), 0));
 	}
 }


More information about the busybox mailing list