[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