diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-09 00:52:15 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-09 00:52:15 +0200 |
commit | 54e9e1217c67563d70d6e2b14021293f707d7927 (patch) | |
tree | f8cd7fe165e7ac70eef901330fb7f95db68dbdd1 /shell/hush.c | |
parent | 80542bad2f1df9d99b579c9eeb3c2675c14c72c0 (diff) | |
download | busybox-w32-54e9e1217c67563d70d6e2b14021293f707d7927.tar.gz busybox-w32-54e9e1217c67563d70d6e2b14021293f707d7927.tar.bz2 busybox-w32-54e9e1217c67563d70d6e2b14021293f707d7927.zip |
hush: code shrink
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to '')
-rw-r--r-- | shell/hush.c | 125 |
1 files changed, 66 insertions, 59 deletions
diff --git a/shell/hush.c b/shell/hush.c index 0b17b222d..71972f751 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1379,6 +1379,11 @@ enum { | |||
1379 | #endif | 1379 | #endif |
1380 | }; | 1380 | }; |
1381 | 1381 | ||
1382 | static void sigprocmask_set(sigset_t *set) | ||
1383 | { | ||
1384 | sigprocmask(SIG_SETMASK, set, NULL); | ||
1385 | } | ||
1386 | |||
1382 | #if ENABLE_HUSH_FAST | 1387 | #if ENABLE_HUSH_FAST |
1383 | static void SIGCHLD_handler(int sig UNUSED_PARAM) | 1388 | static void SIGCHLD_handler(int sig UNUSED_PARAM) |
1384 | { | 1389 | { |
@@ -5378,18 +5383,15 @@ static void reset_traps_to_defaults(void) | |||
5378 | * Stupid. It can be done with *single* &= op, but we can't use | 5383 | * Stupid. It can be done with *single* &= op, but we can't use |
5379 | * the fact that G.blocked_set is implemented as a bitmask | 5384 | * the fact that G.blocked_set is implemented as a bitmask |
5380 | * in libc... */ | 5385 | * in libc... */ |
5381 | mask = (SPECIAL_INTERACTIVE_SIGS >> 1); | 5386 | mask = SPECIAL_INTERACTIVE_SIGS; |
5382 | sig = 1; | 5387 | sig = 0; |
5383 | while (1) { | 5388 | while ((mask >>= 1) != 0) { |
5389 | sig++; | ||
5384 | if (mask & 1) { | 5390 | if (mask & 1) { |
5385 | /* Careful. Only if no trap or trap is not "" */ | 5391 | /* Careful. Only if no trap or trap is not "" */ |
5386 | if (!G.traps || !G.traps[sig] || G.traps[sig][0]) | 5392 | if (!G.traps || !G.traps[sig] || G.traps[sig][0]) |
5387 | sigdelset(&G.blocked_set, sig); | 5393 | sigdelset(&G.blocked_set, sig); |
5388 | } | 5394 | } |
5389 | mask >>= 1; | ||
5390 | if (!mask) | ||
5391 | break; | ||
5392 | sig++; | ||
5393 | } | 5395 | } |
5394 | /* Our homegrown sig mask is saner to work with :) */ | 5396 | /* Our homegrown sig mask is saner to work with :) */ |
5395 | G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS; | 5397 | G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS; |
@@ -5411,7 +5413,7 @@ static void reset_traps_to_defaults(void) | |||
5411 | continue; | 5413 | continue; |
5412 | sigdelset(&G.blocked_set, sig); | 5414 | sigdelset(&G.blocked_set, sig); |
5413 | } | 5415 | } |
5414 | sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); | 5416 | sigprocmask_set(&G.blocked_set); |
5415 | } | 5417 | } |
5416 | 5418 | ||
5417 | #else /* !BB_MMU */ | 5419 | #else /* !BB_MMU */ |
@@ -5541,7 +5543,7 @@ static void re_execute_shell(char ***to_free, const char *s, | |||
5541 | 5543 | ||
5542 | do_exec: | 5544 | do_exec: |
5543 | debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); | 5545 | debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); |
5544 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | 5546 | sigprocmask_set(&G.inherited_set); |
5545 | execve(bb_busybox_exec_path, argv, pp); | 5547 | execve(bb_busybox_exec_path, argv, pp); |
5546 | /* Fallback. Useful for init=/bin/hush usage etc */ | 5548 | /* Fallback. Useful for init=/bin/hush usage etc */ |
5547 | if (argv[0][0] == '/') | 5549 | if (argv[0][0] == '/') |
@@ -6195,7 +6197,7 @@ static void execvp_or_die(char **argv) NORETURN; | |||
6195 | static void execvp_or_die(char **argv) | 6197 | static void execvp_or_die(char **argv) |
6196 | { | 6198 | { |
6197 | debug_printf_exec("execing '%s'\n", argv[0]); | 6199 | debug_printf_exec("execing '%s'\n", argv[0]); |
6198 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | 6200 | sigprocmask_set(&G.inherited_set); |
6199 | execvp(argv[0], argv); | 6201 | execvp(argv[0], argv); |
6200 | bb_perror_msg("can't execute '%s'", argv[0]); | 6202 | bb_perror_msg("can't execute '%s'", argv[0]); |
6201 | _exit(127); /* bash compat */ | 6203 | _exit(127); /* bash compat */ |
@@ -6327,7 +6329,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
6327 | # endif | 6329 | # endif |
6328 | /* Re-exec ourselves */ | 6330 | /* Re-exec ourselves */ |
6329 | debug_printf_exec("re-execing applet '%s'\n", argv[0]); | 6331 | debug_printf_exec("re-execing applet '%s'\n", argv[0]); |
6330 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | 6332 | sigprocmask_set(&G.inherited_set); |
6331 | execv(bb_busybox_exec_path, argv); | 6333 | execv(bb_busybox_exec_path, argv); |
6332 | /* If they called chroot or otherwise made the binary no longer | 6334 | /* If they called chroot or otherwise made the binary no longer |
6333 | * executable, fall through */ | 6335 | * executable, fall through */ |
@@ -7435,84 +7437,89 @@ static void init_sigmasks(void) | |||
7435 | { | 7437 | { |
7436 | unsigned sig; | 7438 | unsigned sig; |
7437 | unsigned mask; | 7439 | unsigned mask; |
7438 | sigset_t old_blocked_set; | ||
7439 | 7440 | ||
7441 | /* POSIX allows shell to re-enable SIGCHLD | ||
7442 | * even if it was SIG_IGN on entry */ | ||
7443 | #if ENABLE_HUSH_FAST | ||
7444 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ | ||
7445 | #endif | ||
7440 | if (!G.inherited_set_is_saved) { | 7446 | if (!G.inherited_set_is_saved) { |
7447 | #if ENABLE_HUSH_FAST | ||
7448 | signal(SIGCHLD, SIGCHLD_handler); | ||
7449 | #else | ||
7450 | signal(SIGCHLD, SIG_DFL); | ||
7451 | #endif | ||
7441 | sigprocmask(SIG_SETMASK, NULL, &G.blocked_set); | 7452 | sigprocmask(SIG_SETMASK, NULL, &G.blocked_set); |
7442 | G.inherited_set = G.blocked_set; | 7453 | G.inherited_set = G.blocked_set; |
7443 | } | 7454 | } |
7444 | old_blocked_set = G.blocked_set; | ||
7445 | 7455 | ||
7456 | /* Which signals are shell-special? */ | ||
7446 | mask = (1 << SIGQUIT); | 7457 | mask = (1 << SIGQUIT); |
7447 | if (G_interactive_fd) { | 7458 | if (G_interactive_fd) { |
7448 | mask = (1 << SIGQUIT) | SPECIAL_INTERACTIVE_SIGS; | 7459 | mask |= SPECIAL_INTERACTIVE_SIGS; |
7449 | if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ | 7460 | if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ |
7450 | mask |= SPECIAL_JOB_SIGS; | 7461 | mask |= SPECIAL_JOB_SIGS; |
7451 | } | 7462 | } |
7452 | G.non_DFL_mask = mask; | 7463 | G.non_DFL_mask = mask; |
7453 | 7464 | ||
7465 | /* Block them. And unblock SIGCHLD */ | ||
7454 | sig = 0; | 7466 | sig = 0; |
7455 | while (mask) { | 7467 | while ((mask >>= 1) != 0) { |
7468 | sig++; | ||
7456 | if (mask & 1) | 7469 | if (mask & 1) |
7457 | sigaddset(&G.blocked_set, sig); | 7470 | sigaddset(&G.blocked_set, sig); |
7458 | mask >>= 1; | ||
7459 | sig++; | ||
7460 | } | 7471 | } |
7461 | sigdelset(&G.blocked_set, SIGCHLD); | 7472 | sigdelset(&G.blocked_set, SIGCHLD); |
7462 | 7473 | ||
7463 | if (memcmp(&old_blocked_set, &G.blocked_set, sizeof(old_blocked_set)) != 0) | 7474 | if (memcmp(&G.inherited_set, &G.blocked_set, sizeof(G.inherited_set)) != 0) |
7464 | sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); | 7475 | sigprocmask_set(&G.blocked_set); |
7465 | |||
7466 | /* POSIX allows shell to re-enable SIGCHLD | ||
7467 | * even if it was SIG_IGN on entry */ | ||
7468 | #if ENABLE_HUSH_FAST | ||
7469 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ | ||
7470 | if (!G.inherited_set_is_saved) | ||
7471 | signal(SIGCHLD, SIGCHLD_handler); | ||
7472 | #else | ||
7473 | if (!G.inherited_set_is_saved) | ||
7474 | signal(SIGCHLD, SIG_DFL); | ||
7475 | #endif | ||
7476 | 7476 | ||
7477 | G.inherited_set_is_saved = 1; | 7477 | G.inherited_set_is_saved = 1; |
7478 | } | 7478 | } |
7479 | 7479 | ||
7480 | #if ENABLE_HUSH_JOB | 7480 | #if ENABLE_HUSH_JOB |
7481 | /* helper */ | 7481 | /* helper */ |
7482 | static void maybe_set_to_sigexit(int sig) | 7482 | /* Set handlers to restore tty pgrp and exit */ |
7483 | static void set_fatal_handlers_to_sigexit(void) | ||
7483 | { | 7484 | { |
7484 | void (*handler)(int); | 7485 | void (*handler)(int); |
7486 | unsigned fatal_sigs, sig; | ||
7487 | |||
7488 | /* We will restore tty pgrp on these signals */ | ||
7489 | fatal_sigs = 0 | ||
7490 | + (1 << SIGILL ) * HUSH_DEBUG | ||
7491 | + (1 << SIGFPE ) * HUSH_DEBUG | ||
7492 | + (1 << SIGBUS ) * HUSH_DEBUG | ||
7493 | + (1 << SIGSEGV) * HUSH_DEBUG | ||
7494 | + (1 << SIGTRAP) * HUSH_DEBUG | ||
7495 | + (1 << SIGABRT) | ||
7496 | /* bash 3.2 seems to handle these just like 'fatal' ones */ | ||
7497 | + (1 << SIGPIPE) | ||
7498 | + (1 << SIGALRM) | ||
7499 | /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked. | ||
7500 | * if we aren't interactive... but in this case | ||
7501 | * we never want to restore pgrp on exit, and this fn is not called */ | ||
7502 | /*+ (1 << SIGHUP )*/ | ||
7503 | /*+ (1 << SIGTERM)*/ | ||
7504 | /*+ (1 << SIGINT )*/ | ||
7505 | ; | ||
7506 | |||
7485 | /* non_DFL_mask'ed signals are, well, masked, | 7507 | /* non_DFL_mask'ed signals are, well, masked, |
7486 | * no need to set handler for them. | 7508 | * no need to set handler for them. |
7487 | */ | 7509 | */ |
7488 | if (!((G.non_DFL_mask >> sig) & 1)) { | 7510 | fatal_sigs &= ~G.non_DFL_mask; |
7511 | |||
7512 | /* For each sig in fatal_sigs... */ | ||
7513 | sig = 0; | ||
7514 | while ((fatal_sigs >>= 1) != 0) { | ||
7515 | sig++; | ||
7516 | if (!(fatal_sigs & 1)) | ||
7517 | continue; | ||
7489 | handler = signal(sig, sigexit); | 7518 | handler = signal(sig, sigexit); |
7490 | if (handler == SIG_IGN) /* oops... restore back to IGN! */ | 7519 | if (handler == SIG_IGN) /* oops... restore back to IGN! */ |
7491 | signal(sig, handler); | 7520 | signal(sig, handler); |
7492 | } | 7521 | } |
7493 | } | 7522 | } |
7494 | /* Set handlers to restore tty pgrp and exit */ | ||
7495 | static void set_fatal_handlers(void) | ||
7496 | { | ||
7497 | /* We _must_ restore tty pgrp on fatal signals */ | ||
7498 | if (HUSH_DEBUG) { | ||
7499 | maybe_set_to_sigexit(SIGILL ); | ||
7500 | maybe_set_to_sigexit(SIGFPE ); | ||
7501 | maybe_set_to_sigexit(SIGBUS ); | ||
7502 | maybe_set_to_sigexit(SIGSEGV); | ||
7503 | maybe_set_to_sigexit(SIGTRAP); | ||
7504 | } /* else: hush is perfect. what SEGV? */ | ||
7505 | maybe_set_to_sigexit(SIGABRT); | ||
7506 | /* bash 3.2 seems to handle these just like 'fatal' ones */ | ||
7507 | maybe_set_to_sigexit(SIGPIPE); | ||
7508 | maybe_set_to_sigexit(SIGALRM); | ||
7509 | /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked. | ||
7510 | * if we aren't interactive... but in this case | ||
7511 | * we never want to restore pgrp on exit, and this fn is not called */ | ||
7512 | /*maybe_set_to_sigexit(SIGHUP );*/ | ||
7513 | /*maybe_set_to_sigexit(SIGTERM);*/ | ||
7514 | /*maybe_set_to_sigexit(SIGINT );*/ | ||
7515 | } | ||
7516 | #endif | 7523 | #endif |
7517 | 7524 | ||
7518 | static int set_mode(int state, char mode, const char *o_opt) | 7525 | static int set_mode(int state, char mode, const char *o_opt) |
@@ -7769,7 +7776,7 @@ int hush_main(int argc, char **argv) | |||
7769 | sigaddset(&G.blocked_set, sig); | 7776 | sigaddset(&G.blocked_set, sig); |
7770 | } | 7777 | } |
7771 | } | 7778 | } |
7772 | sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); | 7779 | sigprocmask_set(&G.blocked_set); |
7773 | } | 7780 | } |
7774 | # if ENABLE_HUSH_LOOPS | 7781 | # if ENABLE_HUSH_LOOPS |
7775 | optarg++; | 7782 | optarg++; |
@@ -7910,7 +7917,7 @@ int hush_main(int argc, char **argv) | |||
7910 | 7917 | ||
7911 | if (G_saved_tty_pgrp) { | 7918 | if (G_saved_tty_pgrp) { |
7912 | /* Set other signals to restore saved_tty_pgrp */ | 7919 | /* Set other signals to restore saved_tty_pgrp */ |
7913 | set_fatal_handlers(); | 7920 | set_fatal_handlers_to_sigexit(); |
7914 | /* Put ourselves in our own process group | 7921 | /* Put ourselves in our own process group |
7915 | * (bash, too, does this only if ctty is available) */ | 7922 | * (bash, too, does this only if ctty is available) */ |
7916 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ | 7923 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ |
@@ -8301,7 +8308,7 @@ static int FAST_FUNC builtin_trap(char **argv) | |||
8301 | sigdelset(&G.blocked_set, sig); | 8308 | sigdelset(&G.blocked_set, sig); |
8302 | } | 8309 | } |
8303 | } | 8310 | } |
8304 | sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); | 8311 | sigprocmask_set(&G.blocked_set); |
8305 | return ret; | 8312 | return ret; |
8306 | } | 8313 | } |
8307 | 8314 | ||
@@ -8858,7 +8865,7 @@ static int FAST_FUNC builtin_wait(char **argv) | |||
8858 | * $ | 8865 | * $ |
8859 | */ | 8866 | */ |
8860 | sigaddset(&G.blocked_set, SIGCHLD); | 8867 | sigaddset(&G.blocked_set, SIGCHLD); |
8861 | sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); | 8868 | sigprocmask_set(&G.blocked_set); |
8862 | while (1) { | 8869 | while (1) { |
8863 | checkjobs(NULL); | 8870 | checkjobs(NULL); |
8864 | if (errno == ECHILD) | 8871 | if (errno == ECHILD) |
@@ -8875,7 +8882,7 @@ static int FAST_FUNC builtin_wait(char **argv) | |||
8875 | } | 8882 | } |
8876 | } | 8883 | } |
8877 | sigdelset(&G.blocked_set, SIGCHLD); | 8884 | sigdelset(&G.blocked_set, SIGCHLD); |
8878 | sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); | 8885 | sigprocmask_set(&G.blocked_set); |
8879 | return ret; | 8886 | return ret; |
8880 | } | 8887 | } |
8881 | 8888 | ||