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.

function                                             old     new   delta
getopt32                                            1385    1412     +27
make_device                                         1187    1200     +13
basename_main                                        120     127      +7
tcpudpsvd_main                                      1922    1926      +4
testcmd                                                5       -      -5
echocmd                                                5       -      -5
fuser_main                                          1243    1231     -12
------------------------------------------------------------------------------
(add/remove: 0/2 grow/shrink: 4/1 up/down: 51/-22)             Total: 29 bytes
This commit is contained in:
Denis Vlasenko 2008-04-01 14:47:57 +00:00
parent 165f5b394f
commit 468aea2d88
14 changed files with 84 additions and 91 deletions

View File

@ -69,9 +69,14 @@ int main(int argc, char **argv)
/* Keep in sync with include/busybox.h! */ /* 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++) { for (i = 0; i < NUM_APPLETS; i++) {
printf("\"%s\" \"\\0\"\n", applets[i].name); printf("\"%s\" \"\\0\"\n", applets[i].name);
} }

View File

@ -30,6 +30,7 @@ lib-$(CONFIG_DOS2UNIX) += dos2unix.o
lib-$(CONFIG_DU) += du.o lib-$(CONFIG_DU) += du.o
lib-$(CONFIG_ECHO) += echo.o lib-$(CONFIG_ECHO) += echo.o
lib-$(CONFIG_ASH) += echo.o # used by ash lib-$(CONFIG_ASH) += echo.o # used by ash
lib-$(CONFIG_HUSH) += echo.o # used by hush
lib-$(CONFIG_ENV) += env.o lib-$(CONFIG_ENV) += env.o
lib-$(CONFIG_EXPR) += expr.o lib-$(CONFIG_EXPR) += expr.o
lib-$(CONFIG_EXPAND) += expand.o lib-$(CONFIG_EXPAND) += expand.o
@ -72,6 +73,8 @@ lib-$(CONFIG_TAIL) += tail.o
lib-$(CONFIG_TEE) += tee.o lib-$(CONFIG_TEE) += tee.o
lib-$(CONFIG_TEST) += test.o lib-$(CONFIG_TEST) += test.o
lib-$(CONFIG_ASH) += test.o # used by ash 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_TOUCH) += touch.o
lib-$(CONFIG_TR) += tr.o lib-$(CONFIG_TR) += tr.o
lib-$(CONFIG_TRUE) += true.o lib-$(CONFIG_TRUE) += true.o

View File

@ -37,15 +37,16 @@ int basename_main(int argc, char **argv)
/* It should strip slash: /abc/def/ -> def */ /* It should strip slash: /abc/def/ -> def */
s = bb_get_last_path_component_strip(*++argv); s = bb_get_last_path_component_strip(*++argv);
m = strlen(s);
if (*++argv) { if (*++argv) {
n = strlen(*argv); n = strlen(*argv);
m = strlen(s);
if ((m > n) && ((strcmp)(s+m-n, *argv) == 0)) { if ((m > n) && ((strcmp)(s+m-n, *argv) == 0)) {
s[m-n] = '\0'; m -= n;
s[m] = '\0';
} }
} }
puts(s); /* puts(s) will do, but we can do without stdio this way: */
s[m++] = '\n';
return fflush(stdout); return full_write(STDOUT_FILENO, s, m) == m;
} }

View File

