ash: optimize tryexec(): avoid one allocation
There was a bug in tryexec which bbox had fixed in 2003.
dash had a smaller fix in 2007. Copy it. It is smaller,
although it is also more quirky (requires argv[-1] to exist).
Upstream commit 1:
    Date: Mon, 15 Oct 2007 20:24:28 +0800
    [EXEC] Fixed execing of scripts with no hash-bang
    The function tryexec used the original name instead of the path found through
    PATH search.  This patch fixes that.
    Test case:
        trap 'rm -f $TMP' EXIT
        TMP=$(tempfile -s nosuchthing)
        cat <<- EOF > $TMP
                echo OK
        EOF
        chmod u+x $TMP
        cd /
        PATH=${TMP%/*} ${TMP##*/}
    Old result:
        /bin/sh: Can't open filelgY4Fanosuchthing
    New result:
        OK
Upstream commit 2:
    Date: Sun, 23 Dec 2007 11:02:26 +0800
    [EVAL] Fix bad pointer arithmetic in evalcommand
    dash dies on sparc with a SIGBUS due to an arithmetic error introduced
    with commit 03b4958, this patch fixes it.
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
function                                             old     new   delta
evalcommand                                         1261    1264      +3
dotcmd                                               321     319      -2
tryexec                                              115      64     -51
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/2 up/down: 3/-53)             Total: -50 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
			
			
This commit is contained in:
		
							
								
								
									
										31
									
								
								shell/ash.c
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								shell/ash.c
									
									
									
									
									
								
							| @@ -7467,13 +7467,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** | ||||
| #else | ||||
| 	execve(cmd, argv, envp); | ||||
| #endif | ||||
| 	if (cmd == (char*) bb_busybox_exec_path) { | ||||
| 		/* We already visited ENOEXEC branch below, don't do it again */ | ||||
| //TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up? | ||||
| 		free(argv); | ||||
| 		return; | ||||
| 	} | ||||
| 	if (errno == ENOEXEC) { | ||||
| 	if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) { | ||||
| 		/* Run "cmd" as a shell script: | ||||
| 		 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html | ||||
| 		 * "If the execve() function fails with ENOEXEC, the shell | ||||
| @@ -7490,19 +7484,13 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** | ||||
| 		 * message and exit code 126. For one, this prevents attempts | ||||
| 		 * to interpret foreign ELF binaries as shell scripts. | ||||
| 		 */ | ||||
| 		char **ap; | ||||
| 		char **new; | ||||
|  | ||||
| 		for (ap = argv; *ap; ap++) | ||||
| 			continue; | ||||
| 		new = ckmalloc((ap - argv + 2) * sizeof(new[0])); | ||||
| 		new[0] = (char*) "ash"; | ||||
| 		new[1] = cmd; | ||||
| 		ap = new + 2; | ||||
| 		while ((*ap++ = *++argv) != NULL) | ||||
| 			continue; | ||||
| 		argv[0] = cmd; | ||||
| 		cmd = (char*) bb_busybox_exec_path; | ||||
| 		argv = new; | ||||
| 		/* NB: this is only possible because all callers of shellexec() | ||||
| 		 * ensure that the argv[-1] slot exists! | ||||
| 		 */ | ||||
| 		argv--; | ||||
| 		argv[0] = (char*) "ash"; | ||||
| 		goto repeat; | ||||
| 	} | ||||
| } | ||||
| @@ -7510,6 +7498,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** | ||||
| /* | ||||
|  * Exec a program.  Never returns.  If you change this routine, you may | ||||
|  * have to change the find_command routine as well. | ||||
|  * argv[-1] must exist and be writable! See tryexec() for why. | ||||
|  */ | ||||
| static void shellexec(char **, const char *, int) NORETURN; | ||||
| static void | ||||
| @@ -9415,7 +9404,9 @@ evalcommand(union node *cmd, int flags) | ||||
| 			argc++; | ||||
| 	} | ||||
|  | ||||
| 	argv = nargv = stalloc(sizeof(char *) * (argc + 1)); | ||||
| 	/* Reserve one extra spot at the front for shellexec. */ | ||||
| 	nargv = stalloc(sizeof(char *) * (argc + 2)); | ||||
| 	argv = ++nargv; | ||||
| 	for (sp = arglist.list; sp; sp = sp->next) { | ||||
| 		TRACE(("evalcommand arg: %s\n", sp->text)); | ||||
| 		*nargv++ = sp->text; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user