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


Ignore:
Timestamp:
Jan 1, 2014, 12:47:38 AM (10 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.21.1
Location:
branches/3.2/mindi-busybox/shell
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • branches/3.2/mindi-busybox/shell/Config.src

    r2725 r3232  
    124124    depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS
    125125    help
    126       This option causes busybox shells [currently only ash]
    127       to not execute typical fork/exec/wait sequence, but call <applet>_main
    128       directly, if possible. (Sometimes it is not possible: for example,
     126      This option causes busybox shells to not execute typical
     127      fork/exec/wait sequence, but call <applet>_main directly,
     128      if possible. (Sometimes it is not possible: for example,
    129129      this is not possible in pipes).
    130130
     
    134134      This may significantly speed up some shell scripts.
    135135
    136       This feature is relatively new. Use with care.
     136      This feature is relatively new. Use with care. Report bugs
     137      to project mailing list.
     138
     139config FEATURE_SH_HISTFILESIZE
     140    bool "Use $HISTFILESIZE"
     141    default y
     142    depends on HUSH || ASH
     143    help
     144      This option makes busybox shells to use $HISTFILESIZE variable
     145      to set shell history size. Note that its max value is capped
     146      by "History size" setting in library tuning section.
     147
    137148
    138149endmenu
  • branches/3.2/mindi-busybox/shell/ash.c

    r2725 r3232  
    2424 *      define DEBUG=2 to compile in and turn on debugging.
    2525 *
    26  * When debugging is on, debugging info will be written to ./trace and
    27  * a quit signal will generate a core dump.
     26 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
     27 * debugging info will be written to ./trace and a quit signal
     28 * will generate a core dump.
    2829 */
    2930#define DEBUG 0
     
    3738#define JOBS ENABLE_ASH_JOB_CONTROL
    3839
    39 #include "busybox.h" /* for applet_names */
    4040#include <paths.h>
    4141#include <setjmp.h>
    4242#include <fnmatch.h>
    4343#include <sys/times.h>
     44
     45#include "busybox.h" /* for applet_names */
     46#include "unicode.h"
    4447
    4548#include "shell_common.h"
     
    7275# error "Do not even bother, ash will not run on NOMMU machine"
    7376#endif
    74 
    75 //applet:IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP))
    76 //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh))
    77 //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash))
    78 
    79 //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
    80 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
    8177
    8278//config:config ASH
     
    9894//config:     Enable bash-compatible extensions.
    9995//config:
     96//config:config ASH_IDLE_TIMEOUT
     97//config:   bool "Idle timeout variable"
     98//config:   default n
     99//config:   depends on ASH
     100//config:   help
     101//config:     Enables bash-like auto-logout after $TMOUT seconds of idle time.
     102//config:
    100103//config:config ASH_JOB_CONTROL
    101104//config:   bool "Job control"
     
    106109//config:
    107110//config:config ASH_ALIAS
    108 //config:   bool "alias support"
     111//config:   bool "Alias support"
    109112//config:   default y
    110113//config:   depends on ASH
     
    117120//config:   depends on ASH
    118121//config:   help
    119 //config:     Enable getopts builtin in the ash shell.
     122//config:     Enable support for getopts builtin in ash.
    120123//config:
    121124//config:config ASH_BUILTIN_ECHO
     
    124127//config:   depends on ASH
    125128//config:   help
    126 //config:     Enable support for echo, builtin to ash.
     129//config:     Enable support for echo builtin in ash.
    127130//config:
    128131//config:config ASH_BUILTIN_PRINTF
     
    131134//config:   depends on ASH
    132135//config:   help
    133 //config:     Enable support for printf, builtin to ash.
     136//config:     Enable support for printf builtin in ash.
    134137//config:
    135138//config:config ASH_BUILTIN_TEST
     
    138141//config:   depends on ASH
    139142//config:   help
    140 //config:     Enable support for test, builtin to ash.
     143//config:     Enable support for test builtin in ash.
    141144//config:
    142145//config:config ASH_CMDCMD
     
    154157//config:   depends on ASH
    155158//config:   help
    156 //config:     Enable "check for new mail" in the ash shell.
     159//config:     Enable "check for new mail" function in the ash shell.
    157160//config:
    158161//config:config ASH_OPTIMIZE_FOR_SIZE
     
    184187//config:
    185188
    186 //usage:#define ash_trivial_usage NOUSAGE_STR
    187 //usage:#define ash_full_usage ""
    188 //usage:#define sh_trivial_usage NOUSAGE_STR
    189 //usage:#define sh_full_usage ""
    190 //usage:#define bash_trivial_usage NOUSAGE_STR
    191 //usage:#define bash_full_usage ""
     189//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
     190//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
     191//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
     192
     193//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
     194//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
    192195
    193196
     
    401404
    402405/* ============ Interrupts / exceptions */
     406
     407static void exitshell(void) NORETURN;
     408
    403409/*
    404410 * These macros allow the user to suspend the handling of interrupt signals
     
    18811887#if ENABLE_ASH_MAIL
    18821888static void chkmail(void);
    1883 static void changemail(const char *) FAST_FUNC;
     1889static void changemail(const char *var_value) FAST_FUNC;
     1890#else
     1891# define chkmail()  ((void)0)
    18841892#endif
    18851893static void changepath(const char *) FAST_FUNC;
     
    18931901    void (*var_func)(const char *) FAST_FUNC;
    18941902} varinit_data[] = {
     1903    /*
     1904     * Note: VEXPORT would not work correctly here for NOFORK applets:
     1905     * some environment strings may be constant.
     1906     */
    18951907    { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
    18961908#if ENABLE_ASH_MAIL
     
    34853497    case S_CATCH:
    34863498        act.sa_handler = signal_handler;
    3487         act.sa_flags = 0; /* matters only if !DFL and !IGN */
    3488         sigfillset(&act.sa_mask); /* ditto */
    34893499        break;
    34903500    case S_IGN:
     
    34923502        break;
    34933503    }
     3504
     3505    /* flags and mask matter only if !DFL and !IGN, but we do it
     3506     * for all cases for more deterministic behavior:
     3507     */
     3508    act.sa_flags = 0;
     3509    sigfillset(&act.sa_mask);
     3510
    34943511    sigaction_set(signo, &act);
    34953512
     
    35283545    /* first remove from list */
    35293546    jpp = curp = &curjob;
    3530     do {
     3547    while (1) {
    35313548        jp1 = *jpp;
    35323549        if (jp1 == jp)
    35333550            break;
    35343551        jpp = &jp1->prev_job;
    3535     } while (1);
     3552    }
    35363553    *jpp = jp1->prev_job;
    35373554
     
    35483565    case CUR_RUNNING:
    35493566        /* newly created job or backgrounded job,
    3550            put after all stopped jobs. */
    3551         do {
     3567         * put after all stopped jobs.
     3568         */
     3569        while (1) {
    35523570            jp1 = *jpp;
    35533571#if JOBS
     
    35563574                break;
    35573575            jpp = &jp1->prev_job;
    3558         } while (1);
     3576        }
    35593577        /* FALLTHROUGH */
    35603578#if JOBS
     
    37293747        /* fd is a tty at this point */
    37303748        close_on_exec_on(fd);
    3731         do { /* while we are in the background */
     3749        while (1) { /* while we are in the background */
    37323750            pgrp = tcgetpgrp(fd);
    37333751            if (pgrp < 0) {
     
    37403758                break;
    37413759            killpg(0, SIGTTIN);
    3742         } while (1);
     3760        }
    37433761        initialpgrp = pgrp;
    37443762
     
    37723790killcmd(int argc, char **argv)
    37733791{
    3774     int i = 1;
    37753792    if (argv[1] && strcmp(argv[1], "-l") != 0) {
     3793        int i = 1;
    37763794        do {
    37773795            if (argv[i][0] == '%') {
    3778                 struct job *jp = getjob(argv[i], 0);
    3779                 unsigned pid = jp->ps[0].ps_pid;
    3780                 /* Enough space for ' -NNN<nul>' */
    3781                 argv[i] = alloca(sizeof(int)*3 + 3);
    3782                 /* kill_main has matching code to expect
    3783                  * leading space. Needed to not confuse
    3784                  * negative pids with "kill -SIGNAL_NO" syntax */
    3785                 sprintf(argv[i], " -%u", pid);
     3796                /*
     3797                 * "kill %N" - job kill
     3798                 * Converting to pgrp / pid kill
     3799                 */
     3800                struct job *jp;
     3801                char *dst;
     3802                int j, n;
     3803
     3804                jp = getjob(argv[i], 0);
     3805                /*
     3806                 * In jobs started under job control, we signal
     3807                 * entire process group by kill -PGRP_ID.
     3808                 * This happens, f.e., in interactive shell.
     3809                 *
     3810                 * Otherwise, we signal each child via
     3811                 * kill PID1 PID2 PID3.
     3812                 * Testcases:
     3813                 * sh -c 'sleep 1|sleep 1 & kill %1'
     3814                 * sh -c 'true|sleep 2 & sleep 1; kill %1'
     3815                 * sh -c 'true|sleep 1 & sleep 2; kill %1'
     3816                 */
     3817                n = jp->nprocs; /* can't be 0 (I hope) */
     3818                if (jp->jobctl)
     3819                    n = 1;
     3820                dst = alloca(n * sizeof(int)*4);
     3821                argv[i] = dst;
     3822                for (j = 0; j < n; j++) {
     3823                    struct procstat *ps = &jp->ps[j];
     3824                    /* Skip non-running and not-stopped members
     3825                     * (i.e. dead members) of the job
     3826                     */
     3827                    if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
     3828                        continue;
     3829                    /*
     3830                     * kill_main has matching code to expect
     3831                     * leading space. Needed to not confuse
     3832                     * negative pids with "kill -SIGNAL_NO" syntax
     3833                     */
     3834                    dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
     3835                }
     3836                *dst = '\0';
    37863837            }
    37873838        } while (argv[++i]);
     
    38813932        }
    38823933        st &= 0x7f;
     3934//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
    38833935        col = fmtstr(s, 32, strsignal(st));
    38843936        if (WCOREDUMP(status)) {
     
    42154267                job = job->prev_job;
    42164268            }
    4217         } else
     4269        } else {
    42184270            job = getjob(*argv, 0);
     4271        }
    42194272        /* loop until process terminated or stopped */
    42204273        while (job->state == JOBRUNNING)
     
    47124765    /* do job control only in root shell */
    47134766    doing_jobctl = 0;
    4714     if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
     4767    if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
    47154768        pid_t pgrp;
    47164769
     
    47384791        }
    47394792    }
    4740     if (!oldlvl) {
     4793    if (oldlvl == 0) {
    47414794        if (iflag) { /* why if iflag only? */
    47424795            setsignal(SIGINT);
     
    49454998 */
    49464999
     5000#undef EMPTY
     5001#undef CLOSED
    49475002#define EMPTY -2                /* marks an unused slot in redirtab */
    49485003#define CLOSED -3               /* marks a slot of previously-closed fd */
     
    50575112    int f;
    50585113
     5114    fname = redir->nfile.expfname;
    50595115    switch (redir->nfile.type) {
    50605116    case NFROM:
    5061         fname = redir->nfile.expfname;
    50625117        f = open(fname, O_RDONLY);
    50635118        if (f < 0)
     
    50655120        break;
    50665121    case NFROMTO:
    5067         fname = redir->nfile.expfname;
    50685122        f = open(fname, O_RDWR|O_CREAT, 0666);
    50695123        if (f < 0)
     
    50765130        /* Take care of noclobber mode. */
    50775131        if (Cflag) {
    5078             fname = redir->nfile.expfname;
    50795132            f = noclobberopen(fname);
    50805133            if (f < 0)
     
    50845137        /* FALLTHROUGH */
    50855138    case NCLOBBER:
    5086         fname = redir->nfile.expfname;
    50875139        f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
    50885140        if (f < 0)
     
    50905142        break;
    50915143    case NAPPEND:
    5092         fname = redir->nfile.expfname;
    50935144        f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
    50945145        if (f < 0)
     
    58705921        if (in.fd < 0)
    58715922            break;
    5872         i = nonblock_safe_read(in.fd, buf, sizeof(buf));
     5923        i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1);
    58735924        TRACE(("expbackq: read returns %d\n", i));
    58745925        if (i <= 0)
     
    59225973    *p = '\0';
    59235974    p--;
    5924     do {
     5975    while (1) {
    59255976        int esc;
    59265977
     
    59405991
    59415992        p -= esc + 1;
    5942     } while (1);
     5993    }
    59435994
    59445995    begoff = p - start;
     
    60906141            goto addquote;
    60916142        case CTLVAR:
     6143            TRACE(("argstr: evalvar('%s')\n", p));
    60926144            p = evalvar(p, flags, var_str_list);
     6145            TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
    60936146            goto start;
    60946147        case CTLBACKQ:
     
    62876340    IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
    62886341    int saveherefd = herefd;
    6289     int amount, workloc, resetloc;
     6342    int amount, resetloc;
     6343    IF_ASH_BASH_COMPAT(int workloc;)
    62906344    int zero;
    62916345    char *(*scan)(char*, char*, char*, char*, int, int);
     
    64006454    str = (char *)stackblock() + strloc;
    64016455    preglob(str, varflags & VSQUOTE, 0);
     6456
     6457#if ENABLE_ASH_BASH_COMPAT
    64026458    workloc = expdest - (char *)stackblock();
    6403 
    6404 #if ENABLE_ASH_BASH_COMPAT
    64056459    if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
    64066460        char *idx, *end;
     
    67986852        if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
    67996853                startloc, varflags,
    6800 //TODO: | EXP_REDIR too? All other such places do it too
    6801                 /* quotes: */ flags & (EXP_FULL | EXP_CASE),
     6854                /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR),
    68026855                var_str_list)
    68036856        ) {
     
    72017254    ifsfirst.next = NULL;
    72027255    ifslastp = NULL;
     7256    TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
    72037257    argstr(arg->narg.text, flag,
    72047258            /* var_str_list: */ arglist ? arglist->list : NULL);
     
    72097263    }
    72107264    p = grabstackstr(p);
     7265    TRACE(("expandarg: p:'%s'\n", p));
    72117266    exparg.lastp = &exparg.list;
    72127267    /*
     
    72197274        expandmeta(exparg.list /*, flag*/);
    72207275    } else {
    7221         if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
     7276        if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
    72227277            rmescapes(p, 0);
     7278            TRACE(("expandarg: rmescapes:'%s'\n", p));
     7279        }
    72237280        sp = stzalloc(sizeof(*sp));
    72247281        sp->text = p;
     
    73487405tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
    73497406{
    7350     int repeated = 0;
    7351 
    73527407#if ENABLE_FEATURE_SH_STANDALONE
    73537408    if (applet_no >= 0) {
     
    73737428    execve(cmd, argv, envp);
    73747429#endif
    7375     if (repeated) {
     7430    if (cmd == (char*) bb_busybox_exec_path) {
     7431        /* We already visited ENOEXEC branch below, don't do it again */
     7432//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
    73767433        free(argv);
    73777434        return;
    73787435    }
    73797436    if (errno == ENOEXEC) {
     7437        /* Run "cmd" as a shell script:
     7438         * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
     7439         * "If the execve() function fails with ENOEXEC, the shell
     7440         * shall execute a command equivalent to having a shell invoked
     7441         * with the command name as its first operand,
     7442         * with any remaining arguments passed to the new shell"
     7443         *
     7444         * That is, do not use $SHELL, user's shell, or /bin/sh;
     7445         * just call ourselves.
     7446         *
     7447         * Note that bash reads ~80 chars of the file, and if it sees
     7448         * a zero byte before it sees newline, it doesn't try to
     7449         * interpret it, but fails with "cannot execute binary file"
     7450         * message and exit code 126. For one, this prevents attempts
     7451         * to interpret foreign ELF binaries as shell scripts.
     7452         */
    73807453        char **ap;
    73817454        char **new;
     
    73837456        for (ap = argv; *ap; ap++)
    73847457            continue;
    7385         ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
    7386         ap[1] = cmd;
    7387         ap[0] = cmd = (char *)DEFAULT_SHELL;
    7388         ap += 2;
    7389         argv++;
    7390         while ((*ap++ = *argv++) != NULL)
     7458        new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
     7459        new[0] = (char*) "ash";
     7460        new[1] = cmd;
     7461        ap = new + 2;
     7462        while ((*ap++ = *++argv) != NULL)
    73917463            continue;
     7464        cmd = (char*) bb_busybox_exec_path;
    73927465        argv = new;
    7393         repeated++;
    73947466        goto repeat;
    73957467    }
     
    74087480    char **envp;
    74097481    int exerrno;
    7410 #if ENABLE_FEATURE_SH_STANDALONE
    7411     int applet_no = -1;
    7412 #endif
     7482    int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
    74137483
    74147484    clearredir(/*drop:*/ 1);
     
    74207490    ) {
    74217491        tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
     7492        if (applet_no >= 0) {
     7493            /* We tried execing ourself, but it didn't work.
     7494             * Maybe /proc/self/exe doesn't exist?
     7495             * Try $PATH search.
     7496             */
     7497            goto try_PATH;
     7498        }
    74227499        e = errno;
    74237500    } else {
     7501 try_PATH:
    74247502        e = ENOENT;
    74257503        while ((cmdname = path_advance(&path, argv[0])) != NULL) {
     
    85968674        case NAPPEND:
    85978675            expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
     8676            TRACE(("expredir expanded to '%s'\n", fn.list->text));
    85988677#if ENABLE_ASH_BASH_COMPAT
    85998678 store_expfname:
     8679#endif
     8680#if 0
     8681// By the design of stack allocator, the loop of this kind:
     8682//  while true; do while true; do break; done </dev/null; done
     8683// will look like a memory leak: ash plans to free expfname's
     8684// of "/dev/null" as soon as it finishes running the loop
     8685// (in this case, never).
     8686// This "fix" is wrong:
     8687            if (redir->nfile.expfname)
     8688                stunalloc(redir->nfile.expfname);
     8689// It results in corrupted state of stacked allocations.
    86008690#endif
    86018691            redir->nfile.expfname = fn.list->text;
     
    92349324    /* Now locate the command. */
    92359325    if (argc) {
    9236         const char *oldpath;
    92379326        int cmd_flag = DO_ERR;
    9238 
     9327#if ENABLE_ASH_CMDCMD
     9328        const char *oldpath = path + 5;
     9329#endif
    92399330        path += 5;
    9240         oldpath = path;
    92419331        for (;;) {
    92429332            find_command(argv[0], &cmdentry, cmd_flag, path);
     
    95609650 retry:
    95619651    if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
    9562         nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
     9652        nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
    95639653    else {
    9564 #if ENABLE_FEATURE_TAB_COMPLETION
     9654        int timeout = -1;
     9655# if ENABLE_ASH_IDLE_TIMEOUT
     9656        if (iflag) {
     9657            const char *tmout_var = lookupvar("TMOUT");
     9658            if (tmout_var) {
     9659                timeout = atoi(tmout_var) * 1000;
     9660                if (timeout <= 0)
     9661                    timeout = -1;
     9662            }
     9663        }
     9664# endif
     9665# if ENABLE_FEATURE_TAB_COMPLETION
    95659666        line_input_state->path_lookup = pathval();
    9566 #endif
    9567         nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state);
     9667# endif
     9668        /* Unicode support should be activated even if LANG is set
     9669         * _during_ shell execution, not only if it was set when
     9670         * shell was started. Therefore, re-check LANG every time:
     9671         */
     9672        reinit_unicode(lookupvar("LANG"));
     9673        nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
    95689674        if (nr == 0) {
    95699675            /* Ctrl+C pressed */
     
    95769682            goto retry;
    95779683        }
    9578         if (nr < 0 && errno == 0) {
    9579             /* Ctrl+D pressed */
    9580             nr = 0;
     9684        if (nr < 0) {
     9685            if (errno == 0) {
     9686                /* Ctrl+D pressed */
     9687                nr = 0;
     9688            }
     9689# if ENABLE_ASH_IDLE_TIMEOUT
     9690            else if (errno == EAGAIN && timeout > 0) {
     9691                printf("\007timed out waiting for input: auto-logout\n");
     9692                exitshell();
     9693            }
     9694# endif
    95819695        }
    95829696    }
    95839697#else
    9584     nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
    9585 #endif
    9586 
    9587 #if 0
    9588 /* nonblock_safe_read() handles this problem */
     9698    nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
     9699#endif
     9700
     9701#if 0 /* disabled: nonblock_immune_read() handles this problem */
    95899702    if (nr < 0) {
    95909703        if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
     
    1010510218                        setparam(argptr);
    1010610219                }
    10107                 break;    /* "-" or  "--" terminates options */
     10220                break;    /* "-" or "--" terminates options */
    1010810221            }
    1010910222        }
     
    1020710320    if (!argv[1])
    1020810321        return showvars(nullstr, 0, VUNSET);
     10322
    1020910323    INT_OFF;
    10210     retval = 1;
    10211     if (!options(0)) { /* if no parse error... */
    10212         retval = 0;
     10324    retval = options(/*cmdline:*/ 0);
     10325    if (retval == 0) { /* if no parse error... */
    1021310326        optschanged();
    1021410327        if (*argptr != NULL) {
     
    1153811651    if (oldstyle) {
    1153911652        /* We must read until the closing backquote, giving special
    11540            treatment to some slashes, and then push the string and
    11541            reread it as input, interpreting it normally.  */
     11653         * treatment to some slashes, and then push the string and
     11654         * reread it as input, interpreting it normally.
     11655         */
    1154211656        char *pout;
    1154311657        size_t psavelen;
     
    1207112185        if (iflag && top) {
    1207212186            inter++;
    12073 #if ENABLE_ASH_MAIL
    1207412187            chkmail();
    12075 #endif
    1207612188        }
    1207712189        n = parsecmd(inter);
     
    1253212644    const char *p;
    1253312645    char **aptr;
    12534     int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
    12535 
    12536     if (nextopt("p") != 'p') {
     12646    char opt;
     12647    int flag;
     12648    int flag_off;
     12649
     12650    /* "readonly" in bash accepts, but ignores -n.
     12651     * We do the same: it saves a conditional in nextopt's param.
     12652     */
     12653    flag_off = 0;
     12654    while ((opt = nextopt("np")) != '\0') {
     12655        if (opt == 'n')
     12656            flag_off = VEXPORT;
     12657    }
     12658    flag = VEXPORT;
     12659    if (argv[0][0] == 'r') {
     12660        flag = VREADONLY;
     12661        flag_off = 0; /* readonly ignores -n */
     12662    }
     12663    flag_off = ~flag_off;
     12664
     12665    /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
     12666    {
    1253712667        aptr = argptr;
    1253812668        name = *aptr;
     
    1254512675                    vp = *findvar(hashvar(name), name);
    1254612676                    if (vp) {
    12547                         vp->flags |= flag;
     12677                        vp->flags = ((vp->flags | flag) & flag_off);
    1254812678                        continue;
    1254912679                    }
    1255012680                }
    12551                 setvar(name, p, flag);
     12681                setvar(name, p, (flag & flag_off));
    1255212682            } while ((name = *++aptr) != NULL);
    1255312683            return 0;
    1255412684        }
    1255512685    }
     12686
     12687    /* No arguments. Show the list of exported or readonly vars.
     12688     * -n is ignored.
     12689     */
    1255612690    showvars(argv[0], flag, 0);
    1255712691    return 0;
     
    1270612840    }
    1270712841
     12842    /* "read -s" needs to save/restore termios, can't allow ^C
     12843     * to jump out of it.
     12844     */
     12845    INT_OFF;
    1270812846    r = shell_builtin_read(setvar2,
    1270912847        argptr,
     
    1271512853        opt_u
    1271612854    );
     12855    INT_ON;
    1271712856
    1271812857    if ((uintptr_t)r > 1)
     
    1280312942 * Called to exit the shell.
    1280412943 */
    12805 static void exitshell(void) NORETURN;
    1280612944static void
    1280712945exitshell(void)
     
    1281012948    char *p;
    1281112949    int status;
     12950
     12951#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
     12952    save_history(line_input_state);
     12953#endif
    1281212954
    1281312955    status = exitstatus;
     
    1286613008
    1286713009        p = lookupvar("PWD");
    12868         if (p)
     13010        if (p) {
    1286913011            if (*p != '/' || stat(p, &st1) || stat(".", &st2)
    12870              || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
     13012             || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
     13013            ) {
    1287113014                p = '\0';
     13015            }
     13016        }
    1287213017        setpwd(p, 0);
    1287313018    }
    1287413019}
     13020
     13021
     13022//usage:#define ash_trivial_usage
     13023//usage:    "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
     13024//usage:#define ash_full_usage "\n\n"
     13025//usage:    "Unix shell interpreter"
     13026
     13027//usage:#if ENABLE_FEATURE_SH_IS_ASH
     13028//usage:# define sh_trivial_usage ash_trivial_usage
     13029//usage:# define sh_full_usage    ash_full_usage
     13030//usage:#endif
     13031//usage:#if ENABLE_FEATURE_BASH_IS_ASH
     13032//usage:# define bash_trivial_usage ash_trivial_usage
     13033//usage:# define bash_full_usage    ash_full_usage
     13034//usage:#endif
    1287513035
    1287613036/*
     
    1289113051        optlist[i] = 2;
    1289213052    argptr = xargv;
    12893     if (options(1)) {
     13053    if (options(/*cmdline:*/ 1)) {
    1289413054        /* it already printed err message */
    1289513055        raise_exception(EXERROR);
     
    1305313213    if (iflag) {
    1305413214        const char *hp = lookupvar("HISTFILE");
    13055 
    13056         if (hp == NULL) {
     13215        if (!hp) {
    1305713216            hp = lookupvar("HOME");
    13058             if (hp != NULL) {
     13217            if (hp) {
    1305913218                char *defhp = concat_path_file(hp, ".ash_history");
    1306013219                setvar("HISTFILE", defhp, 0);
     
    1306413223    }
    1306513224#endif
    13066     if (/* argv[0] && */ argv[0][0] == '-')
     13225    if (argv[0] && argv[0][0] == '-')
    1306713226        isloginsh = 1;
    1306813227    if (isloginsh) {
     
    1310013259
    1310113260    if (sflag || minusc == NULL) {
    13102 #if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
     13261#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
    1310313262        if (iflag) {
    1310413263            const char *hp = lookupvar("HISTFILE");
    1310513264            if (hp)
    1310613265                line_input_state->hist_file = hp;
     13266# if ENABLE_FEATURE_SH_HISTFILESIZE
     13267            hp = lookupvar("HISTFILESIZE");
     13268            line_input_state->max_history = size_from_HISTFILESIZE(hp);
     13269# endif
    1310713270        }
    1310813271#endif
  • branches/3.2/mindi-busybox/shell/ash_test/ash-redir/redir.right

    r2725 r3232  
     1ash: write error: Bad file descriptor
    12TEST
  • branches/3.2/mindi-busybox/shell/cttyhack.c

    r2725 r3232  
    77#include "libbb.h"
    88
    9 //applet:IF_CTTYHACK(APPLET(cttyhack, _BB_DIR_BIN, _BB_SUID_DROP))
     9//applet:IF_CTTYHACK(APPLET(cttyhack, BB_DIR_BIN, BB_SUID_DROP))
    1010
    1111//kbuild:lib-$(CONFIG_CTTYHACK) += cttyhack.o
     
    1515//config:   default y
    1616//config:   help
    17 //config:     One common problem reported on the mailing list is "can't access tty;
    18 //config:     job control turned off" error message which typically appears when
    19 //config:     one tries to use shell with stdin/stdout opened to /dev/console.
     17//config:     One common problem reported on the mailing list is the "can't
     18//config:     access tty; job control turned off" error message, which typically
     19//config:     appears when one tries to use a shell with stdin/stdout on
     20//config:     /dev/console.
    2021//config:     This device is special - it cannot be a controlling tty.
    2122//config:
    22 //config:     Proper solution is to use correct device instead of /dev/console.
     23//config:     The proper solution is to use the correct device instead of
     24//config:     /dev/console.
    2325//config:
    24 //config:     cttyhack provides "quick and dirty" solution to this problem.
     26//config:     cttyhack provides a "quick and dirty" solution to this problem.
    2527//config:     It analyzes stdin with various ioctls, trying to determine whether
    2628//config:     it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line).
    27 //config:     If it detects one, it closes stdin/out/err and reopens that device.
    28 //config:     Then it executes given program. Opening the device will make
     29//config:     On Linux it also checks sysfs for a pointer to the active console.
     30//config:     If cttyhack is able to find the real console device, it closes
     31//config:     stdin/out/err and reopens that device.
     32//config:     Then it executes the given program. Opening the device will make
    2933//config:     that device a controlling tty. This may require cttyhack
    3034//config:     to be a session leader.
     
    4751//config:     # exec setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1'
    4852//config:
     53//config:     Starting getty on a controlling tty from a shell script:
     54//config:
     55//config:     # getty 115200 $(cttyhack)
    4956
    5057//usage:#define cttyhack_trivial_usage
    51 //usage:       "PROG ARGS"
     58//usage:       "[PROG ARGS]"
    5259//usage:#define cttyhack_full_usage "\n\n"
    5360//usage:       "Give PROG a controlling tty if possible."
     
    105112    } u;
    106113
    107     if (!*++argv) {
    108         bb_show_usage();
     114    strcpy(console, "/dev/tty");
     115    fd = open(console, O_RDWR);
     116    if (fd < 0) {
     117        /* We don't have ctty (or don't have "/dev/tty" node...) */
     118        do {
     119#ifdef __linux__
     120            /* Note that this method does not use _stdin_.
     121             * Thus, "cttyhack </dev/something" can't be used.
     122             * However, this method is more reliable than
     123             * TIOCGSERIAL check, which assumes that all
     124             * serial lines follow /dev/ttySn convention -
     125             * which is not always the case.
     126             * Therefore, we use this method first:
     127             */
     128            int s = open_read_close("/sys/class/tty/console/active",
     129                console + 5, sizeof(console) - 5);
     130            if (s > 0) {
     131                char *last;
     132                /* Found active console via sysfs (Linux 2.6.38+).
     133                 * It looks like "[tty0 ]ttyS0\n" so zap the newline:
     134                 */
     135                console[4 + s] = '\0';
     136                /* If there are multiple consoles,
     137                 * take the last one:
     138                 */
     139                last = strrchr(console + 5, ' ');
     140                if (last)
     141                    overlapping_strcpy(console + 5, last + 1);
     142                break;
     143            }
     144
     145            if (ioctl(0, VT_GETSTATE, &u.vt) == 0) {
     146                /* this is linux virtual tty */
     147                sprintf(console + 8, "S%u" + 1, (int)u.vt.v_active);
     148                break;
     149            }
     150#endif
     151#ifdef TIOCGSERIAL
     152            if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) {
     153                /* this is a serial console; assuming it is named /dev/ttySn */
     154                sprintf(console + 8, "S%u", (int)u.sr.line);
     155                break;
     156            }
     157#endif
     158            /* nope, could not find it */
     159            console[0] = '\0';
     160        } while (0);
    109161    }
    110162
    111     strcpy(console, "/dev/tty");
    112     fd = open(console, O_RDWR);
    113     if (fd >= 0) {
    114         /* We already have ctty, nothing to do */
    115         close(fd);
    116     } else {
    117         /* We don't have ctty (or don't have "/dev/tty" node...) */
    118         if (0) {}
    119 #ifdef TIOCGSERIAL
    120         else if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) {
    121             /* this is a serial console */
    122             sprintf(console + 8, "S%d", u.sr.line);
    123         }
    124 #endif
    125 #ifdef __linux__
    126         else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) {
    127             /* this is linux virtual tty */
    128             sprintf(console + 8, "S%d" + 1, u.vt.v_active);
    129         }
    130 #endif
    131         if (console[8]) {
    132             fd = xopen(console, O_RDWR);
    133             //bb_error_msg("switching to '%s'", console);
    134             dup2(fd, 0);
    135             dup2(fd, 1);
    136             dup2(fd, 2);
    137             while (fd > 2)
    138                 close(fd--);
    139             /* Some other session may have it as ctty,
    140              * steal it from them:
    141              */
    142             ioctl(0, TIOCSCTTY, 1);
    143         }
     163    argv++;
     164    if (!argv[0]) {
     165        if (!console[0])
     166            return EXIT_FAILURE;
     167        puts(console);
     168        return EXIT_SUCCESS;
    144169    }
    145170
     171    if (fd < 0) {
     172        fd = open_or_warn(console, O_RDWR);
     173        if (fd < 0)
     174            goto ret;
     175    }
     176    //bb_error_msg("switching to '%s'", console);
     177    dup2(fd, 0);
     178    dup2(fd, 1);
     179    dup2(fd, 2);
     180    while (fd > 2)
     181        close(fd--);
     182    /* Some other session may have it as ctty,
     183     * try to steal it from them:
     184     */
     185    ioctl(0, TIOCSCTTY, 1);
     186 ret:
    146187    BB_EXECVP_or_die(argv);
    147188}
  • 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    }
  • branches/3.2/mindi-busybox/shell/hush_test/hush-parsing/starquoted2.right

    r2725 r3232  
    11Should be printed
     2Would not be printed by bash
     3Would not be printed by bash
     4Would not be printed by bash
    25Should be printed
    36Empty:
  • branches/3.2/mindi-busybox/shell/hush_test/hush-parsing/starquoted2.tests

    r2725 r3232  
    99# treating "" as "this word cannot be expanded to nothing,
    1010# but must be at least null string". Now it can be expanded to nothing.
    11 for a in "$@"""; do echo Should not be printed; done
    12 for a in """$@"; do echo Should not be printed; done
    13 for a in """$@"''"$@"''; do echo Should not be printed; done
     11for a in "$@"""; do echo Would not be printed by bash; done
     12for a in """$@"; do echo Would not be printed by bash; done
     13for a in """$@"''"$@"''; do echo Would not be printed by bash; done
    1414for a in ""; do echo Should be printed; done
    1515
  • branches/3.2/mindi-busybox/shell/hush_test/run-all

    r2725 r3232  
    4949            #*) echo $x ; sh $x ;;
    5050            *)
     51            echo -n "$1/$x:"
    5152            sh "$x" >"../$1-$x.fail" 2>&1 && \
    52             { echo "$1/$x: ok"; rm "../$1-$x.fail"; } || echo "$1/$x: fail";
     53            { { echo " ok"; rm "../$1-$x.fail"; } || echo " fail"; }
    5354            ;;
    5455        esac
     
    6162    test -f "$name.right" || continue
    6263#   echo Running test: "$x"
     64    echo -n "$1/$x:"
    6365    (
    6466        "$THIS_SH" "./$x" >"$name.xx" 2>&1
     
    7173    )
    7274    case $? in
    73         0)  echo "$1/$x: ok";;
    74         77) echo "$1/$x: skip (feature disabled)";;
    75         *)  echo "$1/$x: fail"; tret=1;;
     75        0)  echo " ok";;
     76        77) echo " skip (feature disabled)";;
     77        *)  echo " fail"; tret=1;;
    7678    esac
    7779    done
  • branches/3.2/mindi-busybox/shell/math.c

    r2725 r3232  
    411411            c = 1;
    412412            while (--right_side_val >= 0)
    413                 c *= rez;
     413                c *= rez;
    414414            rez = c;
    415415        }
  • branches/3.2/mindi-busybox/shell/shell_common.c

    r2725 r3232  
    1919#include "libbb.h"
    2020#include "shell_common.h"
     21#include <sys/resource.h> /* getrlimit */
    2122
    2223const char defifsvar[] ALIGN1 = "IFS= \t\n";
     
    3738/* read builtin */
    3839
     40/* Needs to be interruptible: shell mush handle traps and shell-special signals
     41 * while inside read. To implement this, be sure to not loop on EINTR
     42 * and return errno == EINTR reliably.
     43 */
    3944//TODO: use more efficient setvar() which takes a pointer to malloced "VAR=VAL"
    4045//string. hush naturally has it, and ash has setvareq().
     
    5257)
    5358{
     59    unsigned err;
    5460    unsigned end_ms; /* -t TIMEOUT */
    5561    int fd; /* -u FD */
     
    6268    int startword;
    6369    smallint backslash;
     70
     71    errno = err = 0;
    6472
    6573    pp = argv;
     
    132140        if (nchars) {
    133141            tty.c_lflag &= ~ICANON;
    134             tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
     142            // Setting it to more than 1 breaks poll():
     143            // it blocks even if there's data. !??
     144            //tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
     145            /* reads would block only if < 1 char is available */
     146            tty.c_cc[VMIN] = 1;
     147            /* no timeout (reads block forever) */
     148            tty.c_cc[VTIME] = 0;
    135149        }
    136150        if (read_flags & BUILTIN_READ_SILENT) {
     
    153167    do {
    154168        char c;
    155 
     169        struct pollfd pfd[1];
     170        int timeout;
     171
     172        if ((bufpos & 0xff) == 0)
     173            buffer = xrealloc(buffer, bufpos + 0x101);
     174
     175        timeout = -1;
    156176        if (end_ms) {
    157             int timeout;
    158             struct pollfd pfd[1];
    159 
    160             pfd[0].fd = fd;
    161             pfd[0].events = POLLIN;
    162177            timeout = end_ms - (unsigned)monotonic_ms();
    163             if (timeout <= 0 /* already late? */
    164              || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
    165             ) { /* timed out! */
     178            if (timeout <= 0) { /* already late? */
    166179                retval = (const char *)(uintptr_t)1;
    167180                goto ret;
     
    169182        }
    170183
    171         if ((bufpos & 0xff) == 0)
    172             buffer = xrealloc(buffer, bufpos + 0x100);
    173         if (nonblock_safe_read(fd, &buffer[bufpos], 1) != 1) {
     184        /* We must poll even if timeout is -1:
     185         * we want to be interrupted if signal arrives,
     186         * regardless of SA_RESTART-ness of that signal!
     187         */
     188        errno = 0;
     189        pfd[0].fd = fd;
     190        pfd[0].events = POLLIN;
     191        if (poll(pfd, 1, timeout) != 1) {
     192            /* timed out, or EINTR */
     193            err = errno;
     194            retval = (const char *)(uintptr_t)1;
     195            goto ret;
     196        }
     197        if (read(fd, &buffer[bufpos], 1) != 1) {
     198            err = errno;
    174199            retval = (const char *)(uintptr_t)1;
    175200            break;
    176201        }
     202
    177203        c = buffer[bufpos];
    178204        if (c == '\0')
     
    241267    if (read_flags & BUILTIN_READ_SILENT)
    242268        tcsetattr(fd, TCSANOW, &old_tty);
     269
     270    errno = err;
    243271    return retval;
    244272}
     
    287315    { RLIMIT_LOCKS,     0,  'w',    "locks" },
    288316#endif
     317#ifdef RLIMIT_NICE
     318    { RLIMIT_NICE,      0,  'e',    "scheduling priority" },
     319#endif
     320#ifdef RLIMIT_RTPRIO
     321    { RLIMIT_RTPRIO,    0,  'r',    "real-time priority" },
     322#endif
    289323};
    290324
     
    328362#ifdef RLIMIT_LOCKS
    329363            "w::"
     364#endif
     365#ifdef RLIMIT_NICE
     366            "e::"
     367#endif
     368#ifdef RLIMIT_RTPRIO
     369            "r::"
    330370#endif
    331371            ;
     
    369409    /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */
    370410
    371         argc = 1;
    372         while (argv[argc])
    373                 argc++;
     411    argc = 1;
     412    while (argv[argc])
     413        argc++;
    374414
    375415    opts = 0;
  • branches/3.2/mindi-busybox/shell/shell_common.h

    r3045 r3232  
    1919#ifndef SHELL_COMMON_H
    2020#define SHELL_COMMON_H 1
    21 /*  BCO: From http://paste.pound-python.org/show/23796/ - Fix #632 */
    22 #include <sys/resource.h>
    23 /*  End BCO */
    2421
    2522PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
    2623
    27 extern const char defifsvar[]; /* "IFS= \t\n" */
     24extern const char defifsvar[] ALIGN1; /* "IFS= \t\n" */
    2825#define defifs (defifsvar + 4)
    2926
Note: See TracChangeset for help on using the changeset viewer.