Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/shell/hush.c


Ignore:
Timestamp:
Jan 1, 2014, 12:47:38 AM (10 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.21.1
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/3.2/mindi-busybox/shell/hush.c

    r2859 r3232  
    8282 *              aaa
    8383 */
    84 #include "busybox.h"  /* for APPLET_IS_NOFORK/NOEXEC */
    85 #include <malloc.h>   /* for malloc_trim */
     84#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
     85    || defined(__APPLE__) \
     86    )
     87# include <malloc.h>   /* for malloc_trim */
     88#endif
    8689#include <glob.h>
    8790/* #include <dmalloc.h> */
     
    9093#endif
    9194
     95#include "busybox.h"  /* for APPLET_IS_NOFORK/NOEXEC */
     96#include "unicode.h"
    9297#include "shell_common.h"
    9398#include "math.h"
     
    101106# define PIPE_BUF 4096  /* amount of buffering in a pipe */
    102107#endif
    103 
    104 //applet:IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP))
    105 //applet:IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP))
    106 //applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh))
    107 //applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash))
    108 
    109 //kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o
    110 //kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o
    111108
    112109//config:config HUSH
     
    246243//config:
    247244
    248 //usage:#define hush_trivial_usage NOUSAGE_STR
    249 //usage:#define hush_full_usage ""
    250 //usage:#define msh_trivial_usage NOUSAGE_STR
    251 //usage:#define msh_full_usage ""
    252 //usage:#define sh_trivial_usage NOUSAGE_STR
    253 //usage:#define sh_full_usage ""
    254 //usage:#define bash_trivial_usage NOUSAGE_STR
    255 //usage:#define bash_full_usage ""
     245//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP))
     246//applet:IF_MSH(APPLET(msh, BB_DIR_BIN, BB_SUID_DROP))
     247//applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, sh))
     248//applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, bash))
     249
     250//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o
     251//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o
     252
     253/* -i (interactive) and -s (read stdin) are also accepted,
     254 * but currently do nothing, therefore aren't shown in help.
     255 * NOMMU-specific options are not meant to be used by users,
     256 * therefore we don't show them either.
     257 */
     258//usage:#define hush_trivial_usage
     259//usage:    "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
     260//usage:#define hush_full_usage "\n\n"
     261//usage:    "Unix shell interpreter"
     262
     263//usage:#define msh_trivial_usage hush_trivial_usage
     264//usage:#define msh_full_usage hush_full_usage
     265
     266//usage:#if ENABLE_FEATURE_SH_IS_HUSH
     267//usage:# define sh_trivial_usage hush_trivial_usage
     268//usage:# define sh_full_usage    hush_full_usage
     269//usage:#endif
     270//usage:#if ENABLE_FEATURE_BASH_IS_HUSH
     271//usage:# define bash_trivial_usage hush_trivial_usage
     272//usage:# define bash_full_usage    hush_full_usage
     273//usage:#endif
    256274
    257275
     
    303321# undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
    304322# define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
     323# undef ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
     324# define ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 0
    305325#endif
    306326
     
    437457#endif
    438458
    439 /* I can almost use ordinary FILE*.  Is open_memstream() universally
    440  * available?  Where is it documented? */
    441459typedef struct in_str {
    442460    const char *p;
     
    445463    char peek_buf[2];
    446464#if ENABLE_HUSH_INTERACTIVE
    447     smallint promptme;
    448465    smallint promptmode; /* 0: PS1, 1: PS2 */
    449466#endif
     467    int last_char;
    450468    FILE *file;
    451469    int (*get) (struct in_str *) FAST_FUNC;
     
    505523    pid_t pid;                  /* 0 if exited */
    506524    int assignment_cnt;         /* how many argv[i] are assignments? */
    507     smallint is_stopped;        /* is the command currently running? */
    508525    smallint cmd_type;          /* CMD_xxx */
    509526#define CMD_NORMAL   0
     
    677694 * xtrace          off
    678695 */
    679 static const char o_opt_strings[] ALIGN1 = "pipefail\0";
     696static const char o_opt_strings[] ALIGN1 =
     697    "pipefail\0"
     698    "noexec\0"
     699#if ENABLE_HUSH_MODE_X
     700    "xtrace\0"
     701#endif
     702    ;
    680703enum {
    681704    OPT_O_PIPEFAIL,
     705    OPT_O_NOEXEC,
     706#if ENABLE_HUSH_MODE_X
     707    OPT_O_XTRACE,
     708#endif
    682709    NUM_OPT_O
    683710};
     
    727754#endif
    728755    char o_opt[NUM_OPT_O];
     756#if ENABLE_HUSH_MODE_X
     757# define G_x_mode (G.o_opt[OPT_O_XTRACE])
     758#else
     759# define G_x_mode 0
     760#endif
    729761    smallint flag_SIGINT;
    730762#if ENABLE_HUSH_LOOPS
     
    738770    smallint flag_return_in_progress;
    739771#endif
    740     smallint n_mode;
    741 #if ENABLE_HUSH_MODE_X
    742     smallint x_mode;
    743 # define G_x_mode (G.x_mode)
    744 #else
    745 # define G_x_mode 0
    746 #endif
    747772    smallint exiting; /* used to prevent EXIT trap recursion */
    748773    /* These four support $?, $#, and $1 */
     
    750775    /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */
    751776    smalluint global_args_malloced;
    752     smalluint inherited_set_is_saved;
    753777    /* how many non-NULL argv's we have. NB: $# + 1 */
    754778    int global_argc;
     
    778802    smallint we_have_children;
    779803#endif
    780     /* which signals have non-DFL handler (even with no traps set)? */
    781     unsigned non_DFL_mask;
     804    /* Which signals have non-DFL handler (even with no traps set)?
     805     * Set at the start to:
     806     * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS)
     807     * SPECIAL_INTERACTIVE_SIGS are cleared after fork.
     808     * The rest is cleared right before execv syscalls.
     809     * Other than these two times, never modified.
     810     */
     811    unsigned special_sig_mask;
     812#if ENABLE_HUSH_JOB
     813    unsigned fatal_sig_mask;
     814# define G_fatal_sig_mask G.fatal_sig_mask
     815#else
     816# define G_fatal_sig_mask 0
     817#endif
    782818    char **traps; /* char *traps[NSIG] */
    783     sigset_t blocked_set;
    784     sigset_t inherited_set;
     819    sigset_t pending_set;
    785820#if HUSH_DEBUG
    786821    unsigned long memleak_value;
    787822    int debug_indent;
    788823#endif
     824    struct sigaction sa;
    789825    char user_input_buf[ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 2];
    790826};
     
    795831#define INIT_G() do { \
    796832    SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
     833    /* memset(&G.sa, 0, sizeof(G.sa)); */  \
     834    sigfillset(&G.sa.sa_mask); \
     835    G.sa.sa_flags = SA_RESTART; \
    797836} while (0)
    798837
     
    10621101}
    10631102
    1064 static void syntax_error(unsigned lineno, const char *msg)
     1103static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
    10651104{
    10661105    if (msg)
    1067         die_if_script(lineno, "syntax error: %s", msg);
     1106        bb_error_msg("syntax error: %s", msg);
    10681107    else
    1069         die_if_script(lineno, "syntax error", NULL);
    1070 }
    1071 
    1072 static void syntax_error_at(unsigned lineno, const char *msg)
    1073 {
    1074     die_if_script(lineno, "syntax error at '%s'", msg);
    1075 }
    1076 
    1077 static void syntax_error_unterm_str(unsigned lineno, const char *s)
    1078 {
    1079     die_if_script(lineno, "syntax error: unterminated %s", s);
    1080 }
    1081 
    1082 /* It so happens that all such cases are totally fatal
    1083  * even if shell is interactive: EOF while looking for closing
    1084  * delimiter. There is nowhere to read stuff from after that,
    1085  * it's EOF! The only choice is to terminate.
    1086  */
    1087 static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN;
     1108        bb_error_msg("syntax error");
     1109}
     1110
     1111static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg)
     1112{
     1113    bb_error_msg("syntax error at '%s'", msg);
     1114}
     1115
     1116static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s)
     1117{
     1118    bb_error_msg("syntax error: unterminated %s", s);
     1119}
     1120
    10881121static void syntax_error_unterm_ch(unsigned lineno, char ch)
    10891122{
    10901123    char msg[2] = { ch, '\0' };
    10911124    syntax_error_unterm_str(lineno, msg);
    1092     xfunc_die();
    1093 }
    1094 
    1095 static void syntax_error_unexpected_ch(unsigned lineno, int ch)
     1125}
     1126
     1127static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch)
    10961128{
    10971129    char msg[2];
    10981130    msg[0] = ch;
    10991131    msg[1] = '\0';
    1100     die_if_script(lineno, "syntax error: unexpected %s", ch == EOF ? "EOF" : msg);
     1132    bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg);
    11011133}
    11021134
     
    13121344 *    Example 3: this does not wait 5 sec, but executes ls:
    13131345 *    "sleep 5; ls -l" + press ^C
     1346 *    Example 4: this does not wait and does not execute ls:
     1347 *    "sleep 5 & wait; ls -l" + press ^C
    13141348 *
    13151349 * (What happens to signals which are IGN on shell start?)
    13161350 * (What happens with signal mask on shell start?)
    13171351 *
    1318  * Implementation in hush
    1319  * ======================
     1352 * Old implementation
     1353 * ==================
    13201354 * We use in-kernel pending signal mask to determine which signals were sent.
    13211355 * We block all signals which we don't want to take action immediately,
     
    13251359 * and act on them.
    13261360 *
    1327  * unsigned non_DFL_mask: a mask of such "special" signals
     1361 * unsigned special_sig_mask: a mask of such "special" signals
    13281362 * sigset_t blocked_set:  current blocked signal set
    13291363 *
    13301364 * "trap - SIGxxx":
    1331  *    clear bit in blocked_set unless it is also in non_DFL_mask
     1365 *    clear bit in blocked_set unless it is also in special_sig_mask
    13321366 * "trap 'cmd' SIGxxx":
    13331367 *    set bit in blocked_set (even if 'cmd' is '')
     
    13481382 * are set to the default actions". bash interprets it so that traps which
    13491383 * are set to '' (ignore) are NOT reset to defaults. We do the same.
     1384 *
     1385 * Problem: the above approach makes it unwieldy to catch signals while
     1386 * we are in read builtin, of while we read commands from stdin:
     1387 * masked signals are not visible!
     1388 *
     1389 * New implementation
     1390 * ==================
     1391 * We record each signal we are interested in by installing signal handler
     1392 * for them - a bit like emulating kernel pending signal mask in userspace.
     1393 * We are interested in: signals which need to have special handling
     1394 * as described above, and all signals which have traps set.
     1395 * Signals are rocorded in pending_set.
     1396 * After each pipe execution, we extract any pending signals
     1397 * and act on them.
     1398 *
     1399 * unsigned special_sig_mask: a mask of shell-special signals.
     1400 * unsigned fatal_sig_mask: a mask of signals on which we restore tty pgrp.
     1401 * char *traps[sig] if trap for sig is set (even if it's '').
     1402 * sigset_t pending_set: set of sigs we received.
     1403 *
     1404 * "trap - SIGxxx":
     1405 *    if sig is in special_sig_mask, set handler back to:
     1406 *        record_pending_signo, or to IGN if it's a tty stop signal
     1407 *    if sig is in fatal_sig_mask, set handler back to sigexit.
     1408 *    else: set handler back to SIG_DFL
     1409 * "trap 'cmd' SIGxxx":
     1410 *    set handler to record_pending_signo.
     1411 * "trap '' SIGxxx":
     1412 *    set handler to SIG_IGN.
     1413 * after [v]fork, if we plan to be a shell:
     1414 *    set signals with special interactive handling to SIG_DFL
     1415 *    (because child shell is not interactive),
     1416 *    unset all traps except '' (note: regardless of child shell's type - {}, (), etc)
     1417 * after [v]fork, if we plan to exec:
     1418 *    POSIX says fork clears pending signal mask in child - no need to clear it.
     1419 *
     1420 * To make wait builtin interruptible, we handle SIGCHLD as special signal,
     1421 * otherwise (if we leave it SIG_DFL) sigsuspend in wait builtin will not wake up on it.
     1422 *
     1423 * Note (compat):
     1424 * Standard says "When a subshell is entered, traps that are not being ignored
     1425 * are set to the default actions". bash interprets it so that traps which
     1426 * are set to '' (ignore) are NOT reset to defaults. We do the same.
    13501427 */
    13511428enum {
     
    13551432        | (1 << SIGHUP)
    13561433        ,
    1357     SPECIAL_JOB_SIGS = 0
     1434    SPECIAL_JOBSTOP_SIGS = 0
    13581435#if ENABLE_HUSH_JOB
    13591436        | (1 << SIGTTIN)
     
    13611438        | (1 << SIGTSTP)
    13621439#endif
     1440        ,
    13631441};
    13641442
     1443static void record_pending_signo(int sig)
     1444{
     1445    sigaddset(&G.pending_set, sig);
    13651446#if ENABLE_HUSH_FAST
    1366 static void SIGCHLD_handler(int sig UNUSED_PARAM)
    1367 {
    1368     G.count_SIGCHLD++;
     1447    if (sig == SIGCHLD) {
     1448        G.count_SIGCHLD++;
    13691449//bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
    1370 }
    1371 #endif
     1450    }
     1451#endif
     1452}
     1453
     1454static sighandler_t install_sighandler(int sig, sighandler_t handler)
     1455{
     1456    struct sigaction old_sa;
     1457
     1458    /* We could use signal() to install handlers... almost:
     1459     * except that we need to mask ALL signals while handlers run.
     1460     * I saw signal nesting in strace, race window isn't small.
     1461     * SA_RESTART is also needed, but in Linux, signal()
     1462     * sets SA_RESTART too.
     1463     */
     1464    /* memset(&G.sa, 0, sizeof(G.sa)); - already done */
     1465    /* sigfillset(&G.sa.sa_mask);      - already done */
     1466    /* G.sa.sa_flags = SA_RESTART;     - already done */
     1467    G.sa.sa_handler = handler;
     1468    sigaction(sig, &G.sa, &old_sa);
     1469    return old_sa.sa_handler;
     1470}
    13721471
    13731472#if ENABLE_HUSH_JOB
     
    13861485static void sigexit(int sig)
    13871486{
    1388     /* Disable all signals: job control, SIGPIPE, etc. */
    1389     sigprocmask_allsigs(SIG_BLOCK);
    1390 
    13911487    /* Careful: we can end up here after [v]fork. Do not restore
    13921488     * tty pgrp then, only top-level shell process does that */
    1393     if (G_saved_tty_pgrp && getpid() == G.root_pid)
     1489    if (G_saved_tty_pgrp && getpid() == G.root_pid) {
     1490        /* Disable all signals: job control, SIGPIPE, etc.
     1491         * Mostly paranoid measure, to prevent infinite SIGTTOU.
     1492         */
     1493        sigprocmask_allsigs(SIG_BLOCK);
    13941494        tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
     1495    }
    13951496
    13961497    /* Not a signal, just exit */
     
    14071508#endif
    14081509
     1510static sighandler_t pick_sighandler(unsigned sig)
     1511{
     1512    sighandler_t handler = SIG_DFL;
     1513    if (sig < sizeof(unsigned)*8) {
     1514        unsigned sigmask = (1 << sig);
     1515
     1516#if ENABLE_HUSH_JOB
     1517        /* is sig fatal? */
     1518        if (G_fatal_sig_mask & sigmask)
     1519            handler = sigexit;
     1520        else
     1521#endif
     1522        /* sig has special handling? */
     1523        if (G.special_sig_mask & sigmask) {
     1524            handler = record_pending_signo;
     1525            /* TTIN/TTOU/TSTP can't be set to record_pending_signo
     1526             * in order to ignore them: they will be raised
     1527             * in an endless loop when we try to do some
     1528             * terminal ioctls! We do have to _ignore_ these.
     1529             */
     1530            if (SPECIAL_JOBSTOP_SIGS & sigmask)
     1531                handler = SIG_IGN;
     1532        }
     1533    }
     1534    return handler;
     1535}
     1536
    14091537/* Restores tty foreground process group, and exits. */
    14101538static void hush_exit(int exitcode) NORETURN;
    14111539static void hush_exit(int exitcode)
    14121540{
     1541#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
     1542    save_history(G.line_input_state);
     1543#endif
     1544
     1545    fflush_all();
    14131546    if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) {
    1414         /* Prevent recursion:
    1415          * trap "echo Hi; exit" EXIT; exit
    1416          */
    14171547        char *argv[3];
    14181548        /* argv[0] is unused */
     
    14511581
    14521582
    1453 static int check_and_run_traps(int sig)
    1454 {
    1455     /* I want it in rodata, not in bss.
    1456      * gcc 4.2.1 puts it in rodata only if it has { 0, 0 }
    1457      * initializer. But other compilers may still use bss.
    1458      * TODO: find more portable solution.
    1459      */
    1460     static const struct timespec zero_timespec = { 0, 0 };
    1461     smalluint save_rcode;
     1583//TODO: return a mask of ALL handled sigs?
     1584static int check_and_run_traps(void)
     1585{
    14621586    int last_sig = 0;
    14631587
    1464     if (sig)
    1465         goto jump_in;
    14661588    while (1) {
    1467         sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec);
    1468         if (sig <= 0)
     1589        int sig;
     1590
     1591        if (sigisemptyset(&G.pending_set))
    14691592            break;
    1470  jump_in:
    1471         last_sig = sig;
     1593        sig = 0;
     1594        do {
     1595            sig++;
     1596            if (sigismember(&G.pending_set, sig)) {
     1597                sigdelset(&G.pending_set, sig);
     1598                goto got_sig;
     1599            }
     1600        } while (sig < NSIG);
     1601        break;
     1602 got_sig:
    14721603        if (G.traps && G.traps[sig]) {
    14731604            if (G.traps[sig][0]) {
    14741605                /* We have user-defined handler */
     1606                smalluint save_rcode;
    14751607                char *argv[3];
    14761608                /* argv[0] is unused */
     
    14801612                builtin_eval(argv);
    14811613                G.last_exitcode = save_rcode;
     1614                last_sig = sig;
    14821615            } /* else: "" trap, ignoring signal */
    14831616            continue;
     
    14851618        /* not a trap: special action */
    14861619        switch (sig) {
    1487 #if ENABLE_HUSH_FAST
    1488         case SIGCHLD:
    1489             G.count_SIGCHLD++;
    1490 //bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
    1491             break;
    1492 #endif
    14931620        case SIGINT:
    14941621            /* Builtin was ^C'ed, make it look prettier: */
    14951622            bb_putchar('\n');
    14961623            G.flag_SIGINT = 1;
     1624            last_sig = sig;
    14971625            break;
    14981626#if ENABLE_HUSH_JOB
     
    15111639        }
    15121640#endif
     1641#if ENABLE_HUSH_FAST
     1642        case SIGCHLD:
     1643            G.count_SIGCHLD++;
     1644//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD);
     1645            /* Note:
     1646             * We dont do 'last_sig = sig' here -> NOT returning this sig.
     1647             * This simplifies wait builtin a bit.
     1648             */
     1649            break;
     1650#endif
    15131651        default: /* ignored: */
    15141652            /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
     1653            /* Note:
     1654             * We dont do 'last_sig = sig' here -> NOT returning this sig.
     1655             * Example: wait is not interrupted by TERM
     1656             * in interactive shell, because TERM is ignored.
     1657             */
    15151658            break;
    15161659        }
     
    18341977    if (ch != '\0') {
    18351978        i->p++;
     1979        i->last_char = ch;
    18361980        return ch;
    18371981    }
     
    18912035     * is actually being read */
    18922036    do {
     2037        /* Unicode support should be activated even if LANG is set
     2038         * _during_ shell execution, not only if it was set when
     2039         * shell was started. Therefore, re-check LANG every time:
     2040         */
     2041        reinit_unicode(get_local_var_value("LANG"));
     2042
    18932043        G.flag_SIGINT = 0;
    18942044        /* buglet: SIGINT will not make new prompt to appear _at once_,
    18952045         * only after <Enter>. (^C will work) */
    1896         r = read_line_input(prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, G.line_input_state);
     2046        r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1);
    18972047        /* catch *SIGINT* etc (^C is handled by read_line_input) */
    1898         check_and_run_traps(0);
     2048        check_and_run_traps();
    18992049    } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
    19002050    i->eof_flag = (r < 0);
     
    19062056    do {
    19072057        G.flag_SIGINT = 0;
    1908         fputs(prompt_str, stdout);
     2058        if (i->last_char == '\0' || i->last_char == '\n') {
     2059            /* Why check_and_run_traps here? Try this interactively:
     2060             * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) &
     2061             * $ <[enter], repeatedly...>
     2062             * Without check_and_run_traps, handler never runs.
     2063             */
     2064            check_and_run_traps();
     2065            fputs(prompt_str, stdout);
     2066        }
    19092067        fflush_all();
    19102068        G.user_input_buf[0] = r = fgetc(i->file);
    19112069        /*G.user_input_buf[1] = '\0'; - already is and never changed */
    1912 //do we need check_and_run_traps(0)? (maybe only if stdin)
    19132070    } while (G.flag_SIGINT);
    19142071    i->eof_flag = (r == EOF);
     
    19382095         * more complicated by now, like sourcing or substituting. */
    19392096#if ENABLE_HUSH_INTERACTIVE
    1940         if (G_interactive_fd && i->promptme && i->file == stdin) {
     2097        if (G_interactive_fd && i->file == stdin) {
    19412098            do {
    19422099                get_user_input(i);
    19432100            } while (!*i->p); /* need non-empty line */
    19442101            i->promptmode = 1; /* PS2 */
    1945             i->promptme = 0;
    19462102            goto take_cached;
    19472103        }
     
    19502106    }
    19512107    debug_printf("file_get: got '%c' %d\n", ch, ch);
    1952 #if ENABLE_HUSH_INTERACTIVE
    1953     if (ch == '\n')
    1954         i->promptme = 1;
    1955 #endif
     2108    i->last_char = ch;
    19562109    return ch;
    19572110}
     
    19802133static void setup_file_in_str(struct in_str *i, FILE *f)
    19812134{
     2135    memset(i, 0, sizeof(*i));
    19822136    i->peek = file_peek;
    19832137    i->get = file_get;
    1984 #if ENABLE_HUSH_INTERACTIVE
    1985     i->promptme = 1;
    1986     i->promptmode = 0; /* PS1 */
    1987 #endif
     2138    /* i->promptmode = 0; - PS1 (memset did it) */
    19882139    i->file = f;
    1989     i->p = NULL;
     2140    /* i->p = NULL; */
    19902141}
    19912142
    19922143static void setup_string_in_str(struct in_str *i, const char *s)
    19932144{
     2145    memset(i, 0, sizeof(*i));
    19942146    i->peek = static_peek;
    19952147    i->get = static_get;
    1996 #if ENABLE_HUSH_INTERACTIVE
    1997     i->promptme = 1;
    1998     i->promptmode = 0; /* PS1 */
    1999 #endif
     2148    /* i->promptmode = 0; - PS1 (memset did it) */
    20002149    i->p = s;
    2001     i->eof_flag = 0;
     2150    /* i->eof_flag = 0; */
    20022151}
    20032152
     
    21342283        o_addblock(o, str, ordinary_cnt);
    21352284        if (ordinary_cnt == len)
    2136             return;
     2285            return; /* NUL is already added by o_addblock */
    21372286        str += ordinary_cnt;
    21382287        len -= ordinary_cnt + 1; /* we are processing + 1 char below */
     
    21482297        o->data[o->length] = ch;
    21492298        o->length++;
    2150         o->data[o->length] = '\0';
    2151     }
     2299    }
     2300    o->data[o->length] = '\0';
    21522301}
    21532302
     
    22382387        o->has_empty_slot = 0;
    22392388    }
     2389    o->has_quoted_part = 0;
    22402390    list[n] = (char*)(uintptr_t)string_len;
    22412391    return n + 1;
     
    31173267                p += 3;
    31183268            }
    3119             if (p == word->data || p[0] != '\0') {
    3120                 /* saw no "$@", or not only "$@" but some
    3121                  * real text is there too */
    3122                 /* insert "empty variable" reference, this makes
    3123                  * e.g. "", $empty"" etc to not disappear */
    3124                 o_addchr(word, SPECIAL_VAR_SYMBOL);
    3125                 o_addchr(word, SPECIAL_VAR_SYMBOL);
    3126             }
    31273269        }
    31283270        command->argv = add_string_to_strings(command->argv, xstrdup(word->data));
     
    33223464
    33233465    goto jump_in;
     3466
    33243467    while (1) {
    33253468        ch = i_getch(input);
     
    35333676#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS
    35343677/* Subroutines for copying $(...) and `...` things */
    3535 static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
     3678static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
    35363679/* '...' */
    3537 static void add_till_single_quote(o_string *dest, struct in_str *input)
     3680static int add_till_single_quote(o_string *dest, struct in_str *input)
    35383681{
    35393682    while (1) {
     
    35413684        if (ch == EOF) {
    35423685            syntax_error_unterm_ch('\'');
    3543             /*xfunc_die(); - redundant */
     3686            return 0;
    35443687        }
    35453688        if (ch == '\'')
    3546             return;
     3689            return 1;
    35473690        o_addchr(dest, ch);
    35483691    }
    35493692}
    35503693/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
    3551 static void add_till_double_quote(o_string *dest, struct in_str *input)
     3694static int add_till_double_quote(o_string *dest, struct in_str *input)
    35523695{
    35533696    while (1) {
     
    35553698        if (ch == EOF) {
    35563699            syntax_error_unterm_ch('"');
    3557             /*xfunc_die(); - redundant */
     3700            return 0;
    35583701        }
    35593702        if (ch == '"')
    3560             return;
     3703            return 1;
    35613704        if (ch == '\\') {  /* \x. Copy both chars. */
    35623705            o_addchr(dest, ch);
     
    35653708        o_addchr(dest, ch);
    35663709        if (ch == '`') {
    3567             add_till_backquote(dest, input, /*in_dquote:*/ 1);
     3710            if (!add_till_backquote(dest, input, /*in_dquote:*/ 1))
     3711                return 0;
    35683712            o_addchr(dest, ch);
    35693713            continue;
     
    35863730 * echo `echo '\'TEST\`echo ZZ\`BEST`    \TESTZZBEST
    35873731 */
    3588 static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote)
     3732static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote)
    35893733{
    35903734    while (1) {
    35913735        int ch = i_getch(input);
    35923736        if (ch == '`')
    3593             return;
     3737            return 1;
    35943738        if (ch == '\\') {
    35953739            /* \x. Copy both unless it is \`, \$, \\ and maybe \" */
     
    36053749        if (ch == EOF) {
    36063750            syntax_error_unterm_ch('`');
    3607             /*xfunc_die(); - redundant */
     3751            return 0;
    36083752        }
    36093753        o_addchr(dest, ch);
     
    36413785        if (ch == EOF) {
    36423786            syntax_error_unterm_ch(end_ch);
    3643             /*xfunc_die(); - redundant */
     3787            return 0;
    36443788        }
    36453789        if (ch == end_ch  IF_HUSH_BASH_COMPAT( || ch == end_char2)) {
     
    36553799        if (ch == '(' || ch == '{') {
    36563800            ch = (ch == '(' ? ')' : '}');
    3657             add_till_closing_bracket(dest, input, ch);
     3801            if (!add_till_closing_bracket(dest, input, ch))
     3802                return 0;
    36583803            o_addchr(dest, ch);
    36593804            continue;
    36603805        }
    36613806        if (ch == '\'') {
    3662             add_till_single_quote(dest, input);
     3807            if (!add_till_single_quote(dest, input))
     3808                return 0;
    36633809            o_addchr(dest, ch);
    36643810            continue;
    36653811        }
    36663812        if (ch == '"') {
    3667             add_till_double_quote(dest, input);
     3813            if (!add_till_double_quote(dest, input))
     3814                return 0;
    36683815            o_addchr(dest, ch);
    36693816            continue;
    36703817        }
    36713818        if (ch == '`') {
    3672             add_till_backquote(dest, input, /*in_dquote:*/ 0);
     3819            if (!add_till_backquote(dest, input, /*in_dquote:*/ 0))
     3820                return 0;
    36733821            o_addchr(dest, ch);
    36743822            continue;
     
    36793827            if (ch == EOF) {
    36803828                syntax_error_unterm_ch(')');
    3681                 /*xfunc_die(); - redundant */
     3829                return 0;
    36823830            }
    36833831            o_addchr(dest, ch);
     
    37503898 bad_dollar_syntax:
    37513899            syntax_error_unterm_str("${name}");
    3752             debug_printf_parse("parse_dollar return 1: unterminated ${name}\n");
    3753             return 1;
     3900            debug_printf_parse("parse_dollar return 0: unterminated ${name}\n");
     3901            return 0;
    37543902        }
    37553903        nommu_addchr(as_string, ch);
     
    38073955#if ENABLE_HUSH_DOLLAR_OPS
    38083956                last_ch = add_till_closing_bracket(dest, input, end_ch);
     3957                if (last_ch == 0) /* error? */
     3958                    return 0;
    38093959#else
    38103960#error Simple code to only allow ${var} is not implemented
     
    38514001            if (!BB_MMU)
    38524002                pos = dest->length;
    3853             add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG);
     4003            if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG))
     4004                return 0; /* error */
    38544005            if (as_string) {
    38554006                o_addstr(as_string, dest->data + pos);
     
    38664017        if (!BB_MMU)
    38674018            pos = dest->length;
    3868         add_till_closing_bracket(dest, input, ')');
     4019        if (!add_till_closing_bracket(dest, input, ')'))
     4020            return 0; /* error */
    38694021        if (as_string) {
    38704022            o_addstr(as_string, dest->data + pos);
     
    38934045        o_addQchr(dest, '$');
    38944046    }
    3895     debug_printf_parse("parse_dollar return 0\n");
    3896     return 0;
     4047    debug_printf_parse("parse_dollar return 1 (ok)\n");
     4048    return 1;
    38974049#undef as_string
    38984050}
     
    39354087        nommu_addchr(as_string, ch);
    39364088    if (ch == dquote_end) { /* may be only '"' or EOF */
    3937         debug_printf_parse("encode_string return 0\n");
    3938         return 0;
     4089        debug_printf_parse("encode_string return 1 (ok)\n");
     4090        return 1;
    39394091    }
    39404092    /* note: can't move it above ch == dquote_end check! */
    39414093    if (ch == EOF) {
    39424094        syntax_error_unterm_ch('"');
    3943         /*xfunc_die(); - redundant */
     4095        return 0; /* error */
    39444096    }
    39454097    next = '\0';
     
    39724124    }
    39734125    if (ch == '$') {
    3974         if (parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80) != 0) {
    3975             debug_printf_parse("encode_string return 1: "
    3976                     "parse_dollar returned non-0\n");
    3977             return 1;
     4126        if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) {
     4127            debug_printf_parse("encode_string return 0: "
     4128                    "parse_dollar returned 0 (error)\n");
     4129            return 0;
    39784130        }
    39794131        goto again;
     
    39844136        o_addchr(dest, SPECIAL_VAR_SYMBOL);
    39854137        o_addchr(dest, 0x80 | '`');
    3986         add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"');
     4138        if (!add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"'))
     4139            return 0; /* error */
    39874140        o_addchr(dest, SPECIAL_VAR_SYMBOL);
    39884141        //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
     
    39994152 * Return a list of pipes to execute, or NULL on EOF
    40004153 * or if end_trigger character is met.
    4001  * On syntax error, exit is shell is not interactive,
     4154 * On syntax error, exit if shell is not interactive,
    40024155 * reset parsing machinery and start parsing anew,
    40034156 * or return ERR_PTR.
     
    40284181     */
    40294182
    4030  reset: /* we come back here only on syntax errors in interactive shell */
    4031 
    4032 #if ENABLE_HUSH_INTERACTIVE
    4033     input->promptmode = 0; /* PS1 */
    4034 #endif
    40354183    if (MAYBE_ASSIGNMENT != 0)
    40364184        dest.o_assignment = MAYBE_ASSIGNMENT;
     
    40584206             * checking only ')' */
    40594207            if (end_trigger == ')') {
    4060                 syntax_error_unterm_ch('('); /* exits */
    4061                 /* goto parse_error; */
     4208                syntax_error_unterm_ch('(');
     4209                goto parse_error;
    40624210            }
    40634211
     
    40724220             * bash says: "syntax error near unexpected token '&'") */
    40734221            if (pi->num_cmds == 0
    4074                 IF_HAS_KEYWORDS( && pi->res_word == RES_NONE)
     4222            IF_HAS_KEYWORDS(&& pi->res_word == RES_NONE)
    40754223            ) {
    40764224                free_pipe_list(pi);
     
    42254373            /* Do we sit outside of any if's, loops or case's? */
    42264374            if (!HAS_KEYWORDS
    4227              IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0))
     4375            IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0))
    42284376            ) {
    42294377                o_free(&dest);
     
    43544502            break;
    43554503        case '$':
    4356             if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) {
     4504            if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) {
    43574505                debug_printf_parse("parse_stream parse error: "
    4358                     "parse_dollar returned non-0\n");
     4506                    "parse_dollar returned 0 (error)\n");
    43594507                goto parse_error;
    43604508            }
     
    43624510        case '\'':
    43634511            dest.has_quoted_part = 1;
    4364             while (1) {
    4365                 ch = i_getch(input);
    4366                 if (ch == EOF) {
    4367                     syntax_error_unterm_ch('\'');
    4368                     /*xfunc_die(); - redundant */
     4512            if (next == '\'' && !ctx.pending_redirect) {
     4513 insert_empty_quoted_str_marker:
     4514                nommu_addchr(&ctx.as_string, next);
     4515                i_getch(input); /* eat second ' */
     4516                o_addchr(&dest, SPECIAL_VAR_SYMBOL);
     4517                o_addchr(&dest, SPECIAL_VAR_SYMBOL);
     4518            } else {
     4519                while (1) {
     4520                    ch = i_getch(input);
     4521                    if (ch == EOF) {
     4522                        syntax_error_unterm_ch('\'');
     4523                        goto parse_error;
     4524                    }
     4525                    nommu_addchr(&ctx.as_string, ch);
     4526                    if (ch == '\'')
     4527                        break;
     4528                    o_addqchr(&dest, ch);
    43694529                }
    4370                 nommu_addchr(&ctx.as_string, ch);
    4371                 if (ch == '\'')
    4372                     break;
    4373                 o_addqchr(&dest, ch);
    43744530            }
    43754531            break;
    43764532        case '"':
    43774533            dest.has_quoted_part = 1;
     4534            if (next == '"' && !ctx.pending_redirect)
     4535                goto insert_empty_quoted_str_marker;
    43784536            if (dest.o_assignment == NOT_ASSIGNMENT)
    43794537                dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS;
    4380             if (encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1))
     4538            if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1))
    43814539                goto parse_error;
    43824540            dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS;
     
    43844542#if ENABLE_HUSH_TICK
    43854543        case '`': {
    4386             unsigned pos;
     4544            USE_FOR_NOMMU(unsigned pos;)
    43874545
    43884546            o_addchr(&dest, SPECIAL_VAR_SYMBOL);
    43894547            o_addchr(&dest, '`');
    4390             pos = dest.length;
    4391             add_till_backquote(&dest, input, /*in_dquote:*/ 0);
     4548            USE_FOR_NOMMU(pos = dest.length;)
     4549            if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0))
     4550                goto parse_error;
    43924551# if !BB_MMU
    43934552            o_addstr(&ctx.as_string, dest.data + pos);
     
    45284687            IF_HAS_KEYWORDS(pctx = p2;)
    45294688        } while (HAS_KEYWORDS && pctx);
    4530         /* Free text, clear all dest fields */
     4689
    45314690        o_free(&dest);
    4532         /* If we are not in top-level parse, we return,
    4533          * our caller will propagate error.
    4534          */
    4535         if (end_trigger != ';') {
     4691        G.last_exitcode = 1;
    45364692#if !BB_MMU
    4537             if (pstring)
    4538                 *pstring = NULL;
    4539 #endif
    4540             debug_leave();
    4541             return ERR_PTR;
    4542         }
    4543         /* Discard cached input, force prompt */
    4544         input->p = NULL;
    4545         IF_HUSH_INTERACTIVE(input->promptme = 1;)
    4546         goto reset;
     4693        if (pstring)
     4694            *pstring = NULL;
     4695#endif
     4696        debug_leave();
     4697        return ERR_PTR;
    45474698    }
    45484699}
     
    46044755/* Store given string, finalizing the word and starting new one whenever
    46054756 * we encounter IFS char(s). This is used for expanding variable values.
    4606  * End-of-string does NOT finalize word: think about 'echo -$VAR-' */
    4607 static int expand_on_ifs(o_string *output, int n, const char *str)
    4608 {
     4757 * End-of-string does NOT finalize word: think about 'echo -$VAR-'.
     4758 * Return in *ended_with_ifs:
     4759 * 1 - ended with IFS char, else 0 (this includes case of empty str).
     4760 */
     4761static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const char *str)
     4762{
     4763    int last_is_ifs = 0;
     4764
    46094765    while (1) {
    4610         int word_len = strcspn(str, G.ifs);
     4766        int word_len;
     4767
     4768        if (!*str)  /* EOL - do not finalize word */
     4769            break;
     4770        word_len = strcspn(str, G.ifs);
    46114771        if (word_len) {
     4772            /* We have WORD_LEN leading non-IFS chars */
    46124773            if (!(output->o_expflags & EXP_FLAG_GLOB)) {
    46134774                o_addblock(output, str, word_len);
     
    46224783                /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */
    46234784            }
     4785            last_is_ifs = 0;
    46244786            str += word_len;
    4625         }
     4787            if (!*str)  /* EOL - do not finalize word */
     4788                break;
     4789        }
     4790
     4791        /* We know str here points to at least one IFS char */
     4792        last_is_ifs = 1;
     4793        str += strspn(str, G.ifs); /* skip IFS chars */
    46264794        if (!*str)  /* EOL - do not finalize word */
    46274795            break;
    4628         o_addchr(output, '\0');
    4629         debug_print_list("expand_on_ifs", output, n);
    4630         n = o_save_ptr(output, n);
    4631         str += strspn(str, G.ifs); /* skip ifs chars */
    4632     }
     4796
     4797        /* Start new word... but not always! */
     4798        /* Case "v=' a'; echo ''$v": we do need to finalize empty word: */
     4799        if (output->has_quoted_part
     4800        /* Case "v=' a'; echo $v":
     4801         * here nothing precedes the space in $v expansion,
     4802         * therefore we should not finish the word
     4803         * (IOW: if there *is* word to finalize, only then do it):
     4804         */
     4805         || (n > 0 && output->data[output->length - 1])
     4806        ) {
     4807            o_addchr(output, '\0');
     4808            debug_print_list("expand_on_ifs", output, n);
     4809            n = o_save_ptr(output, n);
     4810        }
     4811    }
     4812
     4813    if (ended_with_ifs)
     4814        *ended_with_ifs = last_is_ifs;
    46334815    debug_print_list("expand_on_ifs[1]", output, n);
    46344816    return n;
     
    46674849    setup_string_in_str(&input, str);
    46684850    encode_string(NULL, &dest, &input, EOF, process_bkslash);
     4851//TODO: error check (encode_string returns 0 on error)?
    46694852    //bb_error_msg("'%s' -> '%s'", str, dest.data);
    46704853    exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash);
     
    50445227     */
    50455228    char cant_be_null = 0; /* only bit 0x80 matters */
     5229    int ended_in_ifs = 0;  /* did last unquoted expansion end with IFS chars? */
    50465230    char *p;
    50475231
     
    50625246        char arith_buf[sizeof(arith_t)*3 + 2];
    50635247#endif
     5248
     5249        if (ended_in_ifs) {
     5250            o_addchr(output, '\0');
     5251            n = o_save_ptr(output, n);
     5252            ended_in_ifs = 0;
     5253        }
     5254
    50645255        o_addblock(output, arg, p - arg);
    50655256        debug_print_list("expand_vars_to_list[1]", output, n);
     
    50905281            if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
    50915282                while (G.global_argv[i]) {
    5092                     n = expand_on_ifs(output, n, G.global_argv[i]);
     5283                    n = expand_on_ifs(NULL, output, n, G.global_argv[i]);
    50935284                    debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1);
    50945285                    if (G.global_argv[i++][0] && G.global_argv[i]) {
     
    51235314                        o_addchr(output, G.ifs[0]);
    51245315                }
     5316                output->has_quoted_part = 1;
    51255317            }
    51265318            break;
     
    51285320        case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */
    51295321            /* "Empty variable", used to make "" etc to not disappear */
     5322            output->has_quoted_part = 1;
    51305323            arg++;
    51315324            cant_be_null = 0x80;
     
    51655358                        !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
    51665359                if (val && val[0]) {
    5167                     n = expand_on_ifs(output, n, val);
     5360                    n = expand_on_ifs(&ended_in_ifs, output, n, val);
    51685361                    val = NULL;
    51695362                }
    51705363            } else { /* quoted $VAR, val will be appended below */
     5364                output->has_quoted_part = 1;
    51715365                debug_printf_expand("quoted '%s', output->o_escape:%d\n", val,
    51725366                        !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
     
    51935387
    51945388    if (arg[0]) {
     5389        if (ended_in_ifs) {
     5390            o_addchr(output, '\0');
     5391            n = o_save_ptr(output, n);
     5392        }
    51955393        debug_print_list("expand_vars_to_list[a]", output, n);
    51965394        /* this part is literal, and it was already pre-quoted
     
    53235521
    53245522
     5523static void switch_off_special_sigs(unsigned mask)
     5524{
     5525    unsigned sig = 0;
     5526    while ((mask >>= 1) != 0) {
     5527        sig++;
     5528        if (!(mask & 1))
     5529            continue;
     5530        if (G.traps) {
     5531            if (G.traps[sig] && !G.traps[sig][0])
     5532                /* trap is '', has to remain SIG_IGN */
     5533                continue;
     5534            free(G.traps[sig]);
     5535            G.traps[sig] = NULL;
     5536        }
     5537        /* We are here only if no trap or trap was not '' */
     5538        install_sighandler(sig, SIG_DFL);
     5539    }
     5540}
     5541
    53255542#if BB_MMU
    53265543/* never called */
     
    53425559     * Same goes for SIGTERM, SIGHUP, SIGINT.
    53435560     */
    5344     if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS))
    5345         return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */
    5346 
    5347     /* Switching off SPECIAL_INTERACTIVE_SIGS.
    5348      * Stupid. It can be done with *single* &= op, but we can't use
    5349      * the fact that G.blocked_set is implemented as a bitmask
    5350      * in libc... */
    5351     mask = (SPECIAL_INTERACTIVE_SIGS >> 1);
    5352     sig = 1;
    5353     while (1) {
    5354         if (mask & 1) {
    5355             /* Careful. Only if no trap or trap is not "" */
    5356             if (!G.traps || !G.traps[sig] || G.traps[sig][0])
    5357                 sigdelset(&G.blocked_set, sig);
    5358         }
    5359         mask >>= 1;
    5360         if (!mask)
    5361             break;
    5362         sig++;
    5363     }
    5364     /* Our homegrown sig mask is saner to work with :) */
    5365     G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS;
    5366 
    5367     /* Resetting all traps to default except empty ones */
    5368     mask = G.non_DFL_mask;
    5369     if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) {
    5370         if (!G.traps[sig] || !G.traps[sig][0])
    5371             continue;
     5561    mask = (G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS) | G_fatal_sig_mask;
     5562    if (!G.traps && !mask)
     5563        return; /* already no traps and no special sigs */
     5564
     5565    /* Switch off special sigs */
     5566    switch_off_special_sigs(mask);
     5567#if ENABLE_HUSH_JOB
     5568    G_fatal_sig_mask = 0;
     5569#endif
     5570    G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS;
     5571    /* SIGQUIT,SIGCHLD and maybe SPECIAL_JOBSTOP_SIGS
     5572     * remain set in G.special_sig_mask */
     5573
     5574    if (!G.traps)
     5575        return;
     5576
     5577    /* Reset all sigs to default except ones with empty traps */
     5578    for (sig = 0; sig < NSIG; sig++) {
     5579        if (!G.traps[sig])
     5580            continue; /* no trap: nothing to do */
     5581        if (!G.traps[sig][0])
     5582            continue; /* empty trap: has to remain SIG_IGN */
     5583        /* sig has non-empty trap, reset it: */
    53725584        free(G.traps[sig]);
    53735585        G.traps[sig] = NULL;
    5374         /* There is no signal for 0 (EXIT) */
     5586        /* There is no signal for trap 0 (EXIT) */
    53755587        if (sig == 0)
    53765588            continue;
    5377         /* There was a trap handler, we just removed it.
    5378          * But if sig still has non-DFL handling,
    5379          * we should not unblock the sig. */
    5380         if (mask & 1)
    5381             continue;
    5382         sigdelset(&G.blocked_set, sig);
    5383     }
    5384     sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
     5589        install_sighandler(sig, pick_sighandler(sig));
     5590    }
    53855591}
    53865592
     
    54935699     *
    54945700     * I conclude it means we don't need to pass active traps here.
    5495      * Even if we would use signal handlers instead of signal masking
    5496      * in order to implement trap handling,
    5497      * exec syscall below resets signals to SIG_DFL for us.
    54985701     */
    54995702    *pp++ = (char *) "-c";
     
    55125715 do_exec:
    55135716    debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s);
    5514     sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
     5717    /* Don't propagate SIG_IGN to the child */
     5718    if (SPECIAL_JOBSTOP_SIGS != 0)
     5719        switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
    55155720    execve(bb_busybox_exec_path, argv, pp);
    55165721    /* Fallback. Useful for init=/bin/hush usage etc */
     
    55435748        struct pipe *pipe_list;
    55445749
     5750#if ENABLE_HUSH_INTERACTIVE
     5751        if (end_trigger == ';')
     5752            inp->promptmode = 0; /* PS1 */
     5753#endif
    55455754        pipe_list = parse_stream(NULL, inp, end_trigger);
    5546         if (!pipe_list) { /* EOF */
    5547             if (empty)
     5755        if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */
     5756            /* If we are in "big" script
     5757             * (not in `cmd` or something similar)...
     5758             */
     5759            if (pipe_list == ERR_PTR && end_trigger == ';') {
     5760                /* Discard cached input (rest of line) */
     5761                int ch = inp->last_char;
     5762                while (ch != EOF && ch != '\n') {
     5763                    //bb_error_msg("Discarded:'%c'", ch);
     5764                    ch = i_getch(inp);
     5765                }
     5766                /* Force prompt */
     5767                inp->p = NULL;
     5768                /* This stream isn't empty */
     5769                empty = 0;
     5770                continue;
     5771            }
     5772            if (!pipe_list && empty)
    55485773                G.last_exitcode = 0;
    55495774            break;
     
    55535778        run_and_free_list(pipe_list);
    55545779        empty = 0;
     5780#if ENABLE_HUSH_FUNCTIONS
     5781        if (G.flag_return_in_progress == 1)
     5782            break;
     5783#endif
    55555784    }
    55565785}
     
    61196348{
    61206349#if BB_MMU
    6121     int rcode = x->b_function(argv);
     6350    int rcode;
     6351    fflush_all();
     6352    rcode = x->b_function(argv);
    61226353    fflush_all();
    61236354    _exit(rcode);
    61246355#else
     6356    fflush_all();
    61256357    /* On NOMMU, we must never block!
    61266358     * Example: { sleep 99 | read line; } & echo Ok
     
    61396371{
    61406372    debug_printf_exec("execing '%s'\n", argv[0]);
    6141     sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
     6373    /* Don't propagate SIG_IGN to the child */
     6374    if (SPECIAL_JOBSTOP_SIGS != 0)
     6375        switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
    61426376    execvp(argv[0], argv);
    61436377    bb_perror_msg("can't execute '%s'", argv[0]);
     
    62716505            /* Re-exec ourselves */
    62726506            debug_printf_exec("re-execing applet '%s'\n", argv[0]);
    6273             sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
     6507            /* Don't propagate SIG_IGN to the child */
     6508            if (SPECIAL_JOBSTOP_SIGS != 0)
     6509                switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
    62746510            execv(bb_busybox_exec_path, argv);
    62756511            /* If they called chroot or otherwise made the binary no longer
     
    65146750                    ex = WEXITSTATUS(status);
    65156751                    /* bash prints killer signal's name for *last*
    6516                      * process in pipe (prints just newline for SIGINT).
     6752                     * process in pipe (prints just newline for SIGINT/SIGPIPE).
    65176753                     * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT)
    65186754                     */
     
    65206756                        int sig = WTERMSIG(status);
    65216757                        if (i == fg_pipe->num_cmds-1)
    6522                             printf("%s\n", sig == SIGINT ? "" : get_signame(sig));
     6758                            /* TODO: use strsignal() instead for bash compat? but that's bloat... */
     6759                            printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig));
     6760                        /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */
    65236761                        /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here?
    65246762                         * Maybe we need to use sig | 128? */
     
    65276765                    fg_pipe->cmds[i].cmd_exitcode = ex;
    65286766                } else {
    6529                     fg_pipe->cmds[i].is_stopped = 1;
    65306767                    fg_pipe->stopped_cmds++;
    65316768                }
     
    65886825        } else {
    65896826            /* child stopped */
    6590             pi->cmds[i].is_stopped = 1;
    65916827            pi->stopped_cmds++;
    65926828        }
     
    66296865 * cmd && ...  { list } && ...
    66306866 * cmd || ...  { list } || ...
    6631  * If it is, then we can run cmd as a builtin, NOFORK [do we do this?],
     6867 * If it is, then we can run cmd as a builtin, NOFORK,
    66326868 * or (if SH_STANDALONE) an applet, and we can run the { list }
    66336869 * with run_list. If it isn't one of these, we fork and exec cmd.
     
    68117047
    68127048        /* Expand the rest into (possibly) many strings each */
    6813         if (0) {}
    68147049#if ENABLE_HUSH_BASH_COMPAT
    6815         else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) {
     7050        if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) {
    68167051            argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);
    6817         }
    6818 #endif
    6819         else {
     7052        } else
     7053#endif
     7054        {
    68207055            argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt);
    68217056        }
     
    68477082                    debug_printf_exec(": builtin '%s' '%s'...\n",
    68487083                        x->b_cmd, argv_expanded[1]);
     7084                    fflush_all();
    68497085                    rcode = x->b_function(argv_expanded) & 0xff;
    68507086                    fflush_all();
     
    68797115        }
    68807116
    6881         if (ENABLE_FEATURE_SH_STANDALONE) {
     7117        if (ENABLE_FEATURE_SH_NOFORK) {
    68827118            int n = find_applet_by_name(argv_expanded[0]);
    68837119            if (n >= 0 && APPLET_IS_NOFORK(n)) {
     
    69687204                _exit(1);
    69697205
    6970             /* Restore default handlers just prior to exec */
    6971             /*signal(SIGCHLD, SIG_DFL); - so far we don't have any handlers */
    6972 
    69737206            /* Stores to nommu_save list of env vars putenv'ed
    69747207             * (NOMMU, on MMU we don't need that) */
     
    72487481                G.last_exitcode = rcode;
    72497482                debug_printf_exec(": builtin/func exitcode %d\n", rcode);
    7250                 check_and_run_traps(0);
     7483                check_and_run_traps();
    72517484#if ENABLE_HUSH_LOOPS
    72527485                /* Was it "break" or "continue"? */
     
    72807513                 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
    72817514                 * I'm NOT treating inner &'s as jobs */
    7282                 check_and_run_traps(0);
     7515                check_and_run_traps();
    72837516#if ENABLE_HUSH_JOB
    72847517                if (G.run_list_level == 1)
     
    72957528                    rcode = checkjobs_and_fg_shell(pi);
    72967529                    debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode);
    7297                     check_and_run_traps(0);
     7530                    check_and_run_traps();
    72987531                } else
    72997532#endif
     
    73017534                    rcode = checkjobs(pi);
    73027535                    debug_printf_exec(": checkjobs exitcode %d\n", rcode);
    7303                     check_and_run_traps(0);
     7536                    check_and_run_traps();
    73047537                }
    73057538                G.last_exitcode = rcode;
     
    73167549        if (pi->next
    73177550         && (pi->next->res_word == RES_DO || pi->next->res_word == RES_DONE)
    7318         /* (the second check above is needed for "while ...; do \n done" case) */
     7551         /* check for RES_DONE is needed for "while ...; do \n done" case */
    73197552        ) {
    73207553            if (rword == RES_WHILE) {
     
    73627595    int rcode = 0;
    73637596    debug_printf_exec("run_and_free_list entered\n");
    7364     if (!G.n_mode) {
     7597    if (!G.o_opt[OPT_O_NOEXEC]) {
    73657598        debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds);
    73667599        rcode = run_list(pi);
     
    73757608
    73767609
     7610static void install_sighandlers(unsigned mask)
     7611{
     7612    sighandler_t old_handler;
     7613    unsigned sig = 0;
     7614    while ((mask >>= 1) != 0) {
     7615        sig++;
     7616        if (!(mask & 1))
     7617            continue;
     7618        old_handler = install_sighandler(sig, pick_sighandler(sig));
     7619        /* POSIX allows shell to re-enable SIGCHLD
     7620         * even if it was SIG_IGN on entry.
     7621         * Therefore we skip IGN check for it:
     7622         */
     7623        if (sig == SIGCHLD)
     7624            continue;
     7625        if (old_handler == SIG_IGN) {
     7626            /* oops... restore back to IGN, and record this fact */
     7627            install_sighandler(sig, old_handler);
     7628            if (!G.traps)
     7629                G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
     7630            free(G.traps[sig]);
     7631            G.traps[sig] = xzalloc(1); /* == xstrdup(""); */
     7632        }
     7633    }
     7634}
     7635
    73777636/* Called a few times only (or even once if "sh -c") */
    7378 static void init_sigmasks(void)
    7379 {
    7380     unsigned sig;
     7637static void install_special_sighandlers(void)
     7638{
    73817639    unsigned mask;
    7382     sigset_t old_blocked_set;
    7383 
    7384     if (!G.inherited_set_is_saved) {
    7385         sigprocmask(SIG_SETMASK, NULL, &G.blocked_set);
    7386         G.inherited_set = G.blocked_set;
    7387     }
    7388     old_blocked_set = G.blocked_set;
    7389 
    7390     mask = (1 << SIGQUIT);
     7640
     7641    /* Which signals are shell-special? */
     7642    mask = (1 << SIGQUIT) | (1 << SIGCHLD);
    73917643    if (G_interactive_fd) {
    7392         mask = (1 << SIGQUIT) | SPECIAL_INTERACTIVE_SIGS;
     7644        mask |= SPECIAL_INTERACTIVE_SIGS;
    73937645        if (G_saved_tty_pgrp) /* we have ctty, job control sigs work */
    7394             mask |= SPECIAL_JOB_SIGS;
    7395     }
    7396     G.non_DFL_mask = mask;
    7397 
    7398     sig = 0;
    7399     while (mask) {
    7400         if (mask & 1)
    7401             sigaddset(&G.blocked_set, sig);
    7402         mask >>= 1;
    7403         sig++;
    7404     }
    7405     sigdelset(&G.blocked_set, SIGCHLD);
    7406 
    7407     if (memcmp(&old_blocked_set, &G.blocked_set, sizeof(old_blocked_set)) != 0)
    7408         sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
    7409 
    7410     /* POSIX allows shell to re-enable SIGCHLD
    7411      * even if it was SIG_IGN on entry */
    7412 #if ENABLE_HUSH_FAST
    7413     G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
    7414     if (!G.inherited_set_is_saved)
    7415         signal(SIGCHLD, SIGCHLD_handler);
    7416 #else
    7417     if (!G.inherited_set_is_saved)
    7418         signal(SIGCHLD, SIG_DFL);
    7419 #endif
    7420 
    7421     G.inherited_set_is_saved = 1;
     7646            mask |= SPECIAL_JOBSTOP_SIGS;
     7647    }
     7648    /* Careful, do not re-install handlers we already installed */
     7649    if (G.special_sig_mask != mask) {
     7650        unsigned diff = mask & ~G.special_sig_mask;
     7651        G.special_sig_mask = mask;
     7652        install_sighandlers(diff);
     7653    }
    74227654}
    74237655
    74247656#if ENABLE_HUSH_JOB
    74257657/* helper */
    7426 static void maybe_set_to_sigexit(int sig)
    7427 {
    7428     void (*handler)(int);
    7429     /* non_DFL_mask'ed signals are, well, masked,
    7430      * no need to set handler for them.
     7658/* Set handlers to restore tty pgrp and exit */
     7659static void install_fatal_sighandlers(void)
     7660{
     7661    unsigned mask;
     7662
     7663    /* We will restore tty pgrp on these signals */
     7664    mask = 0
     7665        + (1 << SIGILL ) * HUSH_DEBUG
     7666        + (1 << SIGFPE ) * HUSH_DEBUG
     7667        + (1 << SIGBUS ) * HUSH_DEBUG
     7668        + (1 << SIGSEGV) * HUSH_DEBUG
     7669        + (1 << SIGTRAP) * HUSH_DEBUG
     7670        + (1 << SIGABRT)
     7671    /* bash 3.2 seems to handle these just like 'fatal' ones */
     7672        + (1 << SIGPIPE)
     7673        + (1 << SIGALRM)
     7674    /* if we are interactive, SIGHUP, SIGTERM and SIGINT are special sigs.
     7675     * if we aren't interactive... but in this case
     7676     * we never want to restore pgrp on exit, and this fn is not called
    74317677     */
    7432     if (!((G.non_DFL_mask >> sig) & 1)) {
    7433         handler = signal(sig, sigexit);
    7434         if (handler == SIG_IGN) /* oops... restore back to IGN! */
    7435             signal(sig, handler);
    7436     }
    7437 }
    7438 /* Set handlers to restore tty pgrp and exit */
    7439 static void set_fatal_handlers(void)
    7440 {
    7441     /* We _must_ restore tty pgrp on fatal signals */
    7442     if (HUSH_DEBUG) {
    7443         maybe_set_to_sigexit(SIGILL );
    7444         maybe_set_to_sigexit(SIGFPE );
    7445         maybe_set_to_sigexit(SIGBUS );
    7446         maybe_set_to_sigexit(SIGSEGV);
    7447         maybe_set_to_sigexit(SIGTRAP);
    7448     } /* else: hush is perfect. what SEGV? */
    7449     maybe_set_to_sigexit(SIGABRT);
    7450     /* bash 3.2 seems to handle these just like 'fatal' ones */
    7451     maybe_set_to_sigexit(SIGPIPE);
    7452     maybe_set_to_sigexit(SIGALRM);
    7453     /* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked.
    7454      * if we aren't interactive... but in this case
    7455      * we never want to restore pgrp on exit, and this fn is not called */
    7456     /*maybe_set_to_sigexit(SIGHUP );*/
    7457     /*maybe_set_to_sigexit(SIGTERM);*/
    7458     /*maybe_set_to_sigexit(SIGINT );*/
     7678        /*+ (1 << SIGHUP )*/
     7679        /*+ (1 << SIGTERM)*/
     7680        /*+ (1 << SIGINT )*/
     7681    ;
     7682    G_fatal_sig_mask = mask;
     7683
     7684    install_sighandlers(mask);
    74597685}
    74607686#endif
     
    74657691    switch (mode) {
    74667692    case 'n':
    7467         G.n_mode = state;
     7693        G.o_opt[OPT_O_NOEXEC] = state;
    74687694        break;
    74697695    case 'x':
     
    75027728int hush_main(int argc, char **argv)
    75037729{
     7730    enum {
     7731        OPT_login = (1 << 0),
     7732    };
     7733    unsigned flags;
    75047734    int opt;
    75057735    unsigned builtin_argc;
     
    75097739
    75107740    INIT_G();
    7511     if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */
     7741    if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
    75127742        G.last_exitcode = EXIT_SUCCESS;
     7743#if ENABLE_HUSH_FAST
     7744    G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
     7745#endif
    75137746#if !BB_MMU
    75147747    G.argv0_for_re_execing = argv[0];
     
    75847817#if ENABLE_FEATURE_EDITING
    75857818    G.line_input_state = new_line_input_t(FOR_SHELL);
    7586 # if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_HUSH_SAVEHISTORY
    7587     {
    7588         const char *hp = get_local_var_value("HISTFILE");
    7589         if (!hp) {
    7590             hp = get_local_var_value("HOME");
    7591             if (hp) {
    7592                 G.line_input_state->hist_file = concat_path_file(hp, ".hush_history");
    7593                 //set_local_var(xasprintf("HISTFILE=%s", ...));
    7594             }
    7595         }
    7596     }
    7597 # endif
    7598 #endif
    7599 
    7600     G.global_argc = argc;
    7601     G.global_argv = argv;
     7819#endif
     7820
    76027821    /* Initialize some more globals to non-zero values */
    76037822    cmdedit_update_prompt();
     
    76117830
    76127831    /* Shell is non-interactive at first. We need to call
    7613      * init_sigmasks() if we are going to execute "sh <script>",
     7832     * install_special_sighandlers() if we are going to execute "sh <script>",
    76147833     * "sh -c <cmds>" or login shell's /etc/profile and friends.
    7615      * If we later decide that we are interactive, we run init_sigmasks()
     7834     * If we later decide that we are interactive, we run install_special_sighandlers()
    76167835     * in order to intercept (more) signals.
    76177836     */
     
    76197838    /* Parse options */
    76207839    /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */
     7840    flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0;
    76217841    builtin_argc = 0;
    76227842    while (1) {
    7623         opt = getopt(argc, argv, "+c:xins"
     7843        opt = getopt(argc, argv, "+c:xinsl"
    76247844#if !BB_MMU
    76257845                "<:$:R:V:"
     
    76537873                const struct built_in_command *x;
    76547874
    7655                 init_sigmasks();
     7875                install_special_sighandlers();
    76567876                x = find_builtin(optarg);
    76577877                if (x) { /* paranoia */
     
    76597879                    G.global_argv += builtin_argc;
    76607880                    G.global_argv[-1] = NULL; /* replace "" */
     7881                    fflush_all();
    76617882                    G.last_exitcode = x->b_function(argv + optind - 1);
    76627883                }
     
    76697890                G.global_argc++;
    76707891            } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */
    7671             init_sigmasks();
     7892            install_special_sighandlers();
    76727893            parse_and_run_string(optarg);
    76737894            goto final_return;
     
    76807901            /* "-s" means "read from stdin", but this is how we always
    76817902             * operate, so simply do nothing here. */
     7903            break;
     7904        case 'l':
     7905            flags |= OPT_login;
    76827906            break;
    76837907#if !BB_MMU
     
    77017925            if (empty_trap_mask != 0) {
    77027926                int sig;
    7703                 init_sigmasks();
     7927                install_special_sighandlers();
    77047928                G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
    77057929                for (sig = 1; sig < NSIG; sig++) {
    77067930                    if (empty_trap_mask & (1LL << sig)) {
    77077931                        G.traps[sig] = xzalloc(1); /* == xstrdup(""); */
    7708                         sigaddset(&G.blocked_set, sig);
     7932                        install_sighandler(sig, SIG_IGN);
    77097933                    }
    77107934                }
    7711                 sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
    77127935            }
    77137936# if ENABLE_HUSH_LOOPS
     
    77477970    } /* option parsing loop */
    77487971
     7972    /* Skip options. Try "hush -l": $1 should not be "-l"! */
     7973    G.global_argc = argc - (optind - 1);
     7974    G.global_argv = argv + (optind - 1);
     7975    G.global_argv[0] = argv[0];
     7976
    77497977    if (!G.root_pid) {
    77507978        G.root_pid = getpid();
     
    77537981
    77547982    /* If we are login shell... */
    7755     if (argv[0] && argv[0][0] == '-') {
     7983    if (flags & OPT_login) {
    77567984        FILE *input;
    77577985        debug_printf("sourcing /etc/profile\n");
     
    77597987        if (input != NULL) {
    77607988            close_on_exec_on(fileno(input));
    7761             init_sigmasks();
     7989            install_special_sighandlers();
    77627990            parse_and_run_file(input);
    77637991            fclose(input);
     
    77728000    }
    77738001
    7774     if (argv[optind]) {
     8002    if (G.global_argv[1]) {
    77758003        FILE *input;
    77768004        /*
     
    77798007         * If called as sh, does the same but with $ENV.
    77808008         */
    7781         debug_printf("running script '%s'\n", argv[optind]);
    7782         G.global_argv = argv + optind;
    7783         G.global_argc = argc - optind;
    7784         input = xfopen_for_read(argv[optind]);
     8009        G.global_argc--;
     8010        G.global_argv++;
     8011        debug_printf("running script '%s'\n", G.global_argv[0]);
     8012        input = xfopen_for_read(G.global_argv[0]);
    77858013        close_on_exec_on(fileno(input));
    7786         init_sigmasks();
     8014        install_special_sighandlers();
    77878015        parse_and_run_file(input);
    77888016#if ENABLE_FEATURE_CLEAN_UP
     
    77938021
    77948022    /* Up to here, shell was non-interactive. Now it may become one.
    7795      * NB: don't forget to (re)run init_sigmasks() as needed.
     8023     * NB: don't forget to (re)run install_special_sighandlers() as needed.
    77968024     */
    77978025
     
    78458073        }
    78468074
    7847         /* Block some signals */
    7848         init_sigmasks();
     8075        /* Install more signal handlers */
     8076        install_special_sighandlers();
    78498077
    78508078        if (G_saved_tty_pgrp) {
    78518079            /* Set other signals to restore saved_tty_pgrp */
    7852             set_fatal_handlers();
     8080            install_fatal_sighandlers();
    78538081            /* Put ourselves in our own process group
    78548082             * (bash, too, does this only if ctty is available) */
     
    78608088         * (we reset die_sleep = 0 whereever we [v]fork) */
    78618089        enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
     8090
     8091# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
     8092        {
     8093            const char *hp = get_local_var_value("HISTFILE");
     8094            if (!hp) {
     8095                hp = get_local_var_value("HOME");
     8096                if (hp)
     8097                    hp = concat_path_file(hp, ".hush_history");
     8098            } else {
     8099                hp = xstrdup(hp);
     8100            }
     8101            if (hp) {
     8102                G.line_input_state->hist_file = hp;
     8103                //set_local_var(xasprintf("HISTFILE=%s", ...));
     8104            }
     8105#  if ENABLE_FEATURE_SH_HISTFILESIZE
     8106            hp = get_local_var_value("HISTFILESIZE");
     8107            G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
     8108#  endif
     8109        }
     8110# endif
    78628111    } else {
    7863         init_sigmasks();
     8112        install_special_sighandlers();
    78648113    }
    78658114#elif ENABLE_HUSH_INTERACTIVE
     
    78788127        close_on_exec_on(G_interactive_fd);
    78798128    }
    7880     init_sigmasks();
     8129    install_special_sighandlers();
    78818130#else
    78828131    /* We have interactiveness code disabled */
    7883     init_sigmasks();
     8132    install_special_sighandlers();
    78848133#endif
    78858134    /* bash:
     
    80158264
    80168265    /* TODO: if exec fails, bash does NOT exit! We do.
    8017      * We'll need to undo sigprocmask (it's inside execvp_or_die)
     8266     * We'll need to undo trap cleanup (it's inside execvp_or_die)
    80188267     * and tcsetpgrp, and this is inherently racy.
    80198268     */
     
    80338282     * # exit
    80348283     * exit
    8035      # EEE (then bash exits)
     8284     * EEE (then bash exits)
    80368285     *
    80378286     * TODO: we can use G.exiting = -1 as indicator "last cmd was exit"
     
    82128461        ret = EXIT_SUCCESS;
    82138462        while (*argv) {
     8463            sighandler_t handler;
     8464
    82148465            sig = get_signum(*argv++);
    82158466            if (sig < 0 || sig >= NSIG) {
     
    82308481                continue;
    82318482
    8232             if (new_cmd) {
    8233                 sigaddset(&G.blocked_set, sig);
    8234             } else {
    8235                 /* There was a trap handler, we are removing it
    8236                  * (if sig has non-DFL handling,
    8237                  * we don't need to do anything) */
    8238                 if (sig < 32 && (G.non_DFL_mask & (1 << sig)))
    8239                     continue;
    8240                 sigdelset(&G.blocked_set, sig);
    8241             }
    8242         }
    8243         sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
     8483            if (new_cmd)
     8484                handler = (new_cmd[0] ? record_pending_signo : SIG_IGN);
     8485            else
     8486                /* We are removing trap handler */
     8487                handler = pick_sighandler(sig);
     8488            install_sighandler(sig, handler);
     8489        }
    82448490        return ret;
    82458491    }
     
    83468592    for (i = 0; i < pi->num_cmds; i++) {
    83478593        debug_printf_jobs("reviving pid %d\n", pi->cmds[i].pid);
    8348         pi->cmds[i].is_stopped = 0;
    83498594    }
    83508595    pi->stopped_cmds = 0;
     
    84428687}
    84438688
     8689/* Interruptibility of read builtin in bash
     8690 * (tested on bash-4.2.8 by sending signals (not by ^C)):
     8691 *
     8692 * Empty trap makes read ignore corresponding signal, for any signal.
     8693 *
     8694 * SIGINT:
     8695 * - terminates non-interactive shell;
     8696 * - interrupts read in interactive shell;
     8697 * if it has non-empty trap:
     8698 * - executes trap and returns to command prompt in interactive shell;
     8699 * - executes trap and returns to read in non-interactive shell;
     8700 * SIGTERM:
     8701 * - is ignored (does not interrupt) read in interactive shell;
     8702 * - terminates non-interactive shell;
     8703 * if it has non-empty trap:
     8704 * - executes trap and returns to read;
     8705 * SIGHUP:
     8706 * - terminates shell (regardless of interactivity);
     8707 * if it has non-empty trap:
     8708 * - executes trap and returns to read;
     8709 */
    84448710static int FAST_FUNC builtin_read(char **argv)
    84458711{
     
    84498715    char *opt_t = NULL;
    84508716    char *opt_u = NULL;
     8717    const char *ifs;
    84518718    int read_flags;
    84528719
     
    84588725        return EXIT_FAILURE;
    84598726    argv += optind;
    8460 
     8727    ifs = get_local_var_value("IFS"); /* can be NULL */
     8728
     8729 again:
    84618730    r = shell_builtin_read(set_local_var_from_halves,
    84628731        argv,
    8463         get_local_var_value("IFS"), /* can be NULL */
     8732        ifs,
    84648733        read_flags,
    84658734        opt_n,
     
    84688737        opt_u
    84698738    );
     8739
     8740    if ((uintptr_t)r == 1 && errno == EINTR) {
     8741        unsigned sig = check_and_run_traps();
     8742        if (sig && sig != SIGINT)
     8743            goto again;
     8744    }
    84708745
    84718746    if ((uintptr_t)r > 1) {
     
    87018976{
    87028977    int ret = EXIT_SUCCESS;
    8703     int status, sig;
     8978    int status;
    87048979
    87058980    argv = skip_dash_dash(argv);
     
    87218996         * $
    87228997         */
    8723         sigaddset(&G.blocked_set, SIGCHLD);
    8724         sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
    87258998        while (1) {
    8726             checkjobs(NULL);
    8727             if (errno == ECHILD)
     8999            int sig;
     9000            sigset_t oldset, allsigs;
     9001
     9002            /* waitpid is not interruptible by SA_RESTARTed
     9003             * signals which we use. Thus, this ugly dance:
     9004             */
     9005
     9006            /* Make sure possible SIGCHLD is stored in kernel's
     9007             * pending signal mask before we call waitpid.
     9008             * Or else we may race with SIGCHLD, lose it,
     9009             * and get stuck in sigwaitinfo...
     9010             */
     9011            sigfillset(&allsigs);
     9012            sigprocmask(SIG_SETMASK, &allsigs, &oldset);
     9013
     9014            if (!sigisemptyset(&G.pending_set)) {
     9015                /* Crap! we raced with some signal! */
     9016            //  sig = 0;
     9017                goto restore;
     9018            }
     9019
     9020            checkjobs(NULL); /* waitpid(WNOHANG) inside */
     9021            if (errno == ECHILD) {
     9022                sigprocmask(SIG_SETMASK, &oldset, NULL);
    87289023                break;
    8729             /* Wait for SIGCHLD or any other signal of interest */
    8730             /* sigtimedwait with infinite timeout: */
    8731             sig = sigwaitinfo(&G.blocked_set, NULL);
    8732             if (sig > 0) {
    8733                 sig = check_and_run_traps(sig);
    8734                 if (sig && sig != SIGCHLD) { /* see note 2 */
    8735                     ret = 128 + sig;
    8736                     break;
    8737                 }
    8738             }
    8739         }
    8740         sigdelset(&G.blocked_set, SIGCHLD);
    8741         sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
     9024            }
     9025
     9026            /* Wait for SIGCHLD or any other signal */
     9027            //sig = sigwaitinfo(&allsigs, NULL);
     9028            /* It is vitally important for sigsuspend that SIGCHLD has non-DFL handler! */
     9029            /* Note: sigsuspend invokes signal handler */
     9030            sigsuspend(&oldset);
     9031 restore:
     9032            sigprocmask(SIG_SETMASK, &oldset, NULL);
     9033
     9034            /* So, did we get a signal? */
     9035            //if (sig > 0)
     9036            //  raise(sig); /* run handler */
     9037            sig = check_and_run_traps();
     9038            if (sig /*&& sig != SIGCHLD - always true */) {
     9039                /* see note 2 */
     9040                ret = 128 + sig;
     9041                break;
     9042            }
     9043            /* SIGCHLD, or no signal, or ignored one, such as SIGQUIT. Repeat */
     9044        }
    87429045        return ret;
    87439046    }
Note: See TracChangeset for help on using the changeset viewer.