diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-04 20:24:37 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-04 20:24:37 +0000 |
commit | 34d4d89b2d3337ea1486d98ea979c1594a6a5efe (patch) | |
tree | 1ce6c4b4da6699c66733392c27f8dfc115e2edab | |
parent | 552433bc5af76c8e5b52278b3d609e9a18c19dc2 (diff) | |
download | busybox-w32-34d4d89b2d3337ea1486d98ea979c1594a6a5efe.tar.gz busybox-w32-34d4d89b2d3337ea1486d98ea979c1594a6a5efe.tar.bz2 busybox-w32-34d4d89b2d3337ea1486d98ea979c1594a6a5efe.zip |
hush: fix NOMMU hangs in pseudo_exec_argv. Add forgotted setting
of signal mask. Reuse same help string in all shells.
function old new delta
builtin_exit 49 47 -2
pseudo_exec_argv 149 145 -4
builtin_help 74 63 -11
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-17) Total: -17 bytes
text data bss dec hex filename
825379 476 7616 833471 cb7bf busybox_old
825341 476 7616 833433 cb799 busybox_unstripped
-rw-r--r-- | shell/ash.c | 4 | ||||
-rw-r--r-- | shell/hush.c | 124 | ||||
-rw-r--r-- | shell/lash_unused.c | 5 | ||||
-rw-r--r-- | shell/msh.c | 6 |
4 files changed, 75 insertions, 64 deletions
diff --git a/shell/ash.c b/shell/ash.c index 1cd205068..fe8c1bed2 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -12230,7 +12230,9 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12230 | unsigned col; | 12230 | unsigned col; |
12231 | unsigned i; | 12231 | unsigned i; |
12232 | 12232 | ||
12233 | out1fmt("\nBuilt-in commands:\n-------------------\n"); | 12233 | out1fmt("\n" |
12234 | "Built-in commands:\n" | ||
12235 | "------------------\n"); | ||
12234 | for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) { | 12236 | for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) { |
12235 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), | 12237 | col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), |
12236 | builtintab[i].name + 1); | 12238 | builtintab[i].name + 1); |
diff --git a/shell/hush.c b/shell/hush.c index 61db928b2..c38420240 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -363,11 +363,13 @@ struct parse_context { | |||
363 | /* bitmask of FLAG_xxx, for figuring out valid reserved words */ | 363 | /* bitmask of FLAG_xxx, for figuring out valid reserved words */ |
364 | int old_flag; | 364 | int old_flag; |
365 | /* group we are enclosed in: | 365 | /* group we are enclosed in: |
366 | * example 1: "{ { false; ..." | 366 | * example: "if pipe1; pipe2; then pipe3; fi" |
367 | * example 2: "if true; then { false; ..." | 367 | * when we see "if" or "then", we malloc and copy current context, |
368 | * example 3: "if true; then if false; ..." | 368 | * and make ->stack point to it. then we parse pipeN. |
369 | * when we find closing "}" / "fi" / whatever, we move list_head | 369 | * when closing "then" / fi" / whatever is found, |
370 | * into stack->command->group and delete ourself. | 370 | * we move list_head into ->stack->command->group, |
371 | * copy ->stack into current context, and delete ->stack. | ||
372 | * (parsing of { list } and ( list ) doesn't use this method) | ||
371 | */ | 373 | */ |
372 | struct parse_context *stack; | 374 | struct parse_context *stack; |
373 | #endif | 375 | #endif |
@@ -532,7 +534,6 @@ static int builtin_wait(char **argv); | |||
532 | static int builtin_break(char **argv); | 534 | static int builtin_break(char **argv); |
533 | static int builtin_continue(char **argv); | 535 | static int builtin_continue(char **argv); |
534 | #endif | 536 | #endif |
535 | //static int builtin_not_written(char **argv); | ||
536 | 537 | ||
537 | /* Table of built-in functions. They can be forked or not, depending on | 538 | /* Table of built-in functions. They can be forked or not, depending on |
538 | * context: within pipes, they fork. As simple commands, they do not. | 539 | * context: within pipes, they fork. As simple commands, they do not. |
@@ -554,42 +555,44 @@ struct built_in_command { | |||
554 | /* For now, echo and test are unconditionally enabled. | 555 | /* For now, echo and test are unconditionally enabled. |
555 | * Maybe make it configurable? */ | 556 | * Maybe make it configurable? */ |
556 | static const struct built_in_command bltins[] = { | 557 | static const struct built_in_command bltins[] = { |
557 | BLTIN("." , builtin_source, "Run commands in a file"), | 558 | BLTIN("." , builtin_source , "Run commands in a file"), |
558 | BLTIN(":" , builtin_true, "No-op"), | 559 | BLTIN(":" , builtin_true , "No-op"), |
559 | BLTIN("[" , builtin_test, "Test condition"), | 560 | BLTIN("[" , builtin_test , "Test condition"), |
560 | #if ENABLE_HUSH_JOB | 561 | #if ENABLE_HUSH_JOB |
561 | BLTIN("bg" , builtin_fg_bg, "Resume a job in the background"), | 562 | BLTIN("bg" , builtin_fg_bg , "Resume a job in the background"), |
562 | #endif | 563 | #endif |
563 | #if ENABLE_HUSH_LOOPS | 564 | #if ENABLE_HUSH_LOOPS |
564 | BLTIN("break" , builtin_break, "Exit from a loop"), | 565 | BLTIN("break" , builtin_break , "Exit from a loop"), |
565 | #endif | 566 | #endif |
566 | BLTIN("cd" , builtin_cd, "Change directory"), | 567 | BLTIN("cd" , builtin_cd , "Change directory"), |
567 | #if ENABLE_HUSH_LOOPS | 568 | #if ENABLE_HUSH_LOOPS |
568 | BLTIN("continue", builtin_continue, "Start new loop iteration"), | 569 | BLTIN("continue", builtin_continue, "Start new loop iteration"), |
569 | #endif | 570 | #endif |
570 | BLTIN("echo" , builtin_echo, "Write to stdout"), | 571 | BLTIN("echo" , builtin_echo , "Write to stdout"), |
571 | BLTIN("eval" , builtin_eval, "Construct and run shell command"), | 572 | BLTIN("eval" , builtin_eval , "Construct and run shell command"), |
572 | BLTIN("exec" , builtin_exec, "Execute command, don't return to shell"), | 573 | BLTIN("exec" , builtin_exec , "Execute command, don't return to shell"), |
573 | BLTIN("exit" , builtin_exit, "Exit"), | 574 | BLTIN("exit" , builtin_exit , "Exit"), |
574 | BLTIN("export", builtin_export, "Set environment variable"), | 575 | BLTIN("export" , builtin_export , "Set environment variable"), |
575 | #if ENABLE_HUSH_JOB | 576 | #if ENABLE_HUSH_JOB |
576 | BLTIN("fg" , builtin_fg_bg, "Bring job into the foreground"), | 577 | BLTIN("fg" , builtin_fg_bg , "Bring job into the foreground"), |
577 | BLTIN("jobs" , builtin_jobs, "List active jobs"), | 578 | #endif |
578 | #endif | ||
579 | BLTIN("pwd" , builtin_pwd, "Print current directory"), | ||
580 | BLTIN("read" , builtin_read, "Input environment variable"), | ||
581 | // BLTIN("return", builtin_not_written, "Return from a function"), | ||
582 | BLTIN("set" , builtin_set, "Set/unset shell local variables"), | ||
583 | BLTIN("shift" , builtin_shift, "Shift positional parameters"), | ||
584 | BLTIN("test" , builtin_test, "Test condition"), | ||
585 | BLTIN("trap" , builtin_trap, "Trap signals"), | ||
586 | // BLTIN("ulimit", builtin_not_written, "Control resource limits"), | ||
587 | BLTIN("umask" , builtin_umask, "Set file creation mask"), | ||
588 | BLTIN("unset" , builtin_unset, "Unset environment variable"), | ||
589 | BLTIN("wait" , builtin_wait, "Wait for process"), | ||
590 | #if ENABLE_HUSH_HELP | 579 | #if ENABLE_HUSH_HELP |
591 | BLTIN("help" , builtin_help, "List shell built-in commands"), | 580 | BLTIN("help" , builtin_help , "List shell built-in commands"), |
592 | #endif | 581 | #endif |
582 | #if ENABLE_HUSH_JOB | ||
583 | BLTIN("jobs" , builtin_jobs , "List active jobs"), | ||
584 | #endif | ||
585 | BLTIN("pwd" , builtin_pwd , "Print current directory"), | ||
586 | BLTIN("read" , builtin_read , "Input environment variable"), | ||
587 | // BLTIN("return" , builtin_return , "Return from a function"), | ||
588 | BLTIN("set" , builtin_set , "Set/unset shell local variables"), | ||
589 | BLTIN("shift" , builtin_shift , "Shift positional parameters"), | ||
590 | BLTIN("test" , builtin_test , "Test condition"), | ||
591 | BLTIN("trap" , builtin_trap , "Trap signals"), | ||
592 | // BLTIN("ulimit" , builtin_return , "Control resource limits"), | ||
593 | BLTIN("umask" , builtin_umask , "Set file creation mask"), | ||
594 | BLTIN("unset" , builtin_unset , "Unset environment variable"), | ||
595 | BLTIN("wait" , builtin_wait , "Wait for process"), | ||
593 | }; | 596 | }; |
594 | 597 | ||
595 | 598 | ||
@@ -2117,7 +2120,7 @@ static void restore_redirects(int squirrel[]) | |||
2117 | #endif | 2120 | #endif |
2118 | static void free_pipe_list(struct pipe *head, int indent); | 2121 | static void free_pipe_list(struct pipe *head, int indent); |
2119 | 2122 | ||
2120 | /* return code is the exit status of the pipe */ | 2123 | /* Return code is the exit status of the pipe */ |
2121 | static void free_pipe(struct pipe *pi, int indent) | 2124 | static void free_pipe(struct pipe *pi, int indent) |
2122 | { | 2125 | { |
2123 | char **p; | 2126 | char **p; |
@@ -2125,7 +2128,7 @@ static void free_pipe(struct pipe *pi, int indent) | |||
2125 | struct redir_struct *r, *rnext; | 2128 | struct redir_struct *r, *rnext; |
2126 | int a, i; | 2129 | int a, i; |
2127 | 2130 | ||
2128 | if (pi->stopped_cmds > 0) | 2131 | if (pi->stopped_cmds > 0) /* why? */ |
2129 | return; | 2132 | return; |
2130 | debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid()); | 2133 | debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid()); |
2131 | for (i = 0; i < pi->num_cmds; i++) { | 2134 | for (i = 0; i < pi->num_cmds; i++) { |
@@ -2216,9 +2219,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
2216 | char **new_env; | 2219 | char **new_env; |
2217 | const struct built_in_command *x; | 2220 | const struct built_in_command *x; |
2218 | 2221 | ||
2219 | /* If a variable is assigned in a forest, and nobody listens, | 2222 | /* Case when we are here: ... | var=val | ... */ |
2220 | * was it ever really set? | ||
2221 | */ | ||
2222 | if (!argv[assignment_cnt]) | 2223 | if (!argv[assignment_cnt]) |
2223 | _exit(EXIT_SUCCESS); | 2224 | _exit(EXIT_SUCCESS); |
2224 | 2225 | ||
@@ -2239,8 +2240,13 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
2239 | #endif | 2240 | #endif |
2240 | } | 2241 | } |
2241 | 2242 | ||
2242 | /* | 2243 | /* On NOMMU, we must never block! |
2243 | * Check if the command matches any of the builtins. | 2244 | * Example: { sleep 99999 | read line } & echo Ok |
2245 | * read builtin will block on read syscall, leaving parent blocked | ||
2246 | * in vfork. Therefore we can't do this: | ||
2247 | */ | ||
2248 | #if BB_MMU | ||
2249 | /* Check if the command matches any of the builtins. | ||
2244 | * Depending on context, this might be redundant. But it's | 2250 | * Depending on context, this might be redundant. But it's |
2245 | * easier to waste a few CPU cycles than it is to figure out | 2251 | * easier to waste a few CPU cycles than it is to figure out |
2246 | * if this is one of those cases. | 2252 | * if this is one of those cases. |
@@ -2249,33 +2255,35 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
2249 | if (strcmp(argv[0], x->cmd) == 0) { | 2255 | if (strcmp(argv[0], x->cmd) == 0) { |
2250 | debug_printf_exec("running builtin '%s'\n", argv[0]); | 2256 | debug_printf_exec("running builtin '%s'\n", argv[0]); |
2251 | rcode = x->function(argv); | 2257 | rcode = x->function(argv); |
2252 | fflush(stdout); | 2258 | fflush(NULL); |
2253 | _exit(rcode); | 2259 | _exit(rcode); |
2254 | } | 2260 | } |
2255 | } | 2261 | } |
2262 | #endif | ||
2256 | 2263 | ||
2257 | /* Check if the command matches any busybox applets */ | ||
2258 | #if ENABLE_FEATURE_SH_STANDALONE | 2264 | #if ENABLE_FEATURE_SH_STANDALONE |
2265 | /* Check if the command matches any busybox applets */ | ||
2259 | if (strchr(argv[0], '/') == NULL) { | 2266 | if (strchr(argv[0], '/') == NULL) { |
2260 | int a = find_applet_by_name(argv[0]); | 2267 | int a = find_applet_by_name(argv[0]); |
2261 | if (a >= 0) { | 2268 | if (a >= 0) { |
2269 | #if BB_MMU /* see above why on NOMMU it is not allowed */ | ||
2262 | if (APPLET_IS_NOEXEC(a)) { | 2270 | if (APPLET_IS_NOEXEC(a)) { |
2263 | debug_printf_exec("running applet '%s'\n", argv[0]); | 2271 | debug_printf_exec("running applet '%s'\n", argv[0]); |
2264 | // is it ok that run_applet_no_and_exit() does exit(), not _exit()? | ||
2265 | run_applet_no_and_exit(a, argv); | 2272 | run_applet_no_and_exit(a, argv); |
2266 | } | 2273 | } |
2267 | /* re-exec ourselves with the new arguments */ | 2274 | #endif |
2275 | /* Re-exec ourselves */ | ||
2268 | debug_printf_exec("re-execing applet '%s'\n", argv[0]); | 2276 | debug_printf_exec("re-execing applet '%s'\n", argv[0]); |
2269 | execvp(bb_busybox_exec_path, argv); | 2277 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); |
2278 | execv(bb_busybox_exec_path, argv); | ||
2270 | /* If they called chroot or otherwise made the binary no longer | 2279 | /* If they called chroot or otherwise made the binary no longer |
2271 | * executable, fall through */ | 2280 | * executable, fall through */ |
2272 | } | 2281 | } |
2273 | } | 2282 | } |
2274 | #endif | 2283 | #endif |
2275 | 2284 | ||
2276 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | ||
2277 | |||
2278 | debug_printf_exec("execing '%s'\n", argv[0]); | 2285 | debug_printf_exec("execing '%s'\n", argv[0]); |
2286 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | ||
2279 | execvp(argv[0], argv); | 2287 | execvp(argv[0], argv); |
2280 | bb_perror_msg("can't exec '%s'", argv[0]); | 2288 | bb_perror_msg("can't exec '%s'", argv[0]); |
2281 | _exit(EXIT_FAILURE); | 2289 | _exit(EXIT_FAILURE); |
@@ -2317,8 +2325,8 @@ static void pseudo_exec(nommu_save_t *nommu_save, | |||
2317 | #endif | 2325 | #endif |
2318 | } | 2326 | } |
2319 | 2327 | ||
2320 | /* Can happen. See what bash does with ">foo" by itself. */ | 2328 | /* Case when we are here: ... | >file */ |
2321 | debug_printf("pseudo_exec'ed null command\n"); | 2329 | debug_printf_exec("pseudo_exec'ed null command\n"); |
2322 | _exit(EXIT_SUCCESS); | 2330 | _exit(EXIT_SUCCESS); |
2323 | } | 2331 | } |
2324 | 2332 | ||
@@ -2569,8 +2577,8 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe) | |||
2569 | } | 2577 | } |
2570 | #endif | 2578 | #endif |
2571 | 2579 | ||
2572 | /* run_pipe() starts all the jobs, but doesn't wait for anything | 2580 | /* Start all the jobs, but don't wait for anything to finish. |
2573 | * to finish. See checkjobs(). | 2581 | * See checkjobs(). |
2574 | * | 2582 | * |
2575 | * Return code is normally -1, when the caller has to wait for children | 2583 | * Return code is normally -1, when the caller has to wait for children |
2576 | * to finish to determine the exit status of the pipe. If the pipe | 2584 | * to finish to determine the exit status of the pipe. If the pipe |
@@ -2588,7 +2596,7 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe) | |||
2588 | * cmd || ... { list } || ... | 2596 | * cmd || ... { list } || ... |
2589 | * If it is, then we can run cmd as a builtin, NOFORK [do we do this?], | 2597 | * If it is, then we can run cmd as a builtin, NOFORK [do we do this?], |
2590 | * or (if SH_STANDALONE) an applet, and we can run the { list } | 2598 | * or (if SH_STANDALONE) an applet, and we can run the { list } |
2591 | * with run_list(). Otherwise, we fork and exec cmd. | 2599 | * with run_list(). If it isn't one of these, we fork and exec cmd. |
2592 | * | 2600 | * |
2593 | * Cases when we must fork: | 2601 | * Cases when we must fork: |
2594 | * non-single: cmd | cmd | 2602 | * non-single: cmd | cmd |
@@ -3771,7 +3779,7 @@ static FILE *generate_stream_from_string(const char *s) | |||
3771 | * echo OK | 3779 | * echo OK |
3772 | */ | 3780 | */ |
3773 | //TODO: pass non-exported variables, traps, and functions | 3781 | //TODO: pass non-exported variables, traps, and functions |
3774 | execl(CONFIG_BUSYBOX_EXEC_PATH, "hush", "-c", s, NULL); | 3782 | execl(bb_busybox_exec_path, "hush", "-c", s, NULL); |
3775 | _exit(127); | 3783 | _exit(127); |
3776 | #endif | 3784 | #endif |
3777 | } | 3785 | } |
@@ -5144,7 +5152,7 @@ static int builtin_fg_bg(char **argv) | |||
5144 | found: | 5152 | found: |
5145 | // TODO: bash prints a string representation | 5153 | // TODO: bash prints a string representation |
5146 | // of job being foregrounded (like "sleep 1 | cat") | 5154 | // of job being foregrounded (like "sleep 1 | cat") |
5147 | if (*argv[0] == 'f') { | 5155 | if (argv[0][0] == 'f') { |
5148 | /* Put the job into the foreground. */ | 5156 | /* Put the job into the foreground. */ |
5149 | tcsetpgrp(G_interactive_fd, pi->pgrp); | 5157 | tcsetpgrp(G_interactive_fd, pi->pgrp); |
5150 | } | 5158 | } |
@@ -5162,12 +5170,11 @@ static int builtin_fg_bg(char **argv) | |||
5162 | if (errno == ESRCH) { | 5170 | if (errno == ESRCH) { |
5163 | delete_finished_bg_job(pi); | 5171 | delete_finished_bg_job(pi); |
5164 | return EXIT_SUCCESS; | 5172 | return EXIT_SUCCESS; |
5165 | } else { | ||
5166 | bb_perror_msg("kill (SIGCONT)"); | ||
5167 | } | 5173 | } |
5174 | bb_perror_msg("kill (SIGCONT)"); | ||
5168 | } | 5175 | } |
5169 | 5176 | ||
5170 | if (*argv[0] == 'f') { | 5177 | if (argv[0][0] == 'f') { |
5171 | remove_bg_job(pi); | 5178 | remove_bg_job(pi); |
5172 | return checkjobs_and_fg_shell(pi); | 5179 | return checkjobs_and_fg_shell(pi); |
5173 | } | 5180 | } |
@@ -5180,8 +5187,9 @@ static int builtin_help(char **argv UNUSED_PARAM) | |||
5180 | { | 5187 | { |
5181 | const struct built_in_command *x; | 5188 | const struct built_in_command *x; |
5182 | 5189 | ||
5183 | printf("\nBuilt-in commands:\n"); | 5190 | printf("\n" |
5184 | printf("-------------------\n"); | 5191 | "Built-in commands:\n" |
5192 | "------------------\n"); | ||
5185 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { | 5193 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { |
5186 | printf("%s\t%s\n", x->cmd, x->descr); | 5194 | printf("%s\t%s\n", x->cmd, x->descr); |
5187 | } | 5195 | } |
diff --git a/shell/lash_unused.c b/shell/lash_unused.c index 90b1f56cf..21ea5471b 100644 --- a/shell/lash_unused.c +++ b/shell/lash_unused.c | |||
@@ -312,8 +312,9 @@ static int builtin_help(struct child_prog UNUSED_PARAM *dummy) | |||
312 | { | 312 | { |
313 | const struct built_in_command *x; | 313 | const struct built_in_command *x; |
314 | 314 | ||
315 | printf("\nBuilt-in commands:\n" | 315 | printf("\n" |
316 | "-------------------\n"); | 316 | "Built-in commands:\n" |
317 | "------------------\n"); | ||
317 | for (x = bltins; x <= &VEC_LAST(bltins); x++) { | 318 | for (x = bltins; x <= &VEC_LAST(bltins); x++) { |
318 | if (x->descr == NULL) | 319 | if (x->descr == NULL) |
319 | continue; | 320 | continue; |
diff --git a/shell/msh.c b/shell/msh.c index 5f8c90ef6..da1dc3576 100644 --- a/shell/msh.c +++ b/shell/msh.c | |||
@@ -35,7 +35,6 @@ | |||
35 | # include <assert.h> | 35 | # include <assert.h> |
36 | # define bb_dev_null "/dev/null" | 36 | # define bb_dev_null "/dev/null" |
37 | # define DEFAULT_SHELL "/proc/self/exe" | 37 | # define DEFAULT_SHELL "/proc/self/exe" |
38 | # define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe" | ||
39 | # define bb_banner "busybox standalone" | 38 | # define bb_banner "busybox standalone" |
40 | # define ENABLE_FEATURE_SH_STANDALONE 0 | 39 | # define ENABLE_FEATURE_SH_STANDALONE 0 |
41 | # define bb_msg_memory_exhausted "memory exhausted" | 40 | # define bb_msg_memory_exhausted "memory exhausted" |
@@ -3176,8 +3175,9 @@ static int dohelp(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM) | |||
3176 | int col; | 3175 | int col; |
3177 | const struct builtincmd *x; | 3176 | const struct builtincmd *x; |
3178 | 3177 | ||
3179 | puts("\nBuilt-in commands:\n" | 3178 | printf("\n" |
3180 | "-------------------"); | 3179 | "Built-in commands:\n" |
3180 | "------------------\n"); | ||
3181 | 3181 | ||
3182 | col = 0; | 3182 | col = 0; |
3183 | x = builtincmds; | 3183 | x = builtincmds; |