[BusyBox] read in sh / shell-variables

Larry Doolittle ldoolitt at recycle.lbl.gov
Mon Dec 18 22:46:04 UTC 2000


This patch to the current (??) CVS sh.c will fix Jan Setzer's
problem with
   read T </tmp/VAR
It now seems to behave the same way bash does, by forking all
builtins within pipes, but allowing full redirects without
forking outside of pipes.

This is my working copy, it also has some cosmetic changes.

None of my work so far has addressed Jan's other comment, that
variable expansion is truly lame.  See my wishlist bug item
#1036, and my posting titled "lash, environment variables, and
wordexp", dated Mon, 27 Nov 2000, archived at
http://busybox.net/lists/busybox/2000-November/001022.html

   - Larry

--- /home/ldoolitt/cvs/busybox/sh.c	Mon Dec 18 12:26:14 2000
+++ sh.c	Mon Dec 18 14:27:27 2000
@@ -26,7 +26,7 @@
  */
 
 //
-//This works pretty well now, and is not on by default.
+//This works pretty well now, and is now on by default.
 #define BB_FEATURE_SH_ENVIRONMENT
 //
 //Backtick support has some problems, use at your own risk!
@@ -34,7 +34,7 @@
 //
 //If, then, else, etc. support..  This should now behave basically
 //like any other Bourne shell...
-//#define BB_FEATURE_SH_IF_EXPRESSIONS
+#define BB_FEATURE_SH_IF_EXPRESSIONS
 //
 /* This is currently a little broken... */
 //#define HANDLE_CONTINUATION_CHARS
@@ -97,6 +97,7 @@
 	int free_glob;				/* should we globfree(&glob_result)? */
 	int is_stopped;				/* is the program currently running? */
 	struct job *family;			/* pointer back to the child's parent job */
+	int squirrel_fd[3];			/* saved copies of stdin, stdout, stderr */
 };
 
 struct job {
@@ -315,22 +316,23 @@
 	int i, jobNum;
 	struct job *job=NULL;
 	
+	if (!child->argv[1] || child->argv[2]) {
+		error_msg("%s: exactly one argument is expected\n",
+				child->argv[0]);
+		return EXIT_FAILURE;
+	}
 
-		if (!child->argv[1] || child->argv[2]) {
-			error_msg("%s: exactly one argument is expected\n",
-					child->argv[0]);
-			return EXIT_FAILURE;
-		}
-		if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) {
-			error_msg("%s: bad argument '%s'\n",
-					child->argv[0], child->argv[1]);
-			return EXIT_FAILURE;
-		}
-		for (job = child->family->job_list->head; job; job = job->next) {
-			if (job->jobid == jobNum) {
-				break;
-			}
+	if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) {
+		error_msg("%s: bad argument '%s'\n",
+				child->argv[0], child->argv[1]);
+		return EXIT_FAILURE;
+	}
+
+	for (job = child->family->job_list->head; job; job = job->next) {
+		if (job->jobid == jobNum) {
+			break;
 		}
+	}
 
 	if (!job) {
 		error_msg("%s: unknown job %d\n",
@@ -523,7 +525,7 @@
 	}
 
 	cmd->job_context |= ELSE_EXP_CONTEXT;
-	debug_printf("job=%p builtin_else set job context to %x\n", child->family, cmd->job_context);
+	debug_printf("job=%p builtin_else set job context to %x\n", cmd, cmd->job_context);
 
 	/* Now run the 'else' command */
 	debug_printf( "'else' now running '%s'\n", charptr1);
@@ -681,7 +683,9 @@
 		perror("waitpid");
 }
 
-static int setup_redirects(struct child_prog *prog)
+/* squirrel != 0 means we squirrel away copies of stdin, stdout,
+ * and stderr if they are redirected. */
+static int setup_redirects(struct child_prog *prog, int squirrel)
 {
 	int i;
 	int openfd;
@@ -711,6 +715,9 @@
 		}
 
 		if (openfd != redir->fd) {
+			if (squirrel && redir->fd < 3) {
+				prog->squirrel_fd[redir->fd] = dup(redir->fd);
+			}
 			dup2(openfd, redir->fd);
 			close(openfd);
 		}
@@ -719,6 +726,19 @@
 	return 0;
 }
 
+static void restore_redirects(struct child_prog *prog)
+{
+	int i, fd;
+	for (i=0; i<3; i++) {
+		fd = prog->squirrel_fd[i];
+		if (fd != -1) {
+			/* No error checking.  I sure wouldn't know what
+			 * to do with an error if I found one! */
+			dup2(fd, i);
+			close(fd);
+		}
+	}
+}
 
 static int get_command(FILE * source, char *command)
 {
@@ -984,6 +1004,7 @@
 	prog->free_glob = 0;
 	prog->is_stopped = 0;
 	prog->family = job;
+	for (i=0; i<3; i++) prog->squirrel_fd[i] = -1;
 
 	argv_alloced = 5;
 	prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
@@ -1118,6 +1139,7 @@
 				prog->free_glob = 0;
 				prog->is_stopped = 0;
 				prog->family = job;
+				for (i=0; i<3; i++) prog->squirrel_fd[i] = -1;
 				argc_l = 0;
 
 				argv_alloced = 5;
@@ -1301,11 +1323,18 @@
 	struct BB_applet search_applet, *applet;
 #endif
 
-	/* Check if the command matches any of the forking builtins.
-	 * XXX It would probably be wise to check for non-forking builtins
-	 * here as well, since in some context the non-forking path
-	 * is disabled or bypassed.  See comment in run_command.
+	/* Check if the command matches any of the non-forking builtins.
+	 * Depending on context, this might be duplicitous.  But it's
+	 * easier to waste a few CPU cycles than it is to figure out
+	 * if this is one of those cases.
 	 */
+	for (x = bltins; x->cmd; x++) {
+		if (strcmp(child->argv[0], x->cmd) == 0 ) {
+			exit(x->function(child));
+		}
+	}
+
+	/* Check if the command matches any of the forking builtins. */
 	for (x = bltins_forking; x->cmd; x++) {
 		if (strcmp(child->argv[0], x->cmd) == 0) {
 			applet_name=x->cmd;
@@ -1432,15 +1461,21 @@
 		}
 #endif
 
-		/* Check if the command matches any non-forking builtins.
-		 * XXX should probably skip this test, and fork anyway, if
-		 * there redirects of some kind demand forking to work right.
-		 * pseudo_exec would then need to handle the non-forking command
-		 * in a forked context.
+		/* Check if the command matches any non-forking builtins,
+		 * but only if this is a simple command.
+		 * Non-forking builtins within pipes have to fork anyway,
+		 * and are handled in pseudo_exec.  "echo foo | read bar"
+		 * is doomed to failure, and doesn't work on bash, either.
 		 */
-		for (x = bltins; x->cmd; x++) {
-			if (strcmp(child->argv[0], x->cmd) == 0 ) {
-				return(x->function(child));
+		if (newjob->num_progs == 1) {
+			for (x = bltins; x->cmd; x++) {
+				if (strcmp(child->argv[0], x->cmd) == 0 ) {
+					int rcode;
+					setup_redirects(child, 1); /* needs testing, to put things back at the end */
+					rcode = x->function(child);
+					restore_redirects(child);
+					return rcode;
+				}
 			}
 		}
 
@@ -1463,7 +1498,7 @@
 			}
 
 			/* explicit redirects override pipes */
-			setup_redirects(child);
+			setup_redirects(child,0);
 
 			pseudo_exec(child);
 		}





More information about the busybox mailing list