svn commit: [26011] trunk/busybox/shell

vda at busybox.net vda at busybox.net
Tue Apr 7 13:26:19 UTC 2009


Author: vda
Date: 2009-04-07 13:26:18 +0000 (Tue, 07 Apr 2009)
New Revision: 26011

Log:
hush: fix heredoc <<- handling.
 hush-misc/heredoc2.tests testcase needs only one fix now -
 $var and `cmd` expancsion in heredocs

function                                             old     new   delta
parse_redirect                                       265     306     +41
parse_stream                                        1866    1899     +33



Modified:
   trunk/busybox/shell/hush.c


Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c	2009-04-07 10:52:40 UTC (rev 26010)
+++ trunk/busybox/shell/hush.c	2009-04-07 13:26:18 UTC (rev 26011)
@@ -250,16 +250,6 @@
 
 #define SPECIAL_VAR_SYMBOL 3
 
-typedef enum redir_type {
-	REDIRECT_INVALID   = 0,
-	REDIRECT_INPUT     = 1,
-	REDIRECT_OVERWRITE = 2,
-	REDIRECT_APPEND    = 3,
-	REDIRECT_HEREDOC   = 4,
-	REDIRECT_IO        = 5,
-	REDIRECT_HEREDOC2  = 6, /* REDIRECT_HEREDOC after heredoc load */
-} redir_type;
-
 /* The descrip member of this structure is only used to make
  * debugging output pretty */
 static const struct {
@@ -349,11 +339,25 @@
 struct redir_struct {
 	struct redir_struct *next;
 	char *rd_filename;          /* filename */
-	int fd;                     /* file descriptor being redirected */
-	int dup;                    /* -1, or file descriptor being duplicated */
-	smallint /*enum redir_type*/ rd_type;
+	int rd_fd;                  /* file descriptor being redirected */
+	int rd_dup;                 /* -1, or file descriptor being duplicated */
+	smallint rd_type;           /* (enum redir_type) */
+	/* note: for heredocs, rd_filename contains heredoc delimiter,
+	 * and subsequently heredoc itself; and rd_dup is
+	 * "do we need to trim leading tabs?" bool flag
+	 */
 };
+typedef enum redir_type {
+	REDIRECT_INVALID   = 0,
+	REDIRECT_INPUT     = 1,
+	REDIRECT_OVERWRITE = 2,
+	REDIRECT_APPEND    = 3,
+	REDIRECT_HEREDOC   = 4,
+	REDIRECT_IO        = 5,
+	REDIRECT_HEREDOC2  = 6, /* REDIRECT_HEREDOC after heredoc is loaded */
+} redir_type;
 
+
 struct command {
 	pid_t pid;                  /* 0 if exited */
 	int assignment_cnt;         /* how many argv[i] are assignments? */
@@ -910,6 +914,11 @@
 }
 
 #if ENABLE_HUSH_JOB
+/* After [v]fork, in child: do not restore tty pgrp on xfunc death */
+#define disable_restore_tty_pgrp_on_exit() (die_sleep = 0)
+/* After [v]fork, in parent: do not restore tty pgrp on xfunc death */
+#define enable_restore_tty_pgrp_on_exit()  (die_sleep = -1)
+
 /* Restores tty foreground process group, and exits.
  * May be called as signal handler for fatal signal
  * (will faithfully resend signal to itself, producing correct exit state)
@@ -932,6 +941,11 @@
 
 	kill_myself_with_sig(sig); /* does not return */
 }
+#else
+
+#define disable_restore_tty_pgrp_on_exit() ((void)0)
+#define enable_restore_tty_pgrp_on_exit()  ((void)0)
+
 #endif
 
 /* Restores tty foreground process group, and exits. */
@@ -1359,6 +1373,13 @@
 {
 	o_addblock(o, str, strlen(str));
 }
+static void nommu_addchr(o_string *o, int ch)
+{
+	if (o)
+		o_addchr(o, ch);
+}
+#else
+#define nommu_addchr(o, str) ((void)0)
 #endif
 
 static void o_addstr_with_NUL(o_string *o, const char *str)
