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
/* 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);
}
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
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
/* 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;
}
/* 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;
/* 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;
/* 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 */
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
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
/* 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
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();
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();
}
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))
{
bool re_execed;
#endif
+
+#if !ENABLE_FEATURE_INDIVIDUAL
+
USE_FEATURE_SUID(static uid_t ruid;) /* real uid */
#if ENABLE_FEATURE_SUID_CONFIG
exit(busybox_main(argv));
}
+#endif /* !ENABLE_FEATURE_INDIVIDUAL */
+
+
#if ENABLE_BUILD_LIBBUSYBOX
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
run_applet_and_exit(applet_name, argv);
bb_error_msg_and_die("applet not found");
+#endif
}
#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;
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,
#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;
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
}
}
}
}
-#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
* 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;
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
config ASH_BUILTIN_ECHO
bool "Builtin version of 'echo'"
default y
- select ECHO
depends on ASH
help
Enable support for echo, builtin to ash.
config ASH_BUILTIN_TEST
bool "Builtin version of 'test'"
default y
- select TEST
depends on ASH
help
Enable support for test, builtin to ash.
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
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
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
* 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 },
/* 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.
*/