hush: use NOFORK applets as appropriate. Net reduction of code size.
No binary (build failed)
—
(log yok)
| @@ -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 "<name>: 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 "<argv[1]>: 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"); | |
| } | |
| @@ -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;*/ | |
| @@ -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); | |
| @@ -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 */ | |
| @@ -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); | |
| @@ -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) | |
| @@ -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); | |