ash: fix nofork bug where environment is not properly passed to a command
function old new delta listvars 144 252 +108 evalcommand 1500 1546 +46 showvars 142 147 +5 shellexec 242 245 +3 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/0 up/down: 162/0) Total: 162 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		
							
								
								
									
										45
									
								
								shell/ash.c
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								shell/ash.c
									
									
									
									
									
								
							| @@ -2380,8 +2380,11 @@ listsetvar(struct strlist *list_set_var, int flags) | ||||
| /* | ||||
|  * Generate a list of variables satisfying the given conditions. | ||||
|  */ | ||||
| #if !ENABLE_FEATURE_SH_NOFORK | ||||
| # define listvars(on, off, lp, end) listvars(on, off, end) | ||||
| #endif | ||||
| static char ** | ||||
| listvars(int on, int off, char ***end) | ||||
| listvars(int on, int off, struct strlist *lp, char ***end) | ||||
| { | ||||
| 	struct var **vpp; | ||||
| 	struct var *vp; | ||||
| @@ -2394,12 +2397,40 @@ listvars(int on, int off, char ***end) | ||||
| 	do { | ||||
| 		for (vp = *vpp; vp; vp = vp->next) { | ||||
| 			if ((vp->flags & mask) == on) { | ||||
| #if ENABLE_FEATURE_SH_NOFORK | ||||
| 				/* If variable with the same name is both | ||||
| 				 * exported and temporarily set for a command: | ||||
| 				 *  export ZVAR=5 | ||||
| 				 *  ZVAR=6 printenv | ||||
| 				 * then "ZVAR=6" will be both in vartab and | ||||
| 				 * lp lists. Do not pass it twice to printenv. | ||||
| 				 */ | ||||
| 				struct strlist *lp1 = lp; | ||||
| 				while (lp1) { | ||||
| 					if (strcmp(lp1->text, vp->var_text) == 0) | ||||
| 						goto skip; | ||||
| 					lp1 = lp1->next; | ||||
| 				} | ||||
| #endif | ||||
| 				if (ep == stackstrend()) | ||||
| 					ep = growstackstr(); | ||||
| 				*ep++ = (char*)vp->var_text; | ||||
| #if ENABLE_FEATURE_SH_NOFORK | ||||
|  skip: ; | ||||
| #endif | ||||
| 			} | ||||
| 		} | ||||
| 	} while (++vpp < vartab + VTABSIZE); | ||||
|  | ||||
| #if ENABLE_FEATURE_SH_NOFORK | ||||
| 	while (lp) { | ||||
| 		if (ep == stackstrend()) | ||||
| 			ep = growstackstr(); | ||||
| 		*ep++ = lp->text; | ||||
| 		lp = lp->next; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	if (ep == stackstrend()) | ||||
| 		ep = growstackstr(); | ||||
| 	if (end) | ||||
| @@ -7860,7 +7891,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | ||||
| 	int exerrno; | ||||
| 	int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ | ||||
|  | ||||
| 	envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); | ||||
| 	envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); | ||||
| 	if (strchr(prog, '/') != NULL | ||||
| #if ENABLE_FEATURE_SH_STANDALONE | ||||
| 	 || (applet_no = find_applet_by_name(prog)) >= 0 | ||||
| @@ -9930,7 +9961,11 @@ evalcommand(union node *cmd, int flags) | ||||
| 		/* find_command() encodes applet_no as (-2 - applet_no) */ | ||||
| 		int applet_no = (- cmdentry.u.index - 2); | ||||
| 		if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { | ||||
| 			listsetvar(varlist.list, VEXPORT|VSTACK); | ||||
| 			char **sv_environ; | ||||
|  | ||||
| 			INT_OFF; | ||||
| 			sv_environ = environ; | ||||
| 			environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL); | ||||
| 			/* | ||||
| 			 * Run <applet>_main(). | ||||
| 			 * Signals (^C) can't interrupt here. | ||||
| @@ -9939,8 +9974,8 @@ evalcommand(union node *cmd, int flags) | ||||
| 			 * and/or wait for user input ineligible for NOFORK: | ||||
| 			 * for example, "yes" or "rm" (rm -i waits for input). | ||||
| 			 */ | ||||
| 			INT_OFF; | ||||
| 			status = run_nofork_applet(applet_no, argv); | ||||
| 			environ = sv_environ; | ||||
| 			/* | ||||
| 			 * Try enabling NOFORK for "yes" applet. | ||||
| 			 * ^C _will_ stop it (write returns EINTR), | ||||
| @@ -10854,7 +10889,7 @@ showvars(const char *sep_prefix, int on, int off) | ||||
| 	const char *sep; | ||||
| 	char **ep, **epend; | ||||
|  | ||||
| 	ep = listvars(on, off, &epend); | ||||
| 	ep = listvars(on, off, /*strlist:*/ NULL, &epend); | ||||
| 	qsort(ep, epend - ep, sizeof(char *), vpcmp); | ||||
|  | ||||
| 	sep = *sep_prefix ? " " : sep_prefix; | ||||
|   | ||||
							
								
								
									
										9
									
								
								shell/ash_test/ash-standalone/nofork_env.right
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								shell/ash_test/ash-standalone/nofork_env.right
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| ZVAR=1 | ||||
| ZVAR=2 | ||||
| ZVAR=3 | ||||
| ZVAR=4 | ||||
| ZVAR=5 | ||||
| ZVAR=6 | ||||
| ZVAR=7 | ||||
| ZVAR=8 | ||||
| Ok:0 | ||||
							
								
								
									
										15
									
								
								shell/ash_test/ash-standalone/nofork_env.tests
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								shell/ash_test/ash-standalone/nofork_env.tests
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # ash had a bug where NOFORKed applet (env/printenv) was not seeing new exported variables | ||||
|  | ||||
| (export ZVAR=1; printenv) | grep ^ZVAR= | ||||
| (ZVAR=2 printenv) | grep ^ZVAR= | ||||
|  | ||||
| (export ZVAR=3; env) | grep ^ZVAR= | ||||
| (ZVAR=4 env) | grep ^ZVAR= | ||||
|  | ||||
| export ZVAR=5; printenv | grep ^ZVAR= | ||||
| ZVAR=6 printenv | grep ^ZVAR= | ||||
|  | ||||
| export ZVAR=7; env | grep ^ZVAR= | ||||
| ZVAR=8 env | grep ^ZVAR= | ||||
|  | ||||
| echo Ok:$? | ||||
							
								
								
									
										9
									
								
								shell/hush_test/hush-standalone/nofork_env.right
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								shell/hush_test/hush-standalone/nofork_env.right
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| ZVAR=1 | ||||
| ZVAR=2 | ||||
| ZVAR=3 | ||||
| ZVAR=4 | ||||
| ZVAR=5 | ||||
| ZVAR=6 | ||||
| ZVAR=7 | ||||
| ZVAR=8 | ||||
| Ok:0 | ||||
							
								
								
									
										15
									
								
								shell/hush_test/hush-standalone/nofork_env.tests
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								shell/hush_test/hush-standalone/nofork_env.tests
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # ash had a bug where NOFORKed applet (env/printenv) was not seeing new exported variables | ||||
|  | ||||
| (export ZVAR=1; printenv) | grep ^ZVAR= | ||||
| (ZVAR=2 printenv) | grep ^ZVAR= | ||||
|  | ||||
| (export ZVAR=3; env) | grep ^ZVAR= | ||||
| (ZVAR=4 env) | grep ^ZVAR= | ||||
|  | ||||
| export ZVAR=5; printenv | grep ^ZVAR= | ||||
| ZVAR=6 printenv | grep ^ZVAR= | ||||
|  | ||||
| export ZVAR=7; env | grep ^ZVAR= | ||||
| ZVAR=8 env | grep ^ZVAR= | ||||
|  | ||||
| echo Ok:$? | ||||
		Reference in New Issue
	
	Block a user