From f5294e1f4c56afb377ada95a7757b28ad3c89086 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sat, 14 Apr 2007 10:09:57 +0000 Subject: [PATCH] hush: use NOFORK applets as appropriate. Net reduction of code size. --- applets/applets.c | 30 ++++++++----- findutils/xargs.c | 4 +- include/libbb.h | 64 +++++++++++++-------------- libbb/vfork_daemon_rexec.c | 89 ++++++++++++++++++++------------------ shell/ash.c | 4 +- shell/hush.c | 41 ++++++++++-------- shell/lash.c | 7 +-- 7 files changed, 125 insertions(+), 114 deletions(-) diff --git a/applets/applets.c b/applets/applets.c index 82a7eeea1..fb37fbea5 100644 --- a/applets/applets.c +++ b/applets/applets.c @@ -514,14 +514,14 @@ static void install_links(const char *busybox, int use_symbolic_links) /* If we were called as "busybox..." */ -static int busybox_main(int argc, char **argv) +static int busybox_main(char **argv) { - if (ENABLE_FEATURE_INSTALLER && argc > 1 && !strcmp(argv[1], "--install")) { + if (ENABLE_FEATURE_INSTALLER && argv[1] && !strcmp(argv[1], "--install")) { int use_symbolic_links = 0; char *busybox; /* to use symlinks, or not to use symlinks... */ - if (argc > 2) + if (argv[2]) if (strcmp(argv[2], "-s") == 0) use_symbolic_links = 1; @@ -537,11 +537,12 @@ static int busybox_main(int argc, char **argv) /* Deal with --help. Also print help when called with no arguments */ - if (argc == 1 || !strcmp(argv[1], "--help") ) { - if (argc > 2) { + if (!argv[1] || !strcmp(argv[1], "--help") ) { + if (argv[2]) { /* set name for proper ": applet not found" */ applet_name = argv[2]; - run_applet_and_exit(applet_name, 2, argv); + argv[2] = NULL; + run_applet_and_exit(applet_name, argv); } else { const struct bb_applet *a; int col, output_width; @@ -582,14 +583,19 @@ static int busybox_main(int argc, char **argv) } else { /* we want ": applet not found", not "busybox: ..." */ applet_name = argv[1]; - run_applet_and_exit(argv[1], argc - 1, argv + 1); + run_applet_and_exit(argv[1], argv + 1); } bb_error_msg_and_die("applet not found"); } -void run_current_applet_and_exit(int argc, char **argv) +void run_current_applet_and_exit(char **argv) { + int argc = 1; + + while (argv[argc]) + argc++; + /* Reinit some shared global data */ optind = 1; xfunc_error_retval = EXIT_FAILURE; @@ -602,13 +608,13 @@ void run_current_applet_and_exit(int argc, char **argv) exit(current_applet->main(argc, argv)); } -void run_applet_and_exit(const char *name, int argc, char **argv) +void run_applet_and_exit(const char *name, char **argv) { current_applet = find_applet_by_name(name); if (current_applet) - run_current_applet_and_exit(argc, argv); + run_current_applet_and_exit(argv); if (!strncmp(name, "busybox", 7)) - exit(busybox_main(argc, argv)); + exit(busybox_main(argv)); } @@ -637,6 +643,6 @@ int main(int argc, char **argv) if (ENABLE_LOCALE_SUPPORT && getpid() != 1) setlocale(LC_ALL, ""); - run_applet_and_exit(applet_name, argc, argv); + run_applet_and_exit(applet_name, argv); bb_error_msg_and_die("applet not found"); } diff --git a/findutils/xargs.c b/findutils/xargs.c index a430e5f3d..b90f44ca4 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c @@ -176,7 +176,7 @@ set: } if (!eof_str_detected) { size_t length = (p - buf); - +// TODO: smarter llist_t cur = xzalloc(sizeof(xlist_t) + length); cur->data = memcpy(cur + 1, s, length); cur->length = length; @@ -247,6 +247,7 @@ static xlist_t *process_stdin(xlist_t *list_arg, size_t length = (p - buf); cur = xzalloc(sizeof(xlist_t) + length); +// TODO: smarter llist_t cur->data = memcpy(cur + 1, s, length); cur->length = length; /*cur->link = NULL;*/ @@ -329,6 +330,7 @@ static xlist_t *process0_stdin(xlist_t *list_arg, size_t length = (p - buf); cur = xzalloc(sizeof(xlist_t) + length); +// TODO: smarter llist_t cur->data = memcpy(cur + 1, s, length); cur->length = length; /*cur->link = NULL;*/ diff --git a/include/libbb.h b/include/libbb.h index 212b048de..77f1e0a44 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -123,35 +123,6 @@ /* scary. better ideas? (but do *test* them first!) */ #define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1))) -/* This structure defines protocol families and their handlers. */ -struct aftype { - const char *name; - const char *title; - int af; - int alen; - char *(*print) (unsigned char *); - const char *(*sprint) (struct sockaddr *, int numeric); - int (*input) (/*int type,*/ const char *bufp, struct sockaddr *); - void (*herror) (char *text); - int (*rprint) (int options); - int (*rinput) (int typ, int ext, char **argv); - - /* may modify src */ - int (*getmask) (char *src, struct sockaddr * mask, char *name); -}; - -/* This structure defines hardware protocols and their handlers. */ -struct hwtype { - const char *name; - const char *title; - int type; - int alen; - char *(*print) (unsigned char *); - int (*input) (const char *, struct sockaddr *); - int (*activate) (int fd); - int suppress_null_addr; -}; - /* Some useful definitions */ #undef FALSE #define FALSE ((int) 0) @@ -504,6 +475,7 @@ void clear_username_cache(void); 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); @@ -537,6 +509,8 @@ int wait_nohang(int *wstat); #define wait_exitcode(w) ((w) >> 8) #define wait_stopsig(w) ((w) >> 8) #define wait_stopped(w) (((w) & 127) == 127) +/* Does NOT check that applet is NOFORK, just blindly runs it */ +int run_nofork_applet(const struct bb_applet *a, char **argv); /* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */ int spawn_and_wait(char **argv); @@ -669,6 +643,33 @@ int bbunpack(char **argv, int create_icmp_socket(void); int create_icmp6_socket(void); /* interface.c */ +/* This structure defines protocol families and their handlers. */ +struct aftype { + const char *name; + const char *title; + int af; + int alen; + char *(*print) (unsigned char *); + const char *(*sprint) (struct sockaddr *, int numeric); + int (*input) (/*int type,*/ const char *bufp, struct sockaddr *); + void (*herror) (char *text); + int (*rprint) (int options); + int (*rinput) (int typ, int ext, char **argv); + + /* may modify src */ + int (*getmask) (char *src, struct sockaddr * mask, char *name); +}; +/* This structure defines hardware protocols and their handlers. */ +struct hwtype { + const char *name; + const char *title; + int type; + int alen; + char *(*print) (unsigned char *); + int (*input) (const char *, struct sockaddr *); + int (*activate) (int fd); + int suppress_null_addr; +}; extern int interface_opt_a; int display_interfaces(char *ifname); const struct aftype *get_aftype(const char *name); @@ -677,11 +678,10 @@ const struct hwtype *get_hwntype(int type); #ifndef BUILD_INDIVIDUAL -struct bb_applet; extern const struct bb_applet *find_applet_by_name(const char *name); /* Returns only if applet is not found. */ -extern void run_applet_and_exit(const char *name, int argc, char **argv); -extern void run_current_applet_and_exit(int argc, char **argv) ATTRIBUTE_NORETURN; +extern void run_applet_and_exit(const char *name, char **argv); +extern void run_current_applet_and_exit(char **argv) ATTRIBUTE_NORETURN; #endif extern int match_fstype(const struct mntent *mt, const char *fstypes); diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 7dbc152e2..78f3c4ad4 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -100,6 +100,52 @@ int wait_pid(int *wstat, int pid) return r; } +int run_nofork_applet(const struct bb_applet *a, char **argv) +{ + int rc, argc; + + /* Save some shared globals */ + const struct bb_applet *old_a = current_applet; + int old_x = xfunc_error_retval; + uint32_t old_m = option_mask32; + int old_sleep = die_sleep; + + current_applet = a; + applet_name = a->name; + xfunc_error_retval = EXIT_FAILURE; + /*option_mask32 = 0; - not needed */ + /* special flag for xfunc_die(). If xfunc will "die" + * in NOFORK applet, xfunc_die() sees negative + * die_sleep and longjmp here instead. */ + die_sleep = -1; + + argc = 1; + while (argv[argc]) + argc++; + + rc = setjmp(die_jmp); + if (!rc) { + /* Some callers (xargs) + * need argv untouched because they free argv[i]! */ + 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); + } else { /* xfunc died in NOFORK applet */ + /* in case they meant to return 0... */ + if (rc == -111) + rc = 0; + } + + /* Restoring globals */ + current_applet = old_a; + applet_name = old_a->name; + xfunc_error_retval = old_x; + option_mask32 = old_m; + die_sleep = old_sleep; + return rc; +} + int spawn_and_wait(char **argv) { int rc; @@ -111,50 +157,11 @@ int spawn_and_wait(char **argv) || a->noexec /* NOEXEC trick needs fork() */ #endif )) { - int argc = 1; - char **pp = argv; - while (*++pp) - argc++; #if BB_MMU if (a->nofork) #endif { - /* Save some shared globals */ - const struct bb_applet *old_a = current_applet; - int old_x = xfunc_error_retval; - uint32_t old_m = option_mask32; - int old_sleep = die_sleep; - - current_applet = a; - applet_name = a->name; - xfunc_error_retval = EXIT_FAILURE; - /*option_mask32 = 0; - not needed */ - /* special flag for xfunc_die(). If xfunc will "die" - * in NOFORK applet, xfunc_die() sees negative - * die_sleep and longjmp here instead. */ - die_sleep = -1; - - rc = setjmp(die_jmp); - if (!rc) { - /* Some callers (xargs) - * need argv untouched because they free argv[i]! */ - 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); - } else { /* xfunc died in NOFORK applet */ - /* in case they meant to return 0... */ - if (rc == -111) - rc = 0; - } - - /* Restoring globals */ - current_applet = old_a; - applet_name = old_a->name; - xfunc_error_retval = old_x; - option_mask32 = old_m; - die_sleep = old_sleep; - return rc; + return run_nofork_applet(a, argv); } #if BB_MMU /* MMU only */ @@ -165,7 +172,7 @@ int spawn_and_wait(char **argv) /* child */ xfunc_error_retval = EXIT_FAILURE; current_applet = a; - run_current_applet_and_exit(argc, argv); + run_current_applet_and_exit(argv); #endif } #endif /* FEATURE_PREFER_APPLETS */ diff --git a/shell/ash.c b/shell/ash.c index 63f039df4..90936fcc0 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6539,10 +6539,8 @@ tryexec(char *cmd, char **argv, char **envp) a = find_applet_by_name(cmd); if (a) { if (a->noexec) { - char **c = argv; - while (*c) c++; current_applet = a; - run_current_applet_and_exit(c - argv, argv); + run_current_applet_and_exit(argv); } /* re-exec ourselves with the new arguments */ execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp); diff --git a/shell/hush.c b/shell/hush.c index 035919500..9362e5916 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -765,7 +765,7 @@ static int b_check_space(o_string *o, int len) * in here, such as setting a maximum string length */ if (o->length + len > o->maxlen) { char *old_data = o->data; - /* assert (data == NULL || o->maxlen != 0); */ + /* assert(data == NULL || o->maxlen != 0); */ o->maxlen += max(2*len, B_CHUNK); o->data = realloc(o->data, 1 + o->maxlen); if (o->data == NULL) { @@ -1113,17 +1113,10 @@ static void pseudo_exec(struct child_prog *child) * from global_argv[0], but if we are in a chroot, we may not be able * to find ourself... */ #if ENABLE_FEATURE_SH_STANDALONE - { - int argc_l; - char** argv_l = child->argv; - char *name = child->argv[0]; - - /* Count argc for use in a second... */ - for (argc_l = 0; *argv_l; argv_l++, argc_l++) - continue; - debug_printf("running applet %s\n", name); - run_applet_and_exit(name, argc_l, child->argv); - } + debug_printf("running applet %s\n", child->argv[0]); + run_applet_and_exit(child->argv[0], child->argv); +// is it ok that run_applet_and_exit() does exit(), not _exit()? +// NB: IIRC on NOMMU we are after _vfork_, not fork! #endif debug_printf("exec of %s\n", child->argv[0]); execvp(child->argv[0], child->argv); @@ -1304,6 +1297,9 @@ static int run_pipe_real(struct pipe *pi) struct child_prog *child; const struct built_in_command *x; char *p; + /* it is not always needed, but we aim to smaller code */ + int squirrel[] = { -1, -1, -1 }; + int rcode; nextin = 0; pi->pgrp = -1; @@ -1314,8 +1310,6 @@ static int run_pipe_real(struct pipe *pi) */ child = &(pi->progs[0]); if (pi->num_progs == 1 && child->group && child->subshell == 0) { - int squirrel[] = { -1, -1, -1 }; - int rcode; debug_printf("non-subshell grouping\n"); setup_redirects(child, squirrel); /* XXX could we merge code with following builtin case, @@ -1366,15 +1360,13 @@ static int run_pipe_real(struct pipe *pi) if (child->sp) { char *str; - str = make_string((child->argv + i)); + str = make_string(child->argv + i); parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); free(str); return last_return_code; } for (x = bltins; x->cmd; x++) { if (strcmp(child->argv[i], x->cmd) == 0) { - int squirrel[] = { -1, -1, -1 }; - int rcode; if (x->function == builtin_exec && child->argv[i+1] == NULL) { debug_printf("magic exec\n"); setup_redirects(child, NULL); @@ -1393,6 +1385,17 @@ static int run_pipe_real(struct pipe *pi) return rcode; } } +#if ENABLE_FEATURE_SH_STANDALONE + { + const struct bb_applet *a = find_applet_by_name(child->argv[i]); + if (a && a->nofork) { + setup_redirects(child, squirrel); + rcode = run_nofork_applet(a, child->argv + i); + restore_redirects(squirrel); + return rcode; + } + } +#endif } for (i = 0; i < pi->num_progs; i++) { @@ -2587,8 +2590,8 @@ int parse_stream(o_string *dest, struct p_context *ctx, static void mapset(const char *set, int code) { - while (*s) - map[(unsigned char)*s++] = code; + while (*set) + map[(unsigned char)*set++] = code; } static void update_ifs_map(void) diff --git a/shell/lash.c b/shell/lash.c index c74684bf7..6fe2ddc76 100644 --- a/shell/lash.c +++ b/shell/lash.c @@ -1158,12 +1158,7 @@ static int pseudo_exec(struct child_prog *child) * /bin/foo is a symlink to busybox. */ if (ENABLE_FEATURE_SH_STANDALONE) { - char **argv_l = child->argv; - int argc_l; - - for (argc_l = 0; *argv_l; argv_l++, argc_l++) - continue; - run_applet_and_exit(child->argv[0], argc_l, child->argv); + run_applet_and_exit(child->argv[0], child->argv); } execvp(child->argv[0], child->argv); -- 2.25.1