[PATCH v3] Make busybox an applet

Ron Yorston rmy at pobox.com
Mon Jun 6 11:51:41 UTC 2016


Make busybox an optional applet.

function                                             old     new   delta
busybox_main                                           -     637    +637
applet_names                                        2536    2544      +8
applet_main                                         1468    1472      +4
run_applet_no_and_exit                               451     448      -3
packed_usage                                       30741   30736      -5
run_applet_and_exit                                  675      48    -627
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 2/3 up/down: 649/-635)           Total: 14 bytes

v2:
  Treat applet name prefixed with "busybox" the same as "busybox"
v3:
  Don't treat "busybox" as a special case for --install or --list-full
  Tweak code to squeeze out a few more bytes

Signed-off-by: Ron Yorston <rmy at pobox.com>
---
 Config.in               |   9 --
 applets/applet_tables.c |  18 ++--
 include/busybox.h       |   4 -
 libbb/appletlib.c       | 224 +++++-------------------------------------------
 libbb/busybox.c         | 210 +++++++++++++++++++++++++++++++++++++++++++++
 scripts/trylink         |  20 -----
 6 files changed, 241 insertions(+), 244 deletions(-)
 create mode 100644 libbb/busybox.c

diff --git a/Config.in b/Config.in
index 3d18709..eff733a 100644
--- a/Config.in
+++ b/Config.in
@@ -589,15 +589,6 @@ config FEATURE_INDIVIDUAL
 
 	  You need to have a working dynamic linker.
 
-config FEATURE_SHARED_BUSYBOX
-	bool "Produce additional busybox binary linked against libbusybox"
-	default y
-	depends on BUILD_LIBBUSYBOX
-	help
-	  Build busybox, dynamically linked against libbusybox.so.N.N.N.
-
-	  You need to have a working dynamic linker.
-
 ### config BUILD_AT_ONCE
 ###	bool "Compile all sources at once"
 ###	default n
diff --git a/applets/applet_tables.c b/applets/applet_tables.c
index 843f2ec..a2917cd 100644
--- a/applets/applet_tables.c
+++ b/applets/applet_tables.c
@@ -98,8 +98,15 @@ int main(int argc, char **argv)
 		printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name);
 		printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].main);
 	}
-
 	printf("#define KNOWN_APPNAME_OFFSETS %u\n\n", KNOWN_APPNAME_OFFSETS);
+
+	for (i = 0; i < NUM_APPLETS; i++) {
+		if (str_isalnum_(applets[i].name))
+			printf("#define APPLET_NO_%s %d\n", applets[i].name, i);
+	}
+	printf("\n\n");
+
+	printf("#ifndef SKIP_definitions\n");
 	if (KNOWN_APPNAME_OFFSETS > 0) {
 		int ofs, offset[KNOWN_APPNAME_OFFSETS], index[KNOWN_APPNAME_OFFSETS];
 		for (i = 0; i < KNOWN_APPNAME_OFFSETS; i++)
@@ -120,7 +127,6 @@ int main(int argc, char **argv)
 		printf("};\n\n");
 	}
 
-	//printf("#ifndef SKIP_definitions\n");
 	printf("const char applet_names[] ALIGN1 = \"\"\n");
 	for (i = 0; i < NUM_APPLETS; i++) {
 		printf("\"%s\" \"\\0\"\n", applets[i].name);
@@ -129,12 +135,6 @@ int main(int argc, char **argv)
 	}
 	printf(";\n\n");
 
-	for (i = 0; i < NUM_APPLETS; i++) {
-		if (str_isalnum_(applets[i].name))
-			printf("#define APPLET_NO_%s %d\n", applets[i].name, i);
-	}
-	printf("\n");
-
 	printf("#ifndef SKIP_applet_main\n");
 	printf("int (*const applet_main[])(int argc, char **argv) = {\n");
 	for (i = 0; i < NUM_APPLETS; i++) {
@@ -189,7 +189,7 @@ int main(int argc, char **argv)
 	}
 	printf("};\n");
 #endif
-	//printf("#endif /* SKIP_definitions */\n");
+	printf("#endif /* SKIP_definitions */\n");
 //	printf("\n");
 //	printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN);
 
diff --git a/include/busybox.h b/include/busybox.h
index 737627b..4af6a11 100644
--- a/include/busybox.h
+++ b/include/busybox.h
@@ -44,12 +44,8 @@ extern const uint8_t applet_install_loc[] ALIGN1;
  * and "individual" binaries. Keep them short.
  */
 #if ENABLE_BUILD_LIBBUSYBOX