@@ -2201,8 +2222,8 @@
 
 	/* Okay, pipe buffer was not big enough */
 	/* Note: we must not create a stray child (bastard? :)
-	 * for the unsuspecting parent process. We create a grandchild
-	 * and exit before we exec the process which consumes heredoc
+	 * for the unsuspecting parent process. Child creates a grandchild
+	 * and exits before parent execs the process which consumes heredoc
 	 * (that exec happens after we return from this function) */
 	pid = vfork();
 	if (pid < 0)
@@ -2217,24 +2238,20 @@
 		/* grandchild */
 		close(fd); /* read side of the pipe */
 #if BB_MMU
-		full_write(pair.wr, heredoc, len);
+		full_write(pair.wr, heredoc, len); /* may loop or block */
 		_exit(0);
 #else
 		/* Delegate blocking writes to another process */
-# if ENABLE_HUSH_JOB
-		die_sleep = 0; /* do not restore tty pgrp on xfunc death */
-# endif
+		disable_restore_tty_pgrp_on_exit();
 		xmove_fd(pair.wr, STDOUT_FILENO);
 		re_execute_shell(heredoc, 1);
 #endif
 	}
 	/* parent */
-#if ENABLE_HUSH_JOB
-	die_sleep = -1; /* restore tty pgrp on xfunc death */
-#endif
+	enable_restore_tty_pgrp_on_exit();
 	clean_up_after_re_execute();
 	close(pair.wr);
-	wait(NULL); /* wiat till child has died */
+	wait(NULL); /* wait till child has died */
 }
 
 /* squirrel != NULL means we squirrel away copies of stdin, stdout,
@@ -2247,18 +2264,18 @@
 
 	for (redir = prog->redirects; redir; redir = redir->next) {
 		if (redir->rd_type == REDIRECT_HEREDOC2) {
-			if (squirrel && redir->fd < 3) {
-				squirrel[redir->fd] = dup(redir->fd);
+			if (squirrel && redir->rd_fd < 3) {
+				squirrel[redir->rd_fd] = dup(redir->rd_fd);
 			}
 			/* for REDIRECT_HEREDOC2, rd_filename holds _contents_
 			 * of the heredoc */
 			debug_printf_parse("set heredoc '%s'\n",
 					redir->rd_filename);
-			setup_heredoc(redir->fd, redir->rd_filename);
+			setup_heredoc(redir->rd_fd, redir->rd_filename);
 			continue;
 		}
 
