shells: do not frocibly enable test, echo and kill _applets_, just build relevant source and use xxx_main functions. build system: add a special case when we have exactly one applet enabled (makes "true", "false", "basename" REALLY tiny). getopt32: do not use stdio.
No binary (build failed)
—
(log yok)
| @@ -69,9 +69,14 @@ int main(int argc, char **argv) | |
| /* Keep in sync with include/busybox.h! */ | |
| - | puts("/* This is a generated file, don't edit */"); |
| + | puts("/* This is a generated file, don't edit */\n"); |
| - | puts("const char applet_names[] ALIGN1 = \"\"\n"); |
| + | if (NUM_APPLETS == 1) { |
| + | printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name); |
| + | printf("#define SINGLE_APPLET_MAIN %s_main\n\n", applets[0].name); |
| + | } |
| + | |
| + | puts("const char applet_names[] ALIGN1 = \"\""); |
| for (i = 0; i < NUM_APPLETS; i++) { | |
| printf("\"%s\" \"\\0\"\n", applets[i].name); | |
| } | |
| @@ -30,6 +30,7 @@ lib-$(CONFIG_DOS2UNIX) += dos2unix.o | |
| lib-$(CONFIG_DU) += du.o | |
| lib-$(CONFIG_ECHO) += echo.o | |
| lib-$(CONFIG_ASH) += echo.o # used by ash | |
| + | lib-$(CONFIG_HUSH) += echo.o # used by hush |
| lib-$(CONFIG_ENV) += env.o | |
| lib-$(CONFIG_EXPR) += expr.o | |
| lib-$(CONFIG_EXPAND) += expand.o | |
| @@ -72,6 +73,8 @@ lib-$(CONFIG_TAIL) += tail.o | |
| lib-$(CONFIG_TEE) += tee.o | |
| lib-$(CONFIG_TEST) += test.o | |
| lib-$(CONFIG_ASH) += test.o # used by ash | |
| + | lib-$(CONFIG_HUSH) += test.o # used by hush |
| + | lib-$(CONFIG_MSH) += test.o # used by msh |
| lib-$(CONFIG_TOUCH) += touch.o | |
| lib-$(CONFIG_TR) += tr.o | |
| lib-$(CONFIG_TRUE) += true.o | |
| @@ -37,15 +37,16 @@ int basename_main(int argc, char **argv) | |
| /* It should strip slash: /abc/def/ -> def */ | |
| s = bb_get_last_path_component_strip(*++argv); | |
| + | m = strlen(s); |
| if (*++argv) { | |
| n = strlen(*argv); | |
| - | m = strlen(s); |
| if ((m > n) && ((strcmp)(s+m-n, *argv) == 0)) { | |
| - | s[m-n] = '\0'; |
| + | m -= n; |
| + | s[m] = '\0'; |
| } | |
| } | |
| - | puts(s); |
| - | |
| - | return fflush(stdout); |
| + | /* puts(s) will do, but we can do without stdio this way: */ |
| + | s[m++] = '\n'; |
| + | return full_write(STDOUT_FILENO, s, m) == m; |
| } | |
| @@ -27,10 +27,8 @@ | |
| /* This is a NOFORK applet. Be very careful! */ | |
| - | /* argc is unused, but removing it precludes compiler from |
| - | * using call -> jump optimization */ |
| + | /* NB: can be used by shell even if not enabled as applet */ |
| - | int echo_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| int echo_main(int argc ATTRIBUTE_UNUSED, char **argv) | |
| { | |
| const char *arg; | |
| @@ -59,9 +59,6 @@ extern const uint8_t applet_install_loc[]; | |
| /* Length of these names has effect on size of libbusybox | |
| * and "individual" binaries. Keep them short. | |
| */ | |
| - | void lbb_prepare(const char *applet |
| - | USE_FEATURE_INDIVIDUAL(, char **argv) |
| - | ) MAIN_EXTERNALLY_VISIBLE; |
| #if ENABLE_BUILD_LIBBUSYBOX | |
| #if ENABLE_FEATURE_SHARED_BUSYBOX | |
| int lbb_main(char **argv) EXTERNALLY_VISIBLE; | |
| @@ -848,23 +848,20 @@ extern void bb_verror_msg(const char *s, va_list p, const char *strerr); | |
| /* applets which are useful from another applets */ | |
| int bb_cat(char** argv); | |
| - | int echo_main(int argc, char** argv) MAIN_EXTERNALLY_VISIBLE; |
| - | int test_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| - | int kill_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| - | #if ENABLE_ROUTE |
| - | void bb_displayroutes(int noresolve, int netstatfmt); |
| - | #endif |
| + | /* If shell needs them, these three "exist" even if not enabled as applets */ |
| + | int echo_main(int argc, char** argv) USE_ECHO(MAIN_EXTERNALLY_VISIBLE); |
| + | int test_main(int argc, char **argv) USE_TEST(MAIN_EXTERNALLY_VISIBLE); |
| + | int kill_main(int argc, char **argv) USE_KILL(MAIN_EXTERNALLY_VISIBLE); |
| int chown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| - | #if ENABLE_GUNZIP |
| int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| - | #endif |
| - | #if ENABLE_BUNZIP2 |
| int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| - | #endif |
| int bbunpack(char **argv, | |
| char* (*make_new_name)(char *filename), | |
| USE_DESKTOP(long long) int (*unpacker)(void) | |
| ); | |
| + | #if ENABLE_ROUTE |
| + | void bb_displayroutes(int noresolve, int netstatfmt); |
| + | #endif |
| /* Networking */ | |
| @@ -98,13 +98,13 @@ config FEATURE_INITRD | |
| config HALT | |
| bool "poweroff, halt, and reboot" | |
| - | default y |
| + | default n |
| help | |
| Stop all processes and either halt, reboot, or power off the system. | |
| config MESG | |
| bool "mesg" | |
| - | default y |
| + | default n |
| help | |
| Mesg controls access to your terminal by others. It is typically | |
| used to allow or disallow other users to write to your terminal | |
| @@ -101,6 +101,7 @@ lib-y += wfopen_input.o | |
| lib-y += xatonum.o | |
| lib-y += xconnect.o | |
| lib-y += xfuncs.o | |
| + | lib-y += xfunc_die.o |
| lib-y += xgetcwd.o | |
| lib-y += xgethostbyname.o | |
| lib-y += xreadlink.o | |
| @@ -36,6 +36,13 @@ static const char usage_messages[] ALIGN1 = "" | |
| /* Include generated applet names, pointers to <applet>_main, etc */ | |
| #include "applet_tables.h" | |
| + | /* ...and if applet_tables generator says we have only one applet... */ |
| + | #ifdef SINGLE_APPLET_MAIN |
| + | #undef ENABLE_FEATURE_INDIVIDUAL |
| + | #define ENABLE_FEATURE_INDIVIDUAL 1 |
| + | #undef USE_FEATURE_INDIVIDUAL |
| + | #define USE_FEATURE_INDIVIDUAL(...) __VA_ARGS__ |
| + | #endif |
| #if ENABLE_FEATURE_COMPRESS_USAGE | |
| @@ -77,6 +84,23 @@ static const char *unpack_usage_messages(void) | |
| void bb_show_usage(void) | |
| { | |
| if (ENABLE_SHOW_USAGE) { | |
| + | #ifdef SINGLE_APPLET_STR |
| + | /* Imagine that this applet is "true". Dont suck in printf! */ |
| + | const char *p; |
| + | const char *usage_string = p = unpack_usage_messages(); |
| + | |
| + | if (*p == '\b') { |
| + | write(2, "\nNo help available.\n\n", |
| + | sizeof("\nNo help available.\n\n") - 1); |
| + | } else { |
| + | write(2, "\nUsage: "SINGLE_APPLET_STR" ", |
| + | sizeof("\nUsage: "SINGLE_APPLET_STR" ") - 1); |
| + | write(2, p, strlen(p)); |
| + | write(2, "\n\n", 2); |
| + | } |
| + | dealloc_usage_messages((char*)usage_string); |
| + | #else |
| + | // TODO: in this case, stdio is sucked in by busybox_main() anyway... |
| const char *format_string; | |
| const char *p; | |
| const char *usage_string = p = unpack_usage_messages(); | |
| @@ -84,18 +108,17 @@ void bb_show_usage(void) | |
| if (ap < 0) /* never happens, paranoia */ | |
| xfunc_die(); | |
| - | |
| while (ap) { | |
| while (*p++) continue; | |
| ap--; | |
| } | |
| - | |
| fprintf(stderr, "%s multi-call binary\n", bb_banner); | |
| format_string = "\nUsage: %s %s\n\n"; | |
| if (*p == '\b') | |
| format_string = "\nNo help available.\n\n"; | |
| fprintf(stderr, format_string, applet_name, p); | |
| dealloc_usage_messages((char*)usage_string); | |
| + | #endif |
| } | |
| xfunc_die(); | |
| } | |
| @@ -123,6 +146,9 @@ int find_applet_by_name(const char *name) | |
| int *const bb_errno __attribute__ ((section (".data"))); | |
| #endif | |
| + | void lbb_prepare(const char *applet |
| + | USE_FEATURE_INDIVIDUAL(, char **argv)) |
| + | MAIN_EXTERNALLY_VISIBLE; |
| void lbb_prepare(const char *applet | |
| USE_FEATURE_INDIVIDUAL(, char **argv)) | |
| { | |
| @@ -158,6 +184,9 @@ const char *applet_name; | |
| bool re_execed; | |
| #endif | |
| + | |
| + | #if !ENABLE_FEATURE_INDIVIDUAL |
| + | |
| USE_FEATURE_SUID(static uid_t ruid;) /* real uid */ | |
| #if ENABLE_FEATURE_SUID_CONFIG | |
| @@ -660,6 +689,9 @@ void run_applet_and_exit(const char *name, char **argv) | |
| exit(busybox_main(argv)); | |
| } | |
| + | #endif /* !ENABLE_FEATURE_INDIVIDUAL */ |
| + | |
| + | |
| #if ENABLE_BUILD_LIBBUSYBOX | |
| int lbb_main(char **argv) | |
| @@ -667,6 +699,11 @@ int lbb_main(char **argv) | |
| int main(int argc ATTRIBUTE_UNUSED, char **argv) | |
| #endif | |
| { | |
| + | #if ENABLE_FEATURE_INDIVIDUAL |
| + | /* Only one applet is selected by the user! */ |
| + | lbb_prepare(SINGLE_APPLET_STR USE_FEATURE_INDIVIDUAL(, argv)); |
| + | return SINGLE_APPLET_MAIN(argc, argv); |
| + | #else |
| lbb_prepare("busybox" USE_FEATURE_INDIVIDUAL(, argv)); | |
| #if !BB_MMU | |
| @@ -685,4 +722,5 @@ int main(int argc ATTRIBUTE_UNUSED, char **argv) | |
| run_applet_and_exit(applet_name, argv); | |
| bb_error_msg_and_die("applet not found"); | |
| + | #endif |
| } | |
| @@ -9,33 +9,6 @@ | |
| #include "libbb.h" | |
| - | int die_sleep; |
| - | #if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH |
| - | jmp_buf die_jmp; |
| - | #endif |
| - | |
| - | void xfunc_die(void) |
| - | { |
| - | if (die_sleep) { |
| - | if ((ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH) |
| - | && die_sleep < 0 |
| - | ) { |
| - | /* Special case. We arrive here if NOFORK applet |
| - | * calls xfunc, which then decides to die. |
| - | * We don't die, but jump instead back to caller. |
| - | * NOFORK applets still cannot carelessly call xfuncs: |
| - | * p = xmalloc(10); |
| - | * q = xmalloc(10); // BUG! if this dies, we leak p! |
| - | */ |
| - | /* -2222 means "zero" (longjmp can't pass 0) |
| - | * run_nofork_applet() catches -2222. */ |
| - | longjmp(die_jmp, xfunc_error_retval ? xfunc_error_retval : -2222); |
| - | } |
| - | sleep(die_sleep); |
| - | } |
| - | exit(xfunc_error_retval); |
| - | } |
| - | |
| void bb_error_msg_and_die(const char *s, ...) | |
| { | |
| va_list p; | |
| @@ -285,6 +285,10 @@ const char *const bb_argv_dash[] = { "-", NULL }; | |
| const char *opt_complementary; | |
| + | /* Many small applets don't want to suck in stdio.h only because |
| + | * they need to parse options by calling us */ |
| + | #define DONT_USE_PRINTF 1 |
| + | |
| enum { | |
| PARAM_STRING, | |
| PARAM_LIST, | |
| @@ -335,7 +339,8 @@ getopt32(char **argv, const char *applet_opts, ...) | |
| #define SHOW_USAGE_IF_ERROR 1 | |
| #define ALL_ARGV_IS_OPTS 2 | |
| #define FIRST_ARGV_IS_OPT 4 | |
| - | #define FREE_FIRST_ARGV_IS_OPT 8 |
| + | #define FREE_FIRST_ARGV_IS_OPT (8 * !DONT_USE_PRINTF) |
| + | |
| int spec_flgs = 0; | |
| argc = 0; | |
| @@ -489,10 +494,16 @@ getopt32(char **argv, const char *applet_opts, ...) | |
| va_end(p); | |
| if (spec_flgs & FIRST_ARGV_IS_OPT) { | |
| - | if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') { |
| + | if (argv[1] && argv[1][0] != '-' && argv[1][1] != '\0') { |
| + | #if DONT_USE_PRINTF |
| + | char *pp = alloca(strlen(argv[1]) + 2); |
| + | *pp++ = '-'; |
| + | argv[1] = strcpy(pp, argv[1]); |
| + | #else |
| argv[1] = xasprintf("-%s", argv[1]); | |
| if (ENABLE_FEATURE_CLEAN_UP) | |
| spec_flgs |= FREE_FIRST_ARGV_IS_OPT; | |
| + | #endif |
| } | |
| } | |
| @@ -573,7 +584,7 @@ getopt32(char **argv, const char *applet_opts, ...) | |
| } | |
| } | |
| - | #if (ENABLE_AR || ENABLE_TAR) && ENABLE_FEATURE_CLEAN_UP |
| + | #if ENABLE_FEATURE_CLEAN_UP |
| if (spec_flgs & FREE_FIRST_ARGV_IS_OPT) | |
| free(argv[1]); | |
| #endif | |
| @@ -24,7 +24,6 @@ | |
| * This is needed to avoid collision with kill -9 ... syntax | |
| */ | |
| - | int kill_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| int kill_main(int argc, char **argv) | |
| { | |
| char *arg; | |
| @@ -36,7 +36,6 @@ endchoice | |
| config ASH | |
| bool "ash" | |
| default n | |
| - | select TEST |
| help | |
| Tha 'ash' shell adds about 60k in the default configuration and is | |
| the most complete and most pedantically correct shell included with | |
| @@ -111,7 +110,6 @@ config ASH_GETOPTS | |
| config ASH_BUILTIN_ECHO | |
| bool "Builtin version of 'echo'" | |
| default y | |
| - | select ECHO |
| depends on ASH | |
| help | |
| Enable support for echo, builtin to ash. | |
| @@ -119,7 +117,6 @@ config ASH_BUILTIN_ECHO | |
| config ASH_BUILTIN_TEST | |
| bool "Builtin version of 'test'" | |
| default y | |
| - | select TEST |
| depends on ASH | |
| help | |
| Enable support for test, builtin to ash. | |
| @@ -170,10 +167,6 @@ config ASH_EXPAND_PRMT | |
| config HUSH | |
| bool "hush" | |
| default n | |
| - | select TRUE |
| - | select FALSE |
| - | select TEST |
| - | select ECHO |
| help | |
| hush is a very small shell (just 18k) and it has fairly complete | |
| Bourne shell grammar. It even handles all the normal flow control | |
| @@ -240,13 +233,9 @@ config LASH | |
| help | |
| lash is deprecated and will be removed, please migrate to hush. | |
| - | |
| config MSH | |
| bool "msh" | |
| default n | |
| - | select TRUE |
| - | select FALSE |
| - | select TEST |
| help | |
| The minix shell (adds just 30k) is quite complete and handles things | |
| like for/do/done, case/esac and all the things you expect a Bourne | |
| @@ -8417,12 +8417,6 @@ returncmd(int argc ATTRIBUTE_UNUSED, char **argv) | |
| static int breakcmd(int, char **); | |
| static int dotcmd(int, char **); | |
| static int evalcmd(int, char **); | |
| - | #if ENABLE_ASH_BUILTIN_ECHO |
| - | static int echocmd(int, char **); |
| - | #endif |
| - | #if ENABLE_ASH_BUILTIN_TEST |
| - | static int testcmd(int, char **); |
| - | #endif |
| static int exitcmd(int, char **); | |
| static int exportcmd(int, char **); | |
| #if ENABLE_ASH_GETOPTS | |
| @@ -8464,6 +8458,9 @@ static int ulimitcmd(int, char **); | |
| * Apart from the above, [[ expr ]] should work as [ expr ] | |
| */ | |
| + | #define testcmd test_main |
| + | #define echocmd echo_main |
| + | |
| /* Keep these in proper order since it is searched via bsearch() */ | |
| static const struct builtincmd builtintab[] = { | |
| { BUILTIN_SPEC_REG ".", dotcmd }, | |
| @@ -11506,22 +11503,6 @@ exitcmd(int argc ATTRIBUTE_UNUSED, char **argv) | |
| /* NOTREACHED */ | |
| } | |
| - | #if ENABLE_ASH_BUILTIN_ECHO |
| - | static int |
| - | echocmd(int argc, char **argv) |
| - | { |
| - | return echo_main(argc, argv); |
| - | } |
| - | #endif |
| - | |
| - | #if ENABLE_ASH_BUILTIN_TEST |
| - | static int |
| - | testcmd(int argc, char **argv) |
| - | { |
| - | return test_main(argc, argv); |
| - | } |
| - | #endif |
| - | |
| /* | |
| * Read a file containing shell functions. | |
| */ | |