@ -27,10 +27,8 @@
/* This is a NOFORK applet. Be very careful! */ /* This is a NOFORK applet. Be very careful! */
/* argc is unused, but removing it precludes compiler from /* NB: can be used by shell even if not enabled as applet */
* using call -> jump optimization */
int echo_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int echo_main(int argc ATTRIBUTE_UNUSED, char **argv) int echo_main(int argc ATTRIBUTE_UNUSED, char **argv)
{ {
const char *arg; const char *arg;

View File

@ -59,9 +59,6 @@ extern const uint8_t applet_install_loc[];
/* Length of these names has effect on size of libbusybox /* Length of these names has effect on size of libbusybox
* and "individual" binaries. Keep them short. * 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_BUILD_LIBBUSYBOX
#if ENABLE_FEATURE_SHARED_BUSYBOX #if ENABLE_FEATURE_SHARED_BUSYBOX
int lbb_main(char **argv) EXTERNALLY_VISIBLE; int lbb_main(char **argv) EXTERNALLY_VISIBLE;

View File

@ -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 */ /* applets which are useful from another applets */
int bb_cat(char** argv); int bb_cat(char** argv);
int echo_main(int argc, char** argv) MAIN_EXTERNALLY_VISIBLE; /* If shell needs them, these three "exist" even if not enabled as applets */
int test_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int echo_main(int argc, char** argv) USE_ECHO(MAIN_EXTERNALLY_VISIBLE);
int kill_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int test_main(int argc, char **argv) USE_TEST(MAIN_EXTERNALLY_VISIBLE);
#if ENABLE_ROUTE int kill_main(int argc, char **argv) USE_KILL(MAIN_EXTERNALLY_VISIBLE);
void bb_displayroutes(int noresolve, int netstatfmt);
#endif
int chown_main(int argc, char **argv) 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; int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
#endif
#if ENABLE_BUNZIP2
int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
#endif
int bbunpack(char **argv, int bbunpack(char **argv,
char* (*make_new_name)(char *filename), char* (*make_new_name)(char *filename),
USE_DESKTOP(long long) int (*unpacker)(void) USE_DESKTOP(long long) int (*unpacker)(void)
); );
#if ENABLE_ROUTE
void bb_displayroutes(int noresolve, int netstatfmt);
#endif
/* Networking */ /* Networking */

View File

@ -98,13 +98,13 @@ config FEATURE_INITRD
config HALT config HALT
bool "poweroff, halt, and reboot" bool "poweroff, halt, and reboot"
default y default n
help help
Stop all processes and either halt, reboot, or power off the system. Stop all processes and either halt, reboot, or power off the system.
config MESG config MESG
bool "mesg" bool "mesg"
default y default n
help help
Mesg controls access to your terminal by others. It is typically Mesg controls access to your terminal by others. It is typically
used to allow or disallow other users to write to your terminal used to allow or disallow other users to write to your terminal

View File

@ -101,6 +101,7 @@ lib-y += wfopen_input.o
lib-y += xatonum.o lib-y += xatonum.o
lib-y += xconnect.o lib-y += xconnect.o
lib-y += xfuncs.o lib-y += xfuncs.o
lib-y += xfunc_die.o
lib-y += xgetcwd.o lib-y += xgetcwd.o
lib-y += xgethostbyname.o lib-y += xgethostbyname.o
lib-y += xreadlink.o lib-y += xreadlink.o

View File

@ -36,6 +36,13 @@ static const char usage_messages[] ALIGN1 = ""
/* Include generated applet names, pointers to <applet>_main, etc */ /* Include generated applet names, pointers to <applet>_main, etc */
#include "applet_tables.h" #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 #if ENABLE_FEATURE_COMPRESS_USAGE
@ -77,6 +84,23 @@ static const char *unpack_usage_messages(void)
void bb_show_usage(void) void bb_show_usage(void)
{ {
if (ENABLE_SHOW_USAGE) { 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 *format_string;
const char *p; const char *p;
const char *usage_string = p = unpack_usage_messages(); const char *usage_string = p = unpack_usage_messages();
@ -84,18 +108,17 @@ void bb_show_usage(void)
if (ap < 0) /* never happens, paranoia */ if (ap < 0) /* never happens, paranoia */
xfunc_die(); xfunc_die();
while (ap) { while (ap) {
while (*p++) continue; while (*p++) continue;
ap--; ap--;
} }
fprintf(stderr, "%s multi-call binary\n", bb_banner); fprintf(stderr, "%s multi-call binary\n", bb_banner);
format_string = "\nUsage: %s %s\n\n"; format_string = "\nUsage: %s %s\n\n";
if (*p == '\b') if (*p == '\b')
format_string = "\nNo help available.\n\n"; format_string = "\nNo help available.\n\n";
fprintf(stderr, format_string, applet_name, p); fprintf(stderr, format_string, applet_name, p);
dealloc_usage_messages((char*)usage_string); dealloc_usage_messages((char*)usage_string);
#endif
} }
xfunc_die(); xfunc_die();
} }
@ -123,6 +146,9 @@ int find_applet_by_name(const char *name)
int *const bb_errno __attribute__ ((section (".data"))); int *const bb_errno __attribute__ ((section (".data")));
#endif #endif
void lbb_prepare(const char *applet
USE_FEATURE_INDIVIDUAL(, char **argv))
MAIN_EXTERNALLY_VISIBLE;
void lbb_prepare(const char *applet void lbb_prepare(const char *applet
USE_FEATURE_INDIVIDUAL(, char **argv)) USE_FEATURE_INDIVIDUAL(, char **argv))
{ {
@ -158,6 +184,9 @@ const char *applet_name;
bool re_execed; bool re_execed;
#endif #endif
#if !ENABLE_FEATURE_INDIVIDUAL
USE_FEATURE_SUID(static uid_t ruid;) /* real uid */ USE_FEATURE_SUID(static uid_t ruid;) /* real uid */
#if ENABLE_FEATURE_SUID_CONFIG #if ENABLE_FEATURE_SUID_CONFIG
@ -660,6 +689,9 @@ void run_applet_and_exit(const char *name, char **argv)
exit(busybox_main(argv)); exit(busybox_main(argv));
} }
#endif /* !ENABLE_FEATURE_INDIVIDUAL */
#if ENABLE_BUILD_LIBBUSYBOX #if ENABLE_BUILD_LIBBUSYBOX
int lbb_main(char **argv) int lbb_main(char **argv)
@ -667,6 +699,11 @@ int lbb_main(char **argv)
int main(int argc ATTRIBUTE_UNUSED, char **argv) int main(int argc ATTRIBUTE_UNUSED, char **argv)
#endif #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)); lbb_prepare("busybox" USE_FEATURE_INDIVIDUAL(, argv));
#if !BB_MMU #if !BB_MMU
@ -685,4 +722,5 @@ int main(int argc ATTRIBUTE_UNUSED, char **argv)
run_applet_and_exit(applet_name, argv); run_applet_and_exit(applet_name, argv);
bb_error_msg_and_die("applet not found"); bb_error_msg_and_die("applet not found");
#endif
} }

