busybox/shell/ash.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * ash shell port for busybox
   4 *
   5 * This code is derived from software contributed to Berkeley by
   6 * Kenneth Almquist.
   7 *
   8 * Original BSD copyright notice is retained at the end of this file.
   9 *
  10 * Copyright (c) 1989, 1991, 1993, 1994
  11 *      The Regents of the University of California.  All rights reserved.
  12 *
  13 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
  14 * was re-ported from NetBSD and debianized.
  15 *
  16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  17 */
  18//config:config SHELL_ASH
  19//config:       bool #hidden option
  20//config:       depends on !NOMMU
  21//config:
  22//config:config ASH
  23//config:       bool "ash (78 kb)"
  24//config:       default y
  25//config:       depends on !NOMMU
  26//config:       select SHELL_ASH
  27//config:       help
  28//config:       The most complete and most pedantically correct shell included with
  29//config:       busybox. This shell is actually a derivative of the Debian 'dash'
  30//config:       shell (by Herbert Xu), which was created by porting the 'ash' shell
  31//config:       (written by Kenneth Almquist) from NetBSD.
  32//config:
  33//config:# ash options
  34//config:# note: Don't remove !NOMMU part in the next line; it would break
  35//config:# menuconfig's indenting.
  36//config:if !NOMMU && (SHELL_ASH || ASH || SH_IS_ASH || BASH_IS_ASH)
  37//config:
  38//config:config ASH_OPTIMIZE_FOR_SIZE
  39//config:       bool "Optimize for size instead of speed"
  40//config:       default y
  41//config:       depends on SHELL_ASH
  42//config:
  43//config:config ASH_INTERNAL_GLOB
  44//config:       bool "Use internal glob() implementation"
  45//config:       default y       # Y is bigger, but because of uclibc glob() bug, let Y be default for now
  46//config:       depends on SHELL_ASH
  47//config:       help
  48//config:       Do not use glob() function from libc, use internal implementation.
  49//config:       Use this if you are getting "glob.h: No such file or directory"
  50//config:       or similar build errors.
  51//config:       Note that as of now (2017-01), uclibc and musl glob() both have bugs
  52//config:       which would break ash if you select N here.
  53//config:
  54//config:config ASH_BASH_COMPAT
  55//config:       bool "bash-compatible extensions"
  56//config:       default y
  57//config:       depends on SHELL_ASH
  58//config:
  59//config:config ASH_BASH_SOURCE_CURDIR
  60//config:       bool "'source' and '.' builtins search current directory after $PATH"
  61//config:       default n   # do not encourage non-standard behavior
  62//config:       depends on ASH_BASH_COMPAT
  63//config:       help
  64//config:       This is not compliant with standards. Avoid if possible.
  65//config:
  66//config:config ASH_BASH_NOT_FOUND_HOOK
  67//config:       bool "command_not_found_handle hook support"
  68//config:       default y
  69//config:       depends on ASH_BASH_COMPAT
  70//config:       help
  71//config:       Enable support for the 'command_not_found_handle' hook function,
  72//config:       from GNU bash, which allows for alternative command not found
  73//config:       handling.
  74//config:
  75//config:config ASH_JOB_CONTROL
  76//config:       bool "Job control"
  77//config:       default y
  78//config:       depends on SHELL_ASH
  79//config:
  80//config:config ASH_ALIAS
  81//config:       bool "Alias support"
  82//config:       default y
  83//config:       depends on SHELL_ASH
  84//config:
  85//config:config ASH_RANDOM_SUPPORT
  86//config:       bool "Pseudorandom generator and $RANDOM variable"
  87//config:       default y
  88//config:       depends on SHELL_ASH
  89//config:       help
  90//config:       Enable pseudorandom generator and dynamic variable "$RANDOM".
  91//config:       Each read of "$RANDOM" will generate a new pseudorandom value.
  92//config:       You can reset the generator by using a specified start value.
  93//config:       After "unset RANDOM" the generator will switch off and this
  94//config:       variable will no longer have special treatment.
  95//config:
  96//config:config ASH_EXPAND_PRMT
  97//config:       bool "Expand prompt string"
  98//config:       default y
  99//config:       depends on SHELL_ASH
 100//config:       help
 101//config:       $PS# may contain volatile content, such as backquote commands.
 102//config:       This option recreates the prompt string from the environment
 103//config:       variable each time it is displayed.
 104//config:
 105//config:config ASH_IDLE_TIMEOUT
 106//config:       bool "Idle timeout variable $TMOUT"
 107//config:       default y
 108//config:       depends on SHELL_ASH
 109//config:       help
 110//config:       Enable bash-like auto-logout after $TMOUT seconds of idle time.
 111//config:
 112//config:config ASH_MAIL
 113//config:       bool "Check for new mail in interactive shell"
 114//config:       default y
 115//config:       depends on SHELL_ASH
 116//config:       help
 117//config:       Enable "check for new mail" function:
 118//config:       if set, $MAIL file and $MAILPATH list of files
 119//config:       are checked for mtime changes, and "you have mail"
 120//config:       message is printed if change is detected.
 121//config:
 122//config:config ASH_ECHO
 123//config:       bool "echo builtin"
 124//config:       default y
 125//config:       depends on SHELL_ASH
 126//config:
 127//config:config ASH_PRINTF
 128//config:       bool "printf builtin"
 129//config:       default y
 130//config:       depends on SHELL_ASH
 131//config:
 132//config:config ASH_TEST
 133//config:       bool "test builtin"
 134//config:       default y
 135//config:       depends on SHELL_ASH
 136//config:
 137//config:config ASH_SLEEP
 138//config:       bool "sleep builtin"
 139//config:       default y
 140//config:       depends on SHELL_ASH
 141//config:
 142//config:config ASH_HELP
 143//config:       bool "help builtin"
 144//config:       default y
 145//config:       depends on SHELL_ASH
 146//config:
 147//config:config ASH_GETOPTS
 148//config:       bool "getopts builtin"
 149//config:       default y
 150//config:       depends on SHELL_ASH
 151//config:
 152//config:config ASH_CMDCMD
 153//config:       bool "command builtin"
 154//config:       default y
 155//config:       depends on SHELL_ASH
 156//config:       help
 157//config:       Enable support for the 'command' builtin, which allows
 158//config:       you to run the specified command or builtin,
 159//config:       even when there is a function with the same name.
 160//config:
 161//config:endif # ash options
 162
 163//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
 164//                      APPLET_ODDNAME:name  main location    suid_type     help
 165//applet:IF_SH_IS_ASH(  APPLET_ODDNAME(sh,   ash, BB_DIR_BIN, BB_SUID_DROP, ash))
 166//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
 167
 168//kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o
 169//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
 170
 171/*
 172 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
 173 * DEBUG=2 to compile in and turn on debugging.
 174 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
 175 * debugging info is written to ./trace, quit signal generates core dump.
 176 */
 177#define DEBUG 0
 178/* Tweak debug output verbosity here */
 179#define DEBUG_TIME 0
 180#define DEBUG_PID 1
 181#define DEBUG_SIG 1
 182#define DEBUG_INTONOFF 0
 183
 184#define PROFILE 0
 185
 186#define JOBS ENABLE_ASH_JOB_CONTROL
 187
 188#include <fnmatch.h>
 189#include <sys/times.h>
 190#include <sys/utsname.h> /* for setting $HOSTNAME */
 191#include "busybox.h" /* for applet_names */
 192#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
 193# include "embedded_scripts.h"
 194#else
 195# define NUM_SCRIPTS 0
 196#endif
 197
 198/* So far, all bash compat is controlled by one config option */
 199/* Separate defines document which part of code implements what */
 200/* function keyword */
 201#define    BASH_FUNCTION        ENABLE_ASH_BASH_COMPAT
 202#define IF_BASH_FUNCTION            IF_ASH_BASH_COMPAT
 203/* &>file */
 204#define    BASH_REDIR_OUTPUT    ENABLE_ASH_BASH_COMPAT
 205#define IF_BASH_REDIR_OUTPUT        IF_ASH_BASH_COMPAT
 206/* $'...' */
 207#define    BASH_DOLLAR_SQUOTE   ENABLE_ASH_BASH_COMPAT
 208#define IF_BASH_DOLLAR_SQUOTE       IF_ASH_BASH_COMPAT
 209#define    BASH_PATTERN_SUBST   ENABLE_ASH_BASH_COMPAT
 210#define IF_BASH_PATTERN_SUBST       IF_ASH_BASH_COMPAT
 211#define    BASH_SUBSTR          ENABLE_ASH_BASH_COMPAT
 212#define IF_BASH_SUBSTR              IF_ASH_BASH_COMPAT
 213/* BASH_TEST2: [[ EXPR ]]
 214 * Status of [[ support:
 215 *   && and || work as they should
 216 *   = is glob match operator, not equality operator: STR = GLOB
 217 *   == same as =
 218 *   =~ is regex match operator: STR =~ REGEX
 219 * TODO:
 220 * singleword+noglob expansion:
 221 *   v='a b'; [[ $v = 'a b' ]]; echo 0:$?
 222 *   [[ /bin/n* ]]; echo 0:$?
 223 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
 224 * ( ) < > should not have special meaning (IOW: should not require quoting)
 225 * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*"
 226 */
 227#define    BASH_TEST2           (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
 228#define    BASH_SOURCE          ENABLE_ASH_BASH_COMPAT
 229#define    BASH_PIPEFAIL        ENABLE_ASH_BASH_COMPAT
 230#define    BASH_HOSTNAME_VAR    ENABLE_ASH_BASH_COMPAT
 231#define    BASH_EPOCH_VARS      ENABLE_ASH_BASH_COMPAT
 232#define    BASH_SHLVL_VAR       ENABLE_ASH_BASH_COMPAT
 233#define    BASH_XTRACEFD        ENABLE_ASH_BASH_COMPAT
 234#define    BASH_READ_D          ENABLE_ASH_BASH_COMPAT
 235#define IF_BASH_READ_D              IF_ASH_BASH_COMPAT
 236#define    BASH_WAIT_N          ENABLE_ASH_BASH_COMPAT
 237/* <(...) and >(...) */
 238#if HAVE_DEV_FD
 239# define    BASH_PROCESS_SUBST   ENABLE_ASH_BASH_COMPAT
 240# define IF_BASH_PROCESS_SUBST       IF_ASH_BASH_COMPAT
 241#else
 242# define    BASH_PROCESS_SUBST 0
 243# define IF_BASH_PROCESS_SUBST(...)
 244#endif
 245
 246#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
 247/* Bionic at least up to version 24 has no glob() */
 248# undef  ENABLE_ASH_INTERNAL_GLOB
 249# define ENABLE_ASH_INTERNAL_GLOB 1
 250#endif
 251
 252#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
 253# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
 254# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
 255# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
 256# error glob() should unbackslash them and match. uClibc does not unbackslash,
 257# error fails to match dirname, subsequently not expanding <pattern> in it.
 258// Testcase:
 259// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
 260// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
 261#endif
 262
 263#if !ENABLE_ASH_INTERNAL_GLOB
 264# include <glob.h>
 265#endif
 266
 267#include "unicode.h"
 268#include "shell_common.h"
 269#if ENABLE_FEATURE_SH_MATH
 270# include "math.h"
 271#else
 272typedef long arith_t;
 273# define ARITH_FMT "%ld"
 274#endif
 275#if ENABLE_ASH_RANDOM_SUPPORT
 276# include "random.h"
 277#else
 278# define CLEAR_RANDOM_T(rnd) ((void)0)
 279#endif
 280
 281#include "NUM_APPLETS.h"
 282#if NUM_APPLETS == 1
 283/* STANDALONE does not make sense, and won't compile */
 284# undef CONFIG_FEATURE_SH_STANDALONE
 285# undef ENABLE_FEATURE_SH_STANDALONE
 286# undef IF_FEATURE_SH_STANDALONE
 287# undef IF_NOT_FEATURE_SH_STANDALONE
 288# define ENABLE_FEATURE_SH_STANDALONE 0
 289# define IF_FEATURE_SH_STANDALONE(...)
 290# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 291#endif
 292
 293#ifndef F_DUPFD_CLOEXEC
 294# define F_DUPFD_CLOEXEC F_DUPFD
 295#endif
 296#ifndef O_CLOEXEC
 297# define O_CLOEXEC 0
 298#endif
 299#ifndef PIPE_BUF
 300# define PIPE_BUF 4096           /* amount of buffering in a pipe */
 301#endif
 302
 303#ifndef unlikely
 304# define unlikely(cond) (cond)
 305#endif
 306
 307#if !BB_MMU
 308# error "Do not even bother, ash will not run on NOMMU machine"
 309#endif
 310
 311/* ============ Hash table sizes. Configurable. */
 312
 313#define VTABSIZE 39
 314#define ATABSIZE 39
 315#define CMDTABLESIZE 31         /* should be prime */
 316
 317
 318/* ============ Shell options */
 319
 320/* If you add/change options hare, update --help text too */
 321static const char *const optletters_optnames[] ALIGN_PTR = {
 322        "e"   "errexit",
 323        "f"   "noglob",
 324/* bash has '-o ignoreeof', but no short synonym -I for it */
 325/* (in bash, set -I disables invisible variables (what's that?)) */
 326        "I"   "ignoreeof",
 327/* The below allowed this invocation:
 328 * ash -c 'set -i; echo $-; sleep 5; echo $-'
 329 * to be ^C-ed and get to interactive ash prompt.
 330 * bash does not support such "set -i".
 331 * In our code, this is denoted by empty long name:
 332 */
 333        "i"   "",
 334/* (removing "i" altogether would remove it from "$-", not good) */
 335        "m"   "monitor",
 336        "n"   "noexec",
 337/* Ditto: bash has no "set -s", "set -c" */
 338        "s"   "",
 339        "c"   "",
 340        "x"   "xtrace",
 341        "v"   "verbose",
 342        "C"   "noclobber",
 343        "a"   "allexport",
 344        "b"   "notify",
 345        "u"   "nounset",
 346        "E"   "errtrace",
 347        "\0"  "vi"
 348#if BASH_PIPEFAIL
 349        ,"\0"  "pipefail"
 350#endif
 351#if DEBUG
 352        ,"\0"  "nolog"
 353        ,"\0"  "debug"
 354#endif
 355};
 356//bash 4.4.23 also has these opts (with these defaults):
 357//braceexpand           on
 358//emacs                 on
 359//errtrace              off
 360//functrace             off
 361//hashall               on
 362//histexpand            off
 363//history               on
 364//interactive-comments  on
 365//keyword               off
 366//onecmd                off
 367//physical              off
 368//posix                 off
 369//privileged            off
 370
 371#define optletters(n)  optletters_optnames[n][0]
 372#define optnames(n)   (optletters_optnames[n] + 1)
 373
 374enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
 375
 376
 377/* ============ Misc data */
 378
 379#define msg_illnum "Illegal number: %s"
 380
 381/*
 382 * We enclose jmp_buf in a structure so that we can declare pointers to
 383 * jump locations.  The global variable handler contains the location to
 384 * jump to when an exception occurs, and the global variable exception_type
 385 * contains a code identifying the exception.  To implement nested
 386 * exception handlers, the user should save the value of handler on entry
 387 * to an inner scope, set handler to point to a jmploc structure for the
 388 * inner scope, and restore handler on exit from the scope.
 389 */
 390struct jmploc {
 391        jmp_buf loc;
 392};
 393
 394struct globals_misc {
 395        uint8_t exitstatus;     /* exit status of last command */
 396        uint8_t back_exitstatus;/* exit status of backquoted command */
 397        smallint job_warning;   /* user was warned about stopped jobs (can be 2, 1 or 0). */
 398        smallint inps4;         /* Prevent PS4 nesting. */
 399        int savestatus;         /* exit status of last command outside traps */
 400        int rootpid;            /* pid of main shell */
 401        /* shell level: 0 for the main shell, 1 for its children, and so on */
 402        int shlvl;
 403#define rootshell (!shlvl)
 404        int errlinno;
 405
 406        char *minusc;  /* argument to -c option */
 407
 408        char *curdir; // = nullstr;     /* current working directory */
 409        char *physdir; // = nullstr;    /* physical working directory */
 410
 411        char *arg0; /* value of $0 */
 412
 413        struct jmploc *exception_handler;
 414
 415        volatile int suppress_int; /* counter */
 416        volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
 417        volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
 418        volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
 419        smallint exception_type; /* kind of exception: */
 420#define EXINT 0         /* SIGINT received */
 421#define EXERROR 1       /* a generic error */
 422#define EXEND 3         /* exit the shell */
 423#define EXEXIT 4        /* exit the shell via exitcmd */
 424
 425        char nullstr[1];        /* zero length string */
 426
 427        char optlist[NOPTS];
 428#define eflag optlist[0]
 429#define fflag optlist[1]
 430#define Iflag optlist[2]
 431#define iflag optlist[3]
 432#define mflag optlist[4]
 433#define nflag optlist[5]
 434#define sflag optlist[6]
 435#define cflag optlist[7]
 436#define xflag optlist[8]
 437#define vflag optlist[9]
 438#define Cflag optlist[10]
 439#define aflag optlist[11]
 440#define bflag optlist[12]
 441#define uflag optlist[13]
 442#define Eflag optlist[14]
 443#define viflag optlist[15]
 444#if BASH_PIPEFAIL
 445# define pipefail optlist[16]
 446#else
 447# define pipefail 0
 448#endif
 449#if DEBUG
 450# define nolog optlist[16 + BASH_PIPEFAIL]
 451# define debug optlist[17 + BASH_PIPEFAIL]
 452#endif
 453
 454        /* trap handler commands */
 455        /*
 456         * Sigmode records the current value of the signal handlers for the various
 457         * modes.  A value of zero means that the current handler is not known.
 458         * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
 459         */
 460        char sigmode[NSIG - 1];
 461#define S_DFL      1            /* default signal handling (SIG_DFL) */
 462#define S_CATCH    2            /* signal is caught */
 463#define S_IGN      3            /* signal is ignored (SIG_IGN) */
 464#define S_HARD_IGN 4            /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
 465
 466        /* indicates specified signal received */
 467        uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
 468        uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
 469        char *trap[NSIG + 1];
 470/* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */
 471#define NTRAP_ERR  NSIG
 472#define NTRAP_LAST NSIG
 473
 474        char **trap_ptr;        /* used only by "trap hack" */
 475
 476        /* Rarely referenced stuff */
 477#if ENABLE_ASH_RANDOM_SUPPORT
 478        random_t random_gen;
 479#endif
 480        pid_t backgndpid;        /* pid of last background process */
 481};
 482extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
 483#define G_misc (*ash_ptr_to_globals_misc)
 484#define exitstatus        (G_misc.exitstatus )
 485#define back_exitstatus   (G_misc.back_exitstatus )
 486#define job_warning       (G_misc.job_warning)
 487#define inps4       (G_misc.inps4      )
 488#define savestatus  (G_misc.savestatus )
 489#define rootpid     (G_misc.rootpid    )
 490#define shlvl       (G_misc.shlvl      )
 491#define errlinno    (G_misc.errlinno   )
 492#define minusc      (G_misc.minusc     )
 493#define curdir      (G_misc.curdir     )
 494#define physdir     (G_misc.physdir    )
 495#define arg0        (G_misc.arg0       )
 496#define exception_handler (G_misc.exception_handler)
 497#define exception_type    (G_misc.exception_type   )
 498#define suppress_int      (G_misc.suppress_int     )
 499#define pending_int       (G_misc.pending_int      )
 500#define got_sigchld       (G_misc.got_sigchld      )
 501#define pending_sig       (G_misc.pending_sig      )
 502#define nullstr     (G_misc.nullstr    )
 503#define optlist     (G_misc.optlist    )
 504#define sigmode     (G_misc.sigmode    )
 505#define gotsig      (G_misc.gotsig     )
 506#define may_have_traps    (G_misc.may_have_traps   )
 507#define trap        (G_misc.trap       )
 508#define trap_ptr    (G_misc.trap_ptr   )
 509#define random_gen  (G_misc.random_gen )
 510#define backgndpid  (G_misc.backgndpid )
 511#define INIT_G_misc() do { \
 512        XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \
 513        savestatus = -1; \
 514        curdir = nullstr; \
 515        physdir = nullstr; \
 516        trap_ptr = trap; \
 517} while (0)
 518
 519
 520/* ============ DEBUG */
 521#if DEBUG
 522static void trace_printf(const char *fmt, ...);
 523static void trace_vprintf(const char *fmt, va_list va);
 524# define TRACE(param)    trace_printf param
 525# define TRACEV(param)   trace_vprintf param
 526# define close(fd) do { \
 527        int dfd = (fd); \
 528        if (close(dfd) < 0) \
 529                bb_error_msg("bug on %d: closing %d(0x%x)", \
 530                        __LINE__, dfd, dfd); \
 531} while (0)
 532#else
 533# define TRACE(param)
 534# define TRACEV(param)
 535#endif
 536
 537
 538/* ============ Utility functions */
 539#define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
 540#define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
 541
 542static int
 543isdigit_str9(const char *str)
 544{
 545        int maxlen = 9 + 1; /* max 9 digits: 999999999 */
 546        while (--maxlen && isdigit(*str))
 547                str++;
 548        return (*str == '\0');
 549}
 550
 551static const char *
 552var_end(const char *var)
 553{
 554        while (*var)
 555                if (*var++ == '=')
 556                        break;
 557        return var;
 558}
 559
 560
 561/* ============ Parser data */
 562
 563/*
 564 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
 565 */
 566struct strlist {
 567        struct strlist *next;
 568        char *text;
 569};
 570
 571struct alias;
 572
 573struct strpush {
 574        struct strpush *prev;   /* preceding string on stack */
 575        char *prev_string;
 576        int prev_left_in_line;
 577#if ENABLE_ASH_ALIAS
 578        struct alias *ap;       /* if push was associated with an alias */
 579#endif
 580        char *string;           /* remember the string since it may change */
 581
 582        /* Delay freeing so we can stop nested aliases. */
 583        struct strpush *spfree;
 584
 585        /* Remember last two characters for pungetc. */
 586        int lastc[2];
 587
 588        /* Number of outstanding calls to pungetc. */
 589        int unget;
 590};
 591
 592/*
 593 * The parsefile structure pointed to by the global variable parsefile
 594 * contains information about the current file being read.
 595 */
 596struct parsefile {
 597        struct parsefile *prev; /* preceding file on stack */
 598        int linno;              /* current line */
 599        int pf_fd;              /* file descriptor (or -1 if string) */
 600        int left_in_line;       /* number of chars left in this line */
 601        int left_in_buffer;     /* number of chars left in this buffer past the line */
 602        char *next_to_pgetc;    /* next char in buffer */
 603        char *buf;              /* input buffer */
 604        struct strpush *strpush; /* for pushing strings at this level */
 605        struct strpush basestrpush; /* so pushing one is fast */
 606
 607        /* Delay freeing so we can stop nested aliases. */
 608        struct strpush *spfree;
 609
 610        /* Remember last two characters for pungetc. */
 611        int lastc[2];
 612
 613        /* Number of outstanding calls to pungetc. */
 614        int unget;
 615};
 616
 617static struct parsefile basepf;        /* top level input file */
 618static struct parsefile *g_parsefile = &basepf;  /* current input file */
 619static char *commandname;              /* currently executing command */
 620
 621
 622/* ============ Interrupts / exceptions */
 623
 624static void exitshell(void) NORETURN;
 625
 626/*
 627 * These macros allow the user to suspend the handling of interrupt signals
 628 * over a period of time.  This is similar to SIGHOLD or to sigblock, but
 629 * much more efficient and portable.  (But hacking the kernel is so much
 630 * more fun than worrying about efficiency and portability. :-))
 631 */
 632#if DEBUG_INTONOFF
 633# define INT_OFF do { \
 634        TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
 635        suppress_int++; \
 636        barrier(); \
 637} while (0)
 638#else
 639# define INT_OFF do { \
 640        suppress_int++; \
 641        barrier(); \
 642} while (0)
 643#endif
 644
 645/*
 646 * Called to raise an exception.  Since C doesn't include exceptions, we
 647 * just do a longjmp to the exception handler.  The type of exception is
 648 * stored in the global variable "exception_type".
 649 */
 650static void raise_exception(int) NORETURN;
 651static void
 652raise_exception(int e)
 653{
 654#if DEBUG
 655        if (exception_handler == NULL)
 656                abort();
 657#endif
 658        INT_OFF;
 659        exception_type = e;
 660        longjmp(exception_handler->loc, 1);
 661}
 662#if DEBUG
 663#define raise_exception(e) do { \
 664        TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
 665        raise_exception(e); \
 666} while (0)
 667#endif
 668
 669/*
 670 * Called when a SIGINT is received.  (If the user specifies
 671 * that SIGINT is to be trapped or ignored using the trap builtin, then
 672 * this routine is not called.)  suppress_int is nonzero when interrupts
 673 * are held using the INT_OFF macro.  (The test for iflag is just
 674 * defensive programming.)
 675 */
 676static void raise_interrupt(void) NORETURN;
 677static void
 678raise_interrupt(void)
 679{
 680        pending_int = 0;
 681        /* Signal is not automatically unmasked after it is raised,
 682         * do it ourself - unmask all signals */
 683        sigprocmask_allsigs(SIG_UNBLOCK);
 684        /* pending_sig = 0; - now done in signal_handler() */
 685
 686        if (!(rootshell && iflag)) {
 687                /* Kill ourself with SIGINT */
 688                signal(SIGINT, SIG_DFL);
 689                raise(SIGINT);
 690        }
 691        /* bash: ^C even on empty command line sets $? */
 692        exitstatus = SIGINT + 128;
 693        raise_exception(EXINT);
 694        /* NOTREACHED */
 695}
 696#if DEBUG
 697#define raise_interrupt() do { \
 698        TRACE(("raising interrupt on line %d\n", __LINE__)); \
 699        raise_interrupt(); \
 700} while (0)
 701#endif
 702
 703static IF_NOT_ASH_OPTIMIZE_FOR_SIZE(inline) void
 704int_on(void)
 705{
 706        barrier();
 707        if (--suppress_int == 0 && pending_int)
 708                raise_interrupt();
 709}
 710#if DEBUG_INTONOFF
 711# define INT_ON do { \
 712        TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
 713        int_on(); \
 714} while (0)
 715#else
 716# define INT_ON int_on()
 717#endif
 718static IF_NOT_ASH_OPTIMIZE_FOR_SIZE(inline) void
 719force_int_on(void)
 720{
 721        barrier();
 722        suppress_int = 0;
 723        if (pending_int)
 724                raise_interrupt();
 725}
 726#define FORCE_INT_ON force_int_on()
 727
 728#define SAVE_INT(v) ((v) = suppress_int)
 729
 730#define RESTORE_INT(v) do { \
 731        barrier(); \
 732        suppress_int = (v); \
 733        if (suppress_int == 0 && pending_int) \
 734                raise_interrupt(); \
 735} while (0)
 736
 737
 738/* ============ Stdout/stderr output */
 739
 740static void
 741outstr(const char *p, FILE *file)
 742{
 743        INT_OFF;
 744        fputs(p, file);
 745        INT_ON;
 746}
 747
 748static void
 749flush_stdout_stderr(void)
 750{
 751        INT_OFF;
 752        fflush_all();
 753        INT_ON;
 754}
 755
 756/* Was called outcslow(c,FILE*), but c was always '\n' */
 757static void
 758newline_and_flush(FILE *dest)
 759{
 760        INT_OFF;
 761        putc('\n', dest);
 762        fflush(dest);
 763        INT_ON;
 764}
 765
 766static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
 767static int
 768out1fmt(const char *fmt, ...)
 769{
 770        va_list ap;
 771        int r;
 772
 773        INT_OFF;
 774        va_start(ap, fmt);
 775        r = vprintf(fmt, ap);
 776        va_end(ap);
 777        INT_ON;
 778        return r;
 779}
 780
 781static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
 782static int
 783fmtstr(char *outbuf, size_t length, const char *fmt, ...)
 784{
 785        va_list ap;
 786        int ret;
 787
 788        INT_OFF;
 789        va_start(ap, fmt);
 790        ret = vsnprintf(outbuf, length, fmt, ap);
 791        va_end(ap);
 792        INT_ON;
 793        return ret > (int)length ? length : ret;
 794}
 795
 796static void
 797out1str(const char *p)
 798{
 799        outstr(p, stdout);
 800}
 801
 802static void
 803out2str(const char *p)
 804{
 805        outstr(p, stderr);
 806        flush_stdout_stderr();
 807}
 808
 809
 810/* ============ Parser structures */
 811
 812/* control characters in argument strings */
 813#define CTL_FIRST CTLESC
 814#define CTLESC       ((unsigned char)'\201')    /* escape next character */
 815#define CTLVAR       ((unsigned char)'\202')    /* variable defn */
 816#define CTLENDVAR    ((unsigned char)'\203')
 817#define CTLBACKQ     ((unsigned char)'\204')
 818#define CTLARI       ((unsigned char)'\206')    /* arithmetic expression */
 819#define CTLENDARI    ((unsigned char)'\207')
 820#define CTLQUOTEMARK ((unsigned char)'\210')
 821#define CTL_LAST CTLQUOTEMARK
 822#if BASH_PROCESS_SUBST
 823# define CTLTOPROC    ((unsigned char)'\211')
 824# define CTLFROMPROC  ((unsigned char)'\212')
 825# undef CTL_LAST
 826# define CTL_LAST CTLFROMPROC
 827#endif
 828
 829/* variable substitution byte (follows CTLVAR) */
 830#define VSTYPE  0x0f            /* type of variable substitution */
 831#define VSNUL   0x10            /* colon--treat the empty string as unset */
 832
 833/* values of VSTYPE field */
 834#define VSNORMAL        0x1     /* normal variable:  $var or ${var} */
 835#define VSMINUS         0x2     /* ${var-text} */
 836#define VSPLUS          0x3     /* ${var+text} */
 837#define VSQUESTION      0x4     /* ${var?message} */
 838#define VSASSIGN        0x5     /* ${var=text} */
 839#define VSTRIMRIGHT     0x6     /* ${var%pattern} */
 840#define VSTRIMRIGHTMAX  0x7     /* ${var%%pattern} */
 841#define VSTRIMLEFT      0x8     /* ${var#pattern} */
 842#define VSTRIMLEFTMAX   0x9     /* ${var##pattern} */
 843#define VSLENGTH        0xa     /* ${#var} */
 844#if BASH_SUBSTR
 845#define VSSUBSTR        0xc     /* ${var:position:length} */
 846#endif
 847#if BASH_PATTERN_SUBST
 848#define VSREPLACE       0xd     /* ${var/pattern/replacement} */
 849#define VSREPLACEALL    0xe     /* ${var//pattern/replacement} */
 850#endif
 851
 852static const char dolatstr[] ALIGN1 = {
 853        CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
 854};
 855#define DOLATSTRLEN 6
 856
 857#define NCMD      0
 858#define NPIPE     1
 859#define NREDIR    2
 860#define NBACKGND  3
 861#define NSUBSHELL 4
 862#define NAND      5
 863#define NOR       6
 864#define NSEMI     7
 865#define NIF       8
 866#define NWHILE    9
 867#define NUNTIL   10
 868#define NFOR     11
 869#define NCASE    12
 870#define NCLIST   13
 871#define NDEFUN   14
 872#define NARG     15
 873#define NTO      16
 874#if BASH_REDIR_OUTPUT
 875#define NTO2     17
 876#endif
 877#define NCLOBBER 18
 878#define NFROM    19
 879#define NFROMTO  20
 880#define NAPPEND  21
 881#define NTOFD    22
 882#define NFROMFD  23
 883#define NHERE    24
 884#define NXHERE   25
 885#define NNOT     26
 886#define N_NUMBER 27
 887
 888union node;
 889
 890struct ncmd {
 891        smallint type; /* Nxxxx */
 892        int linno;
 893        union node *assign;
 894        union node *args;
 895        union node *redirect;
 896};
 897
 898struct npipe {
 899        smallint type;
 900        smallint pipe_backgnd;
 901        struct nodelist *cmdlist;
 902};
 903
 904struct nredir {
 905        smallint type;
 906        int linno;
 907        union node *n;
 908        union node *redirect;
 909};
 910
 911struct nbinary {
 912        smallint type;
 913        union node *ch1;
 914        union node *ch2;
 915};
 916
 917struct nif {
 918        smallint type;
 919        union node *test;
 920        union node *ifpart;
 921        union node *elsepart;
 922};
 923
 924struct nfor {
 925        smallint type;
 926        int linno;
 927        union node *args;
 928        union node *body;
 929        char *var;
 930};
 931
 932struct ncase {
 933        smallint type;
 934        int linno;
 935        union node *expr;
 936        union node *cases;
 937};
 938
 939struct nclist {
 940        smallint type;
 941        union node *next;
 942        union node *pattern;
 943        union node *body;
 944};
 945
 946struct ndefun {
 947        smallint type;
 948        int linno;
 949        char *text;
 950        union node *body;
 951};
 952
 953struct narg {
 954        smallint type;
 955        union node *next;
 956        char *text;
 957        struct nodelist *backquote;
 958};
 959
 960/* nfile and ndup layout must match!
 961 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
 962 * that it is actually NTO2 (>&file), and change its type.
 963 */
 964struct nfile {
 965        smallint type;
 966        union node *next;
 967        int fd;
 968        int _unused_dupfd;
 969        union node *fname;
 970        char *expfname;
 971};
 972
 973struct ndup {
 974        smallint type;
 975        union node *next;
 976        int fd;
 977        int dupfd;
 978        union node *vname;
 979        char *_unused_expfname;
 980};
 981
 982struct nhere {
 983        smallint type;
 984        union node *next;
 985        int fd;
 986        union node *doc;
 987};
 988
 989struct nnot {
 990        smallint type;
 991        union node *com;
 992};
 993
 994union node {
 995        smallint type;
 996        struct ncmd ncmd;
 997        struct npipe npipe;
 998        struct nredir nredir;
 999        struct nbinary nbinary;
1000        struct nif nif;
1001        struct nfor nfor;
1002        struct ncase ncase;
1003        struct nclist nclist;
1004        struct ndefun ndefun;
1005        struct narg narg;
1006        struct nfile nfile;
1007        struct ndup ndup;
1008        struct nhere nhere;
1009        struct nnot nnot;
1010};
1011
1012/*
1013 * NODE_EOF is returned by parsecmd when it encounters an end of file.
1014 * It must be distinct from NULL.
1015 */
1016#define NODE_EOF ((union node *) -1L)
1017
1018struct nodelist {
1019        struct nodelist *next;
1020        union node *n;
1021};
1022
1023struct funcnode {
1024        int count;
1025        union node n;
1026};
1027
1028/*
1029 * Free a parse tree.
1030 */
1031static void
1032freefunc(struct funcnode *f)
1033{
1034        if (f && --f->count < 0)
1035                free(f);
1036}
1037
1038
1039/* ============ Debugging output */
1040
1041#if DEBUG
1042
1043static FILE *tracefile;
1044
1045static void
1046trace_printf(const char *fmt, ...)
1047{
1048        va_list va;
1049
1050        if (debug != 1)
1051                return;
1052        if (DEBUG_TIME)
1053                fprintf(tracefile, "%u ", (int) time(NULL));
1054        if (DEBUG_PID)
1055                fprintf(tracefile, "[%u] ", (int) getpid());
1056        if (DEBUG_SIG)
1057                fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
1058        va_start(va, fmt);
1059        vfprintf(tracefile, fmt, va);
1060        va_end(va);
1061}
1062
1063static void
1064trace_vprintf(const char *fmt, va_list va)
1065{
1066        if (debug != 1)
1067                return;
1068        vfprintf(tracefile, fmt, va);
1069        fprintf(tracefile, "\n");
1070}
1071
1072static void
1073trace_puts(const char *s)
1074{
1075        if (debug != 1)
1076                return;
1077        fputs(s, tracefile);
1078}
1079
1080static void
1081trace_puts_quoted(char *s)
1082{
1083        char *p;
1084        char c;
1085
1086        if (debug != 1)
1087                return;
1088        putc('"', tracefile);
1089        for (p = s; *p; p++) {
1090                switch ((unsigned char)*p) {
1091                case '\n': c = 'n'; goto backslash;
1092                case '\t': c = 't'; goto backslash;
1093                case '\r': c = 'r'; goto backslash;
1094                case '\"': c = '\"'; goto backslash;
1095                case '\\': c = '\\'; goto backslash;
1096                case CTLESC: c = 'e'; goto backslash;
1097                case CTLVAR: c = 'v'; goto backslash;
1098                case CTLBACKQ: c = 'q'; goto backslash;
1099#if BASH_PROCESS_SUBST
1100                case CTLTOPROC: c = 'p'; goto backslash;
1101                case CTLFROMPROC: c = 'P'; goto backslash;
1102#endif
1103 backslash:
1104                        putc('\\', tracefile);
1105                        putc(c, tracefile);
1106                        break;
1107                default:
1108                        if (*p >= ' ' && *p <= '~')
1109                                putc(*p, tracefile);
1110                        else {
1111                                putc('\\', tracefile);
1112                                putc((*p >> 6) & 03, tracefile);
1113                                putc((*p >> 3) & 07, tracefile);
1114                                putc(*p & 07, tracefile);
1115                        }
1116                        break;
1117                }
1118        }
1119        putc('"', tracefile);
1120}
1121
1122static void
1123trace_puts_args(char **ap)
1124{
1125        if (debug != 1)
1126                return;
1127        if (!*ap)
1128                return;
1129        while (1) {
1130                trace_puts_quoted(*ap);
1131                if (!*++ap) {
1132                        putc('\n', tracefile);
1133                        break;
1134                }
1135                putc(' ', tracefile);
1136        }
1137}
1138
1139static void
1140opentrace(void)
1141{
1142        char s[100];
1143#ifdef O_APPEND
1144        int flags;
1145#endif
1146
1147        if (debug != 1) {
1148                if (tracefile)
1149                        fflush(tracefile);
1150                /* leave open because libedit might be using it */
1151                return;
1152        }
1153        strcpy(s, "./trace");
1154        if (tracefile) {
1155                if (!freopen(s, "a", tracefile)) {
1156                        fprintf(stderr, "Can't re-open %s\n", s);
1157                        debug = 0;
1158                        return;
1159                }
1160        } else {
1161                tracefile = fopen(s, "a");
1162                if (tracefile == NULL) {
1163                        fprintf(stderr, "Can't open %s\n", s);
1164                        debug = 0;
1165                        return;
1166                }
1167        }
1168#ifdef O_APPEND
1169        flags = fcntl(fileno(tracefile), F_GETFL);
1170        if (flags >= 0)
1171                fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1172#endif
1173        setlinebuf(tracefile);
1174        fputs("\nTracing started.\n", tracefile);
1175}
1176
1177static void
1178indent(int amount, char *pfx, FILE *fp)
1179{
1180        int i;
1181
1182        for (i = 0; i < amount; i++) {
1183                if (pfx && i == amount - 1)
1184                        fputs(pfx, fp);
1185                putc('\t', fp);
1186        }
1187}
1188
1189/* little circular references here... */
1190static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1191
1192static void
1193sharg(union node *arg, FILE *fp)
1194{
1195        char *p;
1196        struct nodelist *bqlist;
1197        unsigned char subtype;
1198
1199        if (arg->type != NARG) {
1200                out1fmt("<node type %d>\n", arg->type);
1201                abort();
1202        }
1203        bqlist = arg->narg.backquote;
1204        for (p = arg->narg.text; *p; p++) {
1205                switch ((unsigned char)*p) {
1206                case CTLESC:
1207                        p++;
1208                        putc(*p, fp);
1209                        break;
1210                case CTLVAR:
1211                        putc('$', fp);
1212                        putc('{', fp);
1213                        subtype = *++p;
1214                        if (subtype == VSLENGTH)
1215                                putc('#', fp);
1216
1217                        while (*p != '=') {
1218                                putc(*p, fp);
1219                                p++;
1220                        }
1221
1222                        if (subtype & VSNUL)
1223                                putc(':', fp);
1224
1225                        switch (subtype & VSTYPE) {
1226                        case VSNORMAL:
1227                                putc('}', fp);
1228                                break;
1229                        case VSMINUS:
1230                                putc('-', fp);
1231                                break;
1232                        case VSPLUS:
1233                                putc('+', fp);
1234                                break;
1235                        case VSQUESTION:
1236                                putc('?', fp);
1237                                break;
1238                        case VSASSIGN:
1239                                putc('=', fp);
1240                                break;
1241                        case VSTRIMLEFT:
1242                                putc('#', fp);
1243                                break;
1244                        case VSTRIMLEFTMAX:
1245                                putc('#', fp);
1246                                putc('#', fp);
1247                                break;
1248                        case VSTRIMRIGHT:
1249                                putc('%', fp);
1250                                break;
1251                        case VSTRIMRIGHTMAX:
1252                                putc('%', fp);
1253                                putc('%', fp);
1254                                break;
1255                        case VSLENGTH:
1256                                break;
1257                        default:
1258                                out1fmt("<subtype %d>", subtype);
1259                        }
1260                        break;
1261                case CTLENDVAR:
1262                        putc('}', fp);
1263                        break;
1264#if BASH_PROCESS_SUBST
1265                case CTLTOPROC:
1266                        putc('>', fp);
1267                        goto backq;
1268                case CTLFROMPROC:
1269                        putc('<', fp);
1270                        goto backq;
1271#endif
1272                case CTLBACKQ:
1273                        putc('$', fp);
1274 IF_BASH_PROCESS_SUBST(backq:)
1275                        putc('(', fp);
1276                        shtree(bqlist->n, -1, NULL, fp);
1277                        putc(')', fp);
1278                        break;
1279                default:
1280                        putc(*p, fp);
1281                        break;
1282                }
1283        }
1284}
1285
1286static void
1287shcmd(union node *cmd, FILE *fp)
1288{
1289        union node *np;
1290        int first;
1291        const char *s;
1292        int dftfd;
1293
1294        first = 1;
1295        for (np = cmd->ncmd.args; np; np = np->narg.next) {
1296                if (!first)
1297                        putc(' ', fp);
1298                sharg(np, fp);
1299                first = 0;
1300        }
1301        for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1302                if (!first)
1303                        putc(' ', fp);
1304                dftfd = 0;
1305                switch (np->nfile.type) {
1306                case NTO:      s = ">>"+1; dftfd = 1; break;
1307                case NCLOBBER: s = ">|"; dftfd = 1; break;
1308                case NAPPEND:  s = ">>"; dftfd = 1; break;
1309#if BASH_REDIR_OUTPUT
1310                case NTO2:
1311#endif
1312                case NTOFD:    s = ">&"; dftfd = 1; break;
1313                case NFROM:    s = "<"; break;
1314                case NFROMFD:  s = "<&"; break;
1315                case NFROMTO:  s = "<>"; break;
1316                default:       s = "*error*"; break;
1317                }
1318                if (np->nfile.fd != dftfd)
1319                        fprintf(fp, "%d", np->nfile.fd);
1320                fputs(s, fp);
1321                if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1322                        fprintf(fp, "%d", np->ndup.dupfd);
1323                } else {
1324                        sharg(np->nfile.fname, fp);
1325                }
1326                first = 0;
1327        }
1328}
1329
1330static void
1331shtree(union node *n, int ind, char *pfx, FILE *fp)
1332{
1333        struct nodelist *lp;
1334        const char *s;
1335
1336        if (n == NULL)
1337                return;
1338
1339        indent(ind, pfx, fp);
1340
1341        if (n == NODE_EOF) {
1342                fputs("<EOF>", fp);
1343                return;
1344        }
1345
1346        switch (n->type) {
1347        case NSEMI:
1348                s = "; ";
1349                goto binop;
1350        case NAND:
1351                s = " && ";
1352                goto binop;
1353        case NOR:
1354                s = " || ";
1355 binop:
1356                shtree(n->nbinary.ch1, ind, NULL, fp);
1357                /* if (ind < 0) */
1358                        fputs(s, fp);
1359                shtree(n->nbinary.ch2, ind, NULL, fp);
1360                break;
1361        case NCMD:
1362                shcmd(n, fp);
1363                if (ind >= 0)
1364                        putc('\n', fp);
1365                break;
1366        case NPIPE:
1367                for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1368                        shtree(lp->n, 0, NULL, fp);
1369                        if (lp->next)
1370                                fputs(" | ", fp);
1371                }
1372                if (n->npipe.pipe_backgnd)
1373                        fputs(" &", fp);
1374                if (ind >= 0)
1375                        putc('\n', fp);
1376                break;
1377        default:
1378                fprintf(fp, "<node type %d>", n->type);
1379                if (ind >= 0)
1380                        putc('\n', fp);
1381                break;
1382        }
1383}
1384
1385static void
1386showtree(union node *n)
1387{
1388        trace_puts("showtree called\n");
1389        shtree(n, 1, NULL, stderr);
1390}
1391
1392#endif /* DEBUG */
1393
1394
1395/* ============ Message printing */
1396
1397static void
1398ash_vmsg(const char *msg, va_list ap)
1399{
1400        fprintf(stderr, "%s: ", arg0);
1401        if (commandname) {
1402                if (strcmp(arg0, commandname))
1403                        fprintf(stderr, "%s: ", commandname);
1404                if (!iflag || g_parsefile->pf_fd > 0)
1405                        fprintf(stderr, "line %d: ", errlinno);
1406        }
1407        vfprintf(stderr, msg, ap);
1408        newline_and_flush(stderr);
1409}
1410
1411/*
1412 * Exverror is called to raise the error exception.  If the second argument
1413 * is not NULL then error prints an error message using printf style
1414 * formatting.  It then raises the error exception.
1415 */
1416static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1417static void
1418ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1419{
1420#if DEBUG
1421        if (msg) {
1422                TRACE(("ash_vmsg_and_raise(%d):", cond));
1423                TRACEV((msg, ap));
1424        } else
1425                TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1426        if (msg)
1427#endif
1428                ash_vmsg(msg, ap);
1429
1430        flush_stdout_stderr();
1431        raise_exception(cond);
1432        /* NOTREACHED */
1433}
1434
1435static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1436static void
1437ash_msg_and_raise_error(const char *msg, ...)
1438{
1439        va_list ap;
1440
1441        exitstatus = 2;
1442
1443        va_start(ap, msg);
1444        ash_vmsg_and_raise(EXERROR, msg, ap);
1445        /* NOTREACHED */
1446        va_end(ap);
1447}
1448
1449/*
1450 * 'fmt' must be a string literal.
1451 */
1452#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
1453
1454static void raise_error_syntax(const char *) NORETURN;
1455static void
1456raise_error_syntax(const char *msg)
1457{
1458        errlinno = g_parsefile->linno;
1459        ash_msg_and_raise_error("syntax error: %s", msg);
1460        /* NOTREACHED */
1461}
1462
1463static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1464static void
1465ash_msg_and_raise(int cond, const char *msg, ...)
1466{
1467        va_list ap;
1468
1469        va_start(ap, msg);
1470        ash_vmsg_and_raise(cond, msg, ap);
1471        /* NOTREACHED */
1472        va_end(ap);
1473}
1474
1475/*
1476 * error/warning routines for external builtins
1477 */
1478static void
1479ash_msg(const char *fmt, ...)
1480{
1481        va_list ap;
1482
1483        va_start(ap, fmt);
1484        ash_vmsg(fmt, ap);
1485        va_end(ap);
1486}
1487
1488/*
1489 * Return a string describing an error.  The returned string may be a
1490 * pointer to a static buffer that will be overwritten on the next call.
1491 * Action describes the operation that got the error.
1492 */
1493static const char *
1494errmsg(int e, const char *em)
1495{
1496        if (e == ENOENT || e == ENOTDIR) {
1497                return em;
1498        }
1499        return strerror(e);
1500}
1501
1502
1503/* ============ Memory allocation */
1504
1505#if 0
1506/* I consider these wrappers nearly useless:
1507 * ok, they return you to nearest exception handler, but
1508 * how much memory do you leak in the process, making
1509 * memory starvation worse?
1510 */
1511static void *
1512ckrealloc(void * p, size_t nbytes)
1513{
1514        p = realloc(p, nbytes);
1515        if (!p)
1516                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1517        return p;
1518}
1519
1520static void *
1521ckmalloc(size_t nbytes)
1522{
1523        return ckrealloc(NULL, nbytes);
1524}
1525
1526static void *
1527ckzalloc(size_t nbytes)
1528{
1529        return memset(ckmalloc(nbytes), 0, nbytes);
1530}
1531
1532static char *
1533ckstrdup(const char *s)
1534{
1535        char *p = strdup(s);
1536        if (!p)
1537                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1538        return p;
1539}
1540#else
1541/* Using bbox equivalents. They exit if out of memory */
1542# define ckrealloc xrealloc
1543# define ckmalloc  xmalloc
1544# define ckzalloc  xzalloc
1545# define ckstrdup  xstrdup
1546#endif
1547
1548/*
1549 * It appears that grabstackstr() will barf with such alignments
1550 * because stalloc() will return a string allocated in a new stackblock.
1551 */
1552#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1553enum {
1554        /* Most machines require the value returned from malloc to be aligned
1555         * in some way.  The following macro will get this right
1556         * on many machines.  */
1557        SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1558        /* Minimum size of a block */
1559        MINSIZE = SHELL_ALIGN(504),
1560};
1561
1562struct stack_block {
1563        struct stack_block *prev;
1564        char space[MINSIZE];
1565};
1566
1567struct stackmark {
1568        struct stack_block *stackp;
1569        char *stacknxt;
1570        size_t stacknleft;
1571};
1572
1573
1574struct globals_memstack {
1575        struct stack_block *g_stackp; // = &stackbase;
1576        char *g_stacknxt; // = stackbase.space;
1577        char *sstrend; // = stackbase.space + MINSIZE;
1578        size_t g_stacknleft; // = MINSIZE;
1579        struct stack_block stackbase;
1580};
1581extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1582#define G_memstack (*ash_ptr_to_globals_memstack)
1583#define g_stackp     (G_memstack.g_stackp    )
1584#define g_stacknxt   (G_memstack.g_stacknxt  )
1585#define sstrend      (G_memstack.sstrend     )
1586#define g_stacknleft (G_memstack.g_stacknleft)
1587#define stackbase    (G_memstack.stackbase   )
1588#define INIT_G_memstack() do { \
1589        XZALLOC_CONST_PTR(&ash_ptr_to_globals_memstack, sizeof(G_memstack)); \
1590        g_stackp = &stackbase; \
1591        g_stacknxt = stackbase.space; \
1592        g_stacknleft = MINSIZE; \
1593        sstrend = stackbase.space + MINSIZE; \
1594} while (0)
1595
1596
1597#define stackblock()     ((void *)g_stacknxt)
1598#define stackblocksize() g_stacknleft
1599
1600/*
1601 * Parse trees for commands are allocated in lifo order, so we use a stack
1602 * to make this more efficient, and also to avoid all sorts of exception
1603 * handling code to handle interrupts in the middle of a parse.
1604 *
1605 * The size 504 was chosen because the Ultrix malloc handles that size
1606 * well.
1607 */
1608static void *
1609stalloc(size_t nbytes)
1610{
1611        char *p;
1612        size_t aligned;
1613
1614        aligned = SHELL_ALIGN(nbytes);
1615        if (aligned > g_stacknleft) {
1616                size_t len;
1617                size_t blocksize;
1618                struct stack_block *sp;
1619
1620                blocksize = aligned;
1621                if (blocksize < MINSIZE)
1622                        blocksize = MINSIZE;
1623                len = sizeof(struct stack_block) - MINSIZE + blocksize;
1624                if (len < blocksize)
1625                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
1626                INT_OFF;
1627                sp = ckmalloc(len);
1628                sp->prev = g_stackp;
1629                g_stacknxt = sp->space;
1630                g_stacknleft = blocksize;
1631                sstrend = g_stacknxt + blocksize;
1632                g_stackp = sp;
1633                INT_ON;
1634        }
1635        p = g_stacknxt;
1636        g_stacknxt += aligned;
1637        g_stacknleft -= aligned;
1638        return p;
1639}
1640
1641static void *
1642stzalloc(size_t nbytes)
1643{
1644        return memset(stalloc(nbytes), 0, nbytes);
1645}
1646
1647static void
1648stunalloc(void *p)
1649{
1650#if DEBUG
1651        if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1652                write(STDERR_FILENO, "stunalloc\n", 10);
1653                abort();
1654        }
1655#endif
1656        g_stacknleft += g_stacknxt - (char *)p;
1657        g_stacknxt = p;
1658}
1659
1660/*
1661 * Like strdup but works with the ash stack.
1662 */
1663static char *
1664sstrdup(const char *p)
1665{
1666        size_t len = strlen(p) + 1;
1667        return memcpy(stalloc(len), p, len);
1668}
1669
1670static ALWAYS_INLINE void
1671grabstackblock(size_t len)
1672{
1673        stalloc(len);
1674}
1675
1676static void
1677pushstackmark(struct stackmark *mark, size_t len)
1678{
1679        mark->stackp = g_stackp;
1680        mark->stacknxt = g_stacknxt;
1681        mark->stacknleft = g_stacknleft;
1682        grabstackblock(len);
1683}
1684
1685static void
1686setstackmark(struct stackmark *mark)
1687{
1688        pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1689}
1690
1691static void
1692popstackmark(struct stackmark *mark)
1693{
1694        struct stack_block *sp;
1695
1696        if (!mark->stackp)
1697                return;
1698
1699        INT_OFF;
1700        while (g_stackp != mark->stackp) {
1701                sp = g_stackp;
1702                g_stackp = sp->prev;
1703                free(sp);
1704        }
1705        g_stacknxt = mark->stacknxt;
1706        g_stacknleft = mark->stacknleft;
1707        sstrend = mark->stacknxt + mark->stacknleft;
1708        INT_ON;
1709}
1710
1711/*
1712 * When the parser reads in a string, it wants to stick the string on the
1713 * stack and only adjust the stack pointer when it knows how big the
1714 * string is.  Stackblock (defined in stack.h) returns a pointer to a block
1715 * of space on top of the stack and stackblocklen returns the length of
1716 * this block.  Growstackblock will grow this space by at least one byte,
1717 * possibly moving it (like realloc).  Grabstackblock actually allocates the
1718 * part of the block that has been used.
1719 */
1720static void
1721growstackblock(size_t min)
1722{
1723        size_t newlen;
1724
1725        newlen = g_stacknleft * 2;
1726        if (newlen < g_stacknleft)
1727                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1728        min = SHELL_ALIGN(min | 128);
1729        if (newlen < min)
1730                newlen += min;
1731
1732        if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1733                struct stack_block *sp;
1734                struct stack_block *prevstackp;
1735                size_t grosslen;
1736
1737                INT_OFF;
1738                sp = g_stackp;
1739                prevstackp = sp->prev;
1740                grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1741                sp = ckrealloc(sp, grosslen);
1742                sp->prev = prevstackp;
1743                g_stackp = sp;
1744                g_stacknxt = sp->space;
1745                g_stacknleft = newlen;
1746                sstrend = sp->space + newlen;
1747                INT_ON;
1748        } else {
1749                char *oldspace = g_stacknxt;
1750                size_t oldlen = g_stacknleft;
1751                char *p = stalloc(newlen);
1752
1753                /* free the space we just allocated */
1754                g_stacknxt = memcpy(p, oldspace, oldlen);
1755                g_stacknleft += newlen;
1756        }
1757}
1758
1759/*
1760 * The following routines are somewhat easier to use than the above.
1761 * The user declares a variable of type STACKSTR, which may be declared
1762 * to be a register.  The macro STARTSTACKSTR initializes things.  Then
1763 * the user uses the macro STPUTC to add characters to the string.  In
1764 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1765 * grown as necessary.  When the user is done, she can just leave the
1766 * string there and refer to it using stackblock().  Or she can allocate
1767 * the space for it using grabstackstr().  If it is necessary to allow
1768 * someone else to use the stack temporarily and then continue to grow
1769 * the string, the user should use grabstack to allocate the space, and
1770 * then call ungrabstr(p) to return to the previous mode of operation.
1771 *
1772 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1773 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1774 * is space for at least one character.
1775 */
1776static void *
1777growstackstr(void)
1778{
1779        size_t len = stackblocksize();
1780        growstackblock(0);
1781        return (char *)stackblock() + len;
1782}
1783
1784static char *
1785growstackto(size_t len)
1786{
1787        if (stackblocksize() < len)
1788                growstackblock(len);
1789        return stackblock();
1790}
1791
1792/*
1793 * Called from CHECKSTRSPACE.
1794 */
1795static char *
1796makestrspace(size_t newlen, char *p)
1797{
1798        size_t len = p - g_stacknxt;
1799
1800        return growstackto(len + newlen) + len;
1801}
1802
1803static char *
1804stnputs(const char *s, size_t n, char *p)
1805{
1806        p = makestrspace(n, p);
1807        p = (char *)mempcpy(p, s, n);
1808        return p;
1809}
1810
1811static char *
1812stack_putstr(const char *s, char *p)
1813{
1814        return stnputs(s, strlen(s), p);
1815}
1816
1817static char *
1818_STPUTC(int c, char *p)
1819{
1820        if (p == sstrend)
1821                p = growstackstr();
1822        *p++ = c;
1823        return p;
1824}
1825
1826#define STARTSTACKSTR(p)        ((p) = stackblock())
1827#define STPUTC(c, p)            ((p) = _STPUTC((c), (p)))
1828#define CHECKSTRSPACE(n, p) do { \
1829        char *q = (p); \
1830        size_t l = (n); \
1831        size_t m = sstrend - q; \
1832        if (l > m) \
1833                (p) = makestrspace(l, q); \
1834} while (0)
1835#define USTPUTC(c, p)           (*(p)++ = (c))
1836#define STACKSTRNUL(p) do { \
1837        if ((p) == sstrend) \
1838                (p) = growstackstr(); \
1839        *(p) = '\0'; \
1840} while (0)
1841#define STUNPUTC(p)             (--(p))
1842#define STTOPC(p)               ((p)[-1])
1843#define STADJUST(amount, p)     ((p) += (amount))
1844
1845#define grabstackstr(p)         stalloc((char *)(p) - (char *)stackblock())
1846#define ungrabstackstr(s, p)    stunalloc(s)
1847#define stackstrend()           ((void *)sstrend)
1848
1849
1850/* ============ String helpers */
1851
1852/*
1853 * prefix -- see if pfx is a prefix of string.
1854 */
1855static char *
1856prefix(const char *string, const char *pfx)
1857{
1858        while (*pfx) {
1859                if (*pfx++ != *string++)
1860                        return NULL;
1861        }
1862        return (char *) string;
1863}
1864
1865/*
1866 * Check for a valid number.  This should be elsewhere.
1867 */
1868static int
1869is_number(const char *p)
1870{
1871        do {
1872                if (!isdigit(*p))
1873                        return 0;
1874        } while (*++p != '\0');
1875        return 1;
1876}
1877
1878/*
1879 * Convert a string of digits to an integer, printing an error message on
1880 * failure.
1881 */
1882static int
1883number(const char *s)
1884{
1885        if (!is_number(s))
1886                ash_msg_and_raise_error(msg_illnum, s);
1887        return atoi(s);
1888}
1889
1890/*
1891 * Produce a single quoted string suitable as input to the shell.
1892 * The return string is allocated on the stack.
1893 */
1894static char *
1895single_quote(const char *s)
1896{
1897        char *p;
1898
1899        STARTSTACKSTR(p);
1900
1901        do {
1902                char *q;
1903                size_t len;
1904
1905                len = strchrnul(s, '\'') - s;
1906
1907                q = p = makestrspace(len + 3, p);
1908
1909                *q++ = '\'';
1910                q = (char *)mempcpy(q, s, len);
1911                *q++ = '\'';
1912                s += len;
1913
1914                STADJUST(q - p, p);
1915
1916                if (*s != '\'')
1917                        break;
1918                len = 0;
1919                do len++; while (*++s == '\'');
1920
1921                q = p = makestrspace(len + 3, p);
1922
1923                *q++ = '"';
1924                q = (char *)mempcpy(q, s - len, len);
1925                *q++ = '"';
1926
1927                STADJUST(q - p, p);
1928        } while (*s);
1929
1930        USTPUTC('\0', p);
1931
1932        return stackblock();
1933}
1934
1935/*
1936 * Produce a possibly single quoted string suitable as input to the shell.
1937 * If quoting was done, the return string is allocated on the stack,
1938 * otherwise a pointer to the original string is returned.
1939 */
1940static const char *
1941maybe_single_quote(const char *s)
1942{
1943        const char *p = s;
1944
1945        while (*p) {
1946                /* Assuming ACSII */
1947                /* quote ctrl_chars space !"#$%&'()* */
1948                if (*p < '+')
1949                        goto need_quoting;
1950                /* quote ;<=>? */
1951                if (*p >= ';' && *p <= '?')
1952                        goto need_quoting;
1953                /* quote `[\ */
1954                if (*p == '`')
1955                        goto need_quoting;
1956                if (*p == '[')
1957                        goto need_quoting;
1958                if (*p == '\\')
1959                        goto need_quoting;
1960                /* quote {|}~ DEL and high bytes */
1961                if (*p > 'z')
1962                        goto need_quoting;
1963                /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1964                /* TODO: maybe avoid quoting % */
1965                p++;
1966        }
1967        return s;
1968
1969 need_quoting:
1970        return single_quote(s);
1971}
1972
1973
1974/* ============ nextopt */
1975
1976static char **argptr;                  /* argument list for builtin commands */
1977static char *optionarg;                /* set by nextopt (like getopt) */
1978static char *optptr;                   /* used by nextopt */
1979
1980/*
1981 * XXX - should get rid of. Have all builtins use getopt(3).
1982 * The library getopt must have the BSD extension static variable
1983 * "optreset", otherwise it can't be used within the shell safely.
1984 *
1985 * Standard option processing (a la getopt) for builtin routines.
1986 * The only argument that is passed to nextopt is the option string;
1987 * the other arguments are unnecessary. It returns the character,
1988 * or '\0' on end of input.
1989 */
1990static int
1991nextopt(const char *optstring)
1992{
1993        char *p;
1994        const char *q;
1995        char c;
1996
1997        p = optptr;
1998        if (p == NULL || *p == '\0') {
1999                /* We ate entire "-param", take next one */
2000                p = *argptr;
2001                if (p == NULL)
2002                        return '\0';
2003                if (*p != '-')
2004                        return '\0';
2005                if (*++p == '\0') /* just "-" ? */
2006                        return '\0';
2007                argptr++;
2008                if (LONE_DASH(p)) /* "--" ? */
2009                        return '\0';
2010                /* p => next "-param" */
2011        }
2012        /* p => some option char in the middle of a "-param" */
2013        c = *p++;
2014        for (q = optstring; *q != c;) {
2015                if (*q == '\0')
2016                        ash_msg_and_raise_error("illegal option -%c", c);
2017                if (*++q == ':')
2018                        q++;
2019        }
2020        if (*++q == ':') {
2021                if (*p == '\0') {
2022                        p = *argptr++;
2023                        if (p == NULL)
2024                                ash_msg_and_raise_error("no arg for -%c option", c);
2025                }
2026                optionarg = p;
2027                p = NULL;
2028        }
2029        optptr = p;
2030        return c;
2031}
2032
2033
2034/* ============ Shell variables */
2035
2036struct shparam {
2037        int nparam;             /* # of positional parameters (without $0) */
2038#if ENABLE_ASH_GETOPTS
2039        int optind;             /* next parameter to be processed by getopts */
2040        int optoff;             /* used by getopts */
2041#endif
2042        unsigned char malloced; /* if parameter list dynamically allocated */
2043        char **p;               /* parameter list */
2044};
2045
2046/*
2047 * Free the list of positional parameters.
2048 */
2049static void
2050freeparam(volatile struct shparam *param)
2051{
2052        if (param->malloced) {
2053                char **ap, **ap1;
2054                ap = ap1 = param->p;
2055                while (*ap)
2056                        free(*ap++);
2057                free(ap1);
2058        }
2059}
2060
2061#if ENABLE_ASH_GETOPTS
2062static void FAST_FUNC getoptsreset(const char *value);
2063#endif
2064
2065struct var {
2066        struct var *next;               /* next entry in hash list */
2067        int flags;                      /* flags are defined above */
2068        const char *var_text;           /* name=value */
2069        void (*var_func)(const char *) FAST_FUNC; /* function to be called when  */
2070                                        /* the variable gets set/unset */
2071};
2072
2073struct localvar {
2074        struct localvar *next;          /* next local variable in list */
2075        struct var *vp;                 /* the variable that was made local */
2076        int flags;                      /* saved flags */
2077        const char *text;               /* saved text */
2078};
2079
2080/* flags */
2081#define VEXPORT         0x01    /* variable is exported */
2082#define VREADONLY       0x02    /* variable cannot be modified */
2083#define VSTRFIXED       0x04    /* variable struct is statically allocated */
2084#define VTEXTFIXED      0x08    /* text is statically allocated */
2085#define VSTACK          0x10    /* text is allocated on the stack */
2086#define VUNSET          0x20    /* the variable is not set */
2087#define VNOFUNC         0x40    /* don't call the callback function */
2088#define VNOSET          0x80    /* do not set variable - just readonly test */
2089#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
2090#if ENABLE_ASH_RANDOM_SUPPORT
2091# define VDYNAMIC       0x200   /* dynamic variable */
2092#else
2093# define VDYNAMIC       0
2094#endif
2095
2096
2097/* Need to be before varinit_data[] */
2098#if ENABLE_LOCALE_SUPPORT
2099static void FAST_FUNC
2100change_lc_all(const char *value)
2101{
2102        if (value && *value != '\0')
2103                setlocale(LC_ALL, value);
2104}
2105static void FAST_FUNC
2106change_lc_ctype(const char *value)
2107{
2108        if (value && *value != '\0')
2109                setlocale(LC_CTYPE, value);
2110}
2111#endif
2112#if ENABLE_ASH_MAIL
2113static void chkmail(void);
2114static void changemail(const char *var_value) FAST_FUNC;
2115#else
2116# define chkmail()  ((void)0)
2117#endif
2118static void changepath(const char *) FAST_FUNC;
2119#if ENABLE_ASH_RANDOM_SUPPORT
2120static void change_random(const char *) FAST_FUNC;
2121#endif
2122#if BASH_EPOCH_VARS
2123static void change_seconds(const char *) FAST_FUNC;
2124static void change_realtime(const char *) FAST_FUNC;
2125#endif
2126
2127static const struct {
2128        int flags;
2129        const char *var_text;
2130        void (*var_func)(const char *) FAST_FUNC;
2131} varinit_data[] ALIGN_PTR = {
2132        /*
2133         * Note: VEXPORT would not work correctly here for NOFORK applets:
2134         * some environment strings may be constant.
2135         */
2136        { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
2137#if ENABLE_ASH_MAIL
2138        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL"      , changemail      },
2139        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH"  , changemail      },
2140#endif
2141        { VSTRFIXED|VTEXTFIXED       , bb_PATH_root_path, changepath },
2142        { VSTRFIXED|VTEXTFIXED       , "PS1=$ "    , NULL            },
2143        { VSTRFIXED|VTEXTFIXED       , "PS2=> "    , NULL            },
2144        { VSTRFIXED|VTEXTFIXED       , "PS4=+ "    , NULL            },
2145#if ENABLE_ASH_GETOPTS
2146        { VSTRFIXED|VTEXTFIXED       , defoptindvar, getoptsreset    },
2147#endif
2148        { VSTRFIXED|VTEXTFIXED       , NULL /* inited to linenovar */, NULL },
2149        { VSTRFIXED|VTEXTFIXED       , NULL /* inited to funcnamevar */, NULL },
2150#if ENABLE_ASH_RANDOM_SUPPORT
2151        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2152#endif
2153#if BASH_EPOCH_VARS
2154        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHSECONDS", change_seconds },
2155        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHREALTIME", change_realtime },
2156#endif
2157#if ENABLE_LOCALE_SUPPORT
2158        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL"    , change_lc_all   },
2159        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE"  , change_lc_ctype },
2160#endif
2161#if ENABLE_FEATURE_EDITING_SAVEHISTORY
2162        { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE"  , NULL            },
2163#endif
2164};
2165
2166struct redirtab;
2167
2168struct globals_var {
2169        struct shparam shellparam;      /* $@ current positional parameters */
2170        struct redirtab *redirlist;
2171        int preverrout_fd;   /* stderr fd: usually 2, unless redirect moved it */
2172        struct var *vartab[VTABSIZE];
2173        struct var varinit[ARRAY_SIZE(varinit_data)];
2174        int lineno;
2175        char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2176        char funcnamevar[sizeof("FUNCNAME=") + 64];
2177        char *funcname;
2178        unsigned trap_depth;
2179        bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */
2180};
2181extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2182#define G_var (*ash_ptr_to_globals_var)
2183#define shellparam    (G_var.shellparam   )
2184//#define redirlist     (G_var.redirlist    )
2185#define preverrout_fd (G_var.preverrout_fd)
2186#define vartab        (G_var.vartab       )
2187#define varinit       (G_var.varinit      )
2188#define lineno        (G_var.lineno       )
2189#define linenovar     (G_var.linenovar    )
2190#define funcnamevar   (G_var.funcnamevar  )
2191#define funcname      (G_var.funcname     )
2192#define trap_depth    (G_var.trap_depth   )
2193#define in_trap_ERR   (G_var.in_trap_ERR  )
2194#define vifs      varinit[0]
2195#if ENABLE_ASH_MAIL
2196# define vmail    varinit[1]
2197# define vmpath   varinit[2]
2198#endif
2199#define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
2200#define vpath     varinit[VAR_OFFSET1 + 1]
2201#define vps1      varinit[VAR_OFFSET1 + 2]
2202#define vps2      varinit[VAR_OFFSET1 + 3]
2203#define vps4      varinit[VAR_OFFSET1 + 4]
2204#if ENABLE_ASH_GETOPTS
2205# define voptind  varinit[VAR_OFFSET1 + 5]
2206#endif
2207#define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
2208#define vlineno   varinit[VAR_OFFSET2 + 5]
2209#define vfuncname varinit[VAR_OFFSET2 + 6]
2210#if ENABLE_ASH_RANDOM_SUPPORT
2211# define vrandom  varinit[VAR_OFFSET2 + 7]
2212#endif
2213#define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
2214#if BASH_EPOCH_VARS
2215# define vepochs  varinit[VAR_OFFSET3 + 7]
2216# define vepochr  varinit[VAR_OFFSET3 + 8]
2217#endif
2218#define INIT_G_var() do { \
2219        unsigned i; \
2220        XZALLOC_CONST_PTR(&ash_ptr_to_globals_var, sizeof(G_var)); \
2221        for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2222                varinit[i].flags    = varinit_data[i].flags; \
2223                varinit[i].var_text = varinit_data[i].var_text; \
2224                varinit[i].var_func = varinit_data[i].var_func; \
2225        } \
2226        strcpy(linenovar, "LINENO="); \
2227        vlineno.var_text = linenovar; \
2228        strcpy(funcnamevar, "FUNCNAME="); \
2229        vfuncname.var_text = funcnamevar; \
2230} while (0)
2231
2232/*
2233 * The following macros access the values of the above variables.
2234 * They have to skip over the name.  They return the null string
2235 * for unset variables.
2236 */
2237#define ifsval()        (vifs.var_text + 4)
2238#define ifsset()        ((vifs.flags & VUNSET) == 0)
2239#if ENABLE_ASH_MAIL
2240# define mailval()      (vmail.var_text + 5)
2241# define mpathval()     (vmpath.var_text + 9)
2242# define mpathset()     ((vmpath.flags & VUNSET) == 0)
2243#endif
2244#define pathval()       (vpath.var_text + 5)
2245#define ps1val()        (vps1.var_text + 4)
2246#define ps2val()        (vps2.var_text + 4)
2247#define ps4val()        (vps4.var_text + 4)
2248#if ENABLE_ASH_GETOPTS
2249# define optindval()    (voptind.var_text + 7)
2250#endif
2251
2252#if ENABLE_ASH_GETOPTS
2253static void FAST_FUNC
2254getoptsreset(const char *value)
2255{
2256        shellparam.optind = 1;
2257        if (is_number(value))
2258                shellparam.optind = number(value) ?: 1;
2259        shellparam.optoff = -1;
2260}
2261#endif
2262
2263/*
2264 * Compares two strings up to the first = or '\0'.  The first
2265 * string must be terminated by '='; the second may be terminated by
2266 * either '=' or '\0'.
2267 */
2268static int
2269varcmp(const char *p, const char *q)
2270{
2271        int c, d;
2272
2273        while ((c = *p) == (d = *q)) {
2274                if (c == '\0' || c == '=')
2275                        goto out;
2276                p++;
2277                q++;
2278        }
2279        if (c == '=')
2280                c = '\0';
2281        if (d == '=')
2282                d = '\0';
2283 out:
2284        return c - d;
2285}
2286
2287/*
2288 * Find the appropriate entry in the hash table from the name.
2289 */
2290static struct var **
2291hashvar(const char *p)
2292{
2293        unsigned hashval;
2294
2295        hashval = ((unsigned char) *p) << 4;
2296        while (*p && *p != '=')
2297                hashval += (unsigned char) *p++;
2298        return &vartab[hashval % VTABSIZE];
2299}
2300
2301static int
2302vpcmp(const void *a, const void *b)
2303{
2304        return varcmp(*(const char **)a, *(const char **)b);
2305}
2306
2307/*
2308 * This routine initializes the builtin variables.
2309 */
2310static void
2311initvar(void)
2312{
2313        struct var *vp;
2314        struct var *end;
2315        struct var **vpp;
2316
2317        /*
2318         * PS1 depends on uid
2319         */
2320#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2321        vps1.var_text = "PS1=\\w \\$ ";
2322#else
2323        if (!geteuid())
2324                vps1.var_text = "PS1=# ";
2325#endif
2326        vp = varinit;
2327        end = vp + ARRAY_SIZE(varinit);
2328        do {
2329                vpp = hashvar(vp->var_text);
2330                vp->next = *vpp;
2331                *vpp = vp;
2332        } while (++vp < end);
2333}
2334
2335static struct var **
2336findvar(struct var **vpp, const char *name)
2337{
2338        for (; *vpp; vpp = &(*vpp)->next) {
2339                if (varcmp((*vpp)->var_text, name) == 0) {
2340                        break;
2341                }
2342        }
2343        return vpp;
2344}
2345
2346/*
2347 * Find the value of a variable.  Returns NULL if not set.
2348 */
2349static const char* FAST_FUNC
2350lookupvar(const char *name)
2351{
2352        struct var *v;
2353
2354        v = *findvar(hashvar(name), name);
2355        if (v) {
2356#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2357        /*
2358         * Dynamic variables are implemented roughly the same way they are
2359         * in bash. Namely, they're "special" so long as they aren't unset.
2360         * As soon as they're unset, they're no longer dynamic, and dynamic
2361         * lookup will no longer happen at that point. -- PFM.
2362         */
2363                if (v->flags & VDYNAMIC)
2364                        v->var_func(NULL);
2365#endif
2366                if (!(v->flags & VUNSET)) {
2367                        if (v->var_text == linenovar) {
2368                                fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2369                        } else
2370                        if (v->var_text == funcnamevar) {
2371                                safe_strncpy(funcnamevar+9, funcname ? funcname : "", sizeof(funcnamevar)-9);
2372                        }
2373                        return var_end(v->var_text);
2374                }
2375        }
2376        return NULL;
2377}
2378
2379#if ENABLE_UNICODE_SUPPORT
2380static void
2381reinit_unicode_for_ash(void)
2382{
2383        /* Unicode support should be activated even if LANG is set
2384         * _during_ shell execution, not only if it was set when
2385         * shell was started. Therefore, re-check LANG every time:
2386         */
2387        if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2388         || ENABLE_UNICODE_USING_LOCALE
2389        ) {
2390                const char *s = lookupvar("LC_ALL");
2391                if (!s) s = lookupvar("LC_CTYPE");
2392                if (!s) s = lookupvar("LANG");
2393                reinit_unicode(s);
2394        }
2395}
2396#else
2397# define reinit_unicode_for_ash() ((void)0)
2398#endif
2399
2400/*
2401 * Search the environment of a builtin command.
2402 */
2403static ALWAYS_INLINE const char *
2404bltinlookup(const char *name)
2405{
2406        return lookupvar(name);
2407}
2408
2409/*
2410 * Same as setvar except that the variable and value are passed in
2411 * the first argument as name=value.  Since the first argument will
2412 * be actually stored in the table, it should not be a string that
2413 * will go away.
2414 * Called with interrupts off.
2415 */
2416static struct var *
2417setvareq(char *s, int flags)
2418{
2419        struct var *vp, **vpp;
2420
2421        vpp = hashvar(s);
2422        flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2423        vpp = findvar(vpp, s);
2424        vp = *vpp;
2425        if (vp) {
2426                if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2427                        const char *n;
2428
2429                        if (flags & VNOSAVE)
2430                                free(s);
2431                        n = vp->var_text;
2432                        exitstatus = 1;
2433                        ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2434                }
2435
2436                if (flags & VNOSET)
2437                        goto out;
2438
2439                if (vp->var_func && !(flags & VNOFUNC))
2440                        vp->var_func(var_end(s));
2441
2442                if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2443                        free((char*)vp->var_text);
2444
2445                if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2446                        *vpp = vp->next;
2447                        free(vp);
2448 out_free:
2449                        if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2450                                free(s);
2451                        goto out;
2452                }
2453
2454                flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2455#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2456                if (flags & VUNSET)
2457                        flags &= ~VDYNAMIC;
2458#endif
2459        } else {
2460                /* variable s is not found */
2461                if (flags & VNOSET)
2462                        goto out;
2463                if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2464                        goto out_free;
2465                vp = ckzalloc(sizeof(*vp));
2466                vp->next = *vpp;
2467                /*vp->func = NULL; - ckzalloc did it */
2468                *vpp = vp;
2469        }
2470        if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2471                s = ckstrdup(s);
2472        vp->var_text = s;
2473        vp->flags = flags;
2474
2475 out:
2476        return vp;
2477}
2478
2479/*
2480 * Set the value of a variable.  The flags argument is ored with the
2481 * flags of the variable.  If val is NULL, the variable is unset.
2482 */
2483static struct var *
2484setvar(const char *name, const char *val, int flags)
2485{
2486        const char *q;
2487        char *p;
2488        char *nameeq;
2489        size_t namelen;
2490        size_t vallen;
2491        struct var *vp;
2492
2493        q = endofname(name);
2494        p = strchrnul(q, '=');
2495        namelen = p - name;
2496        if (!namelen || p != q)
2497                ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2498        vallen = 0;
2499        if (val == NULL) {
2500                flags |= VUNSET;
2501        } else {
2502                vallen = strlen(val);
2503        }
2504
2505        INT_OFF;
2506        nameeq = ckzalloc(namelen + vallen + 2);
2507        p = mempcpy(nameeq, name, namelen);
2508        if (val) {
2509                *p++ = '=';
2510                memcpy(p, val, vallen);
2511        }
2512        vp = setvareq(nameeq, flags | VNOSAVE);
2513        INT_ON;
2514
2515        return vp;
2516}
2517
2518static void FAST_FUNC
2519setvar0(const char *name, const char *val)
2520{
2521        setvar(name, val, 0);
2522}
2523
2524/*
2525 * Unset the specified variable.
2526 */
2527static void
2528unsetvar(const char *s)
2529{
2530        setvar(s, NULL, 0);
2531}
2532
2533/*
2534 * Generate a list of variables satisfying the given conditions.
2535 */
2536#if !ENABLE_FEATURE_SH_NOFORK
2537# define listvars(on, off, lp, end) listvars(on, off, end)
2538#endif
2539static char **
2540listvars(int on, int off, struct strlist *lp, char ***end)
2541{
2542        struct var **vpp;
2543        struct var *vp;
2544        char **ep;
2545        int mask;
2546
2547        STARTSTACKSTR(ep);
2548        vpp = vartab;
2549        mask = on | off;
2550        do {
2551                for (vp = *vpp; vp; vp = vp->next) {
2552                        if ((vp->flags & mask) == on) {
2553#if ENABLE_FEATURE_SH_NOFORK
2554                                /* If variable with the same name is both
2555                                 * exported and temporarily set for a command:
2556                                 *  export ZVAR=5
2557                                 *  ZVAR=6 printenv
2558                                 * then "ZVAR=6" will be both in vartab and
2559                                 * lp lists. Do not pass it twice to printenv.
2560                                 */
2561                                struct strlist *lp1 = lp;
2562                                while (lp1) {
2563                                        if (strcmp(lp1->text, vp->var_text) == 0)
2564                                                goto skip;
2565                                        lp1 = lp1->next;
2566                                }
2567#endif
2568                                if (ep == stackstrend())
2569                                        ep = growstackstr();
2570                                *ep++ = (char*)vp->var_text;
2571#if ENABLE_FEATURE_SH_NOFORK
2572 skip: ;
2573#endif
2574                        }
2575                }
2576        } while (++vpp < vartab + VTABSIZE);
2577
2578#if ENABLE_FEATURE_SH_NOFORK
2579        while (lp) {
2580                if (ep == stackstrend())
2581                        ep = growstackstr();
2582                *ep++ = lp->text;
2583                lp = lp->next;
2584        }
2585#endif
2586
2587        if (ep == stackstrend())
2588                ep = growstackstr();
2589        if (end)
2590                *end = ep;
2591        *ep++ = NULL;
2592        return grabstackstr(ep);
2593}
2594
2595
2596/* ============ Path search helper */
2597static const char *
2598legal_pathopt(const char *opt, const char *term, int magic)
2599{
2600        switch (magic) {
2601        case 0:
2602                opt = NULL;
2603                break;
2604
2605        case 1:
2606                opt = prefix(opt, "builtin") ?: prefix(opt, "func");
2607                break;
2608
2609        default:
2610                opt += strcspn(opt, term);
2611                break;
2612        }
2613
2614        if (opt && *opt == '%')
2615                opt++;
2616
2617        return opt;
2618}
2619
2620/*
2621 * The variable path (passed by reference) should be set to the start
2622 * of the path before the first call; padvance will update
2623 * this value as it proceeds.  Successive calls to padvance will return
2624 * the possible path expansions in sequence.  If an option (indicated by
2625 * a percent sign) appears in the path entry then the global variable
2626 * pathopt will be set to point to it; otherwise pathopt will be set to
2627 * NULL.
2628 *
2629 * If magic is 0 then pathopt recognition will be disabled.  If magic is
2630 * 1 we shall recognise %builtin/%func.  Otherwise we shall accept any
2631 * pathopt.
2632 */
2633static const char *pathopt;     /* set by padvance */
2634
2635static int
2636padvance_magic(const char **path, const char *name, int magic)
2637{
2638        const char *term = "%:";
2639        const char *lpathopt;
2640        const char *p;
2641        char *q;
2642        const char *start;
2643        size_t qlen;
2644        size_t len;
2645
2646        if (*path == NULL)
2647                return -1;
2648
2649        lpathopt = NULL;
2650        start = *path;
2651
2652        if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) {
2653                lpathopt = start + 1;
2654                start = p;
2655                term = ":";
2656        }
2657
2658        len = strcspn(start, term);
2659        p = start + len;
2660
2661        if (*p == '%') {
2662                size_t extra = strchrnul(p, ':') - p;
2663
2664                if (legal_pathopt(p + 1, term, magic))
2665                        lpathopt = p + 1;
2666                else
2667                        len += extra;
2668
2669                p += extra;
2670        }
2671
2672        pathopt = lpathopt;
2673        *path = *p == ':' ? p + 1 : NULL;
2674
2675        /* "2" is for '/' and '\0' */
2676        qlen = len + strlen(name) + 2;
2677        q = growstackto(qlen);
2678
2679        if (len) {
2680                q = mempcpy(q, start, len);
2681                *q++ = '/';
2682        }
2683        strcpy(q, name);
2684
2685        return qlen;
2686}
2687
2688static int
2689padvance(const char **path, const char *name)
2690{
2691        return padvance_magic(path, name, 1);
2692}
2693
2694
2695/* ============ Prompt */
2696
2697static smallint doprompt;                   /* if set, prompt the user */
2698static smallint needprompt;                 /* true if interactive and at start of line */
2699
2700#if ENABLE_FEATURE_EDITING
2701static line_input_t *line_input_state;
2702static const char *cmdedit_prompt;
2703static void
2704putprompt(const char *s)
2705{
2706        if (ENABLE_ASH_EXPAND_PRMT) {
2707                free((char*)cmdedit_prompt);
2708                cmdedit_prompt = ckstrdup(s);
2709                return;
2710        }
2711        cmdedit_prompt = s;
2712}
2713#else
2714static void
2715putprompt(const char *s)
2716{
2717        out2str(s);
2718}
2719#endif
2720
2721/* expandstr() needs parsing machinery, so it is far away ahead... */
2722static const char *expandstr(const char *ps, int syntax_type);
2723/* Values for syntax param */
2724#define BASESYNTAX 0    /* not in quotes */
2725#define DQSYNTAX   1    /* in double quotes */
2726#define SQSYNTAX   2    /* in single quotes */
2727#define ARISYNTAX  3    /* in arithmetic */
2728#if ENABLE_ASH_EXPAND_PRMT
2729# define PSSYNTAX  4    /* prompt. never passed to SIT() */
2730#endif
2731/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
2732
2733/*
2734 * called by editline -- any expansions to the prompt should be added here.
2735 */
2736static void
2737setprompt_if(smallint do_set, int whichprompt)
2738{
2739        const char *prompt;
2740        IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2741
2742        if (!do_set)
2743                return;
2744
2745        needprompt = 0;
2746
2747        switch (whichprompt) {
2748        case 1:
2749                prompt = ps1val();
2750                break;
2751        case 2:
2752                prompt = ps2val();
2753                break;
2754        default:                        /* 0 */
2755                prompt = nullstr;
2756        }
2757#if ENABLE_ASH_EXPAND_PRMT
2758        pushstackmark(&smark, stackblocksize());
2759        putprompt(expandstr(prompt, PSSYNTAX));
2760        popstackmark(&smark);
2761#else
2762        putprompt(prompt);
2763#endif
2764}
2765
2766
2767/* ============ The cd and pwd commands */
2768
2769#define CD_PHYSICAL 1
2770#define CD_PRINT 2
2771
2772static int
2773cdopt(void)
2774{
2775        int flags = 0;
2776        int i, j;
2777
2778        j = 'L';
2779        while ((i = nextopt("LP")) != '\0') {
2780                if (i != j) {
2781                        flags ^= CD_PHYSICAL;
2782                        j = i;
2783                }
2784        }
2785
2786        return flags;
2787}
2788
2789/*
2790 * Update curdir (the name of the current directory) in response to a
2791 * cd command.
2792 */
2793static const char *
2794updatepwd(const char *dir)
2795{
2796        char *new;
2797        char *p;
2798        char *cdcomppath;
2799        const char *lim;
2800
2801        cdcomppath = sstrdup(dir);
2802        STARTSTACKSTR(new);
2803        if (*dir != '/') {
2804                if (curdir == nullstr)
2805                        return 0;
2806                new = stack_putstr(curdir, new);
2807        }
2808        new = makestrspace(strlen(dir) + 2, new);
2809        lim = (char *)stackblock() + 1;
2810        if (*dir != '/') {
2811                if (new[-1] != '/')
2812                        USTPUTC('/', new);
2813                if (new > lim && *lim == '/')
2814                        lim++;
2815        } else {
2816                USTPUTC('/', new);
2817                cdcomppath++;
2818                if (dir[1] == '/' && dir[2] != '/') {
2819                        USTPUTC('/', new);
2820                        cdcomppath++;
2821                        lim++;
2822                }
2823        }
2824        p = strtok_r(cdcomppath, "/", &cdcomppath);
2825        while (p) {
2826                switch (*p) {
2827                case '.':
2828                        if (p[1] == '.' && p[2] == '\0') {
2829                                while (new > lim) {
2830                                        STUNPUTC(new);
2831                                        if (new[-1] == '/')
2832                                                break;
2833                                }
2834                                break;
2835                        }
2836                        if (p[1] == '\0')
2837                                break;
2838                        /* fall through */
2839                default:
2840                        new = stack_putstr(p, new);
2841                        USTPUTC('/', new);
2842                }
2843                p = strtok_r(NULL, "/", &cdcomppath);
2844        }
2845        if (new > lim)
2846                STUNPUTC(new);
2847        *new = 0;
2848        return stackblock();
2849}
2850
2851/*
2852 * Find out what the current directory is. If we already know the current
2853 * directory, this routine returns immediately.
2854 */
2855static char *
2856getpwd(void)
2857{
2858        char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2859        return dir ? dir : nullstr;
2860}
2861
2862static void
2863setpwd(const char *val, int setold)
2864{
2865        char *oldcur, *dir;
2866
2867        oldcur = dir = curdir;
2868
2869        if (setold) {
2870                setvar("OLDPWD", oldcur, VEXPORT);
2871        }
2872        INT_OFF;
2873        if (physdir != nullstr) {
2874                if (physdir != oldcur)
2875                        free(physdir);
2876                physdir = nullstr;
2877        }
2878        if (oldcur == val || !val) {
2879                char *s = getpwd();
2880                physdir = s;
2881                if (!val)
2882                        dir = s;
2883        } else
2884                dir = ckstrdup(val);
2885        if (oldcur != dir && oldcur != nullstr) {
2886                free(oldcur);
2887        }
2888        curdir = dir;
2889        INT_ON;
2890        setvar("PWD", dir, VEXPORT);
2891}
2892
2893static void hashcd(void);
2894
2895/*
2896 * Actually do the chdir.  We also call hashcd to let other routines
2897 * know that the current directory has changed.
2898 */
2899static int
2900docd(const char *dest, int flags)
2901{
2902        const char *dir = NULL;
2903        int err;
2904
2905        TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2906
2907        INT_OFF;
2908        if (!(flags & CD_PHYSICAL)) {
2909                dir = updatepwd(dest);
2910                if (dir)
2911                        dest = dir;
2912        }
2913        err = chdir(dest);
2914        if (err)
2915                goto out;
2916        setpwd(dir, 1);
2917        hashcd();
2918 out:
2919        INT_ON;
2920        return err;
2921}
2922
2923static int FAST_FUNC
2924cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2925{
2926        const char *dest;
2927        const char *path;
2928        const char *p;
2929        char c;
2930        struct stat statb;
2931        int flags;
2932        int len;
2933
2934        flags = cdopt();
2935        dest = *argptr;
2936        if (!dest)
2937                dest = bltinlookup("HOME");
2938        else if (LONE_DASH(dest)) {
2939                dest = bltinlookup("OLDPWD");
2940                flags |= CD_PRINT;
2941        }
2942        if (!dest)
2943                dest = nullstr;
2944        if (*dest == '/')
2945                goto step6;
2946        if (*dest == '.') {
2947                c = dest[1];
2948 dotdot:
2949                switch (c) {
2950                case '\0':
2951                case '/':
2952                        goto step6;
2953                case '.':
2954                        c = dest[2];
2955                        if (c != '.')
2956                                goto dotdot;
2957                }
2958        }
2959        if (!*dest)
2960                dest = ".";
2961        path = bltinlookup("CDPATH");
2962        while (p = path, (len = padvance(&path, dest)) >= 0) {
2963                c = *p;
2964                p = stalloc(len);
2965
2966                if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2967                        if (c && c != ':')
2968                                flags |= CD_PRINT;
2969 docd:
2970                        if (!docd(p, flags))
2971                                goto out;
2972                        goto err;
2973                }
2974        }
2975
2976 step6:
2977        p = dest;
2978        goto docd;
2979
2980 err:
2981        ash_msg_and_raise_perror("can't cd to %s", dest);
2982        /* NOTREACHED */
2983 out:
2984        if (flags & CD_PRINT)
2985                out1fmt("%s\n", curdir);
2986        return 0;
2987}
2988
2989static int FAST_FUNC
2990pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2991{
2992        int flags;
2993        const char *dir = curdir;
2994
2995        flags = cdopt();
2996        if (flags) {
2997                if (physdir == nullstr)
2998                        setpwd(dir, 0);
2999                dir = physdir;
3000        }
3001        out1fmt("%s\n", dir);
3002        return 0;
3003}
3004
3005
3006/* ============ ... */
3007
3008
3009#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
3010
3011/* Syntax classes */
3012#define CWORD     0             /* character is nothing special */
3013#define CNL       1             /* newline character */
3014#define CBACK     2             /* a backslash character */
3015#define CSQUOTE   3             /* single quote */
3016#define CDQUOTE   4             /* double quote */
3017#define CENDQUOTE 5             /* a terminating quote */
3018#define CBQUOTE   6             /* backwards single quote */
3019#define CVAR      7             /* a dollar sign */
3020#define CENDVAR   8             /* a '}' character */
3021#define CLP       9             /* a left paren in arithmetic */
3022#define CRP      10             /* a right paren in arithmetic */
3023#define CENDFILE 11             /* end of file */
3024#define CCTL     12             /* like CWORD, except it must be escaped */
3025#define CSPCL    13             /* these terminate a word */
3026
3027#define PEOF     256
3028
3029#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
3030
3031#if ENABLE_FEATURE_SH_MATH
3032# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
3033#else
3034# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
3035#endif
3036static const uint16_t S_I_T[] ALIGN2 = {
3037        SIT_ITEM(CSPCL   , CWORD    , CWORD, CWORD  ),    /* 0, ' ' */
3038        SIT_ITEM(CNL     , CNL      , CNL  , CNL    ),    /* 1, \n */
3039        SIT_ITEM(CWORD   , CCTL     , CCTL , CWORD  ),    /* 2, !*-/:=?[]~ */
3040        SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD  ),    /* 3, '"' */
3041        SIT_ITEM(CVAR    , CVAR     , CWORD, CVAR   ),    /* 4, $ */
3042        SIT_ITEM(CSQUOTE , CWORD    , CENDQUOTE, CWORD),  /* 5, "'" */
3043        SIT_ITEM(CSPCL   , CWORD    , CWORD, CLP    ),    /* 6, ( */
3044        SIT_ITEM(CSPCL   , CWORD    , CWORD, CRP    ),    /* 7, ) */
3045        SIT_ITEM(CBACK   , CBACK    , CCTL , CBACK  ),    /* 8, \ */
3046        SIT_ITEM(CBQUOTE , CBQUOTE  , CWORD, CBQUOTE),    /* 9, ` */
3047        SIT_ITEM(CENDVAR , CENDVAR  , CWORD, CENDVAR),    /* 10, } */
3048#if !USE_SIT_FUNCTION
3049        SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 11, PEOF */
3050        SIT_ITEM(CWORD   , CWORD    , CWORD, CWORD  ),    /* 12, 0-9A-Za-z */
3051        SIT_ITEM(CCTL    , CCTL     , CCTL , CCTL   )     /* 13, CTLESC ... */
3052#endif
3053#undef SIT_ITEM
3054};
3055/* Constants below must match table above */
3056enum {
3057        CSPCL_CWORD_CWORD_CWORD            , /*  0 */
3058        CNL_CNL_CNL_CNL                    , /*  1 */
3059        CWORD_CCTL_CCTL_CWORD              , /*  2 */
3060        CDQUOTE_CENDQUOTE_CWORD_CWORD      , /*  3 */
3061        CVAR_CVAR_CWORD_CVAR               , /*  4 */
3062        CSQUOTE_CWORD_CENDQUOTE_CWORD      , /*  5 */
3063        CSPCL_CWORD_CWORD_CLP              , /*  6 */
3064        CSPCL_CWORD_CWORD_CRP              , /*  7 */
3065        CBACK_CBACK_CCTL_CBACK             , /*  8 */
3066        CBQUOTE_CBQUOTE_CWORD_CBQUOTE      , /*  9 */
3067        CENDVAR_CENDVAR_CWORD_CENDVAR      , /* 10 */
3068        CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 11 */
3069        CWORD_CWORD_CWORD_CWORD            , /* 12 */
3070        CCTL_CCTL_CCTL_CCTL                , /* 13 */
3071};
3072
3073/* c in SIT(c, syntax) must be an *unsigned char* or PEOF,
3074 * caller must ensure proper cast on it if c is *char_ptr!
3075 */
3076#if USE_SIT_FUNCTION
3077
3078static int
3079SIT(int c, int syntax)
3080{
3081        /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
3082        static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
3083        /*
3084         * This causes '/' to be prepended with CTLESC in dquoted string,
3085         * making "./file"* treated incorrectly because we feed
3086         * ".\/file*" string to glob(), confusing it (see expandmeta func).
3087         * The "homegrown" glob implementation is okay with that,
3088         * but glibc one isn't. With '/' always treated as CWORD,
3089         * both work fine.
3090         */
3091        static const uint8_t syntax_index_table[] ALIGN1 = {
3092                0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
3093                6, 7, 2, 2,/*2,*/2, 0, 0,       /* "()*-/:;<" */
3094                2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
3095                10, 2                           /* "}~" */
3096        };
3097        const char *s;
3098        int indx;
3099
3100        if (c == PEOF)
3101                return CENDFILE;
3102        /* Cast is purely for paranoia here,
3103         * just in case someone passed signed char to us */
3104        if ((unsigned char)c >= CTL_FIRST
3105         && (unsigned char)c <= CTL_LAST
3106        ) {
3107                return CCTL;
3108        }
3109        s = strchrnul(spec_symbls, c);
3110        if (*s == '\0')
3111                return CWORD;
3112        indx = syntax_index_table[s - spec_symbls];
3113        return (S_I_T[indx] >> (syntax*4)) & 0xf;
3114}
3115
3116#else   /* !USE_SIT_FUNCTION */
3117
3118static const uint8_t syntax_index_table[] ALIGN1 = {
3119        /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
3120        /*   0      */ CWORD_CWORD_CWORD_CWORD,
3121        /*   1      */ CWORD_CWORD_CWORD_CWORD,
3122        /*   2      */ CWORD_CWORD_CWORD_CWORD,
3123        /*   3      */ CWORD_CWORD_CWORD_CWORD,
3124        /*   4      */ CWORD_CWORD_CWORD_CWORD,
3125        /*   5      */ CWORD_CWORD_CWORD_CWORD,
3126        /*   6      */ CWORD_CWORD_CWORD_CWORD,
3127        /*   7      */ CWORD_CWORD_CWORD_CWORD,
3128        /*   8      */ CWORD_CWORD_CWORD_CWORD,
3129        /*   9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3130        /*  10 "\n" */ CNL_CNL_CNL_CNL,
3131        /*  11      */ CWORD_CWORD_CWORD_CWORD,
3132        /*  12      */ CWORD_CWORD_CWORD_CWORD,
3133        /*  13      */ CWORD_CWORD_CWORD_CWORD,
3134        /*  14      */ CWORD_CWORD_CWORD_CWORD,
3135        /*  15      */ CWORD_CWORD_CWORD_CWORD,
3136        /*  16      */ CWORD_CWORD_CWORD_CWORD,
3137        /*  17      */ CWORD_CWORD_CWORD_CWORD,
3138        /*  18      */ CWORD_CWORD_CWORD_CWORD,
3139        /*  19      */ CWORD_CWORD_CWORD_CWORD,
3140        /*  20      */ CWORD_CWORD_CWORD_CWORD,
3141        /*  21      */ CWORD_CWORD_CWORD_CWORD,
3142        /*  22      */ CWORD_CWORD_CWORD_CWORD,
3143        /*  23      */ CWORD_CWORD_CWORD_CWORD,
3144        /*  24      */ CWORD_CWORD_CWORD_CWORD,
3145        /*  25      */ CWORD_CWORD_CWORD_CWORD,
3146        /*  26      */ CWORD_CWORD_CWORD_CWORD,
3147        /*  27      */ CWORD_CWORD_CWORD_CWORD,
3148        /*  28      */ CWORD_CWORD_CWORD_CWORD,
3149        /*  29      */ CWORD_CWORD_CWORD_CWORD,
3150        /*  30      */ CWORD_CWORD_CWORD_CWORD,
3151        /*  31      */ CWORD_CWORD_CWORD_CWORD,
3152        /*  32  " " */ CSPCL_CWORD_CWORD_CWORD,
3153        /*  33  "!" */ CWORD_CCTL_CCTL_CWORD,
3154        /*  34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3155        /*  35  "#" */ CWORD_CWORD_CWORD_CWORD,
3156        /*  36  "$" */ CVAR_CVAR_CWORD_CVAR,
3157        /*  37  "%" */ CWORD_CWORD_CWORD_CWORD,
3158        /*  38  "&" */ CSPCL_CWORD_CWORD_CWORD,
3159        /*  39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3160        /*  40  "(" */ CSPCL_CWORD_CWORD_CLP,
3161        /*  41  ")" */ CSPCL_CWORD_CWORD_CRP,
3162        /*  42  "*" */ CWORD_CCTL_CCTL_CWORD,
3163        /*  43  "+" */ CWORD_CWORD_CWORD_CWORD,
3164        /*  44  "," */ CWORD_CWORD_CWORD_CWORD,
3165        /*  45  "-" */ CWORD_CCTL_CCTL_CWORD,
3166        /*  46  "." */ CWORD_CWORD_CWORD_CWORD,
3167/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3168        /*  47  "/" */ CWORD_CWORD_CWORD_CWORD,
3169        /*  48  "0" */ CWORD_CWORD_CWORD_CWORD,
3170        /*  49  "1" */ CWORD_CWORD_CWORD_CWORD,
3171        /*  50  "2" */ CWORD_CWORD_CWORD_CWORD,
3172        /*  51  "3" */ CWORD_CWORD_CWORD_CWORD,
3173        /*  52  "4" */ CWORD_CWORD_CWORD_CWORD,
3174        /*  53  "5" */ CWORD_CWORD_CWORD_CWORD,
3175        /*  54  "6" */ CWORD_CWORD_CWORD_CWORD,
3176        /*  55  "7" */ CWORD_CWORD_CWORD_CWORD,
3177        /*  56  "8" */ CWORD_CWORD_CWORD_CWORD,
3178        /*  57  "9" */ CWORD_CWORD_CWORD_CWORD,
3179        /*  58  ":" */ CWORD_CCTL_CCTL_CWORD,
3180        /*  59  ";" */ CSPCL_CWORD_CWORD_CWORD,
3181        /*  60  "<" */ CSPCL_CWORD_CWORD_CWORD,
3182        /*  61  "=" */ CWORD_CCTL_CCTL_CWORD,
3183        /*  62  ">" */ CSPCL_CWORD_CWORD_CWORD,
3184        /*  63  "?" */ CWORD_CCTL_CCTL_CWORD,
3185        /*  64  "@" */ CWORD_CWORD_CWORD_CWORD,
3186        /*  65  "A" */ CWORD_CWORD_CWORD_CWORD,
3187        /*  66  "B" */ CWORD_CWORD_CWORD_CWORD,
3188        /*  67  "C" */ CWORD_CWORD_CWORD_CWORD,
3189        /*  68  "D" */ CWORD_CWORD_CWORD_CWORD,
3190        /*  69  "E" */ CWORD_CWORD_CWORD_CWORD,
3191        /*  70  "F" */ CWORD_CWORD_CWORD_CWORD,
3192        /*  71  "G" */ CWORD_CWORD_CWORD_CWORD,
3193        /*  72  "H" */ CWORD_CWORD_CWORD_CWORD,
3194        /*  73  "I" */ CWORD_CWORD_CWORD_CWORD,
3195        /*  74  "J" */ CWORD_CWORD_CWORD_CWORD,
3196        /*  75  "K" */ CWORD_CWORD_CWORD_CWORD,
3197        /*  76  "L" */ CWORD_CWORD_CWORD_CWORD,
3198        /*  77  "M" */ CWORD_CWORD_CWORD_CWORD,
3199        /*  78  "N" */ CWORD_CWORD_CWORD_CWORD,
3200        /*  79  "O" */ CWORD_CWORD_CWORD_CWORD,
3201        /*  80  "P" */ CWORD_CWORD_CWORD_CWORD,
3202        /*  81  "Q" */ CWORD_CWORD_CWORD_CWORD,
3203        /*  82  "R" */ CWORD_CWORD_CWORD_CWORD,
3204        /*  83  "S" */ CWORD_CWORD_CWORD_CWORD,
3205        /*  84  "T" */ CWORD_CWORD_CWORD_CWORD,
3206        /*  85  "U" */ CWORD_CWORD_CWORD_CWORD,
3207        /*  86  "V" */ CWORD_CWORD_CWORD_CWORD,
3208        /*  87  "W" */ CWORD_CWORD_CWORD_CWORD,
3209        /*  88  "X" */ CWORD_CWORD_CWORD_CWORD,
3210        /*  89  "Y" */ CWORD_CWORD_CWORD_CWORD,
3211        /*  90  "Z" */ CWORD_CWORD_CWORD_CWORD,
3212        /*  91  "[" */ CWORD_CCTL_CCTL_CWORD,
3213        /*  92  "\" */ CBACK_CBACK_CCTL_CBACK,
3214        /*  93  "]" */ CWORD_CCTL_CCTL_CWORD,
3215        /*  94  "^" */ CWORD_CWORD_CWORD_CWORD,
3216        /*  95  "_" */ CWORD_CWORD_CWORD_CWORD,
3217        /*  96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3218        /*  97  "a" */ CWORD_CWORD_CWORD_CWORD,
3219        /*  98  "b" */ CWORD_CWORD_CWORD_CWORD,
3220        /*  99  "c" */ CWORD_CWORD_CWORD_CWORD,
3221        /* 100  "d" */ CWORD_CWORD_CWORD_CWORD,
3222        /* 101  "e" */ CWORD_CWORD_CWORD_CWORD,
3223        /* 102  "f" */ CWORD_CWORD_CWORD_CWORD,
3224        /* 103  "g" */ CWORD_CWORD_CWORD_CWORD,
3225        /* 104  "h" */ CWORD_CWORD_CWORD_CWORD,
3226        /* 105  "i" */ CWORD_CWORD_CWORD_CWORD,
3227        /* 106  "j" */ CWORD_CWORD_CWORD_CWORD,
3228        /* 107  "k" */ CWORD_CWORD_CWORD_CWORD,
3229        /* 108  "l" */ CWORD_CWORD_CWORD_CWORD,
3230        /* 109  "m" */ CWORD_CWORD_CWORD_CWORD,
3231        /* 110  "n" */ CWORD_CWORD_CWORD_CWORD,
3232        /* 111  "o" */ CWORD_CWORD_CWORD_CWORD,
3233        /* 112  "p" */ CWORD_CWORD_CWORD_CWORD,
3234        /* 113  "q" */ CWORD_CWORD_CWORD_CWORD,
3235        /* 114  "r" */ CWORD_CWORD_CWORD_CWORD,
3236        /* 115  "s" */ CWORD_CWORD_CWORD_CWORD,
3237        /* 116  "t" */ CWORD_CWORD_CWORD_CWORD,
3238        /* 117  "u" */ CWORD_CWORD_CWORD_CWORD,
3239        /* 118  "v" */ CWORD_CWORD_CWORD_CWORD,
3240        /* 119  "w" */ CWORD_CWORD_CWORD_CWORD,
3241        /* 120  "x" */ CWORD_CWORD_CWORD_CWORD,
3242        /* 121  "y" */ CWORD_CWORD_CWORD_CWORD,
3243        /* 122  "z" */ CWORD_CWORD_CWORD_CWORD,
3244        /* 123  "{" */ CWORD_CWORD_CWORD_CWORD,
3245        /* 124  "|" */ CSPCL_CWORD_CWORD_CWORD,
3246        /* 125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3247        /* 126  "~" */ CWORD_CCTL_CCTL_CWORD,
3248        /* 127  del */ CWORD_CWORD_CWORD_CWORD,
3249        /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3250        /* 129 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
3251        /* 130 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
3252        /* 131 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
3253        /* 132 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
3254        /* 133 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
3255        /* 134 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
3256        /* 135 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
3257        /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3258#if BASH_PROCESS_SUBST
3259        /* 137 CTLTOPROC    */ CCTL_CCTL_CCTL_CCTL,
3260        /* 138 CTLFROMPROC  */ CCTL_CCTL_CCTL_CCTL,
3261#else
3262        /* 137      */ CWORD_CWORD_CWORD_CWORD,
3263        /* 138      */ CWORD_CWORD_CWORD_CWORD,
3264#endif
3265        /* 139      */ CWORD_CWORD_CWORD_CWORD,
3266        /* 140      */ CWORD_CWORD_CWORD_CWORD,
3267        /* 141      */ CWORD_CWORD_CWORD_CWORD,
3268        /* 142      */ CWORD_CWORD_CWORD_CWORD,
3269        /* 143      */ CWORD_CWORD_CWORD_CWORD,
3270        /* 144      */ CWORD_CWORD_CWORD_CWORD,
3271        /* 145      */ CWORD_CWORD_CWORD_CWORD,
3272        /* 146      */ CWORD_CWORD_CWORD_CWORD,
3273        /* 147      */ CWORD_CWORD_CWORD_CWORD,
3274        /* 148      */ CWORD_CWORD_CWORD_CWORD,
3275        /* 149      */ CWORD_CWORD_CWORD_CWORD,
3276        /* 150      */ CWORD_CWORD_CWORD_CWORD,
3277        /* 151      */ CWORD_CWORD_CWORD_CWORD,
3278        /* 152      */ CWORD_CWORD_CWORD_CWORD,
3279        /* 153      */ CWORD_CWORD_CWORD_CWORD,
3280        /* 154      */ CWORD_CWORD_CWORD_CWORD,
3281        /* 155      */ CWORD_CWORD_CWORD_CWORD,
3282        /* 156      */ CWORD_CWORD_CWORD_CWORD,
3283        /* 157      */ CWORD_CWORD_CWORD_CWORD,
3284        /* 158      */ CWORD_CWORD_CWORD_CWORD,
3285        /* 159      */ CWORD_CWORD_CWORD_CWORD,
3286        /* 160      */ CWORD_CWORD_CWORD_CWORD,
3287        /* 161      */ CWORD_CWORD_CWORD_CWORD,
3288        /* 162      */ CWORD_CWORD_CWORD_CWORD,
3289        /* 163      */ CWORD_CWORD_CWORD_CWORD,
3290        /* 164      */ CWORD_CWORD_CWORD_CWORD,
3291        /* 165      */ CWORD_CWORD_CWORD_CWORD,
3292        /* 166      */ CWORD_CWORD_CWORD_CWORD,
3293        /* 167      */ CWORD_CWORD_CWORD_CWORD,
3294        /* 168      */ CWORD_CWORD_CWORD_CWORD,
3295        /* 169      */ CWORD_CWORD_CWORD_CWORD,
3296        /* 170      */ CWORD_CWORD_CWORD_CWORD,
3297        /* 171      */ CWORD_CWORD_CWORD_CWORD,
3298        /* 172      */ CWORD_CWORD_CWORD_CWORD,
3299        /* 173      */ CWORD_CWORD_CWORD_CWORD,
3300        /* 174      */ CWORD_CWORD_CWORD_CWORD,
3301        /* 175      */ CWORD_CWORD_CWORD_CWORD,
3302        /* 176      */ CWORD_CWORD_CWORD_CWORD,
3303        /* 177      */ CWORD_CWORD_CWORD_CWORD,
3304        /* 178      */ CWORD_CWORD_CWORD_CWORD,
3305        /* 179      */ CWORD_CWORD_CWORD_CWORD,
3306        /* 180      */ CWORD_CWORD_CWORD_CWORD,
3307        /* 181      */ CWORD_CWORD_CWORD_CWORD,
3308        /* 182      */ CWORD_CWORD_CWORD_CWORD,
3309        /* 183      */ CWORD_CWORD_CWORD_CWORD,
3310        /* 184      */ CWORD_CWORD_CWORD_CWORD,
3311        /* 185      */ CWORD_CWORD_CWORD_CWORD,
3312        /* 186      */ CWORD_CWORD_CWORD_CWORD,
3313        /* 187      */ CWORD_CWORD_CWORD_CWORD,
3314        /* 188      */ CWORD_CWORD_CWORD_CWORD,
3315        /* 189      */ CWORD_CWORD_CWORD_CWORD,
3316        /* 190      */ CWORD_CWORD_CWORD_CWORD,
3317        /* 191      */ CWORD_CWORD_CWORD_CWORD,
3318        /* 192      */ CWORD_CWORD_CWORD_CWORD,
3319        /* 193      */ CWORD_CWORD_CWORD_CWORD,
3320        /* 194      */ CWORD_CWORD_CWORD_CWORD,
3321        /* 195      */ CWORD_CWORD_CWORD_CWORD,
3322        /* 196      */ CWORD_CWORD_CWORD_CWORD,
3323        /* 197      */ CWORD_CWORD_CWORD_CWORD,
3324        /* 198      */ CWORD_CWORD_CWORD_CWORD,
3325        /* 199      */ CWORD_CWORD_CWORD_CWORD,
3326        /* 200      */ CWORD_CWORD_CWORD_CWORD,
3327        /* 201      */ CWORD_CWORD_CWORD_CWORD,
3328        /* 202      */ CWORD_CWORD_CWORD_CWORD,
3329        /* 203      */ CWORD_CWORD_CWORD_CWORD,
3330        /* 204      */ CWORD_CWORD_CWORD_CWORD,
3331        /* 205      */ CWORD_CWORD_CWORD_CWORD,
3332        /* 206      */ CWORD_CWORD_CWORD_CWORD,
3333        /* 207      */ CWORD_CWORD_CWORD_CWORD,
3334        /* 208      */ CWORD_CWORD_CWORD_CWORD,
3335        /* 209      */ CWORD_CWORD_CWORD_CWORD,
3336        /* 210      */ CWORD_CWORD_CWORD_CWORD,
3337        /* 211      */ CWORD_CWORD_CWORD_CWORD,
3338        /* 212      */ CWORD_CWORD_CWORD_CWORD,
3339        /* 213      */ CWORD_CWORD_CWORD_CWORD,
3340        /* 214      */ CWORD_CWORD_CWORD_CWORD,
3341        /* 215      */ CWORD_CWORD_CWORD_CWORD,
3342        /* 216      */ CWORD_CWORD_CWORD_CWORD,
3343        /* 217      */ CWORD_CWORD_CWORD_CWORD,
3344        /* 218      */ CWORD_CWORD_CWORD_CWORD,
3345        /* 219      */ CWORD_CWORD_CWORD_CWORD,
3346        /* 220      */ CWORD_CWORD_CWORD_CWORD,
3347        /* 221      */ CWORD_CWORD_CWORD_CWORD,
3348        /* 222      */ CWORD_CWORD_CWORD_CWORD,
3349        /* 223      */ CWORD_CWORD_CWORD_CWORD,
3350        /* 224      */ CWORD_CWORD_CWORD_CWORD,
3351        /* 225      */ CWORD_CWORD_CWORD_CWORD,
3352        /* 226      */ CWORD_CWORD_CWORD_CWORD,
3353        /* 227      */ CWORD_CWORD_CWORD_CWORD,
3354        /* 228      */ CWORD_CWORD_CWORD_CWORD,
3355        /* 229      */ CWORD_CWORD_CWORD_CWORD,
3356        /* 230      */ CWORD_CWORD_CWORD_CWORD,
3357        /* 231      */ CWORD_CWORD_CWORD_CWORD,
3358        /* 232      */ CWORD_CWORD_CWORD_CWORD,
3359        /* 233      */ CWORD_CWORD_CWORD_CWORD,
3360        /* 234      */ CWORD_CWORD_CWORD_CWORD,
3361        /* 235      */ CWORD_CWORD_CWORD_CWORD,
3362        /* 236      */ CWORD_CWORD_CWORD_CWORD,
3363        /* 237      */ CWORD_CWORD_CWORD_CWORD,
3364        /* 238      */ CWORD_CWORD_CWORD_CWORD,
3365        /* 239      */ CWORD_CWORD_CWORD_CWORD,
3366        /* 230      */ CWORD_CWORD_CWORD_CWORD,
3367        /* 241      */ CWORD_CWORD_CWORD_CWORD,
3368        /* 242      */ CWORD_CWORD_CWORD_CWORD,
3369        /* 243      */ CWORD_CWORD_CWORD_CWORD,
3370        /* 244      */ CWORD_CWORD_CWORD_CWORD,
3371        /* 245      */ CWORD_CWORD_CWORD_CWORD,
3372        /* 246      */ CWORD_CWORD_CWORD_CWORD,
3373        /* 247      */ CWORD_CWORD_CWORD_CWORD,
3374        /* 248      */ CWORD_CWORD_CWORD_CWORD,
3375        /* 249      */ CWORD_CWORD_CWORD_CWORD,
3376        /* 250      */ CWORD_CWORD_CWORD_CWORD,
3377        /* 251      */ CWORD_CWORD_CWORD_CWORD,
3378        /* 252      */ CWORD_CWORD_CWORD_CWORD,
3379        /* 253      */ CWORD_CWORD_CWORD_CWORD,
3380        /* 254      */ CWORD_CWORD_CWORD_CWORD,
3381        /* 255      */ CWORD_CWORD_CWORD_CWORD,
3382        /* PEOF */     CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3383};
3384
3385#if 1
3386# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3387#else /* debug version, caught one signed char bug */
3388# define SIT(c, syntax) \
3389        ({ \
3390                if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3391                        bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3392                if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3393                        bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3394                ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3395        })
3396#endif
3397
3398#endif  /* !USE_SIT_FUNCTION */
3399
3400
3401/* ============ Alias handling */
3402
3403#if ENABLE_ASH_ALIAS
3404
3405#define ALIASINUSE 1
3406#define ALIASDEAD  2
3407
3408struct alias {
3409        struct alias *next;
3410        char *name;
3411        char *val;
3412        int flag;
3413};
3414
3415
3416static struct alias **atab; // [ATABSIZE];
3417#define INIT_G_alias() do { \
3418        atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3419} while (0)
3420
3421
3422static struct alias **
3423__lookupalias(const char *name)
3424{
3425        unsigned int hashval;
3426        struct alias **app;
3427        const char *p;
3428        unsigned int ch;
3429
3430        p = name;
3431
3432        ch = (unsigned char)*p;
3433        hashval = ch << 4;
3434        while (ch) {
3435                hashval += ch;
3436                ch = (unsigned char)*++p;
3437        }
3438        app = &atab[hashval % ATABSIZE];
3439
3440        for (; *app; app = &(*app)->next) {
3441                if (strcmp(name, (*app)->name) == 0) {
3442                        break;
3443                }
3444        }
3445
3446        return app;
3447}
3448
3449static struct alias *
3450lookupalias(const char *name, int check)
3451{
3452        struct alias *ap = *__lookupalias(name);
3453
3454        if (check && ap && (ap->flag & ALIASINUSE))
3455                return NULL;
3456        return ap;
3457}
3458
3459static struct alias *
3460freealias(struct alias *ap)
3461{
3462        struct alias *next;
3463
3464        if (ap->flag & ALIASINUSE) {
3465                ap->flag |= ALIASDEAD;
3466                return ap;
3467        }
3468
3469        next = ap->next;
3470        free(ap->name);
3471        free(ap->val);
3472        free(ap);
3473        return next;
3474}
3475
3476static void
3477setalias(const char *name, const char *val)
3478{
3479        struct alias *ap, **app;
3480
3481        app = __lookupalias(name);
3482        ap = *app;
3483        INT_OFF;
3484        if (ap) {
3485                if (!(ap->flag & ALIASINUSE)) {
3486                        free(ap->val);
3487                }
3488                ap->val = ckstrdup(val);
3489                ap->flag &= ~ALIASDEAD;
3490        } else {
3491                /* not found */
3492                ap = ckzalloc(sizeof(struct alias));
3493                ap->name = ckstrdup(name);
3494                ap->val = ckstrdup(val);
3495                /*ap->flag = 0; - ckzalloc did it */
3496                /*ap->next = NULL;*/
3497                *app = ap;
3498        }
3499        INT_ON;
3500}
3501
3502static int
3503unalias(const char *name)
3504{
3505        struct alias **app;
3506
3507        app = __lookupalias(name);
3508
3509        if (*app) {
3510                INT_OFF;
3511                *app = freealias(*app);
3512                INT_ON;
3513                return 0;
3514        }
3515
3516        return 1;
3517}
3518
3519static void
3520rmaliases(void)
3521{
3522        struct alias *ap, **app;
3523        int i;
3524
3525        INT_OFF;
3526        for (i = 0; i < ATABSIZE; i++) {
3527                app = &atab[i];
3528                for (ap = *app; ap; ap = *app) {
3529                        *app = freealias(*app);
3530                        if (ap == *app) {
3531                                app = &ap->next;
3532                        }
3533                }
3534        }
3535        INT_ON;
3536}
3537
3538static void
3539printalias(const struct alias *ap)
3540{
3541        out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3542}
3543
3544/*
3545 * TODO - sort output
3546 */
3547static int FAST_FUNC
3548aliascmd(int argc UNUSED_PARAM, char **argv)
3549{
3550        char *n, *v;
3551        int ret = 0;
3552        struct alias *ap;
3553
3554        if (!argv[1]) {
3555                int i;
3556
3557                for (i = 0; i < ATABSIZE; i++) {
3558                        for (ap = atab[i]; ap; ap = ap->next) {
3559                                printalias(ap);
3560                        }
3561                }
3562                return 0;
3563        }
3564        while ((n = *++argv) != NULL) {
3565                v = strchr(n+1, '=');
3566                if (v == NULL) { /* n+1: funny ksh stuff */
3567                        ap = *__lookupalias(n);
3568                        if (ap == NULL) {
3569                                fprintf(stderr, "%s: %s not found\n", "alias", n);
3570                                ret = 1;
3571                        } else
3572                                printalias(ap);
3573                } else {
3574                        *v++ = '\0';
3575                        setalias(n, v);
3576                }
3577        }
3578
3579        return ret;
3580}
3581
3582static int FAST_FUNC
3583unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3584{
3585        int i;
3586
3587        while (nextopt("a") != '\0') {
3588                rmaliases();
3589                return 0;
3590        }
3591        for (i = 0; *argptr; argptr++) {
3592                if (unalias(*argptr)) {
3593                        fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3594                        i = 1;
3595                }
3596        }
3597
3598        return i;
3599}
3600
3601#endif /* ASH_ALIAS */
3602
3603
3604/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
3605#define FORK_FG    0
3606#define FORK_BG    1
3607#define FORK_NOJOB 2
3608
3609/* mode flags for showjob(s) */
3610#define SHOW_ONLY_PGID  0x01    /* show only pgid (jobs -p) */
3611#define SHOW_PIDS       0x02    /* show individual pids, not just one line per job */
3612#define SHOW_CHANGED    0x04    /* only jobs whose state has changed */
3613#define SHOW_STDERR     0x08    /* print to stderr (else stdout) */
3614
3615/*
3616 * A job structure contains information about a job.  A job is either a
3617 * single process or a set of processes contained in a pipeline.  In the
3618 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3619 * array of pids.
3620 */
3621struct procstat {
3622        pid_t   ps_pid;         /* process id */
3623        int     ps_status;      /* last process status from wait() */
3624        char    *ps_cmd;        /* text of command being run */
3625};
3626
3627struct job {
3628        struct procstat ps0;    /* status of process */
3629        struct procstat *ps;    /* status of processes when more than one */
3630#if JOBS
3631        int stopstatus;         /* status of a stopped job */
3632#endif
3633        unsigned nprocs;        /* number of processes */
3634
3635#define JOBRUNNING      0       /* at least one proc running */
3636#define JOBSTOPPED      1       /* all procs are stopped */
3637#define JOBDONE         2       /* all procs are completed */
3638        unsigned
3639                state: 8,
3640#if JOBS
3641                sigint: 1,      /* job was killed by SIGINT */
3642                jobctl: 1,      /* job running under job control */
3643#endif
3644                waited: 1,      /* true if this entry has been waited for */
3645                used: 1,        /* true if this entry is in used */
3646                changed: 1;     /* true if status has changed */
3647        struct job *prev_job;   /* previous job */
3648};
3649
3650static struct job *makejob(/*union node *,*/ int);
3651static int forkshell(struct job *, union node *, int);
3652static int waitforjob(struct job *);
3653
3654#if !JOBS
3655enum { doing_jobctl = 0 };
3656#define setjobctl(on) do {} while (0)
3657#else
3658static smallint doing_jobctl; //references:8
3659static void setjobctl(int);
3660#endif
3661
3662/*
3663 * Ignore a signal.
3664 */
3665static void
3666ignoresig(int signo)
3667{
3668        /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3669        if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3670                /* No, need to do it */
3671                signal(signo, SIG_IGN);
3672        }
3673        sigmode[signo - 1] = S_HARD_IGN;
3674}
3675
3676/*
3677 * Only one usage site - in setsignal()
3678 */
3679static void
3680signal_handler(int signo)
3681{
3682        if (signo == SIGCHLD) {
3683                got_sigchld = 1;
3684                if (!trap[SIGCHLD])
3685                        return;
3686        }
3687#if ENABLE_FEATURE_EDITING
3688        bb_got_signal = signo; /* for read_line_input: "we got a signal" */
3689#endif
3690        gotsig[signo - 1] = 1;
3691        pending_sig = signo;
3692
3693        if (signo == SIGINT && !trap[SIGINT]) {
3694                if (!suppress_int) {
3695                        pending_sig = 0;
3696                        raise_interrupt(); /* does not return */
3697                }
3698                pending_int = 1;
3699        }
3700}
3701
3702/*
3703 * Set the signal handler for the specified signal.  The routine figures
3704 * out what it should be set to.
3705 */
3706static void
3707setsignal(int signo)
3708{
3709        char *t;
3710        char cur_act, new_act;
3711        struct sigaction act;
3712
3713        t = trap[signo];
3714        new_act = S_DFL;
3715        if (t != NULL) { /* trap for this sig is set */
3716                new_act = S_CATCH;
3717                if (t[0] == '\0') /* trap is "": ignore this sig */
3718                        new_act = S_IGN;
3719        }
3720
3721        if (rootshell && new_act == S_DFL) {
3722                switch (signo) {
3723                case SIGINT:
3724                        if (iflag || minusc || sflag == 0)
3725                                new_act = S_CATCH;
3726                        break;
3727                case SIGQUIT:
3728#if DEBUG
3729                        if (debug)
3730                                break;
3731#endif
3732                        /* man bash:
3733                         * "In all cases, bash ignores SIGQUIT. Non-builtin
3734                         * commands run by bash have signal handlers
3735                         * set to the values inherited by the shell
3736                         * from its parent". */
3737                        new_act = S_IGN;
3738                        break;
3739                case SIGTERM:
3740                        if (iflag)
3741                                new_act = S_IGN;
3742                        break;
3743#if JOBS
3744                case SIGTSTP:
3745                case SIGTTOU:
3746                        if (mflag)
3747                                new_act = S_IGN;
3748                        break;
3749#endif
3750                }
3751        }
3752        /* if !rootshell, we reset SIGQUIT to DFL,
3753         * whereas we have to restore it to what shell got on entry.
3754         * This is handled by the fact that if signal was IGNored on entry,
3755         * then cur_act is S_HARD_IGN and we never change its sigaction
3756         * (see code below).
3757         */
3758
3759        if (signo == SIGCHLD)
3760                new_act = S_CATCH;
3761
3762        t = &sigmode[signo - 1];
3763        cur_act = *t;
3764        if (cur_act == 0) {
3765                /* current setting is not yet known */
3766                if (sigaction(signo, NULL, &act)) {
3767                        /* pretend it worked; maybe we should give a warning,
3768                         * but other shells don't. We don't alter sigmode,
3769                         * so we retry every time.
3770                         * btw, in Linux it never fails. --vda */
3771                        return;
3772                }
3773                if (act.sa_handler == SIG_IGN) {
3774                        cur_act = S_HARD_IGN;
3775                        if (mflag
3776                         && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3777                        ) {
3778                                cur_act = S_IGN;   /* don't hard ignore these */
3779                        }
3780                }
3781                if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3782                        /* installing SIG_DFL over SIG_DFL is a no-op */
3783                        /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3784                        *t = S_DFL;
3785                        return;
3786                }
3787        }
3788        if (cur_act == S_HARD_IGN || cur_act == new_act)
3789                return;
3790
3791        *t = new_act;
3792
3793        act.sa_handler = SIG_DFL;
3794        switch (new_act) {
3795        case S_CATCH:
3796                act.sa_handler = signal_handler;
3797                break;
3798        case S_IGN:
3799                act.sa_handler = SIG_IGN;
3800                break;
3801        }
3802        /* flags and mask matter only if !DFL and !IGN, but we do it
3803         * for all cases for more deterministic behavior:
3804         */
3805        act.sa_flags = 0; //TODO: why not SA_RESTART?
3806        sigfillset(&act.sa_mask);
3807
3808        sigaction_set(signo, &act);
3809}
3810
3811/* mode flags for set_curjob */
3812#define CUR_DELETE 2
3813#define CUR_RUNNING 1
3814#define CUR_STOPPED 0
3815
3816#if JOBS
3817/* pgrp of shell on invocation */
3818static int initialpgrp; //references:2
3819static int ttyfd = -1; //5
3820#endif
3821/* array of jobs */
3822static struct job *jobtab; //5
3823/* size of array */
3824static unsigned njobs; //4
3825/* current job */
3826static struct job *curjob; //lots
3827
3828#if 0
3829/* Bash has a feature: it restores termios after a successful wait for
3830 * a foreground job which had at least one stopped or sigkilled member.
3831 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3832 * properly restoring tty state. Should we do this too?
3833 * A reproducer: ^Z an interactive python:
3834 *
3835 * # python
3836 * Python 2.7.12 (...)
3837 * >>> ^Z
3838 *      { python leaves tty in -icanon -echo state. We do survive that... }
3839 *  [1]+  Stopped                    python
3840 *      { ...however, next program (python #2) does not survive it well: }
3841 * # python
3842 * Python 2.7.12 (...)
3843 * >>> Traceback (most recent call last):
3844 *      { above, I typed "qwerty<CR>", but -echo state is still in effect }
3845 *   File "<stdin>", line 1, in <module>
3846 * NameError: name 'qwerty' is not defined
3847 *
3848 * The implementation below is modeled on bash code and seems to work.
3849 * However, I'm not sure we should do this. For one: what if I'd fg
3850 * the stopped python instead? It'll be confused by "restored" tty state.
3851 */
3852static struct termios shell_tty_info;
3853static void
3854get_tty_state(void)
3855{
3856        if (rootshell && ttyfd >= 0)
3857                tcgetattr(ttyfd, &shell_tty_info);
3858}
3859static void
3860set_tty_state(void)
3861{
3862        /* if (rootshell) - caller ensures this */
3863        if (ttyfd >= 0)
3864                tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3865}
3866static int
3867job_signal_status(struct job *jp)
3868{
3869        int status;
3870        unsigned i;
3871        struct procstat *ps = jp->ps;
3872        for (i = 0; i < jp->nprocs; i++) {
3873                status = ps[i].ps_status;
3874                if (WIFSIGNALED(status) || WIFSTOPPED(status))
3875                        return status;
3876        }
3877        return 0;
3878}
3879static void
3880restore_tty_if_stopped_or_signaled(struct job *jp)
3881{
3882//TODO: check what happens if we come from waitforjob() in expbackq()
3883        if (rootshell) {
3884                int s = job_signal_status(jp);
3885                if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3886                        set_tty_state();
3887        }
3888}
3889#else
3890# define get_tty_state() ((void)0)
3891# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3892#endif
3893
3894static void
3895set_curjob(struct job *jp, unsigned mode)
3896{
3897        struct job *jp1;
3898        struct job **jpp, **curp;
3899
3900        /* first remove from list */
3901        jpp = curp = &curjob;
3902        while (1) {
3903                jp1 = *jpp;
3904                if (jp1 == jp)
3905                        break;
3906                jpp = &jp1->prev_job;
3907        }
3908        *jpp = jp1->prev_job;
3909
3910        /* Then re-insert in correct position */
3911        jpp = curp;
3912        switch (mode) {
3913        default:
3914#if DEBUG
3915                abort();
3916#endif
3917        case CUR_DELETE:
3918                /* job being deleted */
3919                break;
3920        case CUR_RUNNING:
3921                /* newly created job or backgrounded job,
3922                 * put after all stopped jobs.
3923                 */
3924                while (1) {
3925                        jp1 = *jpp;
3926#if JOBS
3927                        if (!jp1 || jp1->state != JOBSTOPPED)
3928#endif
3929                                break;
3930                        jpp = &jp1->prev_job;
3931                }
3932                /* FALLTHROUGH */
3933#if JOBS
3934        case CUR_STOPPED:
3935#endif
3936                /* newly stopped job - becomes curjob */
3937                jp->prev_job = *jpp;
3938                *jpp = jp;
3939                break;
3940        }
3941}
3942
3943#if JOBS || DEBUG
3944static int
3945jobno(const struct job *jp)
3946{
3947        return jp - jobtab + 1;
3948}
3949#endif
3950
3951/*
3952 * Convert a job name to a job structure.
3953 */
3954#if !JOBS
3955#define getjob(name, getctl) getjob(name)
3956#endif
3957static struct job *
3958getjob(const char *name, int getctl)
3959{
3960        struct job *jp;
3961        struct job *found;
3962        const char *err_msg = "%s: no such job";
3963        unsigned num;
3964        int c;
3965        const char *p;
3966        char *(*match)(const char *, const char *);
3967
3968        jp = curjob;
3969        p = name;
3970        if (!p)
3971                goto currentjob;
3972
3973        if (*p != '%')
3974                goto err;
3975
3976        c = *++p;
3977        if (!c)
3978                goto currentjob;
3979
3980        if (!p[1]) {
3981                if (c == '+' || c == '%') {
3982 currentjob:
3983                        err_msg = "No current job";
3984                        goto check;
3985                }
3986                if (c == '-') {
3987                        if (jp)
3988                                jp = jp->prev_job;
3989                        err_msg = "No previous job";
3990 check:
3991                        if (!jp)
3992                                goto err;
3993                        goto gotit;
3994                }
3995        }
3996
3997        if (is_number(p)) {
3998                num = atoi(p);
3999                if (num > 0 && num <= njobs) {
4000                        jp = jobtab + num - 1;
4001                        if (jp->used)
4002                                goto gotit;
4003                        goto err;
4004                }
4005        }
4006
4007        match = prefix;
4008        if (*p == '?') {
4009                match = strstr;
4010                p++;
4011        }
4012
4013        found = NULL;
4014        while (jp) {
4015                if (match(jp->ps[0].ps_cmd, p)) {
4016                        if (found)
4017                                goto err;
4018                        found = jp;
4019                        err_msg = "%s: ambiguous";
4020                }
4021                jp = jp->prev_job;
4022        }
4023        if (!found)
4024                goto err;
4025        jp = found;
4026
4027 gotit:
4028#if JOBS
4029        err_msg = "job %s not created under job control";
4030        if (getctl && jp->jobctl == 0)
4031                goto err;
4032#endif
4033        return jp;
4034 err:
4035        ash_msg_and_raise_error(err_msg, name);
4036}
4037
4038/*
4039 * Mark a job structure as unused.
4040 */
4041static void
4042freejob(struct job *jp)
4043{
4044        struct procstat *ps;
4045        int i;
4046
4047        INT_OFF;
4048        for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
4049                if (ps->ps_cmd != nullstr)
4050                        free(ps->ps_cmd);
4051        }
4052        if (jp->ps != &jp->ps0)
4053                free(jp->ps);
4054        jp->used = 0;
4055        set_curjob(jp, CUR_DELETE);
4056        INT_ON;
4057}
4058
4059#if JOBS
4060static void
4061xtcsetpgrp(int fd, pid_t pgrp)
4062{
4063        if (tcsetpgrp(fd, pgrp))
4064                ash_msg_and_raise_perror("can't set tty process group");
4065}
4066
4067/*
4068 * Turn job control on and off.
4069 *
4070 * Note:  This code assumes that the third arg to ioctl is a character
4071 * pointer, which is true on Berkeley systems but not System V.  Since
4072 * System V doesn't have job control yet, this isn't a problem now.
4073 *
4074 * Called with interrupts off.
4075 */
4076static void
4077setjobctl(int on)
4078{
4079        int fd;
4080        int pgrp;
4081
4082        if (on == doing_jobctl || rootshell == 0)
4083                return;
4084        if (on) {
4085                int ofd;
4086                ofd = fd = open(_PATH_TTY, O_RDWR);
4087                if (fd < 0) {
4088        /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
4089         * That sometimes helps to acquire controlling tty.
4090         * Obviously, a workaround for bugs when someone
4091         * failed to provide a controlling tty to bash! :) */
4092                        fd = 2;
4093                        while (!isatty(fd))
4094                                if (--fd < 0)
4095                                        goto out;
4096                }
4097                /* fd is a tty at this point */
4098                fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
4099                if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
4100                        close(ofd);
4101                if (fd < 0)
4102                        goto out; /* F_DUPFD failed */
4103                if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
4104                        close_on_exec_on(fd);
4105                while (1) { /* while we are in the background */
4106                        pgrp = tcgetpgrp(fd);
4107                        if (pgrp < 0) {
4108 out:
4109                                ash_msg("can't access tty; job control turned off");
4110                                mflag = on = 0;
4111                                goto close;
4112                        }
4113                        if (pgrp == getpgrp())
4114                                break;
4115                        killpg(0, SIGTTIN);
4116                }
4117                initialpgrp = pgrp;
4118
4119                setsignal(SIGTSTP);
4120                setsignal(SIGTTOU);
4121                setsignal(SIGTTIN);
4122                pgrp = rootpid;
4123                setpgid(0, pgrp);
4124                xtcsetpgrp(fd, pgrp);
4125        } else {
4126                /* turning job control off */
4127                fd = ttyfd;
4128                pgrp = initialpgrp;
4129                /* was xtcsetpgrp, but this can make exiting ash
4130                 * loop forever if pty is already deleted */
4131                tcsetpgrp(fd, pgrp);
4132                setpgid(0, pgrp);
4133                setsignal(SIGTSTP);
4134                setsignal(SIGTTOU);
4135                setsignal(SIGTTIN);
4136 close:
4137                if (fd >= 0)
4138                        close(fd);
4139                fd = -1;
4140        }
4141        ttyfd = fd;
4142        doing_jobctl = on;
4143}
4144
4145static int FAST_FUNC
4146killcmd(int argc, char **argv)
4147{
4148        if (argv[1] && strcmp(argv[1], "-l") != 0) {
4149                int i = 1;
4150                do {
4151                        if (argv[i][0] == '%') {
4152                                /*
4153                                 * "kill %N" - job kill
4154                                 * Converting to pgrp / pid kill
4155                                 */
4156                                struct job *jp;
4157                                char *dst;
4158                                int j, n;
4159
4160                                jp = getjob(argv[i], 0);
4161                                /*
4162                                 * In jobs started under job control, we signal
4163                                 * entire process group by kill -PGRP_ID.
4164                                 * This happens, f.e., in interactive shell.
4165                                 *
4166                                 * Otherwise, we signal each child via
4167                                 * kill PID1 PID2 PID3.
4168                                 * Testcases:
4169                                 * sh -c 'sleep 1|sleep 1 & kill %1'
4170                                 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4171                                 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4172                                 */
4173                                n = jp->nprocs; /* can't be 0 (I hope) */
4174                                if (jp->jobctl)
4175                                        n = 1;
4176                                dst = alloca(n * sizeof(int)*4);
4177                                argv[i] = dst;
4178                                for (j = 0; j < n; j++) {
4179                                        struct procstat *ps = &jp->ps[j];
4180                                        /* Skip non-running and not-stopped members
4181                                         * (i.e. dead members) of the job
4182                                         */
4183                                        if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4184                                                continue;
4185                                        /*
4186                                         * kill_main has matching code to expect
4187                                         * leading space. Needed to not confuse
4188                                         * negative pids with "kill -SIGNAL_NO" syntax
4189                                         */
4190                                        dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4191                                }
4192                                *dst = '\0';
4193                        }
4194                } while (argv[++i]);
4195        }
4196        return kill_main(argc, argv);
4197}
4198
4199static void
4200showpipe(struct job *jp /*, FILE *out*/)
4201{
4202        struct procstat *ps;
4203        struct procstat *psend;
4204
4205        psend = jp->ps + jp->nprocs;
4206        for (ps = jp->ps + 1; ps < psend; ps++)
4207                printf(" | %s", ps->ps_cmd);
4208        newline_and_flush(stdout);
4209        flush_stdout_stderr();
4210}
4211
4212
4213static int
4214restartjob(struct job *jp, int mode)
4215{
4216        struct procstat *ps;
4217        int i;
4218        int status;
4219        pid_t pgid;
4220
4221        INT_OFF;
4222        if (jp->state == JOBDONE)
4223                goto out;
4224        jp->state = JOBRUNNING;
4225        pgid = jp->ps[0].ps_pid;
4226        if (mode == FORK_FG) {
4227                get_tty_state();
4228                xtcsetpgrp(ttyfd, pgid);
4229        }
4230        killpg(pgid, SIGCONT);
4231        ps = jp->ps;
4232        i = jp->nprocs;
4233        do {
4234                if (WIFSTOPPED(ps->ps_status)) {
4235                        ps->ps_status = -1;
4236                }
4237                ps++;
4238        } while (--i);
4239 out:
4240        status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4241        INT_ON;
4242        return status;
4243}
4244
4245static int FAST_FUNC
4246fg_bgcmd(int argc UNUSED_PARAM, char **argv)
4247{
4248        struct job *jp;
4249        int mode;
4250        int retval;
4251
4252        mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4253        nextopt(nullstr);
4254        argv = argptr;
4255        do {
4256                jp = getjob(*argv, 1);
4257                if (mode == FORK_BG) {
4258                        set_curjob(jp, CUR_RUNNING);
4259                        printf("[%d] ", jobno(jp));
4260                }
4261                out1str(jp->ps[0].ps_cmd);
4262                showpipe(jp /*, stdout*/);
4263                retval = restartjob(jp, mode);
4264        } while (*argv && *++argv);
4265        return retval;
4266}
4267#endif
4268
4269static int
4270sprint_status48(char *os, int status, int sigonly)
4271{
4272        char *s = os;
4273        int st;
4274
4275        if (!WIFEXITED(status)) {
4276#if JOBS
4277                if (WIFSTOPPED(status))
4278                        st = WSTOPSIG(status);
4279                else
4280#endif
4281                        st = WTERMSIG(status);
4282                if (sigonly) {
4283                        if (st == SIGINT || st == SIGPIPE)
4284                                goto out;
4285#if JOBS
4286                        if (WIFSTOPPED(status))
4287                                goto out;
4288#endif
4289                }
4290                st &= 0x7f;
4291                s = stpncpy(s, strsignal(st), 32);
4292                if (WCOREDUMP(status)) {
4293                        s = stpcpy(s, " (core dumped)");
4294                }
4295        } else if (!sigonly) {
4296                st = WEXITSTATUS(status);
4297                s += fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
4298        }
4299 out:
4300        return s - os;
4301}
4302
4303#define DOWAIT_NONBLOCK 0
4304#define DOWAIT_BLOCK    1
4305#define DOWAIT_BLOCK_OR_SIG 2
4306#if BASH_WAIT_N
4307# define DOWAIT_JOBSTATUS 0x10   /* OR this to get job's exitstatus instead of pid */
4308#endif
4309
4310static int
4311waitproc(int block, int *status)
4312{
4313        sigset_t oldmask;
4314        int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
4315        int err;
4316
4317#if JOBS
4318        if (doing_jobctl)
4319                flags |= WUNTRACED;
4320#endif
4321
4322        do {
4323                got_sigchld = 0;
4324                do
4325                        err = waitpid(-1, status, flags);
4326                while (err < 0 && errno == EINTR);
4327
4328                if (err || (err = -!block))
4329                        break;
4330
4331                sigfillset(&oldmask);
4332                sigprocmask2(SIG_SETMASK, &oldmask); /* mask is updated */
4333                while (!got_sigchld && !pending_sig)
4334                        sigsuspend(&oldmask);
4335                sigprocmask(SIG_SETMASK, &oldmask, NULL);
4336                //simpler, but unsafe: a signal can set pending_sig after check, but before pause():
4337                //while (!got_sigchld && !pending_sig)
4338                //      pause();
4339
4340        } while (got_sigchld);
4341
4342        return err;
4343}
4344
4345static int
4346waitone(int block, struct job *job)
4347{
4348        int pid;
4349        int status;
4350        struct job *jp;
4351        struct job *thisjob = NULL;
4352#if BASH_WAIT_N
4353        bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
4354        block = (block & ~DOWAIT_JOBSTATUS);
4355#endif
4356
4357        TRACE(("dowait(0x%x) called\n", block));
4358
4359        /* It's wrong to call waitpid() outside of INT_OFF region:
4360         * signal can arrive just after syscall return and handler can
4361         * longjmp away, losing stop/exit notification processing.
4362         * Thus, for "jobs" builtin, and for waiting for a fg job,
4363         * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4364         *
4365         * However, for "wait" builtin it is wrong to simply call waitpid()
4366         * in INT_OFF region: "wait" needs to wait for any running job
4367         * to change state, but should exit on any trap too.
4368         * In INT_OFF region, a signal just before syscall entry can set
4369         * pending_sig variables, but we can't check them, and we would
4370         * either enter a sleeping waitpid() (BUG), or need to busy-loop.
4371         *
4372         * Because of this, we run inside INT_OFF, but use a special routine
4373         * which combines waitpid() and sigsuspend().
4374         * This is the reason why we need to have a handler for SIGCHLD:
4375         * SIG_DFL handler does not wake sigsuspend().
4376         */
4377        INT_OFF;
4378        pid = waitproc(block, &status);
4379        TRACE(("wait returns pid %d, status=%d\n", pid, status));
4380        if (pid <= 0)
4381                goto out;
4382
4383        for (jp = curjob; jp; jp = jp->prev_job) {
4384                int jobstate;
4385                struct procstat *ps;
4386                struct procstat *psend;
4387                if (jp->state == JOBDONE)
4388                        continue;
4389                jobstate = JOBDONE;
4390                ps = jp->ps;
4391                psend = ps + jp->nprocs;
4392                do {
4393                        if (ps->ps_pid == pid) {
4394                                TRACE(("Job %d: changing status of proc %d "
4395                                        "from 0x%x to 0x%x\n",
4396                                        jobno(jp), pid, ps->ps_status, status));
4397                                ps->ps_status = status;
4398                                thisjob = jp;
4399                        }
4400                        if (ps->ps_status == -1)
4401                                jobstate = JOBRUNNING;
4402#if JOBS
4403                        if (jobstate == JOBRUNNING)
4404                                continue;
4405                        if (WIFSTOPPED(ps->ps_status)) {
4406                                jp->stopstatus = ps->ps_status;
4407                                jobstate = JOBSTOPPED;
4408                        }
4409#endif
4410                } while (++ps < psend);
4411                if (!thisjob)
4412                        continue;
4413
4414                /* Found the job where one of its processes changed its state.
4415                 * Is there at least one live and running process in this job? */
4416                if (jobstate != JOBRUNNING) {
4417                        /* No. All live processes in the job are stopped
4418                         * (JOBSTOPPED) or there are no live processes (JOBDONE)
4419                         */
4420                        thisjob->changed = 1;
4421                        if (thisjob->state != jobstate) {
4422                                TRACE(("Job %d: changing state from %d to %d\n",
4423                                        jobno(thisjob), thisjob->state, jobstate));
4424                                thisjob->state = jobstate;
4425#if JOBS
4426                                if (jobstate == JOBSTOPPED)
4427                                        set_curjob(thisjob, CUR_STOPPED);
4428#endif
4429                        }
4430                }
4431                goto out;
4432        }
4433        /* The process wasn't found in job list */
4434 out:
4435        INT_ON;
4436
4437#if BASH_WAIT_N
4438        if (want_jobexitstatus) {
4439                pid = -1;
4440                if (thisjob && thisjob->state == JOBDONE)
4441                        pid = thisjob->ps[thisjob->nprocs - 1].ps_status;
4442        }
4443#endif
4444        if (thisjob && thisjob == job) {
4445                char s[48 + 1];
4446                int len;
4447
4448                len = sprint_status48(s, status, 1);
4449                if (len) {
4450                        s[len] = '\n';
4451                        s[len + 1] = '\0';
4452                        out2str(s);
4453                }
4454        }
4455        return pid;
4456}
4457
4458static int
4459dowait(int block, struct job *jp)
4460{
4461        smallint gotchld = *(volatile smallint *)&got_sigchld;
4462        int rpid;
4463        int pid;
4464
4465        if (jp && jp->state != JOBRUNNING)
4466                block = DOWAIT_NONBLOCK;
4467
4468        if (block == DOWAIT_NONBLOCK && !gotchld)
4469                return 1;
4470
4471        rpid = 1;
4472
4473        do {
4474                pid = waitone(block, jp);
4475                rpid &= !!pid;
4476
4477                if (!pid || (jp && jp->state != JOBRUNNING))
4478                        block = DOWAIT_NONBLOCK;
4479        } while (pid >= 0);
4480
4481        return rpid;
4482}
4483
4484#if JOBS
4485static void
4486showjob(struct job *jp, int mode)
4487{
4488        struct procstat *ps;
4489        struct procstat *psend;
4490        int col;
4491        int indent_col;
4492        char s[16 + 16 + 48];
4493        FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4494
4495        ps = jp->ps;
4496
4497        if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4498                /* just output process (group) id of pipeline */
4499                fprintf(out, "%d\n", ps->ps_pid);
4500                return;
4501        }
4502
4503        col = fmtstr(s, 16, "[%d]   ", jobno(jp));
4504        indent_col = col;
4505
4506        if (jp == curjob)
4507                s[col - 3] = '+';
4508        else if (curjob && jp == curjob->prev_job)
4509                s[col - 3] = '-';
4510
4511        if (mode & SHOW_PIDS)
4512                col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4513
4514        psend = ps + jp->nprocs;
4515
4516        if (jp->state == JOBRUNNING) {
4517                strcpy(s + col, "Running");
4518                col += sizeof("Running") - 1;
4519        } else {
4520                int status = psend[-1].ps_status;
4521                if (jp->state == JOBSTOPPED)
4522                        status = jp->stopstatus;
4523                col += sprint_status48(s + col, status, 0);
4524        }
4525        /* By now, "[JOBID]*  [maybe PID] STATUS" is printed */
4526
4527        /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4528         * or prints several "PID             | <cmdN>" lines,
4529         * depending on SHOW_PIDS bit.
4530         * We do not print status of individual processes
4531         * between PID and <cmdN>. bash does it, but not very well:
4532         * first line shows overall job status, not process status,
4533         * making it impossible to know 1st process status.
4534         */
4535        goto start;
4536        do {
4537                /* for each process */
4538                s[0] = '\0';
4539                col = 33;
4540                if (mode & SHOW_PIDS)
4541                        col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4542 start:
4543                fprintf(out, "%s%*c%s%s",
4544                                s,
4545                                33 - col >= 0 ? 33 - col : 0, ' ',
4546                                ps == jp->ps ? "" : "| ",
4547                                ps->ps_cmd
4548                );
4549        } while (++ps != psend);
4550        newline_and_flush(out);
4551
4552        jp->changed = 0;
4553
4554        if (jp->state == JOBDONE) {
4555                TRACE(("showjob: freeing job %d\n", jobno(jp)));
4556                freejob(jp);
4557        }
4558}
4559
4560/*
4561 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
4562 * statuses have changed since the last call to showjobs.
4563 */
4564static void
4565showjobs(int mode)
4566{
4567        struct job *jp;
4568
4569        TRACE(("showjobs(0x%x) called\n", mode));
4570
4571        /* Handle all finished jobs */
4572        dowait(DOWAIT_NONBLOCK, NULL);
4573
4574        for (jp = curjob; jp; jp = jp->prev_job) {
4575                if (!(mode & SHOW_CHANGED) || jp->changed) {
4576                        showjob(jp, mode);
4577                }
4578        }
4579}
4580
4581static int FAST_FUNC
4582jobscmd(int argc UNUSED_PARAM, char **argv)
4583{
4584        int mode, m;
4585
4586        mode = 0;
4587        while ((m = nextopt("lp")) != '\0') {
4588                if (m == 'l')
4589                        mode |= SHOW_PIDS;
4590                else
4591                        mode |= SHOW_ONLY_PGID;
4592        }
4593
4594        argv = argptr;
4595        if (*argv) {
4596                do
4597                        showjob(getjob(*argv, 0), mode);
4598                while (*++argv);
4599        } else {
4600                showjobs(mode);
4601        }
4602
4603        return 0;
4604}
4605#endif /* JOBS */
4606
4607/* Called only on finished or stopped jobs (no members are running) */
4608static int
4609getstatus(struct job *job)
4610{
4611        int status;
4612        int retval;
4613        struct procstat *ps;
4614
4615        /* Fetch last member's status */
4616        ps = job->ps + job->nprocs - 1;
4617        status = ps->ps_status;
4618        if (pipefail) {
4619                /* "set -o pipefail" mode: use last _nonzero_ status */
4620                while (status == 0 && --ps >= job->ps)
4621                        status = ps->ps_status;
4622        }
4623
4624        retval = WEXITSTATUS(status);
4625        if (!WIFEXITED(status)) {
4626#if JOBS
4627                retval = WSTOPSIG(status);
4628                if (!WIFSTOPPED(status))
4629#endif
4630                {
4631                        /* XXX: limits number of signals */
4632                        retval = WTERMSIG(status);
4633#if JOBS
4634                        if (retval == SIGINT)
4635                                job->sigint = 1;
4636#endif
4637                }
4638                retval |= 128;
4639        }
4640        TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4641                jobno(job), job->nprocs, status, retval));
4642        return retval;
4643}
4644
4645static int FAST_FUNC
4646waitcmd(int argc UNUSED_PARAM, char **argv)
4647{
4648        struct job *job;
4649        int retval;
4650        struct job *jp;
4651#if BASH_WAIT_N
4652        int status;
4653        char one = nextopt("n");
4654#else
4655        nextopt(nullstr);
4656#endif
4657        retval = 0;
4658
4659        argv = argptr;
4660        if (!argv[0]) {
4661                /* wait for all jobs / one job if -n */
4662                for (;;) {
4663                        jp = curjob;
4664#if BASH_WAIT_N
4665                        if (one && !jp)
4666                                /* exitcode of "wait -n" with nothing to wait for is 127, not 0 */
4667                                retval = 127;
4668#endif
4669                        while (1) {
4670                                if (!jp) /* no running procs */
4671                                        goto ret;
4672                                if (jp->state == JOBRUNNING)
4673                                        break;
4674                                jp->waited = 1;
4675                                jp = jp->prev_job;
4676                        }
4677        /* man bash:
4678         * "When bash is waiting for an asynchronous command via
4679         * the wait builtin, the reception of a signal for which a trap
4680         * has been set will cause the wait builtin to return immediately
4681         * with an exit status greater than 128, immediately after which
4682         * the trap is executed."
4683         */
4684#if BASH_WAIT_N
4685                        status = dowait(DOWAIT_BLOCK_OR_SIG | DOWAIT_JOBSTATUS, NULL);
4686#else
4687                        dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4688#endif
4689                        /* if child sends us a signal *and immediately exits*,
4690                         * dowait() returns pid > 0. Check this case,
4691                         * not "if (dowait() < 0)"!
4692                         */
4693                        if (pending_sig)
4694                                goto sigout;
4695#if BASH_WAIT_N
4696                        if (one) {
4697                                /* wait -n waits for one _job_, not one _process_.
4698                                 *  date; sleep 3 & sleep 2 | sleep 1 & wait -n; date
4699                                 * should wait for 2 seconds. Not 1 or 3.
4700                                 */
4701                                if (status != -1 && !WIFSTOPPED(status)) {
4702                                        retval = WEXITSTATUS(status);
4703                                        if (WIFSIGNALED(status))
4704                                                retval = 128 | WTERMSIG(status);
4705                                        goto ret;
4706                                }
4707                        }
4708#endif
4709                }
4710        }
4711
4712        retval = 127;
4713        do {
4714                if (**argv != '%') {
4715                        pid_t pid = number(*argv);
4716                        job = curjob;
4717                        while (1) {
4718                                if (!job)
4719                                        goto repeat;
4720                                if (job->ps[job->nprocs - 1].ps_pid == pid)
4721                                        break;
4722                                job = job->prev_job;
4723                        }
4724                } else {
4725                        job = getjob(*argv, 0);
4726                }
4727                /* loop until process terminated or stopped */
4728                dowait(DOWAIT_BLOCK_OR_SIG, job);
4729                if (pending_sig)
4730                        goto sigout;
4731                job->waited = 1;
4732                retval = getstatus(job);
4733 repeat: ;
4734        } while (*++argv);
4735
4736 ret:
4737        return retval;
4738 sigout:
4739        retval = 128 | pending_sig;
4740        return retval;
4741}
4742
4743static struct job *
4744growjobtab(void)
4745{
4746        size_t len;
4747        ptrdiff_t offset;
4748        struct job *jp, *jq;
4749
4750        len = njobs * sizeof(*jp);
4751        jq = jobtab;
4752        jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4753
4754        offset = (char *)jp - (char *)jq;
4755        if (offset) {
4756                /* Relocate pointers */
4757                size_t l = len;
4758
4759                jq = (struct job *)((char *)jq + l);
4760                while (l) {
4761                        l -= sizeof(*jp);
4762                        jq--;
4763#define joff(p) ((struct job *)((char *)(p) + l))
4764#define jmove(p) (p) = (void *)((char *)(p) + offset)
4765                        if (joff(jp)->ps == &jq->ps0)
4766                                jmove(joff(jp)->ps);
4767                        if (joff(jp)->prev_job)
4768                                jmove(joff(jp)->prev_job);
4769                }
4770                if (curjob)
4771                        jmove(curjob);
4772#undef joff
4773#undef jmove
4774        }
4775
4776        njobs += 4;
4777        jobtab = jp;
4778        jp = (struct job *)((char *)jp + len);
4779        jq = jp + 3;
4780        do {
4781                jq->used = 0;
4782        } while (--jq >= jp);
4783        return jp;
4784}
4785
4786/*
4787 * Return a new job structure.
4788 * Called with interrupts off.
4789 */
4790static struct job *
4791makejob(/*union node *node,*/ int nprocs)
4792{
4793        int i;
4794        struct job *jp;
4795
4796        for (i = njobs, jp = jobtab; ; jp++) {
4797                if (--i < 0) {
4798                        jp = growjobtab();
4799                        break;
4800                }
4801                if (jp->used == 0)
4802                        break;
4803                if (jp->state != JOBDONE || !jp->waited)
4804                        continue;
4805#if JOBS
4806                if (doing_jobctl)
4807                        continue;
4808#endif
4809                freejob(jp);
4810                break;
4811        }
4812        memset(jp, 0, sizeof(*jp));
4813#if JOBS
4814        /* jp->jobctl is a bitfield.
4815         * "jp->jobctl |= doing_jobctl" likely to give awful code */
4816        if (doing_jobctl)
4817                jp->jobctl = 1;
4818#endif
4819        jp->prev_job = curjob;
4820        curjob = jp;
4821        jp->used = 1;
4822        jp->ps = &jp->ps0;
4823        if (nprocs > 1) {
4824                jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4825        }
4826        TRACE(("makejob(%d) returns %%%d\n", nprocs,
4827                                jobno(jp)));
4828        return jp;
4829}
4830
4831#if JOBS
4832/*
4833 * Return a string identifying a command (to be printed by the
4834 * jobs command).
4835 */
4836static char *cmdnextc;
4837
4838static void
4839cmdputs(const char *s)
4840{
4841        static const char vstype[VSTYPE + 1][3] ALIGN1 = {
4842                "", "}", "-", "+", "?", "=",
4843                "%", "%%", "#", "##"
4844                IF_BASH_SUBSTR(, ":")
4845                IF_BASH_PATTERN_SUBST(, "/", "//")
4846        };
4847
4848        const char *p, *str;
4849        char cc[2];
4850        char *nextc;
4851        unsigned char c;
4852        unsigned char subtype = 0;
4853        int quoted = 0;
4854
4855        cc[1] = '\0';
4856        nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4857        p = s;
4858        while ((c = *p++) != '\0') {
4859                str = NULL;
4860                switch (c) {
4861                case CTLESC:
4862                        c = *p++;
4863                        break;
4864                case CTLVAR:
4865                        subtype = *p++;
4866                        if ((subtype & VSTYPE) == VSLENGTH)
4867                                str = "${#";
4868                        else
4869                                str = "${";
4870                        goto dostr;
4871                case CTLENDVAR:
4872                        str = "\"}";
4873                        str += !(quoted & 1);
4874                        quoted >>= 1;
4875                        subtype = 0;
4876                        goto dostr;
4877#if BASH_PROCESS_SUBST
4878                case CTLBACKQ:
4879                        c = '$';
4880                        str = "(...)";
4881                        break;
4882                case CTLTOPROC:
4883                        c = '>';
4884                        str = "(...)";
4885                        break;
4886                case CTLFROMPROC:
4887                        c = '<';
4888                        str = "(...)";
4889                        break;
4890#else
4891                case CTLBACKQ:
4892                        str = "$(...)";
4893                        goto dostr;
4894#endif
4895#if ENABLE_FEATURE_SH_MATH
4896                case CTLARI:
4897                        str = "$((";
4898                        goto dostr;
4899                case CTLENDARI:
4900                        str = "))";
4901                        goto dostr;
4902#endif
4903                case CTLQUOTEMARK:
4904                        quoted ^= 1;
4905                        c = '"';
4906                        break;
4907                case '=':
4908                        if (subtype == 0)
4909                                break;
4910                        if ((subtype & VSTYPE) != VSNORMAL)
4911                                quoted <<= 1;
4912                        str = vstype[subtype & VSTYPE];
4913                        if (subtype & VSNUL)
4914                                c = ':';
4915                        else
4916                                goto checkstr;
4917                        break;
4918                case '\'':
4919                case '\\':
4920                case '"':
4921                case '$':
4922                        /* These can only happen inside quotes */
4923                        cc[0] = c;
4924                        str = cc;
4925//FIXME:
4926// $ true $$ &
4927// $ <cr>
4928// [1]+  Done    true ${\$}   <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
4929                        c = '\\';
4930                        break;
4931                default:
4932                        break;
4933                }
4934                USTPUTC(c, nextc);
4935 checkstr:
4936                if (!str)
4937                        continue;
4938 dostr:
4939                while ((c = *str++) != '\0') {
4940                        USTPUTC(c, nextc);
4941                }
4942        } /* while *p++ not NUL */
4943
4944        if (quoted & 1) {
4945                USTPUTC('"', nextc);
4946        }
4947        *nextc = 0;
4948        cmdnextc = nextc;
4949}
4950
4951/* cmdtxt() and cmdlist() call each other */
4952static void cmdtxt(union node *n);
4953
4954static void
4955cmdlist(union node *np, int sep)
4956{
4957        for (; np; np = np->narg.next) {
4958                if (!sep)
4959                        cmdputs(" ");
4960                cmdtxt(np);
4961                if (sep && np->narg.next)
4962                        cmdputs(" ");
4963        }
4964}
4965
4966static void
4967cmdtxt(union node *n)
4968{
4969        union node *np;
4970        struct nodelist *lp;
4971        const char *p;
4972
4973        if (!n)
4974                return;
4975        switch (n->type) {
4976        default:
4977#if DEBUG
4978                abort();
4979#endif
4980        case NPIPE:
4981                lp = n->npipe.cmdlist;
4982                for (;;) {
4983                        cmdtxt(lp->n);
4984                        lp = lp->next;
4985                        if (!lp)
4986                                break;
4987                        cmdputs(" | ");
4988                }
4989                break;
4990        case NSEMI:
4991                p = "; ";
4992                goto binop;
4993        case NAND:
4994                p = " && ";
4995                goto binop;
4996        case NOR:
4997                p = " || ";
4998 binop:
4999                cmdtxt(n->nbinary.ch1);
5000                cmdputs(p);
5001                n = n->nbinary.ch2;
5002                goto donode;
5003        case NREDIR:
5004        case NBACKGND:
5005                n = n->nredir.n;
5006                goto donode;
5007        case NNOT:
5008                cmdputs("!");
5009                n = n->nnot.com;
5010 donode:
5011                cmdtxt(n);
5012                break;
5013        case NIF:
5014                cmdputs("if ");
5015                cmdtxt(n->nif.test);
5016                cmdputs("; then ");
5017                if (n->nif.elsepart) {
5018                        cmdtxt(n->nif.ifpart);
5019                        cmdputs("; else ");
5020                        n = n->nif.elsepart;
5021                } else {
5022                        n = n->nif.ifpart;
5023                }
5024                p = "; fi";
5025                goto dotail;
5026        case NSUBSHELL:
5027                cmdputs("(");
5028                n = n->nredir.n;
5029                p = ")";
5030                goto dotail;
5031        case NWHILE:
5032                p = "while ";
5033                goto until;
5034        case NUNTIL:
5035                p = "until ";
5036 until:
5037                cmdputs(p);
5038                cmdtxt(n->nbinary.ch1);
5039                n = n->nbinary.ch2;
5040                p = "; done";
5041 dodo:
5042                cmdputs("; do ");
5043 dotail:
5044                cmdtxt(n);
5045                goto dotail2;
5046        case NFOR:
5047                cmdputs("for ");
5048                cmdputs(n->nfor.var);
5049                cmdputs(" in ");
5050                cmdlist(n->nfor.args, 1);
5051                n = n->nfor.body;
5052                p = "; done";
5053                goto dodo;
5054        case NDEFUN:
5055                cmdputs(n->ndefun.text);
5056                p = "() { ... }";
5057                goto dotail2;
5058        case NCMD:
5059                cmdlist(n->ncmd.args, 1);
5060                cmdlist(n->ncmd.redirect, 0);
5061                break;
5062        case NARG:
5063                p = n->narg.text;
5064 dotail2:
5065                cmdputs(p);
5066                break;
5067        case NHERE:
5068        case NXHERE:
5069                p = "<<...";
5070                goto dotail2;
5071        case NCASE:
5072                cmdputs("case ");
5073                cmdputs(n->ncase.expr->narg.text);
5074                cmdputs(" in ");
5075                for (np = n->ncase.cases; np; np = np->nclist.next) {
5076                        cmdtxt(np->nclist.pattern);
5077                        cmdputs(") ");
5078                        cmdtxt(np->nclist.body);
5079                        cmdputs(";; ");
5080                }
5081                p = "esac";
5082                goto dotail2;
5083        case NTO:
5084                p = ">";
5085                goto redir;
5086        case NCLOBBER:
5087                p = ">|";
5088                goto redir;
5089        case NAPPEND:
5090                p = ">>";
5091                goto redir;
5092#if BASH_REDIR_OUTPUT
5093        case NTO2:
5094#endif
5095        case NTOFD:
5096                p = ">&";
5097                goto redir;
5098        case NFROM:
5099                p = "<";
5100                goto redir;
5101        case NFROMFD:
5102                p = "<&";
5103                goto redir;
5104        case NFROMTO:
5105                p = "<>";
5106 redir:
5107                cmdputs(utoa(n->nfile.fd));
5108                cmdputs(p);
5109                if (n->type == NTOFD || n->type == NFROMFD) {
5110                        if (n->ndup.dupfd >= 0)
5111                                cmdputs(utoa(n->ndup.dupfd));
5112                        else
5113                                cmdputs("-");
5114                        break;
5115                }
5116                n = n->nfile.fname;
5117                goto donode;
5118        }
5119}
5120
5121static char *
5122commandtext(union node *n)
5123{
5124        char *name;
5125
5126        STARTSTACKSTR(cmdnextc);
5127        cmdtxt(n);
5128        name = stackblock();
5129        TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
5130        return ckstrdup(name);
5131}
5132#endif /* JOBS */
5133
5134/*
5135 * Fork off a subshell.  If we are doing job control, give the subshell its
5136 * own process group.  Jp is a job structure that the job is to be added to.
5137 * N is the command that will be evaluated by the child.  Both jp and n may
5138 * be NULL.  The mode parameter can be one of the following:
5139 *      FORK_FG - Fork off a foreground process.
5140 *      FORK_BG - Fork off a background process.
5141 *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
5142 *                   process group even if job control is on.
5143 *
5144 * When job control is turned off, background processes have their standard
5145 * input redirected to /dev/null (except for the second and later processes
5146 * in a pipeline).
5147 *
5148 * Called with interrupts off.
5149 */
5150/*
5151 * Clear traps on a fork.
5152 */
5153static void
5154clear_traps(void)
5155{
5156        char **tp;
5157
5158        INT_OFF;
5159        for (tp = trap; tp <= &trap[NTRAP_LAST]; tp++) {
5160                if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */
5161                        if (trap_ptr == trap)
5162                                free(*tp);
5163                        /* else: it "belongs" to trap_ptr vector, don't free */
5164                        *tp = NULL;
5165                        if ((tp - trap) != 0 && (tp - trap) < NSIG)
5166                                setsignal(tp - trap);
5167                }
5168        }
5169        may_have_traps = 0;
5170        INT_ON;
5171}
5172
5173/* Lives far away from here, needed for forkchild */
5174static void closescript(void);
5175
5176/* Called after fork(), in child */
5177/* jp and n are NULL when called by openhere() for heredoc support */
5178static NOINLINE void
5179forkchild(struct job *jp, union node *n, int mode)
5180{
5181        int oldlvl;
5182
5183        TRACE(("Child shell %d\n", getpid()));
5184        oldlvl = shlvl;
5185        shlvl++;
5186
5187        /* man bash: "Non-builtin commands run by bash have signal handlers
5188         * set to the values inherited by the shell from its parent".
5189         * Do we do it correctly? */
5190
5191        closescript();
5192
5193        if (mode == FORK_NOJOB          /* is it `xxx` ? */
5194         && n && n->type == NCMD        /* is it single cmd? */
5195        /* && n->ncmd.args->type == NARG - always true? */
5196         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
5197         && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5198        /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5199        ) {
5200                TRACE(("Trap hack\n"));
5201                /* Awful hack for `trap` or $(trap).
5202                 *
5203                 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5204                 * contains an example where "trap" is executed in a subshell:
5205                 *
5206                 * save_traps=$(trap)
5207                 * ...
5208                 * eval "$save_traps"
5209                 *
5210                 * Standard does not say that "trap" in subshell shall print
5211                 * parent shell's traps. It only says that its output
5212                 * must have suitable form, but then, in the above example
5213                 * (which is not supposed to be normative), it implies that.
5214                 *
5215                 * bash (and probably other shell) does implement it
5216                 * (traps are reset to defaults, but "trap" still shows them),
5217                 * but as a result, "trap" logic is hopelessly messed up:
5218                 *
5219                 * # trap
5220                 * trap -- 'echo Ho' SIGWINCH  <--- we have a handler
5221                 * # (trap)        <--- trap is in subshell - no output (correct, traps are reset)
5222                 * # true | trap   <--- trap is in subshell - no output (ditto)
5223                 * # echo `true | trap`    <--- in subshell - output (but traps are reset!)
5224                 * trap -- 'echo Ho' SIGWINCH
5225                 * # echo `(trap)`         <--- in subshell in subshell - output
5226                 * trap -- 'echo Ho' SIGWINCH
5227                 * # echo `true | (trap)`  <--- in subshell in subshell in subshell - output!
5228                 * trap -- 'echo Ho' SIGWINCH
5229                 *
5230                 * The rules when to forget and when to not forget traps
5231                 * get really complex and nonsensical.
5232                 *
5233                 * Our solution: ONLY bare $(trap) or `trap` is special.
5234                 */
5235                /* Save trap handler strings for trap builtin to print */
5236                trap_ptr = xmemdup(trap, sizeof(trap));
5237                /* Fall through into clearing traps */
5238        }
5239        clear_traps();
5240#if JOBS
5241        /* do job control only in root shell */
5242        doing_jobctl = 0;
5243        if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
5244                pid_t pgrp;
5245
5246                if (jp->nprocs == 0)
5247                        pgrp = getpid();
5248                else
5249                        pgrp = jp->ps[0].ps_pid;
5250                /* this can fail because we are doing it in the parent also */
5251                setpgid(0, pgrp);
5252                if (mode == FORK_FG)
5253                        xtcsetpgrp(ttyfd, pgrp);
5254                setsignal(SIGTSTP);
5255                setsignal(SIGTTOU);
5256        } else
5257#endif
5258        if (mode == FORK_BG) {
5259                /* man bash: "When job control is not in effect,
5260                 * asynchronous commands ignore SIGINT and SIGQUIT" */
5261                ignoresig(SIGINT);
5262                ignoresig(SIGQUIT);
5263                if (jp->nprocs == 0) {
5264                        close(0);
5265                        if (open(bb_dev_null, O_RDONLY) != 0)
5266                                ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
5267                }
5268        }
5269        if (oldlvl == 0) {
5270                if (iflag) { /* why if iflag only? */
5271                        setsignal(SIGINT);
5272                        setsignal(SIGTERM);
5273                }
5274                /* man bash:
5275                 * "In all cases, bash ignores SIGQUIT. Non-builtin
5276                 * commands run by bash have signal handlers
5277                 * set to the values inherited by the shell
5278                 * from its parent".
5279                 * Take care of the second rule: */
5280                setsignal(SIGQUIT);
5281        }
5282#if JOBS
5283        if (n && n->type == NCMD
5284         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
5285        ) {
5286                TRACE(("Job hack\n"));
5287                /* "jobs": we do not want to clear job list for it,
5288                 * instead we remove only _its_ own_ job from job list.
5289                 * This makes "jobs .... | cat" more useful.
5290                 */
5291                freejob(curjob);
5292                return;
5293        }
5294#endif
5295        for (jp = curjob; jp; jp = jp->prev_job)
5296                freejob(jp);
5297}
5298
5299/* Called after fork(), in parent */
5300#if !JOBS
5301#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5302#endif
5303static void
5304forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5305{
5306        TRACE(("In parent shell: child = %d\n", pid));
5307        if (!jp) /* jp is NULL when called by openhere() for heredoc support */
5308                return;
5309#if JOBS
5310        if (mode != FORK_NOJOB && jp->jobctl) {
5311                int pgrp;
5312
5313                if (jp->nprocs == 0)
5314                        pgrp = pid;
5315                else
5316                        pgrp = jp->ps[0].ps_pid;
5317                /* This can fail because we are doing it in the child also */
5318                setpgid(pid, pgrp);
5319        }
5320#endif
5321        if (mode == FORK_BG) {
5322                backgndpid = pid;               /* set $! */
5323                set_curjob(jp, CUR_RUNNING);
5324        }
5325        if (jp) {
5326                struct procstat *ps = &jp->ps[jp->nprocs++];
5327                ps->ps_pid = pid;
5328                ps->ps_status = -1;
5329                ps->ps_cmd = nullstr;
5330#if JOBS
5331                if (doing_jobctl && n)
5332                        ps->ps_cmd = commandtext(n);
5333#endif
5334        }
5335}
5336
5337/* jp and n are NULL when called by openhere() for heredoc support */
5338static int
5339forkshell(struct job *jp, union node *n, int mode)
5340{
5341        int pid;
5342
5343        TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5344        pid = fork();
5345        if (pid < 0) {
5346                TRACE(("Fork failed, errno=%d", errno));
5347                if (jp)
5348                        freejob(jp);
5349                ash_msg_and_raise_perror("can't fork");
5350        }
5351        if (pid == 0) {
5352                CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
5353                forkchild(jp, n, mode);
5354        } else {
5355                forkparent(jp, n, mode, pid);
5356        }
5357        return pid;
5358}
5359
5360/*
5361 * Wait for job to finish.
5362 *
5363 * Under job control we have the problem that while a child process
5364 * is running interrupts generated by the user are sent to the child
5365 * but not to the shell.  This means that an infinite loop started by
5366 * an interactive user may be hard to kill.  With job control turned off,
5367 * an interactive user may place an interactive program inside a loop.
5368 * If the interactive program catches interrupts, the user doesn't want
5369 * these interrupts to also abort the loop.  The approach we take here
5370 * is to have the shell ignore interrupt signals while waiting for a
5371 * foreground process to terminate, and then send itself an interrupt
5372 * signal if the child process was terminated by an interrupt signal.
5373 * Unfortunately, some programs want to do a bit of cleanup and then
5374 * exit on interrupt; unless these processes terminate themselves by
5375 * sending a signal to themselves (instead of calling exit) they will
5376 * confuse this approach.
5377 *
5378 * Called with interrupts off.
5379 */
5380static int
5381waitforjob(struct job *jp)
5382{
5383        int st;
5384
5385        TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
5386
5387        /* In non-interactive shells, we _can_ get
5388         * a keyboard signal here and be EINTRed, but we just loop
5389         * inside dowait(), waiting for command to complete.
5390         *
5391         * man bash:
5392         * "If bash is waiting for a command to complete and receives
5393         * a signal for which a trap has been set, the trap
5394         * will not be executed until the command completes."
5395         *
5396         * Reality is that even if trap is not set, bash
5397         * will not act on the signal until command completes.
5398         * Try this. sleep5intoff.c:
5399         * #include <signal.h>
5400         * #include <unistd.h>
5401         * int main() {
5402         *         sigset_t set;
5403         *         sigemptyset(&set);
5404         *         sigaddset(&set, SIGINT);
5405         *         sigaddset(&set, SIGQUIT);
5406         *         sigprocmask(SIG_BLOCK, &set, NULL);
5407         *         sleep(5);
5408         *         return 0;
5409         * }
5410         * $ bash -c './sleep5intoff; echo hi'
5411         * ^C^C^C^C <--- pressing ^C once a second
5412         * $ _
5413         * $ bash -c './sleep5intoff; echo hi'
5414         * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5415         * $ _
5416         */
5417        dowait(jp ? DOWAIT_BLOCK : DOWAIT_NONBLOCK, jp);
5418        if (!jp)
5419                return exitstatus;
5420
5421        st = getstatus(jp);
5422#if JOBS
5423        if (jp->jobctl) {
5424                xtcsetpgrp(ttyfd, rootpid);
5425                restore_tty_if_stopped_or_signaled(jp);
5426
5427                /*
5428                 * This is truly gross.
5429                 * If we're doing job control, then we did a TIOCSPGRP which
5430                 * caused us (the shell) to no longer be in the controlling
5431                 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
5432                 * intuit from the subprocess exit status whether a SIGINT
5433                 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
5434                 */
5435                if (jp->sigint) /* TODO: do the same with all signals */
5436                        raise(SIGINT); /* ... by raise(jp->sig) instead? */
5437        }
5438        if (jp->state == JOBDONE)
5439#endif
5440                freejob(jp);
5441        return st;
5442}
5443
5444/*
5445 * return 1 if there are stopped jobs, otherwise 0
5446 */
5447static int
5448stoppedjobs(void)
5449{
5450        struct job *jp;
5451        int retval;
5452
5453        retval = 0;
5454        if (!iflag || job_warning)
5455                goto out;
5456        jp = curjob;
5457        if (jp && jp->state == JOBSTOPPED) {
5458                out2str("You have stopped jobs.\n");
5459                job_warning = 2;
5460                retval++;
5461        }
5462 out:
5463        return retval;
5464}
5465
5466
5467/*
5468 * Code for dealing with input/output redirection.
5469 */
5470
5471#undef EMPTY
5472#undef CLOSED
5473#define EMPTY -2                /* marks an unused slot in redirtab */
5474#define CLOSED -1               /* marks a slot of previously-closed fd */
5475
5476/*
5477 * Handle here documents.  Normally we fork off a process to write the
5478 * data to a pipe.  If the document is short, we can stuff the data in
5479 * the pipe without forking.
5480 */
5481/* openhere needs this forward reference */
5482static void expandhere(union node *arg);
5483static int
5484openhere(union node *redir)
5485{
5486        char *p;
5487        int pip[2];
5488        size_t len = 0;
5489
5490        if (pipe(pip) < 0)
5491                ash_msg_and_raise_perror("can't create pipe");
5492
5493        p = redir->nhere.doc->narg.text;
5494        if (redir->type == NXHERE) {
5495                expandhere(redir->nhere.doc);
5496                p = stackblock();
5497        }
5498
5499        len = strlen(p);
5500        if (len <= PIPE_BUF) {
5501                xwrite(pip[1], p, len);
5502                goto out;
5503        }
5504
5505        if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5506                /* child */
5507                close(pip[0]);
5508                ignoresig(SIGINT);  //signal(SIGINT, SIG_IGN);
5509                ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5510                ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
5511                ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5512                signal(SIGPIPE, SIG_DFL);
5513                xwrite(pip[1], p, len);
5514                _exit_SUCCESS();
5515        }
5516 out:
5517        close(pip[1]);
5518        return pip[0];
5519}
5520
5521static int
5522openredirect(union node *redir)
5523{
5524        struct stat sb;
5525        char *fname;
5526        int f;
5527
5528        switch (redir->nfile.type) {
5529/* Can't happen, our single caller does this itself */
5530//      case NTOFD:
5531//      case NFROMFD:
5532//              return -1;
5533        case NHERE:
5534        case NXHERE:
5535                return openhere(redir);
5536        }
5537
5538        /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5539         * allocated space. Do it only when we know it is safe.
5540         */
5541        fname = redir->nfile.expfname;
5542
5543        switch (redir->nfile.type) {
5544        default:
5545#if DEBUG
5546                abort();
5547#endif
5548        case NFROM:
5549                f = open(fname, O_RDONLY);
5550                if (f < 0)
5551                        goto eopen;
5552                break;
5553        case NFROMTO:
5554                f = open(fname, O_RDWR|O_CREAT, 0666);
5555                if (f < 0)
5556                        goto ecreate;
5557                break;
5558        case NTO:
5559#if BASH_REDIR_OUTPUT
5560        case NTO2:
5561#endif
5562                /* Take care of noclobber mode. */
5563                if (Cflag) {
5564                        if (stat(fname, &sb) < 0) {
5565                                f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5566                                if (f < 0)
5567                                        goto ecreate;
5568                        } else if (!S_ISREG(sb.st_mode)) {
5569                                f = open(fname, O_WRONLY, 0666);
5570                                if (f < 0)
5571                                        goto ecreate;
5572                                if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
5573                                        close(f);
5574                                        errno = EEXIST;
5575                                        goto ecreate;
5576                                }
5577                        } else {
5578                                errno = EEXIST;
5579                                goto ecreate;
5580                        }
5581                        break;
5582                }
5583                /* FALLTHROUGH */
5584        case NCLOBBER:
5585                f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5586                if (f < 0)
5587                        goto ecreate;
5588                break;
5589        case NAPPEND:
5590                f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5591                if (f < 0)
5592                        goto ecreate;
5593                break;
5594        }
5595
5596        return f;
5597 ecreate:
5598        ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5599 eopen:
5600        ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5601}
5602
5603/*
5604 * Copy a file descriptor to be >= 10. Throws exception on error.
5605 */
5606static int
5607savefd(int from)
5608{
5609        int newfd;
5610        int err;
5611
5612        newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
5613        err = newfd < 0 ? errno : 0;
5614        if (err != EBADF) {
5615                if (err)
5616                        ash_msg_and_raise_perror("%d", from);
5617                close(from);
5618                if (F_DUPFD_CLOEXEC == F_DUPFD)
5619                        close_on_exec_on(newfd);
5620        }
5621
5622        return newfd;
5623}
5624static int
5625dup2_or_raise(int from, int to)
5626{
5627        int newfd;
5628
5629        newfd = (from != to) ? dup2(from, to) : to;
5630        if (newfd < 0) {
5631                /* Happens when source fd is not open: try "echo >&99" */
5632                ash_msg_and_raise_perror("%d", from);
5633        }
5634        return newfd;
5635}
5636static int
5637dup_CLOEXEC(int fd, int avoid_fd)
5638{
5639        int newfd;
5640 repeat:
5641        newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5642        if (newfd >= 0) {
5643                if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
5644                        close_on_exec_on(newfd);
5645        } else { /* newfd < 0 */
5646                if (errno == EBUSY)
5647                        goto repeat;
5648                if (errno == EINTR)
5649                        goto repeat;
5650        }
5651        return newfd;
5652}
5653static int
5654xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5655{
5656        int newfd;
5657 repeat:
5658        newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5659        if (newfd < 0) {
5660                if (errno == EBUSY)
5661                        goto repeat;
5662                if (errno == EINTR)
5663                        goto repeat;
5664                /* fd was not open? */
5665                if (errno == EBADF)
5666                        return fd;
5667                ash_msg_and_raise_perror("%d", newfd);
5668        }
5669        if (F_DUPFD_CLOEXEC == F_DUPFD)
5670                close_on_exec_on(newfd);
5671        close(fd);
5672        return newfd;
5673}
5674
5675/* Struct def and variable are moved down to the first usage site */
5676struct squirrel {
5677        int orig_fd;
5678        int moved_to;
5679};
5680struct redirtab {
5681        struct redirtab *next;
5682        int pair_count;
5683        struct squirrel two_fd[];
5684};
5685#define redirlist (G_var.redirlist)
5686
5687static void
5688add_squirrel_closed(struct redirtab *sq, int fd)
5689{
5690        int i;
5691
5692        if (!sq)
5693                return;
5694
5695        for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5696                /* If we collide with an already moved fd... */
5697                if (fd == sq->two_fd[i].orig_fd) {
5698                        /* Examples:
5699                         * "echo 3>FILE 3>&- 3>FILE"
5700                         * "echo 3>&- 3>FILE"
5701                         * No need for last redirect to insert
5702                         * another "need to close 3" indicator.
5703                         */
5704                        TRACE(("redirect_fd %d: already moved or closed\n", fd));
5705                        return;
5706                }
5707        }
5708        TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5709        sq->two_fd[i].orig_fd = fd;
5710        sq->two_fd[i].moved_to = CLOSED;
5711}
5712
5713static int
5714save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5715{
5716        int i, new_fd;
5717
5718        if (avoid_fd < 9) /* the important case here is that it can be -1 */
5719                avoid_fd = 9;
5720
5721#if JOBS
5722        if (fd == ttyfd) {
5723                /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5724                ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5725                TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5726                return 1; /* "we closed fd" */
5727        }
5728#endif
5729        /* Are we called from redirect(0)? E.g. redirect
5730         * in a forked child. No need to save fds,
5731         * we aren't going to use them anymore, ok to trash.
5732         */
5733        if (!sq)
5734                return 0;
5735
5736        /* If this one of script's fds? */
5737        if (fd != 0) {
5738                struct parsefile *pf = g_parsefile;
5739                while (pf) {
5740                        /* We skip fd == 0 case because of the following:
5741                         * $ ash  # running ash interactively
5742                         * $ . ./script.sh
5743                         * and in script.sh: "exec 9>&0".
5744                         * Even though top-level pf_fd _is_ 0,
5745                         * it's still ok to use it: "read" builtin uses it,
5746                         * why should we cripple "exec" builtin?
5747                         */
5748                        if (fd == pf->pf_fd) {
5749                                pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5750                                return 1; /* "we closed fd" */
5751                        }
5752                        pf = pf->prev;
5753                }
5754        }
5755
5756        /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5757
5758        /* First: do we collide with some already moved fds? */
5759        for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5760                /* If we collide with an already moved fd... */
5761                if (fd == sq->two_fd[i].moved_to) {
5762                        new_fd = dup_CLOEXEC(fd, avoid_fd);
5763                        sq->two_fd[i].moved_to = new_fd;
5764                        TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5765                        if (new_fd < 0) /* what? */
5766                                xfunc_die();
5767                        return 0; /* "we did not close fd" */
5768                }
5769                if (fd == sq->two_fd[i].orig_fd) {
5770                        /* Example: echo Hello >/dev/null 1>&2 */
5771                        TRACE(("redirect_fd %d: already moved\n", fd));
5772                        return 0; /* "we did not close fd" */
5773                }
5774        }
5775
5776        /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5777        new_fd = dup_CLOEXEC(fd, avoid_fd);
5778        TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5779        if (new_fd < 0) {
5780                if (errno != EBADF)
5781                        xfunc_die();
5782                /* new_fd = CLOSED; - already is -1 */
5783        }
5784        sq->two_fd[i].moved_to = new_fd;
5785        sq->two_fd[i].orig_fd = fd;
5786
5787        /* if we move stderr, let "set -x" code know */
5788        if (fd == preverrout_fd)
5789                preverrout_fd = new_fd;
5790
5791        return 0; /* "we did not close fd" */
5792}
5793
5794static int
5795internally_opened_fd(int fd, struct redirtab *sq)
5796{
5797        int i;
5798#if JOBS
5799        if (fd == ttyfd)
5800                return 1;
5801#endif
5802        /* If this one of script's fds? */
5803        if (fd != 0) {
5804                struct parsefile *pf = g_parsefile;
5805                while (pf) {
5806                        if (fd == pf->pf_fd)
5807                                return 1;
5808                        pf = pf->prev;
5809                }
5810        }
5811
5812        if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5813                if (fd == sq->two_fd[i].moved_to)
5814                        return 1;
5815        }
5816        return 0;
5817}
5818
5819/*
5820 * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
5821 * old file descriptors are stashed away so that the redirection can be
5822 * undone by calling popredir.
5823 */
5824/* flags passed to redirect */
5825#define REDIR_PUSH    01        /* save previous values of file descriptors */
5826static void
5827redirect(union node *redir, int flags)
5828{
5829        struct redirtab *sv;
5830
5831        if (!redir)
5832                return;
5833
5834        sv = NULL;
5835        INT_OFF;
5836        if (flags & REDIR_PUSH)
5837                sv = redirlist;
5838        do {
5839                int fd;
5840                int newfd;
5841                int close_fd;
5842                int closed;
5843
5844                fd = redir->nfile.fd;
5845                if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5846                        //bb_error_msg("doing %d > %d", fd, newfd);
5847                        newfd = redir->ndup.dupfd;
5848                        close_fd = -1;
5849                } else {
5850                        newfd = openredirect(redir); /* always >= 0 */
5851                        if (fd == newfd) {
5852                                /* open() gave us precisely the fd we wanted.
5853                                 * This means that this fd was not busy
5854                                 * (not opened to anywhere).
5855                                 * Remember to close it on restore:
5856                                 */
5857                                add_squirrel_closed(sv, fd);
5858                                continue;
5859                        }
5860                        close_fd = newfd;
5861                }
5862
5863                if (fd == newfd)
5864                        continue;
5865
5866                /* if "N>FILE": move newfd to fd */
5867                /* if "N>&M": dup newfd to fd */
5868                /* if "N>&-": close fd (newfd is -1) */
5869
5870 IF_BASH_REDIR_OUTPUT(redirect_more:)
5871
5872                closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5873                if (newfd == -1) {
5874                        /* "N>&-" means "close me" */
5875                        if (!closed) {
5876                                /* ^^^ optimization: saving may already
5877                                 * have closed it. If not... */
5878                                close(fd);
5879                        }
5880                } else {
5881                        /* if newfd is a script fd or saved fd, simulate EBADF */
5882                        if (internally_opened_fd(newfd, sv)) {
5883                                errno = EBADF;
5884                                ash_msg_and_raise_perror("%d", newfd);
5885                        }
5886                        dup2_or_raise(newfd, fd);
5887                        if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5888                                close(close_fd);
5889#if BASH_REDIR_OUTPUT
5890                        if (redir->nfile.type == NTO2 && fd == 1) {
5891                                /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5892                                fd = 2;
5893                                newfd = 1;
5894                                close_fd = -1;
5895                                goto redirect_more;
5896                        }
5897#endif
5898                }
5899        } while ((redir = redir->nfile.next) != NULL);
5900        INT_ON;
5901
5902//dash:#define REDIR_SAVEFD2 03        /* set preverrout */
5903#define REDIR_SAVEFD2 0
5904        // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5905        // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5906        // not only for calls with flags containing REDIR_SAVEFD2.
5907        // We do this unconditionally (see save_fd_on_redirect()).
5908        //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5909        //      preverrout_fd = copied_fd2;
5910}
5911
5912static int
5913redirectsafe(union node *redir, int flags)
5914{
5915        int err;
5916        volatile int saveint;
5917        struct jmploc *volatile savehandler = exception_handler;
5918        struct jmploc jmploc;
5919
5920        SAVE_INT(saveint);
5921        /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5922        err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
5923        if (!err) {
5924                exception_handler = &jmploc;
5925                redirect(redir, flags);
5926        }
5927        exception_handler = savehandler;
5928        if (err && exception_type != EXERROR)
5929                longjmp(exception_handler->loc, 1);
5930        RESTORE_INT(saveint);
5931        return err;
5932}
5933
5934#if BASH_PROCESS_SUBST
5935static void
5936pushfd(int fd)
5937{
5938        struct redirtab *sv;
5939
5940        sv = ckzalloc(sizeof(*sv) + sizeof(sv->two_fd[0]));
5941        sv->pair_count = 1;
5942        sv->two_fd[0].orig_fd = fd;
5943        sv->two_fd[0].moved_to = CLOSED;
5944        sv->next = redirlist;
5945        redirlist = sv;
5946}
5947#endif
5948
5949static struct redirtab*
5950pushredir(union node *redir)
5951{
5952        struct redirtab *sv;
5953        int i;
5954
5955        if (!redir)
5956                return redirlist;
5957
5958        i = 0;
5959        do {
5960                i++;
5961#if BASH_REDIR_OUTPUT
5962                if (redir->nfile.type == NTO2)
5963                        i++;
5964#endif
5965                redir = redir->nfile.next;
5966        } while (redir);
5967
5968        sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5969        sv->pair_count = i;
5970        while (--i >= 0)
5971                sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
5972        sv->next = redirlist;
5973        redirlist = sv;
5974        return sv->next;
5975}
5976
5977/*
5978 * Undo the effects of the last redirection.
5979 */
5980static void
5981popredir(int drop)
5982{
5983        struct redirtab *rp;
5984        int i;
5985
5986        if (redirlist == NULL)
5987                return;
5988        INT_OFF;
5989        rp = redirlist;
5990        for (i = 0; i < rp->pair_count; i++) {
5991                int fd = rp->two_fd[i].orig_fd;
5992                int copy = rp->two_fd[i].moved_to;
5993                if (copy == CLOSED) {
5994                        if (!drop)
5995                                close(fd);
5996                        continue;
5997                }
5998                if (copy != EMPTY) {
5999                        if (!drop) {
6000                                /*close(fd);*/
6001                                dup2_or_raise(copy, fd);
6002                        }
6003                        close(copy);
6004                }
6005        }
6006        redirlist = rp->next;
6007        free(rp);
6008        INT_ON;
6009}
6010
6011static void
6012unwindredir(struct redirtab *stop)
6013{
6014        while (redirlist != stop)
6015                popredir(/*drop:*/ 0);
6016}
6017
6018
6019/* ============ Routines to expand arguments to commands
6020 *
6021 * We have to deal with backquotes, shell variables, and file metacharacters.
6022 */
6023
6024#if ENABLE_FEATURE_SH_MATH
6025static arith_t
6026ash_arith(const char *s)
6027{
6028        arith_state_t math_state;
6029        arith_t result;
6030
6031        math_state.lookupvar = lookupvar;
6032        math_state.setvar    = setvar0;
6033        //math_state.endofname = endofname;
6034
6035        INT_OFF;
6036        result = arith(&math_state, s);
6037        if (math_state.errmsg)
6038                ash_msg_and_raise_error(math_state.errmsg);
6039        INT_ON;
6040
6041        return result;
6042}
6043#endif
6044#if BASH_SUBSTR
6045# if ENABLE_FEATURE_SH_MATH
6046static int substr_atoi(const char *s)
6047{
6048        arith_t t = ash_arith(s);
6049        if (sizeof(t) > sizeof(int)) {
6050                /* clamp very large or very large negative nums for ${v:N:M}:
6051                 * else "${v:0:0x100000001}" would work as "${v:0:1}"
6052                 */
6053                if (t > INT_MAX)
6054                        t = INT_MAX;
6055                if (t < INT_MIN)
6056                        t = INT_MIN;
6057        }
6058        return t;
6059}
6060# else
6061#  define substr_atoi(s) number(s)
6062# endif
6063#endif
6064
6065/*
6066 * expandarg flags
6067 */
6068#define EXP_FULL        0x1     /* perform word splitting & file globbing */
6069#define EXP_TILDE       0x2     /* do normal tilde expansion */
6070#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
6071#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
6072/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
6073 * POSIX says for this case:
6074 *  Pathname expansion shall not be performed on the word by a
6075 *  non-interactive shell; an interactive shell may perform it, but shall
6076 *  do so only when the expansion would result in one word.
6077 * Currently, our code complies to the above rule by never globbing
6078 * redirection filenames.
6079 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
6080 * (this means that on a typical Linux distro, bash almost always
6081 * performs globbing, and thus diverges from what we do).
6082 */
6083#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
6084#define EXP_VARTILDE2   0x20    /* expand tildes after colons only */
6085#define EXP_WORD        0x40    /* expand word in parameter expansion */
6086#define EXP_QUOTED      0x100   /* expand word in double quotes */
6087#define EXP_KEEPNUL     0x200   /* do not skip NUL characters */
6088#define EXP_DISCARD     0x400   /* discard result of expansion */
6089
6090/*
6091 * rmescape() flags
6092 */
6093#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
6094#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
6095#define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
6096#define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
6097
6098/* Add CTLESC when necessary. */
6099#define QUOTES_ESC     (EXP_FULL | EXP_CASE)
6100
6101/*
6102 * Structure specifying which parts of the string should be searched
6103 * for IFS characters.
6104 */
6105struct ifsregion {
6106        struct ifsregion *next; /* next region in list */
6107        int begoff;             /* offset of start of region */
6108        int endoff;             /* offset of end of region */
6109        int nulonly;            /* search for nul bytes only */
6110};
6111
6112struct arglist {
6113        struct strlist *list;
6114        struct strlist **lastp;
6115};
6116
6117/* output of current string */
6118static char *expdest;
6119/* list of back quote expressions */
6120static struct nodelist *argbackq;
6121/* first struct in list of ifs regions */
6122static struct ifsregion ifsfirst;
6123/* last struct in list */
6124static struct ifsregion *ifslastp;
6125/* holds expanded arg list */
6126static struct arglist exparg;
6127
6128/*
6129 * Break the argument string into pieces based upon IFS and add the
6130 * strings to the argument list.  The regions of the string to be
6131 * searched for IFS characters have been stored by recordregion.
6132 */
6133static void
6134ifsbreakup(char *string, struct arglist *arglist)
6135{
6136        struct ifsregion *ifsp;
6137        struct strlist *sp;
6138        char *start;
6139        char *p;
6140        char *q;
6141        const char *ifs, *realifs;
6142        int ifsspc;
6143        int nulonly;
6144
6145        start = string;
6146        if (ifslastp != NULL) {
6147                ifsspc = 0;
6148                nulonly = 0;
6149                realifs = ifsset() ? ifsval() : defifs;
6150                ifsp = &ifsfirst;
6151                do {
6152                        int afternul;
6153
6154                        p = string + ifsp->begoff;
6155                        afternul = nulonly;
6156                        nulonly = ifsp->nulonly;
6157                        ifs = nulonly ? nullstr : realifs;
6158                        ifsspc = 0;
6159                        while (p < string + ifsp->endoff) {
6160                                q = p;
6161                                if ((unsigned char)*p == CTLESC)
6162                                        p++;
6163                                if (!strchr(ifs, *p)) {
6164                                        p++;
6165                                        continue;
6166                                }
6167                                if (!(afternul || nulonly))
6168                                        ifsspc = (strchr(defifs, *p) != NULL);
6169                                /* Ignore IFS whitespace at start */
6170                                if (q == start && ifsspc) {
6171                                        p++;
6172                                        start = p;
6173                                        continue;
6174                                }
6175                                *q = '\0';
6176                                sp = stzalloc(sizeof(*sp));
6177                                sp->text = start;
6178                                *arglist->lastp = sp;
6179                                arglist->lastp = &sp->next;
6180                                p++;
6181                                if (!nulonly) {
6182                                        for (;;) {
6183                                                if (p >= string + ifsp->endoff) {
6184                                                        break;
6185                                                }
6186                                                q = p;
6187                                                if ((unsigned char)*p == CTLESC)
6188                                                        p++;
6189                                                if (strchr(ifs, *p) == NULL) {
6190                                                        p = q;
6191                                                        break;
6192                                                }
6193                                                if (strchr(defifs, *p) == NULL) {
6194                                                        if (ifsspc) {
6195                                                                p++;
6196                                                                ifsspc = 0;
6197                                                        } else {
6198                                                                p = q;
6199                                                                break;
6200                                                        }
6201                                                } else
6202                                                        p++;
6203                                        }
6204                                }
6205                                start = p;
6206                        } /* while */
6207                        ifsp = ifsp->next;
6208                } while (ifsp != NULL);
6209                if (nulonly)
6210                        goto add;
6211        }
6212
6213        if (!*start)
6214                return;
6215
6216 add:
6217        sp = stzalloc(sizeof(*sp));
6218        sp->text = start;
6219        *arglist->lastp = sp;
6220        arglist->lastp = &sp->next;
6221}
6222
6223static void
6224ifsfree(void)
6225{
6226        struct ifsregion *p = ifsfirst.next;
6227
6228        if (!p)
6229                goto out;
6230
6231        INT_OFF;
6232        do {
6233                struct ifsregion *ifsp;
6234                ifsp = p->next;
6235                free(p);
6236                p = ifsp;
6237        } while (p);
6238        ifsfirst.next = NULL;
6239        INT_ON;
6240 out:
6241        ifslastp = NULL;
6242}
6243
6244static size_t
6245esclen(const char *start, const char *p)
6246{
6247        size_t esc = 0;
6248
6249        while (p > start && (unsigned char)*--p == CTLESC) {
6250                esc++;
6251        }
6252        return esc;
6253}
6254
6255/*
6256 * Remove any CTLESC characters from a string.
6257 */
6258#if !BASH_PATTERN_SUBST
6259#define rmescapes(str, flag, slash_position) \
6260        rmescapes(str, flag)
6261#endif
6262static char *
6263rmescapes(char *str, int flag, int *slash_position)
6264{
6265        static const char qchars[] ALIGN1 = {
6266                IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
6267
6268        char *p, *q, *r;
6269        unsigned protect_against_glob;
6270        unsigned globbing;
6271
6272        p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
6273        if (!p)
6274                return str;
6275
6276        q = p;
6277        r = str;
6278        if (flag & RMESCAPE_ALLOC) {
6279                size_t len = p - str;
6280                size_t fulllen = len + strlen(p) + 1;
6281
6282                if (flag & RMESCAPE_GROW) {
6283                        int strloc = str - (char *)stackblock();
6284                        r = makestrspace(fulllen, expdest);
6285                        /* p and str may be invalidated by makestrspace */
6286                        str = (char *)stackblock() + strloc;
6287                        p = str + len;
6288                } else if (flag & RMESCAPE_HEAP) {
6289                        r = ckmalloc(fulllen);
6290                } else {
6291                        r = stalloc(fulllen);
6292                }
6293                q = r;
6294                if (len > 0) {
6295                        q = (char *)mempcpy(q, str, len);
6296                }
6297        }
6298
6299        globbing = flag & RMESCAPE_GLOB;
6300        protect_against_glob = globbing;
6301        while (*p) {
6302                if ((unsigned char)*p == CTLQUOTEMARK) {
6303// Note: protect_against_glob only affect whether
6304// CTLESC,<ch> gets converted to <ch> or to \<ch>
6305                        p++;
6306                        protect_against_glob = globbing;
6307                        continue;
6308                }
6309                if (*p == '\\') {
6310                        /* naked back slash */
6311                        protect_against_glob = 0;
6312                        goto copy;
6313                }
6314                if ((unsigned char)*p == CTLESC) {
6315                        p++;
6316#if DEBUG
6317                        if (*p == '\0')
6318                                ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6319#endif
6320                        if (protect_against_glob) {
6321                                /*
6322                                 * We used to trust glob() and fnmatch() to eat
6323                                 * superfluous escapes (\z where z has no
6324                                 * special meaning anyway). But this causes
6325                                 * bugs such as string of one greek letter rho
6326                                 * (unicode-encoded as two bytes "cf,81")
6327                                 * getting encoded as "cf,CTLESC,81"
6328                                 * and here, converted to "cf,\,81" -
6329                                 * which does not go well with some flavors
6330                                 * of fnmatch() in unicode locales
6331                                 * (for example, glibc <= 2.22).
6332                                 *
6333                                 * Lets add "\" only on the chars which need it.
6334                                 * Testcases for less obvious chars are shown.
6335                                 */
6336                                if (*p == '*'
6337                                 || *p == '?'
6338                                 || *p == '['
6339                                 || *p == '\\' /* case '\' in \\    ) echo ok;; *) echo WRONG;; esac */
6340                                 || *p == ']'  /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6341                                 || *p == '-'  /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6342                                 || *p == '!'  /* case '!' in [\!]  ) echo ok;; *) echo WRONG;; esac */
6343                                /* Some libc support [^negate], that's why "^" also needs love */
6344                                 || *p == '^'  /* case '^' in [\^]  ) echo ok;; *) echo WRONG;; esac */
6345                                ) {
6346                                        *q++ = '\\';
6347                                }
6348                        }
6349                }
6350#if BASH_PATTERN_SUBST
6351                else if (slash_position && p == str + *slash_position) {
6352                        /* stop handling globbing */
6353                        globbing = 0;
6354                        *slash_position = q - r;
6355                        slash_position = NULL;
6356                }
6357#endif
6358                protect_against_glob = globbing;
6359 copy:
6360                *q++ = *p++;
6361        }
6362        *q = '\0';
6363        if (flag & RMESCAPE_GROW) {
6364                expdest = r;
6365                STADJUST(q - r + 1, expdest);
6366        }
6367        return r;
6368}
6369#define pmatch(a, b) !fnmatch((a), (b), 0)
6370
6371/*
6372 * Prepare a pattern for a expmeta (internal glob(3)) call.
6373 *
6374 * Returns an stalloced string.
6375 */
6376static char *
6377preglob(const char *pattern, int flag)
6378{
6379        return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
6380}
6381
6382/*
6383 * Put a string on the stack.
6384 */
6385static size_t
6386memtodest(const char *p, size_t len, int flags)
6387{
6388        int syntax = flags & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6389        char *q;
6390        char *s;
6391
6392        if (!len)
6393                return 0;
6394
6395        q = makestrspace(len * 2, expdest);
6396        s = q;
6397
6398        do {
6399                unsigned char c = *p++;
6400                if (c) {
6401                        if (flags & QUOTES_ESC) {
6402                                int n = SIT(c, syntax);
6403                                if (n == CCTL
6404                                 || ((flags & EXP_QUOTED) && n == CBACK)
6405                                ) {
6406                                        USTPUTC(CTLESC, q);
6407                                }
6408                        }
6409                } else if (!(flags & EXP_KEEPNUL))
6410                        continue;
6411                USTPUTC(c, q);
6412        } while (--len);
6413
6414        expdest = q;
6415        return q - s;
6416}
6417
6418static size_t
6419strtodest(const char *p, int flags)
6420{
6421        size_t len = strlen(p);
6422        memtodest(p, len, flags);
6423        return len;
6424}
6425
6426/*
6427 * Our own itoa().
6428 * cvtnum() is used even if math support is off (to prepare $? values and such).
6429 */
6430static int
6431cvtnum(arith_t num, int flags)
6432{
6433        /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
6434        /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
6435        int len = (sizeof(arith_t) >= 4) ? sizeof(arith_t) * 3 : sizeof(arith_t) * 3 + 2;
6436        char buf[len];
6437
6438        len = fmtstr(buf, len, ARITH_FMT, num);
6439        return memtodest(buf, len, flags);
6440}
6441
6442/*
6443 * Record the fact that we have to scan this region of the
6444 * string for IFS characters.
6445 */
6446static void
6447recordregion(int start, int end, int nulonly)
6448{
6449        struct ifsregion *ifsp;
6450
6451        if (ifslastp == NULL) {
6452                ifsp = &ifsfirst;
6453        } else {
6454                INT_OFF;
6455                ifsp = ckzalloc(sizeof(*ifsp));
6456                /*ifsp->next = NULL; - ckzalloc did it */
6457                ifslastp->next = ifsp;
6458                INT_ON;
6459        }
6460        ifslastp = ifsp;
6461        ifslastp->begoff = start;
6462        ifslastp->endoff = end;
6463        ifslastp->nulonly = nulonly;
6464}
6465
6466static void
6467removerecordregions(int endoff)
6468{
6469        if (ifslastp == NULL)
6470                return;
6471
6472        if (ifsfirst.endoff > endoff) {
6473                while (ifsfirst.next) {
6474                        struct ifsregion *ifsp;
6475                        INT_OFF;
6476                        ifsp = ifsfirst.next->next;
6477                        free(ifsfirst.next);
6478                        ifsfirst.next = ifsp;
6479                        INT_ON;
6480                }
6481                if (ifsfirst.begoff > endoff) {
6482                        ifslastp = NULL;
6483                } else {
6484                        ifslastp = &ifsfirst;
6485                        ifsfirst.endoff = endoff;
6486                }
6487                return;
6488        }
6489
6490        ifslastp = &ifsfirst;
6491        while (ifslastp->next && ifslastp->next->begoff < endoff)
6492                ifslastp = ifslastp->next;
6493        while (ifslastp->next) {
6494                struct ifsregion *ifsp;
6495                INT_OFF;
6496                ifsp = ifslastp->next->next;
6497                free(ifslastp->next);
6498                ifslastp->next = ifsp;
6499                INT_ON;
6500        }
6501        if (ifslastp->endoff > endoff)
6502                ifslastp->endoff = endoff;
6503}
6504
6505static char *
6506exptilde(char *startp, int flag)
6507{
6508        unsigned char c;
6509        char *name;
6510        struct passwd *pw;
6511        const char *home;
6512        char *p;
6513
6514        p = startp;
6515        name = p + 1;
6516
6517        while ((c = *++p) != '\0') {
6518                switch (c) {
6519                case CTLESC:
6520                        return startp;
6521                case CTLQUOTEMARK:
6522                        return startp;
6523                case ':':
6524                        if (flag & EXP_VARTILDE)
6525                                goto done;
6526                        break;
6527                case '/':
6528                case CTLENDVAR:
6529                        goto done;
6530                }
6531        }
6532 done:
6533        if (flag & EXP_DISCARD)
6534                goto out;
6535        *p = '\0';
6536        if (*name == '\0') {
6537                home = lookupvar("HOME");
6538        } else {
6539                pw = getpwnam(name);
6540                home = pw ? pw->pw_dir : NULL;
6541        }
6542        *p = c;
6543        if (!home)
6544                goto lose;
6545        strtodest(home, flag | EXP_QUOTED);
6546 out:
6547        return p;
6548 lose:
6549        return startp;
6550}
6551
6552/*
6553 * Execute a command inside back quotes.  If it's a builtin command, we
6554 * want to save its output in a block obtained from malloc.  Otherwise
6555 * we fork off a subprocess and get the output of the command via a pipe.
6556 * Should be called with interrupts off.
6557 */
6558struct backcmd {                /* result of evalbackcmd */
6559        int fd;                 /* file descriptor to read from */
6560        int nleft;              /* number of chars in buffer */
6561        char *buf;              /* buffer */
6562        struct job *jp;         /* job structure for command */
6563};
6564
6565/* These forward decls are needed to use "eval" code for backticks handling: */
6566/* flags in argument to evaltree */
6567#define EV_EXIT    01           /* exit after evaluating tree */
6568#define EV_TESTED  02           /* exit status is checked; ignore -e flag */
6569static int evaltree(union node *, int);
6570
6571/* An evaltree() which is known to never return.
6572 * Used to use an alias:
6573 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6574 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6575 */
6576static ALWAYS_INLINE NORETURN void
6577evaltreenr(union node *n, int flags)
6578{
6579        evaltree(n, flags);
6580        bb_unreachable(abort());
6581        /* NOTREACHED */
6582}
6583
6584static void FAST_FUNC
6585evalbackcmd(union node *n, struct backcmd *result
6586                                IF_BASH_PROCESS_SUBST(, int ctl))
6587{
6588        int pip[2];
6589        struct job *jp;
6590#if BASH_PROCESS_SUBST
6591        /* determine end of pipe used by parent (ip) and child (ic) */
6592        const int ip = (ctl == CTLTOPROC);
6593        const int ic = !(ctl == CTLTOPROC);
6594#else
6595        const int ctl = CTLBACKQ;
6596        const int ip = 0;
6597        const int ic = 1;
6598#endif
6599
6600        result->fd = -1;
6601        result->buf = NULL;
6602        result->nleft = 0;
6603        result->jp = NULL;
6604        if (n == NULL) {
6605                goto out;
6606        }
6607
6608        if (pipe(pip) < 0)
6609                ash_msg_and_raise_perror("can't create pipe");
6610        /* process substitution uses NULL job/node, like openhere() */
6611        jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL;
6612        if (forkshell(jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB) == 0) {
6613                /* child */
6614                FORCE_INT_ON;
6615                close(pip[ip]);
6616                /* ic is index of child end of pipe *and* fd to connect it to */
6617                if (pip[ic] != ic) {
6618                        /*close(ic);*/
6619                        dup2_or_raise(pip[ic], ic);
6620                        close(pip[ic]);
6621                }
6622/* TODO: eflag clearing makes the following not abort:
6623 *  ash -c 'set -e; z=$(false;echo foo); echo $z'
6624 * which is what bash does (unless it is in POSIX mode).
6625 * dash deleted "eflag = 0" line in the commit
6626 *  Date: Mon, 28 Jun 2010 17:11:58 +1000
6627 *  [EVAL] Don't clear eflag in evalbackcmd
6628 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6629 */
6630                eflag = 0;
6631                ifsfree();
6632                evaltreenr(n, EV_EXIT);
6633                /* NOTREACHED */
6634        }
6635        /* parent */
6636#if BASH_PROCESS_SUBST
6637        if (ctl != CTLBACKQ) {
6638                int fd = fcntl(pip[ip], F_DUPFD, 64);
6639                if (fd > 0) {
6640                        close(pip[ip]);
6641                        pip[ip] = fd;
6642                }
6643                pushfd(pip[ip]);
6644        }
6645#endif
6646        close(pip[ic]);
6647        result->fd = pip[ip];
6648        result->jp = jp;
6649
6650 out:
6651        TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6652                result->fd, result->buf, result->nleft, result->jp));
6653}
6654
6655/*
6656 * Expand stuff in backwards quotes.
6657 */
6658static void
6659expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl))
6660{
6661#if !BASH_PROCESS_SUBST
6662        const int ctl = CTLBACKQ;
6663#endif
6664        struct backcmd in;
6665        int i;
6666        char buf[128];
6667        char *p;
6668        char *dest;
6669        int startloc;
6670        struct stackmark smark;
6671
6672        if (flag & EXP_DISCARD)
6673                goto out;
6674
6675        INT_OFF;
6676        startloc = expdest - (char *)stackblock();
6677        pushstackmark(&smark, startloc);
6678        evalbackcmd(cmd, &in IF_BASH_PROCESS_SUBST(, ctl));
6679        popstackmark(&smark);
6680
6681        if (ctl != CTLBACKQ) {
6682                sprintf(buf, DEV_FD_PREFIX"%d", in.fd);
6683                strtodest(buf, BASESYNTAX);
6684                goto done;
6685        }
6686
6687        p = in.buf;
6688        i = in.nleft;
6689        if (i == 0)
6690                goto read;
6691        for (;;) {
6692                memtodest(p, i, flag);
6693 read:
6694                if (in.fd < 0)
6695                        break;
6696                i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6697                TRACE(("expbackq: read returns %d\n", i));
6698                if (i <= 0)
6699                        break;
6700                p = buf;
6701        }
6702
6703        free(in.buf);
6704        if (in.fd >= 0) {
6705                close(in.fd);
6706                back_exitstatus = waitforjob(in.jp);
6707        }
6708 done:
6709        INT_ON;
6710
6711        /* Eat all trailing newlines */
6712        dest = expdest;
6713        for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';)
6714                STUNPUTC(dest);
6715        expdest = dest;
6716
6717        if (!(flag & EXP_QUOTED))
6718                recordregion(startloc, dest - (char *)stackblock(), 0);
6719        TRACE(("evalbackq: size:%d:'%.*s'\n",
6720                (int)((dest - (char *)stackblock()) - startloc),
6721                (int)((dest - (char *)stackblock()) - startloc),
6722                stackblock() + startloc));
6723
6724 out:
6725        argbackq = argbackq->next;
6726}
6727
6728/* expari needs it */
6729static char *argstr(char *p, int flag);
6730
6731#if ENABLE_FEATURE_SH_MATH
6732/*
6733 * Expand arithmetic expression.  Backup to start of expression,
6734 * evaluate, place result in (backed up) result, adjust string position.
6735 */
6736static char *
6737expari(char *start, int flag)
6738{
6739        struct stackmark sm;
6740        int begoff;
6741        int endoff;
6742        int len;
6743        arith_t result;
6744        char *p;
6745
6746        p = stackblock();
6747        begoff = expdest - p;
6748        p = argstr(start, flag & EXP_DISCARD);
6749
6750        if (flag & EXP_DISCARD)
6751                goto out;
6752
6753        start = stackblock();
6754        endoff = expdest - start;
6755        start += begoff;
6756        STADJUST(start - expdest, expdest);
6757
6758        removerecordregions(begoff);
6759
6760        if (flag & QUOTES_ESC)
6761                rmescapes(start, 0, NULL);
6762
6763        pushstackmark(&sm, endoff);
6764        result = ash_arith(start);
6765        popstackmark(&sm);
6766
6767        len = cvtnum(result, flag);
6768
6769        if (!(flag & EXP_QUOTED))
6770                recordregion(begoff, begoff + len, 0);
6771
6772 out:
6773        return p;
6774}
6775#endif
6776
6777/* argstr needs it */
6778static char *evalvar(char *p, int flags);
6779
6780/*
6781 * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
6782 * characters to allow for further processing.  Otherwise treat
6783 * $@ like $* since no splitting will be performed.
6784 */
6785static char *
6786argstr(char *p, int flag)
6787{
6788        static const char spclchars[] ALIGN1 = {
6789                '=',
6790                ':',
6791                CTLQUOTEMARK,
6792                CTLENDVAR,
6793                CTLESC,
6794                CTLVAR,
6795                CTLBACKQ,
6796#if BASH_PROCESS_SUBST
6797                CTLTOPROC,
6798                CTLFROMPROC,
6799#endif
6800#if ENABLE_FEATURE_SH_MATH
6801                CTLARI,
6802                CTLENDARI,
6803#endif
6804                '\0'
6805        };
6806        const char *reject = spclchars;
6807        int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6808        int inquotes;
6809        size_t length;
6810        int startloc;
6811
6812        reject += !!(flag & EXP_VARTILDE2);
6813        reject += flag & EXP_VARTILDE ? 0 : 2;
6814        inquotes = 0;
6815        length = 0;
6816        if (flag & EXP_TILDE) {
6817                flag &= ~EXP_TILDE;
6818 tilde:
6819                if (*p == '~')
6820                        p = exptilde(p, flag);
6821        }
6822 start:
6823        startloc = expdest - (char *)stackblock();
6824        for (;;) {
6825                int end;
6826                unsigned char c;
6827
6828                length += strcspn(p + length, reject);
6829                end = 0;
6830                c = p[length];
6831                if (!(c & 0x80)
6832                 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6833                 || c == CTLENDVAR
6834                ) {
6835                        /*
6836                         * c == '=' || c == ':' || c == '\0' ||
6837                         * c == CTLENDARI || c == CTLENDVAR
6838                         */
6839                        length++;
6840                        /* c == '\0' || c == CTLENDARI || c == CTLENDVAR */
6841                        end = !!((c - 1) & 0x80);
6842                }
6843                if (length > 0 && !(flag & EXP_DISCARD)) {
6844                        int newloc;
6845                        char *q;
6846
6847                        q = stnputs(p, length, expdest);
6848                        q[-1] &= end - 1;
6849                        expdest = q - (flag & EXP_WORD ? end : 0);
6850                        newloc = q - (char *)stackblock() - end;
6851                        if (breakall && !inquotes && newloc > startloc) {
6852                                recordregion(startloc, newloc, 0);
6853                        }
6854                        startloc = newloc;
6855                }
6856                p += length + 1;
6857                length = 0;
6858
6859                if (end)
6860                        break;
6861
6862                switch (c) {
6863                case '=':
6864                        flag |= EXP_VARTILDE2;
6865                        reject++;
6866                        /* fall through */
6867                case ':':
6868                        /*
6869                         * sort of a hack - expand tildes in variable
6870                         * assignments (after the first '=' and after ':'s).
6871                         */
6872                        if (*--p == '~') {
6873                                goto tilde;
6874                        }
6875                        continue;
6876                case CTLQUOTEMARK:
6877                        /* "$@" syntax adherence hack */
6878                        if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6879                                p = evalvar(p + 1, flag | EXP_QUOTED) + 1;
6880                                goto start;
6881                        }
6882                        inquotes ^= EXP_QUOTED;
6883 addquote:
6884                        if (flag & QUOTES_ESC) {
6885                                p--;
6886                                length++;
6887                                startloc++;
6888                        }
6889                        break;
6890                case CTLESC:
6891                        startloc++;
6892                        length++;
6893                        goto addquote;
6894                case CTLVAR:
6895                        TRACE(("argstr: evalvar('%s')\n", p));
6896                        p = evalvar(p, flag | inquotes);
6897                        TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6898                        goto start;
6899#if BASH_PROCESS_SUBST
6900                case CTLTOPROC:
6901                case CTLFROMPROC:
6902#endif
6903                case CTLBACKQ:
6904                        expbackq(argbackq->n, flag | inquotes IF_BASH_PROCESS_SUBST(, c));
6905                        goto start;
6906#if ENABLE_FEATURE_SH_MATH
6907                case CTLARI:
6908                        p = expari(p, flag | inquotes);
6909                        goto start;
6910#endif
6911                }
6912        }
6913        return p - 1;
6914}
6915
6916static char *
6917scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6918                char *pattern, int quotes, int zero)
6919{
6920        char *loc, *loc2;
6921        char c;
6922
6923        loc = startp;
6924        loc2 = rmesc;
6925        do {
6926                int match;
6927                const char *s = loc2;
6928
6929                c = *loc2;
6930                if (zero) {
6931                        *loc2 = '\0';
6932                        s = rmesc;
6933                }
6934                match = pmatch(pattern, s);
6935
6936                *loc2 = c;
6937                if (match)
6938                        return loc;
6939                if (quotes && (unsigned char)*loc == CTLESC)
6940                        loc++;
6941                loc++;
6942                loc2++;
6943        } while (c);
6944        return NULL;
6945}
6946
6947static char *
6948scanright(char *startp, char *rmesc, char *rmescend,
6949                char *pattern, int quotes, int match_at_start)
6950{
6951#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6952        int try2optimize = match_at_start;
6953#endif
6954        int esc = 0;
6955        char *loc;
6956        char *loc2;
6957
6958        /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6959         * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6960         * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6961         * Logic:
6962         * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6963         * and on each iteration they go back two/one char until they reach the beginning.
6964         * We try to match "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6965         * If one of these matches, return pointer past last matched char in startp.
6966         */
6967        /* TODO: document in what other circumstances we are called. */
6968
6969        for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6970                int match;
6971                char c = *loc2;
6972                const char *s = loc2;
6973                if (match_at_start) {
6974                        *loc2 = '\0';
6975                        s = rmesc;
6976                }
6977                match = pmatch(pattern, s);
6978                //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6979                *loc2 = c;
6980                if (match)
6981                        return loc;
6982#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6983                if (try2optimize) {
6984                        /* Maybe we can optimize this:
6985                         * if pattern ends with unescaped *, we can avoid checking
6986                         * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6987                         * it won't match truncated "raw_value_of_" strings too.
6988                         */
6989                        unsigned plen = strlen(pattern);
6990                        /* Does it end with "*"? */
6991                        if (plen != 0 && pattern[--plen] == '*') {
6992                                /* "xxxx*" is not escaped */
6993                                /* "xxx\*" is escaped */
6994                                /* "xx\\*" is not escaped */
6995                                /* "x\\\*" is escaped */
6996                                int slashes = 0;
6997                                while (plen != 0 && pattern[--plen] == '\\')
6998                                        slashes++;
6999                                if (!(slashes & 1))
7000                                        break; /* ends with unescaped "*" */
7001                        }
7002                        try2optimize = 0;
7003                }
7004#endif
7005                loc--;
7006                if (quotes) {
7007                        if (--esc < 0) {
7008                                esc = esclen(startp, loc);
7009                        }
7010                        if (esc % 2) {
7011                                esc--;
7012                                loc--;
7013                        }
7014                }
7015        }
7016        return NULL;
7017}
7018
7019static void varunset(const char *, const char *, const char *, int) NORETURN;
7020static void
7021varunset(const char *end, const char *var, const char *umsg, int varflags)
7022{
7023        const char *msg;
7024        const char *tail;
7025
7026        tail = nullstr;
7027        msg = "parameter not set";
7028        if (umsg) {
7029                if ((unsigned char)*end == CTLENDVAR) {
7030                        if (varflags & VSNUL)
7031                                tail = " or null";
7032                } else {
7033                        msg = umsg;
7034                }
7035        }
7036        ifsfree();
7037        ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
7038}
7039
7040static char *
7041subevalvar(char *start, char *str, int strloc,
7042                int startloc, int varflags, int flag)
7043{
7044        int subtype = varflags & VSTYPE;
7045        int quotes = flag & QUOTES_ESC;
7046        char *startp;
7047        char *loc;
7048        char *rmesc, *rmescend;
7049        long amount;
7050        int resetloc;
7051        int argstr_flags;
7052        IF_BASH_PATTERN_SUBST(int workloc;)
7053        IF_BASH_PATTERN_SUBST(int slash_pos;)
7054        IF_BASH_PATTERN_SUBST(char *repl;)
7055        int zero;
7056        char *(*scan)(char*, char*, char*, char*, int, int);
7057        char *p;
7058
7059        //bb_error_msg("subevalvar(start:'%s',str:'%s',strloc:%d,startloc:%d,varflags:%x,quotes:%d)",
7060        //              start, str, strloc, startloc, varflags, quotes);
7061
7062#if BASH_PATTERN_SUBST
7063        /* For "${v/pattern/repl}", we must find the delimiter _before_
7064         * argstr() call expands possible variable references in pattern:
7065         * think about "v=a; a=a/; echo ${v/$a/r}" case.
7066         */
7067        repl = NULL;
7068        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7069                /* Find '/' and replace with NUL */
7070                repl = start;
7071                /* The pattern can't be empty.
7072                 * IOW: if the first char after "${v//" is a slash,
7073                 * it does not terminate the pattern - it's the first char of the pattern:
7074                 *  v=/dev/ram; echo ${v////-}  prints -dev-ram (pattern is "/")
7075                 *  v=/dev/ram; echo ${v///r/-} prints /dev-am  (pattern is "/r")
7076                 */
7077                if (*repl == '/')
7078                        repl++;
7079                for (;;) {
7080                        if (*repl == '\0') {
7081                                repl = NULL;
7082                                break;
7083                        }
7084                        if (*repl == '/') {
7085                                *repl = '\0';
7086                                break;
7087                        }
7088                        if ((unsigned char)*repl == CTLENDVAR) { /* ${v/pattern} (no trailing /, no repl) */
7089                                repl = NULL;
7090                                break;
7091                        }
7092                        /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
7093                        if ((unsigned char)*repl == CTLESC && repl[1])
7094                                repl++;
7095                        repl++;
7096                }
7097        }
7098#endif
7099        argstr_flags = (flag & EXP_DISCARD) | EXP_TILDE;
7100        if (!str
7101#if BASH_SUBSTR
7102         && subtype != VSSUBSTR
7103#endif
7104        ) {
7105                /* EXP_CASE keeps CTLESC's */
7106                argstr_flags |= EXP_CASE;
7107        }
7108        p = argstr(start, argstr_flags);
7109
7110        //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
7111#if BASH_PATTERN_SUBST
7112        slash_pos = -1;
7113        if (repl) {
7114                slash_pos = expdest - ((char *)stackblock() + strloc);
7115                if (!(flag & EXP_DISCARD))
7116                        STPUTC('/', expdest);
7117                //bb_error_msg("repl+1:'%s'", repl + 1);
7118                p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
7119                *repl = '/';
7120        }
7121#endif
7122        if (flag & EXP_DISCARD)
7123                return p;
7124
7125        startp = (char *)stackblock() + startloc;
7126        //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
7127
7128        switch (subtype) {
7129        case VSASSIGN:
7130                setvar0(str, startp);
7131
7132                loc = startp;
7133                goto out;
7134
7135        case VSQUESTION:
7136                varunset(start, str, startp, varflags);
7137                /* NOTREACHED */
7138
7139#if BASH_SUBSTR
7140        case VSSUBSTR: {
7141                int pos, len, orig_len;
7142                char *colon;
7143                char *vstr;
7144
7145                loc = vstr = stackblock() + strloc;
7146
7147                /* Read POS in ${var:POS:LEN} */
7148                colon = strchr(loc, ':');
7149                if (colon) *colon = '\0';
7150                pos = substr_atoi(loc);
7151                if (colon) *colon = ':';
7152
7153                /* Read LEN in ${var:POS:LEN} */
7154                len = vstr - startp - 1;
7155                /* *loc != '\0', guaranteed by parser */
7156                if (quotes) {
7157                        char *ptr;
7158                        /* Adjust the length by the number of escapes */
7159                        for (ptr = startp; ptr < (vstr - 1); ptr++) {
7160                                if ((unsigned char)*ptr == CTLESC) {
7161                                        len--;
7162                                        ptr++;
7163                                }
7164                        }
7165                }
7166                orig_len = len;
7167                if (*loc++ == ':') {
7168                        /* ${var::LEN} */
7169                        len = substr_atoi(loc);
7170                } else {
7171                        /* Skip POS in ${var:POS:LEN} */
7172                        len = orig_len;
7173                        while (*loc && *loc != ':')
7174                                loc++;
7175                        if (*loc++ == ':')
7176                                len = substr_atoi(loc);
7177                }
7178                if (pos < 0) {
7179                        /* ${VAR:$((-n)):l} starts n chars from the end */
7180                        pos = orig_len + pos;
7181                }
7182                if ((unsigned)pos >= orig_len) {
7183                        /* apart from obvious ${VAR:999999:l},
7184                         * covers ${VAR:$((-9999999)):l} - result is ""
7185                         * (bash compat)
7186                         */
7187                        pos = 0;
7188                        len = 0;
7189                }
7190                if (len < 0) {
7191                        /* ${VAR:N:-M} sets LEN to strlen()-M */
7192                        len = (orig_len - pos) + len;
7193                }
7194                if ((unsigned)len > (orig_len - pos))
7195                        len = orig_len - pos;
7196
7197                if (!quotes) {
7198                        /* want: loc = mempcpy(startp, startp + pos, len)
7199                         * but it does not allow overlapping arguments */
7200                        loc = startp;
7201                        while (--len >= 0) {
7202                                *loc = loc[pos];
7203                                loc++;
7204                        }
7205                } else {
7206                        for (vstr = startp; pos != 0; pos--) {
7207                                if ((unsigned char)*vstr == CTLESC)
7208                                        vstr++;
7209                                vstr++;
7210                        }
7211                        for (loc = startp; len != 0; len--) {
7212                                if ((unsigned char)*vstr == CTLESC)
7213                                        *loc++ = *vstr++;
7214                                *loc++ = *vstr++;
7215                        }
7216                }
7217                *loc = '\0';
7218                goto out;
7219        }
7220#endif /* BASH_SUBSTR */
7221        }
7222
7223        resetloc = expdest - (char *)stackblock();
7224
7225#if BASH_PATTERN_SUBST
7226        repl = NULL;
7227
7228        /* We'll comeback here if we grow the stack while handling
7229         * a VSREPLACE or VSREPLACEALL, since our pointers into the
7230         * stack will need rebasing, and we'll need to remove our work
7231         * areas each time
7232         */
7233 restart:
7234#endif
7235
7236        amount = expdest - ((char *)stackblock() + resetloc);
7237        STADJUST(-amount, expdest);
7238        startp = (char *)stackblock() + startloc;
7239
7240        rmesc = startp;
7241        rmescend = (char *)stackblock() + strloc;
7242        //bb_error_msg("str7:'%s'", rmescend);
7243        if (quotes) {
7244//TODO: how to handle slash_pos here if string changes (shortens?)
7245                rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
7246                if (rmesc != startp) {
7247                        rmescend = expdest;
7248                        startp = (char *)stackblock() + startloc;
7249                }
7250        }
7251        rmescend--;
7252        str = (char *)stackblock() + strloc;
7253        /*
7254         * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7255         * The result is a_\_z_c (not a\_\_z_c)!
7256         *
7257         * The search pattern and replace string treat backslashes differently!
7258         * "&slash_pos" causes rmescapes() to work differently on the pattern
7259         * and string.  It's only used on the first call.
7260         */
7261        //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7262        rmescapes(str, RMESCAPE_GLOB,
7263                repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7264        );
7265
7266#if BASH_PATTERN_SUBST
7267        workloc = expdest - (char *)stackblock();
7268        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7269                size_t no_meta_len, first_escaped;
7270                int len;
7271                char *idx, *end;
7272
7273                if (!repl) {
7274                        //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
7275                        repl = nullstr;
7276                        if (slash_pos >= 0) {
7277                                repl = str + slash_pos;
7278                                *repl++ = '\0';
7279                        }
7280                }
7281                //bb_error_msg("str:'%s' repl:'%s'", str, repl);
7282
7283                /* If there's no pattern to match, return the expansion unmolested */
7284                if (str[0] == '\0')
7285                        goto out1;
7286
7287                first_escaped = (str[0] == '\\' && str[1]);
7288                /* "first_escaped" trick allows to treat e.g. "\*no_glob_chars"
7289                 * as literal too (as it is semi-common, and easy to accomodate
7290                 * by just using str + 1).
7291                 */
7292                no_meta_len = strpbrk(str + first_escaped * 2, "*?[\\") ? 0 : strlen(str);
7293                len = 0;
7294                idx = startp;
7295                end = str - 1;
7296                while (idx <= end) {
7297 try_to_match:
7298                        if (no_meta_len == 0) {
7299                                /* pattern has meta chars, have to glob */
7300                                loc = scanright(idx, rmesc, rmescend, str, quotes, /*match_at_start:*/ 1);
7301                        } else {
7302                                /* Testcase for very slow replace (performs about 22k replaces):
7303                                 * x=::::::::::::::::::::::
7304                                 * x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;echo ${#x}
7305                                 * echo "${x//:/|}"
7306                                 * To test "first_escaped" logic, replace : with *.
7307                                 */
7308                                if (strncmp(rmesc, str + first_escaped, no_meta_len - first_escaped) != 0)
7309                                        goto no_match;
7310                                loc = idx;
7311                                if (!quotes) {
7312                                        loc += no_meta_len - first_escaped;
7313                                } else {
7314                                        size_t n = no_meta_len - first_escaped;
7315                                        do {
7316                                                if ((unsigned char)*loc == CTLESC)
7317                                                        loc++;
7318                                                loc++;
7319                                        } while (--n != 0);
7320                                }
7321                        }
7322                        //bb_error_msg("scanright('%s'):'%s'", str, loc);
7323                        if (!loc) {
7324                                char *restart_detect;
7325 no_match:
7326                                /* No match, advance */
7327                                restart_detect = stackblock();
7328 skip_matching:
7329                                if (idx >= end)
7330                                        break;
7331                                STPUTC(*idx, expdest);
7332                                if (stackblock() != restart_detect)
7333                                        goto restart;
7334                                if (quotes && (unsigned char)*idx == CTLESC) {
7335                                        idx++;
7336                                        len++;
7337                                        STPUTC(*idx, expdest);
7338                                        if (stackblock() != restart_detect)
7339                                                goto restart;
7340                                }
7341                                idx++;
7342                                len++;
7343                                rmesc++;
7344                                /* continue; - prone to quadratic behavior, smarter code: */
7345                                if (str[0] == '*') {
7346                                        /* Pattern is "*foo". If "*foo" does not match "long_string",
7347                                         * it would never match "ong_string" etc, no point in trying.
7348                                         */
7349                                        goto skip_matching;
7350                                }
7351                                goto try_to_match;
7352                        }
7353
7354                        if (subtype == VSREPLACEALL) {
7355                                while (idx < loc) {
7356                                        if (quotes && (unsigned char)*idx == CTLESC)
7357                                                idx++;
7358                                        idx++;
7359                                        rmesc++;
7360                                }
7361                        } else {
7362                                idx = loc;
7363                        }
7364
7365                        /* The STPUTC invocations above may resize and move the
7366                         * stack via realloc(3). Since repl is a pointer into the
7367                         * stack, we need to reconstruct it relative to stackblock().
7368                         */
7369                        if (slash_pos >= 0)
7370                                repl = (char *)stackblock() + strloc + slash_pos + 1;
7371
7372                        //bb_error_msg("repl:'%s'", repl);
7373                        for (loc = (char*)repl; *loc; loc++) {
7374                                char *restart_detect = stackblock();
7375                                if (quotes && *loc == '\\') {
7376                                        STPUTC(CTLESC, expdest);
7377                                        len++;
7378                                }
7379                                STPUTC(*loc, expdest);
7380                                if (stackblock() != restart_detect)
7381                                        goto restart;
7382                                len++;
7383                        }
7384
7385                        if (subtype == VSREPLACE) {
7386                                //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
7387                                while (*idx) {
7388                                        char *restart_detect = stackblock();
7389                                        STPUTC(*idx, expdest);
7390                                        if (stackblock() != restart_detect)
7391                                                goto restart;
7392                                        len++;
7393                                        idx++;
7394                                }
7395                                break;
7396                        }
7397                }
7398
7399                /* We've put the replaced text into a buffer at workloc, now
7400                 * move it to the right place and adjust the stack.
7401                 */
7402                STPUTC('\0', expdest);
7403                startp = (char *)stackblock() + startloc;
7404                memmove(startp, (char *)stackblock() + workloc, len + 1);
7405                //bb_error_msg("startp:'%s'", startp);
7406                loc = startp + len;
7407                goto out;
7408        }
7409#endif /* BASH_PATTERN_SUBST */
7410
7411        subtype -= VSTRIMRIGHT;
7412#if DEBUG
7413        if (subtype < 0 || subtype > 7)
7414                abort();
7415#endif
7416        /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
7417        zero = subtype >> 1;
7418        /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7419        scan = (subtype & 1) ^ zero ? scanleft : scanright;
7420
7421        loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7422        if (loc) {
7423                if (zero) {
7424                        memmove(startp, loc, str - loc);
7425                        loc = startp + (str - loc) - 1;
7426                }
7427                *loc = '\0';
7428        } else
7429                loc = str - 1;
7430
7431 out:
7432        amount = loc - expdest;
7433        STADJUST(amount, expdest);
7434#if BASH_PATTERN_SUBST
7435 out1:
7436#endif
7437        /* Remove any recorded regions beyond start of variable */
7438        removerecordregions(startloc);
7439
7440        return p;
7441}
7442
7443/*
7444 * Add the value of a specialized variable to the stack string.
7445 * name parameter (examples):
7446 * ash -c 'echo $1'      name:'1='
7447 * ash -c 'echo $qwe'    name:'qwe='
7448 * ash -c 'echo $$'      name:'$='
7449 * ash -c 'echo ${$}'    name:'$='
7450 * ash -c 'echo ${$##q}' name:'$=q'
7451 * ash -c 'echo ${#$}'   name:'$='
7452 * note: examples with bad shell syntax:
7453 * ash -c 'echo ${#$1}'  name:'$=1'
7454 * ash -c 'echo ${#1#}'  name:'1=#'
7455 */
7456static NOINLINE ssize_t
7457varvalue(char *name, int varflags, int flags, int quoted)
7458{
7459        const char *p;
7460        int num;
7461        int i;
7462        ssize_t len = 0;
7463        int sep;
7464        int subtype = varflags & VSTYPE;
7465        int discard = (subtype == VSPLUS || subtype == VSLENGTH) | (flags & EXP_DISCARD);
7466
7467        if (!subtype) {
7468                if (discard)
7469                        return -1;
7470
7471                ifsfree();
7472                raise_error_syntax("bad substitution");
7473        }
7474
7475        flags |= EXP_KEEPNUL;
7476        flags &= discard ? ~QUOTES_ESC : ~0;
7477        sep = (flags & EXP_FULL) << CHAR_BIT;
7478
7479        switch (*name) {
7480        case '$':
7481                num = rootpid;
7482                goto numvar;
7483        case '?':
7484                num = exitstatus;
7485                goto numvar;
7486        case '#':
7487                num = shellparam.nparam;
7488                goto numvar;
7489        case '!':
7490                num = backgndpid;
7491                if (num == 0)
7492                        return -1;
7493 numvar:
7494                len = cvtnum(num, flags);
7495                goto check_1char_name;
7496        case '-':
7497                expdest = makestrspace(NOPTS, expdest);
7498                for (i = NOPTS - 1; i >= 0; i--) {
7499                        if (optlist[i] && optletters(i)) {
7500                                USTPUTC(optletters(i), expdest);
7501                                len++;
7502                        }
7503                }
7504 check_1char_name:
7505#if 0
7506                /* handles cases similar to ${#$1} */
7507                if (name[2] != '\0')
7508                        raise_error_syntax("bad substitution");
7509#endif
7510                break;
7511        case '@':
7512                if (quoted && sep)
7513                        goto param;
7514                /* fall through */
7515        case '*': {
7516                char **ap;
7517                char sepc;
7518                char c;
7519
7520                /* We will set c to 0 or ~0 depending on whether
7521                 * we're doing field splitting.  We won't do field
7522                 * splitting if either we're quoted or sep is zero.
7523                 *
7524                 * Instead of testing (quoted || !sep) the following
7525                 * trick optimises away any branches by using the
7526                 * fact that EXP_QUOTED (which is the only bit that
7527                 * can be set in quoted) is the same as EXP_FULL <<
7528                 * CHAR_BIT (which is the only bit that can be set
7529                 * in sep).
7530                 */
7531#if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7532#error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7533#endif
7534                c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7535                sep &= ~quoted;
7536                sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
7537 param:
7538                sepc = sep;
7539                ap = shellparam.p;
7540                if (!ap)
7541                        return -1;
7542                while ((p = *ap++) != NULL) {
7543                        len += strtodest(p, flags);
7544
7545                        if (*ap && sep) {
7546                                len++;
7547                                memtodest(&sepc, 1, flags);
7548                        }
7549                }
7550                break;
7551        } /* case '*' */
7552        case '0':
7553        case '1':
7554        case '2':
7555        case '3':
7556        case '4':
7557        case '5':
7558        case '6':
7559        case '7':
7560        case '8':
7561        case '9':
7562                num = atoi(name); /* number(name) fails on ${N#str} etc */
7563                if (num < 0 || num > shellparam.nparam)
7564                        return -1;
7565                p = num ? shellparam.p[num - 1] : arg0;
7566                goto value;
7567        default:
7568                /* NB: name has form "VAR=..." */
7569                p = lookupvar(name);
7570 value:
7571                if (!p)
7572                        return -1;
7573
7574                len = strtodest(p, flags);
7575#if ENABLE_UNICODE_SUPPORT
7576                if (subtype == VSLENGTH && len > 0) {
7577                        reinit_unicode_for_ash();
7578                        if (unicode_status == UNICODE_ON) {
7579                                STADJUST(-len, expdest);
7580                                discard = 0;
7581                                len = unicode_strlen(p);
7582                        }
7583                }
7584#endif
7585                break;
7586        }
7587
7588        if (discard)
7589                STADJUST(-len, expdest);
7590
7591        return len;
7592}
7593
7594/*
7595 * Expand a variable, and return a pointer to the next character in the
7596 * input string.
7597 */
7598static char *
7599evalvar(char *p, int flag)
7600{
7601        char varflags;
7602        char subtype;
7603        char *var;
7604        int patloc;
7605        int startloc;
7606        ssize_t varlen;
7607        int discard;
7608        int quoted;
7609
7610        varflags = (unsigned char) *p++;
7611        subtype = varflags & VSTYPE;
7612
7613        quoted = flag & EXP_QUOTED;
7614        var = p;
7615        startloc = expdest - (char *)stackblock();
7616        p = strchr(p, '=') + 1; //TODO: use var_end(p)?
7617
7618 again:
7619        varlen = varvalue(var, varflags, flag, quoted);
7620        if (varflags & VSNUL)
7621                varlen--;
7622
7623        discard = varlen < 0 ? EXP_DISCARD : 0;
7624
7625        switch (subtype) {
7626        case VSPLUS:
7627                discard ^= EXP_DISCARD;
7628                /* fall through */
7629        case 0:
7630        case VSMINUS:
7631                p = argstr(p, flag | EXP_TILDE | EXP_WORD | (discard ^ EXP_DISCARD));
7632                goto record;
7633
7634        case VSASSIGN:
7635        case VSQUESTION:
7636                p = subevalvar(p, var, 0, startloc, varflags,
7637                        (flag & ~QUOTES_ESC) | (discard ^ EXP_DISCARD));
7638
7639                if ((flag | ~discard) & EXP_DISCARD)
7640                        goto record;
7641
7642                varflags &= ~VSNUL;
7643                subtype = VSNORMAL;
7644                goto again;
7645        }
7646
7647        if ((discard & ~flag) && uflag)
7648                varunset(p, var, 0, 0);
7649
7650        if (subtype == VSLENGTH) {
7651                p++;
7652                if (flag & EXP_DISCARD)
7653                        return p;
7654                cvtnum(varlen > 0 ? varlen : 0, flag);
7655                goto really_record;
7656        }
7657
7658        if (subtype == VSNORMAL)
7659                goto record;
7660
7661#if DEBUG
7662        switch (subtype) {
7663        case VSTRIMLEFT:
7664        case VSTRIMLEFTMAX:
7665        case VSTRIMRIGHT:
7666        case VSTRIMRIGHTMAX:
7667#if BASH_SUBSTR
7668        case VSSUBSTR:
7669#endif
7670#if BASH_PATTERN_SUBST
7671        case VSREPLACE:
7672        case VSREPLACEALL:
7673#endif
7674                break;
7675        default:
7676                abort();
7677        }
7678#endif
7679
7680        flag |= discard;
7681        if (!(flag & EXP_DISCARD)) {
7682                /*
7683                 * Terminate the string and start recording the pattern
7684                 * right after it
7685                 */
7686                STPUTC('\0', expdest);
7687        }
7688
7689        patloc = expdest - (char *)stackblock();
7690        p = subevalvar(p, NULL, patloc, startloc, varflags, flag);
7691
7692 record:
7693        if ((flag | discard) & EXP_DISCARD)
7694                return p;
7695
7696 really_record:
7697        if (quoted) {
7698                quoted = *var == '@' && shellparam.nparam;
7699                if (!quoted)
7700                        return p;
7701        }
7702        recordregion(startloc, expdest - (char *)stackblock(), quoted);
7703        return p;
7704}
7705
7706/*
7707 * Add a file name to the list.
7708 */
7709static void
7710addfname(const char *name)
7711{
7712        struct strlist *sp;
7713
7714        sp = stzalloc(sizeof(*sp));
7715        sp->text = sstrdup(name);
7716        *exparg.lastp = sp;
7717        exparg.lastp = &sp->next;
7718}
7719
7720/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7721static int
7722hasmeta(const char *p)
7723{
7724        static const char chars[] ALIGN1 = {
7725                '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7726        };
7727
7728        for (;;) {
7729                p = strpbrk(p, chars);
7730                if (!p)
7731                        break;
7732                switch ((unsigned char)*p) {
7733                case CTLQUOTEMARK:
7734                        for (;;) {
7735                                p++;
7736                                if ((unsigned char)*p == CTLQUOTEMARK)
7737                                        break;
7738                                if ((unsigned char)*p == CTLESC)
7739                                        p++;
7740                                if (*p == '\0') /* huh? */
7741                                        return 0;
7742                        }
7743                        break;
7744                case '\\':
7745                case CTLESC:
7746                        p++;
7747                        if (*p == '\0')
7748                                return 0;
7749                        break;
7750                case '[':
7751                        if (!strchr(p + 1, ']')) {
7752                                /* It's not a properly closed [] pattern,
7753                                 * but other metas may follow. Continue checking.
7754                                 * my[file* _is_ globbed by bash
7755                                 * and matches filenames like "my[file1".
7756                                 */
7757                                break;
7758                        }
7759                        /* fallthrough */
7760                default:
7761                /* case '*': */
7762                /* case '?': */
7763                        return 1;
7764                }
7765                p++;
7766        }
7767
7768        return 0;
7769}
7770
7771/* If we want to use glob() from libc... */
7772#if !ENABLE_ASH_INTERNAL_GLOB
7773
7774/* Add the result of glob() to the list */
7775static void
7776addglob(const glob_t *pglob)
7777{
7778        char **p = pglob->gl_pathv;
7779
7780        do {
7781                addfname(*p);
7782        } while (*++p);
7783}
7784static void
7785expandmeta(struct strlist *str /*, int flag*/)
7786{
7787        /* TODO - EXP_REDIR */
7788
7789        while (str) {
7790                char *p;
7791                glob_t pglob;
7792                int i;
7793
7794                if (fflag)
7795                        goto nometa;
7796
7797                if (!hasmeta(str->text))
7798                        goto nometa;
7799
7800                INT_OFF;
7801                p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7802// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7803// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7804//
7805// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7806// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7807// Which means you need to unescape the string, right? Not so fast:
7808// if there _is_ a file named "file\?" (with backslash), it is returned
7809// as "file\?" too (whichever pattern you used to find it, say, "file*").
7810// You DON'T KNOW by looking at the result whether you need to unescape it.
7811//
7812// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7813// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7814// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7815// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7816//              i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7817//              i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7818                i = glob(p, 0, NULL, &pglob);
7819                //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7820                if (p != str->text)
7821                        free(p);
7822                switch (i) {
7823                case 0:
7824#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7825                        /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7826                        if (!(pglob.gl_flags & GLOB_MAGCHAR))
7827                                goto nometa2;
7828#endif
7829                        addglob(&pglob);
7830                        globfree(&pglob);
7831                        INT_ON;
7832                        break;
7833                case GLOB_NOMATCH:
7834 //nometa2:
7835                        globfree(&pglob);
7836                        INT_ON;
7837 nometa:
7838                        *exparg.lastp = str;
7839                        rmescapes(str->text, 0, NULL);
7840                        exparg.lastp = &str->next;
7841                        break;
7842                default:        /* GLOB_NOSPACE */
7843                        globfree(&pglob);
7844                        INT_ON;
7845                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
7846                }
7847                str = str->next;
7848        }
7849}
7850
7851#else
7852/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7853
7854/*
7855 * Do metacharacter (i.e. *, ?, [...]) expansion.
7856 */
7857typedef struct exp_t {
7858        char *dir;
7859        unsigned dir_max;
7860} exp_t;
7861static void
7862expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7863{
7864#define expdir exp->dir
7865#define expdir_max exp->dir_max
7866        char *enddir = expdir + expdir_len;
7867        char *p;
7868        const char *cp;
7869        char *start;
7870        char *endname;
7871        int metaflag;
7872        struct stat statb;
7873        DIR *dirp;
7874        struct dirent *dp;
7875        int atend;
7876        int matchdot;
7877        int esc;
7878
7879        metaflag = 0;
7880        start = name;
7881        for (p = name; esc = 0, *p; p += esc + 1) {
7882                if (*p == '*' || *p == '?')
7883                        metaflag = 1;
7884                else if (*p == '[') {
7885                        char *q = p + 1;
7886                        if (*q == '!')
7887                                q++;
7888                        for (;;) {
7889                                if (*q == '\\')
7890                                        q++;
7891                                if (*q == '/' || *q == '\0')
7892                                        break;
7893                                if (*++q == ']') {
7894                                        metaflag = 1;
7895                                        break;
7896                                }
7897                        }
7898                } else {
7899                        if (*p == '\\' && p[1])
7900                                esc++;
7901                        if (p[esc] == '/') {
7902                                if (metaflag)
7903                                        break;
7904                                start = p + esc + 1;
7905                        }
7906                }
7907        }
7908        if (metaflag == 0) {    /* we've reached the end of the file name */
7909                if (!expdir_len)
7910                        return;
7911                p = name;
7912                do {
7913                        if (*p == '\\' && p[1])
7914                                p++;
7915                        *enddir++ = *p;
7916                } while (*p++);
7917                if (lstat(expdir, &statb) == 0)
7918                        addfname(expdir);
7919                return;
7920        }
7921        endname = p;
7922        if (name < start) {
7923                p = name;
7924                do {
7925                        if (*p == '\\' && p[1])
7926                                p++;
7927                        *enddir++ = *p++;
7928                } while (p < start);
7929        }
7930        *enddir = '\0';
7931        cp = expdir;
7932        expdir_len = enddir - cp;
7933        if (!expdir_len)
7934                cp = ".";
7935        dirp = opendir(cp);
7936        if (dirp == NULL)
7937                return;
7938        if (*endname == 0) {
7939                atend = 1;
7940        } else {
7941                atend = 0;
7942                *endname = '\0';
7943                endname += esc + 1;
7944        }
7945        name_len -= endname - name;
7946        matchdot = 0;
7947        p = start;
7948        if (*p == '\\')
7949                p++;
7950        if (*p == '.')
7951                matchdot++;
7952        while (!pending_int && (dp = readdir(dirp)) != NULL) {
7953                if (dp->d_name[0] == '.' && !matchdot)
7954                        continue;
7955                if (pmatch(start, dp->d_name)) {
7956                        if (atend) {
7957                                strcpy(enddir, dp->d_name);
7958                                addfname(expdir);
7959                        } else {
7960                                unsigned offset;
7961                                unsigned len;
7962
7963                                p = stpcpy(enddir, dp->d_name);
7964                                *p = '/';
7965
7966                                offset = p - expdir + 1;
7967                                len = offset + name_len + NAME_MAX;
7968                                if (len > expdir_max) {
7969                                        len += PATH_MAX;
7970                                        expdir = ckrealloc(expdir, len);
7971                                        expdir_max = len;
7972                                }
7973
7974                                expmeta(exp, endname, name_len, offset);
7975                                enddir = expdir + expdir_len;
7976                        }
7977                }
7978        }
7979        closedir(dirp);
7980        if (!atend)
7981                endname[-esc - 1] = esc ? '\\' : '/';
7982#undef expdir
7983#undef expdir_max
7984}
7985
7986static struct strlist *
7987msort(struct strlist *list, int len)
7988{
7989        struct strlist *p, *q = NULL;
7990        struct strlist **lpp;
7991        int half;
7992        int n;
7993
7994        if (len <= 1)
7995                return list;
7996        half = len >> 1;
7997        p = list;
7998        for (n = half; --n >= 0;) {
7999                q = p;
8000                p = p->next;
8001        }
8002        q->next = NULL;                 /* terminate first half of list */
8003        q = msort(list, half);          /* sort first half of list */
8004        p = msort(p, len - half);               /* sort second half */
8005        lpp = &list;
8006        for (;;) {
8007#if ENABLE_LOCALE_SUPPORT
8008                if (strcoll(p->text, q->text) < 0)
8009#else
8010                if (strcmp(p->text, q->text) < 0)
8011#endif
8012                                                {
8013                        *lpp = p;
8014                        lpp = &p->next;
8015                        p = *lpp;
8016                        if (p == NULL) {
8017                                *lpp = q;
8018                                break;
8019                        }
8020                } else {
8021                        *lpp = q;
8022                        lpp = &q->next;
8023                        q = *lpp;
8024                        if (q == NULL) {
8025                                *lpp = p;
8026                                break;
8027                        }
8028                }
8029        }
8030        return list;
8031}
8032
8033/*
8034 * Sort the results of file name expansion.  It calculates the number of
8035 * strings to sort and then calls msort (short for merge sort) to do the
8036 * work.
8037 */
8038static struct strlist *
8039expsort(struct strlist *str)
8040{
8041        int len;
8042        struct strlist *sp;
8043
8044        len = 0;
8045        for (sp = str; sp; sp = sp->next)
8046                len++;
8047        return msort(str, len);
8048}
8049
8050static void
8051expandmeta(struct strlist *str /*, int flag*/)
8052{
8053        /* TODO - EXP_REDIR */
8054
8055        while (str) {
8056                exp_t exp;
8057                struct strlist **savelastp;
8058                struct strlist *sp;
8059                char *p;
8060                unsigned len;
8061
8062                if (fflag)
8063                        goto nometa;
8064                if (!hasmeta(str->text))
8065                        goto nometa;
8066                savelastp = exparg.lastp;
8067
8068                INT_OFF;
8069                p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
8070                len = strlen(p);
8071                exp.dir_max = len + PATH_MAX;
8072                exp.dir = ckmalloc(exp.dir_max);
8073
8074                expmeta(&exp, p, len, 0);
8075                free(exp.dir);
8076                if (p != str->text)
8077                        free(p);
8078                INT_ON;
8079                if (exparg.lastp == savelastp) {
8080                        /*
8081                         * no matches
8082                         */
8083 nometa:
8084                        *exparg.lastp = str;
8085                        rmescapes(str->text, 0, NULL);
8086                        exparg.lastp = &str->next;
8087                } else {
8088                        *exparg.lastp = NULL;
8089                        *savelastp = sp = expsort(*savelastp);
8090                        while (sp->next != NULL)
8091                                sp = sp->next;
8092                        exparg.lastp = &sp->next;
8093                }
8094                str = str->next;
8095        }
8096}
8097#endif /* ENABLE_ASH_INTERNAL_GLOB */
8098
8099/*
8100 * Perform variable substitution and command substitution on an argument,
8101 * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
8102 * perform splitting and file name expansion.  When arglist is NULL, perform
8103 * here document expansion.
8104 */
8105static void
8106expandarg(union node *arg, struct arglist *arglist, int flag)
8107{
8108        struct strlist *sp;
8109        char *p;
8110
8111        argbackq = arg->narg.backquote;
8112        STARTSTACKSTR(expdest);
8113        TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
8114        argstr(arg->narg.text, flag);
8115        if (arglist == NULL) {
8116                /* here document expanded */
8117                goto out;
8118        }
8119        p = grabstackstr(expdest);
8120        TRACE(("expandarg: p:'%s'\n", p));
8121        exparg.lastp = &exparg.list;
8122        /*
8123         * TODO - EXP_REDIR
8124         */
8125        if (flag & EXP_FULL) {
8126                ifsbreakup(p, &exparg);
8127                *exparg.lastp = NULL;
8128                exparg.lastp = &exparg.list;
8129                expandmeta(exparg.list /*, flag*/);
8130        } else {
8131                sp = stzalloc(sizeof(*sp));
8132                sp->text = p;
8133                *exparg.lastp = sp;
8134                exparg.lastp = &sp->next;
8135        }
8136        *exparg.lastp = NULL;
8137        if (exparg.list) {
8138                *arglist->lastp = exparg.list;
8139                arglist->lastp = exparg.lastp;
8140        }
8141
8142 out:
8143        ifsfree();
8144}
8145
8146/*
8147 * Expand shell variables and backquotes inside a here document.
8148 */
8149static void
8150expandhere(union node *arg)
8151{
8152        expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
8153}
8154
8155/*
8156 * Returns true if the pattern matches the string.
8157 */
8158static int
8159patmatch(char *pattern, const char *string)
8160{
8161        char *p = preglob(pattern, 0);
8162        int r = pmatch(p, string);
8163        //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
8164        return r;
8165}
8166
8167/*
8168 * See if a pattern matches in a case statement.
8169 */
8170static int
8171casematch(union node *pattern, char *val)
8172{
8173        struct stackmark smark;
8174        int result;
8175
8176        setstackmark(&smark);
8177        argbackq = pattern->narg.backquote;
8178        STARTSTACKSTR(expdest);
8179        argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
8180        ifsfree();
8181        result = patmatch(stackblock(), val);
8182        popstackmark(&smark);
8183        return result;
8184}
8185
8186
8187/* ============ find_command */
8188
8189struct builtincmd {
8190        const char *name;
8191        int (*builtin)(int, char **) FAST_FUNC;
8192        /* unsigned flags; */
8193};
8194#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
8195/* "regular" builtins always take precedence over commands,
8196 * regardless of PATH=....%builtin... position */
8197#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
8198#define IS_BUILTIN_ASSIGN(b)  ((b)->name[0] & 4)
8199
8200struct cmdentry {
8201        smallint cmdtype;       /* CMDxxx */
8202        union param {
8203                int index;
8204                /* index >= 0 for commands without path (slashes) */
8205                /* (TODO: what exactly does the value mean? PATH position?) */
8206                /* index == -1 for commands with slashes */
8207                /* index == (-2 - applet_no) for NOFORK applets */
8208                const struct builtincmd *cmd;
8209                struct funcnode *func;
8210        } u;
8211};
8212/* values of cmdtype */
8213#define CMDUNKNOWN      -1      /* no entry in table for command */
8214#define CMDNORMAL       0       /* command is an executable program */
8215#define CMDFUNCTION     1       /* command is a shell function */
8216#define CMDBUILTIN      2       /* command is a shell builtin */
8217
8218/* action to find_command() */
8219#define DO_ERR          0x01    /* prints errors */
8220#define DO_ABS          0x02    /* checks absolute paths */
8221#define DO_NOFUNC       0x04    /* don't return shell functions, for command */
8222#define DO_ALTPATH      0x08    /* using alternate path */
8223#define DO_REGBLTIN     0x10    /* regular built-ins and functions only */
8224
8225static void find_command(char *, struct cmdentry *, int, const char *);
8226
8227
8228/* ============ Hashing commands */
8229
8230/*
8231 * When commands are first encountered, they are entered in a hash table.
8232 * This ensures that a full path search will not have to be done for them
8233 * on each invocation.
8234 *
8235 * We should investigate converting to a linear search, even though that
8236 * would make the command name "hash" a misnomer.
8237 */
8238
8239struct tblentry {
8240        struct tblentry *next;  /* next entry in hash chain */
8241        union param param;      /* definition of builtin function */
8242        smallint cmdtype;       /* CMDxxx */
8243        char rehash;            /* if set, cd done since entry created */
8244        char cmdname[1];        /* name of command */
8245};
8246
8247static struct tblentry **cmdtable;
8248#define INIT_G_cmdtable() do { \
8249        cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
8250} while (0)
8251
8252static int builtinloc = -1;     /* index in path of %builtin, or -1 */
8253
8254
8255static void
8256tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
8257{
8258#if ENABLE_FEATURE_SH_STANDALONE
8259        if (applet_no >= 0) {
8260                if (APPLET_IS_NOEXEC(applet_no)) {
8261                        clearenv();
8262                        while (*envp)
8263                                putenv(*envp++);
8264                        popredir(/*drop:*/ 1);
8265                        run_noexec_applet_and_exit(applet_no, cmd, argv);
8266                }
8267                /* re-exec ourselves with the new arguments */
8268                execve(bb_busybox_exec_path, argv, envp);
8269                /* If they called chroot or otherwise made the binary no longer
8270                 * executable, fall through */
8271        }
8272#endif
8273
8274 repeat:
8275#ifdef SYSV
8276        do {
8277                execve(cmd, argv, envp);
8278        } while (errno == EINTR);
8279#else
8280        execve(cmd, argv, envp);
8281#endif
8282
8283        if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
8284                /* Run "cmd" as a shell script:
8285                 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8286                 * "If the execve() function fails with ENOEXEC, the shell
8287                 * shall execute a command equivalent to having a shell invoked
8288                 * with the command name as its first operand,
8289                 * with any remaining arguments passed to the new shell"
8290                 *
8291                 * That is, do not use $SHELL, user's shell, or /bin/sh;
8292                 * just call ourselves.
8293                 *
8294                 * Note that bash reads ~80 chars of the file, and if it sees
8295                 * a zero byte before it sees newline, it doesn't try to
8296                 * interpret it, but fails with "cannot execute binary file"
8297                 * message and exit code 126. For one, this prevents attempts
8298                 * to interpret foreign ELF binaries as shell scripts.
8299                 */
8300                argv[0] = (char*) cmd;
8301                cmd = bb_busybox_exec_path;
8302                /* NB: this is only possible because all callers of shellexec()
8303                 * ensure that the argv[-1] slot exists!
8304                 */
8305                argv--;
8306                argv[0] = (char*) "ash";
8307                goto repeat;
8308        }
8309}
8310
8311/*
8312 * Exec a program.  Never returns.  If you change this routine, you may
8313 * have to change the find_command routine as well.
8314 * argv[-1] must exist and be writable! See tryexec() for why.
8315 */
8316static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8317static void shellexec(char *prog, char **argv, const char *path, int idx)
8318{
8319        char *cmdname;
8320        int e;
8321        char **envp;
8322        int exerrno;
8323        int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
8324
8325        envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
8326        if (strchr(prog, '/') != NULL
8327#if ENABLE_FEATURE_SH_STANDALONE
8328         || (applet_no = find_applet_by_name(prog)) >= 0
8329#endif
8330        ) {
8331                tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
8332                if (applet_no >= 0) {
8333                        /* We tried execing ourself, but it didn't work.
8334                         * Maybe /proc/self/exe doesn't exist?
8335                         * Try $PATH search.
8336                         */
8337                        goto try_PATH;
8338                }
8339                e = errno;
8340        } else {
8341 try_PATH:
8342                e = ENOENT;
8343                while (padvance(&path, argv[0]) >= 0) {
8344                        cmdname = stackblock();
8345                        if (--idx < 0 && pathopt == NULL) {
8346                                tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
8347                                if (errno != ENOENT && errno != ENOTDIR)
8348                                        e = errno;
8349                        }
8350                }
8351        }
8352
8353        /* Map to POSIX errors */
8354        switch (e) {
8355        default:
8356                exerrno = 126;
8357                break;
8358        case ELOOP:
8359        case ENAMETOOLONG:
8360        case ENOENT:
8361        case ENOTDIR:
8362                exerrno = 127;
8363                break;
8364        }
8365        exitstatus = exerrno;
8366        TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
8367                prog, e, suppress_int));
8368        ash_msg_and_raise(EXEND, "%s: %s", prog, errmsg(e, "not found"));
8369        /* NOTREACHED */
8370}
8371
8372static void
8373printentry(struct tblentry *cmdp)
8374{
8375        int idx;
8376        const char *path;
8377        char *name;
8378
8379        idx = cmdp->param.index;
8380        path = pathval();
8381        do {
8382                padvance(&path, cmdp->cmdname);
8383        } while (--idx >= 0);
8384        name = stackblock();
8385        out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8386}
8387
8388/*
8389 * Clear out command entries.
8390 */
8391static void
8392clearcmdentry(void)
8393{
8394        struct tblentry **tblp;
8395        struct tblentry **pp;
8396        struct tblentry *cmdp;
8397
8398        INT_OFF;
8399        for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8400                pp = tblp;
8401                while ((cmdp = *pp) != NULL) {
8402                        if (cmdp->cmdtype == CMDNORMAL
8403                         || (cmdp->cmdtype == CMDBUILTIN
8404                            && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8405                            && builtinloc > 0
8406                            )
8407                        ) {
8408                                *pp = cmdp->next;
8409                                free(cmdp);
8410                        } else {
8411                                pp = &cmdp->next;
8412                        }
8413                }
8414        }
8415        INT_ON;
8416}
8417
8418/*
8419 * Locate a command in the command hash table.  If "add" is nonzero,
8420 * add the command to the table if it is not already present.  The
8421 * variable "lastcmdentry" is set to point to the address of the link
8422 * pointing to the entry, so that delete_cmd_entry can delete the
8423 * entry.
8424 *
8425 * Interrupts must be off if called with add != 0.
8426 */
8427static struct tblentry **lastcmdentry;
8428
8429static struct tblentry *
8430cmdlookup(const char *name, int add)
8431{
8432        unsigned int hashval;
8433        const char *p;
8434        struct tblentry *cmdp;
8435        struct tblentry **pp;
8436
8437        p = name;
8438        hashval = (unsigned char)*p << 4;
8439        while (*p)
8440                hashval += (unsigned char)*p++;
8441        hashval &= 0x7FFF;
8442        pp = &cmdtable[hashval % CMDTABLESIZE];
8443        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8444                if (strcmp(cmdp->cmdname, name) == 0)
8445                        break;
8446                pp = &cmdp->next;
8447        }
8448        if (add && cmdp == NULL) {
8449                cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8450                                + strlen(name)
8451                                /* + 1 - already done because
8452                                 * tblentry::cmdname is char[1] */);
8453                /*cmdp->next = NULL; - ckzalloc did it */
8454                cmdp->cmdtype = CMDUNKNOWN;
8455                strcpy(cmdp->cmdname, name);
8456        }
8457        lastcmdentry = pp;
8458        return cmdp;
8459}
8460
8461/*
8462 * Delete the command entry returned on the last lookup.
8463 */
8464static void
8465delete_cmd_entry(void)
8466{
8467        struct tblentry *cmdp;
8468
8469        INT_OFF;
8470        cmdp = *lastcmdentry;
8471        *lastcmdentry = cmdp->next;
8472        if (cmdp->cmdtype == CMDFUNCTION)
8473                freefunc(cmdp->param.func);
8474        free(cmdp);
8475        INT_ON;
8476}
8477
8478/*
8479 * Add a new command entry, replacing any existing command entry for
8480 * the same name - except special builtins.
8481 */
8482static void
8483addcmdentry(char *name, struct cmdentry *entry)
8484{
8485        struct tblentry *cmdp;
8486
8487        cmdp = cmdlookup(name, 1);
8488        if (cmdp->cmdtype == CMDFUNCTION) {
8489                freefunc(cmdp->param.func);
8490        }
8491        cmdp->cmdtype = entry->cmdtype;
8492        cmdp->param = entry->u;
8493        cmdp->rehash = 0;
8494}
8495
8496static int FAST_FUNC
8497hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8498{
8499        struct tblentry **pp;
8500        struct tblentry *cmdp;
8501        int c;
8502        struct cmdentry entry;
8503        char *name;
8504
8505        if (nextopt("r") != '\0') {
8506                clearcmdentry();
8507                return 0;
8508        }
8509
8510        if (*argptr == NULL) {
8511                for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8512                        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8513                                if (cmdp->cmdtype == CMDNORMAL)
8514                                        printentry(cmdp);
8515                        }
8516                }
8517                return 0;
8518        }
8519
8520        c = 0;
8521        while ((name = *argptr) != NULL) {
8522                cmdp = cmdlookup(name, 0);
8523                if (cmdp != NULL
8524                 && (cmdp->cmdtype == CMDNORMAL
8525                    || (cmdp->cmdtype == CMDBUILTIN
8526                        && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8527                        && builtinloc > 0
8528                        )
8529                    )
8530                ) {
8531                        delete_cmd_entry();
8532                }
8533                find_command(name, &entry, DO_ERR, pathval());
8534                if (entry.cmdtype == CMDUNKNOWN)
8535                        c = 1;
8536                argptr++;
8537        }
8538        return c;
8539}
8540
8541/*
8542 * Called when a cd is done.  Marks all commands so the next time they
8543 * are executed they will be rehashed.
8544 */
8545static void
8546hashcd(void)
8547{
8548        struct tblentry **pp;
8549        struct tblentry *cmdp;
8550
8551        for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8552                for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8553                        if (cmdp->cmdtype == CMDNORMAL
8554                         || (cmdp->cmdtype == CMDBUILTIN
8555                             && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8556                             && builtinloc > 0)
8557                        ) {
8558                                cmdp->rehash = 1;
8559                        }
8560                }
8561        }
8562}
8563
8564/*
8565 * Fix command hash table when PATH changed.
8566 * Called before PATH is changed.  The argument is the new value of PATH;
8567 * pathval() still returns the old value at this point.
8568 * Called with interrupts off.
8569 */
8570static void FAST_FUNC
8571changepath(const char *newval)
8572{
8573        const char *new;
8574        int idx;
8575        int bltin;
8576
8577        new = newval;
8578        idx = 0;
8579        bltin = -1;
8580        for (;;) {
8581                if (*new == '%' && prefix(new + 1, "builtin")) {
8582                        bltin = idx;
8583                        break;
8584                }
8585                new = strchr(new, ':');
8586                if (!new)
8587                        break;
8588                idx++;
8589                new++;
8590        }
8591        builtinloc = bltin;
8592        clearcmdentry();
8593}
8594enum {
8595        TEOF,
8596        TNL,
8597        TREDIR,
8598        TWORD,
8599        TSEMI,
8600        TBACKGND,
8601        TAND,
8602        TOR,
8603        TPIPE,
8604        TLP,
8605        TRP,
8606        TENDCASE,
8607        TENDBQUOTE,
8608        TNOT,
8609        TCASE,
8610        TDO,
8611        TDONE,
8612        TELIF,
8613        TELSE,
8614        TESAC,
8615        TFI,
8616        TFOR,
8617#if BASH_FUNCTION
8618        TFUNCTION,
8619#endif
8620        TIF,
8621        TIN,
8622        TTHEN,
8623        TUNTIL,
8624        TWHILE,
8625        TBEGIN,
8626        TEND
8627};
8628typedef smallint token_id_t;
8629
8630/* Nth bit indicates if token marks the end of a list */
8631enum {
8632        tokendlist = 0
8633        /*  0 */ | (1u << TEOF)
8634        /*  1 */ | (0u << TNL)
8635        /*  2 */ | (0u << TREDIR)
8636        /*  3 */ | (0u << TWORD)
8637        /*  4 */ | (0u << TSEMI)
8638        /*  5 */ | (0u << TBACKGND)
8639        /*  6 */ | (0u << TAND)
8640        /*  7 */ | (0u << TOR)
8641        /*  8 */ | (0u << TPIPE)
8642        /*  9 */ | (0u << TLP)
8643        /* 10 */ | (1u << TRP)
8644        /* 11 */ | (1u << TENDCASE)
8645        /* 12 */ | (1u << TENDBQUOTE)
8646        /* 13 */ | (0u << TNOT)
8647        /* 14 */ | (0u << TCASE)
8648        /* 15 */ | (1u << TDO)
8649        /* 16 */ | (1u << TDONE)
8650        /* 17 */ | (1u << TELIF)
8651        /* 18 */ | (1u << TELSE)
8652        /* 19 */ | (1u << TESAC)
8653        /* 20 */ | (1u << TFI)
8654        /* 21 */ | (0u << TFOR)
8655#if BASH_FUNCTION
8656        /* 22 */ | (0u << TFUNCTION)
8657#endif
8658        /* 23 */ | (0u << TIF)
8659        /* 24 */ | (0u << TIN)
8660        /* 25 */ | (1u << TTHEN)
8661        /* 26 */ | (0u << TUNTIL)
8662        /* 27 */ | (0u << TWHILE)
8663        /* 28 */ | (0u << TBEGIN)
8664        /* 29 */ | (1u << TEND)
8665        , /* thus far 29 bits used */
8666};
8667
8668static const char *const tokname_array[] ALIGN_PTR = {
8669        "end of file",
8670        "newline",
8671        "redirection",
8672        "word",
8673        ";",
8674        "&",
8675        "&&",
8676        "||",
8677        "|",
8678        "(",
8679        ")",
8680        ";;",
8681        "`",
8682#define KWDOFFSET 13
8683        /* the following are keywords */
8684        "!",
8685        "case",
8686        "do",
8687        "done",
8688        "elif",
8689        "else",
8690        "esac",
8691        "fi",
8692        "for",
8693#if BASH_FUNCTION
8694        "function",
8695#endif
8696        "if",
8697        "in",
8698        "then",
8699        "until",
8700        "while",
8701        "{",
8702        "}",
8703};
8704
8705/* Wrapper around strcmp for qsort/bsearch/... */
8706static int
8707pstrcmp(const void *a, const void *b)
8708{
8709        return strcmp((char*)a, *(char**)b);
8710}
8711
8712static const char *const *
8713findkwd(const char *s)
8714{
8715        return bsearch(s, tokname_array + KWDOFFSET,
8716                        ARRAY_SIZE(tokname_array) - KWDOFFSET,
8717                        sizeof(tokname_array[0]), pstrcmp);
8718}
8719
8720/*
8721 * Locate and print what a word is...
8722 */
8723static int
8724describe_command(char *command, const char *path, int describe_command_verbose)
8725{
8726        struct cmdentry entry;
8727#if ENABLE_ASH_ALIAS
8728        const struct alias *ap;
8729#endif
8730
8731        path = path ? path : pathval();
8732
8733        if (describe_command_verbose) {
8734                out1str(command);
8735        }
8736
8737        /* First look at the keywords */
8738        if (findkwd(command)) {
8739                out1str(describe_command_verbose ? " is a shell keyword" : command);
8740                goto out;
8741        }
8742
8743#if ENABLE_ASH_ALIAS
8744        /* Then look at the aliases */
8745        ap = lookupalias(command, 0);
8746        if (ap != NULL) {
8747                if (!describe_command_verbose) {
8748                        out1str("alias ");
8749                        printalias(ap);
8750                        return 0;
8751                }
8752                out1fmt(" is an alias for %s", ap->val);
8753                goto out;
8754        }
8755#endif
8756        /* Brute force */
8757        find_command(command, &entry, DO_ABS, path);
8758
8759        switch (entry.cmdtype) {
8760        case CMDNORMAL: {
8761                int j = entry.u.index;
8762                char *p;
8763                if (j < 0) {
8764                        p = command;
8765                } else {
8766                        do {
8767                                padvance(&path, command);
8768                        } while (--j >= 0);
8769                        p = stackblock();
8770                }
8771                if (describe_command_verbose) {
8772                        out1fmt(" is %s", p);
8773                } else {
8774                        out1str(p);
8775                }
8776                break;
8777        }
8778
8779        case CMDFUNCTION:
8780                if (describe_command_verbose) {
8781                        /*out1str(" is a shell function");*/
8782                        out1str(" is a function"); /* bash says this */
8783                } else {
8784                        out1str(command);
8785                }
8786                break;
8787
8788        case CMDBUILTIN:
8789                if (describe_command_verbose) {
8790                        out1fmt(" is a %sshell builtin",
8791                                IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8792                                        "special " : nullstr
8793                        );
8794                } else {
8795                        out1str(command);
8796                }
8797                break;
8798
8799        default:
8800                if (describe_command_verbose) {
8801                        out1str(": not found\n");
8802                }
8803                return 127;
8804        }
8805 out:
8806        out1str("\n");
8807        return 0;
8808}
8809
8810static int FAST_FUNC
8811typecmd(int argc UNUSED_PARAM, char **argv)
8812{
8813        int i = 1;
8814        int err = 0;
8815        int verbose = 1;
8816
8817        /* type -p ... ? (we don't bother checking for 'p') */
8818        if (argv[1] && argv[1][0] == '-') {
8819                i++;
8820                verbose = 0;
8821        }
8822        while (argv[i]) {
8823                err |= describe_command(argv[i++], NULL, verbose);
8824        }
8825        return err;
8826}
8827
8828static struct strlist *
8829fill_arglist(struct arglist *arglist, union node **argpp)
8830{
8831        struct strlist **lastp = arglist->lastp;
8832        union node *argp;
8833
8834        while ((argp = *argpp) != NULL) {
8835                expandarg(argp, arglist, EXP_FULL | EXP_TILDE);
8836                *argpp = argp->narg.next;
8837                if (*lastp)
8838                        break;
8839        }
8840
8841        return *lastp;
8842}
8843
8844#if ENABLE_ASH_CMDCMD
8845/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8846static int
8847parse_command_args(struct arglist *arglist, union node **argpp, const char **path)
8848{
8849        struct strlist *sp = arglist->list;
8850        char *cp, c;
8851
8852        for (;;) {
8853                sp = sp->next ? sp->next : fill_arglist(arglist, argpp);
8854                if (!sp)
8855                        return 0;
8856                cp = sp->text;
8857                if (*cp++ != '-')
8858                        break;
8859                c = *cp++;
8860                if (!c)
8861                        break;
8862                if (c == '-' && !*cp) {
8863                        if (!sp->next && !fill_arglist(arglist, argpp))
8864                                return 0;
8865                        sp = sp->next;
8866                        break;
8867                }
8868                do {
8869                        switch (c) {
8870                        case 'p':
8871                                *path = bb_default_path;
8872                                break;
8873                        default:
8874                                /* run 'typecmd' for other options */
8875                                return 0;
8876                        }
8877                        c = *cp++;
8878                } while (c);
8879        }
8880
8881        arglist->list = sp;
8882        return DO_NOFUNC;
8883}
8884
8885static int FAST_FUNC
8886commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8887{
8888        char *cmd;
8889        int c;
8890        enum {
8891                VERIFY_BRIEF = 1,
8892                VERIFY_VERBOSE = 2,
8893        } verify = 0;
8894        const char *path = NULL;
8895
8896        /* "command [-p] PROG ARGS" (that is, without -V or -v)
8897         * never reaches this function.
8898         */
8899
8900        while ((c = nextopt("pvV")) != '\0')
8901                if (c == 'V')
8902                        verify |= VERIFY_VERBOSE;
8903                else if (c == 'v')
8904                        /*verify |= VERIFY_BRIEF*/;
8905#if DEBUG
8906                else if (c != 'p')
8907                        abort();
8908#endif
8909                else
8910                        path = bb_default_path;
8911
8912        /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8913        cmd = *argptr;
8914        if (/*verify && */ cmd)
8915                return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8916
8917        return 0;
8918}
8919#endif
8920
8921
8922/*static int funcblocksize;     // size of structures in function */
8923/*static int funcstringsize;    // size of strings in node */
8924static void *funcblock;         /* block to allocate function from */
8925static char *funcstring_end;    /* end of block to allocate strings from */
8926
8927static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8928        [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
8929        [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
8930        [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
8931        [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8932        [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8933        [NAND     ] = SHELL_ALIGN(sizeof(struct nbinary)),
8934        [NOR      ] = SHELL_ALIGN(sizeof(struct nbinary)),
8935        [NSEMI    ] = SHELL_ALIGN(sizeof(struct nbinary)),
8936        [NIF      ] = SHELL_ALIGN(sizeof(struct nif)),
8937        [NWHILE   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8938        [NUNTIL   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8939        [NFOR     ] = SHELL_ALIGN(sizeof(struct nfor)),
8940        [NCASE    ] = SHELL_ALIGN(sizeof(struct ncase)),
8941        [NCLIST   ] = SHELL_ALIGN(sizeof(struct nclist)),
8942        [NDEFUN   ] = SHELL_ALIGN(sizeof(struct narg)),
8943        [NARG     ] = SHELL_ALIGN(sizeof(struct narg)),
8944        [NTO      ] = SHELL_ALIGN(sizeof(struct nfile)),
8945#if BASH_REDIR_OUTPUT
8946        [NTO2     ] = SHELL_ALIGN(sizeof(struct nfile)),
8947#endif
8948        [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8949        [NFROM    ] = SHELL_ALIGN(sizeof(struct nfile)),
8950        [NFROMTO  ] = SHELL_ALIGN(sizeof(struct nfile)),
8951        [NAPPEND  ] = SHELL_ALIGN(sizeof(struct nfile)),
8952        [NTOFD    ] = SHELL_ALIGN(sizeof(struct ndup)),
8953        [NFROMFD  ] = SHELL_ALIGN(sizeof(struct ndup)),
8954        [NHERE    ] = SHELL_ALIGN(sizeof(struct nhere)),
8955        [NXHERE   ] = SHELL_ALIGN(sizeof(struct nhere)),
8956        [NNOT     ] = SHELL_ALIGN(sizeof(struct nnot)),
8957};
8958
8959static int calcsize(int funcblocksize, union node *n);
8960
8961static int
8962sizenodelist(int funcblocksize, struct nodelist *lp)
8963{
8964        while (lp) {
8965                funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8966                funcblocksize = calcsize(funcblocksize, lp->n);
8967                lp = lp->next;
8968        }
8969        return funcblocksize;
8970}
8971
8972static int
8973calcsize(int funcblocksize, union node *n)
8974{
8975        if (n == NULL)
8976                return funcblocksize;
8977        funcblocksize += nodesize[n->type];
8978        switch (n->type) {
8979        case NCMD:
8980                funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8981                funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8982                funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8983                break;
8984        case NPIPE:
8985                funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8986                break;
8987        case NREDIR:
8988        case NBACKGND:
8989        case NSUBSHELL:
8990                funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8991                funcblocksize = calcsize(funcblocksize, n->nredir.n);
8992                break;
8993        case NAND:
8994        case NOR:
8995        case NSEMI:
8996        case NWHILE:
8997        case NUNTIL:
8998                funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8999                funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
9000                break;
9001        case NIF:
9002                funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
9003                funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
9004                funcblocksize = calcsize(funcblocksize, n->nif.test);
9005                break;
9006        case NFOR:
9007                funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
9008                funcblocksize = calcsize(funcblocksize, n->nfor.body);
9009                funcblocksize = calcsize(funcblocksize, n->nfor.args);
9010                break;
9011        case NCASE:
9012                funcblocksize = calcsize(funcblocksize, n->ncase.cases);
9013                funcblocksize = calcsize(funcblocksize, n->ncase.expr);
9014                break;
9015        case NCLIST:
9016                funcblocksize = calcsize(funcblocksize, n->nclist.body);
9017                funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
9018                funcblocksize = calcsize(funcblocksize, n->nclist.next);
9019                break;
9020        case NDEFUN:
9021                funcblocksize = calcsize(funcblocksize, n->ndefun.body);
9022                funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
9023                break;
9024        case NARG:
9025                funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
9026                funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
9027                funcblocksize = calcsize(funcblocksize, n->narg.next);
9028                break;
9029        case NTO:
9030#if BASH_REDIR_OUTPUT
9031        case NTO2:
9032#endif
9033        case NCLOBBER:
9034        case NFROM:
9035        case NFROMTO:
9036        case NAPPEND:
9037                funcblocksize = calcsize(funcblocksize, n->nfile.fname);
9038                funcblocksize = calcsize(funcblocksize, n->nfile.next);
9039                break;
9040        case NTOFD:
9041        case NFROMFD:
9042                funcblocksize = calcsize(funcblocksize, n->ndup.vname);
9043                funcblocksize = calcsize(funcblocksize, n->ndup.next);
9044        break;
9045        case NHERE:
9046        case NXHERE:
9047                funcblocksize = calcsize(funcblocksize, n->nhere.doc);
9048                funcblocksize = calcsize(funcblocksize, n->nhere.next);
9049                break;
9050        case NNOT:
9051                funcblocksize = calcsize(funcblocksize, n->nnot.com);
9052                break;
9053        };
9054        return funcblocksize;
9055}
9056
9057static char *
9058nodeckstrdup(char *s)
9059{
9060        funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
9061        return strcpy(funcstring_end, s);
9062}
9063
9064static union node *copynode(union node *);
9065
9066static struct nodelist *
9067copynodelist(struct nodelist *lp)
9068{
9069        struct nodelist *start;
9070        struct nodelist **lpp;
9071
9072        lpp = &start;
9073        while (lp) {
9074                *lpp = funcblock;
9075                funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
9076                (*lpp)->n = copynode(lp->n);
9077                lp = lp->next;
9078                lpp = &(*lpp)->next;
9079        }
9080        *lpp = NULL;
9081        return start;
9082}
9083
9084static union node *
9085copynode(union node *n)
9086{
9087        union node *new;
9088
9089        if (n == NULL)
9090                return NULL;
9091        new = funcblock;
9092        funcblock = (char *) funcblock + nodesize[n->type];
9093
9094        switch (n->type) {
9095        case NCMD:
9096                new->ncmd.redirect = copynode(n->ncmd.redirect);
9097                new->ncmd.args = copynode(n->ncmd.args);
9098                new->ncmd.assign = copynode(n->ncmd.assign);
9099                new->ncmd.linno = n->ncmd.linno;
9100                break;
9101        case NPIPE:
9102                new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
9103                new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
9104                break;
9105        case NREDIR:
9106        case NBACKGND:
9107        case NSUBSHELL:
9108                new->nredir.redirect = copynode(n->nredir.redirect);
9109                new->nredir.n = copynode(n->nredir.n);
9110                new->nredir.linno = n->nredir.linno;
9111                break;
9112        case NAND:
9113        case NOR:
9114        case NSEMI:
9115        case NWHILE:
9116        case NUNTIL:
9117                new->nbinary.ch2 = copynode(n->nbinary.ch2);
9118                new->nbinary.ch1 = copynode(n->nbinary.ch1);
9119                break;
9120        case NIF:
9121                new->nif.elsepart = copynode(n->nif.elsepart);
9122                new->nif.ifpart = copynode(n->nif.ifpart);
9123                new->nif.test = copynode(n->nif.test);
9124                break;
9125        case NFOR:
9126                new->nfor.var = nodeckstrdup(n->nfor.var);
9127                new->nfor.body = copynode(n->nfor.body);
9128                new->nfor.args = copynode(n->nfor.args);
9129                new->nfor.linno = n->nfor.linno;
9130                break;
9131        case NCASE:
9132                new->ncase.cases = copynode(n->ncase.cases);
9133                new->ncase.expr = copynode(n->ncase.expr);
9134                new->ncase.linno = n->ncase.linno;
9135                break;
9136        case NCLIST:
9137                new->nclist.body = copynode(n->nclist.body);
9138                new->nclist.pattern = copynode(n->nclist.pattern);
9139                new->nclist.next = copynode(n->nclist.next);
9140                break;
9141        case NDEFUN:
9142                new->ndefun.body = copynode(n->ndefun.body);
9143                new->ndefun.text = nodeckstrdup(n->ndefun.text);
9144                new->ndefun.linno = n->ndefun.linno;
9145                break;
9146        case NARG:
9147                new->narg.backquote = copynodelist(n->narg.backquote);
9148                new->narg.text = nodeckstrdup(n->narg.text);
9149                new->narg.next = copynode(n->narg.next);
9150                break;
9151        case NTO:
9152#if BASH_REDIR_OUTPUT
9153        case NTO2:
9154#endif
9155        case NCLOBBER:
9156        case NFROM:
9157        case NFROMTO:
9158        case NAPPEND:
9159                new->nfile.fname = copynode(n->nfile.fname);
9160                new->nfile.fd = n->nfile.fd;
9161                new->nfile.next = copynode(n->nfile.next);
9162                break;
9163        case NTOFD:
9164        case NFROMFD:
9165                new->ndup.vname = copynode(n->ndup.vname);
9166                new->ndup.dupfd = n->ndup.dupfd;
9167                new->ndup.fd = n->ndup.fd;
9168                new->ndup.next = copynode(n->ndup.next);
9169                break;
9170        case NHERE:
9171        case NXHERE:
9172                new->nhere.doc = copynode(n->nhere.doc);
9173                new->nhere.fd = n->nhere.fd;
9174                new->nhere.next = copynode(n->nhere.next);
9175                break;
9176        case NNOT:
9177                new->nnot.com = copynode(n->nnot.com);
9178                break;
9179        };
9180        new->type = n->type;
9181        return new;
9182}
9183
9184/*
9185 * Make a copy of a parse tree.
9186 */
9187static struct funcnode *
9188copyfunc(union node *n)
9189{
9190        struct funcnode *f;
9191        size_t blocksize;
9192
9193        /*funcstringsize = 0;*/
9194        blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
9195        f = ckzalloc(blocksize /* + funcstringsize */);
9196        funcblock = (char *) f + offsetof(struct funcnode, n);
9197        funcstring_end = (char *) f + blocksize;
9198        copynode(n);
9199        /* f->count = 0; - ckzalloc did it */
9200        return f;
9201}
9202
9203/*
9204 * Define a shell function.
9205 */
9206static void
9207defun(union node *func)
9208{
9209        struct cmdentry entry;
9210
9211        INT_OFF;
9212        entry.cmdtype = CMDFUNCTION;
9213        entry.u.func = copyfunc(func);
9214        addcmdentry(func->ndefun.text, &entry);
9215        INT_ON;
9216}
9217
9218/* Reasons for skipping commands (see comment on breakcmd routine) */
9219#define SKIPBREAK      (1 << 0)
9220#define SKIPCONT       (1 << 1)
9221#define SKIPFUNC       (1 << 2)
9222#define SKIPFUNCDEF    (1 << 3)
9223static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
9224static int skipcount;           /* number of levels to skip */
9225static int loopnest;            /* current loop nesting level */
9226static int funcline;            /* starting line number of current function, or 0 if not in a function */
9227
9228/* Forward decl way out to parsing code - dotrap needs it */
9229static int evalstring(char *s, int flags);
9230
9231/* Called to execute a trap.
9232 * Single callsite - at the end of evaltree().
9233 * If we return non-zero, evaltree raises EXEXIT exception.
9234 *
9235 * Perhaps we should avoid entering new trap handlers
9236 * while we are executing a trap handler. [is it a TODO?]
9237 */
9238static void
9239dotrap(void)
9240{
9241        uint8_t *g;
9242        int sig;
9243        int status, last_status;
9244
9245        if (!pending_sig)
9246                return;
9247
9248        status = savestatus;
9249        last_status = status;
9250        if (status < 0) {
9251                status = exitstatus;
9252                savestatus = status;
9253        }
9254        pending_sig = 0;
9255        barrier();
9256
9257        TRACE(("dotrap entered\n"));
9258        for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
9259                char *p;
9260
9261                if (!*g)
9262                        continue;
9263
9264                if (evalskip) {
9265                        pending_sig = sig;
9266                        break;
9267                }
9268
9269                p = trap[sig];
9270                /* non-trapped SIGINT is handled separately by raise_interrupt,
9271                 * don't upset it by resetting gotsig[SIGINT-1] */
9272                if (sig == SIGINT && !p)
9273                        continue;
9274
9275                TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
9276                *g = 0;
9277                if (!p)
9278                        continue;
9279                trap_depth++;
9280                evalstring(p, 0);
9281                trap_depth--;
9282                if (evalskip != SKIPFUNC)
9283                        exitstatus = status;
9284        }
9285
9286        savestatus = last_status;
9287        TRACE(("dotrap returns\n"));
9288}
9289
9290/* forward declarations - evaluation is fairly recursive business... */
9291static int evalloop(union node *, int);
9292static int evalfor(union node *, int);
9293static int evalcase(union node *, int);
9294static int evalsubshell(union node *, int);
9295static void expredir(union node *);
9296static int evalpipe(union node *, int);
9297static int evalcommand(union node *, int);
9298static int evalbltin(const struct builtincmd *, int, char **, int);
9299static void prehash(union node *);
9300
9301/*
9302 * Evaluate a parse tree.  The value is left in the global variable
9303 * exitstatus.
9304 */
9305static int
9306evaltree(union node *n, int flags)
9307{
9308        int checkexit = 0;
9309        int (*evalfn)(union node *, int);
9310        struct stackmark smark;
9311        int status = 0;
9312
9313        setstackmark(&smark);
9314
9315        if (nflag)
9316                goto out;
9317
9318        if (n == NULL) {
9319                TRACE(("evaltree(NULL) called\n"));
9320                goto out;
9321        }
9322        TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
9323
9324        dotrap();
9325
9326        switch (n->type) {
9327        default:
9328#if DEBUG
9329                out1fmt("Node type = %d\n", n->type);
9330                fflush_all();
9331                break;
9332#endif
9333        case NNOT:
9334                status = !evaltree(n->nnot.com, EV_TESTED);
9335                goto setstatus;
9336        case NREDIR:
9337                errlinno = lineno = n->nredir.linno;
9338                expredir(n->nredir.redirect);
9339                pushredir(n->nredir.redirect);
9340                status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9341                if (!status) {
9342                        status = evaltree(n->nredir.n, flags & EV_TESTED);
9343                }
9344                if (n->nredir.redirect)
9345                        popredir(/*drop:*/ 0);
9346                goto setstatus;
9347        case NCMD:
9348                evalfn = evalcommand;
9349 checkexit:
9350                checkexit = ~flags & EV_TESTED;
9351                goto calleval;
9352        case NFOR:
9353                evalfn = evalfor;
9354                goto calleval;
9355        case NWHILE:
9356        case NUNTIL:
9357                evalfn = evalloop;
9358                goto calleval;
9359        case NSUBSHELL:
9360        case NBACKGND:
9361                evalfn = evalsubshell;
9362                goto checkexit;
9363        case NPIPE:
9364                evalfn = evalpipe;
9365                goto checkexit;
9366        case NCASE:
9367                evalfn = evalcase;
9368                goto calleval;
9369        case NAND:
9370        case NOR:
9371        case NSEMI: {
9372#if NAND + 1 != NOR
9373#error NAND + 1 != NOR
9374#endif
9375#if NOR + 1 != NSEMI
9376#error NOR + 1 != NSEMI
9377#endif
9378                unsigned is_or = n->type - NAND;
9379                status = evaltree(
9380                        n->nbinary.ch1,
9381                        (flags | ((is_or >> 1) - 1)) & EV_TESTED
9382                );
9383                if ((!status) == is_or || evalskip)
9384                        break;
9385                n = n->nbinary.ch2;
9386 evaln:
9387                evalfn = evaltree;
9388 calleval:
9389                status = evalfn(n, flags);
9390                goto setstatus;
9391        }
9392        case NIF:
9393                status = evaltree(n->nif.test, EV_TESTED);
9394                if (evalskip)
9395                        break;
9396                if (!status) {
9397                        n = n->nif.ifpart;
9398                        goto evaln;
9399                } else if (n->nif.elsepart) {
9400                        n = n->nif.elsepart;
9401                        goto evaln;
9402                }
9403                status = 0;
9404                goto setstatus;
9405        case NDEFUN:
9406                defun(n);
9407                /* Not necessary. To test it:
9408                 * "false; f() { qwerty; }; echo $?" should print 0.
9409                 */
9410                /* status = 0; */
9411 setstatus:
9412                exitstatus = status;
9413                break;
9414        }
9415 out:
9416        /* Order of checks below is important:
9417         * signal handlers trigger before exit caused by "set -e".
9418         */
9419        dotrap();
9420
9421        if (checkexit && status) {
9422                if (trap[NTRAP_ERR] && !in_trap_ERR) {
9423                        int err;
9424                        struct jmploc *volatile savehandler = exception_handler;
9425                        struct jmploc jmploc;
9426
9427                        in_trap_ERR = 1;
9428                        trap_depth++;
9429                        err = setjmp(jmploc.loc);
9430                        if (!err) {
9431                                exception_handler = &jmploc;
9432                                savestatus = exitstatus;
9433                                evalstring(trap[NTRAP_ERR], 0);
9434                        }
9435                        trap_depth--;
9436                        in_trap_ERR = 0;
9437
9438                        exception_handler = savehandler;
9439                        if (err && exception_type != EXERROR)
9440                                longjmp(exception_handler->loc, 1);
9441
9442                        exitstatus = savestatus;
9443                }
9444                if (eflag)
9445                        goto exexit;
9446        }
9447        if (flags & EV_EXIT) {
9448 exexit:
9449                raise_exception(EXEND);
9450        }
9451
9452        popstackmark(&smark);
9453        TRACE(("leaving evaltree (no interrupts)\n"));
9454        return exitstatus;
9455}
9456
9457static int
9458skiploop(void)
9459{
9460        int skip = evalskip;
9461
9462        switch (skip) {
9463        case 0:
9464                break;
9465        case SKIPBREAK:
9466        case SKIPCONT:
9467                if (--skipcount <= 0) {
9468                        evalskip = 0;
9469                        break;
9470                }
9471                skip = SKIPBREAK;
9472                break;
9473        }
9474        return skip;
9475}
9476
9477static int
9478evalloop(union node *n, int flags)
9479{
9480        int skip;
9481        int status;
9482
9483        loopnest++;
9484        status = 0;
9485        flags &= EV_TESTED;
9486        do {
9487                int i;
9488
9489                i = evaltree(n->nbinary.ch1, EV_TESTED);
9490                skip = skiploop();
9491                if (skip == SKIPFUNC)
9492                        status = i;
9493                if (skip)
9494                        continue;
9495                if (n->type != NWHILE)
9496                        i = !i;
9497                if (i != 0)
9498                        break;
9499                status = evaltree(n->nbinary.ch2, flags);
9500                skip = skiploop();
9501        } while (!(skip & ~SKIPCONT));
9502        loopnest--;
9503
9504        return status;
9505}
9506
9507static int
9508evalfor(union node *n, int flags)
9509{
9510        struct arglist arglist;
9511        union node *argp;
9512        struct strlist *sp;
9513        int status = 0;
9514
9515        errlinno = lineno = n->ncase.linno;
9516
9517        arglist.list = NULL;
9518        arglist.lastp = &arglist.list;
9519        for (argp = n->nfor.args; argp; argp = argp->narg.next) {
9520                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9521        }
9522        *arglist.lastp = NULL;
9523
9524        loopnest++;
9525        flags &= EV_TESTED;
9526        for (sp = arglist.list; sp; sp = sp->next) {
9527                setvar0(n->nfor.var, sp->text);
9528                status = evaltree(n->nfor.body, flags);
9529                if (skiploop() & ~SKIPCONT)
9530                        break;
9531        }
9532        loopnest--;
9533
9534        return status;
9535}
9536
9537static int
9538evalcase(union node *n, int flags)
9539{
9540        union node *cp;
9541        union node *patp;
9542        struct arglist arglist;
9543        int status = 0;
9544
9545        errlinno = lineno = n->ncase.linno;
9546
9547        arglist.list = NULL;
9548        arglist.lastp = &arglist.list;
9549        expandarg(n->ncase.expr, &arglist, EXP_TILDE);
9550        for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9551                for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
9552                        if (casematch(patp, arglist.list->text)) {
9553                                /* Ensure body is non-empty as otherwise
9554                                 * EV_EXIT may prevent us from setting the
9555                                 * exit status.
9556                                 */
9557                                if (evalskip == 0 && cp->nclist.body) {
9558                                        status = evaltree(cp->nclist.body, flags);
9559                                }
9560                                goto out;
9561                        }
9562                }
9563        }
9564 out:
9565        return status;
9566}
9567
9568/*
9569 * Kick off a subshell to evaluate a tree.
9570 */
9571static int
9572evalsubshell(union node *n, int flags)
9573{
9574        struct job *jp;
9575        int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9576        int status;
9577
9578        errlinno = lineno = n->nredir.linno;
9579
9580        expredir(n->nredir.redirect);
9581        if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9582                goto nofork;
9583        INT_OFF;
9584        if (backgnd == FORK_FG)
9585                get_tty_state();
9586        jp = makejob(/*n,*/ 1);
9587        if (forkshell(jp, n, backgnd) == 0) {
9588                /* child */
9589                INT_ON;
9590                flags |= EV_EXIT;
9591                if (backgnd)
9592                        flags &= ~EV_TESTED;
9593 nofork:
9594                redirect(n->nredir.redirect, 0);
9595                evaltreenr(n->nredir.n, flags);
9596                /* never returns */
9597        }
9598        /* parent */
9599        status = 0;
9600        if (backgnd == FORK_FG)
9601                status = waitforjob(jp);
9602        INT_ON;
9603        return status;
9604}
9605
9606/*
9607 * Compute the names of the files in a redirection list.
9608 */
9609static void fixredir(union node *, const char *, int);
9610static void
9611expredir(union node *n)
9612{
9613        union node *redir;
9614
9615        for (redir = n; redir; redir = redir->nfile.next) {
9616                struct arglist fn;
9617
9618                fn.list = NULL;
9619                fn.lastp = &fn.list;
9620                switch (redir->type) {
9621                case NFROMTO:
9622                case NFROM:
9623                case NTO:
9624#if BASH_REDIR_OUTPUT
9625                case NTO2:
9626#endif
9627                case NCLOBBER:
9628                case NAPPEND:
9629                        expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
9630                        TRACE(("expredir expanded to '%s'\n", fn.list->text));
9631#if BASH_REDIR_OUTPUT
9632 store_expfname:
9633#endif
9634#if 0
9635// By the design of stack allocator, the loop of this kind:
9636//      while true; do while true; do break; done </dev/null; done
9637// will look like a memory leak: ash plans to free expfname's
9638// of "/dev/null" as soon as it finishes running the loop
9639// (in this case, never).
9640// This "fix" is wrong:
9641                        if (redir->nfile.expfname)
9642                                stunalloc(redir->nfile.expfname);
9643// It results in corrupted state of stacked allocations.
9644#endif
9645                        redir->nfile.expfname = fn.list->text;
9646                        break;
9647                case NFROMFD:
9648                case NTOFD: /* >& */
9649                        if (redir->ndup.vname) {
9650                                expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
9651                                if (fn.list == NULL)
9652                                        ash_msg_and_raise_error("redir error");
9653#if BASH_REDIR_OUTPUT
9654                                if (!isdigit_str9(fn.list->text)) {
9655                                        /* >&file, not >&fd */
9656                                        if (redir->nfile.fd != 1) /* 123>&file - BAD */
9657                                                ash_msg_and_raise_error("redir error");
9658                                        redir->type = NTO2;
9659                                        goto store_expfname;
9660                                }
9661#endif
9662                                fixredir(redir, fn.list->text, 1);
9663                        }
9664                        break;
9665                }
9666        }
9667}
9668
9669/*
9670 * Evaluate a pipeline.  All the processes in the pipeline are children
9671 * of the process creating the pipeline.  (This differs from some versions
9672 * of the shell, which make the last process in a pipeline the parent
9673 * of all the rest.)
9674 */
9675static int
9676evalpipe(union node *n, int flags)
9677{
9678        struct job *jp;
9679        struct nodelist *lp;
9680        int pipelen;
9681        int prevfd;
9682        int pip[2];
9683        int status = 0;
9684
9685        TRACE(("evalpipe(0x%lx) called\n", (long)n));
9686        pipelen = 0;
9687        for (lp = n->npipe.cmdlist; lp; lp = lp->next)
9688                pipelen++;
9689        flags |= EV_EXIT;
9690        INT_OFF;
9691        if (n->npipe.pipe_backgnd == 0)
9692                get_tty_state();
9693        jp = makejob(/*n,*/ pipelen);
9694        prevfd = -1;
9695        for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
9696                prehash(lp->n);
9697                pip[1] = -1;
9698                if (lp->next) {
9699                        if (pipe(pip) < 0) {
9700                                close(prevfd);
9701                                ash_msg_and_raise_perror("can't create pipe");
9702                        }
9703                }
9704                if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9705                        /* child */
9706                        INT_ON;
9707                        if (pip[1] >= 0) {
9708                                close(pip[0]);
9709                        }
9710                        if (prevfd > 0) {
9711                                dup2(prevfd, 0);
9712                                close(prevfd);
9713                        }
9714                        if (pip[1] > 1) {
9715                                dup2(pip[1], 1);
9716                                close(pip[1]);
9717                        }
9718                        evaltreenr(lp->n, flags);
9719                        /* never returns */
9720                }
9721                /* parent */
9722                if (prevfd >= 0)
9723                        close(prevfd);
9724                prevfd = pip[0];
9725                /* Don't want to trigger debugging */
9726                if (pip[1] != -1)
9727                        close(pip[1]);
9728        }
9729        if (n->npipe.pipe_backgnd == 0) {
9730                status = waitforjob(jp);
9731                TRACE(("evalpipe:  job done exit status %d\n", status));
9732        }
9733        INT_ON;
9734
9735        return status;
9736}
9737
9738/* setinteractive needs this forward reference */
9739#if ENABLE_FEATURE_TAB_COMPLETION
9740static const char *get_builtin_name(int i) FAST_FUNC;
9741#endif
9742
9743/*
9744 * Controls whether the shell is interactive or not.
9745 */
9746static void
9747setinteractive(int on)
9748{
9749        static smallint is_interactive;
9750
9751        if (++on == is_interactive)
9752                return;
9753        is_interactive = on;
9754        setsignal(SIGINT);
9755        setsignal(SIGQUIT);
9756        setsignal(SIGTERM);
9757        if (is_interactive > 1) {
9758#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9759                /* Looks like they want an interactive shell */
9760                static smallint did_banner;
9761
9762                if (!did_banner) {
9763                        /* note: ash and hush share this string */
9764                        out1fmt("\n\n%s %s\n"
9765                                IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9766                                "\n",
9767                                bb_banner,
9768                                "built-in shell (ash)"
9769                        );
9770                        did_banner = 1;
9771                }
9772#endif
9773#if ENABLE_FEATURE_EDITING
9774                if (!line_input_state) {
9775                        line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
9776# if ENABLE_FEATURE_TAB_COMPLETION
9777                        line_input_state->get_exe_name = get_builtin_name;
9778# endif
9779# if EDITING_HAS_sh_get_var
9780                        line_input_state->sh_get_var = lookupvar;
9781# endif
9782                }
9783#endif
9784        }
9785}
9786
9787static void
9788optschanged(void)
9789{
9790#if DEBUG
9791        opentrace();
9792#endif
9793        setinteractive(iflag);
9794        setjobctl(mflag);
9795#if ENABLE_FEATURE_EDITING_VI
9796        if (line_input_state) {
9797                if (viflag)
9798                        line_input_state->flags |= VI_MODE;
9799                else
9800                        line_input_state->flags &= ~VI_MODE;
9801        }
9802#else
9803        viflag = 0; /* forcibly keep the option off */
9804#endif
9805}
9806
9807struct localvar_list {
9808        struct localvar_list *next;
9809        struct localvar *lv;
9810};
9811
9812static struct localvar_list *localvar_stack;
9813
9814/*
9815 * Called after a function returns.
9816 * Interrupts must be off.
9817 */
9818static void
9819poplocalvars(int keep)
9820{
9821        struct localvar_list *ll;
9822        struct localvar *lvp, *next;
9823        struct var *vp;
9824
9825        INT_OFF;
9826        ll = localvar_stack;
9827        localvar_stack = ll->next;
9828
9829        next = ll->lv;
9830        free(ll);
9831
9832        while ((lvp = next) != NULL) {
9833                next = lvp->next;
9834                vp = lvp->vp;
9835                TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9836                if (keep) {
9837                        int bits = VSTRFIXED;
9838
9839                        if (lvp->flags != VUNSET) {
9840                                if (vp->var_text == lvp->text)
9841                                        bits |= VTEXTFIXED;
9842                                else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9843                                        free((char*)lvp->text);
9844                        }
9845
9846                        vp->flags &= ~bits;
9847                        vp->flags |= (lvp->flags & bits);
9848
9849                        if ((vp->flags &
9850                             (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9851                                unsetvar(vp->var_text);
9852                } else if (vp == NULL) {        /* $- saved */
9853                        memcpy(optlist, lvp->text, sizeof(optlist));
9854                        free((char*)lvp->text);
9855                        optschanged();
9856                } else if (lvp->flags == VUNSET) {
9857                        vp->flags &= ~(VSTRFIXED|VREADONLY);
9858                        unsetvar(vp->var_text);
9859                } else {
9860                        if (vp->var_func)
9861                                vp->var_func(var_end(lvp->text));
9862                        if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9863                                free((char*)vp->var_text);
9864                        vp->flags = lvp->flags;
9865                        vp->var_text = lvp->text;
9866                }
9867                free(lvp);
9868        }
9869        INT_ON;
9870}
9871
9872/*
9873 * Create a new localvar environment.
9874 */
9875static struct localvar_list *
9876pushlocalvars(int push)
9877{
9878        struct localvar_list *ll;
9879        struct localvar_list *top;
9880
9881        top = localvar_stack;
9882        if (!push)
9883                goto out;
9884
9885        INT_OFF;
9886        ll = ckzalloc(sizeof(*ll));
9887        /*ll->lv = NULL; - zalloc did it */
9888        ll->next = top;
9889        localvar_stack = ll;
9890        INT_ON;
9891 out:
9892        return top;
9893}
9894
9895static void
9896unwindlocalvars(struct localvar_list *stop)
9897{
9898        while (localvar_stack != stop)
9899                poplocalvars(0);
9900}
9901
9902static int
9903evalfun(struct funcnode *func, int argc, char **argv, int flags)
9904{
9905        volatile struct shparam saveparam;
9906        struct jmploc *volatile savehandler;
9907        struct jmploc jmploc;
9908        int e;
9909        int savelineno;
9910        int savefuncline;
9911        char *savefuncname;
9912        char *savetrap = NULL;
9913
9914        if (!Eflag) {
9915                savetrap = trap[NTRAP_ERR];
9916                trap[NTRAP_ERR] = NULL;
9917        }
9918        savelineno = lineno;
9919        saveparam = shellparam;
9920        savefuncline = funcline;
9921        savefuncname = funcname;
9922        savehandler = exception_handler;
9923        e = setjmp(jmploc.loc);
9924        if (e) {
9925                goto funcdone;
9926        }
9927        INT_OFF;
9928        exception_handler = &jmploc;
9929        shellparam.malloced = 0;
9930        func->count++;
9931        funcname = func->n.ndefun.text;
9932        funcline = func->n.ndefun.linno;
9933        INT_ON;
9934        shellparam.nparam = argc - 1;
9935        shellparam.p = argv + 1;
9936#if ENABLE_ASH_GETOPTS
9937        shellparam.optind = 1;
9938        shellparam.optoff = -1;
9939#endif
9940        evaltree(func->n.ndefun.body, flags & EV_TESTED);
9941 funcdone:
9942        INT_OFF;
9943        funcname = savefuncname;
9944        if (savetrap) {
9945                if (!trap[NTRAP_ERR])
9946                        trap[NTRAP_ERR] = savetrap;
9947                else
9948                        free(savetrap);
9949        }
9950        funcline = savefuncline;
9951        lineno = savelineno;
9952        freefunc(func);
9953        freeparam(&shellparam);
9954        shellparam = saveparam;
9955        exception_handler = savehandler;
9956        INT_ON;
9957        evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
9958        return e;
9959}
9960
9961/*
9962 * Make a variable a local variable.  When a variable is made local, it's
9963 * value and flags are saved in a localvar structure.  The saved values
9964 * will be restored when the shell function returns.  We handle the name
9965 * "-" as a special case: it makes changes to "set +-options" local
9966 * (options will be restored on return from the function).
9967 */
9968static void
9969mklocal(char *name, int flags)
9970{
9971        struct localvar *lvp;
9972        struct var **vpp;
9973        struct var *vp;
9974        char *eq = strchr(name, '=');
9975
9976        INT_OFF;
9977        /* Cater for duplicate "local". Examples:
9978         * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9979         * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9980         */
9981        lvp = localvar_stack->lv;
9982        while (lvp) {
9983                if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9984                        if (eq)
9985                                setvareq(name, 0);
9986                        /* else:
9987                         * it's a duplicate "local VAR" declaration, do nothing
9988                         */
9989                        goto ret;
9990                }
9991                lvp = lvp->next;
9992        }
9993
9994        lvp = ckzalloc(sizeof(*lvp));
9995        if (LONE_DASH(name)) {
9996                char *p;
9997                p = ckmalloc(sizeof(optlist));
9998                lvp->text = memcpy(p, optlist, sizeof(optlist));
9999                vp = NULL;
10000        } else {
10001                vpp = hashvar(name);
10002                vp = *findvar(vpp, name);
10003                if (vp == NULL) {
10004                        /* variable did not exist yet */
10005                        if (eq)
10006                                vp = setvareq(name, VSTRFIXED | flags);
10007                        else
10008                                vp = setvar(name, NULL, VSTRFIXED | flags);
10009                        lvp->flags = VUNSET;
10010                } else {
10011                        lvp->text = vp->var_text;
10012                        lvp->flags = vp->flags;
10013                        /* make sure neither "struct var" nor string gets freed
10014                         * during (un)setting:
10015                         */
10016                        vp->flags |= VSTRFIXED|VTEXTFIXED;
10017                        if (eq)
10018                                setvareq(name, flags);
10019                        else
10020                                /* "local VAR" unsets VAR: */
10021                                unsetvar(name);
10022                }
10023        }
10024        lvp->vp = vp;
10025        lvp->next = localvar_stack->lv;
10026        localvar_stack->lv = lvp;
10027 ret:
10028        INT_ON;
10029}
10030
10031/*
10032 * The "local" command.
10033 */
10034static int FAST_FUNC
10035localcmd(int argc UNUSED_PARAM, char **argv)
10036{
10037        char *name;
10038
10039        if (!localvar_stack)
10040                ash_msg_and_raise_error("not in a function");
10041
10042        argv = argptr;
10043        while ((name = *argv++) != NULL) {
10044                mklocal(name, 0);
10045        }
10046        return 0;
10047}
10048
10049static int FAST_FUNC
10050falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10051{
10052        return 1;
10053}
10054
10055static int FAST_FUNC
10056truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10057{
10058        return 0;
10059}
10060
10061static int FAST_FUNC
10062execcmd(int argc UNUSED_PARAM, char **argv)
10063{
10064        optionarg = NULL;
10065        while (nextopt("a:") != '\0')
10066                /* nextopt() sets optionarg to "-a ARGV0" */;
10067
10068        argv = argptr;
10069        if (argv[0]) {
10070                char *prog;
10071
10072                iflag = 0;              /* exit on error */
10073                mflag = 0;
10074                optschanged();
10075                /* We should set up signals for "exec CMD"
10076                 * the same way as for "CMD" without "exec".
10077                 * But optschanged->setinteractive->setsignal
10078                 * still thought we are a root shell. Therefore, for example,
10079                 * SIGQUIT is still set to IGN. Fix it:
10080                 */
10081                shlvl++;
10082                setsignal(SIGQUIT);
10083                /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
10084                /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
10085                /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
10086
10087                prog = argv[0];
10088                if (optionarg)
10089                        argv[0] = optionarg;
10090                shellexec(prog, argv, pathval(), 0);
10091                /* NOTREACHED */
10092        }
10093        return 0;
10094}
10095
10096/*
10097 * The return command.
10098 */
10099static int FAST_FUNC
10100returncmd(int argc UNUSED_PARAM, char **argv)
10101{
10102        int skip;
10103        int status;
10104
10105        /*
10106         * If called outside a function, do what ksh does;
10107         * skip the rest of the file.
10108         */
10109        if (argv[1]) {
10110                skip = SKIPFUNC;
10111                status = number(argv[1]);
10112        } else {
10113                skip = SKIPFUNCDEF;
10114                status = exitstatus;
10115        }
10116        evalskip = skip;
10117
10118        return status;
10119}
10120
10121/* Forward declarations for builtintab[] */
10122static int breakcmd(int, char **) FAST_FUNC;
10123static int dotcmd(int, char **) FAST_FUNC;
10124static int evalcmd(int, char **, int) FAST_FUNC;
10125static int exitcmd(int, char **) FAST_FUNC;
10126static int exportcmd(int, char **) FAST_FUNC;
10127#if ENABLE_ASH_GETOPTS
10128static int getoptscmd(int, char **) FAST_FUNC;
10129#endif
10130#if ENABLE_ASH_HELP
10131static int helpcmd(int, char **) FAST_FUNC;
10132#endif
10133#if MAX_HISTORY
10134static int historycmd(int, char **) FAST_FUNC;
10135#endif
10136#if ENABLE_FEATURE_SH_MATH
10137static int letcmd(int, char **) FAST_FUNC;
10138#endif
10139static int readcmd(int, char **) FAST_FUNC;
10140static int setcmd(int, char **) FAST_FUNC;
10141static int shiftcmd(int, char **) FAST_FUNC;
10142static int timescmd(int, char **) FAST_FUNC;
10143static int trapcmd(int, char **) FAST_FUNC;
10144static int umaskcmd(int, char **) FAST_FUNC;
10145static int unsetcmd(int, char **) FAST_FUNC;
10146static int ulimitcmd(int, char **) FAST_FUNC;
10147
10148#define BUILTIN_NOSPEC          "0"
10149#define BUILTIN_SPECIAL         "1"
10150#define BUILTIN_REGULAR         "2"
10151#define BUILTIN_SPEC_REG        "3"
10152#define BUILTIN_ASSIGN          "4"
10153#define BUILTIN_SPEC_ASSG       "5"
10154#define BUILTIN_REG_ASSG        "6"
10155#define BUILTIN_SPEC_REG_ASSG   "7"
10156
10157/* Stubs for calling non-FAST_FUNC's */
10158#if ENABLE_ASH_ECHO
10159static int FAST_FUNC echocmd(int argc, char **argv)   { return echo_main(argc, argv); }
10160#endif
10161#if ENABLE_ASH_PRINTF
10162static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
10163#endif
10164#if ENABLE_ASH_TEST || BASH_TEST2
10165static int FAST_FUNC testcmd(int argc, char **argv)   { return test_main(argc, argv); }
10166#endif
10167#if ENABLE_ASH_SLEEP
10168static int FAST_FUNC sleepcmd(int argc, char **argv)  { return sleep_main(argc, argv); }
10169#endif
10170
10171/* Keep these in proper order since it is searched via bsearch() */
10172static const struct builtincmd builtintab[] = {
10173        { BUILTIN_SPEC_REG      "."       , dotcmd     },
10174        { BUILTIN_SPEC_REG      ":"       , truecmd    },
10175#if ENABLE_ASH_TEST
10176        { BUILTIN_REGULAR       "["       , testcmd    },
10177#endif
10178#if BASH_TEST2
10179        { BUILTIN_REGULAR       "[["      , testcmd    },
10180#endif
10181#if ENABLE_ASH_ALIAS
10182        { BUILTIN_REG_ASSG      "alias"   , aliascmd   },
10183#endif
10184#if JOBS
10185        { BUILTIN_REGULAR       "bg"      , fg_bgcmd   },
10186#endif
10187        { BUILTIN_SPEC_REG      "break"   , breakcmd   },
10188        { BUILTIN_REGULAR       "cd"      , cdcmd      },
10189        { BUILTIN_NOSPEC        "chdir"   , cdcmd      },
10190#if ENABLE_ASH_CMDCMD
10191        { BUILTIN_REGULAR       "command" , commandcmd },
10192#endif
10193        { BUILTIN_SPEC_REG      "continue", breakcmd   },
10194#if ENABLE_ASH_ECHO
10195        { BUILTIN_REGULAR       "echo"    , echocmd    },
10196#endif
10197        { BUILTIN_SPEC_REG      "eval"    , NULL       }, /*evalcmd() has a differing prototype*/
10198        { BUILTIN_SPEC_REG      "exec"    , execcmd    },
10199        { BUILTIN_SPEC_REG      "exit"    , exitcmd    },
10200        { BUILTIN_SPEC_REG_ASSG "export"  , exportcmd  },
10201        { BUILTIN_REGULAR       "false"   , falsecmd   },
10202#if JOBS
10203        { BUILTIN_REGULAR       "fg"      , fg_bgcmd   },
10204#endif
10205#if ENABLE_ASH_GETOPTS
10206        { BUILTIN_REGULAR       "getopts" , getoptscmd },
10207#endif
10208        { BUILTIN_REGULAR       "hash"    , hashcmd    },
10209#if ENABLE_ASH_HELP
10210        { BUILTIN_NOSPEC        "help"    , helpcmd    },
10211#endif
10212#if MAX_HISTORY
10213        { BUILTIN_NOSPEC        "history" , historycmd },
10214#endif
10215#if JOBS
10216        { BUILTIN_REGULAR       "jobs"    , jobscmd    },
10217        { BUILTIN_REGULAR       "kill"    , killcmd    },
10218#endif
10219#if ENABLE_FEATURE_SH_MATH
10220        { BUILTIN_NOSPEC        "let"     , letcmd     },
10221#endif
10222        { BUILTIN_SPEC_REG_ASSG "local"   , localcmd   },
10223#if ENABLE_ASH_PRINTF
10224        { BUILTIN_REGULAR       "printf"  , printfcmd  },
10225#endif
10226        { BUILTIN_REGULAR       "pwd"     , pwdcmd     },
10227        { BUILTIN_REGULAR       "read"    , readcmd    },
10228        { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd  },
10229        { BUILTIN_SPEC_REG      "return"  , returncmd  },
10230        { BUILTIN_SPEC_REG      "set"     , setcmd     },
10231        { BUILTIN_SPEC_REG      "shift"   , shiftcmd   },
10232#if ENABLE_ASH_SLEEP
10233        { BUILTIN_REGULAR       "sleep"   , sleepcmd   },
10234#endif
10235#if BASH_SOURCE
10236        { BUILTIN_SPEC_REG      "source"  , dotcmd     },
10237#endif
10238#if ENABLE_ASH_TEST
10239        { BUILTIN_REGULAR       "test"    , testcmd    },
10240#endif
10241        { BUILTIN_SPEC_REG      "times"   , timescmd   },
10242        { BUILTIN_SPEC_REG      "trap"    , trapcmd    },
10243        { BUILTIN_REGULAR       "true"    , truecmd    },
10244        { BUILTIN_REGULAR       "type"    , typecmd    },
10245        { BUILTIN_REGULAR       "ulimit"  , ulimitcmd  },
10246        { BUILTIN_REGULAR       "umask"   , umaskcmd   },
10247#if ENABLE_ASH_ALIAS
10248        { BUILTIN_REGULAR       "unalias" , unaliascmd },
10249#endif
10250        { BUILTIN_SPEC_REG      "unset"   , unsetcmd   },
10251        { BUILTIN_REGULAR       "wait"    , waitcmd    },
10252};
10253
10254/* Should match the above table! */
10255#define COMMANDCMD (builtintab + \
10256        /* . : */       2 + \
10257        /* [ */         1 * ENABLE_ASH_TEST + \
10258        /* [[ */        1 * BASH_TEST2 + \
10259        /* alias */     1 * ENABLE_ASH_ALIAS + \
10260        /* bg */        1 * ENABLE_ASH_JOB_CONTROL + \
10261        /* break cd cddir  */   3)
10262#define EVALCMD (COMMANDCMD + \
10263        /* command */   1 * ENABLE_ASH_CMDCMD + \
10264        /* continue */  1 + \
10265        /* echo */      1 * ENABLE_ASH_ECHO + \
10266        0)
10267#define EXECCMD (EVALCMD + \
10268        /* eval */      1)
10269
10270/*
10271 * Search the table of builtin commands.
10272 */
10273static int
10274pstrcmp1(const void *a, const void *b)
10275{
10276        return strcmp((char*)a, *(char**)b + 1);
10277}
10278static struct builtincmd *
10279find_builtin(const char *name)
10280{
10281        struct builtincmd *bp;
10282
10283        bp = bsearch(
10284                name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
10285                pstrcmp1
10286        );
10287        return bp;
10288}
10289
10290#if ENABLE_FEATURE_TAB_COMPLETION
10291static const char * FAST_FUNC
10292get_builtin_name(int i)
10293{
10294        return /*i >= 0 &&*/ i < ARRAY_SIZE(builtintab) ? builtintab[i].name + 1 : NULL;
10295}
10296#endif
10297
10298/*
10299 * Execute a simple command.
10300 */
10301static void unwindfiles(struct parsefile *stop);
10302static int
10303isassignment(const char *p)
10304{
10305        const char *q = endofname(p);
10306        if (p == q)
10307                return 0;
10308        return *q == '=';
10309}
10310static int FAST_FUNC
10311bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10312{
10313        /* Preserve exitstatus of a previous possible redirection
10314         * as POSIX mandates */
10315        return back_exitstatus;
10316}
10317static int
10318evalcommand(union node *cmd, int flags)
10319{
10320        static const struct builtincmd null_bltin = {
10321                BUILTIN_REGULAR "", bltincmd
10322        };
10323        struct localvar_list *localvar_stop;
10324        struct parsefile *file_stop;
10325        struct redirtab *redir_stop;
10326        union node *argp;
10327        struct arglist arglist;
10328        struct arglist varlist;
10329        char **argv;
10330        int argc;
10331        struct strlist *osp;
10332        const struct strlist *sp;
10333        struct cmdentry cmdentry;
10334        struct job *jp;
10335        char *lastarg;
10336        const char *path;
10337        int spclbltin;
10338        int cmd_flag;
10339        int status;
10340        char **nargv;
10341        smallint cmd_is_exec;
10342        int vflags;
10343        int vlocal;
10344
10345        errlinno = lineno = cmd->ncmd.linno;
10346
10347        /* First expand the arguments. */
10348        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
10349#if BASH_PROCESS_SUBST
10350        redir_stop = redirlist;
10351#endif
10352        file_stop = g_parsefile;
10353        back_exitstatus = 0;
10354
10355        cmdentry.cmdtype = CMDBUILTIN;
10356        cmdentry.u.cmd = &null_bltin;
10357        varlist.lastp = &varlist.list;
10358        *varlist.lastp = NULL;
10359        arglist.lastp = &arglist.list;
10360        *arglist.lastp = NULL;
10361
10362        cmd_flag = 0;
10363        cmd_is_exec = 0;
10364        spclbltin = -1;
10365        vflags = 0;
10366        vlocal = 0;
10367        path = NULL;
10368
10369        argc = 0;
10370        argp = cmd->ncmd.args;
10371        osp = fill_arglist(&arglist, &argp);
10372        if (osp) {
10373                int pseudovarflag = 0;
10374
10375                for (;;) {
10376                        find_command(arglist.list->text, &cmdentry,
10377                                        cmd_flag | DO_REGBLTIN, pathval());
10378
10379                        vlocal++;
10380
10381                        /* implement bltin and command here */
10382                        if (cmdentry.cmdtype != CMDBUILTIN)
10383                                break;
10384
10385                        pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
10386                        if (spclbltin < 0) {
10387                                spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10388                                vlocal = !spclbltin;
10389                        }
10390                        cmd_is_exec = cmdentry.u.cmd == EXECCMD;
10391#if ENABLE_ASH_CMDCMD
10392                        if (cmdentry.u.cmd != COMMANDCMD)
10393                                break;
10394
10395                        cmd_flag = parse_command_args(&arglist, &argp, &path);
10396                        if (!cmd_flag)
10397#endif
10398                                break;
10399                }
10400
10401                for (; argp; argp = argp->narg.next)
10402                        expandarg(argp, &arglist,
10403                                        pseudovarflag &&
10404                                        isassignment(argp->narg.text) ?
10405                                        EXP_VARTILDE : EXP_FULL | EXP_TILDE);
10406
10407                for (sp = arglist.list; sp; sp = sp->next)
10408                        argc++;
10409
10410                if (cmd_is_exec && argc > 1)
10411                        vflags = VEXPORT;
10412        }
10413
10414        localvar_stop = pushlocalvars(vlocal);
10415
10416        /* Reserve one extra spot at the front for shellexec. */
10417        nargv = stalloc(sizeof(char *) * (argc + 2));
10418        argv = ++nargv;
10419        for (sp = arglist.list; sp; sp = sp->next) {
10420                TRACE(("evalcommand arg: %s\n", sp->text));
10421                *nargv++ = sp->text;
10422        }
10423        *nargv = NULL;
10424
10425        lastarg = NULL;
10426        if (iflag && funcline == 0 && argc > 0)
10427                lastarg = nargv[-1];
10428
10429        expredir(cmd->ncmd.redirect);
10430#if !BASH_PROCESS_SUBST
10431        redir_stop = pushredir(cmd->ncmd.redirect);
10432#else
10433        pushredir(cmd->ncmd.redirect);
10434#endif
10435        preverrout_fd = 2;
10436        if (BASH_XTRACEFD && xflag) {
10437                /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10438                 * we do not emulate this. We only use its value.
10439                 */
10440                const char *xtracefd = lookupvar("BASH_XTRACEFD");
10441                if (xtracefd && is_number(xtracefd))
10442                        preverrout_fd = atoi(xtracefd);
10443
10444        }
10445        status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10446
10447        if (status) {
10448 bail:
10449                exitstatus = status;
10450
10451                /* We have a redirection error. */
10452                if (spclbltin > 0)
10453                        raise_exception(EXERROR);
10454
10455                goto out;
10456        }
10457
10458        for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10459                struct strlist **spp;
10460
10461                spp = varlist.lastp;
10462                expandarg(argp, &varlist, EXP_VARTILDE);
10463
10464                if (vlocal)
10465                        mklocal((*spp)->text, VEXPORT);
10466                else
10467                        setvareq((*spp)->text, vflags);
10468        }
10469
10470        /* Print the command if xflag is set. */
10471        if (xflag && !inps4) {
10472                const char *pfx = "";
10473
10474                inps4 = 1;
10475                fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
10476                inps4 = 0;
10477
10478                sp = varlist.list;
10479                while (sp) {
10480                        char *varval = sp->text;
10481                        char *eq = strchrnul(varval, '=');
10482                        if (*eq)
10483                                eq++;
10484                        fdprintf(preverrout_fd, "%s%.*s%s",
10485                                pfx,
10486                                (int)(eq - varval), varval,
10487                                maybe_single_quote(eq)
10488                        );
10489                        sp = sp->next;
10490                        pfx = " ";
10491                }
10492
10493                sp = arglist.list;
10494                while (sp) {
10495                        fdprintf(preverrout_fd, "%s%s",
10496                                pfx,
10497                                /* always quote if matches reserved word: */
10498                                findkwd(sp->text)
10499                                ? single_quote(sp->text)
10500                                : maybe_single_quote(sp->text)
10501                        );
10502                        sp = sp->next;
10503                        pfx = " ";
10504                }
10505                safe_write(preverrout_fd, "\n", 1);
10506        }
10507
10508        /* Now locate the command. */
10509        if (cmdentry.cmdtype != CMDBUILTIN
10510         || !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
10511        ) {
10512                path = path ? path : pathval();
10513                find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path);
10514        }
10515
10516        jp = NULL;
10517
10518        /* Execute the command. */
10519        switch (cmdentry.cmdtype) {
10520        case CMDUNKNOWN:
10521                status = 127;
10522                flush_stdout_stderr();
10523                goto bail;
10524
10525        default: {
10526
10527#if ENABLE_FEATURE_SH_STANDALONE \
10528 && ENABLE_FEATURE_SH_NOFORK \
10529 && NUM_APPLETS > 1
10530/* (1) BUG: if variables are set, we need to fork, or save/restore them
10531 *     around run_nofork_applet() call.
10532 * (2) Should this check also be done in forkshell()?
10533 *     (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10534 */
10535                /* find_command() encodes applet_no as (-2 - applet_no) */
10536                int applet_no = (- cmdentry.u.index - 2);
10537                if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10538                        char **sv_environ;
10539
10540                        INT_OFF;
10541                        sv_environ = environ;
10542                        environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
10543                        /*
10544                         * Run <applet>_main().
10545                         * Signals (^C) can't interrupt here.
10546                         * Otherwise we can mangle stdio or malloc internal state.
10547                         * This makes applets which can run for a long time
10548                         * and/or wait for user input ineligible for NOFORK:
10549                         * for example, "yes" or "rm" (rm -i waits for input).
10550                         */
10551                        exitstatus = run_nofork_applet(applet_no, argv);
10552                        environ = sv_environ;
10553                        /*
10554                         * Try enabling NOFORK for "yes" applet.
10555                         * ^C _will_ stop it (write returns EINTR),
10556                         * but this causes stdout FILE to be stuck
10557                         * and needing clearerr(). What if other applets
10558                         * also can get EINTRs? Do we need to switch
10559                         * our signals to SA_RESTART?
10560                         */
10561                        /*clearerr(stdout);*/
10562                        INT_ON;
10563                        break;
10564                }
10565#endif
10566                /* Can we avoid forking? For example, very last command
10567                 * in a script or a subshell does not need forking,
10568                 * we can just exec it.
10569                 */
10570                if (!(flags & EV_EXIT) || may_have_traps) {
10571                        /* No, forking off a child is necessary */
10572                        INT_OFF;
10573                        get_tty_state();
10574                        jp = makejob(/*cmd,*/ 1);
10575                        if (forkshell(jp, cmd, FORK_FG) != 0) {
10576                                /* parent */
10577                                break;
10578                        }
10579                        /* child */
10580                        FORCE_INT_ON;
10581                        /* fall through to exec'ing external program */
10582                }
10583                shellexec(argv[0], argv, path, cmdentry.u.index);
10584                /* NOTREACHED */
10585        } /* default */
10586        case CMDBUILTIN:
10587                if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
10588                 && !(exception_type == EXERROR && spclbltin <= 0)
10589                ) {
10590 raise:
10591                        longjmp(exception_handler->loc, 1);
10592                }
10593                break;
10594
10595        case CMDFUNCTION:
10596                if (evalfun(cmdentry.u.func, argc, argv, flags))
10597                        goto raise;
10598                break;
10599        } /* switch */
10600
10601        status = waitforjob(jp);
10602        if (jp)
10603                TRACE(("forked child exited with %d\n", status));
10604        FORCE_INT_ON;
10605
10606 out:
10607        if (cmd->ncmd.redirect)
10608                popredir(/*drop:*/ cmd_is_exec);
10609        unwindredir(redir_stop);
10610        unwindfiles(file_stop);
10611        unwindlocalvars(localvar_stop);
10612        if (lastarg) {
10613                /* dsl: I think this is intended to be used to support
10614                 * '_' in 'vi' command mode during line editing...
10615                 * However I implemented that within libedit itself.
10616                 */
10617                setvar0("_", lastarg);
10618        }
10619
10620        return status;
10621}
10622
10623static int
10624evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
10625{
10626        char *volatile savecmdname;
10627        struct jmploc *volatile savehandler;
10628        struct jmploc jmploc;
10629        int status;
10630        int i;
10631
10632        savecmdname = commandname;
10633        savehandler = exception_handler;
10634        i = setjmp(jmploc.loc);
10635        if (i)
10636                goto cmddone;
10637        exception_handler = &jmploc;
10638        commandname = argv[0];
10639        argptr = argv + 1;
10640        optptr = NULL;                  /* initialize nextopt */
10641        if (cmd == EVALCMD)
10642                status = evalcmd(argc, argv, flags);
10643        else
10644                status = (*cmd->builtin)(argc, argv);
10645        flush_stdout_stderr();
10646        status |= ferror(stdout);
10647        exitstatus = status;
10648 cmddone:
10649        clearerr(stdout);
10650        commandname = savecmdname;
10651        exception_handler = savehandler;
10652
10653        return i;
10654}
10655
10656static int
10657goodname(const char *p)
10658{
10659        return endofname(p)[0] == '\0';
10660}
10661
10662
10663/*
10664 * Search for a command.  This is called before we fork so that the
10665 * location of the command will be available in the parent as well as
10666 * the child.  The check for "goodname" is an overly conservative
10667 * check that the name will not be subject to expansion.
10668 */
10669static void
10670prehash(union node *n)
10671{
10672        struct cmdentry entry;
10673
10674        if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10675                find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
10676}
10677
10678
10679/* ============ Builtin commands
10680 *
10681 * Builtin commands whose functions are closely tied to evaluation
10682 * are implemented here.
10683 */
10684
10685/*
10686 * Handle break and continue commands.  Break, continue, and return are
10687 * all handled by setting the evalskip flag.  The evaluation routines
10688 * above all check this flag, and if it is set they start skipping
10689 * commands rather than executing them.  The variable skipcount is
10690 * the number of loops to break/continue, or the number of function
10691 * levels to return.  (The latter is always 1.)  It should probably
10692 * be an error to break out of more loops than exist, but it isn't
10693 * in the standard shell so we don't make it one here.
10694 */
10695static int FAST_FUNC
10696breakcmd(int argc UNUSED_PARAM, char **argv)
10697{
10698        int n = argv[1] ? number(argv[1]) : 1;
10699
10700        if (n <= 0)
10701                ash_msg_and_raise_error(msg_illnum, argv[1]);
10702        if (n > loopnest)
10703                n = loopnest;
10704        if (n > 0) {
10705                evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
10706                skipcount = n;
10707        }
10708        return 0;
10709}
10710
10711
10712/*
10713 * This implements the input routines used by the parser.
10714 */
10715
10716enum {
10717        INPUT_PUSH_FILE = 1,
10718        INPUT_NOFILE_OK = 2,
10719};
10720
10721static smallint checkkwd;
10722/* values of checkkwd variable */
10723#define CHKALIAS        0x1
10724#define CHKKWD          0x2
10725#define CHKNL           0x4
10726#define CHKEOFMARK      0x8
10727
10728/*
10729 * Push a string back onto the input at this current parsefile level.
10730 * We handle aliases this way.
10731 */
10732#if !ENABLE_ASH_ALIAS
10733#define pushstring(s, ap) pushstring(s)
10734#endif
10735static void
10736pushstring(char *s, struct alias *ap)
10737{
10738        struct strpush *sp;
10739        int len;
10740
10741        len = strlen(s);
10742        INT_OFF;
10743        if (g_parsefile->strpush || g_parsefile->spfree) {
10744                sp = ckzalloc(sizeof(*sp));
10745                sp->prev = g_parsefile->strpush;
10746        } else {
10747                sp = &(g_parsefile->basestrpush);
10748        }
10749        g_parsefile->strpush = sp;
10750        sp->prev_string = g_parsefile->next_to_pgetc;
10751        sp->prev_left_in_line = g_parsefile->left_in_line;
10752        sp->unget = g_parsefile->unget;
10753        sp->spfree = g_parsefile->spfree;
10754        memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
10755#if ENABLE_ASH_ALIAS
10756        sp->ap = ap;
10757        if (ap) {
10758                ap->flag |= ALIASINUSE;
10759                sp->string = s;
10760        }
10761#endif
10762        g_parsefile->next_to_pgetc = s;
10763        g_parsefile->left_in_line = len;
10764        g_parsefile->unget = 0;
10765        g_parsefile->spfree = NULL;
10766        INT_ON;
10767}
10768
10769static void popstring(void)
10770{
10771        struct strpush *sp = g_parsefile->strpush;
10772
10773        INT_OFF;
10774#if ENABLE_ASH_ALIAS
10775        if (sp->ap) {
10776                if (g_parsefile->next_to_pgetc[-1] == ' '
10777                 || g_parsefile->next_to_pgetc[-1] == '\t'
10778                ) {
10779                        checkkwd |= CHKALIAS;
10780                }
10781                if (sp->string != sp->ap->val) {
10782                        free(sp->string);
10783                }
10784        }
10785#endif
10786        g_parsefile->next_to_pgetc = sp->prev_string;
10787        g_parsefile->left_in_line = sp->prev_left_in_line;
10788        g_parsefile->unget = sp->unget;
10789        memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
10790        g_parsefile->strpush = sp->prev;
10791        g_parsefile->spfree = sp;
10792        INT_ON;
10793}
10794
10795static int
10796preadfd(void)
10797{
10798        int nr;
10799        char *buf = g_parsefile->buf;
10800
10801        g_parsefile->next_to_pgetc = buf;
10802#if ENABLE_FEATURE_EDITING
10803 /* retry: */
10804        if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10805                nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10806        else {
10807# if ENABLE_ASH_IDLE_TIMEOUT
10808                int timeout = -1;
10809                const char *tmout_var = lookupvar("TMOUT");
10810                if (tmout_var) {
10811                        timeout = atoi(tmout_var) * 1000;
10812                        if (timeout <= 0)
10813                                timeout = -1;
10814                }
10815                line_input_state->timeout = timeout;
10816# endif
10817# if ENABLE_FEATURE_TAB_COMPLETION
10818                line_input_state->path_lookup = pathval();
10819# endif
10820                reinit_unicode_for_ash();
10821 again:
10822                /* For shell, LI_INTERRUPTIBLE is set:
10823                 * read_line_input will abort on either
10824                 * getting EINTR in poll(), or if it sees bb_got_signal != 0
10825                 * (IOW: if signal arrives before poll() is reached).
10826                 * Interactive testcases:
10827                 * (while kill -INT $$; do sleep 1; done) &
10828                 * #^^^ prints ^C, prints prompt, repeats
10829                 * trap 'echo I' int; (while kill -INT $$; do sleep 1; done) &
10830                 * #^^^ prints ^C, prints "I", prints prompt, repeats
10831                 * trap 'echo T' term; (while kill $$; do sleep 1; done) &
10832                 * #^^^ prints "T", prints prompt, repeats
10833                 * #(bash 5.0.17 exits after first "T", looks like a bug)
10834                 */
10835                bb_got_signal = 0;
10836                INT_OFF; /* no longjmp'ing out of read_line_input please */
10837                nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10838                if (bb_got_signal == SIGINT)
10839                        write(STDOUT_FILENO, "^C\n", 3);
10840                INT_ON; /* here non-blocked SIGINT will longjmp */
10841                if (nr == 0) {
10842                        /* ^C pressed, "convert" to SIGINT */
10843                        write(STDOUT_FILENO, "^C\n", 3);
10844                        raise(SIGINT); /* here non-blocked SIGINT will longjmp */
10845                        /* raise(SIGINT) did not work! (e.g. if SIGINT
10846                         * is SIG_IGNed on startup, it stays SIG_IGNed)
10847                         */
10848                        if (trap[SIGINT]) {
10849 empty_line_input:
10850                                buf[0] = '\n';
10851                                buf[1] = '\0';
10852                                return 1;
10853                        }
10854                        exitstatus = 128 + SIGINT;
10855                        /* bash behavior on ^C + ignored SIGINT: */
10856                        goto again;
10857                }
10858                if (nr < 0) {
10859                        if (errno == 0) {
10860                                /* ^D pressed */
10861                                nr = 0;
10862                        }
10863                        else if (errno == EINTR) { /* got signal? */
10864                                if (bb_got_signal != SIGINT)
10865                                        write(STDOUT_FILENO, "\n", 1);
10866                                goto empty_line_input;
10867                        }
10868# if ENABLE_ASH_IDLE_TIMEOUT
10869                        else if (errno == EAGAIN && timeout > 0) {
10870                                puts("\007timed out waiting for input: auto-logout");
10871                                exitshell();
10872                        }
10873# endif
10874                }
10875        }
10876#else
10877        nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10878#endif
10879
10880#if 0 /* disabled: nonblock_immune_read() handles this problem */
10881        if (nr < 0) {
10882                if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10883                        int flags = fcntl(0, F_GETFL);
10884                        if (flags >= 0 && (flags & O_NONBLOCK)) {
10885                                flags &= ~O_NONBLOCK;
10886                                if (fcntl(0, F_SETFL, flags) >= 0) {
10887                                        out2str("sh: turning off NDELAY mode\n");
10888                                        goto retry;
10889                                }
10890                        }
10891                }
10892        }
10893#endif
10894        return nr;
10895}
10896
10897/*
10898 * Refill the input buffer and return the next input character:
10899 *
10900 * 1) If a string was pushed back on the input, pop it;
10901 * 2) If we are reading from a string we can't refill the buffer, return EOF.
10902 * 3) If there is more stuff in this buffer, use it else call read to fill it.
10903 * 4) Process input up to the next newline, deleting nul characters.
10904 */
10905//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10906#define pgetc_debug(...) ((void)0)
10907static int __pgetc(void);
10908static int
10909preadbuffer(void)
10910{
10911        char *q;
10912        int more;
10913
10914        if (unlikely(g_parsefile->strpush)) {
10915                popstring();
10916                return __pgetc();
10917        }
10918
10919        if (g_parsefile->buf == NULL) {
10920                pgetc_debug("preadbuffer PEOF1");
10921                return PEOF;
10922        }
10923
10924        more = g_parsefile->left_in_buffer;
10925        if (more <= 0) {
10926                flush_stdout_stderr();
10927 again:
10928                more = preadfd();
10929                if (more <= 0) {
10930                        g_parsefile->left_in_buffer = g_parsefile->left_in_line = 0;
10931                        pgetc_debug("preadbuffer PEOF2");
10932                        return PEOF;
10933                }
10934        }
10935
10936        /* Find out where's the end of line.
10937         * Set g_parsefile->left_in_line
10938         * and g_parsefile->left_in_buffer acordingly.
10939         * NUL chars are deleted.
10940         */
10941        q = g_parsefile->next_to_pgetc;
10942        for (;;) {
10943                char c;
10944
10945                more--;
10946
10947                c = *q;
10948                if (c == '\0') {
10949                        memmove(q, q + 1, more);
10950                } else {
10951                        q++;
10952                        if (c == '\n') {
10953                                g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10954                                break;
10955                        }
10956                }
10957
10958                if (more <= 0) {
10959                        g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10960                        if (g_parsefile->left_in_line < 0)
10961                                goto again;
10962                        break;
10963                }
10964        }
10965        g_parsefile->left_in_buffer = more;
10966
10967        if (vflag) {
10968                char save = *q;
10969                *q = '\0';
10970                out2str(g_parsefile->next_to_pgetc);
10971                *q = save;
10972        }
10973
10974        pgetc_debug("preadbuffer at %d:%p'%s'",
10975                        g_parsefile->left_in_line,
10976                        g_parsefile->next_to_pgetc,
10977                        g_parsefile->next_to_pgetc);
10978        return (unsigned char)*g_parsefile->next_to_pgetc++;
10979}
10980
10981static void
10982nlprompt(void)
10983{
10984        if (trap_depth == 0)
10985                g_parsefile->linno++;
10986        setprompt_if(doprompt, 2);
10987}
10988static void
10989nlnoprompt(void)
10990{
10991        if (trap_depth == 0)
10992                g_parsefile->linno++;
10993        needprompt = doprompt;
10994}
10995
10996static void freestrings(struct strpush *sp)
10997{
10998        INT_OFF;
10999        do {
11000                struct strpush *psp;
11001#if ENABLE_ASH_ALIAS
11002                if (sp->ap) {
11003                        sp->ap->flag &= ~ALIASINUSE;
11004                        if (sp->ap->flag & ALIASDEAD) {
11005                                unalias(sp->ap->name);
11006                        }
11007                }
11008#endif
11009                psp = sp;
11010                sp = sp->spfree;
11011
11012                if (psp != &(g_parsefile->basestrpush))
11013                        free(psp);
11014        } while (sp);
11015
11016        g_parsefile->spfree = NULL;
11017        INT_ON;
11018}
11019
11020static int __pgetc(void)
11021{
11022        int c;
11023
11024        pgetc_debug("pgetc at %d:%p'%s'",
11025                        g_parsefile->left_in_line,
11026                        g_parsefile->next_to_pgetc,
11027                        g_parsefile->next_to_pgetc);
11028        if (g_parsefile->unget)
11029                return g_parsefile->lastc[--g_parsefile->unget];
11030
11031        if (--g_parsefile->left_in_line >= 0)
11032                c = (unsigned char)*g_parsefile->next_to_pgetc++;
11033        else
11034                c = preadbuffer();
11035
11036        g_parsefile->lastc[1] = g_parsefile->lastc[0];
11037        g_parsefile->lastc[0] = c;
11038
11039        return c;
11040}
11041
11042/*
11043 * Read a character from the script, returning PEOF on end of file.
11044 * Nul characters in the input are silently discarded.
11045 */
11046static int pgetc(void)
11047{
11048        struct strpush *sp = g_parsefile->spfree;
11049
11050        if (unlikely(sp))
11051                freestrings(sp);
11052
11053        return __pgetc();
11054}
11055
11056/*
11057 * Undo a call to pgetc.  Only two characters may be pushed back.
11058 * PEOF may be pushed back.
11059 */
11060static void
11061pungetc(void)
11062{
11063        g_parsefile->unget++;
11064}
11065
11066/* This one eats backslash+newline */
11067static int
11068pgetc_eatbnl(void)
11069{
11070        int c;
11071
11072        while ((c = pgetc()) == '\\') {
11073                if (pgetc() != '\n') {
11074                        pungetc();
11075                        break;
11076                }
11077
11078                nlprompt();
11079        }
11080
11081        return c;
11082}
11083
11084struct synstack {
11085        smalluint syntax;
11086        uint8_t innerdq   :1;
11087        uint8_t varpushed :1;
11088        uint8_t dblquote  :1;
11089        int varnest;            /* levels of variables expansion */
11090        int dqvarnest;          /* levels of variables expansion within double quotes */
11091        int parenlevel;         /* levels of parens in arithmetic */
11092        struct synstack *prev;
11093        struct synstack *next;
11094};
11095
11096static int
11097pgetc_top(struct synstack *stack)
11098{
11099        return stack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl();
11100}
11101
11102static void
11103synstack_push(struct synstack **stack, struct synstack *next, int syntax)
11104{
11105        memset(next, 0, sizeof(*next));
11106        next->syntax = syntax;
11107        next->next = *stack;
11108        (*stack)->prev = next;
11109        *stack = next;
11110}
11111
11112static ALWAYS_INLINE void
11113synstack_pop(struct synstack **stack)
11114{
11115        *stack = (*stack)->next;
11116}
11117
11118/*
11119 * To handle the "." command, a stack of input files is used.  Pushfile
11120 * adds a new entry to the stack and popfile restores the previous level.
11121 */
11122static void
11123pushfile(void)
11124{
11125        struct parsefile *pf;
11126
11127        pf = ckzalloc(sizeof(*pf));
11128        pf->prev = g_parsefile;
11129        pf->pf_fd = -1;
11130        /*pf->strpush = NULL; - ckzalloc did it */
11131        /*pf->spfree = NULL;*/
11132        /*pf->basestrpush.prev = NULL;*/
11133        /*pf->unget = 0;*/
11134        g_parsefile = pf;
11135}
11136
11137static void
11138popfile(void)
11139{
11140        struct parsefile *pf = g_parsefile;
11141
11142        if (pf == &basepf)
11143                return;
11144
11145        INT_OFF;
11146        if (pf->pf_fd >= 0)
11147                close(pf->pf_fd);
11148        free(pf->buf);
11149        if (g_parsefile->spfree)
11150                freestrings(g_parsefile->spfree);
11151        while (pf->strpush) {
11152                popstring();
11153                freestrings(g_parsefile->spfree);
11154        }
11155        g_parsefile = pf->prev;
11156        free(pf);
11157        INT_ON;
11158}
11159
11160static void
11161unwindfiles(struct parsefile *stop)
11162{
11163        while (g_parsefile != stop)
11164                popfile();
11165}
11166
11167/*
11168 * Return to top level.
11169 */
11170static void
11171popallfiles(void)
11172{
11173        unwindfiles(&basepf);
11174}
11175
11176/*
11177 * Close the file(s) that the shell is reading commands from.  Called
11178 * after a fork is done.
11179 */
11180static void
11181closescript(void)
11182{
11183        popallfiles();
11184        if (g_parsefile->pf_fd > 0) {
11185                close(g_parsefile->pf_fd);
11186                g_parsefile->pf_fd = 0;
11187        }
11188}
11189
11190/*
11191 * Like setinputfile, but takes an open file descriptor.  Call this with
11192 * interrupts off.
11193 */
11194static void
11195setinputfd(int fd, int push)
11196{
11197        if (push) {
11198                pushfile();
11199                g_parsefile->buf = NULL;
11200        }
11201        g_parsefile->pf_fd = fd;
11202        if (g_parsefile->buf == NULL)
11203                g_parsefile->buf = ckmalloc(IBUFSIZ);
11204        g_parsefile->left_in_buffer = 0;
11205        g_parsefile->left_in_line = 0;
11206        g_parsefile->linno = 1;
11207}
11208
11209/*
11210 * Set the input to take input from a file.  If push is set, push the
11211 * old input onto the stack first.
11212 */
11213static int
11214setinputfile(const char *fname, int flags)
11215{
11216        int fd;
11217
11218        INT_OFF;
11219        fd = open(fname, O_RDONLY | O_CLOEXEC);
11220        if (fd < 0) {
11221                if (flags & INPUT_NOFILE_OK)
11222                        goto out;
11223                exitstatus = 127;
11224                ash_msg_and_raise_perror("can't open '%s'", fname);
11225        }
11226        if (fd < 10)
11227                fd = savefd(fd);
11228        else if (O_CLOEXEC == 0) /* old libc */
11229                close_on_exec_on(fd);
11230
11231        setinputfd(fd, flags & INPUT_PUSH_FILE);
11232 out:
11233        INT_ON;
11234        return fd;
11235}
11236
11237/*
11238 * Like setinputfile, but takes input from a string.
11239 */
11240static void
11241setinputstring(char *string)
11242{
11243        INT_OFF;
11244        pushfile();
11245        g_parsefile->next_to_pgetc = string;
11246        g_parsefile->left_in_line = strlen(string);
11247        g_parsefile->buf = NULL;
11248        g_parsefile->linno = lineno;
11249        INT_ON;
11250}
11251
11252
11253/*
11254 * Routines to check for mail.
11255 */
11256
11257#if ENABLE_ASH_MAIL
11258
11259/* Hash of mtimes of mailboxes */
11260static unsigned mailtime_hash;
11261/* Set if MAIL or MAILPATH is changed. */
11262static smallint mail_var_path_changed;
11263
11264/*
11265 * Print appropriate message(s) if mail has arrived.
11266 * If mail_var_path_changed is set,
11267 * then the value of MAIL has changed,
11268 * so we just update the hash value.
11269 */
11270static void
11271chkmail(void)
11272{
11273        const char *mpath;
11274        char *p;
11275        char *q;
11276        unsigned new_hash;
11277        struct stackmark smark;
11278        struct stat statb;
11279
11280        setstackmark(&smark);
11281        mpath = mpathset() ? mpathval() : mailval();
11282        new_hash = 0;
11283        for (;;) {
11284                int len;
11285
11286                len = padvance_magic(&mpath, nullstr, 2);
11287                if (len < 0)
11288                        break;
11289                p = stackblock();
11290                if (*p == '\0')
11291                        continue;
11292                for (q = p; *q; q++)
11293                        continue;
11294#if DEBUG
11295                if (q[-1] != '/')
11296                        abort();
11297#endif
11298                q[-1] = '\0';                   /* delete trailing '/' */
11299                if (stat(p, &statb) < 0) {
11300                        continue;
11301                }
11302                /* Very simplistic "hash": just a sum of all mtimes */
11303                new_hash += (unsigned)statb.st_mtime;
11304        }
11305        if (!mail_var_path_changed && mailtime_hash != new_hash) {
11306                if (mailtime_hash != 0)
11307                        out2str("you have mail\n");
11308        }
11309        mailtime_hash = new_hash;
11310        mail_var_path_changed = 0;
11311        popstackmark(&smark);
11312}
11313
11314static void FAST_FUNC
11315changemail(const char *val UNUSED_PARAM)
11316{
11317        mail_var_path_changed = 1;
11318}
11319
11320#endif /* ASH_MAIL */
11321
11322
11323/* ============ ??? */
11324
11325/*
11326 * Set the shell parameters.
11327 */
11328static void
11329setparam(char **argv)
11330{
11331        char **newparam;
11332        char **ap;
11333        int nparam;
11334
11335        for (nparam = 0; argv[nparam]; nparam++)
11336                continue;
11337        ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
11338        while (*argv) {
11339                *ap++ = ckstrdup(*argv++);
11340        }
11341        *ap = NULL;
11342        freeparam(&shellparam);
11343        shellparam.malloced = 1;
11344        shellparam.nparam = nparam;
11345        shellparam.p = newparam;
11346#if ENABLE_ASH_GETOPTS
11347        shellparam.optind = 1;
11348        shellparam.optoff = -1;
11349#endif
11350}
11351
11352/*
11353 * Process shell options.  The global variable argptr contains a pointer
11354 * to the argument list; we advance it past the options.
11355 *
11356 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
11357 * For a non-interactive shell, an error condition encountered
11358 * by a special built-in ... shall cause the shell to write a diagnostic message
11359 * to standard error and exit as shown in the following table:
11360 * Error                                           Special Built-In
11361 * ...
11362 * Utility syntax error (option or operand error)  Shall exit
11363 * ...
11364 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
11365 * we see that bash does not do that (set "finishes" with error code 1 instead,
11366 * and shell continues), and people rely on this behavior!
11367 * Testcase:
11368 * set -o barfoo 2>/dev/null
11369 * echo $?
11370 *
11371 * Oh well. Let's mimic that.
11372 */
11373static int
11374plus_minus_o(char *name, int val)
11375{
11376        int i;
11377
11378        if (name) {
11379                for (i = 0; i < NOPTS; i++) {
11380                        if (strcmp(name, optnames(i)) == 0) {
11381                                optlist[i] = val;
11382                                return 0;
11383                        }
11384                }
11385                ash_msg("illegal option %co %s", val ? '-' : '+', name);
11386                return 1;
11387        }
11388        for (i = 0; i < NOPTS; i++) {
11389                if (optnames(i)[0] == '\0')
11390                        continue;
11391                if (val) {
11392                        out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11393                } else {
11394                        out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11395                }
11396        }
11397        return 0;
11398}
11399static void
11400setoption(int flag, int val)
11401{
11402        int i;
11403
11404        for (i = 0; i < NOPTS; i++) {
11405                if (optletters(i) == flag && optnames(i)[0] != '\0') {
11406                        optlist[i] = val;
11407                        return;
11408                }
11409        }
11410        ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
11411        /* NOTREACHED */
11412}
11413/* If login_sh is not NULL, we are called to parse command line opts,
11414 * not "set -opts"
11415 */
11416static int
11417options(int *login_sh)
11418{
11419        char *p;
11420        int val;
11421        int c;
11422
11423        if (login_sh != NULL) /* if we came from startup code */
11424                minusc = NULL;
11425        while ((p = *argptr) != NULL) {
11426                c = *p++;
11427                if (c != '-' && c != '+')
11428                        break;
11429                argptr++;
11430                val = 0; /* val = 0 if c == '+' */
11431                if (c == '-') {
11432                        val = 1;
11433                        if (p[0] == '\0' || LONE_DASH(p)) {
11434                                if (login_sh == NULL) { /* we came from setcmd() */
11435                                        /* "-" means turn off -x and -v */
11436                                        if (p[0] == '\0')
11437                                                xflag = vflag = 0;
11438                                        /* "--" means reset params */
11439                                        else if (*argptr == NULL)
11440                                                setparam(argptr);
11441                                }
11442                                break;    /* "-" or "--" terminates options */
11443                        }
11444                }
11445                /* first char was + or - */
11446                while ((c = *p++) != '\0') {
11447                        if (login_sh != NULL) { /* if we came from startup code */
11448                                /* bash 3.2 indeed handles -c CMD and +c CMD the same */
11449                                if (c == 'c') {
11450                                        minusc = p; /* command is after shell args */
11451                                        cflag = 1;
11452                                        continue;
11453                                }
11454                                if (c == 's') { /* -s, +s */
11455                                        sflag = 1;
11456                                        continue;
11457                                }
11458                                if (c == 'i') { /* -i, +i */
11459                                        iflag = 1;
11460                                        continue;
11461                                }
11462                                if (c == 'l') {
11463                                        *login_sh = 1; /* -l or +l == --login */
11464                                        continue;
11465                                }
11466                                /* bash does not accept +-login, we also won't */
11467                                if (val && (c == '-')) { /* long options */
11468                                        if (strcmp(p, "login") == 0) {
11469                                                *login_sh = 1;
11470                                        }
11471/* TODO: --noprofile: e.g. if I want to run emergency shell from sulogin,
11472 * I want minimal/no shell init scripts - but it insists on running it as "-ash"...
11473 */
11474                                        break;
11475                                }
11476                        }
11477                        if (c == 'o') {
11478                                if (plus_minus_o(*argptr, val)) {
11479                                        /* it already printed err message */
11480                                        return 1; /* error */
11481                                }
11482                                if (*argptr)
11483                                        argptr++;
11484                        } else {
11485                                setoption(c, val);
11486                        }
11487                }
11488        }
11489        return 0;
11490}
11491
11492/*
11493 * The shift builtin command.
11494 */
11495static int FAST_FUNC
11496shiftcmd(int argc UNUSED_PARAM, char **argv)
11497{
11498        int n;
11499        char **ap1, **ap2;
11500
11501        n = 1;
11502        if (argv[1])
11503                n = number(argv[1]);
11504        if (n > shellparam.nparam)
11505                return 1;
11506        INT_OFF;
11507        shellparam.nparam -= n;
11508        for (ap1 = shellparam.p; --n >= 0; ap1++) {
11509                if (shellparam.malloced)
11510                        free(*ap1);
11511        }
11512        ap2 = shellparam.p;
11513        while ((*ap2++ = *ap1++) != NULL)
11514                continue;
11515#if ENABLE_ASH_GETOPTS
11516        shellparam.optind = 1;
11517        shellparam.optoff = -1;
11518#endif
11519        INT_ON;
11520        return 0;
11521}
11522
11523/*
11524 * POSIX requires that 'set' (but not export or readonly) output the
11525 * variables in lexicographic order - by the locale's collating order (sigh).
11526 * Maybe we could keep them in an ordered balanced binary tree
11527 * instead of hashed lists.
11528 * For now just roll 'em through qsort for printing...
11529 */
11530static int
11531showvars(const char *sep_prefix, int on, int off)
11532{
11533        const char *sep;
11534        char **ep, **epend;
11535
11536        ep = listvars(on, off, /*strlist:*/ NULL, &epend);
11537        qsort(ep, epend - ep, sizeof(char *), vpcmp);
11538
11539        sep = *sep_prefix ? " " : sep_prefix;
11540
11541        for (; ep < epend; ep++) {
11542                const char *p;
11543                const char *q;
11544
11545                p = endofname(*ep);
11546/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11547 * makes "export -p" to have output not suitable for "eval":
11548 * import os
11549 * os.environ["test-test"]="test"
11550 * if os.fork() == 0:
11551 *   os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ])  # fixes this
11552 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11553 */
11554                q = nullstr;
11555                if (*p == '=')
11556                        q = single_quote(++p);
11557                out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11558        }
11559        return 0;
11560}
11561
11562/*
11563 * The set command builtin.
11564 */
11565static int FAST_FUNC
11566setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11567{
11568        int retval;
11569
11570        if (!argv[1])
11571                return showvars(nullstr, 0, VUNSET);
11572
11573        INT_OFF;
11574        retval = options(/*login_sh:*/ NULL);
11575        if (retval == 0) { /* if no parse error... */
11576                optschanged();
11577                if (*argptr != NULL) {
11578                        setparam(argptr);
11579                }
11580        }
11581        INT_ON;
11582        return retval;
11583}
11584
11585#if ENABLE_ASH_RANDOM_SUPPORT
11586static void FAST_FUNC
11587change_random(const char *value)
11588{
11589        uint32_t t;
11590
11591        if (value == NULL) {
11592                /* "get", generate */
11593                t = next_random(&random_gen);
11594                /* set without recursion */
11595                setvar(vrandom.var_text, utoa(t), VNOFUNC);
11596                vrandom.flags &= ~VNOFUNC;
11597        } else {
11598                /* set/reset */
11599                t = strtoul(value, NULL, 10);
11600                INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
11601        }
11602}
11603#endif
11604
11605#if BASH_EPOCH_VARS
11606static void FAST_FUNC
11607change_epoch(struct var *vepoch, const char *fmt)
11608{
11609        struct timeval tv;
11610        char buffer[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
11611
11612        xgettimeofday(&tv);
11613        sprintf(buffer, fmt, (unsigned long long)tv.tv_sec, (unsigned)tv.tv_usec);
11614        setvar(vepoch->var_text, buffer, VNOFUNC);
11615        vepoch->flags &= ~VNOFUNC;
11616}
11617
11618static void FAST_FUNC
11619change_seconds(const char *value UNUSED_PARAM)
11620{
11621        change_epoch(&vepochs, "%llu");
11622}
11623
11624static void FAST_FUNC
11625change_realtime(const char *value UNUSED_PARAM)
11626{
11627        change_epoch(&vepochr, "%llu.%06u");
11628}
11629#endif
11630
11631#if ENABLE_ASH_GETOPTS
11632static int
11633getopts(char *optstr, char *optvar, char **optfirst)
11634{
11635        char *p, *q;
11636        char c = '?';
11637        int done = 0;
11638        char sbuf[2];
11639        char **optnext;
11640        int ind = shellparam.optind;
11641        int off = shellparam.optoff;
11642
11643        sbuf[1] = '\0';
11644
11645        shellparam.optind = -1;
11646        optnext = optfirst + ind - 1;
11647
11648        if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
11649                p = NULL;
11650        else
11651                p = optnext[-1] + off;
11652        if (p == NULL || *p == '\0') {
11653                /* Current word is done, advance */
11654                p = *optnext;
11655                if (p == NULL || *p != '-' || *++p == '\0') {
11656 atend:
11657                        unsetvar("OPTARG");
11658                        p = NULL;
11659                        done = 1;
11660                        goto out;
11661                }
11662                optnext++;
11663                if (LONE_DASH(p))        /* check for "--" */
11664                        goto atend;
11665        }
11666
11667        c = *p++;
11668        for (q = optstr; *q != c;) {
11669                if (*q == '\0') {
11670                        /* OPTERR is a bashism */
11671                        const char *cp = lookupvar("OPTERR");
11672                        if ((cp && LONE_CHAR(cp, '0'))
11673                         || (optstr[0] == ':')
11674                        ) {
11675                                sbuf[0] = c;
11676                                /*sbuf[1] = '\0'; - already is */
11677                                setvar0("OPTARG", sbuf);
11678                        } else {
11679                                fprintf(stderr, "Illegal option -%c\n", c);
11680                                unsetvar("OPTARG");
11681                        }
11682                        c = '?';
11683                        goto out;
11684                }
11685                if (*++q == ':')
11686                        q++;
11687        }
11688
11689        if (*++q == ':') {
11690                if (*p == '\0' && (p = *optnext) == NULL) {
11691                        /* OPTERR is a bashism */
11692                        const char *cp = lookupvar("OPTERR");
11693                        if ((cp && LONE_CHAR(cp, '0'))
11694                         || (optstr[0] == ':')
11695                        ) {
11696                                sbuf[0] = c;
11697                                /*sbuf[1] = '\0'; - already is */
11698                                setvar0("OPTARG", sbuf);
11699                                c = ':';
11700                        } else {
11701                                fprintf(stderr, "No arg for -%c option\n", c);
11702                                unsetvar("OPTARG");
11703                                c = '?';
11704                        }
11705                        goto out;
11706                }
11707
11708                if (p == *optnext)
11709                        optnext++;
11710                setvar0("OPTARG", p);
11711                p = NULL;
11712        } else
11713                setvar0("OPTARG", nullstr);
11714 out:
11715        ind = optnext - optfirst + 1;
11716        setvar("OPTIND", itoa(ind), VNOFUNC);
11717        sbuf[0] = c;
11718        /*sbuf[1] = '\0'; - already is */
11719        setvar0(optvar, sbuf);
11720
11721        shellparam.optoff = p ? p - *(optnext - 1) : -1;
11722        shellparam.optind = ind;
11723
11724        return done;
11725}
11726
11727/*
11728 * The getopts builtin.  Shellparam.optnext points to the next argument
11729 * to be processed.  Shellparam.optptr points to the next character to
11730 * be processed in the current argument.  If shellparam.optnext is NULL,
11731 * then it's the first time getopts has been called.
11732 */
11733static int FAST_FUNC
11734getoptscmd(int argc, char **argv)
11735{
11736        char **optbase;
11737
11738        if (argc < 3)
11739                ash_msg_and_raise_error("usage: getopts optstring var [arg]");
11740        if (argc == 3) {
11741                optbase = shellparam.p;
11742                if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
11743                        shellparam.optind = 1;
11744                        shellparam.optoff = -1;
11745                }
11746        } else {
11747                optbase = &argv[3];
11748                if ((unsigned)shellparam.optind > argc - 2) {
11749                        shellparam.optind = 1;
11750                        shellparam.optoff = -1;
11751                }
11752        }
11753
11754        return getopts(argv[1], argv[2], optbase);
11755}
11756#endif /* ASH_GETOPTS */
11757
11758
11759/* ============ Shell parser */
11760
11761struct heredoc {
11762        struct heredoc *next;   /* next here document in list */
11763        union node *here;       /* redirection node */
11764        char *eofmark;          /* string indicating end of input */
11765        smallint striptabs;     /* if set, strip leading tabs */
11766};
11767
11768static smallint tokpushback;           /* last token pushed back */
11769static smallint quoteflag;             /* set if (part of) last token was quoted */
11770static token_id_t lasttoken;           /* last token read (integer id Txxx) */
11771static struct heredoc *heredoclist;    /* list of here documents to read */
11772static char *wordtext;                 /* text of last word returned by readtoken */
11773static struct nodelist *backquotelist;
11774static union node *redirnode;
11775static struct heredoc *heredoc;
11776
11777static const char *
11778tokname(char *buf, int tok)
11779{
11780        if (tok < TSEMI)
11781                return tokname_array[tok];
11782        sprintf(buf, "\"%s\"", tokname_array[tok]);
11783        return buf;
11784}
11785
11786/* raise_error_unexpected_syntax:
11787 * Called when an unexpected token is read during the parse.  The argument
11788 * is the token that is expected, or -1 if more than one type of token can
11789 * occur at this point.
11790 */
11791static void raise_error_unexpected_syntax(int) NORETURN;
11792static void
11793raise_error_unexpected_syntax(int token)
11794{
11795        char msg[64];
11796        char buf[16];
11797        int l;
11798
11799        l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
11800        if (token >= 0)
11801                sprintf(msg + l, " (expecting %s)", tokname(buf, token));
11802        raise_error_syntax(msg);
11803        /* NOTREACHED */
11804}
11805
11806/* parsing is heavily cross-recursive, need these forward decls */
11807static union node *andor(void);
11808static union node *pipeline(void);
11809static union node *parse_command(void);
11810static void parseheredoc(void);
11811static int readtoken(void);
11812
11813static union node *
11814list(int nlflag)
11815{
11816        int chknl = nlflag & 1 ? 0 : CHKNL;
11817        union node *n1, *n2, *n3;
11818        int tok;
11819
11820        n1 = NULL;
11821        for (;;) {
11822                checkkwd = chknl | CHKKWD | CHKALIAS;
11823                tok = readtoken();
11824                switch (tok) {
11825                case TNL:
11826                        parseheredoc();
11827                        return n1;
11828
11829                case TEOF:
11830                        if (!n1 && !chknl)
11831                                n1 = NODE_EOF;
11832 out_eof:
11833                        parseheredoc();
11834                        tokpushback++;
11835                        lasttoken = TEOF;
11836                        return n1;
11837                }
11838
11839                tokpushback++;
11840                if (nlflag == 2 && ((1 << tok) & tokendlist))
11841                        return n1;
11842                nlflag |= 2;
11843
11844                n2 = andor();
11845                tok = readtoken();
11846                if (tok == TBACKGND) {
11847                        if (n2->type == NPIPE) {
11848                                n2->npipe.pipe_backgnd = 1;
11849                        } else {
11850                                if (n2->type != NREDIR) {
11851                                        n3 = stzalloc(sizeof(struct nredir));
11852                                        n3->nredir.n = n2;
11853                                        /*n3->nredir.redirect = NULL; - stzalloc did it */
11854                                        n2 = n3;
11855                                }
11856                                n2->type = NBACKGND;
11857                        }
11858                }
11859                if (n1 == NULL) {
11860                        n1 = n2;
11861                } else {
11862                        n3 = stzalloc(sizeof(struct nbinary));
11863                        n3->type = NSEMI;
11864                        n3->nbinary.ch1 = n1;
11865                        n3->nbinary.ch2 = n2;
11866                        n1 = n3;
11867                }
11868                switch (tok) {
11869                case TEOF:
11870                        goto out_eof;
11871                case TNL:
11872                        tokpushback = 1;
11873                        /* fall through */
11874                case TBACKGND:
11875                case TSEMI:
11876                        break;
11877                default:
11878                        if (!chknl)
11879                                raise_error_unexpected_syntax(-1);
11880                        tokpushback = 1;
11881                        return n1;
11882                }
11883        }
11884}
11885
11886static union node *
11887andor(void)
11888{
11889        union node *n1, *n2, *n3;
11890        int t;
11891
11892        n1 = pipeline();
11893        for (;;) {
11894                t = readtoken();
11895                if (t == TAND) {
11896                        t = NAND;
11897                } else if (t == TOR) {
11898                        t = NOR;
11899                } else {
11900                        tokpushback = 1;
11901                        return n1;
11902                }
11903                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11904                n2 = pipeline();
11905                n3 = stzalloc(sizeof(struct nbinary));
11906                n3->type = t;
11907                n3->nbinary.ch1 = n1;
11908                n3->nbinary.ch2 = n2;
11909                n1 = n3;
11910        }
11911}
11912
11913static union node *
11914pipeline(void)
11915{
11916        union node *n1, *n2, *pipenode;
11917        struct nodelist *lp, *prev;
11918        int negate;
11919
11920        negate = 0;
11921        TRACE(("pipeline: entered\n"));
11922        if (readtoken() == TNOT) {
11923                negate = !negate;
11924                checkkwd = CHKKWD | CHKALIAS;
11925        } else
11926                tokpushback = 1;
11927        n1 = parse_command();
11928        if (readtoken() == TPIPE) {
11929                pipenode = stzalloc(sizeof(struct npipe));
11930                pipenode->type = NPIPE;
11931                /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
11932                lp = stzalloc(sizeof(struct nodelist));
11933                pipenode->npipe.cmdlist = lp;
11934                lp->n = n1;
11935                do {
11936                        prev = lp;
11937                        lp = stzalloc(sizeof(struct nodelist));
11938                        checkkwd = CHKNL | CHKKWD | CHKALIAS;
11939                        lp->n = parse_command();
11940                        prev->next = lp;
11941                } while (readtoken() == TPIPE);
11942                lp->next = NULL;
11943                n1 = pipenode;
11944        }
11945        tokpushback = 1;
11946        if (negate) {
11947                n2 = stzalloc(sizeof(struct nnot));
11948                n2->type = NNOT;
11949                n2->nnot.com = n1;
11950                return n2;
11951        }
11952        return n1;
11953}
11954
11955static union node *
11956makename(void)
11957{
11958        union node *n;
11959
11960        n = stzalloc(sizeof(struct narg));
11961        n->type = NARG;
11962        /*n->narg.next = NULL; - stzalloc did it */
11963        n->narg.text = wordtext;
11964        n->narg.backquote = backquotelist;
11965        return n;
11966}
11967
11968static void
11969fixredir(union node *n, const char *text, int err)
11970{
11971        int fd;
11972
11973        TRACE(("Fix redir %s %d\n", text, err));
11974        if (!err)
11975                n->ndup.vname = NULL;
11976
11977        fd = bb_strtou(text, NULL, 10);
11978        if (!errno && fd >= 0)
11979                n->ndup.dupfd = fd;
11980        else if (LONE_DASH(text))
11981                n->ndup.dupfd = -1;
11982        else {
11983                if (err)
11984                        raise_error_syntax("bad fd number");
11985                n->ndup.vname = makename();
11986        }
11987}
11988
11989static void
11990parsefname(void)
11991{
11992        union node *n = redirnode;
11993
11994        if (n->type == NHERE)
11995                checkkwd = CHKEOFMARK;
11996        if (readtoken() != TWORD)
11997                raise_error_unexpected_syntax(-1);
11998        if (n->type == NHERE) {
11999                struct heredoc *here = heredoc;
12000                struct heredoc *p;
12001
12002                if (quoteflag == 0)
12003                        n->type = NXHERE;
12004                TRACE(("Here document %d\n", n->type));
12005                rmescapes(wordtext, 0, NULL);
12006                here->eofmark = wordtext;
12007                here->next = NULL;
12008                if (heredoclist == NULL)
12009                        heredoclist = here;
12010                else {
12011                        for (p = heredoclist; p->next; p = p->next)
12012                                continue;
12013                        p->next = here;
12014                }
12015        } else if (n->type == NTOFD || n->type == NFROMFD) {
12016                fixredir(n, wordtext, 0);
12017        } else {
12018                n->nfile.fname = makename();
12019        }
12020}
12021
12022static union node *
12023simplecmd(void)
12024{
12025        union node *args, **app;
12026        union node *n = NULL;
12027        union node *vars, **vpp;
12028        union node **rpp, *redir;
12029        int savecheckkwd;
12030        int savelinno;
12031#if BASH_TEST2
12032        smallint double_brackets_flag = 0;
12033#endif
12034        IF_BASH_FUNCTION(smallint function_flag = 0;)
12035
12036        args = NULL;
12037        app = &args;
12038        vars = NULL;
12039        vpp = &vars;
12040        redir = NULL;
12041        rpp = &redir;
12042
12043        savecheckkwd = CHKALIAS;
12044        savelinno = g_parsefile->linno;
12045        for (;;) {
12046                int t;
12047                checkkwd = savecheckkwd;
12048                t = readtoken();
12049                switch (t) {
12050#if BASH_FUNCTION
12051                case TFUNCTION:
12052                        if (readtoken() != TWORD)
12053                                raise_error_unexpected_syntax(TWORD);
12054                        tokpushback = 1;
12055                        function_flag = 1;
12056                        break;
12057#endif
12058#if BASH_TEST2
12059                case TAND: /* "&&" */
12060                case TOR: /* "||" */
12061                        if (!double_brackets_flag) {
12062                                tokpushback = 1;
12063                                goto out;
12064                        }
12065                        /* pass "&&" or "||" to [[ ]] as literal args */
12066                        wordtext = (char *) (t == TAND ? "&&" : "||");
12067#endif
12068                case TWORD:
12069                        n = stzalloc(sizeof(struct narg));
12070                        n->type = NARG;
12071                        /*n->narg.next = NULL; - stzalloc did it */
12072                        n->narg.text = wordtext;
12073#if BASH_TEST2
12074                        if (strcmp("[[", wordtext) == 0)
12075                                double_brackets_flag = 1;
12076                        else if (strcmp("]]", wordtext) == 0)
12077                                double_brackets_flag = 0;
12078#endif
12079                        n->narg.backquote = backquotelist;
12080                        if (savecheckkwd && isassignment(wordtext)) {
12081                                *vpp = n;
12082                                vpp = &n->narg.next;
12083                        } else {
12084                                *app = n;
12085                                app = &n->narg.next;
12086                                savecheckkwd = 0;
12087                        }
12088#if BASH_FUNCTION
12089                        if (function_flag) {
12090                                checkkwd = CHKNL | CHKKWD;
12091                                t = readtoken();
12092                                tokpushback = 1;
12093                                switch (t) {
12094                                case TBEGIN:
12095                                case TIF:
12096                                case TCASE:
12097                                case TUNTIL:
12098                                case TWHILE:
12099                                case TFOR:
12100                                        goto do_func;
12101                                case TLP:
12102                                        function_flag = 0;
12103                                        break;
12104# if BASH_TEST2
12105                                case TWORD:
12106                                        if (strcmp("[[", wordtext) == 0)
12107                                                goto do_func;
12108                                        /* fall through */
12109# endif
12110                                default:
12111                                        raise_error_unexpected_syntax(-1);
12112                                }
12113                        }
12114#endif
12115                        break;
12116                case TREDIR:
12117                        *rpp = n = redirnode;
12118                        rpp = &n->nfile.next;
12119                        parsefname();   /* read name of redirection file */
12120                        break;
12121                case TLP:
12122 IF_BASH_FUNCTION(do_func:)
12123                        if (args && app == &args->narg.next
12124                         && !vars && !redir
12125                        ) {
12126                                struct builtincmd *bcmd;
12127                                const char *name;
12128
12129                                /* We have a function */
12130                                if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
12131                                        raise_error_unexpected_syntax(TRP);
12132                                name = n->narg.text;
12133                                if (!goodname(name)
12134                                 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
12135                                ) {
12136                                        raise_error_syntax("bad function name");
12137                                }
12138                                n->type = NDEFUN;
12139                                checkkwd = CHKNL | CHKKWD | CHKALIAS;
12140                                n->ndefun.text = n->narg.text;
12141                                n->ndefun.linno = g_parsefile->linno;
12142                                n->ndefun.body = parse_command();
12143                                return n;
12144                        }
12145                        IF_BASH_FUNCTION(function_flag = 0;)
12146                        /* fall through */
12147                default:
12148                        tokpushback = 1;
12149                        goto out;
12150                }
12151        }
12152 out:
12153        *app = NULL;
12154        *vpp = NULL;
12155        *rpp = NULL;
12156        n = stzalloc(sizeof(struct ncmd));
12157        if (NCMD != 0)
12158                n->type = NCMD;
12159        n->ncmd.linno = savelinno;
12160        n->ncmd.args = args;
12161        n->ncmd.assign = vars;
12162        n->ncmd.redirect = redir;
12163        return n;
12164}
12165
12166static union node *
12167parse_command(void)
12168{
12169        union node *n1, *n2;
12170        union node *ap, **app;
12171        union node *cp, **cpp;
12172        union node *redir, **rpp;
12173        union node **rpp2;
12174        int t;
12175        int savelinno;
12176
12177        redir = NULL;
12178        rpp2 = &redir;
12179
12180        savelinno = g_parsefile->linno;
12181
12182        switch (readtoken()) {
12183        default:
12184                raise_error_unexpected_syntax(-1);
12185                /* NOTREACHED */
12186        case TIF:
12187                n1 = stzalloc(sizeof(struct nif));
12188                n1->type = NIF;
12189                n1->nif.test = list(0);
12190                if (readtoken() != TTHEN)
12191                        raise_error_unexpected_syntax(TTHEN);
12192                n1->nif.ifpart = list(0);
12193                n2 = n1;
12194                while (readtoken() == TELIF) {
12195                        n2->nif.elsepart = stzalloc(sizeof(struct nif));
12196                        n2 = n2->nif.elsepart;
12197                        n2->type = NIF;
12198                        n2->nif.test = list(0);
12199                        if (readtoken() != TTHEN)
12200                                raise_error_unexpected_syntax(TTHEN);
12201                        n2->nif.ifpart = list(0);
12202                }
12203                if (lasttoken == TELSE)
12204                        n2->nif.elsepart = list(0);
12205                else {
12206                        n2->nif.elsepart = NULL;
12207                        tokpushback = 1;
12208                }
12209                t = TFI;
12210                break;
12211        case TWHILE:
12212        case TUNTIL: {
12213                int got;
12214                n1 = stzalloc(sizeof(struct nbinary));
12215                n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
12216                n1->nbinary.ch1 = list(0);
12217                got = readtoken();
12218                if (got != TDO) {
12219                        TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
12220                                        got == TWORD ? wordtext : ""));
12221                        raise_error_unexpected_syntax(TDO);
12222                }
12223                n1->nbinary.ch2 = list(0);
12224                t = TDONE;
12225                break;
12226        }
12227        case TFOR:
12228                if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
12229                        raise_error_syntax("bad for loop variable");
12230                n1 = stzalloc(sizeof(struct nfor));
12231                n1->type = NFOR;
12232                n1->nfor.linno = savelinno;
12233                n1->nfor.var = wordtext;
12234                checkkwd = CHKNL | CHKKWD | CHKALIAS;
12235                if (readtoken() == TIN) {
12236                        app = &ap;
12237                        while (readtoken() == TWORD) {
12238                                n2 = stzalloc(sizeof(struct narg));
12239                                n2->type = NARG;
12240                                /*n2->narg.next = NULL; - stzalloc did it */
12241                                n2->narg.text = wordtext;
12242                                n2->narg.backquote = backquotelist;
12243                                *app = n2;
12244                                app = &n2->narg.next;
12245                        }
12246                        *app = NULL;
12247                        n1->nfor.args = ap;
12248                        if (lasttoken != TNL && lasttoken != TSEMI)
12249                                raise_error_unexpected_syntax(-1);
12250                } else {
12251                        n2 = stzalloc(sizeof(struct narg));
12252                        n2->type = NARG;
12253                        /*n2->narg.next = NULL; - stzalloc did it */
12254                        n2->narg.text = (char *)dolatstr;
12255                        /*n2->narg.backquote = NULL;*/
12256                        n1->nfor.args = n2;
12257                        /*
12258                         * Newline or semicolon here is optional (but note
12259                         * that the original Bourne shell only allowed NL).
12260                         */
12261                        if (lasttoken != TSEMI)
12262                                tokpushback = 1;
12263                }
12264                checkkwd = CHKNL | CHKKWD | CHKALIAS;
12265                if (readtoken() != TDO)
12266                        raise_error_unexpected_syntax(TDO);
12267                n1->nfor.body = list(0);
12268                t = TDONE;
12269                break;
12270        case TCASE:
12271                n1 = stzalloc(sizeof(struct ncase));
12272                n1->type = NCASE;
12273                n1->ncase.linno = savelinno;
12274                if (readtoken() != TWORD)
12275                        raise_error_unexpected_syntax(TWORD);
12276                n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
12277                n2->type = NARG;
12278                /*n2->narg.next = NULL; - stzalloc did it */
12279                n2->narg.text = wordtext;
12280                n2->narg.backquote = backquotelist;
12281                checkkwd = CHKNL | CHKKWD | CHKALIAS;
12282                if (readtoken() != TIN)
12283                        raise_error_unexpected_syntax(TIN);
12284                cpp = &n1->ncase.cases;
12285 next_case:
12286                checkkwd = CHKNL | CHKKWD;
12287                t = readtoken();
12288                while (t != TESAC) {
12289                        if (lasttoken == TLP)
12290                                readtoken();
12291                        *cpp = cp = stzalloc(sizeof(struct nclist));
12292                        cp->type = NCLIST;
12293                        app = &cp->nclist.pattern;
12294                        for (;;) {
12295                                *app = ap = stzalloc(sizeof(struct narg));
12296                                ap->type = NARG;
12297                                /*ap->narg.next = NULL; - stzalloc did it */
12298                                ap->narg.text = wordtext;
12299                                ap->narg.backquote = backquotelist;
12300                                if (readtoken() != TPIPE)
12301                                        break;
12302                                app = &ap->narg.next;
12303                                readtoken();
12304                        }
12305                        //ap->narg.next = NULL;
12306                        if (lasttoken != TRP)
12307                                raise_error_unexpected_syntax(TRP);
12308                        cp->nclist.body = list(2);
12309
12310                        cpp = &cp->nclist.next;
12311
12312                        checkkwd = CHKNL | CHKKWD;
12313                        t = readtoken();
12314                        if (t != TESAC) {
12315                                if (t != TENDCASE)
12316                                        raise_error_unexpected_syntax(TENDCASE);
12317                                goto next_case;
12318                        }
12319                }
12320                *cpp = NULL;
12321                goto redir;
12322        case TLP:
12323                n1 = stzalloc(sizeof(struct nredir));
12324                n1->type = NSUBSHELL;
12325                n1->nredir.linno = savelinno;
12326                n1->nredir.n = list(0);
12327                /*n1->nredir.redirect = NULL; - stzalloc did it */
12328                t = TRP;
12329                break;
12330        case TBEGIN:
12331                n1 = list(0);
12332                t = TEND;
12333                break;
12334        IF_BASH_FUNCTION(case TFUNCTION:)
12335        case TWORD:
12336        case TREDIR:
12337                tokpushback = 1;
12338                return simplecmd();
12339        }
12340
12341        if (readtoken() != t)
12342                raise_error_unexpected_syntax(t);
12343
12344 redir:
12345        /* Now check for redirection which may follow command */
12346        checkkwd = CHKKWD | CHKALIAS;
12347        rpp = rpp2;
12348        while (readtoken() == TREDIR) {
12349                *rpp = n2 = redirnode;
12350                rpp = &n2->nfile.next;
12351                parsefname();
12352        }
12353        tokpushback = 1;
12354        *rpp = NULL;
12355        if (redir) {
12356                if (n1->type != NSUBSHELL) {
12357                        n2 = stzalloc(sizeof(struct nredir));
12358                        n2->type = NREDIR;
12359                        n2->nredir.linno = savelinno;
12360                        n2->nredir.n = n1;
12361                        n1 = n2;
12362                }
12363                n1->nredir.redirect = redir;
12364        }
12365        return n1;
12366}
12367
12368#if BASH_DOLLAR_SQUOTE
12369static int
12370decode_dollar_squote(void)
12371{
12372        static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
12373        int c, cnt;
12374        char *p;
12375        char buf[4];
12376
12377        c = pgetc();
12378        p = strchr(C_escapes, c);
12379        if (p) {
12380                buf[0] = c;
12381                p = buf;
12382                cnt = 3;
12383                if ((unsigned char)(c - '0') <= 7) { /* \ooo */
12384                        do {
12385                                c = pgetc();
12386                                *++p = c;
12387                        } while ((unsigned char)(c - '0') <= 7 && --cnt);
12388                        pungetc();
12389                } else if (c == 'x') { /* \xHH */
12390                        do {
12391                                c = pgetc();
12392                                *++p = c;
12393                        } while (isxdigit(c) && --cnt);
12394                        pungetc();
12395                        if (cnt == 3) { /* \x but next char is "bad" */
12396                                c = 'x';
12397                                goto unrecognized;
12398                        }
12399                } else { /* simple seq like \\ or \t */
12400                        p++;
12401                }
12402                *p = '\0';
12403                p = buf;
12404                c = bb_process_escape_sequence((void*)&p);
12405        } else { /* unrecognized "\z": print both chars unless ' or " */
12406                if (c != '\'' && c != '"') {
12407 unrecognized:
12408                        c |= 0x100; /* "please encode \, then me" */
12409                }
12410        }
12411        return c;
12412}
12413#endif
12414
12415/* Used by expandstr to get here-doc like behaviour. */
12416#define FAKEEOFMARK ((char*)(uintptr_t)1)
12417
12418static ALWAYS_INLINE int
12419realeofmark(const char *eofmark)
12420{
12421        return eofmark && eofmark != FAKEEOFMARK;
12422}
12423
12424/*
12425 * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
12426 * is not NULL, read a here document.  In the latter case, eofmark is the
12427 * word which marks the end of the document and striptabs is true if
12428 * leading tabs should be stripped from the document.  The argument c
12429 * is the first character of the input token or document.
12430 *
12431 * Because C does not have internal subroutines, I have simulated them
12432 * using goto's to implement the subroutine linkage.  The following macros
12433 * will run code that appears at the end of readtoken1.
12434 */
12435#define CHECKEND()      {goto checkend; checkend_return:;}
12436#define PARSEREDIR()    {goto parseredir; parseredir_return:;}
12437#define PARSESUB()      {goto parsesub; parsesub_return:;}
12438#define PARSEBACKQOLD() {style = OLD; goto parsebackq; parsebackq_oldreturn:;}
12439#define PARSEBACKQNEW() {style = NEW; goto parsebackq; parsebackq_newreturn:;}
12440#define PARSEPROCSUB()  {style = PSUB; goto parsebackq; parsebackq_psreturn:;}
12441#define PARSEARITH()    {goto parsearith; parsearith_return:;}
12442static int
12443readtoken1(int c, int syntax, char *eofmark, int striptabs)
12444{
12445        /* NB: syntax parameter fits into smallint */
12446        /* c parameter is an unsigned char or PEOF */
12447        char *out;
12448        size_t len;
12449        struct nodelist *bqlist;
12450        smallint quotef;
12451        smallint style;
12452        enum { OLD, NEW, PSUB };
12453#define oldstyle (style == OLD)
12454        smallint pssyntax;   /* we are expanding a prompt string */
12455        IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
12456        /* syntax stack */
12457        struct synstack synbase = { };
12458        struct synstack *synstack = &synbase;
12459
12460#if ENABLE_ASH_EXPAND_PRMT
12461        pssyntax = (syntax == PSSYNTAX);
12462        if (pssyntax)
12463                syntax = DQSYNTAX;
12464#else
12465        pssyntax = 0; /* constant */
12466#endif
12467        synstack->syntax = syntax;
12468
12469        if (syntax == DQSYNTAX)
12470                synstack->dblquote = 1;
12471        quotef = 0;
12472        bqlist = NULL;
12473
12474        STARTSTACKSTR(out);
12475 loop:
12476        /* For each line, until end of word */
12477        CHECKEND();     /* set c to PEOF if at end of here document */
12478        for (;;) {      /* until end of line or end of word */
12479                CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
12480                switch (SIT(c, synstack->syntax)) {
12481                case CNL:       /* '\n' */
12482                        if (synstack->syntax == BASESYNTAX
12483                         && !synstack->varnest
12484                        ) {
12485                                goto endword;   /* exit outer loop */
12486                        }
12487                        USTPUTC(c, out);
12488                        nlprompt();
12489                        c = pgetc_top(synstack);
12490                        goto loop;              /* continue outer loop */
12491                case CWORD:
12492                        USTPUTC(c, out);
12493                        break;
12494                case CCTL:
12495#if BASH_DOLLAR_SQUOTE
12496                        if (c == '\\' && bash_dollar_squote) {
12497                                c = decode_dollar_squote();
12498                                if (c == '\0') {
12499                                        /* skip $'\000', $'\x00' (like bash) */
12500                                        break;
12501                                }
12502                                if (c & 0x100) {
12503                                        /* Unknown escape. Encode as '\z' */
12504                                        c = (unsigned char)c;
12505                                        if (eofmark == NULL || synstack->dblquote)
12506                                                USTPUTC(CTLESC, out);
12507                                        USTPUTC('\\', out);
12508                                }
12509                        }
12510#endif
12511                        if (!eofmark || synstack->dblquote || synstack->varnest)
12512                                USTPUTC(CTLESC, out);
12513                        USTPUTC(c, out);
12514                        break;
12515                case CBACK:     /* backslash */
12516                        c = pgetc();
12517                        if (c == PEOF) {
12518                                USTPUTC(CTLESC, out);
12519                                USTPUTC('\\', out);
12520                                pungetc();
12521                        } else {
12522                                if (pssyntax && c == '$') {
12523                                        USTPUTC(CTLESC, out);
12524                                        USTPUTC('\\', out);
12525                                }
12526                                /* Backslash is retained if we are in "str"
12527                                 * and next char isn't dquote-special.
12528                                 */
12529                                if (synstack->dblquote
12530                                 && c != '\\'
12531                                 && c != '`'
12532                                 && c != '$'
12533                                 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12534                                 && (c != '}' || !synstack->varnest)
12535                                ) {
12536                                        USTPUTC(CTLESC, out); /* protect '\' from glob */
12537                                        USTPUTC('\\', out);
12538                                }
12539                                USTPUTC(CTLESC, out);
12540                                USTPUTC(c, out);
12541                                quotef = 1;
12542                        }
12543                        break;
12544                case CSQUOTE:
12545                        synstack->syntax = SQSYNTAX;
12546 quotemark:
12547                        if (eofmark == NULL) {
12548                                USTPUTC(CTLQUOTEMARK, out);
12549                        }
12550                        break;
12551                case CDQUOTE:
12552                        synstack->syntax = DQSYNTAX;
12553                        synstack->dblquote = 1;
12554 toggledq:
12555                        if (synstack->varnest)
12556                                synstack->innerdq ^= 1;
12557                        goto quotemark;
12558                case CENDQUOTE:
12559                        IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
12560                        if (eofmark != NULL && synstack->varnest == 0) {
12561                                USTPUTC(c, out);
12562                                break;
12563                        }
12564
12565                        if (synstack->dqvarnest == 0) {
12566                                synstack->syntax = BASESYNTAX;
12567                                synstack->dblquote = 0;
12568                        }
12569
12570                        quotef = 1;
12571
12572                        if (c == '"')
12573                                goto toggledq;
12574
12575                        goto quotemark;
12576                case CVAR:      /* '$' */
12577                        PARSESUB();             /* parse substitution */
12578                        break;
12579                case CENDVAR:   /* '}' */
12580                        if (!synstack->innerdq && synstack->varnest > 0) {
12581                                if (!--synstack->varnest && synstack->varpushed)
12582                                        synstack_pop(&synstack);
12583                                else if (synstack->dqvarnest > 0)
12584                                        synstack->dqvarnest--;
12585                                c = CTLENDVAR;
12586                        }
12587                        USTPUTC(c, out);
12588                        break;
12589#if ENABLE_FEATURE_SH_MATH
12590                case CLP:       /* '(' in arithmetic */
12591                        synstack->parenlevel++;
12592                        USTPUTC(c, out);
12593                        break;
12594                case CRP:       /* ')' in arithmetic */
12595                        if (synstack->parenlevel > 0) {
12596                                synstack->parenlevel--;
12597                        } else {
12598                                if (pgetc_eatbnl() == ')') {
12599                                        c = CTLENDARI;
12600                                        synstack_pop(&synstack);
12601                                } else {
12602                                        /*
12603                                         * unbalanced parens
12604                                         * (don't 2nd guess - no error)
12605                                         */
12606                                        pungetc();
12607                                }
12608                        }
12609                        USTPUTC(c, out);
12610                        break;
12611#endif
12612                case CBQUOTE:   /* '`' */
12613                        if (checkkwd & CHKEOFMARK) {
12614                                quotef = 1;
12615                                USTPUTC('`', out);
12616                                break;
12617                        }
12618
12619                        PARSEBACKQOLD();
12620                        break;
12621                case CENDFILE:
12622                        goto endword;           /* exit outer loop */
12623                default:
12624                        if (synstack->varnest == 0) {
12625#if BASH_REDIR_OUTPUT
12626                                if (c == '&') {
12627//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
12628                                        if (pgetc() == '>')
12629                                                c = 0x100 + '>'; /* flag &> */
12630                                        pungetc();
12631                                }
12632#endif
12633#if BASH_PROCESS_SUBST
12634                                if (c == '<' || c == '>') {
12635                                        if (pgetc() == '(') {
12636                                                PARSEPROCSUB();
12637                                                break;
12638                                        }
12639                                        pungetc();
12640                                }
12641#endif
12642                                goto endword;   /* exit outer loop */
12643                        }
12644                        USTPUTC(c, out);
12645                }
12646                c = pgetc_top(synstack);
12647        } /* for (;;) */
12648 endword:
12649
12650#if ENABLE_FEATURE_SH_MATH
12651        if (synstack->syntax == ARISYNTAX)
12652                raise_error_syntax("missing '))'");
12653#endif
12654        if (synstack->syntax != BASESYNTAX && eofmark == NULL)
12655                raise_error_syntax("unterminated quoted string");
12656        if (synstack->varnest != 0) {
12657                /* { */
12658                raise_error_syntax("missing '}'");
12659        }
12660        USTPUTC('\0', out);
12661        len = out - (char *)stackblock();
12662        out = stackblock();
12663        if (eofmark == NULL) {
12664                if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
12665                 && quotef == 0
12666                ) {
12667                        if (isdigit_str9(out)) {
12668                                PARSEREDIR(); /* passed as params: out, c */
12669                                lasttoken = TREDIR;
12670                                return lasttoken;
12671                        }
12672                        /* else: non-number X seen, interpret it
12673                         * as "NNNX>file" = "NNNX >file" */
12674                }
12675                pungetc();
12676        }
12677        quoteflag = quotef;
12678        backquotelist = bqlist;
12679        grabstackblock(len);
12680        wordtext = out;
12681        lasttoken = TWORD;
12682        return lasttoken;
12683/* end of readtoken routine */
12684
12685/*
12686 * Check to see whether we are at the end of the here document.  When this
12687 * is called, c is set to the first character of the next input line.  If
12688 * we are at the end of the here document, this routine sets the c to PEOF.
12689 */
12690checkend: {
12691        if (realeofmark(eofmark)) {
12692                int markloc;
12693                char *p;
12694
12695                if (striptabs) {
12696                        while (c == '\t')
12697                                c = pgetc();
12698                }
12699
12700                markloc = out - (char *)stackblock();
12701                for (p = eofmark; STPUTC(c, out), *p; p++) {
12702                        if (c != *p)
12703                                goto more_heredoc;
12704                        /* FIXME: fails for backslash-newlined terminator:
12705                         * cat <<EOF
12706                         * ...
12707                         * EO\
12708                         * F
12709                         * (see heredoc_bkslash_newline2.tests)
12710                         */
12711                        c = pgetc();
12712                }
12713
12714                if (c == '\n' || c == PEOF) {
12715                        c = PEOF;
12716                        if (trap_depth == 0)
12717                                g_parsefile->linno++;
12718                        needprompt = doprompt;
12719                } else {
12720                        int len_here;
12721
12722 more_heredoc:
12723                        p = (char *)stackblock() + markloc + 1;
12724                        len_here = out - p;
12725
12726                        if (len_here) {
12727                                len_here -= (c >= PEOF);
12728                                c = p[-1];
12729
12730                                if (len_here) {
12731                                        char *str;
12732
12733                                        str = alloca(len_here + 1);
12734                                        *(char *)mempcpy(str, p, len_here) = '\0';
12735
12736                                        pushstring(str, NULL);
12737                                }
12738                        }
12739                }
12740
12741                STADJUST((char *)stackblock() + markloc - out, out);
12742        }
12743        goto checkend_return;
12744}
12745
12746/*
12747 * Parse a redirection operator.  The variable "out" points to a string
12748 * specifying the fd to be redirected.  The variable "c" contains the
12749 * first character of the redirection operator.
12750 */
12751parseredir: {
12752        /* out is already checked to be a valid number or "" */
12753        int fd = (*out == '\0' ? -1 : atoi(out));
12754        union node *np;
12755
12756        np = stzalloc(sizeof(struct nfile));
12757        if (c == '>') {
12758                np->nfile.fd = 1;
12759                c = pgetc_eatbnl();
12760                if (c == '>')
12761                        np->type = NAPPEND;
12762                else if (c == '|')
12763                        np->type = NCLOBBER;
12764                else if (c == '&')
12765                        np->type = NTOFD;
12766                        /* it also can be NTO2 (>&file), but we can't figure it out yet */
12767                else {
12768                        np->type = NTO;
12769                        pungetc();
12770                }
12771        }
12772#if BASH_REDIR_OUTPUT
12773        else if (c == 0x100 + '>') { /* this flags &> redirection */
12774                np->nfile.fd = 1;
12775                pgetc(); /* this is '>', no need to check */
12776                np->type = NTO2;
12777        }
12778#endif
12779        else { /* c == '<' */
12780                /*np->nfile.fd = 0; - stzalloc did it */
12781                c = pgetc_eatbnl();
12782                switch (c) {
12783                case '<':
12784                        if (sizeof(struct nfile) != sizeof(struct nhere)) {
12785                                np = stzalloc(sizeof(struct nhere));
12786                                /*np->nfile.fd = 0; - stzalloc did it */
12787                        }
12788                        np->type = NHERE;
12789                        heredoc = stzalloc(sizeof(struct heredoc));
12790                        heredoc->here = np;
12791                        c = pgetc_eatbnl();
12792                        if (c == '-') {
12793                                heredoc->striptabs = 1;
12794                        } else {
12795                                /*heredoc->striptabs = 0; - stzalloc did it */
12796                                pungetc();
12797                        }
12798                        break;
12799
12800                case '&':
12801                        np->type = NFROMFD;
12802                        break;
12803
12804                case '>':
12805                        np->type = NFROMTO;
12806                        break;
12807
12808                default:
12809                        np->type = NFROM;
12810                        pungetc();
12811                        break;
12812                }
12813        }
12814        if (fd >= 0)
12815                np->nfile.fd = fd;
12816        redirnode = np;
12817        goto parseredir_return;
12818}
12819
12820/*
12821 * Parse a substitution.  At this point, we have read the dollar sign
12822 * and nothing else.
12823 */
12824
12825/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12826 * (assuming ascii char codes, as the original implementation did) */
12827#define is_special(c) \
12828        (((unsigned)(c) - 33 < 32) \
12829                        && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
12830parsesub: {
12831        unsigned char subtype;
12832        int typeloc;
12833
12834        c = pgetc_eatbnl();
12835        if ((checkkwd & CHKEOFMARK)
12836         || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
12837        ) {
12838#if BASH_DOLLAR_SQUOTE
12839                if (synstack->syntax != DQSYNTAX && c == '\'')
12840                        bash_dollar_squote = 1;
12841                else
12842#endif
12843                        USTPUTC('$', out);
12844                pungetc();
12845        } else if (c == '(') {
12846                /* $(command) or $((arith)) */
12847                if (pgetc_eatbnl() == '(') {
12848#if ENABLE_FEATURE_SH_MATH
12849                        PARSEARITH();
12850#else
12851                        raise_error_syntax("support for $((arith)) is disabled");
12852#endif
12853                } else {
12854                        pungetc();
12855                        PARSEBACKQNEW();
12856                }
12857        } else {
12858                /* $VAR, $<specialchar>, ${...}, or PEOF */
12859                smalluint newsyn = synstack->syntax;
12860
12861                USTPUTC(CTLVAR, out);
12862                typeloc = out - (char *)stackblock();
12863                STADJUST(1, out);
12864                subtype = VSNORMAL;
12865                if (c == '{') {
12866                        c = pgetc_eatbnl();
12867                        subtype = 0;
12868                }
12869 varname:
12870                if (is_name(c)) {
12871                        /* $[{[#]]NAME[}] */
12872                        do {
12873                                STPUTC(c, out);
12874                                c = pgetc_eatbnl();
12875                        } while (is_in_name(c));
12876                } else if (isdigit(c)) {
12877                        /* $[{[#]]NUM[}] */
12878                        do {
12879                                STPUTC(c, out);
12880                                c = pgetc_eatbnl();
12881                        } while ((subtype == 0 || subtype == VSLENGTH) && isdigit(c));
12882                } else if (c != '}') {
12883                        /* $[{[#]]<specialchar>[}] */
12884                        int cc = c;
12885
12886                        c = pgetc_eatbnl();
12887                        if (!subtype && cc == '#') {
12888                                subtype = VSLENGTH;
12889                                if (c == '_' || isalnum(c))
12890                                        goto varname;
12891                                cc = c;
12892                                c = pgetc_eatbnl();
12893                                if (cc == '}' || c != '}') {
12894                                        pungetc();
12895                                        subtype = 0;
12896                                        c = cc;
12897                                        cc = '#';
12898                                }
12899                        }
12900
12901                        if (!is_special(cc)) {
12902                                if (subtype == VSLENGTH)
12903                                        subtype = 0;
12904                                goto badsub;
12905                        }
12906
12907                        USTPUTC(cc, out);
12908                } else
12909                        goto badsub;
12910
12911                if (subtype == 0) {
12912                        static const char types[] ALIGN1 = "}-+?=";
12913                        /* ${VAR...} but not $VAR or ${#VAR} */
12914                        /* c == first char after VAR */
12915                        int cc = c;
12916
12917                        switch (c) {
12918                        case ':':
12919                                c = pgetc_eatbnl();
12920#if BASH_SUBSTR
12921                                /* This check is only needed to not misinterpret
12922                                 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12923                                 * constructs.
12924                                 */
12925                                if (!strchr(types, c)) {
12926                                        subtype = VSSUBSTR;
12927                                        pungetc();
12928                                        break; /* "goto badsub" is bigger (!) */
12929                                }
12930#endif
12931                                subtype = VSNUL;
12932                                /*FALLTHROUGH*/
12933                        default: {
12934                                const char *p = strchr(types, c);
12935                                if (p == NULL)
12936                                        break;
12937                                subtype |= p - types + VSNORMAL;
12938                                break;
12939                        }
12940                        case '%':
12941                        case '#':
12942                                subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12943                                c = pgetc_eatbnl();
12944                                if (c == cc)
12945                                        subtype++;
12946                                else
12947                                        pungetc();
12948
12949                                newsyn = BASESYNTAX;
12950                                break;
12951#if BASH_PATTERN_SUBST
12952                        case '/':
12953                                /* ${v/[/]pattern/repl} */
12954//TODO: encode pattern and repl separately.
12955// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12956// are broken (should print "ONE")
12957                                subtype = VSREPLACE;
12958                                newsyn = BASESYNTAX;
12959                                c = pgetc_eatbnl();
12960                                if (c != '/')
12961                                        goto badsub;
12962                                subtype++; /* VSREPLACEALL */
12963                                break;
12964#endif
12965                        }
12966                } else {
12967                        if (subtype == VSLENGTH && c != '}')
12968                                subtype = 0;
12969 badsub:
12970                        pungetc();
12971                }
12972
12973                if (newsyn == ARISYNTAX)
12974                        newsyn = DQSYNTAX;
12975
12976                if ((newsyn != synstack->syntax || synstack->innerdq)
12977                 && subtype != VSNORMAL
12978                ) {
12979                        synstack_push(&synstack,
12980                                synstack->prev ?: alloca(sizeof(*synstack)),
12981                                newsyn);
12982
12983                        synstack->varpushed = 1;
12984                        synstack->dblquote = newsyn != BASESYNTAX;
12985                }
12986
12987                ((unsigned char *)stackblock())[typeloc] = subtype;
12988                if (subtype != VSNORMAL) {
12989                        synstack->varnest++;
12990                        if (synstack->dblquote)
12991                                synstack->dqvarnest++;
12992                }
12993                STPUTC('=', out);
12994        }
12995        goto parsesub_return;
12996}
12997
12998/*
12999 * Called to parse command substitutions.  Newstyle is set if the command
13000 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
13001 * list of commands (passed by reference), and savelen is the number of
13002 * characters on the top of the stack which must be preserved.
13003 */
13004parsebackq: {
13005        struct nodelist **nlpp;
13006        union node *n;
13007        char *str;
13008        size_t savelen;
13009        struct heredoc *saveheredoclist;
13010        smallint saveprompt = 0;
13011
13012        str = NULL;
13013        savelen = out - (char *)stackblock();
13014        if (savelen > 0) {
13015                /*
13016                 * FIXME: this can allocate very large block on stack and SEGV.
13017                 * Example:
13018                 * echo "..<100kbytes>..`true` $(true) `true` ..."
13019                 * allocates 100kb for every command subst. With about
13020                 * a hundred command substitutions stack overflows.
13021                 * With larger prepended string, SEGV happens sooner.
13022                 */
13023                str = alloca(savelen);
13024                memcpy(str, stackblock(), savelen);
13025        }
13026
13027        if (oldstyle) {
13028                /* We must read until the closing backquote, giving special
13029                 * treatment to some slashes, and then push the string and
13030                 * reread it as input, interpreting it normally.
13031                 */
13032                char *pout;
13033                size_t psavelen;
13034                char *pstr;
13035
13036                STARTSTACKSTR(pout);
13037                for (;;) {
13038                        int pc;
13039
13040                        setprompt_if(needprompt, 2);
13041                        pc = pgetc_eatbnl();
13042                        switch (pc) {
13043                        case '`':
13044                                goto done;
13045
13046                        case '\\':
13047                                pc = pgetc(); /* not pgetc_eatbnl! */
13048                                if (pc != '\\' && pc != '`' && pc != '$'
13049                                 && (!synstack->dblquote || pc != '"')
13050                                ) {
13051                                        STPUTC('\\', pout);
13052                                }
13053                                break;
13054
13055                        case PEOF:
13056                                raise_error_syntax("EOF in backquote substitution");
13057
13058                        case '\n':
13059                                nlnoprompt();
13060                                break;
13061
13062                        default:
13063                                break;
13064                        }
13065                        STPUTC(pc, pout);
13066                }
13067 done:
13068                STPUTC('\0', pout);
13069                psavelen = pout - (char *)stackblock();
13070                if (psavelen > 0) {
13071                        pstr = grabstackstr(pout);
13072                        setinputstring(pstr);
13073                }
13074        }
13075        nlpp = &bqlist;
13076        while (*nlpp)
13077                nlpp = &(*nlpp)->next;
13078        *nlpp = stzalloc(sizeof(**nlpp));
13079        /* (*nlpp)->next = NULL; - stzalloc did it */
13080
13081        saveheredoclist = heredoclist;
13082        heredoclist = NULL;
13083
13084        if (oldstyle) {
13085                saveprompt = doprompt;
13086                doprompt = 0;
13087        }
13088
13089        n = list(2);
13090
13091        if (oldstyle)
13092                doprompt = saveprompt;
13093        else {
13094                if (readtoken() != TRP)
13095                        raise_error_unexpected_syntax(TRP);
13096                setinputstring(nullstr);
13097        }
13098
13099        parseheredoc();
13100        heredoclist = saveheredoclist;
13101
13102        (*nlpp)->n = n;
13103        /* Start reading from old file again. */
13104        popfile();
13105        /* Ignore any pushed back tokens left from the backquote parsing. */
13106        if (oldstyle)
13107                tokpushback = 0;
13108        out = growstackto(savelen + 1);
13109        if (str) {
13110                memcpy(out, str, savelen);
13111                STADJUST(savelen, out);
13112        }
13113#if BASH_PROCESS_SUBST
13114        if (style == PSUB)
13115                USTPUTC(c == '<' ? CTLFROMPROC : CTLTOPROC, out);
13116        else
13117#endif
13118                USTPUTC(CTLBACKQ, out);
13119        if (oldstyle)
13120                goto parsebackq_oldreturn;
13121#if BASH_PROCESS_SUBST
13122        else if (style == PSUB)
13123                goto parsebackq_psreturn;
13124#endif
13125        goto parsebackq_newreturn;
13126}
13127
13128#if ENABLE_FEATURE_SH_MATH
13129/*
13130 * Parse an arithmetic expansion (indicate start of one and set state)
13131 */
13132parsearith: {
13133
13134        synstack_push(&synstack,
13135                        synstack->prev ?: alloca(sizeof(*synstack)),
13136                        ARISYNTAX);
13137        synstack->dblquote = 1;
13138        USTPUTC(CTLARI, out);
13139        goto parsearith_return;
13140}
13141#endif
13142} /* end of readtoken */
13143
13144/*
13145 * Read the next input token.
13146 * If the token is a word, we set backquotelist to the list of cmds in
13147 *      backquotes.  We set quoteflag to true if any part of the word was
13148 *      quoted.
13149 * If the token is TREDIR, then we set redirnode to a structure containing
13150 *      the redirection.
13151 *
13152 * [Change comment:  here documents and internal procedures]
13153 * [Readtoken shouldn't have any arguments.  Perhaps we should make the
13154 *  word parsing code into a separate routine.  In this case, readtoken
13155 *  doesn't need to have any internal procedures, but parseword does.
13156 *  We could also make parseoperator in essence the main routine, and
13157 *  have parseword (readtoken1?) handle both words and redirection.]
13158 */
13159#define NEW_xxreadtoken
13160#ifdef NEW_xxreadtoken
13161/* singles must be first! */
13162static const char xxreadtoken_chars[7] ALIGN1 = {
13163        '\n', '(', ')', /* singles */
13164        '&', '|', ';',  /* doubles */
13165        0
13166};
13167
13168#define xxreadtoken_singles 3
13169#define xxreadtoken_doubles 3
13170
13171static const char xxreadtoken_tokens[] ALIGN1 = {
13172        TNL, TLP, TRP,          /* only single occurrence allowed */
13173        TBACKGND, TPIPE, TSEMI, /* if single occurrence */
13174        TEOF,                   /* corresponds to trailing nul */
13175        TAND, TOR, TENDCASE     /* if double occurrence */
13176};
13177
13178static int
13179xxreadtoken(void)
13180{
13181        int c;
13182
13183        if (tokpushback) {
13184                tokpushback = 0;
13185                return lasttoken;
13186        }
13187        setprompt_if(needprompt, 2);
13188        for (;;) {                      /* until token or start of word found */
13189                c = pgetc_eatbnl();
13190                if (c == ' ' || c == '\t')
13191                        continue;
13192
13193                if (c == '#') {
13194                        while ((c = pgetc()) != '\n' && c != PEOF)
13195                                continue;
13196                        pungetc();
13197                } else if (c == '\\') {
13198                        break; /* return readtoken1(...) */
13199                } else {
13200                        const char *p;
13201
13202                        p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
13203                        if (c != PEOF) {
13204                                if (c == '\n') {
13205                                        nlnoprompt();
13206                                }
13207
13208                                p = strchr(xxreadtoken_chars, c);
13209                                if (p == NULL)
13210                                        break; /* return readtoken1(...) */
13211
13212                                if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
13213                                        int cc = pgetc_eatbnl();
13214                                        if (cc == c) {    /* double occurrence? */
13215                                                p += xxreadtoken_doubles + 1;
13216                                        } else {
13217                                                pungetc();
13218#if BASH_REDIR_OUTPUT
13219                                                if (c == '&' && cc == '>') /* &> */
13220                                                        break; /* return readtoken1(...) */
13221#endif
13222                                        }
13223                                }
13224                        }
13225                        lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
13226                        return lasttoken;
13227                }
13228        } /* for (;;) */
13229
13230        return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
13231}
13232#else /* old xxreadtoken */
13233#define RETURN(token)   return lasttoken = token
13234static int
13235xxreadtoken(void)
13236{
13237        int c;
13238
13239        if (tokpushback) {
13240                tokpushback = 0;
13241                return lasttoken;
13242        }
13243        setprompt_if(needprompt, 2);
13244        for (;;) {      /* until token or start of word found */
13245                c = pgetc_eatbnl();
13246                switch (c) {
13247                case ' ': case '\t':
13248                        continue;
13249                case '#':
13250                        while ((c = pgetc()) != '\n' && c != PEOF)
13251                                continue;
13252                        pungetc();
13253                        continue;
13254                case '\n':
13255                        nlnoprompt();
13256                        RETURN(TNL);
13257                case PEOF:
13258                        RETURN(TEOF);
13259                case '&':
13260                        if (pgetc_eatbnl() == '&')
13261                                RETURN(TAND);
13262                        pungetc();
13263                        RETURN(TBACKGND);
13264                case '|':
13265                        if (pgetc_eatbnl() == '|')
13266                                RETURN(TOR);
13267                        pungetc();
13268                        RETURN(TPIPE);
13269                case ';':
13270                        if (pgetc_eatbnl() == ';')
13271                                RETURN(TENDCASE);
13272                        pungetc();
13273                        RETURN(TSEMI);
13274                case '(':
13275                        RETURN(TLP);
13276                case ')':
13277                        RETURN(TRP);
13278                }
13279                break;
13280        }
13281        return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
13282#undef RETURN
13283}
13284#endif /* old xxreadtoken */
13285
13286static int
13287readtoken(void)
13288{
13289        int t;
13290        int kwd = checkkwd;
13291#if DEBUG
13292        smallint alreadyseen = tokpushback;
13293#endif
13294
13295#if ENABLE_ASH_ALIAS
13296 top:
13297#endif
13298
13299        t = xxreadtoken();
13300
13301        /*
13302         * eat newlines
13303         */
13304        if (kwd & CHKNL) {
13305                while (t == TNL) {
13306                        parseheredoc();
13307                        checkkwd = 0;
13308                        t = xxreadtoken();
13309                }
13310        }
13311
13312        kwd |= checkkwd;
13313        checkkwd = 0;
13314
13315        if (t != TWORD || quoteflag) {
13316                goto out;
13317        }
13318
13319        /*
13320         * check for keywords
13321         */
13322        if (kwd & CHKKWD) {
13323                const char *const *pp;
13324
13325                pp = findkwd(wordtext);
13326                if (pp) {
13327                        lasttoken = t = pp - tokname_array;
13328                        TRACE(("keyword '%s' recognized\n", tokname_array[t]));
13329                        goto out;
13330                }
13331        }
13332
13333        if (kwd & CHKALIAS) {
13334#if ENABLE_ASH_ALIAS
13335                struct alias *ap;
13336                ap = lookupalias(wordtext, 1);
13337                if (ap != NULL) {
13338                        if (*ap->val) {
13339                                pushstring(ap->val, ap);
13340                        }
13341                        goto top;
13342                }
13343#endif
13344        }
13345 out:
13346#if DEBUG
13347        if (!alreadyseen)
13348                TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13349        else
13350                TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13351#endif
13352        return t;
13353}
13354
13355/*
13356 * Read and parse a command.  Returns NODE_EOF on end of file.
13357 * (NULL is a valid parse tree indicating a blank line.)
13358 */
13359static union node *
13360parsecmd(int interact)
13361{
13362        tokpushback = 0;
13363        checkkwd = 0;
13364        heredoclist = 0;
13365        doprompt = interact;
13366        setprompt_if(doprompt, doprompt);
13367        needprompt = 0;
13368        return list(1);
13369}
13370
13371/*
13372 * Input any here documents.
13373 */
13374static void
13375parseheredoc(void)
13376{
13377        struct heredoc *here;
13378        union node *n;
13379
13380        here = heredoclist;
13381        heredoclist = NULL;
13382
13383        while (here) {
13384                tokpushback = 0;
13385                setprompt_if(needprompt, 2);
13386                if (here->here->type == NHERE)
13387                        readtoken1(pgetc(), SQSYNTAX, here->eofmark, here->striptabs);
13388                else
13389                        readtoken1(pgetc_eatbnl(), DQSYNTAX, here->eofmark, here->striptabs);
13390                n = stzalloc(sizeof(struct narg));
13391                n->narg.type = NARG;
13392                /*n->narg.next = NULL; - stzalloc did it */
13393                n->narg.text = wordtext;
13394                n->narg.backquote = backquotelist;
13395                here->here->nhere.doc = n;
13396                here = here->next;
13397        }
13398}
13399
13400
13401static const char *
13402expandstr(const char *ps, int syntax_type)
13403{
13404        struct parsefile *file_stop;
13405        struct jmploc *volatile savehandler;
13406        struct heredoc *saveheredoclist;
13407        const char *result;
13408        int saveprompt;
13409        struct jmploc jmploc;
13410        union node n;
13411        int err;
13412
13413        file_stop = g_parsefile;
13414
13415        /* XXX Fix (char *) cast. */
13416        setinputstring((char *)ps);
13417
13418        saveheredoclist = heredoclist;
13419        heredoclist = NULL;
13420        saveprompt = doprompt;
13421        doprompt = 0;
13422        result = ps;
13423        savehandler = exception_handler;
13424        err = setjmp(jmploc.loc);
13425        if (err)
13426                goto out;
13427
13428        /* readtoken1() might die horribly.
13429         * Try a prompt with syntactically wrong command:
13430         * PS1='$(date "+%H:%M:%S) > '
13431         */
13432        exception_handler = &jmploc;
13433        readtoken1(pgetc_eatbnl(), syntax_type, FAKEEOFMARK, 0);
13434
13435        n.narg.type = NARG;
13436        n.narg.next = NULL;
13437        n.narg.text = wordtext;
13438        n.narg.backquote = backquotelist;
13439
13440        /* expandarg() might fail too:
13441         * PS1='$((123+))'
13442         */
13443        expandarg(&n, NULL, EXP_QUOTED);
13444        result = stackblock();
13445
13446out:
13447        exception_handler = savehandler;
13448        if (err && exception_type != EXERROR)
13449                longjmp(exception_handler->loc, 1);
13450
13451        doprompt = saveprompt;
13452        /* Try: PS1='`xxx(`' */
13453        unwindfiles(file_stop);
13454        heredoclist = saveheredoclist;
13455
13456        return result;
13457}
13458
13459static inline int
13460parser_eof(void)
13461{
13462        return tokpushback && lasttoken == TEOF;
13463}
13464
13465/*
13466 * Execute a command or commands contained in a string.
13467 */
13468static int
13469evalstring(char *s, int flags)
13470{
13471        struct jmploc *volatile savehandler;
13472        struct jmploc jmploc;
13473        int ex;
13474
13475        union node *n;
13476        struct stackmark smark;
13477        int status;
13478
13479        s = sstrdup(s);
13480        setinputstring(s);
13481        setstackmark(&smark);
13482
13483        status = 0;
13484        /* On exception inside execution loop, we must popfile().
13485         * Try interactively:
13486         *      readonly a=a
13487         *      command eval "a=b"  # throws "is read only" error
13488         * "command BLTIN" is not supposed to abort (even in non-interactive use).
13489         * But if we skip popfile(), we hit EOF in eval's string, and exit.
13490         */
13491        savehandler = exception_handler;
13492        ex = setjmp(jmploc.loc);
13493        if (ex)
13494                goto out;
13495        exception_handler = &jmploc;
13496
13497        while ((n = parsecmd(0)) != NODE_EOF) {
13498                int i;
13499
13500                i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
13501                if (n)
13502                        status = i;
13503                popstackmark(&smark);
13504                if (evalskip)
13505                        break;
13506        }
13507 out:
13508        popstackmark(&smark);
13509        popfile();
13510        stunalloc(s);
13511
13512        exception_handler = savehandler;
13513        if (ex)
13514                longjmp(exception_handler->loc, ex);
13515
13516        return status;
13517}
13518
13519/*
13520 * The eval command.
13521 */
13522static int FAST_FUNC
13523evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
13524{
13525        char *p;
13526        char *concat;
13527
13528        if (argv[1]) {
13529                p = argv[1];
13530                argv += 2;
13531                if (argv[0]) {
13532                        STARTSTACKSTR(concat);
13533                        for (;;) {
13534                                concat = stack_putstr(p, concat);
13535                                p = *argv++;
13536                                if (p == NULL)
13537                                        break;
13538                                STPUTC(' ', concat);
13539                        }
13540                        STPUTC('\0', concat);
13541                        p = grabstackstr(concat);
13542                }
13543                return evalstring(p, flags & EV_TESTED);
13544        }
13545        return 0;
13546}
13547
13548/*
13549 * Read and execute commands.
13550 * "Top" is nonzero for the top level command loop;
13551 * it turns on prompting if the shell is interactive.
13552 */
13553static int
13554cmdloop(int top)
13555{
13556        union node *n;
13557        struct stackmark smark;
13558        int inter;
13559        int status = 0;
13560        int numeof = 0;
13561
13562        TRACE(("cmdloop(%d) called\n", top));
13563        for (;;) {
13564                int skip;
13565
13566                setstackmark(&smark);
13567#if JOBS
13568                if (doing_jobctl)
13569                        showjobs(SHOW_CHANGED|SHOW_STDERR);
13570#endif
13571                inter = 0;
13572                if (iflag && top) {
13573                        inter++;
13574                        chkmail();
13575                }
13576                n = parsecmd(inter);
13577#if DEBUG
13578                if (DEBUG > 2 && debug && (n != NODE_EOF))
13579                        showtree(n);
13580#endif
13581                if (n == NODE_EOF) {
13582                        if (!top || numeof >= 50)
13583                                break;
13584                        if (!stoppedjobs()) {
13585                                if (!iflag)
13586                                        break;
13587                                if (!Iflag) {
13588                                        newline_and_flush(stderr);
13589                                        break;
13590                                }
13591                                /* "set -o ignoreeof" active, do not exit command loop on ^D */
13592                                out2str("\nUse \"exit\" to leave shell.\n");
13593                        }
13594                        numeof++;
13595                } else {
13596                        int i;
13597
13598                        /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13599                        job_warning >>= 1;
13600                        numeof = 0;
13601                        i = evaltree(n, 0);
13602                        if (n)
13603                                status = i;
13604                }
13605                popstackmark(&smark);
13606                skip = evalskip;
13607
13608                if (skip) {
13609                        evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
13610                        break;
13611                }
13612        }
13613        return status;
13614}
13615
13616/*
13617 * Take commands from a file.  To be compatible we should do a path
13618 * search for the file, which is necessary to find sub-commands.
13619 */
13620static char *
13621find_dot_file(char *basename)
13622{
13623        char *fullname;
13624        const char *path = pathval();
13625        struct stat statb;
13626        int len;
13627
13628        /* don't try this for absolute or relative paths */
13629        if (strchr(basename, '/'))
13630                return basename;
13631
13632        while ((len = padvance(&path, basename)) >= 0) {
13633                fullname = stackblock();
13634                if ((!pathopt || *pathopt == 'f')
13635                 && !stat(fullname, &statb) && S_ISREG(statb.st_mode)
13636                ) {
13637                        /* This will be freed by the caller. */
13638                        return stalloc(len);
13639                }
13640        }
13641        /* not found in PATH */
13642
13643#if ENABLE_ASH_BASH_SOURCE_CURDIR
13644        return basename;
13645#else
13646        ash_msg_and_raise_error("%s: not found", basename);
13647        /* NOTREACHED */
13648#endif
13649}
13650
13651static int FAST_FUNC
13652dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
13653{
13654        /* "false; . empty_file; echo $?" should print 0, not 1: */
13655        int status = 0;
13656        char *fullname;
13657        char **argv;
13658        char *args_need_save;
13659        volatile struct shparam saveparam;
13660
13661//???
13662//      struct strlist *sp;
13663//      for (sp = cmdenviron; sp; sp = sp->next)
13664//              setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
13665
13666        nextopt(nullstr); /* handle possible "--" */
13667        argv = argptr;
13668
13669        if (!argv[0]) {
13670                /* bash says: "bash: .: filename argument required" */
13671                return 2; /* bash compat */
13672        }
13673
13674        /* This aborts if file isn't found, which is POSIXly correct.
13675         * bash returns exitcode 1 instead.
13676         */
13677        fullname = find_dot_file(argv[0]);
13678        argv++;
13679        args_need_save = argv[0];
13680        if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
13681                int argc;
13682                saveparam = shellparam;
13683                shellparam.malloced = 0;
13684                argc = 1;
13685                while (argv[argc])
13686                        argc++;
13687                shellparam.nparam = argc;
13688                shellparam.p = argv;
13689        };
13690
13691        /* This aborts if file can't be opened, which is POSIXly correct.
13692         * bash returns exitcode 1 instead.
13693         */
13694        setinputfile(fullname, INPUT_PUSH_FILE);
13695        commandname = fullname;
13696        status = cmdloop(0);
13697        popfile();
13698
13699        if (args_need_save) {
13700                freeparam(&shellparam);
13701                shellparam = saveparam;
13702        };
13703
13704        return status;
13705}
13706
13707static int FAST_FUNC
13708exitcmd(int argc UNUSED_PARAM, char **argv)
13709{
13710        if (stoppedjobs())
13711                return 0;
13712
13713        if (argv[1])
13714                savestatus = number(argv[1]);
13715
13716//TODO: this script
13717// trap 'echo trap:$FUNCNAME' EXIT
13718// f() { exit; }
13719// f
13720//prints "trap:f" in bash. We can call exitshell() here to achieve this.
13721//For now, keeping dash code:
13722        raise_exception(EXEXIT);
13723        /* NOTREACHED */
13724}
13725
13726/*
13727 * Read a file containing shell functions.
13728 */
13729static void
13730readcmdfile(char *name)
13731{
13732        setinputfile(name, INPUT_PUSH_FILE);
13733        cmdloop(0);
13734        popfile();
13735}
13736
13737
13738/* ============ find_command inplementation */
13739
13740/*
13741 * Resolve a command name.  If you change this routine, you may have to
13742 * change the shellexec routine as well.
13743 */
13744static void
13745find_command(char *name, struct cmdentry *entry, int act, const char *path)
13746{
13747        struct tblentry *cmdp;
13748        int idx;
13749        int prev;
13750        char *fullname;
13751        struct stat statb;
13752        int e;
13753        int updatetbl;
13754        struct builtincmd *bcmd;
13755        int len;
13756
13757        /* If name contains a slash, don't use PATH or hash table */
13758        if (strchr(name, '/') != NULL) {
13759                entry->u.index = -1;
13760                if (act & DO_ABS) {
13761                        while (stat(name, &statb) < 0) {
13762#ifdef SYSV
13763                                if (errno == EINTR)
13764                                        continue;
13765#endif
13766                                entry->cmdtype = CMDUNKNOWN;
13767                                return;
13768                        }
13769                }
13770                entry->cmdtype = CMDNORMAL;
13771                return;
13772        }
13773
13774/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
13775
13776        updatetbl = (path == pathval());
13777        if (!updatetbl)
13778                act |= DO_ALTPATH;
13779
13780        /* If name is in the table, check answer will be ok */
13781        cmdp = cmdlookup(name, 0);
13782        if (cmdp != NULL) {
13783                int bit;
13784
13785                switch (cmdp->cmdtype) {
13786                default:
13787#if DEBUG
13788                        abort();
13789#endif
13790                case CMDNORMAL:
13791                        bit = DO_ALTPATH | DO_REGBLTIN;
13792                        break;
13793                case CMDFUNCTION:
13794                        bit = DO_NOFUNC;
13795                        break;
13796                case CMDBUILTIN:
13797                        bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
13798                        break;
13799                }
13800                if (act & bit) {
13801                        if (act & bit & DO_REGBLTIN)
13802                                goto fail;
13803
13804                        updatetbl = 0;
13805                        cmdp = NULL;
13806                } else if (cmdp->rehash == 0)
13807                        /* if not invalidated by cd, we're done */
13808                        goto success;
13809        }
13810
13811        /* If %builtin not in path, check for builtin next */
13812        bcmd = find_builtin(name);
13813        if (bcmd) {
13814                if (IS_BUILTIN_REGULAR(bcmd))
13815                        goto builtin_success;
13816                if (act & DO_ALTPATH)
13817                        goto builtin_success;
13818                if (builtinloc <= 0)
13819                        goto builtin_success;
13820        }
13821
13822        if (act & DO_REGBLTIN)
13823                goto fail;
13824
13825#if ENABLE_FEATURE_SH_STANDALONE
13826        {
13827                int applet_no = find_applet_by_name(name);
13828                if (applet_no >= 0) {
13829                        entry->cmdtype = CMDNORMAL;
13830                        entry->u.index = -2 - applet_no;
13831                        return;
13832                }
13833        }
13834#endif
13835
13836        /* We have to search path. */
13837        prev = -1;              /* where to start */
13838        if (cmdp && cmdp->rehash) {     /* doing a rehash */
13839                if (cmdp->cmdtype == CMDBUILTIN)
13840                        prev = builtinloc;
13841                else
13842                        prev = cmdp->param.index;
13843        }
13844
13845        e = ENOENT;
13846        idx = -1;
13847 loop:
13848        while ((len = padvance(&path, name)) >= 0) {
13849                const char *lpathopt = pathopt;
13850
13851                fullname = stackblock();
13852                idx++;
13853                if (lpathopt) {
13854                        if (*lpathopt == 'b') {
13855                                if (bcmd)
13856                                        goto builtin_success;
13857                                continue;
13858                        } else if (!(act & DO_NOFUNC)) {
13859                                /* handled below */
13860                        } else {
13861                                /* ignore unimplemented options */
13862                                continue;
13863                        }
13864                }
13865                /* if rehash, don't redo absolute path names */
13866                if (fullname[0] == '/' && idx <= prev) {
13867                        if (idx < prev)
13868                                continue;
13869                        TRACE(("searchexec \"%s\": no change\n", name));
13870                        goto success;
13871                }
13872                while (stat(fullname, &statb) < 0) {
13873#ifdef SYSV
13874                        if (errno == EINTR)
13875                                continue;
13876#endif
13877                        if (errno != ENOENT && errno != ENOTDIR)
13878                                e = errno;
13879                        goto loop;
13880                }
13881                e = EACCES;     /* if we fail, this will be the error */
13882                if (!S_ISREG(statb.st_mode))
13883                        continue;
13884                if (lpathopt) {          /* this is a %func directory */
13885                        stalloc(len);
13886                        /* NB: stalloc will return space pointed by fullname
13887                         * (because we don't have any intervening allocations
13888                         * between stunalloc above and this stalloc) */
13889                        readcmdfile(fullname);
13890                        cmdp = cmdlookup(name, 0);
13891                        if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13892                                ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13893                        stunalloc(fullname);
13894                        goto success;
13895                }
13896                TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13897                if (!updatetbl) {
13898                        entry->cmdtype = CMDNORMAL;
13899                        entry->u.index = idx;
13900                        return;
13901                }
13902                INT_OFF;
13903                cmdp = cmdlookup(name, 1);
13904                cmdp->cmdtype = CMDNORMAL;
13905                cmdp->param.index = idx;
13906                INT_ON;
13907                goto success;
13908        }
13909
13910        /* We failed.  If there was an entry for this command, delete it */
13911        if (cmdp && updatetbl)
13912                delete_cmd_entry();
13913        if (act & DO_ERR) {
13914#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13915                struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13916                if (hookp && hookp->cmdtype == CMDFUNCTION) {
13917                        char *argv[3];
13918                        argv[0] = (char*) "command_not_found_handle";
13919                        argv[1] = name;
13920                        argv[2] = NULL;
13921                        evalfun(hookp->param.func, 2, argv, 0);
13922                        entry->cmdtype = CMDUNKNOWN;
13923                        return;
13924                }
13925#endif
13926                ash_msg("%s: %s", name, errmsg(e, "not found"));
13927        }
13928 fail:
13929        entry->cmdtype = CMDUNKNOWN;
13930        return;
13931
13932 builtin_success:
13933        if (!updatetbl) {
13934                entry->cmdtype = CMDBUILTIN;
13935                entry->u.cmd = bcmd;
13936                return;
13937        }
13938        INT_OFF;
13939        cmdp = cmdlookup(name, 1);
13940        cmdp->cmdtype = CMDBUILTIN;
13941        cmdp->param.cmd = bcmd;
13942        INT_ON;
13943 success:
13944        cmdp->rehash = 0;
13945        entry->cmdtype = cmdp->cmdtype;
13946        entry->u = cmdp->param;
13947}
13948
13949
13950/*
13951 * The trap builtin.
13952 */
13953static int FAST_FUNC
13954trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13955{
13956        char *action;
13957        char **ap;
13958        int signo, exitcode;
13959
13960        nextopt(nullstr);
13961        ap = argptr;
13962        if (!*ap) {
13963                for (signo = 0; signo <= NTRAP_LAST; signo++) {
13964                        char *tr = trap_ptr[signo];
13965                        if (tr) {
13966                                /* note: bash adds "SIG", but only if invoked
13967                                 * as "bash". If called as "sh", or if set -o posix,
13968                                 * then it prints short signal names.
13969                                 * We are printing short names: */
13970                                out1fmt("trap -- %s %s\n",
13971                                                single_quote(tr),
13972                                                (signo == NTRAP_ERR) ? "ERR" : get_signame(signo));
13973                /* trap_ptr != trap only if we are in special-cased `trap` code.
13974                 * In this case, we will exit very soon, no need to free(). */
13975                                /* if (trap_ptr != trap && tp[0]) */
13976                                /*      free(tr); */
13977                        }
13978                }
13979                /*
13980                if (trap_ptr != trap) {
13981                        free(trap_ptr);
13982                        trap_ptr = trap;
13983                }
13984                */
13985                return 0;
13986        }
13987
13988        /* Why the second check?
13989         * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13990         * In this case, NUM is signal no, not an action.
13991         */
13992        action = NULL;
13993        if (ap[1] && !is_number(ap[0]))
13994                action = *ap++;
13995
13996        exitcode = 0;
13997        while (*ap) {
13998                signo = strcmp(*ap, "ERR") == 0 ? NTRAP_ERR : get_signum(*ap);
13999                if (signo < 0) {
14000                        /* Mimic bash message exactly */
14001                        ash_msg("%s: invalid signal specification", *ap);
14002                        exitcode = 1;
14003                        goto next;
14004                }
14005                INT_OFF;
14006                if (action) {
14007                        if (LONE_DASH(action))
14008                                action = NULL;
14009                        else {
14010                                if (action[0]) /* not NULL and not "" and not "-" */
14011                                        may_have_traps = 1;
14012                                action = ckstrdup(action);
14013                        }
14014                }
14015                free(trap[signo]);
14016                trap[signo] = action;
14017                if (signo != 0 && signo < NSIG)
14018                        setsignal(signo);
14019                INT_ON;
14020 next:
14021                ap++;
14022        }
14023        return exitcode;
14024}
14025
14026
14027/* ============ Builtins */
14028
14029#if ENABLE_ASH_HELP
14030static int FAST_FUNC
14031helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14032{
14033        unsigned col;
14034        unsigned i;
14035
14036        out1fmt(
14037                "Built-in commands:\n"
14038                "------------------\n");
14039        for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
14040                col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
14041                                        builtintab[i].name + 1);
14042                if (col > 60) {
14043                        out1fmt("\n");
14044                        col = 0;
14045                }
14046        }
14047# if ENABLE_FEATURE_SH_STANDALONE
14048        {
14049                const char *a = applet_names;
14050                while (*a) {
14051                        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
14052                        if (col > 60) {
14053                                out1fmt("\n");
14054                                col = 0;
14055                        }
14056                        while (*a++ != '\0')
14057                                continue;
14058                }
14059        }
14060# endif
14061        newline_and_flush(stdout);
14062        return EXIT_SUCCESS;
14063}
14064#endif
14065
14066#if MAX_HISTORY
14067static int FAST_FUNC
14068historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14069{
14070        show_history(line_input_state);
14071        return EXIT_SUCCESS;
14072}
14073#endif
14074
14075/*
14076 * The export and readonly commands.
14077 */
14078static int FAST_FUNC
14079exportcmd(int argc UNUSED_PARAM, char **argv)
14080{
14081        struct var *vp;
14082        char *name;
14083        const char *p;
14084        char **aptr;
14085        char opt;
14086        int flag;
14087        int flag_off;
14088
14089        /* "readonly" in bash accepts, but ignores -n.
14090         * We do the same: it saves a conditional in nextopt's param.
14091         */
14092        flag_off = 0;
14093        while ((opt = nextopt("np")) != '\0') {
14094                if (opt == 'n')
14095                        flag_off = VEXPORT;
14096        }
14097        flag = VEXPORT;
14098        if (argv[0][0] == 'r') {
14099                flag = VREADONLY;
14100                flag_off = 0; /* readonly ignores -n */
14101        }
14102        flag_off = ~flag_off;
14103
14104        /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
14105        {
14106                aptr = argptr;
14107                name = *aptr;
14108                if (name) {
14109                        do {
14110                                p = strchr(name, '=');
14111                                if (p != NULL) {
14112                                        p++;
14113                                } else {
14114                                        vp = *findvar(hashvar(name), name);
14115                                        if (vp) {
14116                                                vp->flags = ((vp->flags | flag) & flag_off);
14117                                                continue;
14118                                        }
14119                                }
14120                                setvar(name, p, (flag & flag_off));
14121                        } while ((name = *++aptr) != NULL);
14122                        return 0;
14123                }
14124        }
14125
14126        /* No arguments. Show the list of exported or readonly vars.
14127         * -n is ignored.
14128         */
14129        showvars(argv[0], flag, 0);
14130        return 0;
14131}
14132
14133/*
14134 * Delete a function if it exists.
14135 */
14136static void
14137unsetfunc(const char *name)
14138{
14139        struct tblentry *cmdp;
14140
14141        cmdp = cmdlookup(name, 0);
14142        if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
14143                delete_cmd_entry();
14144}
14145
14146/*
14147 * The unset builtin command.  We unset the function before we unset the
14148 * variable to allow a function to be unset when there is a readonly variable
14149 * with the same name.
14150 */
14151static int FAST_FUNC
14152unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14153{
14154        char **ap;
14155        int i;
14156        int flag = 0;
14157
14158        while ((i = nextopt("vf")) != 0) {
14159                flag = i;
14160        }
14161
14162        for (ap = argptr; *ap; ap++) {
14163                if (flag != 'f') {
14164                        unsetvar(*ap);
14165                        continue;
14166                }
14167                if (flag != 'v')
14168                        unsetfunc(*ap);
14169        }
14170        return 0;
14171}
14172
14173static const unsigned char timescmd_str[] ALIGN1 = {
14174        ' ',  offsetof(struct tms, tms_utime),
14175        '\n', offsetof(struct tms, tms_stime),
14176        ' ',  offsetof(struct tms, tms_cutime),
14177        '\n', offsetof(struct tms, tms_cstime),
14178        0
14179};
14180static int FAST_FUNC
14181timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14182{
14183        unsigned clk_tck;
14184        const unsigned char *p;
14185        struct tms buf;
14186
14187        clk_tck = bb_clk_tck();
14188
14189        times(&buf);
14190        p = timescmd_str;
14191        do {
14192                unsigned sec, frac;
14193                unsigned long t;
14194                t = *(clock_t *)(((char *) &buf) + p[1]);
14195                sec = t / clk_tck;
14196                frac = t % clk_tck;
14197                out1fmt("%um%u.%03us%c",
14198                        sec / 60, sec % 60,
14199                        (frac * 1000) / clk_tck,
14200                        p[0]);
14201                p += 2;
14202        } while (*p);
14203
14204        return 0;
14205}
14206
14207#if ENABLE_FEATURE_SH_MATH
14208/*
14209 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
14210 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
14211 *
14212 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
14213 */
14214static int FAST_FUNC
14215letcmd(int argc UNUSED_PARAM, char **argv)
14216{
14217        arith_t i;
14218
14219        argv++;
14220        if (!*argv)
14221                ash_msg_and_raise_error("expression expected");
14222        do {
14223                i = ash_arith(*argv);
14224        } while (*++argv);
14225
14226        return !i;
14227}
14228#endif
14229
14230/*
14231 * The read builtin. Options:
14232 *      -r              Do not interpret '\' specially
14233 *      -s              Turn off echo (tty only)
14234 *      -n NCHARS       Read NCHARS max
14235 *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
14236 *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
14237 *      -u FD           Read from given FD instead of fd 0
14238 *      -d DELIM        End on DELIM char, not newline
14239 * This uses unbuffered input, which may be avoidable in some cases.
14240 * TODO: bash also has:
14241 *      -a ARRAY        Read into array[0],[1],etc
14242 *      -e              Use line editing (tty only)
14243 */
14244static int FAST_FUNC
14245readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14246{
14247        struct builtin_read_params params;
14248        const char *r;
14249        int i;
14250
14251        memset(&params, 0, sizeof(params));
14252
14253        while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
14254                switch (i) {
14255                case 'p':
14256                        params.opt_p = optionarg;
14257                        break;
14258                case 'n':
14259                        params.opt_n = optionarg;
14260                        break;
14261                case 's':
14262                        params.read_flags |= BUILTIN_READ_SILENT;
14263                        break;
14264                case 't':
14265                        params.opt_t = optionarg;
14266                        break;
14267                case 'r':
14268                        params.read_flags |= BUILTIN_READ_RAW;
14269                        break;
14270                case 'u':
14271                        params.opt_u = optionarg;
14272                        break;
14273#if BASH_READ_D
14274                case 'd':
14275                        params.opt_d = optionarg;
14276                        break;
14277#endif
14278                default:
14279                        break;
14280                }
14281        }
14282
14283        if (!ENABLE_ASH_BASH_COMPAT && !argptr) {
14284                bb_simple_error_msg("read: need variable name");
14285                return 1;
14286        }
14287        params.argv = argptr;
14288        params.setvar = setvar0;
14289        params.ifs = bltinlookup("IFS"); /* can be NULL */
14290
14291        /* "read -s" needs to save/restore termios, can't allow ^C
14292         * to jump out of it.
14293         */
14294 again:
14295        INT_OFF;
14296        r = shell_builtin_read(&params);
14297        INT_ON;
14298
14299        if ((uintptr_t)r == 1 && errno == EINTR) {
14300                /* To get SIGCHLD: sleep 1 & read x; echo $x
14301                 * Correct behavior is to not exit "read"
14302                 */
14303                if (pending_sig == 0)
14304                        goto again;
14305        }
14306
14307        if ((uintptr_t)r > 1)
14308                ash_msg_and_raise_error(r);
14309
14310        return (uintptr_t)r;
14311}
14312
14313static int FAST_FUNC
14314umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14315{
14316        static const char permuser[3] ALIGN1 = "ogu";
14317
14318        mode_t mask;
14319        int symbolic_mode = 0;
14320
14321        while (nextopt("S") != '\0') {
14322                symbolic_mode = 1;
14323        }
14324
14325        INT_OFF;
14326        mask = umask(0);
14327        umask(mask);
14328        INT_ON;
14329
14330        if (*argptr == NULL) {
14331                if (symbolic_mode) {
14332                        char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
14333                        char *p = buf;
14334                        int i;
14335
14336                        i = 2;
14337                        for (;;) {
14338                                *p++ = ',';
14339                                *p++ = permuser[i];
14340                                *p++ = '=';
14341                                /* mask is 0..0uuugggooo. i=2 selects uuu bits */
14342                                if (!(mask & 0400)) *p++ = 'r';
14343                                if (!(mask & 0200)) *p++ = 'w';
14344                                if (!(mask & 0100)) *p++ = 'x';
14345                                mask <<= 3;
14346                                if (--i < 0)
14347                                        break;
14348                        }
14349                        *p = '\0';
14350                        puts(buf + 1);
14351                } else {
14352                        out1fmt("%04o\n", mask);
14353                }
14354        } else {
14355                char *modestr = *argptr;
14356                /* numeric umasks are taken as-is */
14357                /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
14358                if (!isdigit(modestr[0]))
14359                        mask ^= 0777;
14360                mask = bb_parse_mode(modestr, mask);
14361                if ((unsigned)mask > 0777) {
14362                        ash_msg_and_raise_error("illegal mode: %s", modestr);
14363                }
14364                if (!isdigit(modestr[0]))
14365                        mask ^= 0777;
14366                umask(mask);
14367        }
14368        return 0;
14369}
14370
14371static int FAST_FUNC
14372ulimitcmd(int argc UNUSED_PARAM, char **argv)
14373{
14374        return shell_builtin_ulimit(argv);
14375}
14376
14377/* ============ main() and helpers */
14378
14379/*
14380 * This routine is called when an error or an interrupt occurs in an
14381 * interactive shell and control is returned to the main command loop
14382 * but prior to exitshell.
14383 */
14384static void
14385exitreset(void)
14386{
14387        /* from eval.c: */
14388        if (savestatus >= 0) {
14389                if (exception_type == EXEXIT || evalskip == SKIPFUNCDEF)
14390                        exitstatus = savestatus;
14391                savestatus = -1;
14392        }
14393        evalskip = 0;
14394        loopnest = 0;
14395        inps4 = 0;
14396
14397        /* from expand.c: */
14398        ifsfree();
14399
14400        /* from redir.c: */
14401        unwindredir(NULL);
14402}
14403
14404/*
14405 * This routine is called when an error or an interrupt occurs in an
14406 * interactive shell and control is returned to the main command loop.
14407 * (In dash, this function is auto-generated by build machinery).
14408 */
14409static void
14410reset(void)
14411{
14412        /* from input.c: */
14413        g_parsefile->left_in_buffer = 0;
14414        g_parsefile->left_in_line = 0;      /* clear input buffer */
14415        g_parsefile->unget = 0;
14416        popallfiles();
14417
14418        /* from var.c: */
14419        unwindlocalvars(NULL);
14420}
14421
14422/*
14423 * Called to exit the shell.
14424 */
14425static void
14426exitshell(void)
14427{
14428        struct jmploc loc;
14429        char *p;
14430
14431#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
14432        save_history(line_input_state); /* may be NULL */
14433#endif
14434        savestatus = exitstatus;
14435        TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
14436        if (setjmp(loc.loc))
14437                goto out;
14438        exception_handler = &loc;
14439        p = trap[0];
14440        if (p) {
14441                trap[0] = NULL;
14442                evalskip = 0;
14443                trap_depth++;
14444                evalstring(p, 0);
14445                trap_depth--;
14446                evalskip = SKIPFUNCDEF;
14447                /*free(p); - we'll exit soon */
14448        }
14449 out:
14450        exitreset();
14451        /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14452         * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
14453         */
14454        setjobctl(0);
14455        flush_stdout_stderr();
14456        _exit(exitstatus);
14457        /* NOTREACHED */
14458}
14459
14460/* Don't inline: conserve stack of caller from having our locals too */
14461static NOINLINE void
14462init(void)
14463{
14464        /* we will never free this */
14465        basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
14466        basepf.linno = 1;
14467
14468        sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
14469        setsignal(SIGCHLD);
14470
14471        {
14472                char **envp;
14473                const char *p;
14474
14475                initvar();
14476                for (envp = environ; envp && *envp; envp++) {
14477/* Used to have
14478 *                      p = endofname(*envp);
14479 *                      if (p != *envp && *p == '=') {
14480 * here to weed out badly-named variables, but this breaks
14481 * scenarios where people do want them passed to children:
14482 * import os
14483 * os.environ["test-test"]="test"
14484 * if os.fork() == 0:
14485 *   os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ])  # fixes this
14486 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])  # breaks this
14487 */
14488                        if (strchr(*envp, '=')) {
14489                                setvareq(*envp, VEXPORT|VTEXTFIXED);
14490                        }
14491                }
14492
14493                setvareq((char*)defifsvar, VTEXTFIXED);
14494                setvareq((char*)defoptindvar, VTEXTFIXED);
14495
14496                setvar0("PPID", utoa(getppid()));
14497#if BASH_SHLVL_VAR
14498                p = lookupvar("SHLVL");
14499                setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
14500#endif
14501#if BASH_HOSTNAME_VAR
14502                if (!lookupvar("HOSTNAME")) {
14503                        struct utsname uts;
14504                        uname(&uts);
14505                        setvar0("HOSTNAME", uts.nodename);
14506                }
14507#endif
14508                p = lookupvar("PWD");
14509                if (p) {
14510                        struct stat st1, st2;
14511                        if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
14512                         || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14513                        ) {
14514                                p = NULL;
14515                        }
14516                }
14517                setpwd(p, 0);
14518        }
14519}
14520
14521
14522//usage:#define ash_trivial_usage
14523//usage:        "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]"
14524////////        comes from ^^^^^^^^^^optletters
14525//usage:#define ash_full_usage "\n\n"
14526//usage:        "Unix shell interpreter"
14527
14528/*
14529 * Process the shell command line arguments.
14530 */
14531static int
14532procargs(char **argv)
14533{
14534        int i;
14535        const char *xminusc;
14536        char **xargv;
14537        int login_sh;
14538
14539        xargv = argv;
14540        login_sh = xargv[0] && xargv[0][0] == '-';
14541#if NUM_SCRIPTS > 0
14542        if (minusc)
14543                goto setarg0;
14544#endif
14545        arg0 = xargv[0];
14546        /* if (xargv[0]) - mmm, this is always true! */
14547                xargv++;
14548        argptr = xargv;
14549        for (i = 0; i < NOPTS; i++)
14550                optlist[i] = 2;
14551        if (options(&login_sh)) {
14552                /* it already printed err message */
14553                raise_exception(EXERROR);
14554        }
14555        xargv = argptr;
14556        xminusc = minusc;
14557        if (*xargv == NULL) {
14558                if (xminusc)
14559                        ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14560                sflag = 1;
14561        }
14562        if (iflag == 2 /* no explicit -i given */
14563         && sflag == 1 /* -s given (or implied) */
14564         && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */
14565         && isatty(0) && isatty(1) /* we are on tty */
14566        ) {
14567                iflag = 1;
14568        }
14569        if (mflag == 2)
14570                mflag = iflag;
14571        /* Unset options which weren't explicitly set or unset */
14572        for (i = 0; i < NOPTS; i++)
14573                optlist[i] &= 1; /* same effect as "if (optlist[i] == 2) optlist[i] = 0;" */
14574#if DEBUG == 2
14575        debug = 1;
14576#endif
14577        /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
14578        if (xminusc) {
14579                minusc = *xargv++;
14580                if (*xargv)
14581                        goto setarg0;
14582        } else if (!sflag) {
14583                setinputfile(*xargv, 0);
14584 setarg0:
14585                arg0 = *xargv++;
14586                commandname = arg0;
14587        }
14588
14589        shellparam.p = xargv;
14590#if ENABLE_ASH_GETOPTS
14591        shellparam.optind = 1;
14592        shellparam.optoff = -1;
14593#endif
14594        /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
14595        while (*xargv) {
14596                shellparam.nparam++;
14597                xargv++;
14598        }
14599
14600        /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
14601         * Try:
14602         * trap '' hup; bash; echo RET  # type "kill -hup $$", see SIGHUP having effect
14603         * trap '' hup; bash -c 'kill -hup $$; echo ALIVE'  # here SIGHUP is SIG_IGNed
14604         * NB: must do it before setting up signals (in optschanged())
14605         * and reading .profile etc (after we return from here):
14606         */
14607        if (iflag)
14608                signal(SIGHUP, SIG_DFL);
14609
14610        optschanged();
14611
14612        return login_sh;
14613}
14614
14615/*
14616 * Read /etc/profile, ~/.profile, $ENV.
14617 */
14618static void
14619read_profile(const char *name)
14620{
14621        name = expandstr(name, DQSYNTAX);
14622        if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14623                return;
14624        cmdloop(0);
14625        popfile();
14626}
14627
14628#if PROFILE
14629static short profile_buf[16384];
14630extern int etext();
14631#endif
14632
14633/*
14634 * Main routine.  We initialize things, parse the arguments, execute
14635 * profiles if we're a login shell, and then call cmdloop to execute
14636 * commands.  The setjmp call sets up the location to jump to when an
14637 * exception occurs.  When an exception occurs the variable "state"
14638 * is used to figure out how far we had gotten.
14639 */
14640int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14641#if NUM_SCRIPTS > 0
14642int ash_main(int argc, char **argv)
14643#else
14644int ash_main(int argc UNUSED_PARAM, char **argv)
14645#endif
14646/* note: 'argc' is used only if embedded scripts are enabled */
14647{
14648        volatile smallint state;
14649        struct jmploc jmploc;
14650        struct stackmark smark;
14651        int login_sh;
14652
14653        /* Initialize global data */
14654        INIT_G_misc();
14655        INIT_G_memstack();
14656        INIT_G_var();
14657#if ENABLE_ASH_ALIAS
14658        INIT_G_alias();
14659#endif
14660        INIT_G_cmdtable();
14661
14662#if PROFILE
14663        monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14664#endif
14665
14666        state = 0;
14667        if (setjmp(jmploc.loc)) {
14668                smallint e;
14669                smallint s;
14670
14671                exitreset();
14672
14673                e = exception_type;
14674                s = state;
14675                if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
14676                        exitshell();
14677                }
14678
14679                reset();
14680
14681                if (e == EXINT) {
14682                        newline_and_flush(stderr);
14683                }
14684
14685                popstackmark(&smark);
14686                FORCE_INT_ON; /* enable interrupts */
14687                if (s == 1)
14688                        goto state1;
14689                if (s == 2)
14690                        goto state2;
14691                if (s == 3)
14692                        goto state3;
14693                goto state4;
14694        }
14695        exception_handler = &jmploc;
14696        rootpid = getpid();
14697
14698        init();
14699        setstackmark(&smark);
14700
14701#if NUM_SCRIPTS > 0
14702        if (argc < 0)
14703                /* Non-NULL minusc tells procargs that an embedded script is being run */
14704                minusc = get_script_content(-argc - 1);
14705#endif
14706        login_sh = procargs(argv);
14707#if DEBUG
14708        TRACE(("Shell args: "));
14709        trace_puts_args(argv);
14710#endif
14711
14712        if (login_sh) {
14713                const char *hp;
14714
14715                state = 1;
14716                read_profile("/etc/profile");
14717 state1:
14718                state = 2;
14719                hp = lookupvar("HOME");
14720                if (hp)
14721                        read_profile("$HOME/.profile");
14722        }
14723 state2:
14724        state = 3;
14725        if (iflag
14726#ifndef linux
14727         && getuid() == geteuid() && getgid() == getegid()
14728#endif
14729        ) {
14730                const char *shinit = lookupvar("ENV");
14731                if (shinit != NULL && *shinit != '\0')
14732                        read_profile(shinit);
14733        }
14734        popstackmark(&smark);
14735 state3:
14736        state = 4;
14737        if (minusc) {
14738                /* evalstring pushes parsefile stack.
14739                 * Ensure we don't falsely claim that 0 (stdin)
14740                 * is one of stacked source fds.
14741                 * Testcase: ash -c 'exec 1>&0' must not complain. */
14742
14743                // if (!sflag) g_parsefile->pf_fd = -1;
14744                // ^^ not necessary since now we special-case fd 0
14745                // in save_fd_on_redirect()
14746
14747                lineno = 0; // bash compat
14748                // dash: evalstring(minusc, sflag ? 0 : EV_EXIT);
14749                // The above makes
14750                //  ash -sc 'echo $-'
14751                // continue reading input from stdin after running 'echo'.
14752                // bash does not do this: it prints "hBcs" and exits.
14753                evalstring(minusc, EV_EXIT);
14754        }
14755
14756        if (sflag || minusc == NULL) {
14757#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
14758                if (line_input_state) {
14759                        const char *hp = lookupvar("HISTFILE");
14760                        if (!hp) {
14761                                hp = lookupvar("HOME");
14762                                if (hp) {
14763                                        INT_OFF;
14764                                        hp = concat_path_file(hp, ".ash_history");
14765                                        setvar0("HISTFILE", hp);
14766                                        free((char*)hp);
14767                                        INT_ON;
14768                                        hp = lookupvar("HISTFILE");
14769                                }
14770                        }
14771                        if (hp)
14772                                line_input_state->hist_file = xstrdup(hp);
14773# if ENABLE_FEATURE_SH_HISTFILESIZE
14774                        hp = lookupvar("HISTFILESIZE");
14775                        line_input_state->max_history = size_from_HISTFILESIZE(hp);
14776# endif
14777                }
14778#endif
14779 state4: /* XXX ??? - why isn't this before the "if" statement */
14780                cmdloop(1);
14781        }
14782#if PROFILE
14783        monitor(0);
14784#endif
14785#ifdef GPROF
14786        {
14787                extern void _mcleanup(void);
14788                _mcleanup();
14789        }
14790#endif
14791        TRACE(("End of main reached\n"));
14792        exitshell();
14793        /* NOTREACHED */
14794}
14795
14796
14797/*-
14798 * Copyright (c) 1989, 1991, 1993, 1994
14799 *      The Regents of the University of California.  All rights reserved.
14800 *
14801 * This code is derived from software contributed to Berkeley by
14802 * Kenneth Almquist.
14803 *
14804 * Redistribution and use in source and binary forms, with or without
14805 * modification, are permitted provided that the following conditions
14806 * are met:
14807 * 1. Redistributions of source code must retain the above copyright
14808 *    notice, this list of conditions and the following disclaimer.
14809 * 2. Redistributions in binary form must reproduce the above copyright
14810 *    notice, this list of conditions and the following disclaimer in the
14811 *    documentation and/or other materials provided with the distribution.
14812 * 3. Neither the name of the University nor the names of its contributors
14813 *    may be used to endorse or promote products derived from this software
14814 *    without specific prior written permission.
14815 *
14816 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
14817 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14818 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14819 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14820 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14821 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14822 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14823 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14824 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14825 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14826 * SUCH DAMAGE.
14827 */
14828