-#if ENABLE_FEATURE_SHARED_BUSYBOX
-int lbb_main(char **argv) EXTERNALLY_VISIBLE;
-#else
 int lbb_main(char **argv);
 #endif
-#endif
 
 POP_SAVED_FUNCTION_VISIBILITY
 
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 281123c..9628003 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -656,196 +656,6 @@ static void check_suid(int applet_no)
 # endif /* FEATURE_SUID */
 
 
-# if ENABLE_FEATURE_INSTALLER
-static const char usr_bin [] ALIGN1 = "/usr/bin/";
-static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
-static const char *const install_dir[] = {
-	&usr_bin [8], /* "/" */
-	&usr_bin [4], /* "/bin/" */
-	&usr_sbin[4]  /* "/sbin/" */
-#  if !ENABLE_INSTALL_NO_USR
-	,usr_bin
-	,usr_sbin
-#  endif
-};
-
-/* create (sym)links for each applet */
-static void install_links(const char *busybox, int use_symbolic_links,
-		char *custom_install_dir)
-{
-	/* directory table
-	 * this should be consistent w/ the enum,
-	 * busybox.h::bb_install_loc_t, or else... */
-	int (*lf)(const char *, const char *);
-	char *fpc;
-        const char *appname = applet_names;
-	unsigned i;
-	int rc;
-
-	lf = link;
-	if (use_symbolic_links)
-		lf = symlink;
-
-	for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
-		fpc = concat_path_file(
-				custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)],
-				appname);
-		// debug: bb_error_msg("%slinking %s to busybox",
-		//		use_symbolic_links ? "sym" : "", fpc);
-		rc = lf(busybox, fpc);
-		if (rc != 0 && errno != EEXIST) {
-			bb_simple_perror_msg(fpc);
-		}
-		free(fpc);
-		while (*appname++ != '\0')
-			continue;
-	}
-}
-# elif ENABLE_BUSYBOX
-static void install_links(const char *busybox UNUSED_PARAM,
-		int use_symbolic_links UNUSED_PARAM,
-		char *custom_install_dir UNUSED_PARAM)
-{
-}
-# endif
-
-# if ENABLE_BUSYBOX
-/* If we were called as "busybox..." */
-static int busybox_main(char **argv)
-{
-	if (!argv[1]) {
-		/* Called without arguments */
-		const char *a;
-		int col;
-		unsigned output_width;
- help:
-		output_width = 80;
-		if (ENABLE_FEATURE_AUTOWIDTH) {
-			/* Obtain the terminal width */
-			output_width = get_terminal_width(2);
-		}
-
-		dup2(1, 2);
-		full_write2_str(bb_banner); /* reuse const string */
-		full_write2_str(" multi-call binary.\n"); /* reuse */
-		full_write2_str(
-			"BusyBox is copyrighted by many authors between 1998-2015.\n"
-			"Licensed under GPLv2. See source distribution for detailed\n"
-			"copyright notices.\n"
-			"\n"
-			"Usage: busybox [function [arguments]...]\n"
-			"   or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n"
-			IF_FEATURE_INSTALLER(
-			"   or: busybox --install [-s] [DIR]\n"
-			)
-			"   or: function [arguments]...\n"
-			"\n"
-			IF_NOT_FEATURE_SH_STANDALONE(
-			"\tBusyBox is a multi-call binary that combines many common Unix\n"
-			"\tutilities into a single executable.  Most people will create a\n"
-			"\tlink to busybox for each function they wish to use and BusyBox\n"
-			"\twill act like whatever it was invoked as.\n"
-			)
-			IF_FEATURE_SH_STANDALONE(
-			"\tBusyBox is a multi-call binary that combines many common Unix\n"
-			"\tutilities into a single executable.  The shell in this build\n"
-			"\tis configured to run built-in utilities without $PATH search.\n"
-			"\tYou don't need to install a link to busybox for each utility.\n"
-			"\tTo run external program, use full path (/sbin/ip instead of ip).\n"
-			)
-			"\n"
-			"Currently defined functions:\n"
-		);
-		col = 0;
-		a = applet_names;
-		/* prevent last comma to be in the very last pos */
-		output_width--;
-		while (*a) {
-			int len2 = strlen(a) + 2;
-			if (col >= (int)output_width - len2) {
-				full_write2_str(",\n");
-				col = 0;
-			}
-			if (col == 0) {
-				col = 6;
-				full_write2_str("\t");
-			} else {
-				full_write2_str(", ");
-			}
-			full_write2_str(a);
-			col += len2;
-			a += len2 - 1;
-		}
-		full_write2_str("\n\n");
-		return 0;
-	}
-
-	if (is_prefixed_with(argv[1], "--list")) {
-		unsigned i = 0;
-		const char *a = applet_names;
-		dup2(1, 2);
-		while (*a) {
-#  if ENABLE_FEATURE_INSTALLER
-			if (argv[1][6]) /* --list-full? */
-				full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
-#  endif
-			full_write2_str(a);
-			full_write2_str("\n");
-			i++;
-			while (*a++ != '\0')
-				continue;
-		}
-		return 0;
-	}
-
-	if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
-		int use_symbolic_links;
-		const char *busybox;
-
-		busybox = xmalloc_readlink(bb_busybox_exec_path);
-		if (!busybox) {
-			/* bb_busybox_exec_path is usually "/proc/self/exe".
-			 * In chroot, readlink("/proc/self/exe") usually fails.
-			 * In such case, better use argv[0] as symlink target
-			 * if it is a full path name.
-			 */
-			if (argv[0][0] != '/')
-				bb_error_msg_and_die("'%s' is not an absolute path", argv[0]);
-			busybox = argv[0];
-		}
-		/* busybox --install [-s] [DIR]:
-		 * -s: make symlinks
-		 * DIR: directory to install links to
-		 */
-		use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv);
-		install_links(busybox, use_symbolic_links, argv[2]);
-		return 0;
-	}
-
-	if (strcmp(argv[1], "--help") == 0) {
-		/* "busybox --help [<applet>]" */
-		if (!argv[2])
-			goto help;
-		/* convert to "<applet> --help" */
-		argv[0] = argv[2];
-		argv[2] = NULL;
-	} else {
-		/* "busybox <applet> arg1 arg2 ..." */
-		argv++;
-	}
-	/* We support "busybox /a/path/to/applet args..." too. Allows for
-	 * "#!/bin/busybox"-style wrappers */
-	applet_name = bb_get_last_path_component_nostrip(argv[0]);
-	run_applet_and_exit(applet_name, argv);
-
-	/*bb_error_msg_and_die("applet not found"); - sucks in printf */
-	full_write2_str(applet_name);
-	full_write2_str(": applet not found\n");
-	/* POSIX: "If a command is not found, the exit status shall be 127" */
-	exit(127);
-}
-# endif
-
 void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
 {
 	int argc = 1;
@@ -860,19 +670,27 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
 	/* Special case. POSIX says "test --help"
 	 * should be no different from e.g. "test --foo".
 	 * Thus for "test", we skip --help check.
-	 * "true" and "false" are also special.
+	 * "true", "false" and "busybox" are also special.
 	 */
-	if (1
+#if ENABLE_TEST || ENABLE_TRUE || ENABLE_FALSE || ENABLE_BUSYBOX
+	switch (applet_no) {
 #if defined APPLET_NO_test
-	 && applet_no != APPLET_NO_test
+	case APPLET_NO_test:
 #endif
 #if defined APPLET_NO_true
-	 && applet_no != APPLET_NO_true
+	case APPLET_NO_true:
 #endif
 #if defined APPLET_NO_false
-	 && applet_no != APPLET_NO_false
+	case APPLET_NO_false:
+#endif
+#if defined APPLET_NO_busybox
+	case APPLET_NO_busybox:
+#endif
+		break;
+	default:
+#else
+	if (1) {
 #endif
-	) {
 		if (argc == 2 && strcmp(argv[1], "--help") == 0) {
 			/* Make "foo --help" exit with 0: */
 			xfunc_error_retval = 0;
@@ -888,12 +706,10 @@ void FAST_FUNC run_applet_and_exit(const char *name, char **argv)
 {
 	int applet;
 
-# if ENABLE_BUSYBOX
-	if (is_prefixed_with(name, "busybox"))
-		exit(busybox_main(argv));
-# endif
-	/* find_applet_by_name() search is more expensive, so goes second */
-	applet = find_applet_by_name(name);
+	if (ENABLE_BUSYBOX && is_prefixed_with(name, "busybox"))
+		applet = APPLET_NO_busybox;
+	else
+		applet = find_applet_by_name(name);
 	if (applet >= 0)
 		run_applet_no_and_exit(applet, argv);
 }
@@ -956,6 +772,10 @@ int main(int argc UNUSED_PARAM, char **argv)
 #else
 	lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
 
+#if !ENABLE_BUSYBOX
+	if (argv[1] && is_prefixed_with(bb_basename(argv[0]), "busybox"))
+		argv++;
+#endif
 	applet_name = argv[0];
 	if (applet_name[0] == '-')
 		applet_name++;
diff --git a/libbb/busybox.c b/libbb/busybox.c
new file mode 100644
index 0000000..75e7d4b
--- /dev/null
+++ b/libbb/busybox.c
@@ -0,0 +1,210 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * busybox applet
+ *
+ * Copyright (C) tons of folks.  Tracking down who wrote what
+ * isn't something I'm going to worry about...  If you wrote something
+ * here, please feel free to acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include "busybox.h"
+#define SKIP_definitions
+#include "applet_tables.h"
+
+//applet:IF_BUSYBOX(APPLET(busybox, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_BUSYBOX) += busybox.o
+
+//usage:#define busybox_trivial_usage
+//usage:       ""
+//usage:#define busybox_full_usage
+//usage:       ""
+
+# if ENABLE_FEATURE_INSTALLER
+static const char usr_bin [] ALIGN1 = "/usr/bin/";
+static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
+static const char *const install_dir[] = {
+	&usr_bin [8], /* "/" */
+	&usr_bin [4], /* "/bin/" */
+	&usr_sbin[4]  /* "/sbin/" */
+#  if !ENABLE_INSTALL_NO_USR
+	,usr_bin
+	,usr_sbin
+#  endif
+};
+
+/* create (sym)links for each applet */
+static void install_links(const char *busybox, int use_symbolic_links,
+		char *custom_install_dir)
+{
+	/* directory table
+	 * this should be consistent w/ the enum,
+	 * busybox.h::bb_install_loc_t, or else... */
+	int (*lf)(const char *, const char *);
+	char *fpc;
+	const char *appname = applet_names;
+	unsigned i;
+	int rc;
+
+	lf = link;
+	if (use_symbolic_links)
+		lf = symlink;
+
+	for (i = 0; i < NUM_APPLETS; i++) {
+		fpc = concat_path_file(
+				custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)],
+				appname);
+		// debug: bb_error_msg("%slinking %s to busybox",
+		//		use_symbolic_links ? "sym" : "", fpc);
+		rc = lf(busybox, fpc);
+		if (rc != 0 && errno != EEXIST) {
+			bb_simple_perror_msg(fpc);
+		}
+		free(fpc);
+		while (*appname++ != '\0')
+			continue;
+	}
+}
+# else
+static void install_links(const char *busybox UNUSED_PARAM,
+		int use_symbolic_links UNUSED_PARAM,
+		char *custom_install_dir UNUSED_PARAM)
+{
+}
+# endif
+
+int busybox_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int busybox_main(int argc UNUSED_PARAM, char **argv)
+{
+	if (!argv[1]) {
+		/* Called without arguments */
+		const char *a;
+		int col;
+		unsigned output_width;
+ help:
+		output_width = 80;
+		if (ENABLE_FEATURE_AUTOWIDTH) {
+			/* Obtain the terminal width */
+			output_width = get_terminal_width(2);
+		}
+
+		dup2(1, 2);
+		full_write2_str(bb_banner); /* reuse const string */
+		full_write2_str(" multi-call binary.\n"); /* reuse */
+		full_write2_str(
+			"BusyBox is copyrighted by many authors between 1998-2015.\n"
+			"Licensed under GPLv2. See source distribution for detailed\n"
+			"copyright notices.\n"
+			"\n"
+			"Usage: busybox [function [arguments]...]\n"
+			"   or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n"
+			IF_FEATURE_INSTALLER(
+			"   or: busybox --install [-s] [DIR]\n"
+			)
+			"   or: function [arguments]...\n"
+			"\n"
+			IF_NOT_FEATURE_SH_STANDALONE(
+			"\tBusyBox is a multi-call binary that combines many common Unix\n"
+			"\tutilities into a single executable.  Most people will create a\n"
+			"\tlink to busybox for each function they wish to use and BusyBox\n"
+			"\twill act like whatever it was invoked as.\n"
+			)
+			IF_FEATURE_SH_STANDALONE(
+			"\tBusyBox is a multi-call binary that combines many common Unix\n"
+			"\tutilities into a single executable.  The shell in this build\n"
+			"\tis configured to run built-in utilities without $PATH search.\n"
+			"\tYou don't need to install a link to busybox for each utility.\n"
+			"\tTo run external program, use full path (/sbin/ip instead of ip).\n"
+			)
+			"\n"
+			"Currently defined functions:\n"
+		);
+		col = 0;
+		a = applet_names;
+		/* prevent last comma to be in the very last pos */
+		output_width--;
+		while (*a) {
+			int len2 = strlen(a) + 2;
+			if (col >= (int)output_width - len2) {
+				full_write2_str(",\n");
+				col = 0;
+			}
+			if (col == 0) {
+				col = 6;
+				full_write2_str("\t");
+			} else {
+				full_write2_str(", ");
+			}
+			full_write2_str(a);
+			col += len2;
+			a += len2 - 1;
+		}
+		full_write2_str("\n\n");
+		return 0;
+	}
+
+	if (is_prefixed_with(argv[1], "--list")) {
+		unsigned i = 0;
+		const char *a = applet_names;
+		dup2(1, 2);
+		while (*a) {
+			if (ENABLE_FEATURE_INSTALLER && argv[1][6]) { /* --list-full? */
+				full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
+			}
+			full_write2_str(a);
+			full_write2_str("\n");
+			i++;
+			while (*a++ != '\0')
+				continue;
+		}
+		return 0;
+	}
+
+	if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
+		int use_symbolic_links;
+		const char *busybox;
+
+		busybox = xmalloc_readlink(bb_busybox_exec_path);
+		if (!busybox) {
+			/* bb_busybox_exec_path is usually "/proc/self/exe".
+			 * In chroot, readlink("/proc/self/exe") usually fails.
+			 * In such case, better use argv[0] as symlink target
+			 * if it is a full path name.
+			 */
+			if (argv[0][0] != '/')
+				bb_error_msg_and_die("'%s' is not an absolute path", argv[0]);
+			busybox = argv[0];
+		}
+		/* busybox --install [-s] [DIR]:
+		 * -s: make symlinks
+		 * DIR: directory to install links to
+		 */
+		use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv);
+		install_links(busybox, use_symbolic_links, argv[2]);
+		return 0;
+	}
+
+	if (strcmp(argv[1], "--help") == 0) {
+		/* "busybox --help [<applet>]" */
+		if (!argv[2])
+			goto help;
+		/* convert to "<applet> --help" */
+		argv[0] = argv[2];
+		argv[2] = NULL;
+	} else {
+		/* "busybox <applet> arg1 arg2 ..." */
+		argv++;
+	}
+	/* We support "busybox /a/path/to/applet args..." too. Allows for
+	 * "#!/bin/busybox"-style wrappers */
+	applet_name = bb_get_last_path_component_nostrip(argv[0]);
+	run_applet_and_exit(applet_name, argv);
+
+	/*bb_error_msg_and_die("applet not found"); - sucks in printf */
+	full_write2_str(applet_name);
+	full_write2_str(": applet not found\n");
+	/* POSIX: "If a command is not found, the exit status shall be 127" */
+	exit(127);
+}
diff --git a/scripts/trylink b/scripts/trylink
index 129570a..daa8c1f 100755
--- a/scripts/trylink
+++ b/scripts/trylink
@@ -269,26 +269,6 @@ if test "$CONFIG_BUILD_LIBBUSYBOX" = y; then
     echo "libbusybox: $sharedlib_dir/libbusybox.so.$BB_VER"
 fi
 
-if test "$CONFIG_FEATURE_SHARED_BUSYBOX" = y; then
-    EXE="$sharedlib_dir/busybox_unstripped"
-    try $CC $CFLAGS $LDFLAGS \
-	    -o $EXE \
-	    $SORT_COMMON \
-	    $SORT_SECTION \
-	    $GC_SECTIONS \
-	    $START_GROUP $O_FILES $END_GROUP \
-	    -L"$sharedlib_dir" -lbusybox \
-	    $l_list \
-	    $INFO_OPTS \
-    || {
-	echo "Linking $EXE failed"
-	cat $EXE.out
-	exit 1
-    }
-    $STRIP -s --remove-section=.note --remove-section=.comment $EXE -o "$sharedlib_dir/busybox"
-    echo "busybox linked against libbusybox: $sharedlib_dir/busybox"
-fi
-
 if test "$CONFIG_FEATURE_INDIVIDUAL" = y; then
     echo "Linking individual applets against libbusybox (see $sharedlib_dir/*)"
     gcc -DNAME_MAIN -E -include include/autoconf.h include/applets.h \
-- 
2.5.5



More information about the busybox mailing list