View File

@ -9,33 +9,6 @@
#include "libbb.h" #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, ...) void bb_error_msg_and_die(const char *s, ...)
{ {
va_list p; va_list p;

View File

@ -285,6 +285,10 @@ const char *const bb_argv_dash[] = { "-", NULL };
const char *opt_complementary; 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 { enum {
PARAM_STRING, PARAM_STRING,
PARAM_LIST, PARAM_LIST,
@ -335,7 +339,8 @@ getopt32(char **argv, const char *applet_opts, ...)
#define SHOW_USAGE_IF_ERROR 1 #define SHOW_USAGE_IF_ERROR 1
#define ALL_ARGV_IS_OPTS 2 #define ALL_ARGV_IS_OPTS 2
#define FIRST_ARGV_IS_OPT 4 #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; int spec_flgs = 0;
argc = 0; argc = 0;
@ -489,10 +494,16 @@ getopt32(char **argv, const char *applet_opts, ...)
va_end(p); va_end(p);
if (spec_flgs & FIRST_ARGV_IS_OPT) { 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]); argv[1] = xasprintf("-%s", argv[1]);
if (ENABLE_FEATURE_CLEAN_UP) if (ENABLE_FEATURE_CLEAN_UP)
spec_flgs |= FREE_FIRST_ARGV_IS_OPT; 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) if (spec_flgs & FREE_FIRST_ARGV_IS_OPT)
free(argv[1]); free(argv[1]);
#endif #endif

View File

@ -24,7 +24,6 @@
* This is needed to avoid collision with kill -9 ... syntax * 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) int kill_main(int argc, char **argv)
{ {
char *arg; char *arg;

View File

@ -36,7 +36,6 @@ endchoice
config ASH config ASH
bool "ash" bool "ash"
default n default n
select TEST
help help
Tha 'ash' shell adds about 60k in the default configuration and is Tha 'ash' shell adds about 60k in the default configuration and is
the most complete and most pedantically correct shell included with the most complete and most pedantically correct shell included with
@ -111,7 +110,6 @@ config ASH_GETOPTS
config ASH_BUILTIN_ECHO config ASH_BUILTIN_ECHO
bool "Builtin version of 'echo'" bool "Builtin version of 'echo'"
default y default y
select ECHO
depends on ASH depends on ASH
help help
Enable support for echo, builtin to ash. Enable support for echo, builtin to ash.
@ -119,7 +117,6 @@ config ASH_BUILTIN_ECHO
config ASH_BUILTIN_TEST config ASH_BUILTIN_TEST
bool "Builtin version of 'test'" bool "Builtin version of 'test'"
default y default y
select TEST
depends on ASH depends on ASH
help help
Enable support for test, builtin to ash. Enable support for test, builtin to ash.
@ -170,10 +167,6 @@ config ASH_EXPAND_PRMT
config HUSH config HUSH
bool "hush" bool "hush"
default n default n
select TRUE
select FALSE
select TEST
select ECHO
help help
hush is a very small shell (just 18k) and it has fairly complete hush is a very small shell (just 18k) and it has fairly complete
Bourne shell grammar. It even handles all the normal flow control Bourne shell grammar. It even handles all the normal flow control
@ -240,13 +233,9 @@ config LASH
help help
lash is deprecated and will be removed, please migrate to hush. lash is deprecated and will be removed, please migrate to hush.
config MSH config MSH
bool "msh" bool "msh"
default n default n
select TRUE
select FALSE
select TEST
help help
The minix shell (adds just 30k) is quite complete and handles things 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 like for/do/done, case/esac and all the things you expect a Bourne

View File

@ -8417,12 +8417,6 @@ returncmd(int argc ATTRIBUTE_UNUSED, char **argv)
static int breakcmd(int, char **); static int breakcmd(int, char **);
static int dotcmd(int, char **); static int dotcmd(int, char **);
static int evalcmd(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 exitcmd(int, char **);
static int exportcmd(int, char **); static int exportcmd(int, char **);
#if ENABLE_ASH_GETOPTS #if ENABLE_ASH_GETOPTS
@ -8464,6 +8458,9 @@ static int ulimitcmd(int, char **);
* Apart from the above, [[ expr ]] should work as [ expr ] * 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() */ /* Keep these in proper order since it is searched via bsearch() */
static const struct builtincmd builtintab[] = { static const struct builtincmd builtintab[] = {
{ BUILTIN_SPEC_REG ".", dotcmd }, { BUILTIN_SPEC_REG ".", dotcmd },
@ -11506,22 +11503,6 @@ exitcmd(int argc ATTRIBUTE_UNUSED, char **argv)
/* NOTREACHED */ /* 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. * Read a file containing shell functions.
*/ */