busybox (1:1.17.1-8) applets-fallback.patch

Summary

 Config.in          |    7 +-----
 coreutils/chroot.c |    4 ++-
 include/libbb.h    |    9 ++++----
 libbb/execable.c   |   55 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 libbb/messages.c   |    9 ++++++++
 shell/ash.c        |   27 +++++---------------------
 6 files changed, 78 insertions(+), 33 deletions(-)

    
download this patch

Patch contents

--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7241,25 +7241,10 @@
 
 
 static void
-tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
+tryexec(IF_FEATURE_SH_STANDALONE(int applet_no UNUSED_PARAM,) char *cmd, char **argv, char **envp)
 {
 	int repeated = 0;
 
-#if ENABLE_FEATURE_SH_STANDALONE
-	if (applet_no >= 0) {
-		if (APPLET_IS_NOEXEC(applet_no)) {
-			clearenv();
-			while (*envp)
-				putenv(*envp++);
-			run_applet_no_and_exit(applet_no, argv);
-		}
-		/* re-exec ourselves with the new arguments */
-		execve(bb_busybox_exec_path, argv, envp);
-		/* If they called chroot or otherwise made the binary no longer
-		 * executable, fall through */
-	}
-#endif
-
  repeat:
 #ifdef SYSV
 	do {
@@ -7309,14 +7294,14 @@
 
 	clearredir(/*drop:*/ 1);
 	envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
-	if (strchr(argv[0], '/') != NULL
-#if ENABLE_FEATURE_SH_STANDALONE
-	 || (applet_no = find_applet_by_name(argv[0])) >= 0
-#endif
-	) {
+	if (strchr(argv[0], '/') != NULL) {
 		tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
 		e = errno;
 	} else {
+#if ENABLE_FEATURE_SH_STANDALONE
+		bb_execv_applet(argv[0], argv, envp);
+#endif
+
 		e = ENOENT;
 		while ((cmdname = path_advance(&path, argv[0])) != NULL) {
 			if (--idx < 0 && pathopt == NULL) {
--- a/libbb/execable.c
+++ b/libbb/execable.c
@@ -9,6 +9,9 @@
 
 #include "libbb.h"
 
+#include <alloca.h>
+#include <stdarg.h>
+
 /* check if path points to an executable file;
  * return 1 if found;
  * return 0 otherwise;
@@ -68,12 +71,60 @@
 }
 
 #if ENABLE_FEATURE_PREFER_APPLETS
+int FAST_FUNC bb_execv_applet(const char *name, char *const argv[], char *const envp[])
+{
+	const char **path = bb_busybox_exec_paths;
+
+	errno = ENOENT;
+
+	if (find_applet_by_name(name) < 0)
+		return -1;
+
+	for (; *path; ++path)
+		execve(*path, argv, envp);
+
+	return -1;
+}
+
 /* just like the real execvp, but try to launch an applet named 'file' first
  */
 int FAST_FUNC bb_execvp(const char *file, char *const argv[])
 {
-	return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file,
-					argv);
+	int ret = bb_execv_applet(file, argv, environ);
+	if (errno != ENOENT)
+		return ret;
+
+	return execvp(file, argv);
+}
+
+int FAST_FUNC bb_execlp(const char *file, const char *arg, ...)
+{
+#define INITIAL_ARGV_MAX 16
+	size_t argv_max = INITIAL_ARGV_MAX;
+	const char **argv = malloc(argv_max * sizeof (const char *));
+	va_list args;
+	unsigned int i = 0;
+	int ret;
+
+	va_start (args, arg);
+	while (argv[i++] != NULL) {
+		if (i == argv_max) {
+			const char **nptr;
+			argv_max *= 2;
+			nptr = realloc (argv, argv_max * sizeof (const char *));
+			if (nptr == NULL)
+				return -1;
+			argv = nptr;
+		}
+
+		argv[i] = va_arg (args, const char *);
+	}
+	va_end (args);
+
+	ret = bb_execvp(file, (char *const *)argv);
+	free(argv);
+
+	return ret;
 }
 #endif
 
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -45,6 +45,15 @@
 const char bb_path_motd_file[] ALIGN1 = "/etc/motd";
 const char bb_dev_null[] ALIGN1 = "/dev/null";
 const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
+const char *bb_busybox_exec_paths[] ALIGN1 = {
+#ifdef __linux__
+	"/proc/self/exe",
+#endif
+#ifdef CONFIG_BUSYBOX_EXEC_PATH
+	CONFIG_BUSYBOX_EXEC_PATH,
+#endif
+	NULL
+};
 const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
 /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
  * but I want to save a few bytes here. Check libbb.h before changing! */
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -830,11 +830,11 @@
  * but it may exec busybox and call applet instead of searching PATH.
  */
 #if ENABLE_FEATURE_PREFER_APPLETS
+int bb_execv_applet(const char *name, char *const argv[], char *const envp[]) FAST_FUNC;
 int bb_execvp(const char *file, char *const argv[]) FAST_FUNC;
-#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd)
-#define BB_EXECLP(prog,cmd,...) \
-	execlp((find_applet_by_name(prog) >= 0) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \
-		cmd, __VA_ARGS__)
+int bb_execlp(const char *file, const char *arg, ...) FAST_FUNC;
+#define BB_EXECVP(prog,cmd)     bb_execvp(prog,cmd)
+#define BB_EXECLP(prog,cmd,...) bb_execlp(prog,cmd, __VA_ARGS__)
 #else
 #define BB_EXECVP(prog,cmd)     execvp(prog,cmd)
 #define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__)
@@ -1575,6 +1575,7 @@
 extern const char bb_path_wtmp_file[];
 extern const char bb_dev_null[];
 extern const char bb_busybox_exec_path[];
+extern const char *bb_busybox_exec_paths[];
 /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
  * but I want to save a few bytes here */
 extern const char bb_PATH_root_path[]; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */
--- a/Config.in
+++ b/Config.in
@@ -386,13 +386,10 @@
 
 config BUSYBOX_EXEC_PATH
 	string "Path to BusyBox executable"
-	default "/proc/self/exe"
+	default "/bin/busybox"
 	help
 	  When Busybox applets need to run other busybox applets, BusyBox
-	  sometimes needs to exec() itself. When the /proc filesystem is
-	  mounted, /proc/self/exe always points to the currently running
-	  executable. If you haven't got /proc, set this to wherever you
-	  want to run BusyBox from.
+	  sometimes needs to exec() itself.
 
 # These are auto-selected by other options
 
--- a/coreutils/chroot.c
+++ b/coreutils/chroot.c
@@ -30,5 +30,7 @@
 		argv[1] = (char *) "-i";
 	}
 
-	BB_EXECVP_or_die(argv);
+	execvp(argv[0], argv);
+	xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
+	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
 }