From f58f705c5812cec5d5308ae29baceeb648d08e24 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 12 May 2011 02:10:33 +0200 Subject: [PATCH] hush: fix login shell's signal handling; add -l option so that it's easier to test function old new delta hush_main 958 1001 +43 install_special_sighandlers 47 52 +5 packed_usage 28752 28741 -11 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 48/-11) Total: 37 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 67 +++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index b2c3a752e..cdd4be4e3 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -260,7 +260,7 @@ typedef void (*hush_sighandler_t)(int); * therefore we don't show them either. */ //usage:#define hush_trivial_usage -//usage: "[-nx] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" +//usage: "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" //usage:#define hush_full_usage "\n\n" //usage: "Unix shell interpreter" @@ -1493,8 +1493,8 @@ static sighandler_t pick_sighandler(unsigned sig) handler = record_pending_signo; /* TTIN/TTOU/TSTS can't be set to record_pending_signo * in order to ignore them: they will be raised - * in an endless loop then when we try to do some - * terminal ioctls! We do nave to _ignore_ these. + * in an endless loop when we try to do some + * terminal ioctls! We do have to _ignore_ these. */ if (SPECIAL_JOBSTOP_SIGS & sigmask) handler = SIG_IGN; @@ -1508,9 +1508,6 @@ static void hush_exit(int exitcode) { fflush_all(); if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { - /* Prevent recursion: - * trap "echo Hi; exit" EXIT; exit - */ char *argv[3]; /* argv[0] is unused */ argv[1] = G.traps[0]; @@ -5474,7 +5471,8 @@ static void reset_traps_to_defaults(void) G_fatal_sig_mask = 0; #endif G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS; - /* SIGQUIT and maybe SPECIAL_JOBSTOP_SIGS remain set in G.special_sig_mask */ + /* SIGQUIT,SIGCHLD and maybe SPECIAL_JOBSTOP_SIGS + * remain set in G.special_sig_mask */ if (!G.traps) return; @@ -5537,7 +5535,6 @@ static void re_execute_shell(char ***to_free, const char *s, for (sig = 1; sig < NSIG; sig++) { if (G.traps[sig] && !G.traps[sig][0]) empty_trap_mask |= 1LL << sig; -///vda: optimize } } @@ -7540,9 +7537,6 @@ static void install_special_sighandlers(void) { unsigned mask; - if (G.special_sig_mask != 0) - return; - /* Which signals are shell-special? */ mask = (1 << SIGQUIT) | (1 << SIGCHLD); if (G_interactive_fd) { @@ -7550,9 +7544,12 @@ static void install_special_sighandlers(void) if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */ mask |= SPECIAL_JOBSTOP_SIGS; } - G.special_sig_mask = mask; - - install_sighandlers(mask); + /* Careful, do not re-install handlers we already installed */ + if (G.special_sig_mask != mask) { + unsigned diff = mask & ~G.special_sig_mask; + G.special_sig_mask = mask; + install_sighandlers(diff); + } } #if ENABLE_HUSH_JOB @@ -7573,17 +7570,14 @@ static void install_fatal_sighandlers(void) /* bash 3.2 seems to handle these just like 'fatal' ones */ + (1 << SIGPIPE) + (1 << SIGALRM) - /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked. + /* if we are interactive, SIGHUP, SIGTERM and SIGINT are special sigs. * if we aren't interactive... but in this case - * we never want to restore pgrp on exit, and this fn is not called */ + * we never want to restore pgrp on exit, and this fn is not called + */ /*+ (1 << SIGHUP )*/ /*+ (1 << SIGTERM)*/ /*+ (1 << SIGINT )*/ ; - /* special_sig_mask'ed signals are set to record_pending_signo - * no need to set handler for them. - */ - /*mask &= ~G.special_sig_mask; - they never overlap */ G_fatal_sig_mask = mask; install_sighandlers(mask); @@ -7632,6 +7626,10 @@ static int set_mode(int state, char mode, const char *o_opt) int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int hush_main(int argc, char **argv) { + enum { + OPT_login = (1 << 0), + }; + unsigned flags; int opt; unsigned builtin_argc; char **e; @@ -7735,8 +7733,6 @@ int hush_main(int argc, char **argv) # endif #endif - G.global_argc = argc; - G.global_argv = argv; /* Initialize some more globals to non-zero values */ cmdedit_update_prompt(); @@ -7752,14 +7748,14 @@ int hush_main(int argc, char **argv) * "sh -c " or login shell's /etc/profile and friends. * If we later decide that we are interactive, we run install_special_sighandlers() * in order to intercept (more) signals. -//FIXME: re-running is currently most likely broken, it's a no-op. */ /* Parse options */ /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ + flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; builtin_argc = 0; while (1) { - opt = getopt(argc, argv, "+c:xins" + opt = getopt(argc, argv, "+c:xinsl" #if !BB_MMU "<:$:R:V:" # if ENABLE_HUSH_FUNCTIONS @@ -7820,6 +7816,9 @@ int hush_main(int argc, char **argv) /* "-s" means "read from stdin", but this is how we always * operate, so simply do nothing here. */ break; + case 'l': + flags |= OPT_login; + break; #if !BB_MMU case '<': /* "big heredoc" support */ full_write1_str(optarg); @@ -7843,7 +7842,6 @@ int hush_main(int argc, char **argv) install_special_sighandlers(); G.traps = xzalloc(sizeof(G.traps[0]) * NSIG); for (sig = 1; sig < NSIG; sig++) { -///vda: fixme: more efficient code if (empty_trap_mask & (1LL << sig)) { G.traps[sig] = xzalloc(1); /* == xstrdup(""); */ signal(sig, SIG_IGN); @@ -7886,13 +7884,18 @@ int hush_main(int argc, char **argv) } } /* option parsing loop */ + /* Skip options. Try "hush -l": $1 should not be "-l"! */ + G.global_argc = argc - (optind - 1); + G.global_argv = argv + (optind - 1); + G.global_argv[0] = argv[0]; + if (!G.root_pid) { G.root_pid = getpid(); G.root_ppid = getppid(); } /* If we are login shell... */ - if (argv[0] && argv[0][0] == '-') { + if (flags & OPT_login) { FILE *input; debug_printf("sourcing /etc/profile\n"); input = fopen_for_read("/etc/profile"); @@ -7911,17 +7914,17 @@ int hush_main(int argc, char **argv) */ } - if (argv[optind]) { + if (G.global_argv[1]) { FILE *input; /* * "bash