include/autoconf.h \
include/bbconfigopts.h \
include/usage_compressed.h \
+ include/applet_tables.h \
+ applets/usage \
.kernelrelease Module.symvers tags TAGS cscope*
# clean - Delete most, but leave enough to build external modules
obj-y += applets.o
hostprogs-y:=
-hostprogs-y += usage
+hostprogs-y += usage applet_tables
always:= $(hostprogs-y)
HOSTCFLAGS_usage.o = -I$(srctree)/include
-applets/applets.o: include/usage_compressed.h
+applets/applets.o: include/usage_compressed.h include/applet_tables.h
+
applets/usage: .config $(srctree)/applets/usage_compressed
+
include/usage_compressed.h: applets/usage $(srctree)/applets/usage_compressed
$(call cmd,gen_usage_compressed)
+
+# Two-stage file creation, to avoid having target file still created
+# in case applet_tables fails
+include/applet_tables.h: applets/applet_tables
+ applets/applet_tables >include/applet_tables.h.tmp
+ mv include/applet_tables.h.tmp include/applet_tables.h
/*
* Stub for linking busybox binary against libbusybox.
*
- * Copyright (C) 2007 Denis Vlasenko
+ * Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com>
*
* Licensed under GPLv2, see file License in this tarball for details.
*/
# define APPLET_NOFORK(name,main,l,s,name2) LINK l name
#else
- const struct bb_applet applets[] = { /* name, main, location, need_suid */
-# define APPLET(name,l,s) { #name, name##_main USE_FEATURE_INSTALLER(,l) USE_FEATURE_SUID(,s) },
-# define APPLET_NOUSAGE(name,main,l,s) { #name, main##_main USE_FEATURE_INSTALLER(,l) USE_FEATURE_SUID(,s) },
-# define APPLET_ODDNAME(name,main,l,s,name2) { #name, main##_main USE_FEATURE_INSTALLER(,l) USE_FEATURE_SUID(,s) },
-# define APPLET_NOEXEC(name,main,l,s,name2) { #name, main##_main USE_FEATURE_INSTALLER(,l) USE_FEATURE_SUID(,s) USE_FEATURE_PREFER_APPLETS(,1) },
-# define APPLET_NOFORK(name,main,l,s,name2) { #name, main##_main USE_FEATURE_INSTALLER(,l) USE_FEATURE_SUID(,s) USE_FEATURE_PREFER_APPLETS(,1 ,1) },
+ static struct bb_applet applets[] = { /* name, main, location, need_suid */
+# define APPLET(name,l,s) { #name, #name, l, s },
+# define APPLET_NOUSAGE(name,main,l,s) { #name, #main, l, s },
+# define APPLET_ODDNAME(name,main,l,s,name2) { #name, #main, l, s },
+# define APPLET_NOEXEC(name,main,l,s,name2) { #name, #main, l, s, 1 },
+# define APPLET_NOFORK(name,main,l,s,name2) { #name, #main, l, s, 1, 1 },
#endif
#if ENABLE_INSTALL_NO_USR
USE_ZCIP(APPLET(zcip, _BB_DIR_SBIN, _BB_SUID_NEVER))
#if !defined(PROTOTYPES) && !defined(NAME_MAIN_CNAME) && !defined(MAKE_USAGE)
- { NULL }
};
#endif
#include "libbb.h"
-#if ENABLE_FEATURE_INSTALLER
-/* order matters: used as index into "install_dir[]" in busybox.c */
+/* order matters: used as index into "install_dir[]" in appletlib.c */
typedef enum bb_install_loc_t {
_BB_DIR_ROOT = 0,
_BB_DIR_BIN,
_BB_DIR_USR_BIN,
_BB_DIR_USR_SBIN
} bb_install_loc_t;
-#endif
-#if ENABLE_FEATURE_SUID
typedef enum bb_suid_t {
_BB_SUID_NEVER = 0,
_BB_SUID_MAYBE,
_BB_SUID_ALWAYS
} bb_suid_t;
-#endif
-struct bb_applet {
- const char *name;
- int (*main) (int argc, char **argv);
-#if ENABLE_FEATURE_INSTALLER
- __extension__ enum bb_install_loc_t install_loc:8;
+
+/* Defined in appletlib.c (by including generated applet_tables.h) */
+/* Keep in sync with applets/applet_tables.c! */
+extern const char applet_names[];
+extern int (*const applet_mains[])(int argc, char **argv);
+
+#if ENABLE_FEATURE_INSTALLER || ENABLE_FEATURE_PREFER_APPLETS
+extern const uint32_t applet_nameofs[];
+#else
+extern const uint16_t applet_nameofs[];
#endif
+
#if ENABLE_FEATURE_SUID
- __extension__ enum bb_suid_t need_suid:8;
+#define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x3fff))
+#define APPLET_SUID(i) ((applet_nameofs[i] >> 14) & 0x3)
+#else
+#define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0xffff))
#endif
-#if ENABLE_FEATURE_PREFER_APPLETS
- /* true if instead of fork(); exec("applet"); waitpid();
- * one can do fork(); exit(applet_main(argc,argv)); waitpid(); */
- unsigned char noexec;
- /* Even nicer */
- /* true if instead of fork(); exec("applet"); waitpid();
- * one can simply call applet_main(argc,argv); */
- unsigned char nofork;
+
+#if ENABLE_FEATURE_INSTALLER
+#define APPLET_INSTALL_LOC(i) ((applet_nameofs[i] >> 16) & 0x7)
#endif
-};
+#if ENABLE_FEATURE_PREFER_APPLETS
+#define APPLET_IS_NOFORK(i) (applet_nameofs[i] & (1 << 19))
+#define APPLET_IS_NOEXEC(i) (applet_nameofs[i] & (1 << 20))
+#endif
-/* Defined in appletlib.c */
-extern const struct bb_applet applets[];
-extern const unsigned short NUM_APPLETS;
/* Length of these names has effect on size of libbusybox
* and "individual" binaries. Keep them short.
enum { USERNAME_MAX_SIZE = 16 - sizeof(int) };
-struct bb_applet;
int execable_file(const char *name);
char *find_execable(const char *filename);
int exists_execable(const char *filename);
int bb_execvp(const char *file, char *const argv[]);
#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd)
#define BB_EXECLP(prog,cmd,...) \
- execlp((find_applet_by_name(prog)) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \
+ execlp((find_applet_by_name(prog) >= 0) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \
cmd, __VA_ARGS__)
#else
#define BB_EXECVP(prog,cmd) execvp(prog,cmd)
void save_nofork_data(struct nofork_save_area *save);
void restore_nofork_data(struct nofork_save_area *save);
/* Does NOT check that applet is NOFORK, just blindly runs it */
-int run_nofork_applet(const struct bb_applet *a, char **argv);
-int run_nofork_applet_prime(struct nofork_save_area *old, const struct bb_applet *a, char **argv);
+int run_nofork_applet(int applet_no, char **argv);
+int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv);
/* Helpers for daemonization.
*
#ifndef BUILD_INDIVIDUAL
-extern const struct bb_applet *find_applet_by_name(const char *name);
+extern int find_applet_by_name(const char *name);
/* Returns only if applet is not found. */
extern void run_applet_and_exit(const char *name, char **argv);
-extern void run_appletstruct_and_exit(const struct bb_applet *a, char **argv) ATTRIBUTE_NORETURN;
+extern void run_applet_no_and_exit(int a, char **argv) ATTRIBUTE_NORETURN;
#endif
extern int match_fstype(const struct mntent *mt, const char *fstypes);
#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;
-#endif
+/* Include generated applet names, pointers to <apllet>_main, etc */
+#include "applet_tables.h"
#if ENABLE_FEATURE_COMPRESS_USAGE
const char *format_string;
const char *p;
const char *usage_string = p = unpack_usage_messages();
- const struct bb_applet *ap = find_applet_by_name(applet_name);
- int i;
+ int ap = find_applet_by_name(applet_name);
- if (!ap) /* never happens, paranoia */
+ if (ap < 0) /* never happens, paranoia */
xfunc_die();
- i = ap - applets;
- while (i) {
+ while (ap) {
while (*p++) continue;
- i--;
+ ap--;
}
fprintf(stderr, "%s multi-call binary\n", bb_banner);
}
-static int applet_name_compare(const void *name, const void *vapplet)
+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)
+int find_applet_by_name(const char *name)
{
+ const char *p;
/* 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);
+
+ /* NB: any char pointer will work as well, not necessarily applet_names */
+ p = bsearch(name, applet_names, ARRAY_SIZE(applet_mains), 1, applet_name_compare);
+ if (!p)
+ return -1;
+ return p - applet_names;
}
/* 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;
* 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;
}
goto check_need_suid;
#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("must be suid to work properly");
- } else if (applet->need_suid == _BB_SUID_NEVER) {
+ } 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;
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_mains); i++) {
fpc = concat_path_file(
- install_dir[applets[i].install_loc],
- applets[i].name);
+ install_dir[APPLET_INSTALL_LOC(i)],
+ APPLET_NAME(i));
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;
+ const char *a;
int col, output_width;
help:
output_width = 80;
"\twill act like whatever it was invoked as!\n"
"\nCurrently defined functions:\n");
col = 0;
- a = applets;
- while (a->name) {
+ a = applet_names;
+ while (*a) {
if (col > output_width) {
puts(",");
col = 0;
}
- col += printf("%s%s", (col ? ", " : "\t"), a->name);
- a++;
+ col += printf("%s%s", (col ? ", " : "\t"), a);
+ a += strlen(a) + 1;
}
puts("\n");
return 0;
bb_error_msg_and_die("applet not found");
}
-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;
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_mains[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));
}
*/
int bb_execvp(const char *file, char *const argv[])
{
- return execvp(find_applet_by_name(file) ? bb_busybox_exec_path : file,
+ return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file,
argv);
}
#endif
*/
#include <paths.h>
-#include "busybox.h" /* for struct bb_applet */
+#include "busybox.h" /* uses applet tables */
/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
* -1 for failure. Runs argv[0], searching path if that has no / in it. */
die_sleep = save->die_sleep;
}
-int run_nofork_applet_prime(struct nofork_save_area *old, const struct bb_applet *a, char **argv)
+int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv)
{
int rc, argc;
- applet_name = a->name;
+ applet_name = APPLET_NAME(applet_no);
xfunc_error_retval = EXIT_FAILURE;
/*option_mask32 = 0; - not needed */
/* special flag for xfunc_die(). If xfunc will "die"
char *tmp_argv[argc+1];
memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
/* Finally we can call NOFORK applet's main() */
- rc = a->main(argc, tmp_argv);
+ rc = applet_mains[applet_no](argc, tmp_argv);
} else { /* xfunc died in NOFORK applet */
/* in case they meant to return 0... */
if (rc == -2222)
return rc;
}
-int run_nofork_applet(const struct bb_applet *a, char **argv)
+int run_nofork_applet(int applet_no, char **argv)
{
struct nofork_save_area old;
/* Saving globals */
save_nofork_data(&old);
- return run_nofork_applet_prime(&old, a, argv);
+ return run_nofork_applet_prime(&old, applet_no, argv);
}
#endif /* FEATURE_PREFER_APPLETS */
{
int rc;
#if ENABLE_FEATURE_PREFER_APPLETS
- const struct bb_applet *a = find_applet_by_name(argv[0]);
+ int a = find_applet_by_name(argv[0]);
- if (a && (a->nofork
+ if (a >= 0 && (APPLET_IS_NOFORK(a)
#if BB_MMU
- || a->noexec /* NOEXEC trick needs fork() */
+ || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */
#endif
)) {
#if BB_MMU
- if (a->nofork)
+ if (APPLET_IS_NOFORK(a))
#endif
{
return run_nofork_applet(a, argv);
return wait4pid(rc);
/* child */
xfunc_error_retval = EXIT_FAILURE;
- run_appletstruct_and_exit(a, argv);
+ run_applet_no_and_exit(a, argv);
#endif
}
#endif /* FEATURE_PREFER_APPLETS */
#if DEBUG
#define _GNU_SOURCE
#endif
-#include "busybox.h" /* for struct bb_applet */
+#include "busybox.h" /* for applet_names */
#include <paths.h>
#include <setjmp.h>
#include <fnmatch.h>
#if ENABLE_FEATURE_SH_STANDALONE
if (strchr(cmd, '/') == NULL) {
- const struct bb_applet *a;
-
- a = find_applet_by_name(cmd);
- if (a) {
- if (a->noexec)
- run_appletstruct_and_exit(a, argv);
+ int a = find_applet_by_name(cmd);
+ if (a >= 0) {
+ if (APPLET_IS_NOEXEC(a))
+ run_applet_no_and_exit(a, argv);
/* re-exec ourselves with the new arguments */
execve(bb_busybox_exec_path, argv, envp);
/* If they called chroot or otherwise made the binary no longer
envp = environment();
if (strchr(argv[0], '/')
#if ENABLE_FEATURE_SH_STANDALONE
- || find_applet_by_name(argv[0])
+ || find_applet_by_name(argv[0]) >= 0
#endif
) {
tryexec(argv[0], argv, envp);
}
#if ENABLE_FEATURE_SH_STANDALONE
- if (find_applet_by_name(name)) {
+ if (find_applet_by_name(name) >= 0) {
entry->cmdtype = CMDNORMAL;
entry->u.index = -1;
return;
}
}
#if ENABLE_FEATURE_SH_STANDALONE
- for (i = 0; i < NUM_APPLETS; i++) {
- col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
- if (col > 60) {
- out1fmt("\n");
- col = 0;
+ {
+ const char *a = applet_names;
+ while (*a) {
+ col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
+ if (col > 60) {
+ out1fmt("\n");
+ col = 0;
+ }
+ a += strlen(a) + 1;
}
}
#endif
extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
-#include "busybox.h" /* for struct bb_applet */
+#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
#if !BB_MMU
/* Check if the command matches any busybox applets */
#if ENABLE_FEATURE_SH_STANDALONE
if (strchr(argv[0], '/') == NULL) {
- const struct bb_applet *a = find_applet_by_name(argv[0]);
- if (a) {
- if (a->noexec) {
+ int a = find_applet_by_name(argv[0]);
+ if (a >= 0) {
+ if (APPLET_IS_NOEXEC(a)) {
debug_printf_exec("running applet '%s'\n", argv[0]);
-// is it ok that run_appletstruct_and_exit() does exit(), not _exit()?
- run_appletstruct_and_exit(a, argv);
+// is it ok that run_applet_no_and_exit() does exit(), not _exit()?
+ run_applet_no_and_exit(a, argv);
}
/* re-exec ourselves with the new arguments */
debug_printf_exec("re-execing applet '%s'\n", argv[0]);
}
#if ENABLE_FEATURE_SH_STANDALONE
{
- const struct bb_applet *a = find_applet_by_name(argv[i]);
- if (a && a->nofork) {
+ int a = find_applet_by_name(argv[i]);
+ if (a >= 0 && APPLET_IS_NOFORK(a)) {
setup_redirects(child, squirrel);
save_nofork_data(&nofork_save);
argv_expanded = argv + i;
#include <getopt.h>
#include <glob.h>
-#include "busybox.h" /* for struct bb_applet */
+#include "libbb.h"
#define expand_t glob_t
}
#if ENABLE_FEATURE_SH_STANDALONE
{
- const struct bb_applet *a = find_applet_by_name(child->argv[i]);
- if (a && a->nofork) {
+ int a = find_applet_by_name(child->argv[i]);
+ if (a >= 0 && APPLET_IS_NOFORK(a)) {
setup_redirects(child, squirrel);
rcode = run_nofork_applet(a, child->argv + i);
restore_redirects(squirrel);
# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
-static char *find_applet_by_name(const char *applet)
+static int find_applet_by_name(const char *applet)
{
- return NULL;
+ return -1;
}
static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
{
return local_buf;
}
#else
-# include "busybox.h"
+# include "busybox.h" /* for applet_names */
extern char **environ;
#endif
char *name = c;
if (ENABLE_FEATURE_SH_STANDALONE) {
- if (find_applet_by_name(name)) {
+ if (find_applet_by_name(name) >= 0) {
/* We have to exec here since we vforked. Running
* run_applet_and_exit() won't work and bad things
* will happen. */
}
#if ENABLE_FEATURE_SH_STANDALONE
{
- const struct bb_applet *applet = applets;
+ const char *applet = applet_names;
- while (applet->name) {
- col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet->name);
+ while (*applet) {
+ col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
if (col > 60) {
bb_putchar('\n');
col = 0;
}
- applet++;
+ applet += strlen(applet) + 1;
}
}
#endif