[PATCH 1/2] Allow BusyBox to be built without a list of applet names
Ron Yorston
rmy at pobox.com
Fri Apr 29 12:47:49 UTC 2016
Use a hash of the command name to determine which applet to execute.
Invalid names will also match.
Without applet names the following features don't work:
- busybox --list
- busybox --install
- tab completion for applets in standalone shell mode
- in standalone shell mode the help builtin doesn't list applets
Compared with the current default configuration, not storing applet
names gives:
function old new delta
applet_hash - 734 +734
usr_bin 10 - -10
usr_sbin 11 - -11
applet_nameofs 14 - -14
install_dir 20 - -20
find_applet_by_name 112 69 -43
applet_install_loc 184 - -184
run_applet_and_exit 675 192 -483
applet_names 2536 - -2536
------------------------------------------------------------------------------
(add/remove: 1/6 grow/shrink: 0/2 up/down: 734/-3301) Total: -2567 bytes
text data bss dec hex filename
764230 2059 1636 767925 bb7b5 busybox_old
761520 2059 1636 765215 bad1f busybox_unstripped
Signed-off-by: Ron Yorston <rmy at pobox.com>
---
Config.in | 9 +++++++++
applets/applet_tables.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
libbb/appletlib.c | 33 ++++++++++++++++++++++++++++++++-
libbb/lineedit.c | 2 +-
shell/ash.c | 2 +-
5 files changed, 87 insertions(+), 5 deletions(-)
diff --git a/Config.in b/Config.in
index 0a0b5d7..49ee333 100644
--- a/Config.in
+++ b/Config.in
@@ -116,9 +116,18 @@ config FEATURE_COMPRESS_USAGE
and have very little memory, this might not be a win. Otherwise,
you probably want this.
+config STORE_APPLET_NAMES
+ bool "Store applet names"
+ default y
+ help
+ Enable BusyBox applet names to be stored in the binary.
+ Disabling this will save some space but also disables useful
+ features like the installer and listing applet names.
+
config FEATURE_INSTALLER
bool "Support --install [-s] to install applet links at runtime"
default y
+ depends on STORE_APPLET_NAMES
help
Enable 'busybox --install [-s]' support. This will allow you to use
busybox at runtime to create hard links or symlinks for all the
diff --git a/applets/applet_tables.c b/applets/applet_tables.c
index 843f2ec..31ea188 100644
--- a/applets/applet_tables.c
+++ b/applets/applet_tables.c
@@ -11,6 +11,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
@@ -34,6 +35,7 @@ struct bb_applet {
/* true if instead of fork(); exec("applet"); waitpid();
* one can simply call applet_main(argc,argv); */
unsigned char nofork;
+ uint32_t app_hash;
};
/* Define struct bb_applet applets[] */
@@ -58,9 +60,21 @@ static int str_isalnum_(const char *s)
return 1;
}
+#if !ENABLE_STORE_APPLET_NAMES
+static uint32_t hash(const char *s, uint32_t mul)
+{
+ uint32_t h = *s++;
+ while (*s)
+ h = (h * mul) ^ (uint8_t)*s++;
+ return (uint16_t)h & 0xffff;
+}
+#endif
+
int main(int argc, char **argv)
{
int i, j;
+ uint32_t mul;
+ int MAX_APPLET_NAME_LEN = 0;
// In find_applet_by_name(), before linear search, narrow it down
// by looking at N "equidistant" names. With ~350 applets:
@@ -121,6 +135,8 @@ int main(int argc, char **argv)
}
//printf("#ifndef SKIP_definitions\n");
+ mul = 0;
+#if ENABLE_STORE_APPLET_NAMES
printf("const char applet_names[] ALIGN1 = \"\"\n");
for (i = 0; i < NUM_APPLETS; i++) {
printf("\"%s\" \"\\0\"\n", applets[i].name);
@@ -128,10 +144,36 @@ int main(int argc, char **argv)
// MAX_APPLET_NAME_LEN = strlen(applets[i].name);
}
printf(";\n\n");
+#else
+ mul = 1;
+ collision:
+ for (i = 0; i < NUM_APPLETS; i++) {
+ int j;
+ uint32_t h = hash(applets[i].name, mul);
+ for (j = 0; j < i; j++) {
+ if (h == applets[j].app_hash) {
+ mul += 2;
+ goto collision;
+ }
+ }
+ applets[i].app_hash = h;
+ }
+#endif
+
+ printf("#define APPNAME_HASH_MUL %u\n\n", mul);
+ if ( mul != 0 ) {
+ printf("const uint16_t applet_hash[] ALIGN2 = {\n");
+ for (i = 0; i < NUM_APPLETS; i++) {
+ printf("0x%04x,\n", applets[i].app_hash);
+ }
+ 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);
+ if (MAX_APPLET_NAME_LEN < strlen(applets[i].name))
+ MAX_APPLET_NAME_LEN = strlen(applets[i].name);
}
printf("\n");
@@ -190,8 +232,8 @@ int main(int argc, char **argv)
printf("};\n");
#endif
//printf("#endif /* SKIP_definitions */\n");
-// printf("\n");
-// printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN);
+ printf("\n");
+ printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN);
if (argv[2]) {
char line_old[80];
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index b682e6b..9a4f367 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -139,6 +139,7 @@ void FAST_FUNC bb_show_usage(void)
xfunc_die();
}
+#if APPNAME_HASH_MUL == 0
int FAST_FUNC find_applet_by_name(const char *name)
{
unsigned i, max;
@@ -265,6 +266,30 @@ int FAST_FUNC find_applet_by_name(const char *name)
return -1;
#endif
}
+#else
+static uint32_t hash(const char *s)
+{
+ uint32_t h = *s++;
+ while (*s)
+ h = (h * APPNAME_HASH_MUL) ^ (uint8_t)*s++;
+ return (uint16_t)h & 0xffff;
+}
+
+int FAST_FUNC find_applet_by_name(const char *name)
+{
+ uint32_t h = hash(name);
+ int i;
+
+ if (strlen(name) > MAX_APPLET_NAME_LEN)
+ return -1;
+
+ for (i=0; i<NUM_APPLETS; i++)
+ if (applet_hash[i] == h)
+ return i;
+
+ return -1;
+}
+#endif
void lbb_prepare(const char *applet
@@ -733,7 +758,9 @@ static int busybox_main(char **argv)
"copyright notices.\n"
"\n"
"Usage: busybox [function [arguments]...]\n"
+ IF_STORE_APPLET_NAMES(
" or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n"
+ )
IF_FEATURE_INSTALLER(
" or: busybox --install [-s] [DIR]\n"
)
@@ -753,8 +780,11 @@ static int busybox_main(char **argv)
"\tTo run external program, use full path (/sbin/ip instead of ip).\n"
)
"\n"
+ IF_STORE_APPLET_NAMES(
"Currently defined functions:\n"
+ )
);
+#if ENABLE_STORE_APPLET_NAMES
col = 0;
a = applet_names;
/* prevent last comma to be in the very last pos */
@@ -776,10 +806,11 @@ static int busybox_main(char **argv)
a += len2 - 1;
}
full_write2_str("\n\n");
+#endif
return 0;
}
- if (is_prefixed_with(argv[1], "--list")) {
+ if (ENABLE_STORE_APPLET_NAMES && is_prefixed_with(argv[1], "--list")) {
unsigned i = 0;
const char *a = applet_names;
dup2(1, 2);
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 3e62f46..2c35d50 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -775,7 +775,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
}
pf_len = strlen(pfind);
-#if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1
+#if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 && ENABLE_STORE_APPLET_NAMES
if (type == FIND_EXE_ONLY) {
const char *p = applet_names;
diff --git a/shell/ash.c b/shell/ash.c
index faa45a8..acaf95c 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -12588,7 +12588,7 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
col = 0;
}
}
-# if ENABLE_FEATURE_SH_STANDALONE
+# if ENABLE_FEATURE_SH_STANDALONE && ENABLE_STORE_APPLET_NAMES
{
const char *a = applet_names;
while (*a) {
--
2.5.5
More information about the busybox
mailing list