ash: better fix for ash -c 'echo 5&' and ash -c 'sleep 5&'
with testcase
This commit is contained in:
		
							
								
								
									
										75
									
								
								shell/ash.c
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								shell/ash.c
									
									
									
									
									
								
							| @@ -9079,8 +9079,6 @@ breakcmd(int argc UNUSED_PARAM, char **argv) | ||||
|  * This implements the input routines used by the parser. | ||||
|  */ | ||||
|  | ||||
| #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */ | ||||
|  | ||||
| enum { | ||||
| 	INPUT_PUSH_FILE = 1, | ||||
| 	INPUT_NOFILE_OK = 2, | ||||
| @@ -9121,7 +9119,6 @@ popstring(void) | ||||
| #endif | ||||
| 	parsenextc = sp->prevstring; | ||||
| 	parsenleft = sp->prevnleft; | ||||
| /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ | ||||
| 	g_parsefile->strpush = sp->prev; | ||||
| 	if (sp != &(g_parsefile->basestrpush)) | ||||
| 		free(sp); | ||||
| @@ -9137,7 +9134,7 @@ preadfd(void) | ||||
|  | ||||
| #if ENABLE_FEATURE_EDITING | ||||
|  retry: | ||||
| 	if (!iflag || g_parsefile->fd) | ||||
| 	if (!iflag || g_parsefile->fd != STDIN_FILENO) | ||||
| 		nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1); | ||||
| 	else { | ||||
| #if ENABLE_FEATURE_TAB_COMPLETION | ||||
| @@ -9185,56 +9182,76 @@ preadfd(void) | ||||
|  * Refill the input buffer and return the next input character: | ||||
|  * | ||||
|  * 1) If a string was pushed back on the input, pop it; | ||||
|  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading | ||||
|  * 2) If an EOF was pushed back (parsenleft < -BIGNUM) or we are reading | ||||
|  *    from a string so we can't refill the buffer, return EOF. | ||||
|  * 3) If the is more stuff in this buffer, use it else call read to fill it. | ||||
|  * 4) Process input up to the next newline, deleting nul characters. | ||||
|  */ | ||||
| //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) | ||||
| #define pgetc_debug(...) ((void)0) | ||||
| static int | ||||
| preadbuffer(void) | ||||
| { | ||||
| 	char *q; | ||||
| 	int more; | ||||
| 	char savec; | ||||
|  | ||||
| 	while (g_parsefile->strpush) { | ||||
| #if ENABLE_ASH_ALIAS | ||||
| 		if (parsenleft == -1 && g_parsefile->strpush->ap | ||||
| 		 && parsenextc[-1] != ' ' && parsenextc[-1] != '\t' | ||||
| 		) { | ||||
| 			pgetc_debug("preadbuffer PEOA"); | ||||
| 			return PEOA; | ||||
| 		} | ||||
| #endif | ||||
| 		popstring(); | ||||
| 		/* try "pgetc" now: */ | ||||
| 		pgetc_debug("internal pgetc at %d:%p'%s'", parsenleft, parsenextc, parsenextc); | ||||
| 		if (--parsenleft >= 0) | ||||
| 			return signed_char2int(*parsenextc++); | ||||
| 	} | ||||
| 	if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL) | ||||
| 	/* on both branches above parsenleft < 0. | ||||
| 	 * "pgetc" needs refilling. | ||||
| 	 */ | ||||
|  | ||||
| 	/* -90 is -BIGNUM. Below we use -99 to mark "EOF on read", | ||||
| 	 * pungetc() may decrement it a few times. -90 is enough. | ||||
| 	 */ | ||||
| 	if (parsenleft < -90 || g_parsefile->buf == NULL) { | ||||
| 		pgetc_debug("preadbuffer PEOF1"); | ||||
| 		/* even in failure keep them in lock step, | ||||
| 		 * for correct pungetc. */ | ||||
| 		parsenextc++; | ||||
| 		return PEOF; | ||||
| 	flush_stdout_stderr(); | ||||
| 	} | ||||
|  | ||||
| 	more = parselleft; | ||||
| 	if (more <= 0) { | ||||
| 		flush_stdout_stderr(); | ||||
|  again: | ||||
| 		more = preadfd(); | ||||
| 		if (more <= 0) { | ||||
| 			parselleft = parsenleft = EOF_NLEFT; | ||||
| 			parselleft = parsenleft = -99; | ||||
| 			pgetc_debug("preadbuffer PEOF2"); | ||||
| 			parsenextc++; | ||||
| 			return PEOF; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* Find out where's the end of line. | ||||
| 	 * Set parsenleft/parselleft acordingly. | ||||
| 	 * NUL chars are deleted. | ||||
| 	 */ | ||||
| 	q = parsenextc; | ||||
|  | ||||
| 	/* delete nul characters */ | ||||
| 	for (;;) { | ||||
| 		int c; | ||||
| 		char c; | ||||
|  | ||||
| 		more--; | ||||
| 		c = *q; | ||||
|  | ||||
| 		if (!c) | ||||
| 		c = *q; | ||||
| 		if (c == '\0') { | ||||
| 			memmove(q, q + 1, more); | ||||
| 		else { | ||||
| 		} else { | ||||
| 			q++; | ||||
| 			if (c == '\n') { | ||||
| 				parsenleft = q - parsenextc - 1; | ||||
| @@ -9251,22 +9268,23 @@ preadbuffer(void) | ||||
| 	} | ||||
| 	parselleft = more; | ||||
|  | ||||
| 	savec = *q; | ||||
| 	*q = '\0'; | ||||
|  | ||||
| 	if (vflag) { | ||||
| 		char save = *q; | ||||
| 		*q = '\0'; | ||||
| 		out2str(parsenextc); | ||||
| 		*q = save; | ||||
| 	} | ||||
|  | ||||
| 	*q = savec; | ||||
|  | ||||
| 	pgetc_debug("preadbuffer at %d:%p'%s'", parsenleft, parsenextc, parsenextc); | ||||
| 	return signed_char2int(*parsenextc++); | ||||
| } | ||||
|  | ||||
| #define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer()) | ||||
|  | ||||
| static int | ||||
| pgetc(void) | ||||
| { | ||||
| 	pgetc_debug("pgetc at %d:%p'%s'", parsenleft, parsenextc, parsenextc); | ||||
| 	return pgetc_as_macro(); | ||||
| } | ||||
|  | ||||
| @@ -9325,11 +9343,9 @@ pfgets(char *line, int len) | ||||
| static void | ||||
| pungetc(void) | ||||
| { | ||||
| 	/* check is needed for ash -c 'echo 5&' + BASH_COMPAT to work */ | ||||
| 	if (parsenleft < 0) | ||||
| 		return; | ||||
| 	parsenleft++; | ||||
| 	parsenextc--; | ||||
| 	pgetc_debug("pushed back to %d:%p'%s'", parsenleft, parsenextc, parsenextc); | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -9343,16 +9359,17 @@ static void | ||||
| pushstring(char *s, struct alias *ap) | ||||
| { | ||||
| 	struct strpush *sp; | ||||
| 	size_t len; | ||||
| 	int len; | ||||
|  | ||||
| 	len = strlen(s); | ||||
| 	INT_OFF; | ||||
| 	if (g_parsefile->strpush) { | ||||
| 		sp = ckzalloc(sizeof(struct strpush)); | ||||
| 		sp = ckzalloc(sizeof(*sp)); | ||||
| 		sp->prev = g_parsefile->strpush; | ||||
| 		g_parsefile->strpush = sp; | ||||
| 	} else | ||||
| 		sp = g_parsefile->strpush = &(g_parsefile->basestrpush); | ||||
| 	} else { | ||||
| 		sp = &(g_parsefile->basestrpush); | ||||
| 	} | ||||
| 	g_parsefile->strpush = sp; | ||||
| 	sp->prevstring = parsenextc; | ||||
| 	sp->prevnleft = parsenleft; | ||||
| #if ENABLE_ASH_ALIAS | ||||
| @@ -9442,7 +9459,7 @@ setinputfd(int fd, int push) | ||||
| 	close_on_exec_on(fd); | ||||
| 	if (push) { | ||||
| 		pushfile(); | ||||
| 		g_parsefile->buf = 0; | ||||
| 		g_parsefile->buf = NULL; | ||||
| 	} | ||||
| 	g_parsefile->fd = fd; | ||||
| 	if (g_parsefile->buf == NULL) | ||||
|   | ||||
							
								
								
									
										2
									
								
								shell/ash_test/ash-misc/last_amp.right
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								shell/ash_test/ash-misc/last_amp.right
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| 3 | ||||
| End | ||||
							
								
								
									
										8
									
								
								shell/ash_test/ash-misc/last_amp.tests
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										8
									
								
								shell/ash_test/ash-misc/last_amp.tests
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| $THIS_SH -c 'echo 3&' | ||||
| d=`date` | ||||
| while test "`date`" = "$d"; do true; done | ||||
| d1=`date` | ||||
| $THIS_SH -c 'sleep 1&' | ||||
| d2=`date` | ||||
| test "$d1" = "$d2" || echo BAD | ||||
| echo End | ||||
		Reference in New Issue
	
	Block a user