[PATCH] ash: special treatment for 'busybox' in standalone shell mode

Ron Yorston rmy at pobox.com
Wed Jul 26 09:31:24 UTC 2017


In standalone shell mode applets can be run from the shell without
having to install symlinks to them.  You don't even need to set PATH.
Tab-completion also works.  This makes minimal deployments of BusyBox
very easy to set up.  For example, a container can be created with just
the BusyBox binary installed as /bin/sh.

There's one exception:  since 'busybox' isn't an applet it won't run
in standalone shell mode without being installed on the path.

This patch adds special treatment for 'busybox' in standalone shell
mode so tab-completion and execution from the shell both work.

function                                             old     new   delta
tryexec                                                -     175    +175
add_partial_match                                      -      35     +35
find_command                                         952     978     +26
complete_cmd_dir_file                                891     882      -9
shellexec                                            498     316    -182
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 1/2 up/down: 236/-191)           Total: 45 bytes

These extra bytes are only required if standalone shell mode is enabled,
which it isn't in the default configuration.

Signed-off-by: Ron Yorston <rmy at pobox.com>
---
 libbb/lineedit.c | 12 ++++++++++--
 shell/ash.c      | 15 +++++++++++----
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 2a5d4e704..c0e36d8b4 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -638,6 +638,14 @@ static void add_match(char *matched)
 	num_matches++;
 }
 
+#if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1
+static void add_partial_match(const char *part, const char *full, int plen)
+{
+	if (strncmp(part, full, plen) == 0)
+		add_match(xstrdup(full));
+	}
+#endif
+
 # if ENABLE_FEATURE_USERNAME_COMPLETION
 /* Replace "~user/..." with "/homedir/...".
  * The parameter is malloced, free it or return it
@@ -781,11 +789,11 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
 		const char *p = applet_names;
 
 		while (*p) {
-			if (strncmp(pfind, p, pf_len) == 0)
-				add_match(xstrdup(p));
+			add_partial_match(pfind, p, pf_len);
 			while (*p++ != '\0')
 				continue;
 		}
+		add_partial_match(pfind, "busybox", pf_len);
 	}
 #endif
 
diff --git a/shell/ash.c b/shell/ash.c
index c96ec939e..199040c16 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7690,7 +7690,8 @@ static int builtinloc = -1;     /* index in path of %builtin, or -1 */
 
 
 static void
-tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
+tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd,
+		char **argv, char **envp)
 {
 #if ENABLE_FEATURE_SH_STANDALONE
 	if (applet_no >= 0) {
@@ -7715,7 +7716,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 && errno == ENOEXEC) {
+	if (cmd != 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
@@ -7732,7 +7733,7 @@ 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.
 		 */
-		argv[0] = cmd;
+		argv[0] = (char*) cmd;
 		cmd = (char*) bb_busybox_exec_path;
 		/* NB: this is only possible because all callers of shellexec()
 		 * ensure that the argv[-1] slot exists!
@@ -7772,6 +7773,11 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
 			goto try_PATH;
 		}
 		e = errno;
+#if ENABLE_FEATURE_SH_STANDALONE
+	} else if (is_prefixed_with(argv[0], "busybox")) {
+		tryexec(-1, bb_busybox_exec_path, argv, envp);
+		e = errno;
+#endif
 	} else {
  try_PATH:
 		e = ENOENT;
@@ -12839,7 +12845,8 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
 #if ENABLE_FEATURE_SH_STANDALONE
 	{
 		int applet_no = find_applet_by_name(name);
-		if (applet_no >= 0) {
+		/* applet_no is -1 on no match so u.index is -1 for busybox */
+		if (applet_no >= 0 || is_prefixed_with(name, "busybox")) {
 			entry->cmdtype = CMDNORMAL;
 			entry->u.index = -2 - applet_no;
 			return;
-- 
2.13.3




More information about the busybox mailing list