[uClibc][PATCH] Busybox 0.60.2 vfork-safe msh

Stefan Soucek ssoucek at coactive.com
Wed Dec 12 17:46:12 MST 2001


Howdy,

In an effort to get a bash-like shell running on our non-MMU platform, I
have patched the latest msh from BusyBox 0.60.2 to be vfork-safe
again. Basically, I have applied the same scheme as I found it in earlier
busybox versions plus fixed the grave() function to be vfork-safe as
well. This is responsible for backticks support.

Using this version of msh, one gets the following features on a non-MMU
system: if, nested if, case, for, shell vars, backticks, subshells. Maybe
more but I haven't tested (needed) more.

I don't know how the future of msh will look like in the new busybox
structure but I think this is a good start for non-MMU systems!

Please find the patch attached.

-Stefan

--
Stefan Soucek, ssoucek at coactive.com
Coactive Networks, 28 Liberty Ship Way, Sausalito, CA 94965
Ph: (415) 289 7840, Fax: (415) 289 1320

-------------- next part --------------
--- msh.c	Tue Dec 11 20:16:13 2001
+++ /home/ssoucek/salem/source/busybox/msh.c	Wed Dec 12 17:17:10 2001
@@ -23,6 +23,9 @@
  * Original copyright notice is retained at the end of this file.
  */
 
+/* define this to use fork on MMU-systems instead of vfork */
+#undef USE_FORK
+
 /* -------- sh.h -------- */
 
 #include <stdlib.h>
@@ -2124,10 +2127,29 @@ static char *signame[] = {
 
 #define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
 
+/*
+ * common actions when creating a new child
+ */
+#ifdef USE_FORK
+#define XFORK fork
+static int parent()
+{
+	register int i;
+
+	i = fork();
+	if (i != 0) {
+		if (i == -1)
+			warn("try again");
+	}
+	return (i);
+}
+#else
+#  define parent vfork
+#  define XFORK  vfork
+#endif
 
 static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp,
 					int *pforked);
-static int parent(void);
 static int iosetup(struct ioword *iop, int pipein, int pipeout);
 static void echo(char **wp);
 static struct op **find1case(struct op *t, char *w);
@@ -2210,8 +2232,15 @@ int act;
 		break;
 
 	case TASYNC:
+	{
+	        /* save global vars altered by child */
+		int hinteractive = interactive;
+
 		i = parent();
 		if (i != 0) {
+		        /* restore global vars */
+			interactive = hinteractive;
+
 			if (i != -1) {
 				setval(lookup("!"), putn(i));
 				if (pin != NULL)
@@ -2236,7 +2265,7 @@ int act;
 			exit(execute(t->left, pin, pout, FEXEC));
 		}
 		break;
-
+	}
 	case TOR:
 	case TAND:
 		rv = execute(t->left, pin, pout, 0);
@@ -2338,6 +2367,26 @@ int *pforked;
 	int resetsig;
 	char **owp;
 
+	int *hpin = pin;
+	int *hpout = pout;
+	int hforked;
+	char *hwp;
+	int hinteractive;
+	int hintr;
+	struct brkcon * hbrklist;
+	int hexecflg;
+
+#if __GNUC__
+	/* Avoid longjmp clobbering */
+	(void) &pin;
+	(void) &pout;
+	(void) &wp;
+	(void) &shcom;
+	(void) &cp;
+	(void) &resetsig;
+	(void) &owp;
+#endif	
+
 	owp = wp;
 	resetsig = 0;
 	*pforked = 0;
@@ -2360,8 +2409,30 @@ int *pforked;
 	t->words = wp;
 	f = act;
 	if (shcom == NULL && (f & FEXEC) == 0) {
+
+	        /* save vars altered by child (needed by vfork) */
+		hpin = pin;
+		hpout = pout;
+		hforked = *pforked;
+		hwp = *wp;
+		hinteractive = interactive;
+		hintr = intr;
+		hbrklist = brklist;
+		hexecflg = execflg;
+	
 		i = parent();
 		if (i != 0) {
+		        /* restore vars altered by child (needed by vfork) */
+			pin = hpin;
+			pout = hpout;
+			*pforked = hforked;
+			*wp = hwp;
+			interactive = hinteractive;
+			intr = hintr;
+			brklist = hbrklist;
+			execflg = hexecflg;
+
+			*pforked = 0;
 			if (i == -1)
 				return (rv);
 			if (pin != NULL)
@@ -2431,21 +2502,6 @@ int *pforked;
 }
 
 /*
- * common actions when creating a new child
- */
-static int parent()
-{
-	register int i;
-
-	i = fork();
-	if (i != 0) {
-		if (i == -1)
-			warn("try again");
-	}
-	return (i);
-}
-
-/*
  * 0< 1> are ignored as required
  * within pipelines.
  */
@@ -2670,7 +2726,22 @@ char *c, **v, **envp;
 	register char *sp, *tp;
 	int eacces = 0, asis = 0;
 
-	sp = any('/', c) ? "" : path->value;
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+	char *name = c;
+#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+	name = get_last_path_component(name);
+#endif
+	optind = 1;
+	if (find_applet_by_name(name)) {
+		/* We have to exec here since we vforked.  Running 
+		 * run_applet_by_name() won't work and bad things
+		 * will happen. */
+		execve("/proc/self/exe", v, envp);
+		execve("busybox", v, envp);
+	}
+#endif
+
+	sp = any('/', c)? "": path->value;
 	asis = *sp == '\0';
 	while (asis || *sp != '\0') {
 		asis = 0;
@@ -2756,12 +2827,14 @@ int (*f) ();
  * built-in commands: doX
  */
 
-int dolabel()
+static int
+dolabel()
 {
 	return (0);
 }
 
-int dochdir(t)
+static int
+dochdir(t)
 register struct op *t;
 {
 	register char *cp, *er;
@@ -3598,7 +3671,7 @@ int quoted;
 	}
 	if (openpipe(pf) < 0)
 		return (0);
-	if ((i = fork()) == -1) {
+	if ((i = XFORK()) == -1) {
 		closepipe(pf);
 		err("try again");
 		return (0);
@@ -3616,10 +3689,11 @@ int quoted;
 			signal(i, SIG_DFL);
 	dup2(pf[1], 1);
 	closepipe(pf);
+	cp = strsave(e.linep = s, 0);
+#ifdef USE_FORK
 	flag['e'] = 0;
 	flag['v'] = 0;
 	flag['n'] = 0;
-	cp = strsave(e.linep = s, 0);
 	areanum = 1;
 	inhere = acthere = (struct here *) 0;
 	freearea(areanum);			/* free old space */
@@ -3630,6 +3704,14 @@ int quoted;
 	PUSHIO(aword, cp, nlchar);
 	onecommand();
 	exit(1);
+#else
+	/* NOTE: When we are vfork()'ing we've got to exec here.
+	 * Therefore we start the command using /bin/sh -c.
+	 */
+	execlp("/bin/sh", "/bin/sh", "-c", cp, NULL);
+	err("grave: execlp failed\n");
+	_exit(1);
+#endif
 }
 
 char *unquote(as)


More information about the uClibc mailing list