-		if (redir->dup == -1) {
+		if (redir->rd_dup == -1) {
 			char *p;
 			if (redir->rd_filename == NULL) {
 				/* Something went wrong in the parse.
@@ -2277,19 +2294,19 @@
 				return 1;
 			}
 		} else {
-			openfd = redir->dup;
+			openfd = redir->rd_dup;
 		}
 
-		if (openfd != redir->fd) {
-			if (squirrel && redir->fd < 3) {
-				squirrel[redir->fd] = dup(redir->fd);
+		if (openfd != redir->rd_fd) {
+			if (squirrel && redir->rd_fd < 3) {
+				squirrel[redir->rd_fd] = dup(redir->rd_fd);
 			}
 			if (openfd == -3) {
 				/* "-" means "close me" and we use -3 for that */
-				close(redir->fd);
+				close(redir->rd_fd);
 			} else {
-				dup2(openfd, redir->fd);
-				if (redir->dup == -1)
+				dup2(openfd, redir->rd_fd);
+				if (redir->rd_dup == -1)
 					close(openfd);
 			}
 		}
@@ -2350,7 +2367,7 @@
 #endif
 		for (r = command->redirects; r; r = rnext) {
 			debug_printf_clean("%s   redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip);
-			if (r->dup == -1) {
+			if (r->rd_dup == -1) {
 				/* guard against the case >$FOO, where foo is unset or blank */
 				if (r->rd_filename) {
 					debug_printf_clean(" %s\n", r->rd_filename);
@@ -2358,7 +2375,7 @@
 					r->rd_filename = NULL;
 				}
 			} else {
-				debug_printf_clean("&%d\n", r->dup);
+				debug_printf_clean("&%d\n", r->rd_dup);
 			}
 			rnext = r->next;
 			free(r);
@@ -2968,7 +2985,7 @@
 		command->pid = BB_MMU ? fork() : vfork();
 		if (!command->pid) { /* child */
 #if ENABLE_HUSH_JOB
-			die_sleep = 0; /* do not restore tty pgrp on xfunc death */
+			disable_restore_tty_pgrp_on_exit();
 
 			/* Every child adds itself to new process group
 			 * with pgid == pid_of_first_child_in_pipe */
@@ -3003,9 +3020,7 @@
 		}
 
 		/* parent or error */
-#if ENABLE_HUSH_JOB
-		die_sleep = -1; /* restore tty pgrp on xfunc death */
-#endif
+		enable_restore_tty_pgrp_on_exit();
 #if !BB_MMU
 		/* Clean up after vforked child */
 		clean_up_after_re_execute();
@@ -3914,15 +3929,11 @@
 		return -1;
 
 	ch = i_getch(input);  /* get the & */
-#if !BB_MMU
-	o_addchr(as_string, ch);
-#endif
+	nommu_addchr(as_string, ch);
 	ch = i_peek(input);
 	if (ch == '-') {
 		ch = i_getch(input);
-#if !BB_MMU
-		o_addchr(as_string, ch);
-#endif
+		nommu_addchr(as_string, ch);
 		return -3;  /* "-" represents "close me" */
 	}
 	d = 0;
@@ -3931,9 +3942,7 @@
 		d = d*10 + (ch-'0');
 		ok = 1;
 		ch = i_getch(input);
-#if !BB_MMU
-		o_addchr(as_string, ch);
-#endif
+		nommu_addchr(as_string, ch);
 		ch = i_peek(input);
 	}
 	if (ok) return d;
@@ -3962,8 +3971,21 @@
 		dup_num = redirect_dup_num(&ctx->as_string, input);
 		if (dup_num == -2)
 			return 1;  /* syntax error */
+	} else {
+		int ch = i_peek(input);
+		dup_num = (ch == '-');
+		if (dup_num) { /* <<-... */
+			ch = i_getch(input);
+			nommu_addchr(&ctx->as_string, ch);
+			ch = i_peek(input);
+		}
+		/* <<[-] word is the same as <<[-]word */
+		while (ch == ' ' || ch == '\t') {
+			ch = i_getch(input);
+			nommu_addchr(&ctx->as_string, ch);
+			ch = i_peek(input);
+		}
 	}
-//TODO: else { check for <<-word }
 
 	if (style == REDIRECT_OVERWRITE && dup_num == -1) {
 		int ch = i_peek(input);
@@ -3973,9 +3995,7 @@
 			 * >| and > are the same for now. Just eat |.
 			 */
 			ch = i_getch(input);
-#if !BB_MMU
-			o_addchr(&ctx->as_string, ch);
-#endif
+			nommu_addchr(&ctx->as_string, ch);
 		}
 	}
 
@@ -3988,16 +4008,16 @@
 	/* redir->next = NULL; */
 	/* redir->rd_filename = NULL; */
 	redir->rd_type = style;
-	redir->fd = (fd == -1) ? redir_table[style].default_fd : fd;
+	redir->rd_fd = (fd == -1) ? redir_table[style].default_fd : fd;
 
-	debug_printf_parse("redirect type %d %s\n", redir->fd, redir_table[style].descrip);
+	debug_printf_parse("redirect type %d %s\n", redir->rd_fd, redir_table[style].descrip);
 
-	redir->dup = dup_num;
-	if (dup_num != -1) {
+	redir->rd_dup = dup_num;
+	if (style != REDIRECT_HEREDOC && dup_num != -1) {
 		/* Erik had a check here that the file descriptor in question
 		 * is legit; I postpone that to "run time"
 		 * A "-" representation of "close me" shows up as a -3 here */
-		debug_printf_parse("duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
+		debug_printf_parse("duplicating redirect '%d>&%d'\n", redir->rd_fd, redir->rd_dup);
 	} else {
 		/* Set ctx->pending_redirect, so we know what to do at the
 		 * end of the next parsed word. */
@@ -4039,28 +4059,45 @@
 	return num;
 }
 
-//TODO: add NOMMU as_string fill
-static char *fetch_till_str(struct in_str *input, const char *word)
+#if BB_MMU
+#define fetch_till_str(as_string, input, word, skip_tabs) \
+	fetch_till_str(input, word, skip_tabs)
+#endif
+static char *fetch_till_str(o_string *as_string,
+		struct in_str *input,
+		const char *word,
+		int skip_tabs)
 {
 	o_string heredoc = NULL_O_STRING;
 	int past_EOL = 0;
 	int ch;
 
+	goto jump_in;
 	while (1) {
 		ch = i_getch(input);
-		if (ch == EOF) {
-			o_free_unsafe(&heredoc);
-			return NULL;
-		}
+		nommu_addchr(as_string, ch);
 		if (ch == '\n') {
 			if (strcmp(heredoc.data + past_EOL, word) == 0) {
 				heredoc.data[past_EOL] = '\0';
 				debug_printf_parse("parsed heredoc '%s'\n", heredoc.data);
 				return heredoc.data;
 			}
-			past_EOL = heredoc.length + 1;
+			do {
+				o_addchr(&heredoc, ch);
+				past_EOL = heredoc.length;
+ jump_in:
+				do {
+					ch = i_getch(input);
+					nommu_addchr(as_string, ch);
+				} while (skip_tabs && ch == '\t');
+			} while (ch == '\n');
 		}
+		if (ch == EOF) {
+			o_free_unsafe(&heredoc);
+			return NULL;
+		}
 		o_addchr(&heredoc, ch);
+		nommu_addchr(as_string, ch);
 	}
 }
 
@@ -4076,25 +4113,27 @@
 				pi->num_cmds,
 				cmd->argv ? cmd->argv[0] : "NONE");
 		for (i = 0; i < pi->num_cmds; i++) {
-			struct redir_struct *redirect = cmd->redirects;
+			struct redir_struct *redir = cmd->redirects;
 
 			debug_printf_parse("fetch_heredocs: %d cmd argv0:'%s'\n",
 					i, cmd->argv ? cmd->argv[0] : "NONE");
-			while (redirect) {
-				if (redirect->rd_type == REDIRECT_HEREDOC) {
+			while (redir) {
+				if (redir->rd_type == REDIRECT_HEREDOC) {
 					char *p;
 
 					if (heredoc_cnt <= 0)
 						return 1; /* error */
-					redirect->rd_type = REDIRECT_HEREDOC2;
-					p = fetch_till_str(input, redirect->rd_filename);
+					redir->rd_type = REDIRECT_HEREDOC2;
+					/* redir->dup is (ab)used to indicate <<- */
+					p = fetch_till_str(&ctx->as_string, input,
+						redir->rd_filename, redir->rd_dup);
 					if (!p)
 						return 1; /* unexpected EOF */
-					free(redirect->rd_filename);
-					redirect->rd_filename = p;
+					free(redir->rd_filename);
+					redir->rd_filename = p;
 					heredoc_cnt--;
 				}
-				redirect = redirect->next;
+				redir = redir->next;
 			}
 			cmd++;
 		}
@@ -4126,9 +4165,7 @@
 		bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork");
 
 	if (pid == 0) { /* child */
-#if ENABLE_HUSH_JOB
-		die_sleep = 0; /* do not restore tty pgrp on xfunc death */
-#endif
+		disable_restore_tty_pgrp_on_exit();
 		/* Process substitution is not considered to be usual
 		 * 'command execution'.
 		 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not.
@@ -4157,9 +4194,7 @@
 	}
 
 	/* parent */
-#if ENABLE_HUSH_JOB
-	die_sleep = -1; /* restore tty pgrp on xfunc death */
-#endif
+	enable_restore_tty_pgrp_on_exit();
 	clean_up_after_re_execute();
 	close(channel[1]);
 	pf = fdopen(channel[0], "r");
@@ -4409,9 +4444,7 @@
 	debug_printf_parse("handle_dollar entered: ch='%c'\n", ch);
 	if (isalpha(ch)) {
 		ch = i_getch(input);
-#if !BB_MMU
-		if (as_string) o_addchr(as_string, ch);
-#endif
+		nommu_addchr(as_string, ch);
  make_var:
 		o_addchr(dest, SPECIAL_VAR_SYMBOL);
 		while (1) {
@@ -4422,17 +4455,13 @@
 			if (!isalnum(ch) && ch != '_')
 				break;
 			ch = i_getch(input);
-#if !BB_MMU
-			if (as_string) o_addchr(as_string, ch);
-#endif
+			nommu_addchr(as_string, ch);
 		}
 		o_addchr(dest, SPECIAL_VAR_SYMBOL);
 	} else if (isdigit(ch)) {
  make_one_char_var:
 		ch = i_getch(input);
-#if !BB_MMU
-		if (as_string) o_addchr(as_string, ch);
-#endif
+		nommu_addchr(as_string, ch);
 		o_addchr(dest, SPECIAL_VAR_SYMBOL);
 		debug_printf_parse(": '%c'\n", ch);
 		o_addchr(dest, ch | quote_mask);
@@ -4450,18 +4479,14 @@
 
 		o_addchr(dest, SPECIAL_VAR_SYMBOL);
 		ch = i_getch(input);
-#if !BB_MMU
-		if (as_string) o_addchr(as_string, ch);
-#endif
+		nommu_addchr(as_string, ch);
 		/* XXX maybe someone will try to escape the '}' */
 		expansion = 0;
 		first_char = true;
 		all_digits = false;
 		while (1) {
 			ch = i_getch(input);
-#if !BB_MMU
-			if (as_string) o_addchr(as_string, ch);
-#endif
+			nommu_addchr(as_string, ch);
 			if (ch == '}')
 				break;
 
@@ -4530,15 +4555,11 @@
 		int pos;
 # endif
 		ch = i_getch(input);
-# if !BB_MMU
-		if (as_string) o_addchr(as_string, ch);
-# endif
+		nommu_addchr(as_string, ch);
 # if ENABLE_SH_MATH_SUPPORT
 		if (i_peek(input) == '(') {
 			ch = i_getch(input);
-#  if !BB_MMU
-			if (as_string) o_addchr(as_string, ch);
-#  endif
+			nommu_addchr(as_string, ch);
 			o_addchr(dest, SPECIAL_VAR_SYMBOL);
 			o_addchr(dest, /*quote_mask |*/ '+');
 #  if !BB_MMU
@@ -4578,9 +4599,7 @@
 #endif
 	case '_':
 		ch = i_getch(input);
-#if !BB_MMU
-		if (as_string) o_addchr(as_string, ch);
-#endif
+		nommu_addchr(as_string, ch);
 		ch = i_peek(input);
 		if (isalnum(ch)) { /* it's $_name or $_123 */
 			ch = '_';
@@ -4611,9 +4630,8 @@
 
  again:
 	ch = i_getch(input);
-#if !BB_MMU
-	if (as_string && ch != EOF) o_addchr(as_string, ch);
-#endif
+	if (ch != EOF)
+		nommu_addchr(as_string, ch);
 	if (ch == dquote_end) { /* may be only '"' or EOF */
 		dest->nonnull = 1;
 		if (dest->o_assignment == NOT_ASSIGNMENT)
@@ -4769,9 +4787,7 @@
 #endif
 			return pi;
 		}
-#if !BB_MMU
-		o_addchr(&ctx.as_string, ch);
-#endif
+		nommu_addchr(&ctx.as_string, ch);
 		is_ifs = strchr(G.ifs, ch);
 		is_special = strchr("<>;&|(){}#'" /* special outside of "str" */
 				"\\$\"" USE_HUSH_TICK("`") /* always special */
@@ -4882,10 +4898,8 @@
 					i_getch(input);
 					/* note: we do not add it to &ctx.as_string */
 				}
-#if !BB_MMU
 //TODO: go back one char?
-				o_addchr(&ctx.as_string, '\n');
-#endif
+				nommu_addchr(&ctx.as_string, '\n');
 			} else {
 				o_addQchr(&dest, ch);
 			}
@@ -4898,9 +4912,7 @@
 			o_addchr(&dest, '\\');
 			ch = i_getch(input);
 			o_addchr(&dest, ch);
-#if !BB_MMU
-			o_addchr(&ctx.as_string, ch);
-#endif
+			nommu_addchr(&ctx.as_string, ch);
 			break;
 		case '$':
 			if (handle_dollar(&ctx.as_string, &dest, input) != 0) {
@@ -4917,9 +4929,7 @@
 					syntax("unterminated '");
 					goto parse_error;
 				}
-#if !BB_MMU
-				o_addchr(&ctx.as_string, ch);
-#endif
+				nommu_addchr(&ctx.as_string, ch);
 				if (ch == '\'')
 					break;
 				if (dest.o_assignment == NOT_ASSIGNMENT)
@@ -4954,9 +4964,7 @@
 			if (next == '>') {
 				redir_style = REDIRECT_APPEND;
 				ch = i_getch(input);
-#if !BB_MMU
-				o_addchr(&ctx.as_string, ch);
-#endif
+				nommu_addchr(&ctx.as_string, ch);
 			}
 #if 0
 			else if (next == '(') {
@@ -4978,15 +4986,11 @@
 				heredoc_cnt++;
 				debug_printf_parse("++heredoc_cnt=%d\n", heredoc_cnt);
 				ch = i_getch(input);
-#if !BB_MMU
-				o_addchr(&ctx.as_string, ch);
-#endif
+				nommu_addchr(&ctx.as_string, ch);
 			} else if (next == '>') {
 				redir_style = REDIRECT_IO;
 				ch = i_getch(input);
-#if !BB_MMU
-				o_addchr(&ctx.as_string, ch);
-#endif
+				nommu_addchr(&ctx.as_string, ch);
 			}
 #if 0
 			else if (next == '(') {
@@ -5013,9 +5017,7 @@
 				if (ch != ';')
 					break;
 				ch = i_getch(input);
-#if !BB_MMU
-				o_addchr(&ctx.as_string, ch);
-#endif
+				nommu_addchr(&ctx.as_string, ch);
 				if (ctx.ctx_res_w == RES_CASEI) {
 					ctx.ctx_dsemicolon = 1;
 					ctx.ctx_res_w = RES_MATCH;
@@ -5034,9 +5036,7 @@
 			}
 			if (next == '&') {
 				ch = i_getch(input);
-#if !BB_MMU
-				o_addchr(&ctx.as_string, ch);
-#endif
+				nommu_addchr(&ctx.as_string, ch);
 				done_pipe(&ctx, PIPE_AND);
 			} else {
 				done_pipe(&ctx, PIPE_BG);
@@ -5052,9 +5052,7 @@
 #endif
 			if (next == '|') { /* || */
 				ch = i_getch(input);
-#if !BB_MMU
-				o_addchr(&ctx.as_string, ch);
-#endif
+				nommu_addchr(&ctx.as_string, ch);
 				done_pipe(&ctx, PIPE_OR);
 			} else {
 				/* we could pick up a file descriptor choice here
@@ -5537,7 +5535,7 @@
 		tcsetpgrp(G_interactive_fd, getpid());
 		/* -1 is special - makes xfuncs longjmp, not exit
 		 * (we reset die_sleep = 0 whereever we [v]fork) */
-		die_sleep = -1;
+		enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
 		if (setjmp(die_jmp)) {
 			/* xfunc has failed! die die die */
 			hush_exit(xfunc_error_retval);



More information about the busybox-cvs mailing list