Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/shell/hush.c


Ignore:
Timestamp:
Dec 20, 2016, 4:07:32 PM (7 years ago)
Author:
Bruno Cornec
Message:

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

Location:
branches/3.3
Files:
1 edited
1 copied

Legend:

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

    r3232 r3621  
    9292# include <fnmatch.h>
    9393#endif
     94#include <sys/utsname.h> /* for setting $HOSTNAME */
    9495
    9596#include "busybox.h"  /* for APPLET_IS_NOFORK/NOEXEC */
     
    442443    DEFINITELY_ASSIGNMENT = 1,
    443444    NOT_ASSIGNMENT        = 2,
    444     /* Not an assigment, but next word may be: "if v=xyz cmd;" */
     445    /* Not an assignment, but next word may be: "if v=xyz cmd;" */
    445446    WORD_IS_KEYWORD       = 3,
    446447};
     
    851852static int builtin_help(char **argv) FAST_FUNC;
    852853#endif
     854#if MAX_HISTORY && ENABLE_FEATURE_EDITING
     855static int builtin_history(char **argv) FAST_FUNC;
     856#endif
    853857#if ENABLE_HUSH_LOCAL
    854858static int builtin_local(char **argv) FAST_FUNC;
     
    920924    BLTIN("help"     , builtin_help    , NULL),
    921925#endif
     926#if MAX_HISTORY && ENABLE_FEATURE_EDITING
     927    BLTIN("history"  , builtin_history , "Show command history"),
     928#endif
    922929#if ENABLE_HUSH_JOB
    923930    BLTIN("jobs"     , builtin_jobs    , "List jobs"),
     
    939946#endif
    940947    BLTIN("trap"     , builtin_trap    , "Trap signals"),
     948    BLTIN("true"     , builtin_true    , NULL),
    941949    BLTIN("type"     , builtin_type    , "Show command type"),
    942950    BLTIN("ulimit"   , shell_builtin_ulimit  , "Control resource limits"),
     
    13051313 * pipe.
    13061314 *
    1307  * Wait builtin in interruptible by signals for which user trap is set
     1315 * Wait builtin is interruptible by signals for which user trap is set
    13081316 * or by SIGINT in interactive shell.
    13091317 *
     
    13841392 *
    13851393 * Problem: the above approach makes it unwieldy to catch signals while
    1386  * we are in read builtin, of while we read commands from stdin:
     1394 * we are in read builtin, or while we read commands from stdin:
    13871395 * masked signals are not visible!
    13881396 *
     
    13931401 * We are interested in: signals which need to have special handling
    13941402 * as described above, and all signals which have traps set.
    1395  * Signals are rocorded in pending_set.
     1403 * Signals are recorded in pending_set.
    13961404 * After each pipe execution, we extract any pending signals
    13971405 * and act on them.
     
    14701478}
    14711479
     1480static void hush_exit(int exitcode) NORETURN;
     1481static void fflush_and__exit(void) NORETURN;
     1482static void restore_ttypgrp_and__exit(void) NORETURN;
     1483
     1484static void restore_ttypgrp_and__exit(void)
     1485{
     1486    /* xfunc has failed! die die die */
     1487    /* no EXIT traps, this is an escape hatch! */
     1488    G.exiting = 1;
     1489    hush_exit(xfunc_error_retval);
     1490}
     1491
     1492/* Needed only on some libc:
     1493 * It was observed that on exit(), fgetc'ed buffered data
     1494 * gets "unwound" via lseek(fd, -NUM, SEEK_CUR).
     1495 * With the net effect that even after fork(), not vfork(),
     1496 * exit() in NOEXECed applet in "sh SCRIPT":
     1497 *  noexec_applet_here
     1498 *  echo END_OF_SCRIPT
     1499 * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT".
     1500 * This makes "echo END_OF_SCRIPT" executed twice.
     1501 * Similar problems can be seen with die_if_script() -> xfunc_die()
     1502 * and in `cmd` handling.
     1503 * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit():
     1504 */
     1505static void fflush_and__exit(void)
     1506{
     1507    fflush_all();
     1508    _exit(xfunc_error_retval);
     1509}
     1510
    14721511#if ENABLE_HUSH_JOB
    14731512
    14741513/* After [v]fork, in child: do not restore tty pgrp on xfunc death */
    1475 # define disable_restore_tty_pgrp_on_exit() (die_sleep = 0)
     1514# define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit)
    14761515/* After [v]fork, in parent: restore tty pgrp on xfunc death */
    1477 # define enable_restore_tty_pgrp_on_exit()  (die_sleep = -1)
     1516# define enable_restore_tty_pgrp_on_exit()  (die_func = restore_ttypgrp_and__exit)
    14781517
    14791518/* Restores tty foreground process group, and exits.
     
    14811520 * (will resend signal to itself, producing correct exit state)
    14821521 * or called directly with -EXITCODE.
    1483  * We also call it if xfunc is exiting. */
     1522 * We also call it if xfunc is exiting.
     1523 */
    14841524static void sigexit(int sig) NORETURN;
    14851525static void sigexit(int sig)
     
    15361576
    15371577/* Restores tty foreground process group, and exits. */
    1538 static void hush_exit(int exitcode) NORETURN;
    15391578static void hush_exit(int exitcode)
    15401579{
     
    15721611#endif
    15731612
     1613    fflush_all();
    15741614#if ENABLE_HUSH_JOB
    1575     fflush_all();
    15761615    sigexit(- (exitcode & 0xff));
    15771616#else
    1578     exit(exitcode);
     1617    _exit(exitcode);
    15791618#endif
    15801619}
     
    17491788    struct variable **var_pp;
    17501789    struct variable *cur;
     1790    char *free_me = NULL;
    17511791    char *eq_sign;
    17521792    int name_len;
     
    17651805            continue;
    17661806        }
     1807
    17671808        /* We found an existing var with this name */
    17681809        if (cur->flg_read_only) {
     
    18131854                goto free_and_exp;
    18141855            }
    1815         } else {
    1816             /* max_len == 0 signifies "malloced" var, which we can
    1817              * (and has to) free */
    1818             free(cur->varstr);
    1819         }
    1820         cur->max_len = 0;
     1856            /* Can't reuse */
     1857            cur->max_len = 0;
     1858            goto set_str_and_exp;
     1859        }
     1860        /* max_len == 0 signifies "malloced" var, which we can
     1861         * (and have to) free. But we can't free(cur->varstr) here:
     1862         * if cur->flg_export is 1, it is in the environment.
     1863         * We should either unsetenv+free, or wait until putenv,
     1864         * then putenv(new)+free(old).
     1865         */
     1866        free_me = cur->varstr;
    18211867        goto set_str_and_exp;
    18221868    }
     
    18451891            /* unsetenv was already done */
    18461892        } else {
     1893            int i;
    18471894            debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr);
    1848             return putenv(cur->varstr);
    1849         }
    1850     }
     1895            i = putenv(cur->varstr);
     1896            /* only now we can free old exported malloced string */
     1897            free(free_me);
     1898            return i;
     1899        }
     1900    }
     1901    free(free_me);
    18511902    return 0;
    18521903}
     
    19662017    }
    19672018    return old;
     2019}
     2020
     2021
     2022/*
     2023 * Unicode helper
     2024 */
     2025static void reinit_unicode_for_hush(void)
     2026{
     2027    /* Unicode support should be activated even if LANG is set
     2028     * _during_ shell execution, not only if it was set when
     2029     * shell was started. Therefore, re-check LANG every time:
     2030     */
     2031    if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
     2032     || ENABLE_UNICODE_USING_LOCALE
     2033        ) {
     2034        const char *s = get_local_var_value("LC_ALL");
     2035        if (!s) s = get_local_var_value("LC_CTYPE");
     2036        if (!s) s = get_local_var_value("LANG");
     2037        reinit_unicode(s);
     2038    }
    19682039}
    19692040
     
    20352106     * is actually being read */
    20362107    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 
     2108        reinit_unicode_for_hush();
    20432109        G.flag_SIGINT = 0;
    20442110        /* buglet: SIGINT will not make new prompt to appear _at once_,
     
    31393205        old->command->cmd_type = CMD_NORMAL;
    31403206# if !BB_MMU
    3141         o_addstr(&old->as_string, ctx->as_string.data);
    3142         o_free_unsafe(&ctx->as_string);
    3143         old->command->group_as_string = xstrdup(old->as_string.data);
    3144         debug_printf_parse("pop, remembering as:'%s'\n",
    3145                 old->command->group_as_string);
     3207        /* At this point, the compound command's string is in
     3208         * ctx->as_string... except for the leading keyword!
     3209         * Consider this example: "echo a | if true; then echo a; fi"
     3210         * ctx->as_string will contain "true; then echo a; fi",
     3211         * with "if " remaining in old->as_string!
     3212         */
     3213        {
     3214            char *str;
     3215            int len = old->as_string.length;
     3216            /* Concatenate halves */
     3217            o_addstr(&old->as_string, ctx->as_string.data);
     3218            o_free_unsafe(&ctx->as_string);
     3219            /* Find where leading keyword starts in first half */
     3220            str = old->as_string.data + len;
     3221            if (str > old->as_string.data)
     3222                str--; /* skip whitespace after keyword */
     3223            while (str > old->as_string.data && isalpha(str[-1]))
     3224                str--;
     3225            /* Ugh, we're done with this horrid hack */
     3226            old->command->group_as_string = xstrdup(str);
     3227            debug_printf_parse("pop, remembering as:'%s'\n",
     3228                    old->command->group_as_string);
     3229        }
    31463230# endif
    31473231        *ctx = *old;   /* physical copy */
     
    42264310            }
    42274311#if !BB_MMU
    4228             debug_printf_parse("as_string '%s'\n", ctx.as_string.data);
     4312            debug_printf_parse("as_string1 '%s'\n", ctx.as_string.data);
    42294313            if (pstring)
    42304314                *pstring = ctx.as_string.data;
     
    43774461                o_free(&dest);
    43784462#if !BB_MMU
    4379                 debug_printf_parse("as_string '%s'\n", ctx.as_string.data);
     4463                debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data);
    43804464                if (pstring)
    43814465                    *pstring = ctx.as_string.data;
     
    46174701                 * "echo foo 2| cat" yields "foo 2". */
    46184702                done_command(&ctx);
    4619 #if !BB_MMU
    4620                 o_reset_to_empty_unquoted(&ctx.as_string);
    4621 #endif
    46224703            }
    46234704            goto new_cmd;
     
    50185099    /* Handle any expansions */
    50195100    if (exp_op == 'L') {
     5101        reinit_unicode_for_hush();
    50205102        debug_printf_expand("expand: length(%s)=", val);
    5021         val = utoa(val ? strlen(val) : 0);
     5103        val = utoa(val ? unicode_strlen(val) : 0);
    50225104        debug_printf_expand("%s\n", val);
    50235105    } else if (exp_op) {
     
    53675449            }
    53685450            break;
    5369 
    53705451        } /* switch (char after <SPECIAL_VAR_SYMBOL>) */
    53715452
     
    58615942         */
    58625943        s = skip_whitespace(s);
    5863         if (strncmp(s, "trap", 4) == 0
     5944        if (is_prefixed_with(s, "trap")
    58645945         && skip_whitespace(s + 4)[0] == '\0'
    58655946        ) {
    58665947            static const char *const argv[] = { NULL, NULL };
    58675948            builtin_trap((char**)argv);
    5868             exit(0); /* not _exit() - we need to fflush */
     5949            fflush_all(); /* important */
     5950            _exit(0);
    58695951        }
    58705952# if BB_MMU
     
    64196501 * Don't exit() here.  If you don't exec, use _exit instead.
    64206502 * The at_exit handlers apparently confuse the calling process,
    6421  * in particular stdin handling.  Not sure why? -- because of vfork! (vda) */
     6503 * in particular stdin handling. Not sure why? -- because of vfork! (vda)
     6504 */
    64226505static void pseudo_exec_argv(nommu_save_t *nommu_save,
    64236506        char **argv, int assignment_cnt,
     
    67576840                        if (i == fg_pipe->num_cmds-1)
    67586841                            /* TODO: use strsignal() instead for bash compat? but that's bloat... */
    6759                             printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig));
     6842                            puts(sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig));
    67606843                        /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */
    67616844                        /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here?
     
    73557438                debug_printf_exec("skipped cmd because of || or &&\n");
    73567439                last_followup = pi->followup;
    7357                 continue;
     7440                goto dont_check_jobs_but_continue;
    73587441            }
    73597442        }
     
    74947577                        /* else: e.g. "continue 2" should *break* once, *then* continue */
    74957578                    } /* else: "while... do... { we are here (innermost list is not a loop!) };...done" */
    7496                     if (G.depth_break_continue != 0 || fbc == BC_BREAK)
    7497                         goto check_jobs_and_break;
     7579                    if (G.depth_break_continue != 0 || fbc == BC_BREAK) {
     7580                        checkjobs(NULL);
     7581                        break;
     7582                    }
    74987583                    /* "continue": simulate end of loop */
    74997584                    rword = RES_DONE;
     
    75037588#if ENABLE_HUSH_FUNCTIONS
    75047589                if (G.flag_return_in_progress == 1) {
    7505                     /* same as "goto check_jobs_and_break" */
    75067590                    checkjobs(NULL);
    75077591                    break;
     
    75457629            cond_code = rcode;
    75467630#endif
     7631 check_jobs_and_continue:
     7632        checkjobs(NULL);
     7633 dont_check_jobs_but_continue: ;
    75477634#if ENABLE_HUSH_LOOPS
    75487635        /* Beware of "while false; true; do ..."! */
     
    75567643                    G.last_exitcode = rcode = EXIT_SUCCESS;
    75577644                    debug_printf_exec(": while expr is false: breaking (exitcode:EXIT_SUCCESS)\n");
    7558                     goto check_jobs_and_break;
     7645                    break;
    75597646                }
    75607647            }
     
    75627649                if (!rcode) {
    75637650                    debug_printf_exec(": until expr is true: breaking\n");
    7564  check_jobs_and_break:
    7565                     checkjobs(NULL);
    75667651                    break;
    75677652                }
     
    75697654        }
    75707655#endif
    7571 
    7572  check_jobs_and_continue:
    7573         checkjobs(NULL);
    75747656    } /* for (pi) */
    75757657
     
    77417823    if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
    77427824        G.last_exitcode = EXIT_SUCCESS;
     7825
    77437826#if ENABLE_HUSH_FAST
    77447827    G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
     
    77787861    /* Export PWD */
    77797862    set_pwd_var(/*exp:*/ 1);
     7863
     7864#if ENABLE_HUSH_BASH_COMPAT
     7865    /* Set (but not export) HOSTNAME unless already set */
     7866    if (!get_local_var_value("HOSTNAME")) {
     7867        struct utsname uts;
     7868        uname(&uts);
     7869        set_local_var_from_halves("HOSTNAME", uts.nodename);
     7870    }
    77807871    /* bash also exports SHLVL and _,
    77817872     * and sets (but doesn't export) the following variables:
     
    77867877     * MACHTYPE=i386-pc-linux-gnu
    77877878     * OSTYPE=linux-gnu
    7788      * HOSTNAME=<xxxxxxxxxx>
    77897879     * PPID=<NNNNN> - we also do it elsewhere
    77907880     * EUID=<NNNNN>
     
    78147904     * PS4='+ '
    78157905     */
     7906#endif
    78167907
    78177908#if ENABLE_FEATURE_EDITING
     
    78227913    cmdedit_update_prompt();
    78237914
    7824     if (setjmp(die_jmp)) {
    7825         /* xfunc has failed! die die die */
    7826         /* no EXIT traps, this is an escape hatch! */
    7827         G.exiting = 1;
    7828         hush_exit(xfunc_error_retval);
    7829     }
     7915    die_func = restore_ttypgrp_and__exit;
    78307916
    78317917    /* Shell is non-interactive at first. We need to call
     
    80858171            tcsetpgrp(G_interactive_fd, getpid());
    80868172        }
    8087         /* -1 is special - makes xfuncs longjmp, not exit
    8088          * (we reset die_sleep = 0 whereever we [v]fork) */
    8089         enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
     8173        enable_restore_tty_pgrp_on_exit();
    80908174
    80918175# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
     
    86258709    }
    86268710    bb_putchar('\n');
     8711    return EXIT_SUCCESS;
     8712}
     8713#endif
     8714
     8715#if MAX_HISTORY && ENABLE_FEATURE_EDITING
     8716static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM)
     8717{
     8718    show_history(G.line_input_state);
    86278719    return EXIT_SUCCESS;
    86288720}
     
    88818973    if (!input) {
    88828974        /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */
     8975        /* POSIX: non-interactive shell should abort here,
     8976         * not merely fail. So far no one complained :)
     8977         */
    88838978        return EXIT_FAILURE;
    88848979    }
     
    88908985    G.flag_return_in_progress = -1;
    88918986#endif
    8892     save_and_replace_G_args(&sv, argv);
     8987    if (argv[1])
     8988        save_and_replace_G_args(&sv, argv);
    88938989
    88948990    parse_and_run_file(input);
    88958991    fclose(input);
    88968992
    8897     restore_G_args(&sv, argv);
     8993    if (argv[1])
     8994        restore_G_args(&sv, argv);
    88988995#if ENABLE_HUSH_FUNCTIONS
    88998996    G.flag_return_in_progress = sv_flg;
     
    89089005    mode_t mask;
    89099006
     9007    rc = 1;
    89109008    mask = umask(0);
    89119009    argv = skip_dash_dash(argv);
     
    89139011        mode_t old_mask = mask;
    89149012
    8915         mask ^= 0777;
    8916         rc = bb_parse_mode(argv[0], &mask);
    8917         mask ^= 0777;
    8918         if (rc == 0) {
     9013        /* numeric umasks are taken as-is */
     9014        /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
     9015        if (!isdigit(argv[0][0]))
     9016            mask ^= 0777;
     9017        mask = bb_parse_mode(argv[0], mask);
     9018        if (!isdigit(argv[0][0]))
     9019            mask ^= 0777;
     9020        if ((unsigned)mask > 0777) {
    89199021            mask = old_mask;
    89209022            /* bash messages:
     
    89239025             */
    89249026            bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]);
     9027            rc = 0;
    89259028        }
    89269029    } else {
    8927         rc = 1;
    89289030        /* Mimic bash */
    89299031        printf("%04o\n", (unsigned) mask);
     
    90559157        }
    90569158        if (waitpid(pid, &status, 0) == pid) {
     9159            ret = WEXITSTATUS(status);
    90579160            if (WIFSIGNALED(status))
    90589161                ret = 128 + WTERMSIG(status);
    9059             else if (WIFEXITED(status))
    9060                 ret = WEXITSTATUS(status);
    9061             else /* wtf? */
    9062                 ret = EXIT_FAILURE;
    90639162        } else {
    90649163            bb_perror_msg("wait %s", *argv);
Note: See TracChangeset for help on using the changeset viewer.