* Licensed under GPLv2 or later, see file License in this tarball for details.
*/
+/* We are trying to not use printf, this benefits the case when selected
+ * applets are really simple. Example:
+ *
+ * $ ./busybox
+ * ...
+ * Currently defined functions:
+ * basename, false, true
+ *
+ * $ size busybox
+ * text data bss dec hex filename
+ * 4473 52 72 4597 11f5 busybox
+ *
+ * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :(
+ */
+
#include <assert.h>
#include "busybox.h"
#define usage_messages 0
#endif /* SHOW_USAGE */
-/* Define struct bb_applet applets[] */
-#include "applets.h"
-#if ENABLE_FEATURE_SH_STANDALONE
-/* -1 because last entry is NULL */
-const unsigned short NUM_APPLETS = ARRAY_SIZE(applets) - 1;
+/* 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
i = start_bunzip(&bd,
/* src_fd: */ -1,
- /* inbuf: */ packed_usage,
+ /* inbuf: */ (void *)packed_usage,
/* len: */ sizeof(packed_usage));
/* read_bunzip can longjmp to start_bunzip, and ultimately
* end up here with i != 0 on read data errors! Not trivial */
#endif /* FEATURE_COMPRESS_USAGE */
+static void full_write2_str(const char *str)
+{
+ full_write(STDERR_FILENO, str, strlen(str));
+}
+
void bb_show_usage(void)
{
if (ENABLE_SHOW_USAGE) {
- const char *format_string;
+#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();
- const struct bb_applet *ap = find_applet_by_name(applet_name);
- int i;
- if (!ap) /* never happens, paranoia */
- xfunc_die();
+ if (*p == '\b') {
+ full_write2_str("\nNo help available.\n\n");
+ } else {
+ full_write2_str("\nUsage: "SINGLE_APPLET_STR" ");
+ full_write2_str(p);
+ full_write2_str("\n\n");
+ }
+ dealloc_usage_messages((char*)usage_string);
+#else
+ const char *p;
+ const char *usage_string = p = unpack_usage_messages();
+ int ap = find_applet_by_name(applet_name);
- i = ap - applets;
- while (i) {
+ if (ap < 0) /* never happens, paranoia */
+ xfunc_die();
+ while (ap) {
while (*p++) continue;
- i--;
+ ap--;
}
-
- fprintf(stderr, "%s multi-call binary\n", bb_banner);
- format_string = "\nUsage: %s %s\n\n";
+ full_write2_str(bb_banner);
+ full_write2_str(" multi-call binary\n");
if (*p == '\b')
- format_string = "\nNo help available.\n\n";
- fprintf(stderr, format_string, applet_name, p);
+ full_write2_str("\nNo help available.\n\n");
+ else {
+ full_write2_str("\nUsage: ");
+ full_write2_str(applet_name);
+ full_write2_str(" ");
+ full_write2_str(p);
+ full_write2_str("\n\n");
+ }
dealloc_usage_messages((char*)usage_string);
+#endif
}
xfunc_die();
}
-
-static int applet_name_compare(const void *name, const void *vapplet)
+#if NUM_APPLETS > 8
+/* NB: any char pointer will work as well, not necessarily applet_names */
+static int applet_name_compare(const void *name, const void *v)
{
- const struct bb_applet *applet = vapplet;
-
- return strcmp(name, applet->name);
+ int i = (const char *)v - applet_names;
+ return strcmp(name, APPLET_NAME(i));
}
-
-const struct bb_applet *find_applet_by_name(const char *name)
+#endif
+int find_applet_by_name(const char *name)
{
+#if NUM_APPLETS > 8
/* Do a binary search to find the applet entry given the name. */
- return bsearch(name, applets, ARRAY_SIZE(applets)-1, sizeof(applets[0]),
- applet_name_compare);
+ const char *p;
+ p = bsearch(name, applet_names, ARRAY_SIZE(applet_main), 1, applet_name_compare);
+ if (!p)
+ return -1;
+ return p - applet_names;
+#else
+ /* A version which does not pull in bsearch */
+ int i = 0;
+ const char *p = applet_names;
+ while (i < NUM_APPLETS) {
+ if (strcmp(name, p) == 0)
+ return i;
+ p += strlen(p) + 1;
+ i++;
+ }
+ return -1;
+#endif
}
-#ifdef __GLIBC__
-/* Make it reside in R/W memory: */
-int *const bb_errno __attribute__ ((section (".data")));
-#endif
-
-void lbb_prepare(char **argv)
+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))
{
#ifdef __GLIBC__
(*(int **)&bb_errno) = __errno_location();
+ barrier();
#endif
+ applet_name = applet;
/* Set locale for everybody except 'init' */
if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
bool re_execed;
#endif
+
+/* If not built as a single-applet executable... */
+#if !defined(SINGLE_APPLET_MAIN)
+
USE_FEATURE_SUID(static uid_t ruid;) /* real uid */
#if ENABLE_FEATURE_SUID_CONFIG
/* applets[] is const, so we have to define this "override" structure */
static struct BB_suid_config {
- const struct bb_applet *m_applet;
+ int m_applet;
uid_t m_uid;
gid_t m_gid;
mode_t m_mode;
{
struct BB_suid_config *sct_head;
struct BB_suid_config *sct;
- const struct bb_applet *applet;
+ int applet_no;
FILE *f;
const char *errmsg;
char *s;
s = buffer;
if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */
+// why?
if (ferror(f)) { /* Make sure it wasn't a read error. */
parse_error("reading");
}
* applet is currently built in and ignore it otherwise.
* Note: this can hide config file bugs which only pop
* up when the busybox configuration is changed. */
- applet = find_applet_by_name(s);
- if (applet) {
+ applet_no = find_applet_by_name(s);
+ if (applet_no >= 0) {
/* Note: We currently don't check for duplicates!
* The last config line for each applet will be the
* one used since we insert at the head of the list.
* I suppose this could be considered a feature. */
sct = xmalloc(sizeof(struct BB_suid_config));
- sct->m_applet = applet;
+ sct->m_applet = applet_no;
sct->m_mode = 0;
sct->m_next = sct_head;
sct_head = sct;
#if ENABLE_FEATURE_SUID
-static void check_suid(const struct bb_applet *applet)
+static void check_suid(int applet_no)
{
gid_t rgid; /* real gid */
mode_t m;
for (sct = suid_config; sct; sct = sct->m_next) {
- if (sct->m_applet == applet)
+ if (sct->m_applet == applet_no)
goto found;
}
- /* default: drop all privileges */
- xsetgid(rgid);
- xsetuid(ruid);
- return;
+ goto check_need_suid;
found:
m = sct->m_mode;
if (sct->m_uid == ruid)
}
}
#endif
+ check_need_suid:
#endif
-
- if (applet->need_suid == _BB_SUID_ALWAYS) {
+ if (APPLET_SUID(applet_no) == _BB_SUID_ALWAYS) {
/* Real uid is not 0. If euid isn't 0 too, suid bit
* is most probably not set on our executable */
if (geteuid())
- bb_error_msg_and_die("applet requires root privileges!");
- } else if (applet->need_suid == _BB_SUID_NEVER) {
+ bb_error_msg_and_die("must be suid to work properly");
+ } else if (APPLET_SUID(applet_no) == _BB_SUID_NEVER) {
xsetgid(rgid); /* drop all privileges */
xsetuid(ruid);
}
usr_sbin
};
- int (*lf)(const char *, const char *) = link;
+ int (*lf)(const char *, const char *);
char *fpc;
- int i;
+ unsigned i;
int rc;
+ lf = link;
if (use_symbolic_links)
lf = symlink;
- for (i = 0; applets[i].name != NULL; i++) {
+ for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
fpc = concat_path_file(
- install_dir[applets[i].install_loc],
- applets[i].name);
+ install_dir[APPLET_INSTALL_LOC(i)],
+ APPLET_NAME(i));
+ // 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);
{
if (!argv[1]) {
/* Called without arguments */
- const struct bb_applet *a;
- int col, output_width;
+ const char *a;
+ unsigned col, output_width;
help:
output_width = 80;
if (ENABLE_FEATURE_AUTOWIDTH) {
get_terminal_width_height(0, &output_width, NULL);
}
/* leading tab and room to wrap */
- output_width -= sizeof("start-stop-daemon, ") + 8;
-
- printf("%s multi-call binary\n", bb_banner); /* reuse const string... */
- printf("Copyright (C) 1998-2006 Erik Andersen, Rob Landley, and others.\n"
- "Licensed under GPLv2. See source distribution for full notice.\n"
+ output_width -= MAX_APPLET_NAME_LEN + 8;
+
+ dup2(1, 2);
+ full_write2_str(bb_banner); /* reuse const string... */
+ full_write2_str(" multi-call binary\n"
+ "Copyright (C) 1998-2008 Erik Andersen, Rob Landley, Denys Vlasenko\n"
+ "and others. Licensed under GPLv2.\n"
+ "See source distribution for full notice.\n"
"\n"
"Usage: busybox [function] [arguments]...\n"
- " or: [function] [arguments]...\n"
+ " or: function [arguments]...\n"
"\n"
"\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"
- "\nCurrently defined functions:\n");
+ "\n"
+ "Currently defined functions:\n");
col = 0;
- a = applets;
- while (a->name) {
+ a = applet_names;
+ while (*a) {
+ int len;
if (col > output_width) {
- puts(",");
+ full_write2_str(",\n");
col = 0;
}
- col += printf("%s%s", (col ? ", " : "\t"), a->name);
- a++;
+ full_write2_str(col ? ", " : "\t");
+ full_write2_str(a);
+ len = strlen(a);
+ col += len + 2;
+ a += len + 1;
}
- puts("\n");
+ full_write2_str("\n\n");
return 0;
}
* "#!/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");
+
+ /*bb_error_msg_and_die("applet not found"); - sucks in printf */
+ full_write2_str(applet_name);
+ full_write2_str(": applet not found\n");
+ xfunc_die();
}
-void run_appletstruct_and_exit(const struct bb_applet *applet, char **argv)
+void run_applet_no_and_exit(int applet_no, char **argv)
{
int argc = 1;
argc++;
/* Reinit some shared global data */
- optind = 1;
xfunc_error_retval = EXIT_FAILURE;
- applet_name = applet->name;
+ applet_name = APPLET_NAME(applet_no);
if (argc == 2 && !strcmp(argv[1], "--help"))
bb_show_usage();
if (ENABLE_FEATURE_SUID)
- check_suid(applet);
- exit(applet->main(argc, argv));
+ check_suid(applet_no);
+ exit(applet_main[applet_no](argc, argv));
}
void run_applet_and_exit(const char *name, char **argv)
{
- const struct bb_applet *applet = find_applet_by_name(name);
- if (applet)
- run_appletstruct_and_exit(applet, argv);
+ int applet = find_applet_by_name(name);
+ if (applet >= 0)
+ run_applet_no_and_exit(applet, argv);
if (!strncmp(name, "busybox", 7))
exit(busybox_main(argv));
}
+#endif /* !defined(SINGLE_APPLET_MAIN) */
+
+
#if ENABLE_BUILD_LIBBUSYBOX
-int lbb_main(int argc, char **argv)
+int lbb_main(char **argv)
#else
-int main(int argc, char **argv)
+int main(int argc ATTRIBUTE_UNUSED, char **argv)
#endif
{
- lbb_prepare(argv);
+#if defined(SINGLE_APPLET_MAIN)
+ /* Only one applet is selected by the user! */
+ /* applet_names in this case is just "applet\0\0" */
+ lbb_prepare(applet_names USE_FEATURE_INDIVIDUAL(, argv));
+ return SINGLE_APPLET_MAIN(argc, argv);
+#else
+ lbb_prepare("busybox" USE_FEATURE_INDIVIDUAL(, argv));
#if !BB_MMU
/* NOMMU re-exec trick sets high-order bit in first byte of name */
parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */
run_applet_and_exit(applet_name, argv);
- bb_error_msg_and_die("applet not found");
+
+ /*bb_error_msg_and_die("applet not found"); - sucks in printf */
+ full_write2_str(applet_name);
+ full_write2_str(": applet not found\n");
+ xfunc_die();
+#endif
}