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 ASH
  19//config:       bool "ash (78 kb)"
  20//config:       default y
  21//config:       depends on !NOMMU
  22//config:       help
  23//config:       The most complete and most pedantically correct shell included with
  24//config:       busybox. This shell is actually a derivative of the Debian 'dash'
  25//config:       shell (by Herbert Xu), which was created by porting the 'ash' shell
  26//config:       (written by Kenneth Almquist) from NetBSD.
  27//config:
  28//config:# ash options
  29//config:# note: Don't remove !NOMMU part in the next line; it would break
  30//config:# menuconfig's indenting.
  31//config:if !NOMMU && (ASH || SH_IS_ASH || BASH_IS_ASH)
  32//config:
  33//config:config ASH_OPTIMIZE_FOR_SIZE
  34//config:       bool "Optimize for size instead of speed"
  35//config:       default y
  36//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  37//config:
  38//config:config ASH_INTERNAL_GLOB
  39//config:       bool "Use internal glob() implementation"
  40//config:       default y       # Y is bigger, but because of uclibc glob() bug, let Y be default for now
  41//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  42//config:       help
  43//config:       Do not use glob() function from libc, use internal implementation.
  44//config:       Use this if you are getting "glob.h: No such file or directory"
  45//config:       or similar build errors.
  46//config:       Note that as of now (2017-01), uclibc and musl glob() both have bugs
  47//config:       which would break ash if you select N here.
  48//config:
  49//config:config ASH_BASH_COMPAT
  50//config:       bool "bash-compatible extensions"
  51//config:       default y
  52//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  53//config:
  54//config:config ASH_BASH_SOURCE_CURDIR
  55//config:       bool "'source' and '.' builtins search current directory after $PATH"
  56//config:       default n   # do not encourage non-standard behavior
  57//config:       depends on ASH_BASH_COMPAT
  58//config:       help
  59//config:       This is not compliant with standards. Avoid if possible.
  60//config:
  61//config:config ASH_BASH_NOT_FOUND_HOOK
  62//config:       bool "command_not_found_handle hook support"
  63//config:       default y
  64//config:       depends on ASH_BASH_COMPAT
  65//config:       help
  66//config:       Enable support for the 'command_not_found_handle' hook function,
  67//config:       from GNU bash, which allows for alternative command not found
  68//config:       handling.
  69//config:
  70//config:config ASH_JOB_CONTROL
  71//config:       bool "Job control"
  72//config:       default y
  73//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  74//config:
  75//config:config ASH_ALIAS
  76//config:       bool "Alias support"
  77//config:       default y
  78//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  79//config:
  80//config:config ASH_RANDOM_SUPPORT
  81//config:       bool "Pseudorandom generator and $RANDOM variable"
  82//config:       default y
  83//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  84//config:       help
  85//config:       Enable pseudorandom generator and dynamic variable "$RANDOM".
  86//config:       Each read of "$RANDOM" will generate a new pseudorandom value.
  87//config:       You can reset the generator by using a specified start value.
  88//config:       After "unset RANDOM" the generator will switch off and this
  89//config:       variable will no longer have special treatment.
  90//config:
  91//config:config ASH_EXPAND_PRMT
  92//config:       bool "Expand prompt string"
  93//config:       default y
  94//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  95//config:       help
  96//config:       $PS# may contain volatile content, such as backquote commands.
  97//config:       This option recreates the prompt string from the environment
  98//config:       variable each time it is displayed.
  99//config:
 100//config:config ASH_IDLE_TIMEOUT
 101//config:       bool "Idle timeout variable $TMOUT"
 102//config:       default y
 103//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 104//config:       help
 105//config:       Enable bash-like auto-logout after $TMOUT seconds of idle time.
 106//config:
 107//config:config ASH_MAIL
 108//config:       bool "Check for new mail in interactive shell"
 109//config:       default y
 110//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 111//config:       help
 112//config:       Enable "check for new mail" function:
 113//config:       if set, $MAIL file and $MAILPATH list of files
 114//config:       are checked for mtime changes, and "you have mail"
 115//config:       message is printed if change is detected.
 116//config:
 117//config:config ASH_ECHO
 118//config:       bool "echo builtin"
 119//config:       default y
 120//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 121//config:
 122//config:config ASH_PRINTF
 123//config:       bool "printf builtin"
 124//config:       default y
 125//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 126//config:
 127//config:config ASH_TEST
 128//config:       bool "test builtin"
 129//config:       default y
 130//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 131//config:
 132//config:config ASH_HELP
 133//config:       bool "help builtin"
 134//config:       default y
 135//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 136//config:
 137//config:config ASH_GETOPTS
 138//config:       bool "getopts builtin"
 139//config:       default y
 140//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 141//config:
 142//config:config ASH_CMDCMD
 143//config:       bool "command builtin"
 144//config:       default y
 145//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 146//config:       help
 147//config:       Enable support for the 'command' builtin, which allows
 148//config:       you to run the specified command or builtin,
 149//config:       even when there is a function with the same name.
 150//config:
 151//config:endif # ash options
 152
 153//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
 154//                      APPLET_ODDNAME:name  main location    suid_type     help
 155//applet:IF_SH_IS_ASH(  APPLET_ODDNAME(sh,   ash, BB_DIR_BIN, BB_SUID_DROP, ash))
 156//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
 157
 158//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
 159//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
 160//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
 161//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
 162
 163/*
 164 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
 165 * DEBUG=2 to compile in and turn on debugging.
 166 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
 167 * debugging info is written to ./trace, quit signal generates core dump.
 168 */
 169#define DEBUG 0
 170/* Tweak debug output verbosity here */
 171#define DEBUG_TIME 0
 172#define DEBUG_PID 1
 173#define DEBUG_SIG 1
 174#define DEBUG_INTONOFF 0
 175
 176#define PROFILE 0
 177
 178#define JOBS ENABLE_ASH_JOB_CONTROL
 179
 180#include <fnmatch.h>
 181#include <sys/times.h>
 182#include <sys/utsname.h> /* for setting $HOSTNAME */
 183#include "busybox.h" /* for applet_names */
 184#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
 185# include "embedded_scripts.h"
 186#else
 187# define NUM_SCRIPTS 0
 188#endif
 189
 190/* So far, all bash compat is controlled by one config option */
 191/* Separate defines document which part of code implements what */
 192/* function keyword */
 193#define    BASH_FUNCTION        ENABLE_ASH_BASH_COMPAT
 194#define IF_BASH_FUNCTION            IF_ASH_BASH_COMPAT
 195/* &>file */
 196#define    BASH_REDIR_OUTPUT    ENABLE_ASH_BASH_COMPAT
 197#define IF_BASH_REDIR_OUTPUT        IF_ASH_BASH_COMPAT
 198/* $'...' */
 199#define    BASH_DOLLAR_SQUOTE   ENABLE_ASH_BASH_COMPAT
 200#define IF_BASH_DOLLAR_SQUOTE       IF_ASH_BASH_COMPAT
 201#define    BASH_PATTERN_SUBST   ENABLE_ASH_BASH_COMPAT
 202#define IF_BASH_PATTERN_SUBST       IF_ASH_BASH_COMPAT
 203#define    BASH_SUBSTR          ENABLE_ASH_BASH_COMPAT
 204#define IF_BASH_SUBSTR              IF_ASH_BASH_COMPAT
 205/* BASH_TEST2: [[ EXPR ]]
 206 * Status of [[ support:
 207 * We replace && and || with -a and -o
 208 * TODO:
 209 * singleword+noglob expansion:
 210 *   v='a b'; [[ $v = 'a b' ]]; echo 0:$?
 211 *   [[ /bin/n* ]]; echo 0:$?
 212 * -a/-o are not AND/OR ops! (they are just strings)
 213 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
 214 * = is glob match operator, not equality operator: STR = GLOB
 215 * (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
 216 * == same as =
 217 * add =~ regex match operator: STR =~ REGEX
 218 */
 219#define    BASH_TEST2           (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
 220#define    BASH_SOURCE          ENABLE_ASH_BASH_COMPAT
 221#define    BASH_PIPEFAIL        ENABLE_ASH_BASH_COMPAT
 222#define    BASH_HOSTNAME_VAR    ENABLE_ASH_BASH_COMPAT
 223#define    BASH_SHLVL_VAR       ENABLE_ASH_BASH_COMPAT
 224#define    BASH_XTRACEFD        ENABLE_ASH_BASH_COMPAT
 225#define    BASH_READ_D          ENABLE_ASH_BASH_COMPAT
 226#define IF_BASH_READ_D              IF_ASH_BASH_COMPAT
 227
 228#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
 229/* Bionic at least up to version 24 has no glob() */
 230# undef  ENABLE_ASH_INTERNAL_GLOB
 231# define ENABLE_ASH_INTERNAL_GLOB 1
 232#endif
 233
 234#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
 235# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
 236# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
 237# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
 238# error glob() should unbackslash them and match. uClibc does not unbackslash,
 239# error fails to match dirname, subsequently not expanding <pattern> in it.
 240// Testcase:
 241// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
 242// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
 243#endif
 244
 245#if !ENABLE_ASH_INTERNAL_GLOB
 246# include <glob.h>
 247#endif
 248
 249#include "unicode.h"
 250#include "shell_common.h"
 251#if ENABLE_FEATURE_SH_MATH
 252# include "math.h"
 253#else
 254typedef long arith_t;
 255# define ARITH_FMT "%ld"
 256#endif
 257#if ENABLE_ASH_RANDOM_SUPPORT
 258# include "random.h"
 259#else
 260# define CLEAR_RANDOM_T(rnd) ((void)0)
 261#endif
 262
 263#include "NUM_APPLETS.h"
 264#if NUM_APPLETS == 1
 265/* STANDALONE does not make sense, and won't compile */
 266# undef CONFIG_FEATURE_SH_STANDALONE
 267# undef ENABLE_FEATURE_SH_STANDALONE
 268# undef IF_FEATURE_SH_STANDALONE
 269# undef IF_NOT_FEATURE_SH_STANDALONE
 270# define ENABLE_FEATURE_SH_STANDALONE 0
 271# define IF_FEATURE_SH_STANDALONE(...)
 272# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 273#endif
 274
 275#ifndef F_DUPFD_CLOEXEC
 276# define F_DUPFD_CLOEXEC F_DUPFD
 277#endif
 278#ifndef O_CLOEXEC
 279# define O_CLOEXEC 0
 280#endif
 281#ifndef PIPE_BUF
 282# define PIPE_BUF 4096           /* amount of buffering in a pipe */
 283#endif
 284
 285#if !BB_MMU
 286# error "Do not even bother, ash will not run on NOMMU machine"
 287#endif
 288
 289/* We use a trick to have more optimized code (fewer pointer reloads):
 290 *  ash.c:   extern struct globals *const ash_ptr_to_globals;
 291 *  ash_ptr_hack.c: struct globals *ash_ptr_to_globals;
 292 * This way, compiler in ash.c knows the pointer can not change.
 293 *
 294 * However, this may break on weird arches or toolchains. In this case,
 295 * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable
 296 * this optimization.
 297 */
 298#ifndef BB_GLOBAL_CONST
 299# define BB_GLOBAL_CONST const
 300#endif
 301
 302
 303/* ============ Hash table sizes. Configurable. */
 304
 305#define VTABSIZE 39
 306#define ATABSIZE 39
 307#define CMDTABLESIZE 31         /* should be prime */
 308
 309
 310/* ============ Shell options */
 311
 312static const char *const optletters_optnames[] = {
 313        "e"   "errexit",
 314        "f"   "noglob",
 315        "I"   "ignoreeof",
 316        "i"   "interactive",
 317        "m"   "monitor",
 318        "n"   "noexec",
 319        "s"   "stdin",
 320        "x"   "xtrace",
 321        "v"   "verbose",
 322        "C"   "noclobber",
 323        "a"   "allexport",
 324        "b"   "notify",
 325        "u"   "nounset",
 326        "\0"  "vi"
 327#if BASH_PIPEFAIL
 328        ,"\0"  "pipefail"
 329#endif
 330#if DEBUG
 331        ,"\0"  "nolog"
 332        ,"\0"  "debug"
 333#endif
 334};
 335
 336#define optletters(n)  optletters_optnames[n][0]
 337#define optnames(n)   (optletters_optnames[n] + 1)
 338
 339enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
 340
 341
 342/* ============ Misc data */
 343
 344#define msg_illnum "Illegal number: %s"
 345
 346/*
 347 * We enclose jmp_buf in a structure so that we can declare pointers to
 348 * jump locations.  The global variable handler contains the location to
 349 * jump to when an exception occurs, and the global variable exception_type
 350 * contains a code identifying the exception.  To implement nested
 351 * exception handlers, the user should save the value of handler on entry
 352 * to an inner scope, set handler to point to a jmploc structure for the
 353 * inner scope, and restore handler on exit from the scope.
 354 */
 355struct jmploc {
 356        jmp_buf loc;
 357};
 358
 359struct globals_misc {
 360        uint8_t exitstatus;     /* exit status of last command */
 361        uint8_t back_exitstatus;/* exit status of backquoted command */
 362        smallint job_warning;   /* user was warned about stopped jobs (can be 2, 1 or 0). */
 363        int rootpid;            /* pid of main shell */
 364        /* shell level: 0 for the main shell, 1 for its children, and so on */
 365        int shlvl;
 366#define rootshell (!shlvl)
 367        int errlinno;
 368
 369        char *minusc;  /* argument to -c option */
 370
 371        char *curdir; // = nullstr;     /* current working directory */
 372        char *physdir; // = nullstr;    /* physical working directory */
 373
 374        char *arg0; /* value of $0 */
 375
 376        struct jmploc *exception_handler;
 377
 378        volatile int suppress_int; /* counter */
 379        volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
 380        volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
 381        volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
 382        smallint exception_type; /* kind of exception (0..5) */
 383        /* exceptions */
 384#define EXINT 0         /* SIGINT received */
 385#define EXERROR 1       /* a generic error */
 386#define EXEXIT 4        /* exit the shell */
 387
 388        char nullstr[1];        /* zero length string */
 389
 390        char optlist[NOPTS];
 391#define eflag optlist[0]
 392#define fflag optlist[1]
 393#define Iflag optlist[2]
 394#define iflag optlist[3]
 395#define mflag optlist[4]
 396#define nflag optlist[5]
 397#define sflag optlist[6]
 398#define xflag optlist[7]
 399#define vflag optlist[8]
 400#define Cflag optlist[9]
 401#define aflag optlist[10]
 402#define bflag optlist[11]
 403#define uflag optlist[12]
 404#define viflag optlist[13]
 405#if BASH_PIPEFAIL
 406# define pipefail optlist[14]
 407#else
 408# define pipefail 0
 409#endif
 410#if DEBUG
 411# define nolog optlist[14 + BASH_PIPEFAIL]
 412# define debug optlist[15 + BASH_PIPEFAIL]
 413#endif
 414
 415        /* trap handler commands */
 416        /*
 417         * Sigmode records the current value of the signal handlers for the various
 418         * modes.  A value of zero means that the current handler is not known.
 419         * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
 420         */
 421        char sigmode[NSIG - 1];
 422#define S_DFL      1            /* default signal handling (SIG_DFL) */
 423#define S_CATCH    2            /* signal is caught */
 424#define S_IGN      3            /* signal is ignored (SIG_IGN) */
 425#define S_HARD_IGN 4            /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
 426
 427        /* indicates specified signal received */
 428        uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
 429        uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
 430        char *trap[NSIG];
 431        char **trap_ptr;        /* used only by "trap hack" */
 432
 433        /* Rarely referenced stuff */
 434#if ENABLE_ASH_RANDOM_SUPPORT
 435        random_t random_gen;
 436#endif
 437        pid_t backgndpid;        /* pid of last background process */
 438};
 439extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
 440#define G_misc (*ash_ptr_to_globals_misc)
 441#define exitstatus        (G_misc.exitstatus )
 442#define back_exitstatus   (G_misc.back_exitstatus )
 443#define job_warning       (G_misc.job_warning)
 444#define rootpid     (G_misc.rootpid    )
 445#define shlvl       (G_misc.shlvl      )
 446#define errlinno    (G_misc.errlinno   )
 447#define minusc      (G_misc.minusc     )
 448#define curdir      (G_misc.curdir     )
 449#define physdir     (G_misc.physdir    )
 450#define arg0        (G_misc.arg0       )
 451#define exception_handler (G_misc.exception_handler)
 452#define exception_type    (G_misc.exception_type   )
 453#define suppress_int      (G_misc.suppress_int     )
 454#define pending_int       (G_misc.pending_int      )
 455#define got_sigchld       (G_misc.got_sigchld      )
 456#define pending_sig       (G_misc.pending_sig      )
 457#define nullstr     (G_misc.nullstr    )
 458#define optlist     (G_misc.optlist    )
 459#define sigmode     (G_misc.sigmode    )
 460#define gotsig      (G_misc.gotsig     )
 461#define may_have_traps    (G_misc.may_have_traps   )
 462#define trap        (G_misc.trap       )
 463#define trap_ptr    (G_misc.trap_ptr   )
 464#define random_gen  (G_misc.random_gen )
 465#define backgndpid  (G_misc.backgndpid )
 466#define INIT_G_misc() do { \
 467        (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
 468        barrier(); \
 469        curdir = nullstr; \
 470        physdir = nullstr; \
 471        trap_ptr = trap; \
 472} while (0)
 473
 474
 475/* ============ DEBUG */
 476#if DEBUG
 477static void trace_printf(const char *fmt, ...);
 478static void trace_vprintf(const char *fmt, va_list va);
 479# define TRACE(param)    trace_printf param
 480# define TRACEV(param)   trace_vprintf param
 481# define close(fd) do { \
 482        int dfd = (fd); \
 483        if (close(dfd) < 0) \
 484                bb_error_msg("bug on %d: closing %d(0x%x)", \
 485                        __LINE__, dfd, dfd); \
 486} while (0)
 487#else
 488# define TRACE(param)
 489# define TRACEV(param)
 490#endif
 491
 492
 493/* ============ Utility functions */
 494#define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
 495#define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
 496
 497static int
 498isdigit_str9(const char *str)
 499{
 500        int maxlen = 9 + 1; /* max 9 digits: 999999999 */
 501        while (--maxlen && isdigit(*str))
 502                str++;
 503        return (*str == '\0');
 504}
 505
 506static const char *
 507var_end(const char *var)
 508{
 509        while (*var)
 510                if (*var++ == '=')
 511                        break;
 512        return var;
 513}
 514
 515
 516/* ============ Interrupts / exceptions */
 517
 518static void exitshell(void) NORETURN;
 519
 520/*
 521 * These macros allow the user to suspend the handling of interrupt signals
 522 * over a period of time.  This is similar to SIGHOLD or to sigblock, but
 523 * much more efficient and portable.  (But hacking the kernel is so much
 524 * more fun than worrying about efficiency and portability. :-))
 525 */
 526#if DEBUG_INTONOFF
 527# define INT_OFF do { \
 528        TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
 529        suppress_int++; \
 530        barrier(); \
 531} while (0)
 532#else
 533# define INT_OFF do { \
 534        suppress_int++; \
 535        barrier(); \
 536} while (0)
 537#endif
 538
 539/*
 540 * Called to raise an exception.  Since C doesn't include exceptions, we
 541 * just do a longjmp to the exception handler.  The type of exception is
 542 * stored in the global variable "exception_type".
 543 */
 544static void raise_exception(int) NORETURN;
 545static void
 546raise_exception(int e)
 547{
 548#if DEBUG
 549        if (exception_handler == NULL)
 550                abort();
 551#endif
 552        INT_OFF;
 553        exception_type = e;
 554        longjmp(exception_handler->loc, 1);
 555}
 556#if DEBUG
 557#define raise_exception(e) do { \
 558        TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
 559        raise_exception(e); \
 560} while (0)
 561#endif
 562
 563/*
 564 * Called when a SIGINT is received.  (If the user specifies
 565 * that SIGINT is to be trapped or ignored using the trap builtin, then
 566 * this routine is not called.)  Suppressint is nonzero when interrupts
 567 * are held using the INT_OFF macro.  (The test for iflag is just
 568 * defensive programming.)
 569 */
 570static void raise_interrupt(void) NORETURN;
 571static void
 572raise_interrupt(void)
 573{
 574        pending_int = 0;
 575        /* Signal is not automatically unmasked after it is raised,
 576         * do it ourself - unmask all signals */
 577        sigprocmask_allsigs(SIG_UNBLOCK);
 578        /* pending_sig = 0; - now done in signal_handler() */
 579
 580        if (!(rootshell && iflag)) {
 581                /* Kill ourself with SIGINT */
 582                signal(SIGINT, SIG_DFL);
 583                raise(SIGINT);
 584        }
 585        /* bash: ^C even on empty command line sets $? */
 586        exitstatus = SIGINT + 128;
 587        raise_exception(EXINT);
 588        /* NOTREACHED */
 589}
 590#if DEBUG
 591#define raise_interrupt() do { \
 592        TRACE(("raising interrupt on line %d\n", __LINE__)); \
 593        raise_interrupt(); \
 594} while (0)
 595#endif
 596
 597static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 598int_on(void)
 599{
 600        barrier();
 601        if (--suppress_int == 0 && pending_int) {
 602                raise_interrupt();
 603        }
 604}
 605#if DEBUG_INTONOFF
 606# define INT_ON do { \
 607        TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
 608        int_on(); \
 609} while (0)
 610#else
 611# define INT_ON int_on()
 612#endif
 613static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 614force_int_on(void)
 615{
 616        barrier();
 617        suppress_int = 0;
 618        if (pending_int)
 619                raise_interrupt();
 620}
 621#define FORCE_INT_ON force_int_on()
 622
 623#define SAVE_INT(v) ((v) = suppress_int)
 624
 625#define RESTORE_INT(v) do { \
 626        barrier(); \
 627        suppress_int = (v); \
 628        if (suppress_int == 0 && pending_int) \
 629                raise_interrupt(); \
 630} while (0)
 631
 632
 633/* ============ Stdout/stderr output */
 634
 635static void
 636outstr(const char *p, FILE *file)
 637{
 638        INT_OFF;
 639        fputs(p, file);
 640        INT_ON;
 641}
 642
 643static void
 644flush_stdout_stderr(void)
 645{
 646        INT_OFF;
 647        fflush_all();
 648        INT_ON;
 649}
 650
 651/* Was called outcslow(c,FILE*), but c was always '\n' */
 652static void
 653newline_and_flush(FILE *dest)
 654{
 655        INT_OFF;
 656        putc('\n', dest);
 657        fflush(dest);
 658        INT_ON;
 659}
 660
 661static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
 662static int
 663out1fmt(const char *fmt, ...)
 664{
 665        va_list ap;
 666        int r;
 667
 668        INT_OFF;
 669        va_start(ap, fmt);
 670        r = vprintf(fmt, ap);
 671        va_end(ap);
 672        INT_ON;
 673        return r;
 674}
 675
 676static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
 677static int
 678fmtstr(char *outbuf, size_t length, const char *fmt, ...)
 679{
 680        va_list ap;
 681        int ret;
 682
 683        INT_OFF;
 684        va_start(ap, fmt);
 685        ret = vsnprintf(outbuf, length, fmt, ap);
 686        va_end(ap);
 687        INT_ON;
 688        return ret;
 689}
 690
 691static void
 692out1str(const char *p)
 693{
 694        outstr(p, stdout);
 695}
 696
 697static void
 698out2str(const char *p)
 699{
 700        outstr(p, stderr);
 701        flush_stdout_stderr();
 702}
 703
 704
 705/* ============ Parser structures */
 706
 707/* control characters in argument strings */
 708#define CTL_FIRST CTLESC
 709#define CTLESC       ((unsigned char)'\201')    /* escape next character */
 710#define CTLVAR       ((unsigned char)'\202')    /* variable defn */
 711#define CTLENDVAR    ((unsigned char)'\203')
 712#define CTLBACKQ     ((unsigned char)'\204')
 713#define CTLARI       ((unsigned char)'\206')    /* arithmetic expression */
 714#define CTLENDARI    ((unsigned char)'\207')
 715#define CTLQUOTEMARK ((unsigned char)'\210')
 716#define CTL_LAST CTLQUOTEMARK
 717
 718/* variable substitution byte (follows CTLVAR) */
 719#define VSTYPE  0x0f            /* type of variable substitution */
 720#define VSNUL   0x10            /* colon--treat the empty string as unset */
 721
 722/* values of VSTYPE field */
 723#define VSNORMAL        0x1     /* normal variable:  $var or ${var} */
 724#define VSMINUS         0x2     /* ${var-text} */
 725#define VSPLUS          0x3     /* ${var+text} */
 726#define VSQUESTION      0x4     /* ${var?message} */
 727#define VSASSIGN        0x5     /* ${var=text} */
 728#define VSTRIMRIGHT     0x6     /* ${var%pattern} */
 729#define VSTRIMRIGHTMAX  0x7     /* ${var%%pattern} */
 730#define VSTRIMLEFT      0x8     /* ${var#pattern} */
 731#define VSTRIMLEFTMAX   0x9     /* ${var##pattern} */
 732#define VSLENGTH        0xa     /* ${#var} */
 733#if BASH_SUBSTR
 734#define VSSUBSTR        0xc     /* ${var:position:length} */
 735#endif
 736#if BASH_PATTERN_SUBST
 737#define VSREPLACE       0xd     /* ${var/pattern/replacement} */
 738#define VSREPLACEALL    0xe     /* ${var//pattern/replacement} */
 739#endif
 740
 741static const char dolatstr[] ALIGN1 = {
 742        CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
 743};
 744#define DOLATSTRLEN 6
 745
 746#define NCMD      0
 747#define NPIPE     1
 748#define NREDIR    2
 749#define NBACKGND  3
 750#define NSUBSHELL 4
 751#define NAND      5
 752#define NOR       6
 753#define NSEMI     7
 754#define NIF       8
 755#define NWHILE    9
 756#define NUNTIL   10
 757#define NFOR     11
 758#define NCASE    12
 759#define NCLIST   13
 760#define NDEFUN   14
 761#define NARG     15
 762#define NTO      16
 763#if BASH_REDIR_OUTPUT
 764#define NTO2     17
 765#endif
 766#define NCLOBBER 18
 767#define NFROM    19
 768#define NFROMTO  20
 769#define NAPPEND  21
 770#define NTOFD    22
 771#define NFROMFD  23
 772#define NHERE    24
 773#define NXHERE   25
 774#define NNOT     26
 775#define N_NUMBER 27
 776
 777union node;
 778
 779struct ncmd {
 780        smallint type; /* Nxxxx */
 781        int linno;
 782        union node *assign;
 783        union node *args;
 784        union node *redirect;
 785};
 786
 787struct npipe {
 788        smallint type;
 789        smallint pipe_backgnd;
 790        struct nodelist *cmdlist;
 791};
 792
 793struct nredir {
 794        smallint type;
 795        int linno;
 796        union node *n;
 797        union node *redirect;
 798};
 799
 800struct nbinary {
 801        smallint type;
 802        union node *ch1;
 803        union node *ch2;
 804};
 805
 806struct nif {
 807        smallint type;
 808        union node *test;
 809        union node *ifpart;
 810        union node *elsepart;
 811};
 812
 813struct nfor {
 814        smallint type;
 815        int linno;
 816        union node *args;
 817        union node *body;
 818        char *var;
 819};
 820
 821struct ncase {
 822        smallint type;
 823        int linno;
 824        union node *expr;
 825        union node *cases;
 826};
 827
 828struct nclist {
 829        smallint type;
 830        union node *next;
 831        union node *pattern;
 832        union node *body;
 833};
 834
 835struct ndefun {
 836        smallint type;
 837        int linno;
 838        char *text;
 839        union node *body;
 840};
 841
 842struct narg {
 843        smallint type;
 844        union node *next;
 845        char *text;
 846        struct nodelist *backquote;
 847};
 848
 849/* nfile and ndup layout must match!
 850 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
 851 * that it is actually NTO2 (>&file), and change its type.
 852 */
 853struct nfile {
 854        smallint type;
 855        union node *next;
 856        int fd;
 857        int _unused_dupfd;
 858        union node *fname;
 859        char *expfname;
 860};
 861
 862struct ndup {
 863        smallint type;
 864        union node *next;
 865        int fd;
 866        int dupfd;
 867        union node *vname;
 868        char *_unused_expfname;
 869};
 870
 871struct nhere {
 872        smallint type;
 873        union node *next;
 874        int fd;
 875        union node *doc;
 876};
 877
 878struct nnot {
 879        smallint type;
 880        union node *com;
 881};
 882
 883union node {
 884        smallint type;
 885        struct ncmd ncmd;
 886        struct npipe npipe;
 887        struct nredir nredir;
 888        struct nbinary nbinary;
 889        struct nif nif;
 890        struct nfor nfor;
 891        struct ncase ncase;
 892        struct nclist nclist;
 893        struct ndefun ndefun;
 894        struct narg narg;
 895        struct nfile nfile;
 896        struct ndup ndup;
 897        struct nhere nhere;
 898        struct nnot nnot;
 899};
 900
 901/*
 902 * NODE_EOF is returned by parsecmd when it encounters an end of file.
 903 * It must be distinct from NULL.
 904 */
 905#define NODE_EOF ((union node *) -1L)
 906
 907struct nodelist {
 908        struct nodelist *next;
 909        union node *n;
 910};
 911
 912struct funcnode {
 913        int count;
 914        union node n;
 915};
 916
 917/*
 918 * Free a parse tree.
 919 */
 920static void
 921freefunc(struct funcnode *f)
 922{
 923        if (f && --f->count < 0)
 924                free(f);
 925}
 926
 927
 928/* ============ Debugging output */
 929
 930#if DEBUG
 931
 932static FILE *tracefile;
 933
 934static void
 935trace_printf(const char *fmt, ...)
 936{
 937        va_list va;
 938
 939        if (debug != 1)
 940                return;
 941        if (DEBUG_TIME)
 942                fprintf(tracefile, "%u ", (int) time(NULL));
 943        if (DEBUG_PID)
 944                fprintf(tracefile, "[%u] ", (int) getpid());
 945        if (DEBUG_SIG)
 946                fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
 947        va_start(va, fmt);
 948        vfprintf(tracefile, fmt, va);
 949        va_end(va);
 950}
 951
 952static void
 953trace_vprintf(const char *fmt, va_list va)
 954{
 955        if (debug != 1)
 956                return;
 957        vfprintf(tracefile, fmt, va);
 958        fprintf(tracefile, "\n");
 959}
 960
 961static void
 962trace_puts(const char *s)
 963{
 964        if (debug != 1)
 965                return;
 966        fputs(s, tracefile);
 967}
 968
 969static void
 970trace_puts_quoted(char *s)
 971{
 972        char *p;
 973        char c;
 974
 975        if (debug != 1)
 976                return;
 977        putc('"', tracefile);
 978        for (p = s; *p; p++) {
 979                switch ((unsigned char)*p) {
 980                case '\n': c = 'n'; goto backslash;
 981                case '\t': c = 't'; goto backslash;
 982                case '\r': c = 'r'; goto backslash;
 983                case '\"': c = '\"'; goto backslash;
 984                case '\\': c = '\\'; goto backslash;
 985                case CTLESC: c = 'e'; goto backslash;
 986                case CTLVAR: c = 'v'; goto backslash;
 987                case CTLBACKQ: c = 'q'; goto backslash;
 988 backslash:
 989                        putc('\\', tracefile);
 990                        putc(c, tracefile);
 991                        break;
 992                default:
 993                        if (*p >= ' ' && *p <= '~')
 994                                putc(*p, tracefile);
 995                        else {
 996                                putc('\\', tracefile);
 997                                putc((*p >> 6) & 03, tracefile);
 998                                putc((*p >> 3) & 07, tracefile);
 999                                putc(*p & 07, tracefile);
1000                        }
1001                        break;
1002                }
1003        }
1004        putc('"', tracefile);
1005}
1006
1007static void
1008trace_puts_args(char **ap)
1009{
1010        if (debug != 1)
1011                return;
1012        if (!*ap)
1013                return;
1014        while (1) {
1015                trace_puts_quoted(*ap);
1016                if (!*++ap) {
1017                        putc('\n', tracefile);
1018                        break;
1019                }
1020                putc(' ', tracefile);
1021        }
1022}
1023
1024static void
1025opentrace(void)
1026{
1027        char s[100];
1028#ifdef O_APPEND
1029        int flags;
1030#endif
1031
1032        if (debug != 1) {
1033                if (tracefile)
1034                        fflush(tracefile);
1035                /* leave open because libedit might be using it */
1036                return;
1037        }
1038        strcpy(s, "./trace");
1039        if (tracefile) {
1040                if (!freopen(s, "a", tracefile)) {
1041                        fprintf(stderr, "Can't re-open %s\n", s);
1042                        debug = 0;
1043                        return;
1044                }
1045        } else {
1046                tracefile = fopen(s, "a");
1047                if (tracefile == NULL) {
1048                        fprintf(stderr, "Can't open %s\n", s);
1049                        debug = 0;
1050                        return;
1051                }
1052        }
1053#ifdef O_APPEND
1054        flags = fcntl(fileno(tracefile), F_GETFL);
1055        if (flags >= 0)
1056                fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1057#endif
1058        setlinebuf(tracefile);
1059        fputs("\nTracing started.\n", tracefile);
1060}
1061
1062static void
1063indent(int amount, char *pfx, FILE *fp)
1064{
1065        int i;
1066
1067        for (i = 0; i < amount; i++) {
1068                if (pfx && i == amount - 1)
1069                        fputs(pfx, fp);
1070                putc('\t', fp);
1071        }
1072}
1073
1074/* little circular references here... */
1075static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1076
1077static void
1078sharg(union node *arg, FILE *fp)
1079{
1080        char *p;
1081        struct nodelist *bqlist;
1082        unsigned char subtype;
1083
1084        if (arg->type != NARG) {
1085                out1fmt("<node type %d>\n", arg->type);
1086                abort();
1087        }
1088        bqlist = arg->narg.backquote;
1089        for (p = arg->narg.text; *p; p++) {
1090                switch ((unsigned char)*p) {
1091                case CTLESC:
1092                        p++;
1093                        putc(*p, fp);
1094                        break;
1095                case CTLVAR:
1096                        putc('$', fp);
1097                        putc('{', fp);
1098                        subtype = *++p;
1099                        if (subtype == VSLENGTH)
1100                                putc('#', fp);
1101
1102                        while (*p != '=') {
1103                                putc(*p, fp);
1104                                p++;
1105                        }
1106
1107                        if (subtype & VSNUL)
1108                                putc(':', fp);
1109
1110                        switch (subtype & VSTYPE) {
1111                        case VSNORMAL:
1112                                putc('}', fp);
1113                                break;
1114                        case VSMINUS:
1115                                putc('-', fp);
1116                                break;
1117                        case VSPLUS:
1118                                putc('+', fp);
1119                                break;
1120                        case VSQUESTION:
1121                                putc('?', fp);
1122                                break;
1123                        case VSASSIGN:
1124                                putc('=', fp);
1125                                break;
1126                        case VSTRIMLEFT:
1127                                putc('#', fp);
1128                                break;
1129                        case VSTRIMLEFTMAX:
1130                                putc('#', fp);
1131                                putc('#', fp);
1132                                break;
1133                        case VSTRIMRIGHT:
1134                                putc('%', fp);
1135                                break;
1136                        case VSTRIMRIGHTMAX:
1137                                putc('%', fp);
1138                                putc('%', fp);
1139                                break;
1140                        case VSLENGTH:
1141                                break;
1142                        default:
1143                                out1fmt("<subtype %d>", subtype);
1144                        }
1145                        break;
1146                case CTLENDVAR:
1147                        putc('}', fp);
1148                        break;
1149                case CTLBACKQ:
1150                        putc('$', fp);
1151                        putc('(', fp);
1152                        shtree(bqlist->n, -1, NULL, fp);
1153                        putc(')', fp);
1154                        break;
1155                default:
1156                        putc(*p, fp);
1157                        break;
1158                }
1159        }
1160}
1161
1162static void
1163shcmd(union node *cmd, FILE *fp)
1164{
1165        union node *np;
1166        int first;
1167        const char *s;
1168        int dftfd;
1169
1170        first = 1;
1171        for (np = cmd->ncmd.args; np; np = np->narg.next) {
1172                if (!first)
1173                        putc(' ', fp);
1174                sharg(np, fp);
1175                first = 0;
1176        }
1177        for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1178                if (!first)
1179                        putc(' ', fp);
1180                dftfd = 0;
1181                switch (np->nfile.type) {
1182                case NTO:      s = ">>"+1; dftfd = 1; break;
1183                case NCLOBBER: s = ">|"; dftfd = 1; break;
1184                case NAPPEND:  s = ">>"; dftfd = 1; break;
1185#if BASH_REDIR_OUTPUT
1186                case NTO2:
1187#endif
1188                case NTOFD:    s = ">&"; dftfd = 1; break;
1189                case NFROM:    s = "<"; break;
1190                case NFROMFD:  s = "<&"; break;
1191                case NFROMTO:  s = "<>"; break;
1192                default:       s = "*error*"; break;
1193                }
1194                if (np->nfile.fd != dftfd)
1195                        fprintf(fp, "%d", np->nfile.fd);
1196                fputs(s, fp);
1197                if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1198                        fprintf(fp, "%d", np->ndup.dupfd);
1199                } else {
1200                        sharg(np->nfile.fname, fp);
1201                }
1202                first = 0;
1203        }
1204}
1205
1206static void
1207shtree(union node *n, int ind, char *pfx, FILE *fp)
1208{
1209        struct nodelist *lp;
1210        const char *s;
1211
1212        if (n == NULL)
1213                return;
1214
1215        indent(ind, pfx, fp);
1216
1217        if (n == NODE_EOF) {
1218                fputs("<EOF>", fp);
1219                return;
1220        }
1221
1222        switch (n->type) {
1223        case NSEMI:
1224                s = "; ";
1225                goto binop;
1226        case NAND:
1227                s = " && ";
1228                goto binop;
1229        case NOR:
1230                s = " || ";
1231 binop:
1232                shtree(n->nbinary.ch1, ind, NULL, fp);
1233                /* if (ind < 0) */
1234                        fputs(s, fp);
1235                shtree(n->nbinary.ch2, ind, NULL, fp);
1236                break;
1237        case NCMD:
1238                shcmd(n, fp);
1239                if (ind >= 0)
1240                        putc('\n', fp);
1241                break;
1242        case NPIPE:
1243                for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1244                        shtree(lp->n, 0, NULL, fp);
1245                        if (lp->next)
1246                                fputs(" | ", fp);
1247                }
1248                if (n->npipe.pipe_backgnd)
1249                        fputs(" &", fp);
1250                if (ind >= 0)
1251                        putc('\n', fp);
1252                break;
1253        default:
1254                fprintf(fp, "<node type %d>", n->type);
1255                if (ind >= 0)
1256                        putc('\n', fp);
1257                break;
1258        }
1259}
1260
1261static void
1262showtree(union node *n)
1263{
1264        trace_puts("showtree called\n");
1265        shtree(n, 1, NULL, stderr);
1266}
1267
1268#endif /* DEBUG */
1269
1270
1271/* ============ Parser data */
1272
1273/*
1274 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1275 */
1276struct strlist {
1277        struct strlist *next;
1278        char *text;
1279};
1280
1281struct alias;
1282
1283struct strpush {
1284        struct strpush *prev;   /* preceding string on stack */
1285        char *prev_string;
1286        int prev_left_in_line;
1287#if ENABLE_ASH_ALIAS
1288        struct alias *ap;       /* if push was associated with an alias */
1289#endif
1290        char *string;           /* remember the string since it may change */
1291
1292        /* Remember last two characters for pungetc. */
1293        int lastc[2];
1294
1295        /* Number of outstanding calls to pungetc. */
1296        int unget;
1297};
1298
1299/*
1300 * The parsefile structure pointed to by the global variable parsefile
1301 * contains information about the current file being read.
1302 */
1303struct parsefile {
1304        struct parsefile *prev; /* preceding file on stack */
1305        int linno;              /* current line */
1306        int pf_fd;              /* file descriptor (or -1 if string) */
1307        int left_in_line;       /* number of chars left in this line */
1308        int left_in_buffer;     /* number of chars left in this buffer past the line */
1309        char *next_to_pgetc;    /* next char in buffer */
1310        char *buf;              /* input buffer */
1311        struct strpush *strpush; /* for pushing strings at this level */
1312        struct strpush basestrpush; /* so pushing one is fast */
1313
1314        /* Remember last two characters for pungetc. */
1315        int lastc[2];
1316
1317        /* Number of outstanding calls to pungetc. */
1318        int unget;
1319};
1320
1321static struct parsefile basepf;        /* top level input file */
1322static struct parsefile *g_parsefile = &basepf;  /* current input file */
1323static char *commandname;              /* currently executing command */
1324
1325
1326/* ============ Message printing */
1327
1328static void
1329ash_vmsg(const char *msg, va_list ap)
1330{
1331        fprintf(stderr, "%s: ", arg0);
1332        if (commandname) {
1333                if (strcmp(arg0, commandname))
1334                        fprintf(stderr, "%s: ", commandname);
1335                if (!iflag || g_parsefile->pf_fd > 0)
1336                        fprintf(stderr, "line %d: ", errlinno);
1337        }
1338        vfprintf(stderr, msg, ap);
1339        newline_and_flush(stderr);
1340}
1341
1342/*
1343 * Exverror is called to raise the error exception.  If the second argument
1344 * is not NULL then error prints an error message using printf style
1345 * formatting.  It then raises the error exception.
1346 */
1347static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1348static void
1349ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1350{
1351#if DEBUG
1352        if (msg) {
1353                TRACE(("ash_vmsg_and_raise(%d):", cond));
1354                TRACEV((msg, ap));
1355        } else
1356                TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1357        if (msg)
1358#endif
1359                ash_vmsg(msg, ap);
1360
1361        flush_stdout_stderr();
1362        raise_exception(cond);
1363        /* NOTREACHED */
1364}
1365
1366static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1367static void
1368ash_msg_and_raise_error(const char *msg, ...)
1369{
1370        va_list ap;
1371
1372        exitstatus = 2;
1373
1374        va_start(ap, msg);
1375        ash_vmsg_and_raise(EXERROR, msg, ap);
1376        /* NOTREACHED */
1377        va_end(ap);
1378}
1379
1380/*
1381 * 'fmt' must be a string literal.
1382 */
1383#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
1384
1385static void raise_error_syntax(const char *) NORETURN;
1386static void
1387raise_error_syntax(const char *msg)
1388{
1389        errlinno = g_parsefile->linno;
1390        ash_msg_and_raise_error("syntax error: %s", msg);
1391        /* NOTREACHED */
1392}
1393
1394static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1395static void
1396ash_msg_and_raise(int cond, const char *msg, ...)
1397{
1398        va_list ap;
1399
1400        va_start(ap, msg);
1401        ash_vmsg_and_raise(cond, msg, ap);
1402        /* NOTREACHED */
1403        va_end(ap);
1404}
1405
1406/*
1407 * error/warning routines for external builtins
1408 */
1409static void
1410ash_msg(const char *fmt, ...)
1411{
1412        va_list ap;
1413
1414        va_start(ap, fmt);
1415        ash_vmsg(fmt, ap);
1416        va_end(ap);
1417}
1418
1419/*
1420 * Return a string describing an error.  The returned string may be a
1421 * pointer to a static buffer that will be overwritten on the next call.
1422 * Action describes the operation that got the error.
1423 */
1424static const char *
1425errmsg(int e, const char *em)
1426{
1427        if (e == ENOENT || e == ENOTDIR) {
1428                return em;
1429        }
1430        return strerror(e);
1431}
1432
1433
1434/* ============ Memory allocation */
1435
1436#if 0
1437/* I consider these wrappers nearly useless:
1438 * ok, they return you to nearest exception handler, but
1439 * how much memory do you leak in the process, making
1440 * memory starvation worse?
1441 */
1442static void *
1443ckrealloc(void * p, size_t nbytes)
1444{
1445        p = realloc(p, nbytes);
1446        if (!p)
1447                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1448        return p;
1449}
1450
1451static void *
1452ckmalloc(size_t nbytes)
1453{
1454        return ckrealloc(NULL, nbytes);
1455}
1456
1457static void *
1458ckzalloc(size_t nbytes)
1459{
1460        return memset(ckmalloc(nbytes), 0, nbytes);
1461}
1462
1463static char *
1464ckstrdup(const char *s)
1465{
1466        char *p = strdup(s);
1467        if (!p)
1468                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1469        return p;
1470}
1471#else
1472/* Using bbox equivalents. They exit if out of memory */
1473# define ckrealloc xrealloc
1474# define ckmalloc  xmalloc
1475# define ckzalloc  xzalloc
1476# define ckstrdup  xstrdup
1477#endif
1478
1479/*
1480 * It appears that grabstackstr() will barf with such alignments
1481 * because stalloc() will return a string allocated in a new stackblock.
1482 */
1483#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1484enum {
1485        /* Most machines require the value returned from malloc to be aligned
1486         * in some way.  The following macro will get this right
1487         * on many machines.  */
1488        SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1489        /* Minimum size of a block */
1490        MINSIZE = SHELL_ALIGN(504),
1491};
1492
1493struct stack_block {
1494        struct stack_block *prev;
1495        char space[MINSIZE];
1496};
1497
1498struct stackmark {
1499        struct stack_block *stackp;
1500        char *stacknxt;
1501        size_t stacknleft;
1502};
1503
1504
1505struct globals_memstack {
1506        struct stack_block *g_stackp; // = &stackbase;
1507        char *g_stacknxt; // = stackbase.space;
1508        char *sstrend; // = stackbase.space + MINSIZE;
1509        size_t g_stacknleft; // = MINSIZE;
1510        struct stack_block stackbase;
1511};
1512extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1513#define G_memstack (*ash_ptr_to_globals_memstack)
1514#define g_stackp     (G_memstack.g_stackp    )
1515#define g_stacknxt   (G_memstack.g_stacknxt  )
1516#define sstrend      (G_memstack.sstrend     )
1517#define g_stacknleft (G_memstack.g_stacknleft)
1518#define stackbase    (G_memstack.stackbase   )
1519#define INIT_G_memstack() do { \
1520        (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1521        barrier(); \
1522        g_stackp = &stackbase; \
1523        g_stacknxt = stackbase.space; \
1524        g_stacknleft = MINSIZE; \
1525        sstrend = stackbase.space + MINSIZE; \
1526} while (0)
1527
1528
1529#define stackblock()     ((void *)g_stacknxt)
1530#define stackblocksize() g_stacknleft
1531
1532/*
1533 * Parse trees for commands are allocated in lifo order, so we use a stack
1534 * to make this more efficient, and also to avoid all sorts of exception
1535 * handling code to handle interrupts in the middle of a parse.
1536 *
1537 * The size 504 was chosen because the Ultrix malloc handles that size
1538 * well.
1539 */
1540static void *
1541stalloc(size_t nbytes)
1542{
1543        char *p;
1544        size_t aligned;
1545
1546        aligned = SHELL_ALIGN(nbytes);
1547        if (aligned > g_stacknleft) {
1548                size_t len;
1549                size_t blocksize;
1550                struct stack_block *sp;
1551
1552                blocksize = aligned;
1553                if (blocksize < MINSIZE)
1554                        blocksize = MINSIZE;
1555                len = sizeof(struct stack_block) - MINSIZE + blocksize;
1556                if (len < blocksize)
1557                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
1558                INT_OFF;
1559                sp = ckmalloc(len);
1560                sp->prev = g_stackp;
1561                g_stacknxt = sp->space;
1562                g_stacknleft = blocksize;
1563                sstrend = g_stacknxt + blocksize;
1564                g_stackp = sp;
1565                INT_ON;
1566        }
1567        p = g_stacknxt;
1568        g_stacknxt += aligned;
1569        g_stacknleft -= aligned;
1570        return p;
1571}
1572
1573static void *
1574stzalloc(size_t nbytes)
1575{
1576        return memset(stalloc(nbytes), 0, nbytes);
1577}
1578
1579static void
1580stunalloc(void *p)
1581{
1582#if DEBUG
1583        if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1584                write(STDERR_FILENO, "stunalloc\n", 10);
1585                abort();
1586        }
1587#endif
1588        g_stacknleft += g_stacknxt - (char *)p;
1589        g_stacknxt = p;
1590}
1591
1592/*
1593 * Like strdup but works with the ash stack.
1594 */
1595static char *
1596sstrdup(const char *p)
1597{
1598        size_t len = strlen(p) + 1;
1599        return memcpy(stalloc(len), p, len);
1600}
1601
1602static ALWAYS_INLINE void
1603grabstackblock(size_t len)
1604{
1605        stalloc(len);
1606}
1607
1608static void
1609pushstackmark(struct stackmark *mark, size_t len)
1610{
1611        mark->stackp = g_stackp;
1612        mark->stacknxt = g_stacknxt;
1613        mark->stacknleft = g_stacknleft;
1614        grabstackblock(len);
1615}
1616
1617static void
1618setstackmark(struct stackmark *mark)
1619{
1620        pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1621}
1622
1623static void
1624popstackmark(struct stackmark *mark)
1625{
1626        struct stack_block *sp;
1627
1628        if (!mark->stackp)
1629                return;
1630
1631        INT_OFF;
1632        while (g_stackp != mark->stackp) {
1633                sp = g_stackp;
1634                g_stackp = sp->prev;
1635                free(sp);
1636        }
1637        g_stacknxt = mark->stacknxt;
1638        g_stacknleft = mark->stacknleft;
1639        sstrend = mark->stacknxt + mark->stacknleft;
1640        INT_ON;
1641}
1642
1643/*
1644 * When the parser reads in a string, it wants to stick the string on the
1645 * stack and only adjust the stack pointer when it knows how big the
1646 * string is.  Stackblock (defined in stack.h) returns a pointer to a block
1647 * of space on top of the stack and stackblocklen returns the length of
1648 * this block.  Growstackblock will grow this space by at least one byte,
1649 * possibly moving it (like realloc).  Grabstackblock actually allocates the
1650 * part of the block that has been used.
1651 */
1652static void
1653growstackblock(void)
1654{
1655        size_t newlen;
1656
1657        newlen = g_stacknleft * 2;
1658        if (newlen < g_stacknleft)
1659                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1660        if (newlen < 128)
1661                newlen += 128;
1662
1663        if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1664                struct stack_block *sp;
1665                struct stack_block *prevstackp;
1666                size_t grosslen;
1667
1668                INT_OFF;
1669                sp = g_stackp;
1670                prevstackp = sp->prev;
1671                grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1672                sp = ckrealloc(sp, grosslen);
1673                sp->prev = prevstackp;
1674                g_stackp = sp;
1675                g_stacknxt = sp->space;
1676                g_stacknleft = newlen;
1677                sstrend = sp->space + newlen;
1678                INT_ON;
1679        } else {
1680                char *oldspace = g_stacknxt;
1681                size_t oldlen = g_stacknleft;
1682                char *p = stalloc(newlen);
1683
1684                /* free the space we just allocated */
1685                g_stacknxt = memcpy(p, oldspace, oldlen);
1686                g_stacknleft += newlen;
1687        }
1688}
1689
1690/*
1691 * The following routines are somewhat easier to use than the above.
1692 * The user declares a variable of type STACKSTR, which may be declared
1693 * to be a register.  The macro STARTSTACKSTR initializes things.  Then
1694 * the user uses the macro STPUTC to add characters to the string.  In
1695 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1696 * grown as necessary.  When the user is done, she can just leave the
1697 * string there and refer to it using stackblock().  Or she can allocate
1698 * the space for it using grabstackstr().  If it is necessary to allow
1699 * someone else to use the stack temporarily and then continue to grow
1700 * the string, the user should use grabstack to allocate the space, and
1701 * then call ungrabstr(p) to return to the previous mode of operation.
1702 *
1703 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1704 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1705 * is space for at least one character.
1706 */
1707static void *
1708growstackstr(void)
1709{
1710        size_t len = stackblocksize();
1711        growstackblock();
1712        return (char *)stackblock() + len;
1713}
1714
1715/*
1716 * Called from CHECKSTRSPACE.
1717 */
1718static char *
1719makestrspace(size_t newlen, char *p)
1720{
1721        size_t len = p - g_stacknxt;
1722        size_t size;
1723
1724        for (;;) {
1725                size_t nleft;
1726
1727                size = stackblocksize();
1728                nleft = size - len;
1729                if (nleft >= newlen)
1730                        break;
1731                growstackblock();
1732        }
1733        return (char *)stackblock() + len;
1734}
1735
1736static char *
1737stack_nputstr(const char *s, size_t n, char *p)
1738{
1739        p = makestrspace(n, p);
1740        p = (char *)mempcpy(p, s, n);
1741        return p;
1742}
1743
1744static char *
1745stack_putstr(const char *s, char *p)
1746{
1747        return stack_nputstr(s, strlen(s), p);
1748}
1749
1750static char *
1751_STPUTC(int c, char *p)
1752{
1753        if (p == sstrend)
1754                p = growstackstr();
1755        *p++ = c;
1756        return p;
1757}
1758
1759#define STARTSTACKSTR(p)        ((p) = stackblock())
1760#define STPUTC(c, p)            ((p) = _STPUTC((c), (p)))
1761#define CHECKSTRSPACE(n, p) do { \
1762        char *q = (p); \
1763        size_t l = (n); \
1764        size_t m = sstrend - q; \
1765        if (l > m) \
1766                (p) = makestrspace(l, q); \
1767} while (0)
1768#define USTPUTC(c, p)           (*(p)++ = (c))
1769#define STACKSTRNUL(p) do { \
1770        if ((p) == sstrend) \
1771                (p) = growstackstr(); \
1772        *(p) = '\0'; \
1773} while (0)
1774#define STUNPUTC(p)             (--(p))
1775#define STTOPC(p)               ((p)[-1])
1776#define STADJUST(amount, p)     ((p) += (amount))
1777
1778#define grabstackstr(p)         stalloc((char *)(p) - (char *)stackblock())
1779#define ungrabstackstr(s, p)    stunalloc(s)
1780#define stackstrend()           ((void *)sstrend)
1781
1782
1783/* ============ String helpers */
1784
1785/*
1786 * prefix -- see if pfx is a prefix of string.
1787 */
1788static char *
1789prefix(const char *string, const char *pfx)
1790{
1791        while (*pfx) {
1792                if (*pfx++ != *string++)
1793                        return NULL;
1794        }
1795        return (char *) string;
1796}
1797
1798/*
1799 * Check for a valid number.  This should be elsewhere.
1800 */
1801static int
1802is_number(const char *p)
1803{
1804        do {
1805                if (!isdigit(*p))
1806                        return 0;
1807        } while (*++p != '\0');
1808        return 1;
1809}
1810
1811/*
1812 * Convert a string of digits to an integer, printing an error message on
1813 * failure.
1814 */
1815static int
1816number(const char *s)
1817{
1818        if (!is_number(s))
1819                ash_msg_and_raise_error(msg_illnum, s);
1820        return atoi(s);
1821}
1822
1823/*
1824 * Produce a single quoted string suitable as input to the shell.
1825 * The return string is allocated on the stack.
1826 */
1827static char *
1828single_quote(const char *s)
1829{
1830        char *p;
1831
1832        STARTSTACKSTR(p);
1833
1834        do {
1835                char *q;
1836                size_t len;
1837
1838                len = strchrnul(s, '\'') - s;
1839
1840                q = p = makestrspace(len + 3, p);
1841
1842                *q++ = '\'';
1843                q = (char *)mempcpy(q, s, len);
1844                *q++ = '\'';
1845                s += len;
1846
1847                STADJUST(q - p, p);
1848
1849                if (*s != '\'')
1850                        break;
1851                len = 0;
1852                do len++; while (*++s == '\'');
1853
1854                q = p = makestrspace(len + 3, p);
1855
1856                *q++ = '"';
1857                q = (char *)mempcpy(q, s - len, len);
1858                *q++ = '"';
1859
1860                STADJUST(q - p, p);
1861        } while (*s);
1862
1863        USTPUTC('\0', p);
1864
1865        return stackblock();
1866}
1867
1868/*
1869 * Produce a possibly single quoted string suitable as input to the shell.
1870 * If quoting was done, the return string is allocated on the stack,
1871 * otherwise a pointer to the original string is returned.
1872 */
1873static const char *
1874maybe_single_quote(const char *s)
1875{
1876        const char *p = s;
1877
1878        while (*p) {
1879                /* Assuming ACSII */
1880                /* quote ctrl_chars space !"#$%&'()* */
1881                if (*p < '+')
1882                        goto need_quoting;
1883                /* quote ;<=>? */
1884                if (*p >= ';' && *p <= '?')
1885                        goto need_quoting;
1886                /* quote `[\ */
1887                if (*p == '`')
1888                        goto need_quoting;
1889                if (*p == '[')
1890                        goto need_quoting;
1891                if (*p == '\\')
1892                        goto need_quoting;
1893                /* quote {|}~ DEL and high bytes */
1894                if (*p > 'z')
1895                        goto need_quoting;
1896                /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1897                /* TODO: maybe avoid quoting % */
1898                p++;
1899        }
1900        return s;
1901
1902 need_quoting:
1903        return single_quote(s);
1904}
1905
1906
1907/* ============ nextopt */
1908
1909static char **argptr;                  /* argument list for builtin commands */
1910static char *optionarg;                /* set by nextopt (like getopt) */
1911static char *optptr;                   /* used by nextopt */
1912
1913/*
1914 * XXX - should get rid of. Have all builtins use getopt(3).
1915 * The library getopt must have the BSD extension static variable
1916 * "optreset", otherwise it can't be used within the shell safely.
1917 *
1918 * Standard option processing (a la getopt) for builtin routines.
1919 * The only argument that is passed to nextopt is the option string;
1920 * the other arguments are unnecessary. It returns the character,
1921 * or '\0' on end of input.
1922 */
1923static int
1924nextopt(const char *optstring)
1925{
1926        char *p;
1927        const char *q;
1928        char c;
1929
1930        p = optptr;
1931        if (p == NULL || *p == '\0') {
1932                /* We ate entire "-param", take next one */
1933                p = *argptr;
1934                if (p == NULL)
1935                        return '\0';
1936                if (*p != '-')
1937                        return '\0';
1938                if (*++p == '\0') /* just "-" ? */
1939                        return '\0';
1940                argptr++;
1941                if (LONE_DASH(p)) /* "--" ? */
1942                        return '\0';
1943                /* p => next "-param" */
1944        }
1945        /* p => some option char in the middle of a "-param" */
1946        c = *p++;
1947        for (q = optstring; *q != c;) {
1948                if (*q == '\0')
1949                        ash_msg_and_raise_error("illegal option -%c", c);
1950                if (*++q == ':')
1951                        q++;
1952        }
1953        if (*++q == ':') {
1954                if (*p == '\0') {
1955                        p = *argptr++;
1956                        if (p == NULL)
1957                                ash_msg_and_raise_error("no arg for -%c option", c);
1958                }
1959                optionarg = p;
1960                p = NULL;
1961        }
1962        optptr = p;
1963        return c;
1964}
1965
1966
1967/* ============ Shell variables */
1968
1969struct shparam {
1970        int nparam;             /* # of positional parameters (without $0) */
1971#if ENABLE_ASH_GETOPTS
1972        int optind;             /* next parameter to be processed by getopts */
1973        int optoff;             /* used by getopts */
1974#endif
1975        unsigned char malloced; /* if parameter list dynamically allocated */
1976        char **p;               /* parameter list */
1977};
1978
1979/*
1980 * Free the list of positional parameters.
1981 */
1982static void
1983freeparam(volatile struct shparam *param)
1984{
1985        if (param->malloced) {
1986                char **ap, **ap1;
1987                ap = ap1 = param->p;
1988                while (*ap)
1989                        free(*ap++);
1990                free(ap1);
1991        }
1992}
1993
1994#if ENABLE_ASH_GETOPTS
1995static void FAST_FUNC getoptsreset(const char *value);
1996#endif
1997
1998struct var {
1999        struct var *next;               /* next entry in hash list */
2000        int flags;                      /* flags are defined above */
2001        const char *var_text;           /* name=value */
2002        void (*var_func)(const char *) FAST_FUNC; /* function to be called when  */
2003                                        /* the variable gets set/unset */
2004};
2005
2006struct localvar {
2007        struct localvar *next;          /* next local variable in list */
2008        struct var *vp;                 /* the variable that was made local */
2009        int flags;                      /* saved flags */
2010        const char *text;               /* saved text */
2011};
2012
2013/* flags */
2014#define VEXPORT         0x01    /* variable is exported */
2015#define VREADONLY       0x02    /* variable cannot be modified */
2016#define VSTRFIXED       0x04    /* variable struct is statically allocated */
2017#define VTEXTFIXED      0x08    /* text is statically allocated */
2018#define VSTACK          0x10    /* text is allocated on the stack */
2019#define VUNSET          0x20    /* the variable is not set */
2020#define VNOFUNC         0x40    /* don't call the callback function */
2021#define VNOSET          0x80    /* do not set variable - just readonly test */
2022#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
2023#if ENABLE_ASH_RANDOM_SUPPORT
2024# define VDYNAMIC       0x200   /* dynamic variable */
2025#else
2026# define VDYNAMIC       0
2027#endif
2028
2029
2030/* Need to be before varinit_data[] */
2031#if ENABLE_LOCALE_SUPPORT
2032static void FAST_FUNC
2033change_lc_all(const char *value)
2034{
2035        if (value && *value != '\0')
2036                setlocale(LC_ALL, value);
2037}
2038static void FAST_FUNC
2039change_lc_ctype(const char *value)
2040{
2041        if (value && *value != '\0')
2042                setlocale(LC_CTYPE, value);
2043}
2044#endif
2045#if ENABLE_ASH_MAIL
2046static void chkmail(void);
2047static void changemail(const char *var_value) FAST_FUNC;
2048#else
2049# define chkmail()  ((void)0)
2050#endif
2051static void changepath(const char *) FAST_FUNC;
2052#if ENABLE_ASH_RANDOM_SUPPORT
2053static void change_random(const char *) FAST_FUNC;
2054#endif
2055
2056static const struct {
2057        int flags;
2058        const char *var_text;
2059        void (*var_func)(const char *) FAST_FUNC;
2060} varinit_data[] = {
2061        /*
2062         * Note: VEXPORT would not work correctly here for NOFORK applets:
2063         * some environment strings may be constant.
2064         */
2065        { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
2066#if ENABLE_ASH_MAIL
2067        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL"      , changemail      },
2068        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH"  , changemail      },
2069#endif
2070        { VSTRFIXED|VTEXTFIXED       , bb_PATH_root_path, changepath },
2071        { VSTRFIXED|VTEXTFIXED       , "PS1=$ "    , NULL            },
2072        { VSTRFIXED|VTEXTFIXED       , "PS2=> "    , NULL            },
2073        { VSTRFIXED|VTEXTFIXED       , "PS4=+ "    , NULL            },
2074#if ENABLE_ASH_GETOPTS
2075        { VSTRFIXED|VTEXTFIXED       , defoptindvar, getoptsreset    },
2076#endif
2077        { VSTRFIXED|VTEXTFIXED       , NULL /* inited to linenovar */, NULL },
2078#if ENABLE_ASH_RANDOM_SUPPORT
2079        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2080#endif
2081#if ENABLE_LOCALE_SUPPORT
2082        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL"    , change_lc_all   },
2083        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE"  , change_lc_ctype },
2084#endif
2085#if ENABLE_FEATURE_EDITING_SAVEHISTORY
2086        { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE"  , NULL            },
2087#endif
2088};
2089
2090struct redirtab;
2091
2092struct globals_var {
2093        struct shparam shellparam;      /* $@ current positional parameters */
2094        struct redirtab *redirlist;
2095        int preverrout_fd;   /* stderr fd: usually 2, unless redirect moved it */
2096        struct var *vartab[VTABSIZE];
2097        struct var varinit[ARRAY_SIZE(varinit_data)];
2098        int lineno;
2099        char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2100};
2101extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2102#define G_var (*ash_ptr_to_globals_var)
2103#define shellparam    (G_var.shellparam   )
2104//#define redirlist     (G_var.redirlist    )
2105#define preverrout_fd (G_var.preverrout_fd)
2106#define vartab        (G_var.vartab       )
2107#define varinit       (G_var.varinit      )
2108#define lineno        (G_var.lineno       )
2109#define linenovar     (G_var.linenovar    )
2110#define vifs      varinit[0]
2111#if ENABLE_ASH_MAIL
2112# define vmail    (&vifs)[1]
2113# define vmpath   (&vmail)[1]
2114# define vpath    (&vmpath)[1]
2115#else
2116# define vpath    (&vifs)[1]
2117#endif
2118#define vps1      (&vpath)[1]
2119#define vps2      (&vps1)[1]
2120#define vps4      (&vps2)[1]
2121#if ENABLE_ASH_GETOPTS
2122# define voptind  (&vps4)[1]
2123# define vlineno  (&voptind)[1]
2124# if ENABLE_ASH_RANDOM_SUPPORT
2125#  define vrandom (&vlineno)[1]
2126# endif
2127#else
2128# define vlineno  (&vps4)[1]
2129# if ENABLE_ASH_RANDOM_SUPPORT
2130#  define vrandom (&vlineno)[1]
2131# endif
2132#endif
2133#define INIT_G_var() do { \
2134        unsigned i; \
2135        (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2136        barrier(); \
2137        for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2138                varinit[i].flags    = varinit_data[i].flags; \
2139                varinit[i].var_text = varinit_data[i].var_text; \
2140                varinit[i].var_func = varinit_data[i].var_func; \
2141        } \
2142        strcpy(linenovar, "LINENO="); \
2143        vlineno.var_text = linenovar; \
2144} while (0)
2145
2146/*
2147 * The following macros access the values of the above variables.
2148 * They have to skip over the name.  They return the null string
2149 * for unset variables.
2150 */
2151#define ifsval()        (vifs.var_text + 4)
2152#define ifsset()        ((vifs.flags & VUNSET) == 0)
2153#if ENABLE_ASH_MAIL
2154# define mailval()      (vmail.var_text + 5)
2155# define mpathval()     (vmpath.var_text + 9)
2156# define mpathset()     ((vmpath.flags & VUNSET) == 0)
2157#endif
2158#define pathval()       (vpath.var_text + 5)
2159#define ps1val()        (vps1.var_text + 4)
2160#define ps2val()        (vps2.var_text + 4)
2161#define ps4val()        (vps4.var_text + 4)
2162#if ENABLE_ASH_GETOPTS
2163# define optindval()    (voptind.var_text + 7)
2164#endif
2165
2166#if ENABLE_ASH_GETOPTS
2167static void FAST_FUNC
2168getoptsreset(const char *value)
2169{
2170        shellparam.optind = 1;
2171        if (is_number(value))
2172                shellparam.optind = number(value) ?: 1;
2173        shellparam.optoff = -1;
2174}
2175#endif
2176
2177/*
2178 * Compares two strings up to the first = or '\0'.  The first
2179 * string must be terminated by '='; the second may be terminated by
2180 * either '=' or '\0'.
2181 */
2182static int
2183varcmp(const char *p, const char *q)
2184{
2185        int c, d;
2186
2187        while ((c = *p) == (d = *q)) {
2188                if (c == '\0' || c == '=')
2189                        goto out;
2190                p++;
2191                q++;
2192        }
2193        if (c == '=')
2194                c = '\0';
2195        if (d == '=')
2196                d = '\0';
2197 out:
2198        return c - d;
2199}
2200
2201/*
2202 * Find the appropriate entry in the hash table from the name.
2203 */
2204static struct var **
2205hashvar(const char *p)
2206{
2207        unsigned hashval;
2208
2209        hashval = ((unsigned char) *p) << 4;
2210        while (*p && *p != '=')
2211                hashval += (unsigned char) *p++;
2212        return &vartab[hashval % VTABSIZE];
2213}
2214
2215static int
2216vpcmp(const void *a, const void *b)
2217{
2218        return varcmp(*(const char **)a, *(const char **)b);
2219}
2220
2221/*
2222 * This routine initializes the builtin variables.
2223 */
2224static void
2225initvar(void)
2226{
2227        struct var *vp;
2228        struct var *end;
2229        struct var **vpp;
2230
2231        /*
2232         * PS1 depends on uid
2233         */
2234#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2235        vps1.var_text = "PS1=\\w \\$ ";
2236#else
2237        if (!geteuid())
2238                vps1.var_text = "PS1=# ";
2239#endif
2240        vp = varinit;
2241        end = vp + ARRAY_SIZE(varinit);
2242        do {
2243                vpp = hashvar(vp->var_text);
2244                vp->next = *vpp;
2245                *vpp = vp;
2246        } while (++vp < end);
2247}
2248
2249static struct var **
2250findvar(struct var **vpp, const char *name)
2251{
2252        for (; *vpp; vpp = &(*vpp)->next) {
2253                if (varcmp((*vpp)->var_text, name) == 0) {
2254                        break;
2255                }
2256        }
2257        return vpp;
2258}
2259
2260/*
2261 * Find the value of a variable.  Returns NULL if not set.
2262 */
2263static const char* FAST_FUNC
2264lookupvar(const char *name)
2265{
2266        struct var *v;
2267
2268        v = *findvar(hashvar(name), name);
2269        if (v) {
2270#if ENABLE_ASH_RANDOM_SUPPORT
2271        /*
2272         * Dynamic variables are implemented roughly the same way they are
2273         * in bash. Namely, they're "special" so long as they aren't unset.
2274         * As soon as they're unset, they're no longer dynamic, and dynamic
2275         * lookup will no longer happen at that point. -- PFM.
2276         */
2277                if (v->flags & VDYNAMIC)
2278                        v->var_func(NULL);
2279#endif
2280                if (!(v->flags & VUNSET)) {
2281                        if (v == &vlineno && v->var_text == linenovar) {
2282                                fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2283                        }
2284                        return var_end(v->var_text);
2285                }
2286        }
2287        return NULL;
2288}
2289
2290#if ENABLE_UNICODE_SUPPORT
2291static void
2292reinit_unicode_for_ash(void)
2293{
2294        /* Unicode support should be activated even if LANG is set
2295         * _during_ shell execution, not only if it was set when
2296         * shell was started. Therefore, re-check LANG every time:
2297         */
2298        if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2299         || ENABLE_UNICODE_USING_LOCALE
2300        ) {
2301                const char *s = lookupvar("LC_ALL");
2302                if (!s) s = lookupvar("LC_CTYPE");
2303                if (!s) s = lookupvar("LANG");
2304                reinit_unicode(s);
2305        }
2306}
2307#else
2308# define reinit_unicode_for_ash() ((void)0)
2309#endif
2310
2311/*
2312 * Search the environment of a builtin command.
2313 */
2314static ALWAYS_INLINE const char *
2315bltinlookup(const char *name)
2316{
2317        return lookupvar(name);
2318}
2319
2320/*
2321 * Same as setvar except that the variable and value are passed in
2322 * the first argument as name=value.  Since the first argument will
2323 * be actually stored in the table, it should not be a string that
2324 * will go away.
2325 * Called with interrupts off.
2326 */
2327static struct var *
2328setvareq(char *s, int flags)
2329{
2330        struct var *vp, **vpp;
2331
2332        vpp = hashvar(s);
2333        flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2334        vpp = findvar(vpp, s);
2335        vp = *vpp;
2336        if (vp) {
2337                if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2338                        const char *n;
2339
2340                        if (flags & VNOSAVE)
2341                                free(s);
2342                        n = vp->var_text;
2343                        exitstatus = 1;
2344                        ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2345                }
2346
2347                if (flags & VNOSET)
2348                        goto out;
2349
2350                if (vp->var_func && !(flags & VNOFUNC))
2351                        vp->var_func(var_end(s));
2352
2353                if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2354                        free((char*)vp->var_text);
2355
2356                if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2357                        *vpp = vp->next;
2358                        free(vp);
2359 out_free:
2360                        if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2361                                free(s);
2362                        goto out;
2363                }
2364
2365                flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2366        } else {
2367                /* variable s is not found */
2368                if (flags & VNOSET)
2369                        goto out;
2370                if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2371                        goto out_free;
2372                vp = ckzalloc(sizeof(*vp));
2373                vp->next = *vpp;
2374                /*vp->func = NULL; - ckzalloc did it */
2375                *vpp = vp;
2376        }
2377        if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2378                s = ckstrdup(s);
2379        vp->var_text = s;
2380        vp->flags = flags;
2381
2382 out:
2383        return vp;
2384}
2385
2386/*
2387 * Set the value of a variable.  The flags argument is ored with the
2388 * flags of the variable.  If val is NULL, the variable is unset.
2389 */
2390static struct var *
2391setvar(const char *name, const char *val, int flags)
2392{
2393        const char *q;
2394        char *p;
2395        char *nameeq;
2396        size_t namelen;
2397        size_t vallen;
2398        struct var *vp;
2399
2400        q = endofname(name);
2401        p = strchrnul(q, '=');
2402        namelen = p - name;
2403        if (!namelen || p != q)
2404                ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2405        vallen = 0;
2406        if (val == NULL) {
2407                flags |= VUNSET;
2408        } else {
2409                vallen = strlen(val);
2410        }
2411
2412        INT_OFF;
2413        nameeq = ckzalloc(namelen + vallen + 2);
2414        p = mempcpy(nameeq, name, namelen);
2415        if (val) {
2416                *p++ = '=';
2417                memcpy(p, val, vallen);
2418        }
2419        vp = setvareq(nameeq, flags | VNOSAVE);
2420        INT_ON;
2421
2422        return vp;
2423}
2424
2425static void FAST_FUNC
2426setvar0(const char *name, const char *val)
2427{
2428        setvar(name, val, 0);
2429}
2430
2431/*
2432 * Unset the specified variable.
2433 */
2434static void
2435unsetvar(const char *s)
2436{
2437        setvar(s, NULL, 0);
2438}
2439
2440/*
2441 * Process a linked list of variable assignments.
2442 */
2443static void
2444listsetvar(struct strlist *list_set_var, int flags)
2445{
2446        struct strlist *lp = list_set_var;
2447
2448        if (!lp)
2449                return;
2450        INT_OFF;
2451        do {
2452                setvareq(lp->text, flags);
2453                lp = lp->next;
2454        } while (lp);
2455        INT_ON;
2456}
2457
2458/*
2459 * Generate a list of variables satisfying the given conditions.
2460 */
2461#if !ENABLE_FEATURE_SH_NOFORK
2462# define listvars(on, off, lp, end) listvars(on, off, end)
2463#endif
2464static char **
2465listvars(int on, int off, struct strlist *lp, char ***end)
2466{
2467        struct var **vpp;
2468        struct var *vp;
2469        char **ep;
2470        int mask;
2471
2472        STARTSTACKSTR(ep);
2473        vpp = vartab;
2474        mask = on | off;
2475        do {
2476                for (vp = *vpp; vp; vp = vp->next) {
2477                        if ((vp->flags & mask) == on) {
2478#if ENABLE_FEATURE_SH_NOFORK
2479                                /* If variable with the same name is both
2480                                 * exported and temporarily set for a command:
2481                                 *  export ZVAR=5
2482                                 *  ZVAR=6 printenv
2483                                 * then "ZVAR=6" will be both in vartab and
2484                                 * lp lists. Do not pass it twice to printenv.
2485                                 */
2486                                struct strlist *lp1 = lp;
2487                                while (lp1) {
2488                                        if (strcmp(lp1->text, vp->var_text) == 0)
2489                                                goto skip;
2490                                        lp1 = lp1->next;
2491                                }
2492#endif
2493                                if (ep == stackstrend())
2494                                        ep = growstackstr();
2495                                *ep++ = (char*)vp->var_text;
2496#if ENABLE_FEATURE_SH_NOFORK
2497 skip: ;
2498#endif
2499                        }
2500                }
2501        } while (++vpp < vartab + VTABSIZE);
2502
2503#if ENABLE_FEATURE_SH_NOFORK
2504        while (lp) {
2505                if (ep == stackstrend())
2506                        ep = growstackstr();
2507                *ep++ = lp->text;
2508                lp = lp->next;
2509        }
2510#endif
2511
2512        if (ep == stackstrend())
2513                ep = growstackstr();
2514        if (end)
2515                *end = ep;
2516        *ep++ = NULL;
2517        return grabstackstr(ep);
2518}
2519
2520
2521/* ============ Path search helper
2522 *
2523 * The variable path (passed by reference) should be set to the start
2524 * of the path before the first call; path_advance will update
2525 * this value as it proceeds.  Successive calls to path_advance will return
2526 * the possible path expansions in sequence.  If an option (indicated by
2527 * a percent sign) appears in the path entry then the global variable
2528 * pathopt will be set to point to it; otherwise pathopt will be set to
2529 * NULL.
2530 */
2531static const char *pathopt;     /* set by path_advance */
2532
2533static char *
2534path_advance(const char **path, const char *name)
2535{
2536        const char *p;
2537        char *q;
2538        const char *start;
2539        size_t len;
2540
2541        if (*path == NULL)
2542                return NULL;
2543        start = *path;
2544        for (p = start; *p && *p != ':' && *p != '%'; p++)
2545                continue;
2546        len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
2547        while (stackblocksize() < len)
2548                growstackblock();
2549        q = stackblock();
2550        if (p != start) {
2551                q = mempcpy(q, start, p - start);
2552                *q++ = '/';
2553        }
2554        strcpy(q, name);
2555        pathopt = NULL;
2556        if (*p == '%') {
2557                pathopt = ++p;
2558                while (*p && *p != ':')
2559                        p++;
2560        }
2561        if (*p == ':')
2562                *path = p + 1;
2563        else
2564                *path = NULL;
2565        return stalloc(len);
2566}
2567
2568
2569/* ============ Prompt */
2570
2571static smallint doprompt;                   /* if set, prompt the user */
2572static smallint needprompt;                 /* true if interactive and at start of line */
2573
2574#if ENABLE_FEATURE_EDITING
2575static line_input_t *line_input_state;
2576static const char *cmdedit_prompt;
2577static void
2578putprompt(const char *s)
2579{
2580        if (ENABLE_ASH_EXPAND_PRMT) {
2581                free((char*)cmdedit_prompt);
2582                cmdedit_prompt = ckstrdup(s);
2583                return;
2584        }
2585        cmdedit_prompt = s;
2586}
2587#else
2588static void
2589putprompt(const char *s)
2590{
2591        out2str(s);
2592}
2593#endif
2594
2595/* expandstr() needs parsing machinery, so it is far away ahead... */
2596static const char *expandstr(const char *ps, int syntax_type);
2597/* Values for syntax param */
2598#define BASESYNTAX 0    /* not in quotes */
2599#define DQSYNTAX   1    /* in double quotes */
2600#define SQSYNTAX   2    /* in single quotes */
2601#define ARISYNTAX  3    /* in arithmetic */
2602#if ENABLE_ASH_EXPAND_PRMT
2603# define PSSYNTAX  4    /* prompt. never passed to SIT() */
2604#endif
2605/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
2606
2607/*
2608 * called by editline -- any expansions to the prompt should be added here.
2609 */
2610static void
2611setprompt_if(smallint do_set, int whichprompt)
2612{
2613        const char *prompt;
2614        IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2615
2616        if (!do_set)
2617                return;
2618
2619        needprompt = 0;
2620
2621        switch (whichprompt) {
2622        case 1:
2623                prompt = ps1val();
2624                break;
2625        case 2:
2626                prompt = ps2val();
2627                break;
2628        default:                        /* 0 */
2629                prompt = nullstr;
2630        }
2631#if ENABLE_ASH_EXPAND_PRMT
2632        pushstackmark(&smark, stackblocksize());
2633        putprompt(expandstr(prompt, PSSYNTAX));
2634        popstackmark(&smark);
2635#else
2636        putprompt(prompt);
2637#endif
2638}
2639
2640
2641/* ============ The cd and pwd commands */
2642
2643#define CD_PHYSICAL 1
2644#define CD_PRINT 2
2645
2646static int
2647cdopt(void)
2648{
2649        int flags = 0;
2650        int i, j;
2651
2652        j = 'L';
2653        while ((i = nextopt("LP")) != '\0') {
2654                if (i != j) {
2655                        flags ^= CD_PHYSICAL;
2656                        j = i;
2657                }
2658        }
2659
2660        return flags;
2661}
2662
2663/*
2664 * Update curdir (the name of the current directory) in response to a
2665 * cd command.
2666 */
2667static const char *
2668updatepwd(const char *dir)
2669{
2670        char *new;
2671        char *p;
2672        char *cdcomppath;
2673        const char *lim;
2674
2675        cdcomppath = sstrdup(dir);
2676        STARTSTACKSTR(new);
2677        if (*dir != '/') {
2678                if (curdir == nullstr)
2679                        return 0;
2680                new = stack_putstr(curdir, new);
2681        }
2682        new = makestrspace(strlen(dir) + 2, new);
2683        lim = (char *)stackblock() + 1;
2684        if (*dir != '/') {
2685                if (new[-1] != '/')
2686                        USTPUTC('/', new);
2687                if (new > lim && *lim == '/')
2688                        lim++;
2689        } else {
2690                USTPUTC('/', new);
2691                cdcomppath++;
2692                if (dir[1] == '/' && dir[2] != '/') {
2693                        USTPUTC('/', new);
2694                        cdcomppath++;
2695                        lim++;
2696                }
2697        }
2698        p = strtok(cdcomppath, "/");
2699        while (p) {
2700                switch (*p) {
2701                case '.':
2702                        if (p[1] == '.' && p[2] == '\0') {
2703                                while (new > lim) {
2704                                        STUNPUTC(new);
2705                                        if (new[-1] == '/')
2706                                                break;
2707                                }
2708                                break;
2709                        }
2710                        if (p[1] == '\0')
2711                                break;
2712                        /* fall through */
2713                default:
2714                        new = stack_putstr(p, new);
2715                        USTPUTC('/', new);
2716                }
2717                p = strtok(NULL, "/");
2718        }
2719        if (new > lim)
2720                STUNPUTC(new);
2721        *new = 0;
2722        return stackblock();
2723}
2724
2725/*
2726 * Find out what the current directory is. If we already know the current
2727 * directory, this routine returns immediately.
2728 */
2729static char *
2730getpwd(void)
2731{
2732        char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2733        return dir ? dir : nullstr;
2734}
2735
2736static void
2737setpwd(const char *val, int setold)
2738{
2739        char *oldcur, *dir;
2740
2741        oldcur = dir = curdir;
2742
2743        if (setold) {
2744                setvar("OLDPWD", oldcur, VEXPORT);
2745        }
2746        INT_OFF;
2747        if (physdir != nullstr) {
2748                if (physdir != oldcur)
2749                        free(physdir);
2750                physdir = nullstr;
2751        }
2752        if (oldcur == val || !val) {
2753                char *s = getpwd();
2754                physdir = s;
2755                if (!val)
2756                        dir = s;
2757        } else
2758                dir = ckstrdup(val);
2759        if (oldcur != dir && oldcur != nullstr) {
2760                free(oldcur);
2761        }
2762        curdir = dir;
2763        INT_ON;
2764        setvar("PWD", dir, VEXPORT);
2765}
2766
2767static void hashcd(void);
2768
2769/*
2770 * Actually do the chdir.  We also call hashcd to let other routines
2771 * know that the current directory has changed.
2772 */
2773static int
2774docd(const char *dest, int flags)
2775{
2776        const char *dir = NULL;
2777        int err;
2778
2779        TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2780
2781        INT_OFF;
2782        if (!(flags & CD_PHYSICAL)) {
2783                dir = updatepwd(dest);
2784                if (dir)
2785                        dest = dir;
2786        }
2787        err = chdir(dest);
2788        if (err)
2789                goto out;
2790        setpwd(dir, 1);
2791        hashcd();
2792 out:
2793        INT_ON;
2794        return err;
2795}
2796
2797static int FAST_FUNC
2798cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2799{
2800        const char *dest;
2801        const char *path;
2802        const char *p;
2803        char c;
2804        struct stat statb;
2805        int flags;
2806
2807        flags = cdopt();
2808        dest = *argptr;
2809        if (!dest)
2810                dest = bltinlookup("HOME");
2811        else if (LONE_DASH(dest)) {
2812                dest = bltinlookup("OLDPWD");
2813                flags |= CD_PRINT;
2814        }
2815        if (!dest)
2816                dest = nullstr;
2817        if (*dest == '/')
2818                goto step6;
2819        if (*dest == '.') {
2820                c = dest[1];
2821 dotdot:
2822                switch (c) {
2823                case '\0':
2824                case '/':
2825                        goto step6;
2826                case '.':
2827                        c = dest[2];
2828                        if (c != '.')
2829                                goto dotdot;
2830                }
2831        }
2832        if (!*dest)
2833                dest = ".";
2834        path = bltinlookup("CDPATH");
2835        while (path) {
2836                c = *path;
2837                p = path_advance(&path, dest);
2838                if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2839                        if (c && c != ':')
2840                                flags |= CD_PRINT;
2841 docd:
2842                        if (!docd(p, flags))
2843                                goto out;
2844                        goto err;
2845                }
2846        }
2847
2848 step6:
2849        p = dest;
2850        goto docd;
2851
2852 err:
2853        ash_msg_and_raise_perror("can't cd to %s", dest);
2854        /* NOTREACHED */
2855 out:
2856        if (flags & CD_PRINT)
2857                out1fmt("%s\n", curdir);
2858        return 0;
2859}
2860
2861static int FAST_FUNC
2862pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2863{
2864        int flags;
2865        const char *dir = curdir;
2866
2867        flags = cdopt();
2868        if (flags) {
2869                if (physdir == nullstr)
2870                        setpwd(dir, 0);
2871                dir = physdir;
2872        }
2873        out1fmt("%s\n", dir);
2874        return 0;
2875}
2876
2877
2878/* ============ ... */
2879
2880
2881#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2882
2883/* Syntax classes */
2884#define CWORD     0             /* character is nothing special */
2885#define CNL       1             /* newline character */
2886#define CBACK     2             /* a backslash character */
2887#define CSQUOTE   3             /* single quote */
2888#define CDQUOTE   4             /* double quote */
2889#define CENDQUOTE 5             /* a terminating quote */
2890#define CBQUOTE   6             /* backwards single quote */
2891#define CVAR      7             /* a dollar sign */
2892#define CENDVAR   8             /* a '}' character */
2893#define CLP       9             /* a left paren in arithmetic */
2894#define CRP      10             /* a right paren in arithmetic */
2895#define CENDFILE 11             /* end of file */
2896#define CCTL     12             /* like CWORD, except it must be escaped */
2897#define CSPCL    13             /* these terminate a word */
2898#define CIGN     14             /* character should be ignored */
2899
2900#define PEOF     256
2901#if ENABLE_ASH_ALIAS
2902# define PEOA    257
2903#endif
2904
2905#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2906
2907#if ENABLE_FEATURE_SH_MATH
2908# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2909#else
2910# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2911#endif
2912static const uint16_t S_I_T[] ALIGN2 = {
2913#if ENABLE_ASH_ALIAS
2914        SIT_ITEM(CSPCL   , CIGN     , CIGN , CIGN   ),    /* 0, PEOA */
2915#endif
2916        SIT_ITEM(CSPCL   , CWORD    , CWORD, CWORD  ),    /* 1, ' ' */
2917        SIT_ITEM(CNL     , CNL      , CNL  , CNL    ),    /* 2, \n */
2918        SIT_ITEM(CWORD   , CCTL     , CCTL , CWORD  ),    /* 3, !*-/:=?[]~ */
2919        SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD  ),    /* 4, '"' */
2920        SIT_ITEM(CVAR    , CVAR     , CWORD, CVAR   ),    /* 5, $ */
2921        SIT_ITEM(CSQUOTE , CWORD    , CENDQUOTE, CWORD),  /* 6, "'" */
2922        SIT_ITEM(CSPCL   , CWORD    , CWORD, CLP    ),    /* 7, ( */
2923        SIT_ITEM(CSPCL   , CWORD    , CWORD, CRP    ),    /* 8, ) */
2924        SIT_ITEM(CBACK   , CBACK    , CCTL , CBACK  ),    /* 9, \ */
2925        SIT_ITEM(CBQUOTE , CBQUOTE  , CWORD, CBQUOTE),    /* 10, ` */
2926        SIT_ITEM(CENDVAR , CENDVAR  , CWORD, CENDVAR),    /* 11, } */
2927#if !USE_SIT_FUNCTION
2928        SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2929        SIT_ITEM(CWORD   , CWORD    , CWORD, CWORD  ),    /* 13, 0-9A-Za-z */
2930        SIT_ITEM(CCTL    , CCTL     , CCTL , CCTL   )     /* 14, CTLESC ... */
2931#endif
2932#undef SIT_ITEM
2933};
2934/* Constants below must match table above */
2935enum {
2936#if ENABLE_ASH_ALIAS
2937        CSPCL_CIGN_CIGN_CIGN               , /*  0 */
2938#endif
2939        CSPCL_CWORD_CWORD_CWORD            , /*  1 */
2940        CNL_CNL_CNL_CNL                    , /*  2 */
2941        CWORD_CCTL_CCTL_CWORD              , /*  3 */
2942        CDQUOTE_CENDQUOTE_CWORD_CWORD      , /*  4 */
2943        CVAR_CVAR_CWORD_CVAR               , /*  5 */
2944        CSQUOTE_CWORD_CENDQUOTE_CWORD      , /*  6 */
2945        CSPCL_CWORD_CWORD_CLP              , /*  7 */
2946        CSPCL_CWORD_CWORD_CRP              , /*  8 */
2947        CBACK_CBACK_CCTL_CBACK             , /*  9 */
2948        CBQUOTE_CBQUOTE_CWORD_CBQUOTE      , /* 10 */
2949        CENDVAR_CENDVAR_CWORD_CENDVAR      , /* 11 */
2950        CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2951        CWORD_CWORD_CWORD_CWORD            , /* 13 */
2952        CCTL_CCTL_CCTL_CCTL                , /* 14 */
2953};
2954
2955/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2956 * caller must ensure proper cast on it if c is *char_ptr!
2957 */
2958#if USE_SIT_FUNCTION
2959
2960static int
2961SIT(int c, int syntax)
2962{
2963        /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2964        static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2965        /*
2966         * This causes '/' to be prepended with CTLESC in dquoted string,
2967         * making "./file"* treated incorrectly because we feed
2968         * ".\/file*" string to glob(), confusing it (see expandmeta func).
2969         * The "homegrown" glob implementation is okay with that,
2970         * but glibc one isn't. With '/' always treated as CWORD,
2971         * both work fine.
2972         */
2973# if ENABLE_ASH_ALIAS
2974        static const uint8_t syntax_index_table[] ALIGN1 = {
2975                1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
2976                7, 8, 3, 3,/*3,*/3, 1, 1,       /* "()*-/:;<" */
2977                3, 1, 3, 3, 9, 3, 10, 1,        /* "=>?[\\]`|" */
2978                11, 3                           /* "}~" */
2979        };
2980# else
2981        static const uint8_t syntax_index_table[] ALIGN1 = {
2982                0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
2983                6, 7, 2, 2,/*2,*/2, 0, 0,       /* "()*-/:;<" */
2984                2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
2985                10, 2                           /* "}~" */
2986        };
2987# endif
2988        const char *s;
2989        int indx;
2990
2991        if (c == PEOF)
2992                return CENDFILE;
2993# if ENABLE_ASH_ALIAS
2994        if (c == PEOA)
2995                indx = 0;
2996        else
2997# endif
2998        {
2999                /* Cast is purely for paranoia here,
3000                 * just in case someone passed signed char to us */
3001                if ((unsigned char)c >= CTL_FIRST
3002                 && (unsigned char)c <= CTL_LAST
3003                ) {
3004                        return CCTL;
3005                }
3006                s = strchrnul(spec_symbls, c);
3007                if (*s == '\0')
3008                        return CWORD;
3009                indx = syntax_index_table[s - spec_symbls];
3010        }
3011        return (S_I_T[indx] >> (syntax*4)) & 0xf;
3012}
3013
3014#else   /* !USE_SIT_FUNCTION */
3015
3016static const uint8_t syntax_index_table[] ALIGN1 = {
3017        /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
3018        /*   0      */ CWORD_CWORD_CWORD_CWORD,
3019        /*   1      */ CWORD_CWORD_CWORD_CWORD,
3020        /*   2      */ CWORD_CWORD_CWORD_CWORD,
3021        /*   3      */ CWORD_CWORD_CWORD_CWORD,
3022        /*   4      */ CWORD_CWORD_CWORD_CWORD,
3023        /*   5      */ CWORD_CWORD_CWORD_CWORD,
3024        /*   6      */ CWORD_CWORD_CWORD_CWORD,
3025        /*   7      */ CWORD_CWORD_CWORD_CWORD,
3026        /*   8      */ CWORD_CWORD_CWORD_CWORD,
3027        /*   9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3028        /*  10 "\n" */ CNL_CNL_CNL_CNL,
3029        /*  11      */ CWORD_CWORD_CWORD_CWORD,
3030        /*  12      */ CWORD_CWORD_CWORD_CWORD,
3031        /*  13      */ CWORD_CWORD_CWORD_CWORD,
3032        /*  14      */ CWORD_CWORD_CWORD_CWORD,
3033        /*  15      */ CWORD_CWORD_CWORD_CWORD,
3034        /*  16      */ CWORD_CWORD_CWORD_CWORD,
3035        /*  17      */ CWORD_CWORD_CWORD_CWORD,
3036        /*  18      */ CWORD_CWORD_CWORD_CWORD,
3037        /*  19      */ CWORD_CWORD_CWORD_CWORD,
3038        /*  20      */ CWORD_CWORD_CWORD_CWORD,
3039        /*  21      */ CWORD_CWORD_CWORD_CWORD,
3040        /*  22      */ CWORD_CWORD_CWORD_CWORD,
3041        /*  23      */ CWORD_CWORD_CWORD_CWORD,
3042        /*  24      */ CWORD_CWORD_CWORD_CWORD,
3043        /*  25      */ CWORD_CWORD_CWORD_CWORD,
3044        /*  26      */ CWORD_CWORD_CWORD_CWORD,
3045        /*  27      */ CWORD_CWORD_CWORD_CWORD,
3046        /*  28      */ CWORD_CWORD_CWORD_CWORD,
3047        /*  29      */ CWORD_CWORD_CWORD_CWORD,
3048        /*  30      */ CWORD_CWORD_CWORD_CWORD,
3049        /*  31      */ CWORD_CWORD_CWORD_CWORD,
3050        /*  32  " " */ CSPCL_CWORD_CWORD_CWORD,
3051        /*  33  "!" */ CWORD_CCTL_CCTL_CWORD,
3052        /*  34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3053        /*  35  "#" */ CWORD_CWORD_CWORD_CWORD,
3054        /*  36  "$" */ CVAR_CVAR_CWORD_CVAR,
3055        /*  37  "%" */ CWORD_CWORD_CWORD_CWORD,
3056        /*  38  "&" */ CSPCL_CWORD_CWORD_CWORD,
3057        /*  39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3058        /*  40  "(" */ CSPCL_CWORD_CWORD_CLP,
3059        /*  41  ")" */ CSPCL_CWORD_CWORD_CRP,
3060        /*  42  "*" */ CWORD_CCTL_CCTL_CWORD,
3061        /*  43  "+" */ CWORD_CWORD_CWORD_CWORD,
3062        /*  44  "," */ CWORD_CWORD_CWORD_CWORD,
3063        /*  45  "-" */ CWORD_CCTL_CCTL_CWORD,
3064        /*  46  "." */ CWORD_CWORD_CWORD_CWORD,
3065/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3066        /*  47  "/" */ CWORD_CWORD_CWORD_CWORD,
3067        /*  48  "0" */ CWORD_CWORD_CWORD_CWORD,
3068        /*  49  "1" */ CWORD_CWORD_CWORD_CWORD,
3069        /*  50  "2" */ CWORD_CWORD_CWORD_CWORD,
3070        /*  51  "3" */ CWORD_CWORD_CWORD_CWORD,
3071        /*  52  "4" */ CWORD_CWORD_CWORD_CWORD,
3072        /*  53  "5" */ CWORD_CWORD_CWORD_CWORD,
3073        /*  54  "6" */ CWORD_CWORD_CWORD_CWORD,
3074        /*  55  "7" */ CWORD_CWORD_CWORD_CWORD,
3075        /*  56  "8" */ CWORD_CWORD_CWORD_CWORD,
3076        /*  57  "9" */ CWORD_CWORD_CWORD_CWORD,
3077        /*  58  ":" */ CWORD_CCTL_CCTL_CWORD,
3078        /*  59  ";" */ CSPCL_CWORD_CWORD_CWORD,
3079        /*  60  "<" */ CSPCL_CWORD_CWORD_CWORD,
3080        /*  61  "=" */ CWORD_CCTL_CCTL_CWORD,
3081        /*  62  ">" */ CSPCL_CWORD_CWORD_CWORD,
3082        /*  63  "?" */ CWORD_CCTL_CCTL_CWORD,
3083        /*  64  "@" */ CWORD_CWORD_CWORD_CWORD,
3084        /*  65  "A" */ CWORD_CWORD_CWORD_CWORD,
3085        /*  66  "B" */ CWORD_CWORD_CWORD_CWORD,
3086        /*  67  "C" */ CWORD_CWORD_CWORD_CWORD,
3087        /*  68  "D" */ CWORD_CWORD_CWORD_CWORD,
3088        /*  69  "E" */ CWORD_CWORD_CWORD_CWORD,
3089        /*  70  "F" */ CWORD_CWORD_CWORD_CWORD,
3090        /*  71  "G" */ CWORD_CWORD_CWORD_CWORD,
3091        /*  72  "H" */ CWORD_CWORD_CWORD_CWORD,
3092        /*  73  "I" */ CWORD_CWORD_CWORD_CWORD,
3093        /*  74  "J" */ CWORD_CWORD_CWORD_CWORD,
3094        /*  75  "K" */ CWORD_CWORD_CWORD_CWORD,
3095        /*  76  "L" */ CWORD_CWORD_CWORD_CWORD,
3096        /*  77  "M" */ CWORD_CWORD_CWORD_CWORD,
3097        /*  78  "N" */ CWORD_CWORD_CWORD_CWORD,
3098        /*  79  "O" */ CWORD_CWORD_CWORD_CWORD,
3099        /*  80  "P" */ CWORD_CWORD_CWORD_CWORD,
3100        /*  81  "Q" */ CWORD_CWORD_CWORD_CWORD,
3101        /*  82  "R" */ CWORD_CWORD_CWORD_CWORD,
3102        /*  83  "S" */ CWORD_CWORD_CWORD_CWORD,
3103        /*  84  "T" */ CWORD_CWORD_CWORD_CWORD,
3104        /*  85  "U" */ CWORD_CWORD_CWORD_CWORD,
3105        /*  86  "V" */ CWORD_CWORD_CWORD_CWORD,
3106        /*  87  "W" */ CWORD_CWORD_CWORD_CWORD,
3107        /*  88  "X" */ CWORD_CWORD_CWORD_CWORD,
3108        /*  89  "Y" */ CWORD_CWORD_CWORD_CWORD,
3109        /*  90  "Z" */ CWORD_CWORD_CWORD_CWORD,
3110        /*  91  "[" */ CWORD_CCTL_CCTL_CWORD,
3111        /*  92  "\" */ CBACK_CBACK_CCTL_CBACK,
3112        /*  93  "]" */ CWORD_CCTL_CCTL_CWORD,
3113        /*  94  "^" */ CWORD_CWORD_CWORD_CWORD,
3114        /*  95  "_" */ CWORD_CWORD_CWORD_CWORD,
3115        /*  96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3116        /*  97  "a" */ CWORD_CWORD_CWORD_CWORD,
3117        /*  98  "b" */ CWORD_CWORD_CWORD_CWORD,
3118        /*  99  "c" */ CWORD_CWORD_CWORD_CWORD,
3119        /* 100  "d" */ CWORD_CWORD_CWORD_CWORD,
3120        /* 101  "e" */ CWORD_CWORD_CWORD_CWORD,
3121        /* 102  "f" */ CWORD_CWORD_CWORD_CWORD,
3122        /* 103  "g" */ CWORD_CWORD_CWORD_CWORD,
3123        /* 104  "h" */ CWORD_CWORD_CWORD_CWORD,
3124        /* 105  "i" */ CWORD_CWORD_CWORD_CWORD,
3125        /* 106  "j" */ CWORD_CWORD_CWORD_CWORD,
3126        /* 107  "k" */ CWORD_CWORD_CWORD_CWORD,
3127        /* 108  "l" */ CWORD_CWORD_CWORD_CWORD,
3128        /* 109  "m" */ CWORD_CWORD_CWORD_CWORD,
3129        /* 110  "n" */ CWORD_CWORD_CWORD_CWORD,
3130        /* 111  "o" */ CWORD_CWORD_CWORD_CWORD,
3131        /* 112  "p" */ CWORD_CWORD_CWORD_CWORD,
3132        /* 113  "q" */ CWORD_CWORD_CWORD_CWORD,
3133        /* 114  "r" */ CWORD_CWORD_CWORD_CWORD,
3134        /* 115  "s" */ CWORD_CWORD_CWORD_CWORD,
3135        /* 116  "t" */ CWORD_CWORD_CWORD_CWORD,
3136        /* 117  "u" */ CWORD_CWORD_CWORD_CWORD,
3137        /* 118  "v" */ CWORD_CWORD_CWORD_CWORD,
3138        /* 119  "w" */ CWORD_CWORD_CWORD_CWORD,
3139        /* 120  "x" */ CWORD_CWORD_CWORD_CWORD,
3140        /* 121  "y" */ CWORD_CWORD_CWORD_CWORD,
3141        /* 122  "z" */ CWORD_CWORD_CWORD_CWORD,
3142        /* 123  "{" */ CWORD_CWORD_CWORD_CWORD,
3143        /* 124  "|" */ CSPCL_CWORD_CWORD_CWORD,
3144        /* 125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3145        /* 126  "~" */ CWORD_CCTL_CCTL_CWORD,
3146        /* 127  del */ CWORD_CWORD_CWORD_CWORD,
3147        /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3148        /* 129 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
3149        /* 130 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
3150        /* 131 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
3151        /* 132 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
3152        /* 133 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
3153        /* 134 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
3154        /* 135 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
3155        /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3156        /* 137      */ CWORD_CWORD_CWORD_CWORD,
3157        /* 138      */ CWORD_CWORD_CWORD_CWORD,
3158        /* 139      */ CWORD_CWORD_CWORD_CWORD,
3159        /* 140      */ CWORD_CWORD_CWORD_CWORD,
3160        /* 141      */ CWORD_CWORD_CWORD_CWORD,
3161        /* 142      */ CWORD_CWORD_CWORD_CWORD,
3162        /* 143      */ CWORD_CWORD_CWORD_CWORD,
3163        /* 144      */ CWORD_CWORD_CWORD_CWORD,
3164        /* 145      */ CWORD_CWORD_CWORD_CWORD,
3165        /* 146      */ CWORD_CWORD_CWORD_CWORD,
3166        /* 147      */ CWORD_CWORD_CWORD_CWORD,
3167        /* 148      */ CWORD_CWORD_CWORD_CWORD,
3168        /* 149      */ CWORD_CWORD_CWORD_CWORD,
3169        /* 150      */ CWORD_CWORD_CWORD_CWORD,
3170        /* 151      */ CWORD_CWORD_CWORD_CWORD,
3171        /* 152      */ CWORD_CWORD_CWORD_CWORD,
3172        /* 153      */ CWORD_CWORD_CWORD_CWORD,
3173        /* 154      */ CWORD_CWORD_CWORD_CWORD,
3174        /* 155      */ CWORD_CWORD_CWORD_CWORD,
3175        /* 156      */ CWORD_CWORD_CWORD_CWORD,
3176        /* 157      */ CWORD_CWORD_CWORD_CWORD,
3177        /* 158      */ CWORD_CWORD_CWORD_CWORD,
3178        /* 159      */ CWORD_CWORD_CWORD_CWORD,
3179        /* 160      */ CWORD_CWORD_CWORD_CWORD,
3180        /* 161      */ CWORD_CWORD_CWORD_CWORD,
3181        /* 162      */ CWORD_CWORD_CWORD_CWORD,
3182        /* 163      */ CWORD_CWORD_CWORD_CWORD,
3183        /* 164      */ CWORD_CWORD_CWORD_CWORD,
3184        /* 165      */ CWORD_CWORD_CWORD_CWORD,
3185        /* 166      */ CWORD_CWORD_CWORD_CWORD,
3186        /* 167      */ CWORD_CWORD_CWORD_CWORD,
3187        /* 168      */ CWORD_CWORD_CWORD_CWORD,
3188        /* 169      */ CWORD_CWORD_CWORD_CWORD,
3189        /* 170      */ CWORD_CWORD_CWORD_CWORD,
3190        /* 171      */ CWORD_CWORD_CWORD_CWORD,
3191        /* 172      */ CWORD_CWORD_CWORD_CWORD,
3192        /* 173      */ CWORD_CWORD_CWORD_CWORD,
3193        /* 174      */ CWORD_CWORD_CWORD_CWORD,
3194        /* 175      */ CWORD_CWORD_CWORD_CWORD,
3195        /* 176      */ CWORD_CWORD_CWORD_CWORD,
3196        /* 177      */ CWORD_CWORD_CWORD_CWORD,
3197        /* 178      */ CWORD_CWORD_CWORD_CWORD,
3198        /* 179      */ CWORD_CWORD_CWORD_CWORD,
3199        /* 180      */ CWORD_CWORD_CWORD_CWORD,
3200        /* 181      */ CWORD_CWORD_CWORD_CWORD,
3201        /* 182      */ CWORD_CWORD_CWORD_CWORD,
3202        /* 183      */ CWORD_CWORD_CWORD_CWORD,
3203        /* 184      */ CWORD_CWORD_CWORD_CWORD,
3204        /* 185      */ CWORD_CWORD_CWORD_CWORD,
3205        /* 186      */ CWORD_CWORD_CWORD_CWORD,
3206        /* 187      */ CWORD_CWORD_CWORD_CWORD,
3207        /* 188      */ CWORD_CWORD_CWORD_CWORD,
3208        /* 189      */ CWORD_CWORD_CWORD_CWORD,
3209        /* 190      */ CWORD_CWORD_CWORD_CWORD,
3210        /* 191      */ CWORD_CWORD_CWORD_CWORD,
3211        /* 192      */ CWORD_CWORD_CWORD_CWORD,
3212        /* 193      */ CWORD_CWORD_CWORD_CWORD,
3213        /* 194      */ CWORD_CWORD_CWORD_CWORD,
3214        /* 195      */ CWORD_CWORD_CWORD_CWORD,
3215        /* 196      */ CWORD_CWORD_CWORD_CWORD,
3216        /* 197      */ CWORD_CWORD_CWORD_CWORD,
3217        /* 198      */ CWORD_CWORD_CWORD_CWORD,
3218        /* 199      */ CWORD_CWORD_CWORD_CWORD,
3219        /* 200      */ CWORD_CWORD_CWORD_CWORD,
3220        /* 201      */ CWORD_CWORD_CWORD_CWORD,
3221        /* 202      */ CWORD_CWORD_CWORD_CWORD,
3222        /* 203      */ CWORD_CWORD_CWORD_CWORD,
3223        /* 204      */ CWORD_CWORD_CWORD_CWORD,
3224        /* 205      */ CWORD_CWORD_CWORD_CWORD,
3225        /* 206      */ CWORD_CWORD_CWORD_CWORD,
3226        /* 207      */ CWORD_CWORD_CWORD_CWORD,
3227        /* 208      */ CWORD_CWORD_CWORD_CWORD,
3228        /* 209      */ CWORD_CWORD_CWORD_CWORD,
3229        /* 210      */ CWORD_CWORD_CWORD_CWORD,
3230        /* 211      */ CWORD_CWORD_CWORD_CWORD,
3231        /* 212      */ CWORD_CWORD_CWORD_CWORD,
3232        /* 213      */ CWORD_CWORD_CWORD_CWORD,
3233        /* 214      */ CWORD_CWORD_CWORD_CWORD,
3234        /* 215      */ CWORD_CWORD_CWORD_CWORD,
3235        /* 216      */ CWORD_CWORD_CWORD_CWORD,
3236        /* 217      */ CWORD_CWORD_CWORD_CWORD,
3237        /* 218      */ CWORD_CWORD_CWORD_CWORD,
3238        /* 219      */ CWORD_CWORD_CWORD_CWORD,
3239        /* 220      */ CWORD_CWORD_CWORD_CWORD,
3240        /* 221      */ CWORD_CWORD_CWORD_CWORD,
3241        /* 222      */ CWORD_CWORD_CWORD_CWORD,
3242        /* 223      */ CWORD_CWORD_CWORD_CWORD,
3243        /* 224      */ CWORD_CWORD_CWORD_CWORD,
3244        /* 225      */ CWORD_CWORD_CWORD_CWORD,
3245        /* 226      */ CWORD_CWORD_CWORD_CWORD,
3246        /* 227      */ CWORD_CWORD_CWORD_CWORD,
3247        /* 228      */ CWORD_CWORD_CWORD_CWORD,
3248        /* 229      */ CWORD_CWORD_CWORD_CWORD,
3249        /* 230      */ CWORD_CWORD_CWORD_CWORD,
3250        /* 231      */ CWORD_CWORD_CWORD_CWORD,
3251        /* 232      */ CWORD_CWORD_CWORD_CWORD,
3252        /* 233      */ CWORD_CWORD_CWORD_CWORD,
3253        /* 234      */ CWORD_CWORD_CWORD_CWORD,
3254        /* 235      */ CWORD_CWORD_CWORD_CWORD,
3255        /* 236      */ CWORD_CWORD_CWORD_CWORD,
3256        /* 237      */ CWORD_CWORD_CWORD_CWORD,
3257        /* 238      */ CWORD_CWORD_CWORD_CWORD,
3258        /* 239      */ CWORD_CWORD_CWORD_CWORD,
3259        /* 230      */ CWORD_CWORD_CWORD_CWORD,
3260        /* 241      */ CWORD_CWORD_CWORD_CWORD,
3261        /* 242      */ CWORD_CWORD_CWORD_CWORD,
3262        /* 243      */ CWORD_CWORD_CWORD_CWORD,
3263        /* 244      */ CWORD_CWORD_CWORD_CWORD,
3264        /* 245      */ CWORD_CWORD_CWORD_CWORD,
3265        /* 246      */ CWORD_CWORD_CWORD_CWORD,
3266        /* 247      */ CWORD_CWORD_CWORD_CWORD,
3267        /* 248      */ CWORD_CWORD_CWORD_CWORD,
3268        /* 249      */ CWORD_CWORD_CWORD_CWORD,
3269        /* 250      */ CWORD_CWORD_CWORD_CWORD,
3270        /* 251      */ CWORD_CWORD_CWORD_CWORD,
3271        /* 252      */ CWORD_CWORD_CWORD_CWORD,
3272        /* 253      */ CWORD_CWORD_CWORD_CWORD,
3273        /* 254      */ CWORD_CWORD_CWORD_CWORD,
3274        /* 255      */ CWORD_CWORD_CWORD_CWORD,
3275        /* PEOF */     CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3276# if ENABLE_ASH_ALIAS
3277        /* PEOA */     CSPCL_CIGN_CIGN_CIGN,
3278# endif
3279};
3280
3281#if 1
3282# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3283#else /* debug version, caught one signed char bug */
3284# define SIT(c, syntax) \
3285        ({ \
3286                if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3287                        bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3288                if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3289                        bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3290                ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3291        })
3292#endif
3293
3294#endif  /* !USE_SIT_FUNCTION */
3295
3296
3297/* ============ Alias handling */
3298
3299#if ENABLE_ASH_ALIAS
3300
3301#define ALIASINUSE 1
3302#define ALIASDEAD  2
3303
3304struct alias {
3305        struct alias *next;
3306        char *name;
3307        char *val;
3308        int flag;
3309};
3310
3311
3312static struct alias **atab; // [ATABSIZE];
3313#define INIT_G_alias() do { \
3314        atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3315} while (0)
3316
3317
3318static struct alias **
3319__lookupalias(const char *name)
3320{
3321        unsigned int hashval;
3322        struct alias **app;
3323        const char *p;
3324        unsigned int ch;
3325
3326        p = name;
3327
3328        ch = (unsigned char)*p;
3329        hashval = ch << 4;
3330        while (ch) {
3331                hashval += ch;
3332                ch = (unsigned char)*++p;
3333        }
3334        app = &atab[hashval % ATABSIZE];
3335
3336        for (; *app; app = &(*app)->next) {
3337                if (strcmp(name, (*app)->name) == 0) {
3338                        break;
3339                }
3340        }
3341
3342        return app;
3343}
3344
3345static struct alias *
3346lookupalias(const char *name, int check)
3347{
3348        struct alias *ap = *__lookupalias(name);
3349
3350        if (check && ap && (ap->flag & ALIASINUSE))
3351                return NULL;
3352        return ap;
3353}
3354
3355static struct alias *
3356freealias(struct alias *ap)
3357{
3358        struct alias *next;
3359
3360        if (ap->flag & ALIASINUSE) {
3361                ap->flag |= ALIASDEAD;
3362                return ap;
3363        }
3364
3365        next = ap->next;
3366        free(ap->name);
3367        free(ap->val);
3368        free(ap);
3369        return next;
3370}
3371
3372static void
3373setalias(const char *name, const char *val)
3374{
3375        struct alias *ap, **app;
3376
3377        app = __lookupalias(name);
3378        ap = *app;
3379        INT_OFF;
3380        if (ap) {
3381                if (!(ap->flag & ALIASINUSE)) {
3382                        free(ap->val);
3383                }
3384                ap->val = ckstrdup(val);
3385                ap->flag &= ~ALIASDEAD;
3386        } else {
3387                /* not found */
3388                ap = ckzalloc(sizeof(struct alias));
3389                ap->name = ckstrdup(name);
3390                ap->val = ckstrdup(val);
3391                /*ap->flag = 0; - ckzalloc did it */
3392                /*ap->next = NULL;*/
3393                *app = ap;
3394        }
3395        INT_ON;
3396}
3397
3398static int
3399unalias(const char *name)
3400{
3401        struct alias **app;
3402
3403        app = __lookupalias(name);
3404
3405        if (*app) {
3406                INT_OFF;
3407                *app = freealias(*app);
3408                INT_ON;
3409                return 0;
3410        }
3411
3412        return 1;
3413}
3414
3415static void
3416rmaliases(void)
3417{
3418        struct alias *ap, **app;
3419        int i;
3420
3421        INT_OFF;
3422        for (i = 0; i < ATABSIZE; i++) {
3423                app = &atab[i];
3424                for (ap = *app; ap; ap = *app) {
3425                        *app = freealias(*app);
3426                        if (ap == *app) {
3427                                app = &ap->next;
3428                        }
3429                }
3430        }
3431        INT_ON;
3432}
3433
3434static void
3435printalias(const struct alias *ap)
3436{
3437        out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3438}
3439
3440/*
3441 * TODO - sort output
3442 */
3443static int FAST_FUNC
3444aliascmd(int argc UNUSED_PARAM, char **argv)
3445{
3446        char *n, *v;
3447        int ret = 0;
3448        struct alias *ap;
3449
3450        if (!argv[1]) {
3451                int i;
3452
3453                for (i = 0; i < ATABSIZE; i++) {
3454                        for (ap = atab[i]; ap; ap = ap->next) {
3455                                printalias(ap);
3456                        }
3457                }
3458                return 0;
3459        }
3460        while ((n = *++argv) != NULL) {
3461                v = strchr(n+1, '=');
3462                if (v == NULL) { /* n+1: funny ksh stuff */
3463                        ap = *__lookupalias(n);
3464                        if (ap == NULL) {
3465                                fprintf(stderr, "%s: %s not found\n", "alias", n);
3466                                ret = 1;
3467                        } else
3468                                printalias(ap);
3469                } else {
3470                        *v++ = '\0';
3471                        setalias(n, v);
3472                }
3473        }
3474
3475        return ret;
3476}
3477
3478static int FAST_FUNC
3479unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3480{
3481        int i;
3482
3483        while (nextopt("a") != '\0') {
3484                rmaliases();
3485                return 0;
3486        }
3487        for (i = 0; *argptr; argptr++) {
3488                if (unalias(*argptr)) {
3489                        fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3490                        i = 1;
3491                }
3492        }
3493
3494        return i;
3495}
3496
3497#endif /* ASH_ALIAS */
3498
3499
3500/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
3501#define FORK_FG    0
3502#define FORK_BG    1
3503#define FORK_NOJOB 2
3504
3505/* mode flags for showjob(s) */
3506#define SHOW_ONLY_PGID  0x01    /* show only pgid (jobs -p) */
3507#define SHOW_PIDS       0x02    /* show individual pids, not just one line per job */
3508#define SHOW_CHANGED    0x04    /* only jobs whose state has changed */
3509#define SHOW_STDERR     0x08    /* print to stderr (else stdout) */
3510
3511/*
3512 * A job structure contains information about a job.  A job is either a
3513 * single process or a set of processes contained in a pipeline.  In the
3514 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3515 * array of pids.
3516 */
3517struct procstat {
3518        pid_t   ps_pid;         /* process id */
3519        int     ps_status;      /* last process status from wait() */
3520        char    *ps_cmd;        /* text of command being run */
3521};
3522
3523struct job {
3524        struct procstat ps0;    /* status of process */
3525        struct procstat *ps;    /* status or processes when more than one */
3526#if JOBS
3527        int stopstatus;         /* status of a stopped job */
3528#endif
3529        unsigned nprocs;        /* number of processes */
3530
3531#define JOBRUNNING      0       /* at least one proc running */
3532#define JOBSTOPPED      1       /* all procs are stopped */
3533#define JOBDONE         2       /* all procs are completed */
3534        unsigned
3535                state: 8,
3536#if JOBS
3537                sigint: 1,      /* job was killed by SIGINT */
3538                jobctl: 1,      /* job running under job control */
3539#endif
3540                waited: 1,      /* true if this entry has been waited for */
3541                used: 1,        /* true if this entry is in used */
3542                changed: 1;     /* true if status has changed */
3543        struct job *prev_job;   /* previous job */
3544};
3545
3546static struct job *makejob(/*union node *,*/ int);
3547static int forkshell(struct job *, union node *, int);
3548static int waitforjob(struct job *);
3549
3550#if !JOBS
3551enum { doing_jobctl = 0 };
3552#define setjobctl(on) do {} while (0)
3553#else
3554static smallint doing_jobctl; //references:8
3555static void setjobctl(int);
3556#endif
3557
3558/*
3559 * Ignore a signal.
3560 */
3561static void
3562ignoresig(int signo)
3563{
3564        /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3565        if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3566                /* No, need to do it */
3567                signal(signo, SIG_IGN);
3568        }
3569        sigmode[signo - 1] = S_HARD_IGN;
3570}
3571
3572/*
3573 * Only one usage site - in setsignal()
3574 */
3575static void
3576signal_handler(int signo)
3577{
3578        if (signo == SIGCHLD) {
3579                got_sigchld = 1;
3580                if (!trap[SIGCHLD])
3581                        return;
3582        }
3583
3584        gotsig[signo - 1] = 1;
3585        pending_sig = signo;
3586
3587        if (signo == SIGINT && !trap[SIGINT]) {
3588                if (!suppress_int) {
3589                        pending_sig = 0;
3590                        raise_interrupt(); /* does not return */
3591                }
3592                pending_int = 1;
3593        }
3594}
3595
3596/*
3597 * Set the signal handler for the specified signal.  The routine figures
3598 * out what it should be set to.
3599 */
3600static void
3601setsignal(int signo)
3602{
3603        char *t;
3604        char cur_act, new_act;
3605        struct sigaction act;
3606
3607        t = trap[signo];
3608        new_act = S_DFL;
3609        if (t != NULL) { /* trap for this sig is set */
3610                new_act = S_CATCH;
3611                if (t[0] == '\0') /* trap is "": ignore this sig */
3612                        new_act = S_IGN;
3613        }
3614
3615        if (rootshell && new_act == S_DFL) {
3616                switch (signo) {
3617                case SIGINT:
3618                        if (iflag || minusc || sflag == 0)
3619                                new_act = S_CATCH;
3620                        break;
3621                case SIGQUIT:
3622#if DEBUG
3623                        if (debug)
3624                                break;
3625#endif
3626                        /* man bash:
3627                         * "In all cases, bash ignores SIGQUIT. Non-builtin
3628                         * commands run by bash have signal handlers
3629                         * set to the values inherited by the shell
3630                         * from its parent". */
3631                        new_act = S_IGN;
3632                        break;
3633                case SIGTERM:
3634                        if (iflag)
3635                                new_act = S_IGN;
3636                        break;
3637#if JOBS
3638                case SIGTSTP:
3639                case SIGTTOU:
3640                        if (mflag)
3641                                new_act = S_IGN;
3642                        break;
3643#endif
3644                }
3645        }
3646        /* if !rootshell, we reset SIGQUIT to DFL,
3647         * whereas we have to restore it to what shell got on entry.
3648         * This is handled by the fact that if signal was IGNored on entry,
3649         * then cur_act is S_HARD_IGN and we never change its sigaction
3650         * (see code below).
3651         */
3652
3653        if (signo == SIGCHLD)
3654                new_act = S_CATCH;
3655
3656        t = &sigmode[signo - 1];
3657        cur_act = *t;
3658        if (cur_act == 0) {
3659                /* current setting is not yet known */
3660                if (sigaction(signo, NULL, &act)) {
3661                        /* pretend it worked; maybe we should give a warning,
3662                         * but other shells don't. We don't alter sigmode,
3663                         * so we retry every time.
3664                         * btw, in Linux it never fails. --vda */
3665                        return;
3666                }
3667                if (act.sa_handler == SIG_IGN) {
3668                        cur_act = S_HARD_IGN;
3669                        if (mflag
3670                         && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3671                        ) {
3672                                cur_act = S_IGN;   /* don't hard ignore these */
3673                        }
3674                }
3675                if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3676                        /* installing SIG_DFL over SIG_DFL is a no-op */
3677                        /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3678                        *t = S_DFL;
3679                        return;
3680                }
3681        }
3682        if (cur_act == S_HARD_IGN || cur_act == new_act)
3683                return;
3684
3685        *t = new_act;
3686
3687        act.sa_handler = SIG_DFL;
3688        switch (new_act) {
3689        case S_CATCH:
3690                act.sa_handler = signal_handler;
3691                break;
3692        case S_IGN:
3693                act.sa_handler = SIG_IGN;
3694                break;
3695        }
3696        /* flags and mask matter only if !DFL and !IGN, but we do it
3697         * for all cases for more deterministic behavior:
3698         */
3699        act.sa_flags = 0; //TODO: why not SA_RESTART?
3700        sigfillset(&act.sa_mask);
3701
3702        sigaction_set(signo, &act);
3703}
3704
3705/* mode flags for set_curjob */
3706#define CUR_DELETE 2
3707#define CUR_RUNNING 1
3708#define CUR_STOPPED 0
3709
3710#if JOBS
3711/* pgrp of shell on invocation */
3712static int initialpgrp; //references:2
3713static int ttyfd = -1; //5
3714#endif
3715/* array of jobs */
3716static struct job *jobtab; //5
3717/* size of array */
3718static unsigned njobs; //4
3719/* current job */
3720static struct job *curjob; //lots
3721/* number of presumed living untracked jobs */
3722static int jobless; //4
3723
3724#if 0
3725/* Bash has a feature: it restores termios after a successful wait for
3726 * a foreground job which had at least one stopped or sigkilled member.
3727 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3728 * properly restoring tty state. Should we do this too?
3729 * A reproducer: ^Z an interactive python:
3730 *
3731 * # python
3732 * Python 2.7.12 (...)
3733 * >>> ^Z
3734 *      { python leaves tty in -icanon -echo state. We do survive that... }
3735 *  [1]+  Stopped                    python
3736 *      { ...however, next program (python #2) does not survive it well: }
3737 * # python
3738 * Python 2.7.12 (...)
3739 * >>> Traceback (most recent call last):
3740 *      { above, I typed "qwerty<CR>", but -echo state is still in effect }
3741 *   File "<stdin>", line 1, in <module>
3742 * NameError: name 'qwerty' is not defined
3743 *
3744 * The implementation below is modeled on bash code and seems to work.
3745 * However, I'm not sure we should do this. For one: what if I'd fg
3746 * the stopped python instead? It'll be confused by "restored" tty state.
3747 */
3748static struct termios shell_tty_info;
3749static void
3750get_tty_state(void)
3751{
3752        if (rootshell && ttyfd >= 0)
3753                tcgetattr(ttyfd, &shell_tty_info);
3754}
3755static void
3756set_tty_state(void)
3757{
3758        /* if (rootshell) - caller ensures this */
3759        if (ttyfd >= 0)
3760                tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3761}
3762static int
3763job_signal_status(struct job *jp)
3764{
3765        int status;
3766        unsigned i;
3767        struct procstat *ps = jp->ps;
3768        for (i = 0; i < jp->nprocs; i++) {
3769                status = ps[i].ps_status;
3770                if (WIFSIGNALED(status) || WIFSTOPPED(status))
3771                        return status;
3772        }
3773        return 0;
3774}
3775static void
3776restore_tty_if_stopped_or_signaled(struct job *jp)
3777{
3778//TODO: check what happens if we come from waitforjob() in expbackq()
3779        if (rootshell) {
3780                int s = job_signal_status(jp);
3781                if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3782                        set_tty_state();
3783        }
3784}
3785#else
3786# define get_tty_state() ((void)0)
3787# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3788#endif
3789
3790static void
3791set_curjob(struct job *jp, unsigned mode)
3792{
3793        struct job *jp1;
3794        struct job **jpp, **curp;
3795
3796        /* first remove from list */
3797        jpp = curp = &curjob;
3798        while (1) {
3799                jp1 = *jpp;
3800                if (jp1 == jp)
3801                        break;
3802                jpp = &jp1->prev_job;
3803        }
3804        *jpp = jp1->prev_job;
3805
3806        /* Then re-insert in correct position */
3807        jpp = curp;
3808        switch (mode) {
3809        default:
3810#if DEBUG
3811                abort();
3812#endif
3813        case CUR_DELETE:
3814                /* job being deleted */
3815                break;
3816        case CUR_RUNNING:
3817                /* newly created job or backgrounded job,
3818                 * put after all stopped jobs.
3819                 */
3820                while (1) {
3821                        jp1 = *jpp;
3822#if JOBS
3823                        if (!jp1 || jp1->state != JOBSTOPPED)
3824#endif
3825                                break;
3826                        jpp = &jp1->prev_job;
3827                }
3828                /* FALLTHROUGH */
3829#if JOBS
3830        case CUR_STOPPED:
3831#endif
3832                /* newly stopped job - becomes curjob */
3833                jp->prev_job = *jpp;
3834                *jpp = jp;
3835                break;
3836        }
3837}
3838
3839#if JOBS || DEBUG
3840static int
3841jobno(const struct job *jp)
3842{
3843        return jp - jobtab + 1;
3844}
3845#endif
3846
3847/*
3848 * Convert a job name to a job structure.
3849 */
3850#if !JOBS
3851#define getjob(name, getctl) getjob(name)
3852#endif
3853static struct job *
3854getjob(const char *name, int getctl)
3855{
3856        struct job *jp;
3857        struct job *found;
3858        const char *err_msg = "%s: no such job";
3859        unsigned num;
3860        int c;
3861        const char *p;
3862        char *(*match)(const char *, const char *);
3863
3864        jp = curjob;
3865        p = name;
3866        if (!p)
3867                goto currentjob;
3868
3869        if (*p != '%')
3870                goto err;
3871
3872        c = *++p;
3873        if (!c)
3874                goto currentjob;
3875
3876        if (!p[1]) {
3877                if (c == '+' || c == '%') {
3878 currentjob:
3879                        err_msg = "No current job";
3880                        goto check;
3881                }
3882                if (c == '-') {
3883                        if (jp)
3884                                jp = jp->prev_job;
3885                        err_msg = "No previous job";
3886 check:
3887                        if (!jp)
3888                                goto err;
3889                        goto gotit;
3890                }
3891        }
3892
3893        if (is_number(p)) {
3894                num = atoi(p);
3895                if (num > 0 && num <= njobs) {
3896                        jp = jobtab + num - 1;
3897                        if (jp->used)
3898                                goto gotit;
3899                        goto err;
3900                }
3901        }
3902
3903        match = prefix;
3904        if (*p == '?') {
3905                match = strstr;
3906                p++;
3907        }
3908
3909        found = NULL;
3910        while (jp) {
3911                if (match(jp->ps[0].ps_cmd, p)) {
3912                        if (found)
3913                                goto err;
3914                        found = jp;
3915                        err_msg = "%s: ambiguous";
3916                }
3917                jp = jp->prev_job;
3918        }
3919        if (!found)
3920                goto err;
3921        jp = found;
3922
3923 gotit:
3924#if JOBS
3925        err_msg = "job %s not created under job control";
3926        if (getctl && jp->jobctl == 0)
3927                goto err;
3928#endif
3929        return jp;
3930 err:
3931        ash_msg_and_raise_error(err_msg, name);
3932}
3933
3934/*
3935 * Mark a job structure as unused.
3936 */
3937static void
3938freejob(struct job *jp)
3939{
3940        struct procstat *ps;
3941        int i;
3942
3943        INT_OFF;
3944        for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3945                if (ps->ps_cmd != nullstr)
3946                        free(ps->ps_cmd);
3947        }
3948        if (jp->ps != &jp->ps0)
3949                free(jp->ps);
3950        jp->used = 0;
3951        set_curjob(jp, CUR_DELETE);
3952        INT_ON;
3953}
3954
3955#if JOBS
3956static void
3957xtcsetpgrp(int fd, pid_t pgrp)
3958{
3959        if (tcsetpgrp(fd, pgrp))
3960                ash_msg_and_raise_perror("can't set tty process group");
3961}
3962
3963/*
3964 * Turn job control on and off.
3965 *
3966 * Note:  This code assumes that the third arg to ioctl is a character
3967 * pointer, which is true on Berkeley systems but not System V.  Since
3968 * System V doesn't have job control yet, this isn't a problem now.
3969 *
3970 * Called with interrupts off.
3971 */
3972static void
3973setjobctl(int on)
3974{
3975        int fd;
3976        int pgrp;
3977
3978        if (on == doing_jobctl || rootshell == 0)
3979                return;
3980        if (on) {
3981                int ofd;
3982                ofd = fd = open(_PATH_TTY, O_RDWR);
3983                if (fd < 0) {
3984        /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3985         * That sometimes helps to acquire controlling tty.
3986         * Obviously, a workaround for bugs when someone
3987         * failed to provide a controlling tty to bash! :) */
3988                        fd = 2;
3989                        while (!isatty(fd))
3990                                if (--fd < 0)
3991                                        goto out;
3992                }
3993                /* fd is a tty at this point */
3994                fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
3995                if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
3996                        close(ofd);
3997                if (fd < 0)
3998                        goto out; /* F_DUPFD failed */
3999                if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
4000                        close_on_exec_on(fd);
4001                while (1) { /* while we are in the background */
4002                        pgrp = tcgetpgrp(fd);
4003                        if (pgrp < 0) {
4004 out:
4005                                ash_msg("can't access tty; job control turned off");
4006                                mflag = on = 0;
4007                                goto close;
4008                        }
4009                        if (pgrp == getpgrp())
4010                                break;
4011                        killpg(0, SIGTTIN);
4012                }
4013                initialpgrp = pgrp;
4014
4015                setsignal(SIGTSTP);
4016                setsignal(SIGTTOU);
4017                setsignal(SIGTTIN);
4018                pgrp = rootpid;
4019                setpgid(0, pgrp);
4020                xtcsetpgrp(fd, pgrp);
4021        } else {
4022                /* turning job control off */
4023                fd = ttyfd;
4024                pgrp = initialpgrp;
4025                /* was xtcsetpgrp, but this can make exiting ash
4026                 * loop forever if pty is already deleted */
4027                tcsetpgrp(fd, pgrp);
4028                setpgid(0, pgrp);
4029                setsignal(SIGTSTP);
4030                setsignal(SIGTTOU);
4031                setsignal(SIGTTIN);
4032 close:
4033                if (fd >= 0)
4034                        close(fd);
4035                fd = -1;
4036        }
4037        ttyfd = fd;
4038        doing_jobctl = on;
4039}
4040
4041static int FAST_FUNC
4042killcmd(int argc, char **argv)
4043{
4044        if (argv[1] && strcmp(argv[1], "-l") != 0) {
4045                int i = 1;
4046                do {
4047                        if (argv[i][0] == '%') {
4048                                /*
4049                                 * "kill %N" - job kill
4050                                 * Converting to pgrp / pid kill
4051                                 */
4052                                struct job *jp;
4053                                char *dst;
4054                                int j, n;
4055
4056                                jp = getjob(argv[i], 0);
4057                                /*
4058                                 * In jobs started under job control, we signal
4059                                 * entire process group by kill -PGRP_ID.
4060                                 * This happens, f.e., in interactive shell.
4061                                 *
4062                                 * Otherwise, we signal each child via
4063                                 * kill PID1 PID2 PID3.
4064                                 * Testcases:
4065                                 * sh -c 'sleep 1|sleep 1 & kill %1'
4066                                 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4067                                 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4068                                 */
4069                                n = jp->nprocs; /* can't be 0 (I hope) */
4070                                if (jp->jobctl)
4071                                        n = 1;
4072                                dst = alloca(n * sizeof(int)*4);
4073                                argv[i] = dst;
4074                                for (j = 0; j < n; j++) {
4075                                        struct procstat *ps = &jp->ps[j];
4076                                        /* Skip non-running and not-stopped members
4077                                         * (i.e. dead members) of the job
4078                                         */
4079                                        if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4080                                                continue;
4081                                        /*
4082                                         * kill_main has matching code to expect
4083                                         * leading space. Needed to not confuse
4084                                         * negative pids with "kill -SIGNAL_NO" syntax
4085                                         */
4086                                        dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4087                                }
4088                                *dst = '\0';
4089                        }
4090                } while (argv[++i]);
4091        }
4092        return kill_main(argc, argv);
4093}
4094
4095static void
4096showpipe(struct job *jp /*, FILE *out*/)
4097{
4098        struct procstat *ps;
4099        struct procstat *psend;
4100
4101        psend = jp->ps + jp->nprocs;
4102        for (ps = jp->ps + 1; ps < psend; ps++)
4103                printf(" | %s", ps->ps_cmd);
4104        newline_and_flush(stdout);
4105        flush_stdout_stderr();
4106}
4107
4108
4109static int
4110restartjob(struct job *jp, int mode)
4111{
4112        struct procstat *ps;
4113        int i;
4114        int status;
4115        pid_t pgid;
4116
4117        INT_OFF;
4118        if (jp->state == JOBDONE)
4119                goto out;
4120        jp->state = JOBRUNNING;
4121        pgid = jp->ps[0].ps_pid;
4122        if (mode == FORK_FG) {
4123                get_tty_state();
4124                xtcsetpgrp(ttyfd, pgid);
4125        }
4126        killpg(pgid, SIGCONT);
4127        ps = jp->ps;
4128        i = jp->nprocs;
4129        do {
4130                if (WIFSTOPPED(ps->ps_status)) {
4131                        ps->ps_status = -1;
4132                }
4133                ps++;
4134        } while (--i);
4135 out:
4136        status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4137        INT_ON;
4138        return status;
4139}
4140
4141static int FAST_FUNC
4142fg_bgcmd(int argc UNUSED_PARAM, char **argv)
4143{
4144        struct job *jp;
4145        int mode;
4146        int retval;
4147
4148        mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4149        nextopt(nullstr);
4150        argv = argptr;
4151        do {
4152                jp = getjob(*argv, 1);
4153                if (mode == FORK_BG) {
4154                        set_curjob(jp, CUR_RUNNING);
4155                        printf("[%d] ", jobno(jp));
4156                }
4157                out1str(jp->ps[0].ps_cmd);
4158                showpipe(jp /*, stdout*/);
4159                retval = restartjob(jp, mode);
4160        } while (*argv && *++argv);
4161        return retval;
4162}
4163#endif
4164
4165static int
4166sprint_status48(char *s, int status, int sigonly)
4167{
4168        int col;
4169        int st;
4170
4171        col = 0;
4172        if (!WIFEXITED(status)) {
4173#if JOBS
4174                if (WIFSTOPPED(status))
4175                        st = WSTOPSIG(status);
4176                else
4177#endif
4178                        st = WTERMSIG(status);
4179                if (sigonly) {
4180                        if (st == SIGINT || st == SIGPIPE)
4181                                goto out;
4182#if JOBS
4183                        if (WIFSTOPPED(status))
4184                                goto out;
4185#endif
4186                }
4187                st &= 0x7f;
4188//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
4189                col = fmtstr(s, 32, strsignal(st));
4190                if (WCOREDUMP(status)) {
4191                        strcpy(s + col, " (core dumped)");
4192                        col += sizeof(" (core dumped)")-1;
4193                }
4194        } else if (!sigonly) {
4195                st = WEXITSTATUS(status);
4196                col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
4197        }
4198 out:
4199        return col;
4200}
4201
4202static int
4203wait_block_or_sig(int *status)
4204{
4205        int pid;
4206
4207        do {
4208                sigset_t mask;
4209
4210                /* Poll all children for changes in their state */
4211                got_sigchld = 0;
4212                /* if job control is active, accept stopped processes too */
4213                pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
4214                if (pid != 0)
4215                        break; /* Error (e.g. EINTR, ECHILD) or pid */
4216
4217                /* Children exist, but none are ready. Sleep until interesting signal */
4218#if 1
4219                sigfillset(&mask);
4220                sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */
4221                while (!got_sigchld && !pending_sig)
4222                        sigsuspend(&mask);
4223                sigprocmask(SIG_SETMASK, &mask, NULL);
4224#else /* unsafe: a signal can set pending_sig after check, but before pause() */
4225                while (!got_sigchld && !pending_sig)
4226                        pause();
4227#endif
4228
4229                /* If it was SIGCHLD, poll children again */
4230        } while (got_sigchld);
4231
4232        return pid;
4233}
4234
4235#define DOWAIT_NONBLOCK 0
4236#define DOWAIT_BLOCK    1
4237#define DOWAIT_BLOCK_OR_SIG 2
4238
4239static int
4240dowait(int block, struct job *job)
4241{
4242        int pid;
4243        int status;
4244        struct job *jp;
4245        struct job *thisjob = NULL;
4246
4247        TRACE(("dowait(0x%x) called\n", block));
4248
4249        /* It's wrong to call waitpid() outside of INT_OFF region:
4250         * signal can arrive just after syscall return and handler can
4251         * longjmp away, losing stop/exit notification processing.
4252         * Thus, for "jobs" builtin, and for waiting for a fg job,
4253         * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4254         *
4255         * However, for "wait" builtin it is wrong to simply call waitpid()
4256         * in INT_OFF region: "wait" needs to wait for any running job
4257         * to change state, but should exit on any trap too.
4258         * In INT_OFF region, a signal just before syscall entry can set
4259         * pending_sig variables, but we can't check them, and we would
4260         * either enter a sleeping waitpid() (BUG), or need to busy-loop.
4261         *
4262         * Because of this, we run inside INT_OFF, but use a special routine
4263         * which combines waitpid() and sigsuspend().
4264         * This is the reason why we need to have a handler for SIGCHLD:
4265         * SIG_DFL handler does not wake sigsuspend().
4266         */
4267        INT_OFF;
4268        if (block == DOWAIT_BLOCK_OR_SIG) {
4269                pid = wait_block_or_sig(&status);
4270        } else {
4271                int wait_flags = 0;
4272                if (block == DOWAIT_NONBLOCK)
4273                        wait_flags = WNOHANG;
4274                /* if job control is active, accept stopped processes too */
4275                if (doing_jobctl)
4276                        wait_flags |= WUNTRACED;
4277                /* NB: _not_ safe_waitpid, we need to detect EINTR */
4278                pid = waitpid(-1, &status, wait_flags);
4279        }
4280        TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4281                                pid, status, errno, strerror(errno)));
4282        if (pid <= 0)
4283                goto out;
4284
4285        thisjob = NULL;
4286        for (jp = curjob; jp; jp = jp->prev_job) {
4287                int jobstate;
4288                struct procstat *ps;
4289                struct procstat *psend;
4290                if (jp->state == JOBDONE)
4291                        continue;
4292                jobstate = JOBDONE;
4293                ps = jp->ps;
4294                psend = ps + jp->nprocs;
4295                do {
4296                        if (ps->ps_pid == pid) {
4297                                TRACE(("Job %d: changing status of proc %d "
4298                                        "from 0x%x to 0x%x\n",
4299                                        jobno(jp), pid, ps->ps_status, status));
4300                                ps->ps_status = status;
4301                                thisjob = jp;
4302                        }
4303                        if (ps->ps_status == -1)
4304                                jobstate = JOBRUNNING;
4305#if JOBS
4306                        if (jobstate == JOBRUNNING)
4307                                continue;
4308                        if (WIFSTOPPED(ps->ps_status)) {
4309                                jp->stopstatus = ps->ps_status;
4310                                jobstate = JOBSTOPPED;
4311                        }
4312#endif
4313                } while (++ps < psend);
4314                if (!thisjob)
4315                        continue;
4316
4317                /* Found the job where one of its processes changed its state.
4318                 * Is there at least one live and running process in this job? */
4319                if (jobstate != JOBRUNNING) {
4320                        /* No. All live processes in the job are stopped
4321                         * (JOBSTOPPED) or there are no live processes (JOBDONE)
4322                         */
4323                        thisjob->changed = 1;
4324                        if (thisjob->state != jobstate) {
4325                                TRACE(("Job %d: changing state from %d to %d\n",
4326                                        jobno(thisjob), thisjob->state, jobstate));
4327                                thisjob->state = jobstate;
4328#if JOBS
4329                                if (jobstate == JOBSTOPPED)
4330                                        set_curjob(thisjob, CUR_STOPPED);
4331#endif
4332                        }
4333                }
4334                goto out;
4335        }
4336        /* The process wasn't found in job list */
4337#if JOBS
4338        if (!WIFSTOPPED(status))
4339                jobless--;
4340#endif
4341 out:
4342        INT_ON;
4343
4344        if (thisjob && thisjob == job) {
4345                char s[48 + 1];
4346                int len;
4347
4348                len = sprint_status48(s, status, 1);
4349                if (len) {
4350                        s[len] = '\n';
4351                        s[len + 1] = '\0';
4352                        out2str(s);
4353                }
4354        }
4355        return pid;
4356}
4357
4358#if JOBS
4359static void
4360showjob(struct job *jp, int mode)
4361{
4362        struct procstat *ps;
4363        struct procstat *psend;
4364        int col;
4365        int indent_col;
4366        char s[16 + 16 + 48];
4367        FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4368
4369        ps = jp->ps;
4370
4371        if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4372                /* just output process (group) id of pipeline */
4373                fprintf(out, "%d\n", ps->ps_pid);
4374                return;
4375        }
4376
4377        col = fmtstr(s, 16, "[%d]   ", jobno(jp));
4378        indent_col = col;
4379
4380        if (jp == curjob)
4381                s[col - 3] = '+';
4382        else if (curjob && jp == curjob->prev_job)
4383                s[col - 3] = '-';
4384
4385        if (mode & SHOW_PIDS)
4386                col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4387
4388        psend = ps + jp->nprocs;
4389
4390        if (jp->state == JOBRUNNING) {
4391                strcpy(s + col, "Running");
4392                col += sizeof("Running") - 1;
4393        } else {
4394                int status = psend[-1].ps_status;
4395                if (jp->state == JOBSTOPPED)
4396                        status = jp->stopstatus;
4397                col += sprint_status48(s + col, status, 0);
4398        }
4399        /* By now, "[JOBID]*  [maybe PID] STATUS" is printed */
4400
4401        /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4402         * or prints several "PID             | <cmdN>" lines,
4403         * depending on SHOW_PIDS bit.
4404         * We do not print status of individual processes
4405         * between PID and <cmdN>. bash does it, but not very well:
4406         * first line shows overall job status, not process status,
4407         * making it impossible to know 1st process status.
4408         */
4409        goto start;
4410        do {
4411                /* for each process */
4412                s[0] = '\0';
4413                col = 33;
4414                if (mode & SHOW_PIDS)
4415                        col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4416 start:
4417                fprintf(out, "%s%*c%s%s",
4418                                s,
4419                                33 - col >= 0 ? 33 - col : 0, ' ',
4420                                ps == jp->ps ? "" : "| ",
4421                                ps->ps_cmd
4422                );
4423        } while (++ps != psend);
4424        newline_and_flush(out);
4425
4426        jp->changed = 0;
4427
4428        if (jp->state == JOBDONE) {
4429                TRACE(("showjob: freeing job %d\n", jobno(jp)));
4430                freejob(jp);
4431        }
4432}
4433
4434/*
4435 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
4436 * statuses have changed since the last call to showjobs.
4437 */
4438static void
4439showjobs(int mode)
4440{
4441        struct job *jp;
4442
4443        TRACE(("showjobs(0x%x) called\n", mode));
4444
4445        /* Handle all finished jobs */
4446        while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
4447                continue;
4448
4449        for (jp = curjob; jp; jp = jp->prev_job) {
4450                if (!(mode & SHOW_CHANGED) || jp->changed) {
4451                        showjob(jp, mode);
4452                }
4453        }
4454}
4455
4456static int FAST_FUNC
4457jobscmd(int argc UNUSED_PARAM, char **argv)
4458{
4459        int mode, m;
4460
4461        mode = 0;
4462        while ((m = nextopt("lp")) != '\0') {
4463                if (m == 'l')
4464                        mode |= SHOW_PIDS;
4465                else
4466                        mode |= SHOW_ONLY_PGID;
4467        }
4468
4469        argv = argptr;
4470        if (*argv) {
4471                do
4472                        showjob(getjob(*argv, 0), mode);
4473                while (*++argv);
4474        } else {
4475                showjobs(mode);
4476        }
4477
4478        return 0;
4479}
4480#endif /* JOBS */
4481
4482/* Called only on finished or stopped jobs (no members are running) */
4483static int
4484getstatus(struct job *job)
4485{
4486        int status;
4487        int retval;
4488        struct procstat *ps;
4489
4490        /* Fetch last member's status */
4491        ps = job->ps + job->nprocs - 1;
4492        status = ps->ps_status;
4493        if (pipefail) {
4494                /* "set -o pipefail" mode: use last _nonzero_ status */
4495                while (status == 0 && --ps >= job->ps)
4496                        status = ps->ps_status;
4497        }
4498
4499        retval = WEXITSTATUS(status);
4500        if (!WIFEXITED(status)) {
4501#if JOBS
4502                retval = WSTOPSIG(status);
4503                if (!WIFSTOPPED(status))
4504#endif
4505                {
4506                        /* XXX: limits number of signals */
4507                        retval = WTERMSIG(status);
4508#if JOBS
4509                        if (retval == SIGINT)
4510                                job->sigint = 1;
4511#endif
4512                }
4513                retval += 128;
4514        }
4515        TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4516                jobno(job), job->nprocs, status, retval));
4517        return retval;
4518}
4519
4520static int FAST_FUNC
4521waitcmd(int argc UNUSED_PARAM, char **argv)
4522{
4523        struct job *job;
4524        int retval;
4525        struct job *jp;
4526
4527        nextopt(nullstr);
4528        retval = 0;
4529
4530        argv = argptr;
4531        if (!*argv) {
4532                /* wait for all jobs */
4533                for (;;) {
4534                        jp = curjob;
4535                        while (1) {
4536                                if (!jp) /* no running procs */
4537                                        goto ret;
4538                                if (jp->state == JOBRUNNING)
4539                                        break;
4540                                jp->waited = 1;
4541                                jp = jp->prev_job;
4542                        }
4543        /* man bash:
4544         * "When bash is waiting for an asynchronous command via
4545         * the wait builtin, the reception of a signal for which a trap
4546         * has been set will cause the wait builtin to return immediately
4547         * with an exit status greater than 128, immediately after which
4548         * the trap is executed."
4549         */
4550                        dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4551        /* if child sends us a signal *and immediately exits*,
4552         * dowait() returns pid > 0. Check this case,
4553         * not "if (dowait() < 0)"!
4554         */
4555                        if (pending_sig)
4556                                goto sigout;
4557                }
4558        }
4559
4560        retval = 127;
4561        do {
4562                if (**argv != '%') {
4563                        pid_t pid = number(*argv);
4564                        job = curjob;
4565                        while (1) {
4566                                if (!job)
4567                                        goto repeat;
4568                                if (job->ps[job->nprocs - 1].ps_pid == pid)
4569                                        break;
4570                                job = job->prev_job;
4571                        }
4572                } else {
4573                        job = getjob(*argv, 0);
4574                }
4575                /* loop until process terminated or stopped */
4576                while (job->state == JOBRUNNING) {
4577                        dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4578                        if (pending_sig)
4579                                goto sigout;
4580                }
4581                job->waited = 1;
4582                retval = getstatus(job);
4583 repeat: ;
4584        } while (*++argv);
4585
4586 ret:
4587        return retval;
4588 sigout:
4589        retval = 128 + pending_sig;
4590        return retval;
4591}
4592
4593static struct job *
4594growjobtab(void)
4595{
4596        size_t len;
4597        ptrdiff_t offset;
4598        struct job *jp, *jq;
4599
4600        len = njobs * sizeof(*jp);
4601        jq = jobtab;
4602        jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4603
4604        offset = (char *)jp - (char *)jq;
4605        if (offset) {
4606                /* Relocate pointers */
4607                size_t l = len;
4608
4609                jq = (struct job *)((char *)jq + l);
4610                while (l) {
4611                        l -= sizeof(*jp);
4612                        jq--;
4613#define joff(p) ((struct job *)((char *)(p) + l))
4614#define jmove(p) (p) = (void *)((char *)(p) + offset)
4615                        if (joff(jp)->ps == &jq->ps0)
4616                                jmove(joff(jp)->ps);
4617                        if (joff(jp)->prev_job)
4618                                jmove(joff(jp)->prev_job);
4619                }
4620                if (curjob)
4621                        jmove(curjob);
4622#undef joff
4623#undef jmove
4624        }
4625
4626        njobs += 4;
4627        jobtab = jp;
4628        jp = (struct job *)((char *)jp + len);
4629        jq = jp + 3;
4630        do {
4631                jq->used = 0;
4632        } while (--jq >= jp);
4633        return jp;
4634}
4635
4636/*
4637 * Return a new job structure.
4638 * Called with interrupts off.
4639 */
4640static struct job *
4641makejob(/*union node *node,*/ int nprocs)
4642{
4643        int i;
4644        struct job *jp;
4645
4646        for (i = njobs, jp = jobtab; ; jp++) {
4647                if (--i < 0) {
4648                        jp = growjobtab();
4649                        break;
4650                }
4651                if (jp->used == 0)
4652                        break;
4653                if (jp->state != JOBDONE || !jp->waited)
4654                        continue;
4655#if JOBS
4656                if (doing_jobctl)
4657                        continue;
4658#endif
4659                freejob(jp);
4660                break;
4661        }
4662        memset(jp, 0, sizeof(*jp));
4663#if JOBS
4664        /* jp->jobctl is a bitfield.
4665         * "jp->jobctl |= doing_jobctl" likely to give awful code */
4666        if (doing_jobctl)
4667                jp->jobctl = 1;
4668#endif
4669        jp->prev_job = curjob;
4670        curjob = jp;
4671        jp->used = 1;
4672        jp->ps = &jp->ps0;
4673        if (nprocs > 1) {
4674                jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4675        }
4676        TRACE(("makejob(%d) returns %%%d\n", nprocs,
4677                                jobno(jp)));
4678        return jp;
4679}
4680
4681#if JOBS
4682/*
4683 * Return a string identifying a command (to be printed by the
4684 * jobs command).
4685 */
4686static char *cmdnextc;
4687
4688static void
4689cmdputs(const char *s)
4690{
4691        static const char vstype[VSTYPE + 1][3] = {
4692                "", "}", "-", "+", "?", "=",
4693                "%", "%%", "#", "##"
4694                IF_BASH_SUBSTR(, ":")
4695                IF_BASH_PATTERN_SUBST(, "/", "//")
4696        };
4697
4698        const char *p, *str;
4699        char cc[2];
4700        char *nextc;
4701        unsigned char c;
4702        unsigned char subtype = 0;
4703        int quoted = 0;
4704
4705        cc[1] = '\0';
4706        nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4707        p = s;
4708        while ((c = *p++) != '\0') {
4709                str = NULL;
4710                switch (c) {
4711                case CTLESC:
4712                        c = *p++;
4713                        break;
4714                case CTLVAR:
4715                        subtype = *p++;
4716                        if ((subtype & VSTYPE) == VSLENGTH)
4717                                str = "${#";
4718                        else
4719                                str = "${";
4720                        goto dostr;
4721                case CTLENDVAR:
4722                        str = "\"}" + !(quoted & 1);
4723                        quoted >>= 1;
4724                        subtype = 0;
4725                        goto dostr;
4726                case CTLBACKQ:
4727                        str = "$(...)";
4728                        goto dostr;
4729#if ENABLE_FEATURE_SH_MATH
4730                case CTLARI:
4731                        str = "$((";
4732                        goto dostr;
4733                case CTLENDARI:
4734                        str = "))";
4735                        goto dostr;
4736#endif
4737                case CTLQUOTEMARK:
4738                        quoted ^= 1;
4739                        c = '"';
4740                        break;
4741                case '=':
4742                        if (subtype == 0)
4743                                break;
4744                        if ((subtype & VSTYPE) != VSNORMAL)
4745                                quoted <<= 1;
4746                        str = vstype[subtype & VSTYPE];
4747                        if (subtype & VSNUL)
4748                                c = ':';
4749                        else
4750                                goto checkstr;
4751                        break;
4752                case '\'':
4753                case '\\':
4754                case '"':
4755                case '$':
4756                        /* These can only happen inside quotes */
4757                        cc[0] = c;
4758                        str = cc;
4759//FIXME:
4760// $ true $$ &
4761// $ <cr>
4762// [1]+  Done    true ${\$}   <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
4763                        c = '\\';
4764                        break;
4765                default:
4766                        break;
4767                }
4768                USTPUTC(c, nextc);
4769 checkstr:
4770                if (!str)
4771                        continue;
4772 dostr:
4773                while ((c = *str++) != '\0') {
4774                        USTPUTC(c, nextc);
4775                }
4776        } /* while *p++ not NUL */
4777
4778        if (quoted & 1) {
4779                USTPUTC('"', nextc);
4780        }
4781        *nextc = 0;
4782        cmdnextc = nextc;
4783}
4784
4785/* cmdtxt() and cmdlist() call each other */
4786static void cmdtxt(union node *n);
4787
4788static void
4789cmdlist(union node *np, int sep)
4790{
4791        for (; np; np = np->narg.next) {
4792                if (!sep)
4793                        cmdputs(" ");
4794                cmdtxt(np);
4795                if (sep && np->narg.next)
4796                        cmdputs(" ");
4797        }
4798}
4799
4800static void
4801cmdtxt(union node *n)
4802{
4803        union node *np;
4804        struct nodelist *lp;
4805        const char *p;
4806
4807        if (!n)
4808                return;
4809        switch (n->type) {
4810        default:
4811#if DEBUG
4812                abort();
4813#endif
4814        case NPIPE:
4815                lp = n->npipe.cmdlist;
4816                for (;;) {
4817                        cmdtxt(lp->n);
4818                        lp = lp->next;
4819                        if (!lp)
4820                                break;
4821                        cmdputs(" | ");
4822                }
4823                break;
4824        case NSEMI:
4825                p = "; ";
4826                goto binop;
4827        case NAND:
4828                p = " && ";
4829                goto binop;
4830        case NOR:
4831                p = " || ";
4832 binop:
4833                cmdtxt(n->nbinary.ch1);
4834                cmdputs(p);
4835                n = n->nbinary.ch2;
4836                goto donode;
4837        case NREDIR:
4838        case NBACKGND:
4839                n = n->nredir.n;
4840                goto donode;
4841        case NNOT:
4842                cmdputs("!");
4843                n = n->nnot.com;
4844 donode:
4845                cmdtxt(n);
4846                break;
4847        case NIF:
4848                cmdputs("if ");
4849                cmdtxt(n->nif.test);
4850                cmdputs("; then ");
4851                if (n->nif.elsepart) {
4852                        cmdtxt(n->nif.ifpart);
4853                        cmdputs("; else ");
4854                        n = n->nif.elsepart;
4855                } else {
4856                        n = n->nif.ifpart;
4857                }
4858                p = "; fi";
4859                goto dotail;
4860        case NSUBSHELL:
4861                cmdputs("(");
4862                n = n->nredir.n;
4863                p = ")";
4864                goto dotail;
4865        case NWHILE:
4866                p = "while ";
4867                goto until;
4868        case NUNTIL:
4869                p = "until ";
4870 until:
4871                cmdputs(p);
4872                cmdtxt(n->nbinary.ch1);
4873                n = n->nbinary.ch2;
4874                p = "; done";
4875 dodo:
4876                cmdputs("; do ");
4877 dotail:
4878                cmdtxt(n);
4879                goto dotail2;
4880        case NFOR:
4881                cmdputs("for ");
4882                cmdputs(n->nfor.var);
4883                cmdputs(" in ");
4884                cmdlist(n->nfor.args, 1);
4885                n = n->nfor.body;
4886                p = "; done";
4887                goto dodo;
4888        case NDEFUN:
4889                cmdputs(n->ndefun.text);
4890                p = "() { ... }";
4891                goto dotail2;
4892        case NCMD:
4893                cmdlist(n->ncmd.args, 1);
4894                cmdlist(n->ncmd.redirect, 0);
4895                break;
4896        case NARG:
4897                p = n->narg.text;
4898 dotail2:
4899                cmdputs(p);
4900                break;
4901        case NHERE:
4902        case NXHERE:
4903                p = "<<...";
4904                goto dotail2;
4905        case NCASE:
4906                cmdputs("case ");
4907                cmdputs(n->ncase.expr->narg.text);
4908                cmdputs(" in ");
4909                for (np = n->ncase.cases; np; np = np->nclist.next) {
4910                        cmdtxt(np->nclist.pattern);
4911                        cmdputs(") ");
4912                        cmdtxt(np->nclist.body);
4913                        cmdputs(";; ");
4914                }
4915                p = "esac";
4916                goto dotail2;
4917        case NTO:
4918                p = ">";
4919                goto redir;
4920        case NCLOBBER:
4921                p = ">|";
4922                goto redir;
4923        case NAPPEND:
4924                p = ">>";
4925                goto redir;
4926#if BASH_REDIR_OUTPUT
4927        case NTO2:
4928#endif
4929        case NTOFD:
4930                p = ">&";
4931                goto redir;
4932        case NFROM:
4933                p = "<";
4934                goto redir;
4935        case NFROMFD:
4936                p = "<&";
4937                goto redir;
4938        case NFROMTO:
4939                p = "<>";
4940 redir:
4941                cmdputs(utoa(n->nfile.fd));
4942                cmdputs(p);
4943                if (n->type == NTOFD || n->type == NFROMFD) {
4944                        if (n->ndup.dupfd >= 0)
4945                                cmdputs(utoa(n->ndup.dupfd));
4946                        else
4947                                cmdputs("-");
4948                        break;
4949                }
4950                n = n->nfile.fname;
4951                goto donode;
4952        }
4953}
4954
4955static char *
4956commandtext(union node *n)
4957{
4958        char *name;
4959
4960        STARTSTACKSTR(cmdnextc);
4961        cmdtxt(n);
4962        name = stackblock();
4963        TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
4964        return ckstrdup(name);
4965}
4966#endif /* JOBS */
4967
4968/*
4969 * Fork off a subshell.  If we are doing job control, give the subshell its
4970 * own process group.  Jp is a job structure that the job is to be added to.
4971 * N is the command that will be evaluated by the child.  Both jp and n may
4972 * be NULL.  The mode parameter can be one of the following:
4973 *      FORK_FG - Fork off a foreground process.
4974 *      FORK_BG - Fork off a background process.
4975 *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
4976 *                   process group even if job control is on.
4977 *
4978 * When job control is turned off, background processes have their standard
4979 * input redirected to /dev/null (except for the second and later processes
4980 * in a pipeline).
4981 *
4982 * Called with interrupts off.
4983 */
4984/*
4985 * Clear traps on a fork.
4986 */
4987static void
4988clear_traps(void)
4989{
4990        char **tp;
4991
4992        INT_OFF;
4993        for (tp = trap; tp < &trap[NSIG]; tp++) {
4994                if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */
4995                        if (trap_ptr == trap)
4996                                free(*tp);
4997                        /* else: it "belongs" to trap_ptr vector, don't free */
4998                        *tp = NULL;
4999                        if ((tp - trap) != 0)
5000                                setsignal(tp - trap);
5001                }
5002        }
5003        may_have_traps = 0;
5004        INT_ON;
5005}
5006
5007/* Lives far away from here, needed for forkchild */
5008static void closescript(void);
5009
5010/* Called after fork(), in child */
5011/* jp and n are NULL when called by openhere() for heredoc support */
5012static NOINLINE void
5013forkchild(struct job *jp, union node *n, int mode)
5014{
5015        int oldlvl;
5016
5017        TRACE(("Child shell %d\n", getpid()));
5018        oldlvl = shlvl;
5019        shlvl++;
5020
5021        /* man bash: "Non-builtin commands run by bash have signal handlers
5022         * set to the values inherited by the shell from its parent".
5023         * Do we do it correctly? */
5024
5025        closescript();
5026
5027        if (mode == FORK_NOJOB          /* is it `xxx` ? */
5028         && n && n->type == NCMD        /* is it single cmd? */
5029        /* && n->ncmd.args->type == NARG - always true? */
5030         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
5031         && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5032        /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5033        ) {
5034                TRACE(("Trap hack\n"));
5035                /* Awful hack for `trap` or $(trap).
5036                 *
5037                 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5038                 * contains an example where "trap" is executed in a subshell:
5039                 *
5040                 * save_traps=$(trap)
5041                 * ...
5042                 * eval "$save_traps"
5043                 *
5044                 * Standard does not say that "trap" in subshell shall print
5045                 * parent shell's traps. It only says that its output
5046                 * must have suitable form, but then, in the above example
5047                 * (which is not supposed to be normative), it implies that.
5048                 *
5049                 * bash (and probably other shell) does implement it
5050                 * (traps are reset to defaults, but "trap" still shows them),
5051                 * but as a result, "trap" logic is hopelessly messed up:
5052                 *
5053                 * # trap
5054                 * trap -- 'echo Ho' SIGWINCH  <--- we have a handler
5055                 * # (trap)        <--- trap is in subshell - no output (correct, traps are reset)
5056                 * # true | trap   <--- trap is in subshell - no output (ditto)
5057                 * # echo `true | trap`    <--- in subshell - output (but traps are reset!)
5058                 * trap -- 'echo Ho' SIGWINCH
5059                 * # echo `(trap)`         <--- in subshell in subshell - output
5060                 * trap -- 'echo Ho' SIGWINCH
5061                 * # echo `true | (trap)`  <--- in subshell in subshell in subshell - output!
5062                 * trap -- 'echo Ho' SIGWINCH
5063                 *
5064                 * The rules when to forget and when to not forget traps
5065                 * get really complex and nonsensical.
5066                 *
5067                 * Our solution: ONLY bare $(trap) or `trap` is special.
5068                 */
5069                /* Save trap handler strings for trap builtin to print */
5070                trap_ptr = xmemdup(trap, sizeof(trap));
5071                /* Fall through into clearing traps */
5072        }
5073        clear_traps();
5074#if JOBS
5075        /* do job control only in root shell */
5076        doing_jobctl = 0;
5077        if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
5078                pid_t pgrp;
5079
5080                if (jp->nprocs == 0)
5081                        pgrp = getpid();
5082                else
5083                        pgrp = jp->ps[0].ps_pid;
5084                /* this can fail because we are doing it in the parent also */
5085                setpgid(0, pgrp);
5086                if (mode == FORK_FG)
5087                        xtcsetpgrp(ttyfd, pgrp);
5088                setsignal(SIGTSTP);
5089                setsignal(SIGTTOU);
5090        } else
5091#endif
5092        if (mode == FORK_BG) {
5093                /* man bash: "When job control is not in effect,
5094                 * asynchronous commands ignore SIGINT and SIGQUIT" */
5095                ignoresig(SIGINT);
5096                ignoresig(SIGQUIT);
5097                if (jp->nprocs == 0) {
5098                        close(0);
5099                        if (open(bb_dev_null, O_RDONLY) != 0)
5100                                ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
5101                }
5102        }
5103        if (oldlvl == 0) {
5104                if (iflag) { /* why if iflag only? */
5105                        setsignal(SIGINT);
5106                        setsignal(SIGTERM);
5107                }
5108                /* man bash:
5109                 * "In all cases, bash ignores SIGQUIT. Non-builtin
5110                 * commands run by bash have signal handlers
5111                 * set to the values inherited by the shell
5112                 * from its parent".
5113                 * Take care of the second rule: */
5114                setsignal(SIGQUIT);
5115        }
5116#if JOBS
5117        if (n && n->type == NCMD
5118         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
5119        ) {
5120                TRACE(("Job hack\n"));
5121                /* "jobs": we do not want to clear job list for it,
5122                 * instead we remove only _its_ own_ job from job list.
5123                 * This makes "jobs .... | cat" more useful.
5124                 */
5125                freejob(curjob);
5126                return;
5127        }
5128#endif
5129        for (jp = curjob; jp; jp = jp->prev_job)
5130                freejob(jp);
5131        jobless = 0;
5132}
5133
5134/* Called after fork(), in parent */
5135#if !JOBS
5136#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5137#endif
5138static void
5139forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5140{
5141        TRACE(("In parent shell: child = %d\n", pid));
5142        if (!jp) {
5143                /* jp is NULL when called by openhere() for heredoc support */
5144                while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5145                        continue;
5146                jobless++;
5147                return;
5148        }
5149#if JOBS
5150        if (mode != FORK_NOJOB && jp->jobctl) {
5151                int pgrp;
5152
5153                if (jp->nprocs == 0)
5154                        pgrp = pid;
5155                else
5156                        pgrp = jp->ps[0].ps_pid;
5157                /* This can fail because we are doing it in the child also */
5158                setpgid(pid, pgrp);
5159        }
5160#endif
5161        if (mode == FORK_BG) {
5162                backgndpid = pid;               /* set $! */
5163                set_curjob(jp, CUR_RUNNING);
5164        }
5165        if (jp) {
5166                struct procstat *ps = &jp->ps[jp->nprocs++];
5167                ps->ps_pid = pid;
5168                ps->ps_status = -1;
5169                ps->ps_cmd = nullstr;
5170#if JOBS
5171                if (doing_jobctl && n)
5172                        ps->ps_cmd = commandtext(n);
5173#endif
5174        }
5175}
5176
5177/* jp and n are NULL when called by openhere() for heredoc support */
5178static int
5179forkshell(struct job *jp, union node *n, int mode)
5180{
5181        int pid;
5182
5183        TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5184        pid = fork();
5185        if (pid < 0) {
5186                TRACE(("Fork failed, errno=%d", errno));
5187                if (jp)
5188                        freejob(jp);
5189                ash_msg_and_raise_perror("can't fork");
5190        }
5191        if (pid == 0) {
5192                CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
5193                forkchild(jp, n, mode);
5194        } else {
5195                forkparent(jp, n, mode, pid);
5196        }
5197        return pid;
5198}
5199
5200/*
5201 * Wait for job to finish.
5202 *
5203 * Under job control we have the problem that while a child process
5204 * is running interrupts generated by the user are sent to the child
5205 * but not to the shell.  This means that an infinite loop started by
5206 * an interactive user may be hard to kill.  With job control turned off,
5207 * an interactive user may place an interactive program inside a loop.
5208 * If the interactive program catches interrupts, the user doesn't want
5209 * these interrupts to also abort the loop.  The approach we take here
5210 * is to have the shell ignore interrupt signals while waiting for a
5211 * foreground process to terminate, and then send itself an interrupt
5212 * signal if the child process was terminated by an interrupt signal.
5213 * Unfortunately, some programs want to do a bit of cleanup and then
5214 * exit on interrupt; unless these processes terminate themselves by
5215 * sending a signal to themselves (instead of calling exit) they will
5216 * confuse this approach.
5217 *
5218 * Called with interrupts off.
5219 */
5220static int
5221waitforjob(struct job *jp)
5222{
5223        int st;
5224
5225        TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
5226
5227        INT_OFF;
5228        while (jp->state == JOBRUNNING) {
5229                /* In non-interactive shells, we _can_ get
5230                 * a keyboard signal here and be EINTRed,
5231                 * but we just loop back, waiting for command to complete.
5232                 *
5233                 * man bash:
5234                 * "If bash is waiting for a command to complete and receives
5235                 * a signal for which a trap has been set, the trap
5236                 * will not be executed until the command completes."
5237                 *
5238                 * Reality is that even if trap is not set, bash
5239                 * will not act on the signal until command completes.
5240                 * Try this. sleep5intoff.c:
5241                 * #include <signal.h>
5242                 * #include <unistd.h>
5243                 * int main() {
5244                 *         sigset_t set;
5245                 *         sigemptyset(&set);
5246                 *         sigaddset(&set, SIGINT);
5247                 *         sigaddset(&set, SIGQUIT);
5248                 *         sigprocmask(SIG_BLOCK, &set, NULL);
5249                 *         sleep(5);
5250                 *         return 0;
5251                 * }
5252                 * $ bash -c './sleep5intoff; echo hi'
5253                 * ^C^C^C^C <--- pressing ^C once a second
5254                 * $ _
5255                 * $ bash -c './sleep5intoff; echo hi'
5256                 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5257                 * $ _
5258                 */
5259                dowait(DOWAIT_BLOCK, jp);
5260        }
5261        INT_ON;
5262
5263        st = getstatus(jp);
5264#if JOBS
5265        if (jp->jobctl) {
5266                xtcsetpgrp(ttyfd, rootpid);
5267                restore_tty_if_stopped_or_signaled(jp);
5268
5269                /*
5270                 * This is truly gross.
5271                 * If we're doing job control, then we did a TIOCSPGRP which
5272                 * caused us (the shell) to no longer be in the controlling
5273                 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
5274                 * intuit from the subprocess exit status whether a SIGINT
5275                 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
5276                 */
5277                if (jp->sigint) /* TODO: do the same with all signals */
5278                        raise(SIGINT); /* ... by raise(jp->sig) instead? */
5279        }
5280        if (jp->state == JOBDONE)
5281#endif
5282                freejob(jp);
5283        return st;
5284}
5285
5286/*
5287 * return 1 if there are stopped jobs, otherwise 0
5288 */
5289static int
5290stoppedjobs(void)
5291{
5292        struct job *jp;
5293        int retval;
5294
5295        retval = 0;
5296        if (job_warning)
5297                goto out;
5298        jp = curjob;
5299        if (jp && jp->state == JOBSTOPPED) {
5300                out2str("You have stopped jobs.\n");
5301                job_warning = 2;
5302                retval++;
5303        }
5304 out:
5305        return retval;
5306}
5307
5308
5309/*
5310 * Code for dealing with input/output redirection.
5311 */
5312
5313#undef EMPTY
5314#undef CLOSED
5315#define EMPTY -2                /* marks an unused slot in redirtab */
5316#define CLOSED -1               /* marks a slot of previously-closed fd */
5317
5318/*
5319 * Handle here documents.  Normally we fork off a process to write the
5320 * data to a pipe.  If the document is short, we can stuff the data in
5321 * the pipe without forking.
5322 */
5323/* openhere needs this forward reference */
5324static void expandhere(union node *arg, int fd);
5325static int
5326openhere(union node *redir)
5327{
5328        int pip[2];
5329        size_t len = 0;
5330
5331        if (pipe(pip) < 0)
5332                ash_msg_and_raise_perror("can't create pipe");
5333        if (redir->type == NHERE) {
5334                len = strlen(redir->nhere.doc->narg.text);
5335                if (len <= PIPE_BUF) {
5336                        full_write(pip[1], redir->nhere.doc->narg.text, len);
5337                        goto out;
5338                }
5339        }
5340        if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5341                /* child */
5342                close(pip[0]);
5343                ignoresig(SIGINT);  //signal(SIGINT, SIG_IGN);
5344                ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5345                ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
5346                ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5347                signal(SIGPIPE, SIG_DFL);
5348                if (redir->type == NHERE)
5349                        full_write(pip[1], redir->nhere.doc->narg.text, len);
5350                else /* NXHERE */
5351                        expandhere(redir->nhere.doc, pip[1]);
5352                _exit(EXIT_SUCCESS);
5353        }
5354 out:
5355        close(pip[1]);
5356        return pip[0];
5357}
5358
5359static int
5360openredirect(union node *redir)
5361{
5362        struct stat sb;
5363        char *fname;
5364        int f;
5365
5366        switch (redir->nfile.type) {
5367/* Can't happen, our single caller does this itself */
5368//      case NTOFD:
5369//      case NFROMFD:
5370//              return -1;
5371        case NHERE:
5372        case NXHERE:
5373                return openhere(redir);
5374        }
5375
5376        /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5377         * allocated space. Do it only when we know it is safe.
5378         */
5379        fname = redir->nfile.expfname;
5380
5381        switch (redir->nfile.type) {
5382        default:
5383#if DEBUG
5384                abort();
5385#endif
5386        case NFROM:
5387                f = open(fname, O_RDONLY);
5388                if (f < 0)
5389                        goto eopen;
5390                break;
5391        case NFROMTO:
5392                f = open(fname, O_RDWR|O_CREAT, 0666);
5393                if (f < 0)
5394                        goto ecreate;
5395                break;
5396        case NTO:
5397#if BASH_REDIR_OUTPUT
5398        case NTO2:
5399#endif
5400                /* Take care of noclobber mode. */
5401                if (Cflag) {
5402                        if (stat(fname, &sb) < 0) {
5403                                f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5404                                if (f < 0)
5405                                        goto ecreate;
5406                        } else if (!S_ISREG(sb.st_mode)) {
5407                                f = open(fname, O_WRONLY, 0666);
5408                                if (f < 0)
5409                                        goto ecreate;
5410                                if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
5411                                        close(f);
5412                                        errno = EEXIST;
5413                                        goto ecreate;
5414                                }
5415                        } else {
5416                                errno = EEXIST;
5417                                goto ecreate;
5418                        }
5419                        break;
5420                }
5421                /* FALLTHROUGH */
5422        case NCLOBBER:
5423                f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5424                if (f < 0)
5425                        goto ecreate;
5426                break;
5427        case NAPPEND:
5428                f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5429                if (f < 0)
5430                        goto ecreate;
5431                break;
5432        }
5433
5434        return f;
5435 ecreate:
5436        ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5437 eopen:
5438        ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5439}
5440
5441/*
5442 * Copy a file descriptor to be >= 10. Throws exception on error.
5443 */
5444static int
5445savefd(int from)
5446{
5447        int newfd;
5448        int err;
5449
5450        newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
5451        err = newfd < 0 ? errno : 0;
5452        if (err != EBADF) {
5453                if (err)
5454                        ash_msg_and_raise_perror("%d", from);
5455                close(from);
5456                if (F_DUPFD_CLOEXEC == F_DUPFD)
5457                        close_on_exec_on(newfd);
5458        }
5459
5460        return newfd;
5461}
5462static int
5463dup2_or_raise(int from, int to)
5464{
5465        int newfd;
5466
5467        newfd = (from != to) ? dup2(from, to) : to;
5468        if (newfd < 0) {
5469                /* Happens when source fd is not open: try "echo >&99" */
5470                ash_msg_and_raise_perror("%d", from);
5471        }
5472        return newfd;
5473}
5474static int
5475dup_CLOEXEC(int fd, int avoid_fd)
5476{
5477        int newfd;
5478 repeat:
5479        newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5480        if (newfd >= 0) {
5481                if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
5482                        close_on_exec_on(newfd);
5483        } else { /* newfd < 0 */
5484                if (errno == EBUSY)
5485                        goto repeat;
5486                if (errno == EINTR)
5487                        goto repeat;
5488        }
5489        return newfd;
5490}
5491static int
5492xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5493{
5494        int newfd;
5495 repeat:
5496        newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5497        if (newfd < 0) {
5498                if (errno == EBUSY)
5499                        goto repeat;
5500                if (errno == EINTR)
5501                        goto repeat;
5502                /* fd was not open? */
5503                if (errno == EBADF)
5504                        return fd;
5505                ash_msg_and_raise_perror("%d", newfd);
5506        }
5507        if (F_DUPFD_CLOEXEC == F_DUPFD)
5508                close_on_exec_on(newfd);
5509        close(fd);
5510        return newfd;
5511}
5512
5513/* Struct def and variable are moved down to the first usage site */
5514struct squirrel {
5515        int orig_fd;
5516        int moved_to;
5517};
5518struct redirtab {
5519        struct redirtab *next;
5520        int pair_count;
5521        struct squirrel two_fd[];
5522};
5523#define redirlist (G_var.redirlist)
5524
5525static void
5526add_squirrel_closed(struct redirtab *sq, int fd)
5527{
5528        int i;
5529
5530        if (!sq)
5531                return;
5532
5533        for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5534                /* If we collide with an already moved fd... */
5535                if (fd == sq->two_fd[i].orig_fd) {
5536                        /* Examples:
5537                         * "echo 3>FILE 3>&- 3>FILE"
5538                         * "echo 3>&- 3>FILE"
5539                         * No need for last redirect to insert
5540                         * another "need to close 3" indicator.
5541                         */
5542                        TRACE(("redirect_fd %d: already moved or closed\n", fd));
5543                        return;
5544                }
5545        }
5546        TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5547        sq->two_fd[i].orig_fd = fd;
5548        sq->two_fd[i].moved_to = CLOSED;
5549}
5550
5551static int
5552save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5553{
5554        int i, new_fd;
5555
5556        if (avoid_fd < 9) /* the important case here is that it can be -1 */
5557                avoid_fd = 9;
5558
5559#if JOBS
5560        if (fd == ttyfd) {
5561                /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5562                ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5563                TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5564                return 1; /* "we closed fd" */
5565        }
5566#endif
5567        /* Are we called from redirect(0)? E.g. redirect
5568         * in a forked child. No need to save fds,
5569         * we aren't going to use them anymore, ok to trash.
5570         */
5571        if (!sq)
5572                return 0;
5573
5574        /* If this one of script's fds? */
5575        if (fd != 0) {
5576                struct parsefile *pf = g_parsefile;
5577                while (pf) {
5578                        /* We skip fd == 0 case because of the following:
5579                         * $ ash  # running ash interactively
5580                         * $ . ./script.sh
5581                         * and in script.sh: "exec 9>&0".
5582                         * Even though top-level pf_fd _is_ 0,
5583                         * it's still ok to use it: "read" builtin uses it,
5584                         * why should we cripple "exec" builtin?
5585                         */
5586                        if (fd == pf->pf_fd) {
5587                                pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5588                                return 1; /* "we closed fd" */
5589                        }
5590                        pf = pf->prev;
5591                }
5592        }
5593
5594        /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5595
5596        /* First: do we collide with some already moved fds? */
5597        for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5598                /* If we collide with an already moved fd... */
5599                if (fd == sq->two_fd[i].moved_to) {
5600                        new_fd = dup_CLOEXEC(fd, avoid_fd);
5601                        sq->two_fd[i].moved_to = new_fd;
5602                        TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5603                        if (new_fd < 0) /* what? */
5604                                xfunc_die();
5605                        return 0; /* "we did not close fd" */
5606                }
5607                if (fd == sq->two_fd[i].orig_fd) {
5608                        /* Example: echo Hello >/dev/null 1>&2 */
5609                        TRACE(("redirect_fd %d: already moved\n", fd));
5610                        return 0; /* "we did not close fd" */
5611                }
5612        }
5613
5614        /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5615        new_fd = dup_CLOEXEC(fd, avoid_fd);
5616        TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5617        if (new_fd < 0) {
5618                if (errno != EBADF)
5619                        xfunc_die();
5620                /* new_fd = CLOSED; - already is -1 */
5621        }
5622        sq->two_fd[i].moved_to = new_fd;
5623        sq->two_fd[i].orig_fd = fd;
5624
5625        /* if we move stderr, let "set -x" code know */
5626        if (fd == preverrout_fd)
5627                preverrout_fd = new_fd;
5628
5629        return 0; /* "we did not close fd" */
5630}
5631
5632static int
5633internally_opened_fd(int fd, struct redirtab *sq)
5634{
5635        int i;
5636#if JOBS
5637        if (fd == ttyfd)
5638                return 1;
5639#endif
5640        /* If this one of script's fds? */
5641        if (fd != 0) {
5642                struct parsefile *pf = g_parsefile;
5643                while (pf) {
5644                        if (fd == pf->pf_fd)
5645                                return 1;
5646                        pf = pf->prev;
5647                }
5648        }
5649
5650        if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5651                if (fd == sq->two_fd[i].moved_to)
5652                        return 1;
5653        }
5654        return 0;
5655}
5656
5657/*
5658 * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
5659 * old file descriptors are stashed away so that the redirection can be
5660 * undone by calling popredir.
5661 */
5662/* flags passed to redirect */
5663#define REDIR_PUSH    01        /* save previous values of file descriptors */
5664static void
5665redirect(union node *redir, int flags)
5666{
5667        struct redirtab *sv;
5668
5669        if (!redir)
5670                return;
5671
5672        sv = NULL;
5673        INT_OFF;
5674        if (flags & REDIR_PUSH)
5675                sv = redirlist;
5676        do {
5677                int fd;
5678                int newfd;
5679                int close_fd;
5680                int closed;
5681
5682                fd = redir->nfile.fd;
5683                if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5684                        //bb_error_msg("doing %d > %d", fd, newfd);
5685                        newfd = redir->ndup.dupfd;
5686                        close_fd = -1;
5687                } else {
5688                        newfd = openredirect(redir); /* always >= 0 */
5689                        if (fd == newfd) {
5690                                /* open() gave us precisely the fd we wanted.
5691                                 * This means that this fd was not busy
5692                                 * (not opened to anywhere).
5693                                 * Remember to close it on restore:
5694                                 */
5695                                add_squirrel_closed(sv, fd);
5696                                continue;
5697                        }
5698                        close_fd = newfd;
5699                }
5700
5701                if (fd == newfd)
5702                        continue;
5703
5704                /* if "N>FILE": move newfd to fd */
5705                /* if "N>&M": dup newfd to fd */
5706                /* if "N>&-": close fd (newfd is -1) */
5707
5708 IF_BASH_REDIR_OUTPUT(redirect_more:)
5709
5710                closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5711                if (newfd == -1) {
5712                        /* "N>&-" means "close me" */
5713                        if (!closed) {
5714                                /* ^^^ optimization: saving may already
5715                                 * have closed it. If not... */
5716                                close(fd);
5717                        }
5718                } else {
5719                        /* if newfd is a script fd or saved fd, simulate EBADF */
5720                        if (internally_opened_fd(newfd, sv)) {
5721                                errno = EBADF;
5722                                ash_msg_and_raise_perror("%d", newfd);
5723                        }
5724                        dup2_or_raise(newfd, fd);
5725                        if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5726                                close(close_fd);
5727#if BASH_REDIR_OUTPUT
5728                        if (redir->nfile.type == NTO2 && fd == 1) {
5729                                /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5730                                fd = 2;
5731                                newfd = 1;
5732                                close_fd = -1;
5733                                goto redirect_more;
5734                        }
5735#endif
5736                }
5737        } while ((redir = redir->nfile.next) != NULL);
5738        INT_ON;
5739
5740//dash:#define REDIR_SAVEFD2 03        /* set preverrout */
5741#define REDIR_SAVEFD2 0
5742        // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5743        // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5744        // not only for calls with flags containing REDIR_SAVEFD2.
5745        // We do this unconditionally (see save_fd_on_redirect()).
5746        //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5747        //      preverrout_fd = copied_fd2;
5748}
5749
5750static int
5751redirectsafe(union node *redir, int flags)
5752{
5753        int err;
5754        volatile int saveint;
5755        struct jmploc *volatile savehandler = exception_handler;
5756        struct jmploc jmploc;
5757
5758        SAVE_INT(saveint);
5759        /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5760        err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
5761        if (!err) {
5762                exception_handler = &jmploc;
5763                redirect(redir, flags);
5764        }
5765        exception_handler = savehandler;
5766        if (err && exception_type != EXERROR)
5767                longjmp(exception_handler->loc, 1);
5768        RESTORE_INT(saveint);
5769        return err;
5770}
5771
5772static struct redirtab*
5773pushredir(union node *redir)
5774{
5775        struct redirtab *sv;
5776        int i;
5777
5778        if (!redir)
5779                return redirlist;
5780
5781        i = 0;
5782        do {
5783                i++;
5784#if BASH_REDIR_OUTPUT
5785                if (redir->nfile.type == NTO2)
5786                        i++;
5787#endif
5788                redir = redir->nfile.next;
5789        } while (redir);
5790
5791        sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5792        sv->pair_count = i;
5793        while (--i >= 0)
5794                sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
5795        sv->next = redirlist;
5796        redirlist = sv;
5797        return sv->next;
5798}
5799
5800/*
5801 * Undo the effects of the last redirection.
5802 */
5803static void
5804popredir(int drop)
5805{
5806        struct redirtab *rp;
5807        int i;
5808
5809        if (redirlist == NULL)
5810                return;
5811        INT_OFF;
5812        rp = redirlist;
5813        for (i = 0; i < rp->pair_count; i++) {
5814                int fd = rp->two_fd[i].orig_fd;
5815                int copy = rp->two_fd[i].moved_to;
5816                if (copy == CLOSED) {
5817                        if (!drop)
5818                                close(fd);
5819                        continue;
5820                }
5821                if (copy != EMPTY) {
5822                        if (!drop) {
5823                                /*close(fd);*/
5824                                dup2_or_raise(copy, fd);
5825                        }
5826                        close(copy);
5827                }
5828        }
5829        redirlist = rp->next;
5830        free(rp);
5831        INT_ON;
5832}
5833
5834static void
5835unwindredir(struct redirtab *stop)
5836{
5837        while (redirlist != stop)
5838                popredir(/*drop:*/ 0);
5839}
5840
5841
5842/* ============ Routines to expand arguments to commands
5843 *
5844 * We have to deal with backquotes, shell variables, and file metacharacters.
5845 */
5846
5847#if ENABLE_FEATURE_SH_MATH
5848static arith_t
5849ash_arith(const char *s)
5850{
5851        arith_state_t math_state;
5852        arith_t result;
5853
5854        math_state.lookupvar = lookupvar;
5855        math_state.setvar    = setvar0;
5856        //math_state.endofname = endofname;
5857
5858        INT_OFF;
5859        result = arith(&math_state, s);
5860        if (math_state.errmsg)
5861                ash_msg_and_raise_error(math_state.errmsg);
5862        INT_ON;
5863
5864        return result;
5865}
5866#endif
5867#if BASH_SUBSTR
5868# if ENABLE_FEATURE_SH_MATH
5869static int substr_atoi(const char *s)
5870{
5871        arith_t t = ash_arith(s);
5872        if (sizeof(t) > sizeof(int)) {
5873                /* clamp very large or very large negative nums for ${v:N:M}:
5874                 * else "${v:0:0x100000001}" would work as "${v:0:1}"
5875                 */
5876                if (t > INT_MAX)
5877                        t = INT_MAX;
5878                if (t < INT_MIN)
5879                        t = INT_MIN;
5880        }
5881        return t;
5882}
5883# else
5884#  define substr_atoi(s) number(s)
5885# endif
5886#endif
5887
5888/*
5889 * expandarg flags
5890 */
5891#define EXP_FULL        0x1     /* perform word splitting & file globbing */
5892#define EXP_TILDE       0x2     /* do normal tilde expansion */
5893#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
5894#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
5895/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5896 * POSIX says for this case:
5897 *  Pathname expansion shall not be performed on the word by a
5898 *  non-interactive shell; an interactive shell may perform it, but shall
5899 *  do so only when the expansion would result in one word.
5900 * Currently, our code complies to the above rule by never globbing
5901 * redirection filenames.
5902 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5903 * (this means that on a typical Linux distro, bash almost always
5904 * performs globbing, and thus diverges from what we do).
5905 */
5906#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
5907#define EXP_VARTILDE2   0x20    /* expand tildes after colons only */
5908#define EXP_WORD        0x40    /* expand word in parameter expansion */
5909#define EXP_QUOTED      0x100   /* expand word in double quotes */
5910/*
5911 * rmescape() flags
5912 */
5913#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
5914#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
5915#define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
5916#define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
5917
5918/* Add CTLESC when necessary. */
5919#define QUOTES_ESC     (EXP_FULL | EXP_CASE)
5920/* Do not skip NUL characters. */
5921#define QUOTES_KEEPNUL EXP_TILDE
5922
5923/*
5924 * Structure specifying which parts of the string should be searched
5925 * for IFS characters.
5926 */
5927struct ifsregion {
5928        struct ifsregion *next; /* next region in list */
5929        int begoff;             /* offset of start of region */
5930        int endoff;             /* offset of end of region */
5931        int nulonly;            /* search for nul bytes only */
5932};
5933
5934struct arglist {
5935        struct strlist *list;
5936        struct strlist **lastp;
5937};
5938
5939/* output of current string */
5940static char *expdest;
5941/* list of back quote expressions */
5942static struct nodelist *argbackq;
5943/* first struct in list of ifs regions */
5944static struct ifsregion ifsfirst;
5945/* last struct in list */
5946static struct ifsregion *ifslastp;
5947/* holds expanded arg list */
5948static struct arglist exparg;
5949
5950/*
5951 * Our own itoa().
5952 * cvtnum() is used even if math support is off (to prepare $? values and such).
5953 */
5954static int
5955cvtnum(arith_t num)
5956{
5957        int len;
5958
5959        /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5960        len = sizeof(arith_t) * 3;
5961        /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5962        if (sizeof(arith_t) < 4) len += 2;
5963
5964        expdest = makestrspace(len, expdest);
5965        len = fmtstr(expdest, len, ARITH_FMT, num);
5966        STADJUST(len, expdest);
5967        return len;
5968}
5969
5970/*
5971 * Break the argument string into pieces based upon IFS and add the
5972 * strings to the argument list.  The regions of the string to be
5973 * searched for IFS characters have been stored by recordregion.
5974 */
5975static void
5976ifsbreakup(char *string, struct arglist *arglist)
5977{
5978        struct ifsregion *ifsp;
5979        struct strlist *sp;
5980        char *start;
5981        char *p;
5982        char *q;
5983        const char *ifs, *realifs;
5984        int ifsspc;
5985        int nulonly;
5986
5987        start = string;
5988        if (ifslastp != NULL) {
5989                ifsspc = 0;
5990                nulonly = 0;
5991                realifs = ifsset() ? ifsval() : defifs;
5992                ifsp = &ifsfirst;
5993                do {
5994                        int afternul;
5995
5996                        p = string + ifsp->begoff;
5997                        afternul = nulonly;
5998                        nulonly = ifsp->nulonly;
5999                        ifs = nulonly ? nullstr : realifs;
6000                        ifsspc = 0;
6001                        while (p < string + ifsp->endoff) {
6002                                q = p;
6003                                if ((unsigned char)*p == CTLESC)
6004                                        p++;
6005                                if (!strchr(ifs, *p)) {
6006                                        p++;
6007                                        continue;
6008                                }
6009                                if (!(afternul || nulonly))
6010                                        ifsspc = (strchr(defifs, *p) != NULL);
6011                                /* Ignore IFS whitespace at start */
6012                                if (q == start && ifsspc) {
6013                                        p++;
6014                                        start = p;
6015                                        continue;
6016                                }
6017                                *q = '\0';
6018                                sp = stzalloc(sizeof(*sp));
6019                                sp->text = start;
6020                                *arglist->lastp = sp;
6021                                arglist->lastp = &sp->next;
6022                                p++;
6023                                if (!nulonly) {
6024                                        for (;;) {
6025                                                if (p >= string + ifsp->endoff) {
6026                                                        break;
6027                                                }
6028                                                q = p;
6029                                                if ((unsigned char)*p == CTLESC)
6030                                                        p++;
6031                                                if (strchr(ifs, *p) == NULL) {
6032                                                        p = q;
6033                                                        break;
6034                                                }
6035                                                if (strchr(defifs, *p) == NULL) {
6036                                                        if (ifsspc) {
6037                                                                p++;
6038                                                                ifsspc = 0;
6039                                                        } else {
6040                                                                p = q;
6041                                                                break;
6042                                                        }
6043                                                } else
6044                                                        p++;
6045                                        }
6046                                }
6047                                start = p;
6048                        } /* while */
6049                        ifsp = ifsp->next;
6050                } while (ifsp != NULL);
6051                if (nulonly)
6052                        goto add;
6053        }
6054
6055        if (!*start)
6056                return;
6057
6058 add:
6059        sp = stzalloc(sizeof(*sp));
6060        sp->text = start;
6061        *arglist->lastp = sp;
6062        arglist->lastp = &sp->next;
6063}
6064
6065static void
6066ifsfree(void)
6067{
6068        struct ifsregion *p = ifsfirst.next;
6069
6070        if (!p)
6071                goto out;
6072
6073        INT_OFF;
6074        do {
6075                struct ifsregion *ifsp;
6076                ifsp = p->next;
6077                free(p);
6078                p = ifsp;
6079        } while (p);
6080        ifsfirst.next = NULL;
6081        INT_ON;
6082 out:
6083        ifslastp = NULL;
6084}
6085
6086static size_t
6087esclen(const char *start, const char *p)
6088{
6089        size_t esc = 0;
6090
6091        while (p > start && (unsigned char)*--p == CTLESC) {
6092                esc++;
6093        }
6094        return esc;
6095}
6096
6097/*
6098 * Remove any CTLESC characters from a string.
6099 */
6100#if !BASH_PATTERN_SUBST
6101#define rmescapes(str, flag, slash_position) \
6102        rmescapes(str, flag)
6103#endif
6104static char *
6105rmescapes(char *str, int flag, int *slash_position)
6106{
6107        static const char qchars[] ALIGN1 = {
6108                IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
6109
6110        char *p, *q, *r;
6111        unsigned protect_against_glob;
6112        unsigned globbing;
6113
6114        p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
6115        if (!p)
6116                return str;
6117
6118        q = p;
6119        r = str;
6120        if (flag & RMESCAPE_ALLOC) {
6121                size_t len = p - str;
6122                size_t fulllen = len + strlen(p) + 1;
6123
6124                if (flag & RMESCAPE_GROW) {
6125                        int strloc = str - (char *)stackblock();
6126                        r = makestrspace(fulllen, expdest);
6127                        /* p and str may be invalidated by makestrspace */
6128                        str = (char *)stackblock() + strloc;
6129                        p = str + len;
6130                } else if (flag & RMESCAPE_HEAP) {
6131                        r = ckmalloc(fulllen);
6132                } else {
6133                        r = stalloc(fulllen);
6134                }
6135                q = r;
6136                if (len > 0) {
6137                        q = (char *)mempcpy(q, str, len);
6138                }
6139        }
6140
6141        globbing = flag & RMESCAPE_GLOB;
6142        protect_against_glob = globbing;
6143        while (*p) {
6144                if ((unsigned char)*p == CTLQUOTEMARK) {
6145// Note: protect_against_glob only affect whether
6146// CTLESC,<ch> gets converted to <ch> or to \<ch>
6147                        p++;
6148                        protect_against_glob = globbing;
6149                        continue;
6150                }
6151                if (*p == '\\') {
6152                        /* naked back slash */
6153                        protect_against_glob = 0;
6154                        goto copy;
6155                }
6156                if ((unsigned char)*p == CTLESC) {
6157                        p++;
6158#if DEBUG
6159                        if (*p == '\0')
6160                                ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6161#endif
6162                        if (protect_against_glob) {
6163                                /*
6164                                 * We used to trust glob() and fnmatch() to eat
6165                                 * superfluous escapes (\z where z has no
6166                                 * special meaning anyway). But this causes
6167                                 * bugs such as string of one greek letter rho
6168                                 * (unicode-encoded as two bytes "cf,81")
6169                                 * getting encoded as "cf,CTLESC,81"
6170                                 * and here, converted to "cf,\,81" -
6171                                 * which does not go well with some flavors
6172                                 * of fnmatch() in unicode locales
6173                                 * (for example, glibc <= 2.22).
6174                                 *
6175                                 * Lets add "\" only on the chars which need it.
6176                                 * Testcases for less obvious chars are shown.
6177                                 */
6178                                if (*p == '*'
6179                                 || *p == '?'
6180                                 || *p == '['
6181                                 || *p == '\\' /* case '\' in \\    ) echo ok;; *) echo WRONG;; esac */
6182                                 || *p == ']'  /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6183                                 || *p == '-'  /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6184                                 || *p == '!'  /* case '!' in [\!]  ) echo ok;; *) echo WRONG;; esac */
6185                                /* Some libc support [^negate], that's why "^" also needs love */
6186                                 || *p == '^'  /* case '^' in [\^]  ) echo ok;; *) echo WRONG;; esac */
6187                                ) {
6188                                        *q++ = '\\';
6189                                }
6190                        }
6191                }
6192#if BASH_PATTERN_SUBST
6193                else if (slash_position && p == str + *slash_position) {
6194                        /* stop handling globbing */
6195                        globbing = 0;
6196                        *slash_position = q - r;
6197                        slash_position = NULL;
6198                }
6199#endif
6200                protect_against_glob = globbing;
6201 copy:
6202                *q++ = *p++;
6203        }
6204        *q = '\0';
6205        if (flag & RMESCAPE_GROW) {
6206                expdest = r;
6207                STADJUST(q - r + 1, expdest);
6208        }
6209        return r;
6210}
6211#define pmatch(a, b) !fnmatch((a), (b), 0)
6212
6213/*
6214 * Prepare a pattern for a expmeta (internal glob(3)) call.
6215 *
6216 * Returns an stalloced string.
6217 */
6218static char *
6219preglob(const char *pattern, int flag)
6220{
6221        return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
6222}
6223
6224/*
6225 * Put a string on the stack.
6226 */
6227static void
6228memtodest(const char *p, size_t len, int syntax, int quotes)
6229{
6230        char *q;
6231
6232        if (!len)
6233                return;
6234
6235        q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6236
6237        do {
6238                unsigned char c = *p++;
6239                if (c) {
6240                        if (quotes & QUOTES_ESC) {
6241                                int n = SIT(c, syntax);
6242                                if (n == CCTL
6243                                 || (syntax != BASESYNTAX && n == CBACK)
6244                                ) {
6245                                        USTPUTC(CTLESC, q);
6246                                }
6247                        }
6248                } else if (!(quotes & QUOTES_KEEPNUL))
6249                        continue;
6250                USTPUTC(c, q);
6251        } while (--len);
6252
6253        expdest = q;
6254}
6255
6256static size_t
6257strtodest(const char *p, int syntax, int quotes)
6258{
6259        size_t len = strlen(p);
6260        memtodest(p, len, syntax, quotes);
6261        return len;
6262}
6263
6264/*
6265 * Record the fact that we have to scan this region of the
6266 * string for IFS characters.
6267 */
6268static void
6269recordregion(int start, int end, int nulonly)
6270{
6271        struct ifsregion *ifsp;
6272
6273        if (ifslastp == NULL) {
6274                ifsp = &ifsfirst;
6275        } else {
6276                INT_OFF;
6277                ifsp = ckzalloc(sizeof(*ifsp));
6278                /*ifsp->next = NULL; - ckzalloc did it */
6279                ifslastp->next = ifsp;
6280                INT_ON;
6281        }
6282        ifslastp = ifsp;
6283        ifslastp->begoff = start;
6284        ifslastp->endoff = end;
6285        ifslastp->nulonly = nulonly;
6286}
6287
6288static void
6289removerecordregions(int endoff)
6290{
6291        if (ifslastp == NULL)
6292                return;
6293
6294        if (ifsfirst.endoff > endoff) {
6295                while (ifsfirst.next) {
6296                        struct ifsregion *ifsp;
6297                        INT_OFF;
6298                        ifsp = ifsfirst.next->next;
6299                        free(ifsfirst.next);
6300                        ifsfirst.next = ifsp;
6301                        INT_ON;
6302                }
6303                if (ifsfirst.begoff > endoff) {
6304                        ifslastp = NULL;
6305                } else {
6306                        ifslastp = &ifsfirst;
6307                        ifsfirst.endoff = endoff;
6308                }
6309                return;
6310        }
6311
6312        ifslastp = &ifsfirst;
6313        while (ifslastp->next && ifslastp->next->begoff < endoff)
6314                ifslastp = ifslastp->next;
6315        while (ifslastp->next) {
6316                struct ifsregion *ifsp;
6317                INT_OFF;
6318                ifsp = ifslastp->next->next;
6319                free(ifslastp->next);
6320                ifslastp->next = ifsp;
6321                INT_ON;
6322        }
6323        if (ifslastp->endoff > endoff)
6324                ifslastp->endoff = endoff;
6325}
6326
6327static char *
6328exptilde(char *startp, char *p, int flags)
6329{
6330        unsigned char c;
6331        char *name;
6332        struct passwd *pw;
6333        const char *home;
6334        int quotes = flags & QUOTES_ESC;
6335
6336        name = p + 1;
6337
6338        while ((c = *++p) != '\0') {
6339                switch (c) {
6340                case CTLESC:
6341                        return startp;
6342                case CTLQUOTEMARK:
6343                        return startp;
6344                case ':':
6345                        if (flags & EXP_VARTILDE)
6346                                goto done;
6347                        break;
6348                case '/':
6349                case CTLENDVAR:
6350                        goto done;
6351                }
6352        }
6353 done:
6354        *p = '\0';
6355        if (*name == '\0') {
6356                home = lookupvar("HOME");
6357        } else {
6358                pw = getpwnam(name);
6359                if (pw == NULL)
6360                        goto lose;
6361                home = pw->pw_dir;
6362        }
6363        if (!home || !*home)
6364                goto lose;
6365        *p = c;
6366        strtodest(home, SQSYNTAX, quotes);
6367        return p;
6368 lose:
6369        *p = c;
6370        return startp;
6371}
6372
6373/*
6374 * Execute a command inside back quotes.  If it's a builtin command, we
6375 * want to save its output in a block obtained from malloc.  Otherwise
6376 * we fork off a subprocess and get the output of the command via a pipe.
6377 * Should be called with interrupts off.
6378 */
6379struct backcmd {                /* result of evalbackcmd */
6380        int fd;                 /* file descriptor to read from */
6381        int nleft;              /* number of chars in buffer */
6382        char *buf;              /* buffer */
6383        struct job *jp;         /* job structure for command */
6384};
6385
6386/* These forward decls are needed to use "eval" code for backticks handling: */
6387/* flags in argument to evaltree */
6388#define EV_EXIT    01           /* exit after evaluating tree */
6389#define EV_TESTED  02           /* exit status is checked; ignore -e flag */
6390static int evaltree(union node *, int);
6391
6392/* An evaltree() which is known to never return.
6393 * Used to use an alias:
6394 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6395 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6396 */
6397static ALWAYS_INLINE NORETURN void
6398evaltreenr(union node *n, int flags)
6399{
6400        evaltree(n, flags);
6401        bb_unreachable(abort());
6402        /* NOTREACHED */
6403}
6404
6405static void FAST_FUNC
6406evalbackcmd(union node *n, struct backcmd *result)
6407{
6408        int pip[2];
6409        struct job *jp;
6410
6411        result->fd = -1;
6412        result->buf = NULL;
6413        result->nleft = 0;
6414        result->jp = NULL;
6415        if (n == NULL) {
6416                goto out;
6417        }
6418
6419        if (pipe(pip) < 0)
6420                ash_msg_and_raise_perror("can't create pipe");
6421        jp = makejob(/*n,*/ 1);
6422        if (forkshell(jp, n, FORK_NOJOB) == 0) {
6423                /* child */
6424                FORCE_INT_ON;
6425                close(pip[0]);
6426                if (pip[1] != 1) {
6427                        /*close(1);*/
6428                        dup2_or_raise(pip[1], 1);
6429                        close(pip[1]);
6430                }
6431/* TODO: eflag clearing makes the following not abort:
6432 *  ash -c 'set -e; z=$(false;echo foo); echo $z'
6433 * which is what bash does (unless it is in POSIX mode).
6434 * dash deleted "eflag = 0" line in the commit
6435 *  Date: Mon, 28 Jun 2010 17:11:58 +1000
6436 *  [EVAL] Don't clear eflag in evalbackcmd
6437 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6438 */
6439                eflag = 0;
6440                ifsfree();
6441                evaltreenr(n, EV_EXIT);
6442                /* NOTREACHED */
6443        }
6444        /* parent */
6445        close(pip[1]);
6446        result->fd = pip[0];
6447        result->jp = jp;
6448
6449 out:
6450        TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6451                result->fd, result->buf, result->nleft, result->jp));
6452}
6453
6454/*
6455 * Expand stuff in backwards quotes.
6456 */
6457static void
6458expbackq(union node *cmd, int flag)
6459{
6460        struct backcmd in;
6461        int i;
6462        char buf[128];
6463        char *p;
6464        char *dest;
6465        int startloc;
6466        int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6467        struct stackmark smark;
6468
6469        INT_OFF;
6470        startloc = expdest - (char *)stackblock();
6471        pushstackmark(&smark, startloc);
6472        evalbackcmd(cmd, &in);
6473        popstackmark(&smark);
6474
6475        p = in.buf;
6476        i = in.nleft;
6477        if (i == 0)
6478                goto read;
6479        for (;;) {
6480                memtodest(p, i, syntax, flag & QUOTES_ESC);
6481 read:
6482                if (in.fd < 0)
6483                        break;
6484                i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6485                TRACE(("expbackq: read returns %d\n", i));
6486                if (i <= 0)
6487                        break;
6488                p = buf;
6489        }
6490
6491        free(in.buf);
6492        if (in.fd >= 0) {
6493                close(in.fd);
6494                back_exitstatus = waitforjob(in.jp);
6495        }
6496        INT_ON;
6497
6498        /* Eat all trailing newlines */
6499        dest = expdest;
6500        for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6501                STUNPUTC(dest);
6502        expdest = dest;
6503
6504        if (!(flag & EXP_QUOTED))
6505                recordregion(startloc, dest - (char *)stackblock(), 0);
6506        TRACE(("evalbackq: size:%d:'%.*s'\n",
6507                (int)((dest - (char *)stackblock()) - startloc),
6508                (int)((dest - (char *)stackblock()) - startloc),
6509                stackblock() + startloc));
6510}
6511
6512#if ENABLE_FEATURE_SH_MATH
6513/*
6514 * Expand arithmetic expression.  Backup to start of expression,
6515 * evaluate, place result in (backed up) result, adjust string position.
6516 */
6517static void
6518expari(int flag)
6519{
6520        char *p, *start;
6521        int begoff;
6522        int len;
6523
6524        /* ifsfree(); */
6525
6526        /*
6527         * This routine is slightly over-complicated for
6528         * efficiency.  Next we scan backwards looking for the
6529         * start of arithmetic.
6530         */
6531        start = stackblock();
6532        p = expdest - 1;
6533        *p = '\0';
6534        p--;
6535        while (1) {
6536                int esc;
6537
6538                while ((unsigned char)*p != CTLARI) {
6539                        p--;
6540#if DEBUG
6541                        if (p < start) {
6542                                ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6543                        }
6544#endif
6545                }
6546
6547                esc = esclen(start, p);
6548                if (!(esc % 2)) {
6549                        break;
6550                }
6551
6552                p -= esc + 1;
6553        }
6554
6555        begoff = p - start;
6556
6557        removerecordregions(begoff);
6558
6559        expdest = p;
6560
6561        if (flag & QUOTES_ESC)
6562                rmescapes(p + 1, 0, NULL);
6563
6564        len = cvtnum(ash_arith(p + 1));
6565
6566        if (!(flag & EXP_QUOTED))
6567                recordregion(begoff, begoff + len, 0);
6568}
6569#endif
6570
6571/* argstr needs it */
6572static char *evalvar(char *p, int flags);
6573
6574/*
6575 * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
6576 * characters to allow for further processing.  Otherwise treat
6577 * $@ like $* since no splitting will be performed.
6578 */
6579static void
6580argstr(char *p, int flags)
6581{
6582        static const char spclchars[] ALIGN1 = {
6583                '=',
6584                ':',
6585                CTLQUOTEMARK,
6586                CTLENDVAR,
6587                CTLESC,
6588                CTLVAR,
6589                CTLBACKQ,
6590#if ENABLE_FEATURE_SH_MATH
6591                CTLENDARI,
6592#endif
6593                '\0'
6594        };
6595        const char *reject = spclchars;
6596        int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6597        int inquotes;
6598        size_t length;
6599        int startloc;
6600
6601        if (!(flags & EXP_VARTILDE)) {
6602                reject += 2;
6603        } else if (flags & EXP_VARTILDE2) {
6604                reject++;
6605        }
6606        inquotes = 0;
6607        length = 0;
6608        if (flags & EXP_TILDE) {
6609                char *q;
6610
6611                flags &= ~EXP_TILDE;
6612 tilde:
6613                q = p;
6614                if (*q == '~')
6615                        p = exptilde(p, q, flags);
6616        }
6617 start:
6618        startloc = expdest - (char *)stackblock();
6619        for (;;) {
6620                unsigned char c;
6621
6622                length += strcspn(p + length, reject);
6623                c = p[length];
6624                if (c) {
6625                        if (!(c & 0x80)
6626                        IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6627                        ) {
6628                                /* c == '=' || c == ':' || c == CTLENDARI */
6629                                length++;
6630                        }
6631                }
6632                if (length > 0) {
6633                        int newloc;
6634                        expdest = stack_nputstr(p, length, expdest);
6635                        newloc = expdest - (char *)stackblock();
6636                        if (breakall && !inquotes && newloc > startloc) {
6637                                recordregion(startloc, newloc, 0);
6638                        }
6639                        startloc = newloc;
6640                }
6641                p += length + 1;
6642                length = 0;
6643
6644                switch (c) {
6645                case '\0':
6646                        goto breakloop;
6647                case '=':
6648                        if (flags & EXP_VARTILDE2) {
6649                                p--;
6650                                continue;
6651                        }
6652                        flags |= EXP_VARTILDE2;
6653                        reject++;
6654                        /* fall through */
6655                case ':':
6656                        /*
6657                         * sort of a hack - expand tildes in variable
6658                         * assignments (after the first '=' and after ':'s).
6659                         */
6660                        if (*--p == '~') {
6661                                goto tilde;
6662                        }
6663                        continue;
6664                }
6665
6666                switch (c) {
6667                case CTLENDVAR: /* ??? */
6668                        goto breakloop;
6669                case CTLQUOTEMARK:
6670                        /* "$@" syntax adherence hack */
6671                        if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6672                                p = evalvar(p + 1, flags | EXP_QUOTED) + 1;
6673                                goto start;
6674                        }
6675                        inquotes ^= EXP_QUOTED;
6676 addquote:
6677                        if (flags & QUOTES_ESC) {
6678                                p--;
6679                                length++;
6680                                startloc++;
6681                        }
6682                        break;
6683                case CTLESC:
6684                        startloc++;
6685                        length++;
6686                        goto addquote;
6687                case CTLVAR:
6688                        TRACE(("argstr: evalvar('%s')\n", p));
6689                        p = evalvar(p, flags | inquotes);
6690                        TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6691                        goto start;
6692                case CTLBACKQ:
6693                        expbackq(argbackq->n, flags | inquotes);
6694                        argbackq = argbackq->next;
6695                        goto start;
6696#if ENABLE_FEATURE_SH_MATH
6697                case CTLENDARI:
6698                        p--;
6699                        expari(flags | inquotes);
6700                        goto start;
6701#endif
6702                }
6703        }
6704 breakloop: ;
6705}
6706
6707static char *
6708scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6709                char *pattern, int quotes, int zero)
6710{
6711        char *loc, *loc2;
6712        char c;
6713
6714        loc = startp;
6715        loc2 = rmesc;
6716        do {
6717                int match;
6718                const char *s = loc2;
6719
6720                c = *loc2;
6721                if (zero) {
6722                        *loc2 = '\0';
6723                        s = rmesc;
6724                }
6725                match = pmatch(pattern, s);
6726
6727                *loc2 = c;
6728                if (match)
6729                        return loc;
6730                if (quotes && (unsigned char)*loc == CTLESC)
6731                        loc++;
6732                loc++;
6733                loc2++;
6734        } while (c);
6735        return NULL;
6736}
6737
6738static char *
6739scanright(char *startp, char *rmesc, char *rmescend,
6740                char *pattern, int quotes, int match_at_start)
6741{
6742#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6743        int try2optimize = match_at_start;
6744#endif
6745        int esc = 0;
6746        char *loc;
6747        char *loc2;
6748
6749        /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6750         * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6751         * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6752         * Logic:
6753         * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6754         * and on each iteration they go back two/one char until they reach the beginning.
6755         * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6756         */
6757        /* TODO: document in what other circumstances we are called. */
6758
6759        for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6760                int match;
6761                char c = *loc2;
6762                const char *s = loc2;
6763                if (match_at_start) {
6764                        *loc2 = '\0';
6765                        s = rmesc;
6766                }
6767                match = pmatch(pattern, s);
6768                //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6769                *loc2 = c;
6770                if (match)
6771                        return loc;
6772#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6773                if (try2optimize) {
6774                        /* Maybe we can optimize this:
6775                         * if pattern ends with unescaped *, we can avoid checking
6776                         * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6777                         * it won't match truncated "raw_value_of_" strings too.
6778                         */
6779                        unsigned plen = strlen(pattern);
6780                        /* Does it end with "*"? */
6781                        if (plen != 0 && pattern[--plen] == '*') {
6782                                /* "xxxx*" is not escaped */
6783                                /* "xxx\*" is escaped */
6784                                /* "xx\\*" is not escaped */
6785                                /* "x\\\*" is escaped */
6786                                int slashes = 0;
6787                                while (plen != 0 && pattern[--plen] == '\\')
6788                                        slashes++;
6789                                if (!(slashes & 1))
6790                                        break; /* ends with unescaped "*" */
6791                        }
6792                        try2optimize = 0;
6793                }
6794#endif
6795                loc--;
6796                if (quotes) {
6797                        if (--esc < 0) {
6798                                esc = esclen(startp, loc);
6799                        }
6800                        if (esc % 2) {
6801                                esc--;
6802                                loc--;
6803                        }
6804                }
6805        }
6806        return NULL;
6807}
6808
6809static void varunset(const char *, const char *, const char *, int) NORETURN;
6810static void
6811varunset(const char *end, const char *var, const char *umsg, int varflags)
6812{
6813        const char *msg;
6814        const char *tail;
6815
6816        tail = nullstr;
6817        msg = "parameter not set";
6818        if (umsg) {
6819                if ((unsigned char)*end == CTLENDVAR) {
6820                        if (varflags & VSNUL)
6821                                tail = " or null";
6822                } else {
6823                        msg = umsg;
6824                }
6825        }
6826        ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6827}
6828
6829static const char *
6830subevalvar(char *p, char *varname, int strloc, int subtype,
6831                int startloc, int varflags, int flag)
6832{
6833        struct nodelist *saveargbackq = argbackq;
6834        int quotes = flag & QUOTES_ESC;
6835        char *startp;
6836        char *loc;
6837        char *rmesc, *rmescend;
6838        char *str;
6839        int amount, resetloc;
6840        int argstr_flags;
6841        IF_BASH_PATTERN_SUBST(int workloc;)
6842        IF_BASH_PATTERN_SUBST(int slash_pos;)
6843        IF_BASH_PATTERN_SUBST(char *repl;)
6844        int zero;
6845        char *(*scan)(char*, char*, char*, char*, int, int);
6846
6847        //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6848        //              p, varname, strloc, subtype, startloc, varflags, quotes);
6849
6850#if BASH_PATTERN_SUBST
6851        /* For "${v/pattern/repl}", we must find the delimiter _before_
6852         * argstr() call expands possible variable references in pattern:
6853         * think about "v=a; a=a/; echo ${v/$a/r}" case.
6854         */
6855        repl = NULL;
6856        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6857                /* Find '/' and replace with NUL */
6858                repl = p;
6859                /* The pattern can't be empty.
6860                 * IOW: if the first char after "${v//" is a slash,
6861                 * it does not terminate the pattern - it's the first char of the pattern:
6862                 *  v=/dev/ram; echo ${v////-}  prints -dev-ram (pattern is "/")
6863                 *  v=/dev/ram; echo ${v///r/-} prints /dev-am  (pattern is "/r")
6864                 */
6865                if (*repl == '/')
6866                        repl++;
6867                for (;;) {
6868                        if (*repl == '\0') {
6869                                repl = NULL;
6870                                break;
6871                        }
6872                        if (*repl == '/') {
6873                                *repl = '\0';
6874                                break;
6875                        }
6876                        /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
6877                        if ((unsigned char)*repl == CTLESC && repl[1])
6878                                repl++;
6879                        repl++;
6880                }
6881        }
6882#endif
6883        argstr_flags = EXP_TILDE;
6884        if (subtype != VSASSIGN
6885         && subtype != VSQUESTION
6886#if BASH_SUBSTR
6887         && subtype != VSSUBSTR
6888#endif
6889        ) {
6890                /* EXP_CASE keeps CTLESC's */
6891                argstr_flags = EXP_TILDE | EXP_CASE;
6892        }
6893        argstr(p, argstr_flags);
6894        //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
6895#if BASH_PATTERN_SUBST
6896        slash_pos = -1;
6897        if (repl) {
6898                slash_pos = expdest - ((char *)stackblock() + strloc);
6899                STPUTC('/', expdest);
6900                //bb_error_msg("repl+1:'%s'", repl + 1);
6901                argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
6902                *repl = '/';
6903        }
6904#endif
6905        STPUTC('\0', expdest);
6906        argbackq = saveargbackq;
6907        startp = (char *)stackblock() + startloc;
6908        //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
6909
6910        switch (subtype) {
6911        case VSASSIGN:
6912                setvar0(varname, startp);
6913                amount = startp - expdest;
6914                STADJUST(amount, expdest);
6915                return startp;
6916
6917        case VSQUESTION:
6918                varunset(p, varname, startp, varflags);
6919                /* NOTREACHED */
6920
6921#if BASH_SUBSTR
6922        case VSSUBSTR: {
6923                int pos, len, orig_len;
6924                char *colon;
6925
6926                loc = str = stackblock() + strloc;
6927
6928                /* Read POS in ${var:POS:LEN} */
6929                colon = strchr(loc, ':');
6930                if (colon) *colon = '\0';
6931                pos = substr_atoi(loc);
6932                if (colon) *colon = ':';
6933
6934                /* Read LEN in ${var:POS:LEN} */
6935                len = str - startp - 1;
6936                /* *loc != '\0', guaranteed by parser */
6937                if (quotes) {
6938                        char *ptr;
6939                        /* Adjust the length by the number of escapes */
6940                        for (ptr = startp; ptr < (str - 1); ptr++) {
6941                                if ((unsigned char)*ptr == CTLESC) {
6942                                        len--;
6943                                        ptr++;
6944                                }
6945                        }
6946                }
6947                orig_len = len;
6948                if (*loc++ == ':') {
6949                        /* ${var::LEN} */
6950                        len = substr_atoi(loc);
6951                } else {
6952                        /* Skip POS in ${var:POS:LEN} */
6953                        len = orig_len;
6954                        while (*loc && *loc != ':')
6955                                loc++;
6956                        if (*loc++ == ':')
6957                                len = substr_atoi(loc);
6958                }
6959                if (pos < 0) {
6960                        /* ${VAR:$((-n)):l} starts n chars from the end */
6961                        pos = orig_len + pos;
6962                }
6963                if ((unsigned)pos >= orig_len) {
6964                        /* apart from obvious ${VAR:999999:l},
6965                         * covers ${VAR:$((-9999999)):l} - result is ""
6966                         * (bash compat)
6967                         */
6968                        pos = 0;
6969                        len = 0;
6970                }
6971                if (len < 0) {
6972                        /* ${VAR:N:-M} sets LEN to strlen()-M */
6973                        len = (orig_len - pos) + len;
6974                }
6975                if ((unsigned)len > (orig_len - pos))
6976                        len = orig_len - pos;
6977
6978                for (str = startp; pos; str++, pos--) {
6979                        if (quotes && (unsigned char)*str == CTLESC)
6980                                str++;
6981                }
6982                for (loc = startp; len; len--) {
6983                        if (quotes && (unsigned char)*str == CTLESC)
6984                                *loc++ = *str++;
6985                        *loc++ = *str++;
6986                }
6987                *loc = '\0';
6988                amount = loc - expdest;
6989                STADJUST(amount, expdest);
6990                return loc;
6991        }
6992#endif /* BASH_SUBSTR */
6993        }
6994
6995        resetloc = expdest - (char *)stackblock();
6996
6997#if BASH_PATTERN_SUBST
6998        repl = NULL;
6999
7000        /* We'll comeback here if we grow the stack while handling
7001         * a VSREPLACE or VSREPLACEALL, since our pointers into the
7002         * stack will need rebasing, and we'll need to remove our work
7003         * areas each time
7004         */
7005 restart:
7006#endif
7007
7008        amount = expdest - ((char *)stackblock() + resetloc);
7009        STADJUST(-amount, expdest);
7010        startp = (char *)stackblock() + startloc;
7011
7012        rmesc = startp;
7013        rmescend = (char *)stackblock() + strloc;
7014        //bb_error_msg("str7:'%s'", rmescend);
7015        if (quotes) {
7016//TODO: how to handle slash_pos here if string changes (shortens?)
7017                rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
7018                if (rmesc != startp) {
7019                        rmescend = expdest;
7020                        startp = (char *)stackblock() + startloc;
7021                }
7022        }
7023        rmescend--;
7024        str = (char *)stackblock() + strloc;
7025        /*
7026         * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7027         * The result is a_\_z_c (not a\_\_z_c)!
7028         *
7029         * The search pattern and replace string treat backslashes differently!
7030         * "&slash_pos" causes rmescapes() to work differently on the pattern
7031         * and string.  It's only used on the first call.
7032         */
7033        //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7034        rmescapes(str, RMESCAPE_GLOB,
7035                repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7036        );
7037
7038#if BASH_PATTERN_SUBST
7039        workloc = expdest - (char *)stackblock();
7040        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7041                int len;
7042                char *idx, *end;
7043
7044                if (!repl) {
7045                        //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
7046                        repl = nullstr;
7047                        if (slash_pos >= 0) {
7048                                repl = str + slash_pos;
7049                                *repl++ = '\0';
7050                        }
7051                }
7052                //bb_error_msg("str:'%s' repl:'%s'", str, repl);
7053
7054                /* If there's no pattern to match, return the expansion unmolested */
7055                if (str[0] == '\0')
7056                        return NULL;
7057
7058                len = 0;
7059                idx = startp;
7060                end = str - 1;
7061                while (idx < end) {
7062 try_to_match:
7063                        loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
7064                        //bb_error_msg("scanright('%s'):'%s'", str, loc);
7065                        if (!loc) {
7066                                /* No match, advance */
7067                                char *restart_detect = stackblock();
7068 skip_matching:
7069                                STPUTC(*idx, expdest);
7070                                if (quotes && (unsigned char)*idx == CTLESC) {
7071                                        idx++;
7072                                        len++;
7073                                        STPUTC(*idx, expdest);
7074                                }
7075                                if (stackblock() != restart_detect)
7076                                        goto restart;
7077                                idx++;
7078                                len++;
7079                                rmesc++;
7080                                /* continue; - prone to quadratic behavior, smarter code: */
7081                                if (idx >= end)
7082                                        break;
7083                                if (str[0] == '*') {
7084                                        /* Pattern is "*foo". If "*foo" does not match "long_string",
7085                                         * it would never match "ong_string" etc, no point in trying.
7086                                         */
7087                                        goto skip_matching;
7088                                }
7089                                goto try_to_match;
7090                        }
7091
7092                        if (subtype == VSREPLACEALL) {
7093                                while (idx < loc) {
7094                                        if (quotes && (unsigned char)*idx == CTLESC)
7095                                                idx++;
7096                                        idx++;
7097                                        rmesc++;
7098                                }
7099                        } else {
7100                                idx = loc;
7101                        }
7102
7103                        //bb_error_msg("repl:'%s'", repl);
7104                        for (loc = (char*)repl; *loc; loc++) {
7105                                char *restart_detect = stackblock();
7106                                if (quotes && *loc == '\\') {
7107                                        STPUTC(CTLESC, expdest);
7108                                        len++;
7109                                }
7110                                STPUTC(*loc, expdest);
7111                                if (stackblock() != restart_detect)
7112                                        goto restart;
7113                                len++;
7114                        }
7115
7116                        if (subtype == VSREPLACE) {
7117                                //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
7118                                while (*idx) {
7119                                        char *restart_detect = stackblock();
7120                                        STPUTC(*idx, expdest);
7121                                        if (stackblock() != restart_detect)
7122                                                goto restart;
7123                                        len++;
7124                                        idx++;
7125                                }
7126                                break;
7127                        }
7128                }
7129
7130                /* We've put the replaced text into a buffer at workloc, now
7131                 * move it to the right place and adjust the stack.
7132                 */
7133                STPUTC('\0', expdest);
7134                startp = (char *)stackblock() + startloc;
7135                memmove(startp, (char *)stackblock() + workloc, len + 1);
7136                //bb_error_msg("startp:'%s'", startp);
7137                amount = expdest - (startp + len);
7138                STADJUST(-amount, expdest);
7139                return startp;
7140        }
7141#endif /* BASH_PATTERN_SUBST */
7142
7143        subtype -= VSTRIMRIGHT;
7144#if DEBUG
7145        if (subtype < 0 || subtype > 7)
7146                abort();
7147#endif
7148        /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
7149        zero = subtype >> 1;
7150        /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7151        scan = (subtype & 1) ^ zero ? scanleft : scanright;
7152
7153        loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7154        if (loc) {
7155                if (zero) {
7156                        memmove(startp, loc, str - loc);
7157                        loc = startp + (str - loc) - 1;
7158                }
7159                *loc = '\0';
7160                amount = loc - expdest;
7161                STADJUST(amount, expdest);
7162        }
7163        return loc;
7164}
7165
7166/*
7167 * Add the value of a specialized variable to the stack string.
7168 * name parameter (examples):
7169 * ash -c 'echo $1'      name:'1='
7170 * ash -c 'echo $qwe'    name:'qwe='
7171 * ash -c 'echo $$'      name:'$='
7172 * ash -c 'echo ${$}'    name:'$='
7173 * ash -c 'echo ${$##q}' name:'$=q'
7174 * ash -c 'echo ${#$}'   name:'$='
7175 * note: examples with bad shell syntax:
7176 * ash -c 'echo ${#$1}'  name:'$=1'
7177 * ash -c 'echo ${#1#}'  name:'1=#'
7178 */
7179static NOINLINE ssize_t
7180varvalue(char *name, int varflags, int flags, int quoted)
7181{
7182        const char *p;
7183        int num;
7184        int i;
7185        ssize_t len = 0;
7186        int sep;
7187        int subtype = varflags & VSTYPE;
7188        int discard = subtype == VSPLUS || subtype == VSLENGTH;
7189        int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
7190        int syntax;
7191
7192        sep = (flags & EXP_FULL) << CHAR_BIT;
7193        syntax = quoted ? DQSYNTAX : BASESYNTAX;
7194
7195        switch (*name) {
7196        case '$':
7197                num = rootpid;
7198                goto numvar;
7199        case '?':
7200                num = exitstatus;
7201                goto numvar;
7202        case '#':
7203                num = shellparam.nparam;
7204                goto numvar;
7205        case '!':
7206                num = backgndpid;
7207                if (num == 0)
7208                        return -1;
7209 numvar:
7210                len = cvtnum(num);
7211                goto check_1char_name;
7212        case '-':
7213                expdest = makestrspace(NOPTS, expdest);
7214                for (i = NOPTS - 1; i >= 0; i--) {
7215                        if (optlist[i] && optletters(i)) {
7216                                USTPUTC(optletters(i), expdest);
7217                                len++;
7218                        }
7219                }
7220 check_1char_name:
7221#if 0
7222                /* handles cases similar to ${#$1} */
7223                if (name[2] != '\0')
7224                        raise_error_syntax("bad substitution");
7225#endif
7226                break;
7227        case '@':
7228                if (quoted && sep)
7229                        goto param;
7230                /* fall through */
7231        case '*': {
7232                char **ap;
7233                char sepc;
7234                char c;
7235
7236                /* We will set c to 0 or ~0 depending on whether
7237                 * we're doing field splitting.  We won't do field
7238                 * splitting if either we're quoted or sep is zero.
7239                 *
7240                 * Instead of testing (quoted || !sep) the following
7241                 * trick optimises away any branches by using the
7242                 * fact that EXP_QUOTED (which is the only bit that
7243                 * can be set in quoted) is the same as EXP_FULL <<
7244                 * CHAR_BIT (which is the only bit that can be set
7245                 * in sep).
7246                 */
7247#if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7248#error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7249#endif
7250                c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7251                sep &= ~quoted;
7252                sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
7253 param:
7254                sepc = sep;
7255                ap = shellparam.p;
7256                if (!ap)
7257                        return -1;
7258                while ((p = *ap++) != NULL) {
7259                        len += strtodest(p, syntax, quotes);
7260
7261                        if (*ap && sep) {
7262                                len++;
7263                                memtodest(&sepc, 1, syntax, quotes);
7264                        }
7265                }
7266                break;
7267        } /* case '*' */
7268        case '0':
7269        case '1':
7270        case '2':
7271        case '3':
7272        case '4':
7273        case '5':
7274        case '6':
7275        case '7':
7276        case '8':
7277        case '9':
7278                num = atoi(name); /* number(name) fails on ${N#str} etc */
7279                if (num < 0 || num > shellparam.nparam)
7280                        return -1;
7281                p = num ? shellparam.p[num - 1] : arg0;
7282                goto value;
7283        default:
7284                /* NB: name has form "VAR=..." */
7285                p = lookupvar(name);
7286 value:
7287                if (!p)
7288                        return -1;
7289
7290                len = strtodest(p, syntax, quotes);
7291#if ENABLE_UNICODE_SUPPORT
7292                if (subtype == VSLENGTH && len > 0) {
7293                        reinit_unicode_for_ash();
7294                        if (unicode_status == UNICODE_ON) {
7295                                STADJUST(-len, expdest);
7296                                discard = 0;
7297                                len = unicode_strlen(p);
7298                        }
7299                }
7300#endif
7301                break;
7302        }
7303
7304        if (discard)
7305                STADJUST(-len, expdest);
7306        return len;
7307}
7308
7309/*
7310 * Expand a variable, and return a pointer to the next character in the
7311 * input string.
7312 */
7313static char *
7314evalvar(char *p, int flag)
7315{
7316        char varflags;
7317        char subtype;
7318        int quoted;
7319        char *var;
7320        int patloc;
7321        int startloc;
7322        ssize_t varlen;
7323
7324        varflags = (unsigned char) *p++;
7325        subtype = varflags & VSTYPE;
7326
7327        if (!subtype)
7328                raise_error_syntax("bad substitution");
7329
7330        quoted = flag & EXP_QUOTED;
7331        var = p;
7332        startloc = expdest - (char *)stackblock();
7333        p = strchr(p, '=') + 1; //TODO: use var_end(p)?
7334
7335 again:
7336        varlen = varvalue(var, varflags, flag, quoted);
7337        if (varflags & VSNUL)
7338                varlen--;
7339
7340        if (subtype == VSPLUS) {
7341                varlen = -1 - varlen;
7342                goto vsplus;
7343        }
7344
7345        if (subtype == VSMINUS) {
7346 vsplus:
7347                if (varlen < 0) {
7348                        argstr(
7349                                p,
7350                                flag | EXP_TILDE | EXP_WORD
7351                        );
7352                        goto end;
7353                }
7354                goto record;
7355        }
7356
7357        if (subtype == VSASSIGN || subtype == VSQUESTION) {
7358                if (varlen >= 0)
7359                        goto record;
7360
7361                subevalvar(p, var, 0, subtype, startloc, varflags,
7362                           flag & ~QUOTES_ESC);
7363                varflags &= ~VSNUL;
7364                /*
7365                 * Remove any recorded regions beyond
7366                 * start of variable
7367                 */
7368                removerecordregions(startloc);
7369                goto again;
7370        }
7371
7372        if (varlen < 0 && uflag)
7373                varunset(p, var, 0, 0);
7374
7375        if (subtype == VSLENGTH) {
7376                cvtnum(varlen > 0 ? varlen : 0);
7377                goto record;
7378        }
7379
7380        if (subtype == VSNORMAL) {
7381 record:
7382                if (quoted) {
7383                        quoted = *var == '@' && shellparam.nparam;
7384                        if (!quoted)
7385                                goto end;
7386                }
7387                recordregion(startloc, expdest - (char *)stackblock(), quoted);
7388                goto end;
7389        }
7390
7391#if DEBUG
7392        switch (subtype) {
7393        case VSTRIMLEFT:
7394        case VSTRIMLEFTMAX:
7395        case VSTRIMRIGHT:
7396        case VSTRIMRIGHTMAX:
7397#if BASH_SUBSTR
7398        case VSSUBSTR:
7399#endif
7400#if BASH_PATTERN_SUBST
7401        case VSREPLACE:
7402        case VSREPLACEALL:
7403#endif
7404                break;
7405        default:
7406                abort();
7407        }
7408#endif
7409
7410        if (varlen >= 0) {
7411                /*
7412                 * Terminate the string and start recording the pattern
7413                 * right after it
7414                 */
7415                STPUTC('\0', expdest);
7416                patloc = expdest - (char *)stackblock();
7417                if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
7418                                startloc, varflags, flag)) {
7419                        int amount = expdest - (
7420                                (char *)stackblock() + patloc - 1
7421                        );
7422                        STADJUST(-amount, expdest);
7423                }
7424                /* Remove any recorded regions beyond start of variable */
7425                removerecordregions(startloc);
7426                goto record;
7427        }
7428
7429 end:
7430        if (subtype != VSNORMAL) {      /* skip to end of alternative */
7431                int nesting = 1;
7432                for (;;) {
7433                        unsigned char c = *p++;
7434                        if (c == CTLESC)
7435                                p++;
7436                        else if (c == CTLBACKQ) {
7437                                if (varlen >= 0)
7438                                        argbackq = argbackq->next;
7439                        } else if (c == CTLVAR) {
7440                                if ((*p++ & VSTYPE) != VSNORMAL)
7441                                        nesting++;
7442                        } else if (c == CTLENDVAR) {
7443                                if (--nesting == 0)
7444                                        break;
7445                        }
7446                }
7447        }
7448        return p;
7449}
7450
7451/*
7452 * Add a file name to the list.
7453 */
7454static void
7455addfname(const char *name)
7456{
7457        struct strlist *sp;
7458
7459        sp = stzalloc(sizeof(*sp));
7460        sp->text = sstrdup(name);
7461        *exparg.lastp = sp;
7462        exparg.lastp = &sp->next;
7463}
7464
7465/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7466static int
7467hasmeta(const char *p)
7468{
7469        static const char chars[] ALIGN1 = {
7470                '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7471        };
7472
7473        for (;;) {
7474                p = strpbrk(p, chars);
7475                if (!p)
7476                        break;
7477                switch ((unsigned char)*p) {
7478                case CTLQUOTEMARK:
7479                        for (;;) {
7480                                p++;
7481                                if ((unsigned char)*p == CTLQUOTEMARK)
7482                                        break;
7483                                if ((unsigned char)*p == CTLESC)
7484                                        p++;
7485                                if (*p == '\0') /* huh? */
7486                                        return 0;
7487                        }
7488                        break;
7489                case '\\':
7490                case CTLESC:
7491                        p++;
7492                        if (*p == '\0')
7493                                return 0;
7494                        break;
7495                case '[':
7496                        if (!strchr(p + 1, ']')) {
7497                                /* It's not a properly closed [] pattern,
7498                                 * but other metas may follow. Continue checking.
7499                                 * my[file* _is_ globbed by bash
7500                                 * and matches filenames like "my[file1".
7501                                 */
7502                                break;
7503                        }
7504                        /* fallthrough */
7505                default:
7506                /* case '*': */
7507                /* case '?': */
7508                        return 1;
7509                }
7510                p++;
7511        }
7512
7513        return 0;
7514}
7515
7516/* If we want to use glob() from libc... */
7517#if !ENABLE_ASH_INTERNAL_GLOB
7518
7519/* Add the result of glob() to the list */
7520static void
7521addglob(const glob_t *pglob)
7522{
7523        char **p = pglob->gl_pathv;
7524
7525        do {
7526                addfname(*p);
7527        } while (*++p);
7528}
7529static void
7530expandmeta(struct strlist *str /*, int flag*/)
7531{
7532        /* TODO - EXP_REDIR */
7533
7534        while (str) {
7535                char *p;
7536                glob_t pglob;
7537                int i;
7538
7539                if (fflag)
7540                        goto nometa;
7541
7542                if (!hasmeta(str->text))
7543                        goto nometa;
7544
7545                INT_OFF;
7546                p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7547// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7548// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7549//
7550// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7551// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7552// Which means you need to unescape the string, right? Not so fast:
7553// if there _is_ a file named "file\?" (with backslash), it is returned
7554// as "file\?" too (whichever pattern you used to find it, say, "file*").
7555// You DON'T KNOW by looking at the result whether you need to unescape it.
7556//
7557// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7558// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7559// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7560// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7561//              i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7562//              i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7563                i = glob(p, 0, NULL, &pglob);
7564                //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7565                if (p != str->text)
7566                        free(p);
7567                switch (i) {
7568                case 0:
7569#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7570                        /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7571                        if (!(pglob.gl_flags & GLOB_MAGCHAR))
7572                                goto nometa2;
7573#endif
7574                        addglob(&pglob);
7575                        globfree(&pglob);
7576                        INT_ON;
7577                        break;
7578                case GLOB_NOMATCH:
7579 //nometa2:
7580                        globfree(&pglob);
7581                        INT_ON;
7582 nometa:
7583                        *exparg.lastp = str;
7584                        rmescapes(str->text, 0, NULL);
7585                        exparg.lastp = &str->next;
7586                        break;
7587                default:        /* GLOB_NOSPACE */
7588                        globfree(&pglob);
7589                        INT_ON;
7590                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
7591                }
7592                str = str->next;
7593        }
7594}
7595
7596#else
7597/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7598
7599/*
7600 * Do metacharacter (i.e. *, ?, [...]) expansion.
7601 */
7602typedef struct exp_t {
7603        char *dir;
7604        unsigned dir_max;
7605} exp_t;
7606static void
7607expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7608{
7609#define expdir exp->dir
7610#define expdir_max exp->dir_max
7611        char *enddir = expdir + expdir_len;
7612        char *p;
7613        const char *cp;
7614        char *start;
7615        char *endname;
7616        int metaflag;
7617        struct stat statb;
7618        DIR *dirp;
7619        struct dirent *dp;
7620        int atend;
7621        int matchdot;
7622        int esc;
7623
7624        metaflag = 0;
7625        start = name;
7626        for (p = name; esc = 0, *p; p += esc + 1) {
7627                if (*p == '*' || *p == '?')
7628                        metaflag = 1;
7629                else if (*p == '[') {
7630                        char *q = p + 1;
7631                        if (*q == '!')
7632                                q++;
7633                        for (;;) {
7634                                if (*q == '\\')
7635                                        q++;
7636                                if (*q == '/' || *q == '\0')
7637                                        break;
7638                                if (*++q == ']') {
7639                                        metaflag = 1;
7640                                        break;
7641                                }
7642                        }
7643                } else {
7644                        if (*p == '\\' && p[1])
7645                                esc++;
7646                        if (p[esc] == '/') {
7647                                if (metaflag)
7648                                        break;
7649                                start = p + esc + 1;
7650                        }
7651                }
7652        }
7653        if (metaflag == 0) {    /* we've reached the end of the file name */
7654                if (!expdir_len)
7655                        return;
7656                p = name;
7657                do {
7658                        if (*p == '\\' && p[1])
7659                                p++;
7660                        *enddir++ = *p;
7661                } while (*p++);
7662                if (lstat(expdir, &statb) == 0)
7663                        addfname(expdir);
7664                return;
7665        }
7666        endname = p;
7667        if (name < start) {
7668                p = name;
7669                do {
7670                        if (*p == '\\' && p[1])
7671                                p++;
7672                        *enddir++ = *p++;
7673                } while (p < start);
7674        }
7675        *enddir = '\0';
7676        cp = expdir;
7677        expdir_len = enddir - cp;
7678        if (!expdir_len)
7679                cp = ".";
7680        dirp = opendir(cp);
7681        if (dirp == NULL)
7682                return;
7683        if (*endname == 0) {
7684                atend = 1;
7685        } else {
7686                atend = 0;
7687                *endname = '\0';
7688                endname += esc + 1;
7689        }
7690        name_len -= endname - name;
7691        matchdot = 0;
7692        p = start;
7693        if (*p == '\\')
7694                p++;
7695        if (*p == '.')
7696                matchdot++;
7697        while (!pending_int && (dp = readdir(dirp)) != NULL) {
7698                if (dp->d_name[0] == '.' && !matchdot)
7699                        continue;
7700                if (pmatch(start, dp->d_name)) {
7701                        if (atend) {
7702                                strcpy(enddir, dp->d_name);
7703                                addfname(expdir);
7704                        } else {
7705                                unsigned offset;
7706                                unsigned len;
7707
7708                                p = stpcpy(enddir, dp->d_name);
7709                                *p = '/';
7710
7711                                offset = p - expdir + 1;
7712                                len = offset + name_len + NAME_MAX;
7713                                if (len > expdir_max) {
7714                                        len += PATH_MAX;
7715                                        expdir = ckrealloc(expdir, len);
7716                                        expdir_max = len;
7717                                }
7718
7719                                expmeta(exp, endname, name_len, offset);
7720                                enddir = expdir + expdir_len;
7721                        }
7722                }
7723        }
7724        closedir(dirp);
7725        if (!atend)
7726                endname[-esc - 1] = esc ? '\\' : '/';
7727#undef expdir
7728#undef expdir_max
7729}
7730
7731static struct strlist *
7732msort(struct strlist *list, int len)
7733{
7734        struct strlist *p, *q = NULL;
7735        struct strlist **lpp;
7736        int half;
7737        int n;
7738
7739        if (len <= 1)
7740                return list;
7741        half = len >> 1;
7742        p = list;
7743        for (n = half; --n >= 0;) {
7744                q = p;
7745                p = p->next;
7746        }
7747        q->next = NULL;                 /* terminate first half of list */
7748        q = msort(list, half);          /* sort first half of list */
7749        p = msort(p, len - half);               /* sort second half */
7750        lpp = &list;
7751        for (;;) {
7752#if ENABLE_LOCALE_SUPPORT
7753                if (strcoll(p->text, q->text) < 0)
7754#else
7755                if (strcmp(p->text, q->text) < 0)
7756#endif
7757                                                {
7758                        *lpp = p;
7759                        lpp = &p->next;
7760                        p = *lpp;
7761                        if (p == NULL) {
7762                                *lpp = q;
7763                                break;
7764                        }
7765                } else {
7766                        *lpp = q;
7767                        lpp = &q->next;
7768                        q = *lpp;
7769                        if (q == NULL) {
7770                                *lpp = p;
7771                                break;
7772                        }
7773                }
7774        }
7775        return list;
7776}
7777
7778/*
7779 * Sort the results of file name expansion.  It calculates the number of
7780 * strings to sort and then calls msort (short for merge sort) to do the
7781 * work.
7782 */
7783static struct strlist *
7784expsort(struct strlist *str)
7785{
7786        int len;
7787        struct strlist *sp;
7788
7789        len = 0;
7790        for (sp = str; sp; sp = sp->next)
7791                len++;
7792        return msort(str, len);
7793}
7794
7795static void
7796expandmeta(struct strlist *str /*, int flag*/)
7797{
7798        /* TODO - EXP_REDIR */
7799
7800        while (str) {
7801                exp_t exp;
7802                struct strlist **savelastp;
7803                struct strlist *sp;
7804                char *p;
7805                unsigned len;
7806
7807                if (fflag)
7808                        goto nometa;
7809                if (!hasmeta(str->text))
7810                        goto nometa;
7811                savelastp = exparg.lastp;
7812
7813                INT_OFF;
7814                p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7815                len = strlen(p);
7816                exp.dir_max = len + PATH_MAX;
7817                exp.dir = ckmalloc(exp.dir_max);
7818
7819                expmeta(&exp, p, len, 0);
7820                free(exp.dir);
7821                if (p != str->text)
7822                        free(p);
7823                INT_ON;
7824                if (exparg.lastp == savelastp) {
7825                        /*
7826                         * no matches
7827                         */
7828 nometa:
7829                        *exparg.lastp = str;
7830                        rmescapes(str->text, 0, NULL);
7831                        exparg.lastp = &str->next;
7832                } else {
7833                        *exparg.lastp = NULL;
7834                        *savelastp = sp = expsort(*savelastp);
7835                        while (sp->next != NULL)
7836                                sp = sp->next;
7837                        exparg.lastp = &sp->next;
7838                }
7839                str = str->next;
7840        }
7841}
7842#endif /* ENABLE_ASH_INTERNAL_GLOB */
7843
7844/*
7845 * Perform variable substitution and command substitution on an argument,
7846 * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
7847 * perform splitting and file name expansion.  When arglist is NULL, perform
7848 * here document expansion.
7849 */
7850static void
7851expandarg(union node *arg, struct arglist *arglist, int flag)
7852{
7853        struct strlist *sp;
7854        char *p;
7855
7856        argbackq = arg->narg.backquote;
7857        STARTSTACKSTR(expdest);
7858        TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7859        argstr(arg->narg.text, flag);
7860        p = _STPUTC('\0', expdest);
7861        expdest = p - 1;
7862        if (arglist == NULL) {
7863                /* here document expanded */
7864                goto out;
7865        }
7866        p = grabstackstr(p);
7867        TRACE(("expandarg: p:'%s'\n", p));
7868        exparg.lastp = &exparg.list;
7869        /*
7870         * TODO - EXP_REDIR
7871         */
7872        if (flag & EXP_FULL) {
7873                ifsbreakup(p, &exparg);
7874                *exparg.lastp = NULL;
7875                exparg.lastp = &exparg.list;
7876                expandmeta(exparg.list /*, flag*/);
7877        } else {
7878                sp = stzalloc(sizeof(*sp));
7879                sp->text = p;
7880                *exparg.lastp = sp;
7881                exparg.lastp = &sp->next;
7882        }
7883        *exparg.lastp = NULL;
7884        if (exparg.list) {
7885                *arglist->lastp = exparg.list;
7886                arglist->lastp = exparg.lastp;
7887        }
7888
7889 out:
7890        ifsfree();
7891}
7892
7893/*
7894 * Expand shell variables and backquotes inside a here document.
7895 */
7896static void
7897expandhere(union node *arg, int fd)
7898{
7899        expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7900        full_write(fd, stackblock(), expdest - (char *)stackblock());
7901}
7902
7903/*
7904 * Returns true if the pattern matches the string.
7905 */
7906static int
7907patmatch(char *pattern, const char *string)
7908{
7909        char *p = preglob(pattern, 0);
7910        int r = pmatch(p, string);
7911        //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7912        return r;
7913}
7914
7915/*
7916 * See if a pattern matches in a case statement.
7917 */
7918static int
7919casematch(union node *pattern, char *val)
7920{
7921        struct stackmark smark;
7922        int result;
7923
7924        setstackmark(&smark);
7925        argbackq = pattern->narg.backquote;
7926        STARTSTACKSTR(expdest);
7927        argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
7928        STACKSTRNUL(expdest);
7929        ifsfree();
7930        result = patmatch(stackblock(), val);
7931        popstackmark(&smark);
7932        return result;
7933}
7934
7935
7936/* ============ find_command */
7937
7938struct builtincmd {
7939        const char *name;
7940        int (*builtin)(int, char **) FAST_FUNC;
7941        /* unsigned flags; */
7942};
7943#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7944/* "regular" builtins always take precedence over commands,
7945 * regardless of PATH=....%builtin... position */
7946#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7947#define IS_BUILTIN_ASSIGN(b)  ((b)->name[0] & 4)
7948
7949struct cmdentry {
7950        smallint cmdtype;       /* CMDxxx */
7951        union param {
7952                int index;
7953                /* index >= 0 for commands without path (slashes) */
7954                /* (TODO: what exactly does the value mean? PATH position?) */
7955                /* index == -1 for commands with slashes */
7956                /* index == (-2 - applet_no) for NOFORK applets */
7957                const struct builtincmd *cmd;
7958                struct funcnode *func;
7959        } u;
7960};
7961/* values of cmdtype */
7962#define CMDUNKNOWN      -1      /* no entry in table for command */
7963#define CMDNORMAL       0       /* command is an executable program */
7964#define CMDFUNCTION     1       /* command is a shell function */
7965#define CMDBUILTIN      2       /* command is a shell builtin */
7966
7967/* action to find_command() */
7968#define DO_ERR          0x01    /* prints errors */
7969#define DO_ABS          0x02    /* checks absolute paths */
7970#define DO_NOFUNC       0x04    /* don't return shell functions, for command */
7971#define DO_ALTPATH      0x08    /* using alternate path */
7972#define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
7973
7974static void find_command(char *, struct cmdentry *, int, const char *);
7975
7976
7977/* ============ Hashing commands */
7978
7979/*
7980 * When commands are first encountered, they are entered in a hash table.
7981 * This ensures that a full path search will not have to be done for them
7982 * on each invocation.
7983 *
7984 * We should investigate converting to a linear search, even though that
7985 * would make the command name "hash" a misnomer.
7986 */
7987
7988struct tblentry {
7989        struct tblentry *next;  /* next entry in hash chain */
7990        union param param;      /* definition of builtin function */
7991        smallint cmdtype;       /* CMDxxx */
7992        char rehash;            /* if set, cd done since entry created */
7993        char cmdname[1];        /* name of command */
7994};
7995
7996static struct tblentry **cmdtable;
7997#define INIT_G_cmdtable() do { \
7998        cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7999} while (0)
8000
8001static int builtinloc = -1;     /* index in path of %builtin, or -1 */
8002
8003
8004static void
8005tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
8006{
8007#if ENABLE_FEATURE_SH_STANDALONE
8008        if (applet_no >= 0) {
8009                if (APPLET_IS_NOEXEC(applet_no)) {
8010                        clearenv();
8011                        while (*envp)
8012                                putenv(*envp++);
8013                        popredir(/*drop:*/ 1);
8014                        run_noexec_applet_and_exit(applet_no, cmd, argv);
8015                }
8016                /* re-exec ourselves with the new arguments */
8017                execve(bb_busybox_exec_path, argv, envp);
8018                /* If they called chroot or otherwise made the binary no longer
8019                 * executable, fall through */
8020        }
8021#endif
8022
8023 repeat:
8024#ifdef SYSV
8025        do {
8026                execve(cmd, argv, envp);
8027        } while (errno == EINTR);
8028#else
8029        execve(cmd, argv, envp);
8030#endif
8031
8032        if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
8033                /* Run "cmd" as a shell script:
8034                 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8035                 * "If the execve() function fails with ENOEXEC, the shell
8036                 * shall execute a command equivalent to having a shell invoked
8037                 * with the command name as its first operand,
8038                 * with any remaining arguments passed to the new shell"
8039                 *
8040                 * That is, do not use $SHELL, user's shell, or /bin/sh;
8041                 * just call ourselves.
8042                 *
8043                 * Note that bash reads ~80 chars of the file, and if it sees
8044                 * a zero byte before it sees newline, it doesn't try to
8045                 * interpret it, but fails with "cannot execute binary file"
8046                 * message and exit code 126. For one, this prevents attempts
8047                 * to interpret foreign ELF binaries as shell scripts.
8048                 */
8049                argv[0] = (char*) cmd;
8050                cmd = bb_busybox_exec_path;
8051                /* NB: this is only possible because all callers of shellexec()
8052                 * ensure that the argv[-1] slot exists!
8053                 */
8054                argv--;
8055                argv[0] = (char*) "ash";
8056                goto repeat;
8057        }
8058}
8059
8060/*
8061 * Exec a program.  Never returns.  If you change this routine, you may
8062 * have to change the find_command routine as well.
8063 * argv[-1] must exist and be writable! See tryexec() for why.
8064 */
8065static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8066static void shellexec(char *prog, char **argv, const char *path, int idx)
8067{
8068        char *cmdname;
8069        int e;
8070        char **envp;
8071        int exerrno;
8072        int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
8073
8074        envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
8075        if (strchr(prog, '/') != NULL
8076#if ENABLE_FEATURE_SH_STANDALONE
8077         || (applet_no = find_applet_by_name(prog)) >= 0
8078#endif
8079        ) {
8080                tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
8081                if (applet_no >= 0) {
8082                        /* We tried execing ourself, but it didn't work.
8083                         * Maybe /proc/self/exe doesn't exist?
8084                         * Try $PATH search.
8085                         */
8086                        goto try_PATH;
8087                }
8088                e = errno;
8089        } else {
8090 try_PATH:
8091                e = ENOENT;
8092                while ((cmdname = path_advance(&path, prog)) != NULL) {
8093                        if (--idx < 0 && pathopt == NULL) {
8094                                tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
8095                                if (errno != ENOENT && errno != ENOTDIR)
8096                                        e = errno;
8097                        }
8098                        stunalloc(cmdname);
8099                }
8100        }
8101
8102        /* Map to POSIX errors */
8103        switch (e) {
8104        default:
8105                exerrno = 126;
8106                break;
8107        case ELOOP:
8108        case ENAMETOOLONG:
8109        case ENOENT:
8110        case ENOTDIR:
8111                exerrno = 127;
8112                break;
8113        }
8114        exitstatus = exerrno;
8115        TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
8116                prog, e, suppress_int));
8117        ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
8118        /* NOTREACHED */
8119}
8120
8121static void
8122printentry(struct tblentry *cmdp)
8123{
8124        int idx;
8125        const char *path;
8126        char *name;
8127
8128        idx = cmdp->param.index;
8129        path = pathval();
8130        do {
8131                name = path_advance(&path, cmdp->cmdname);
8132                stunalloc(name);
8133        } while (--idx >= 0);
8134        out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8135}
8136
8137/*
8138 * Clear out command entries.  The argument specifies the first entry in
8139 * PATH which has changed.
8140 */
8141static void
8142clearcmdentry(int firstchange)
8143{
8144        struct tblentry **tblp;
8145        struct tblentry **pp;
8146        struct tblentry *cmdp;
8147
8148        INT_OFF;
8149        for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8150                pp = tblp;
8151                while ((cmdp = *pp) != NULL) {
8152                        if ((cmdp->cmdtype == CMDNORMAL &&
8153                             cmdp->param.index >= firstchange)
8154                         || (cmdp->cmdtype == CMDBUILTIN &&
8155                             builtinloc >= firstchange)
8156                        ) {
8157                                *pp = cmdp->next;
8158                                free(cmdp);
8159                        } else {
8160                                pp = &cmdp->next;
8161                        }
8162                }
8163        }
8164        INT_ON;
8165}
8166
8167/*
8168 * Locate a command in the command hash table.  If "add" is nonzero,
8169 * add the command to the table if it is not already present.  The
8170 * variable "lastcmdentry" is set to point to the address of the link
8171 * pointing to the entry, so that delete_cmd_entry can delete the
8172 * entry.
8173 *
8174 * Interrupts must be off if called with add != 0.
8175 */
8176static struct tblentry **lastcmdentry;
8177
8178static struct tblentry *
8179cmdlookup(const char *name, int add)
8180{
8181        unsigned int hashval;
8182        const char *p;
8183        struct tblentry *cmdp;
8184        struct tblentry **pp;
8185
8186        p = name;
8187        hashval = (unsigned char)*p << 4;
8188        while (*p)
8189                hashval += (unsigned char)*p++;
8190        hashval &= 0x7FFF;
8191        pp = &cmdtable[hashval % CMDTABLESIZE];
8192        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8193                if (strcmp(cmdp->cmdname, name) == 0)
8194                        break;
8195                pp = &cmdp->next;
8196        }
8197        if (add && cmdp == NULL) {
8198                cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8199                                + strlen(name)
8200                                /* + 1 - already done because
8201                                 * tblentry::cmdname is char[1] */);
8202                /*cmdp->next = NULL; - ckzalloc did it */
8203                cmdp->cmdtype = CMDUNKNOWN;
8204                strcpy(cmdp->cmdname, name);
8205        }
8206        lastcmdentry = pp;
8207        return cmdp;
8208}
8209
8210/*
8211 * Delete the command entry returned on the last lookup.
8212 */
8213static void
8214delete_cmd_entry(void)
8215{
8216        struct tblentry *cmdp;
8217
8218        INT_OFF;
8219        cmdp = *lastcmdentry;
8220        *lastcmdentry = cmdp->next;
8221        if (cmdp->cmdtype == CMDFUNCTION)
8222                freefunc(cmdp->param.func);
8223        free(cmdp);
8224        INT_ON;
8225}
8226
8227/*
8228 * Add a new command entry, replacing any existing command entry for
8229 * the same name - except special builtins.
8230 */
8231static void
8232addcmdentry(char *name, struct cmdentry *entry)
8233{
8234        struct tblentry *cmdp;
8235
8236        cmdp = cmdlookup(name, 1);
8237        if (cmdp->cmdtype == CMDFUNCTION) {
8238                freefunc(cmdp->param.func);
8239        }
8240        cmdp->cmdtype = entry->cmdtype;
8241        cmdp->param = entry->u;
8242        cmdp->rehash = 0;
8243}
8244
8245static int FAST_FUNC
8246hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8247{
8248        struct tblentry **pp;
8249        struct tblentry *cmdp;
8250        int c;
8251        struct cmdentry entry;
8252        char *name;
8253
8254        if (nextopt("r") != '\0') {
8255                clearcmdentry(0);
8256                return 0;
8257        }
8258
8259        if (*argptr == NULL) {
8260                for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8261                        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8262                                if (cmdp->cmdtype == CMDNORMAL)
8263                                        printentry(cmdp);
8264                        }
8265                }
8266                return 0;
8267        }
8268
8269        c = 0;
8270        while ((name = *argptr) != NULL) {
8271                cmdp = cmdlookup(name, 0);
8272                if (cmdp != NULL
8273                 && (cmdp->cmdtype == CMDNORMAL
8274                     || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8275                ) {
8276                        delete_cmd_entry();
8277                }
8278                find_command(name, &entry, DO_ERR, pathval());
8279                if (entry.cmdtype == CMDUNKNOWN)
8280                        c = 1;
8281                argptr++;
8282        }
8283        return c;
8284}
8285
8286/*
8287 * Called when a cd is done.  Marks all commands so the next time they
8288 * are executed they will be rehashed.
8289 */
8290static void
8291hashcd(void)
8292{
8293        struct tblentry **pp;
8294        struct tblentry *cmdp;
8295
8296        for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8297                for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8298                        if (cmdp->cmdtype == CMDNORMAL
8299                         || (cmdp->cmdtype == CMDBUILTIN
8300                             && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8301                             && builtinloc > 0)
8302                        ) {
8303                                cmdp->rehash = 1;
8304                        }
8305                }
8306        }
8307}
8308
8309/*
8310 * Fix command hash table when PATH changed.
8311 * Called before PATH is changed.  The argument is the new value of PATH;
8312 * pathval() still returns the old value at this point.
8313 * Called with interrupts off.
8314 */
8315static void FAST_FUNC
8316changepath(const char *new)
8317{
8318        const char *old;
8319        int firstchange;
8320        int idx;
8321        int idx_bltin;
8322
8323        old = pathval();
8324        firstchange = 9999;     /* assume no change */
8325        idx = 0;
8326        idx_bltin = -1;
8327        for (;;) {
8328                if (*old != *new) {
8329                        firstchange = idx;
8330                        if ((*old == '\0' && *new == ':')
8331                         || (*old == ':' && *new == '\0')
8332                        ) {
8333                                firstchange++;
8334                        }
8335                        old = new;      /* ignore subsequent differences */
8336                }
8337                if (*new == '\0')
8338                        break;
8339                if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8340                        idx_bltin = idx;
8341                if (*new == ':')
8342                        idx++;
8343                new++;
8344                old++;
8345        }
8346        if (builtinloc < 0 && idx_bltin >= 0)
8347                builtinloc = idx_bltin;             /* zap builtins */
8348        if (builtinloc >= 0 && idx_bltin < 0)
8349                firstchange = 0;
8350        clearcmdentry(firstchange);
8351        builtinloc = idx_bltin;
8352}
8353enum {
8354        TEOF,
8355        TNL,
8356        TREDIR,
8357        TWORD,
8358        TSEMI,
8359        TBACKGND,
8360        TAND,
8361        TOR,
8362        TPIPE,
8363        TLP,
8364        TRP,
8365        TENDCASE,
8366        TENDBQUOTE,
8367        TNOT,
8368        TCASE,
8369        TDO,
8370        TDONE,
8371        TELIF,
8372        TELSE,
8373        TESAC,
8374        TFI,
8375        TFOR,
8376#if BASH_FUNCTION
8377        TFUNCTION,
8378#endif
8379        TIF,
8380        TIN,
8381        TTHEN,
8382        TUNTIL,
8383        TWHILE,
8384        TBEGIN,
8385        TEND
8386};
8387typedef smallint token_id_t;
8388
8389/* Nth bit indicates if token marks the end of a list */
8390enum {
8391        tokendlist = 0
8392        /*  0 */ | (1u << TEOF)
8393        /*  1 */ | (0u << TNL)
8394        /*  2 */ | (0u << TREDIR)
8395        /*  3 */ | (0u << TWORD)
8396        /*  4 */ | (0u << TSEMI)
8397        /*  5 */ | (0u << TBACKGND)
8398        /*  6 */ | (0u << TAND)
8399        /*  7 */ | (0u << TOR)
8400        /*  8 */ | (0u << TPIPE)
8401        /*  9 */ | (0u << TLP)
8402        /* 10 */ | (1u << TRP)
8403        /* 11 */ | (1u << TENDCASE)
8404        /* 12 */ | (1u << TENDBQUOTE)
8405        /* 13 */ | (0u << TNOT)
8406        /* 14 */ | (0u << TCASE)
8407        /* 15 */ | (1u << TDO)
8408        /* 16 */ | (1u << TDONE)
8409        /* 17 */ | (1u << TELIF)
8410        /* 18 */ | (1u << TELSE)
8411        /* 19 */ | (1u << TESAC)
8412        /* 20 */ | (1u << TFI)
8413        /* 21 */ | (0u << TFOR)
8414#if BASH_FUNCTION
8415        /* 22 */ | (0u << TFUNCTION)
8416#endif
8417        /* 23 */ | (0u << TIF)
8418        /* 24 */ | (0u << TIN)
8419        /* 25 */ | (1u << TTHEN)
8420        /* 26 */ | (0u << TUNTIL)
8421        /* 27 */ | (0u << TWHILE)
8422        /* 28 */ | (0u << TBEGIN)
8423        /* 29 */ | (1u << TEND)
8424        , /* thus far 29 bits used */
8425};
8426
8427static const char *const tokname_array[] = {
8428        "end of file",
8429        "newline",
8430        "redirection",
8431        "word",
8432        ";",
8433        "&",
8434        "&&",
8435        "||",
8436        "|",
8437        "(",
8438        ")",
8439        ";;",
8440        "`",
8441#define KWDOFFSET 13
8442        /* the following are keywords */
8443        "!",
8444        "case",
8445        "do",
8446        "done",
8447        "elif",
8448        "else",
8449        "esac",
8450        "fi",
8451        "for",
8452#if BASH_FUNCTION
8453        "function",
8454#endif
8455        "if",
8456        "in",
8457        "then",
8458        "until",
8459        "while",
8460        "{",
8461        "}",
8462};
8463
8464/* Wrapper around strcmp for qsort/bsearch/... */
8465static int
8466pstrcmp(const void *a, const void *b)
8467{
8468        return strcmp((char*)a, *(char**)b);
8469}
8470
8471static const char *const *
8472findkwd(const char *s)
8473{
8474        return bsearch(s, tokname_array + KWDOFFSET,
8475                        ARRAY_SIZE(tokname_array) - KWDOFFSET,
8476                        sizeof(tokname_array[0]), pstrcmp);
8477}
8478
8479/*
8480 * Locate and print what a word is...
8481 */
8482static int
8483describe_command(char *command, const char *path, int describe_command_verbose)
8484{
8485        struct cmdentry entry;
8486#if ENABLE_ASH_ALIAS
8487        const struct alias *ap;
8488#endif
8489
8490        path = path ? path : pathval();
8491
8492        if (describe_command_verbose) {
8493                out1str(command);
8494        }
8495
8496        /* First look at the keywords */
8497        if (findkwd(command)) {
8498                out1str(describe_command_verbose ? " is a shell keyword" : command);
8499                goto out;
8500        }
8501
8502#if ENABLE_ASH_ALIAS
8503        /* Then look at the aliases */
8504        ap = lookupalias(command, 0);
8505        if (ap != NULL) {
8506                if (!describe_command_verbose) {
8507                        out1str("alias ");
8508                        printalias(ap);
8509                        return 0;
8510                }
8511                out1fmt(" is an alias for %s", ap->val);
8512                goto out;
8513        }
8514#endif
8515        /* Brute force */
8516        find_command(command, &entry, DO_ABS, path);
8517
8518        switch (entry.cmdtype) {
8519        case CMDNORMAL: {
8520                int j = entry.u.index;
8521                char *p;
8522                if (j < 0) {
8523                        p = command;
8524                } else {
8525                        do {
8526                                p = path_advance(&path, command);
8527                                stunalloc(p);
8528                        } while (--j >= 0);
8529                }
8530                if (describe_command_verbose) {
8531                        out1fmt(" is %s", p);
8532                } else {
8533                        out1str(p);
8534                }
8535                break;
8536        }
8537
8538        case CMDFUNCTION:
8539                if (describe_command_verbose) {
8540                        /*out1str(" is a shell function");*/
8541                        out1str(" is a function"); /* bash says this */
8542                } else {
8543                        out1str(command);
8544                }
8545                break;
8546
8547        case CMDBUILTIN:
8548                if (describe_command_verbose) {
8549                        out1fmt(" is a %sshell builtin",
8550                                IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8551                                        "special " : nullstr
8552                        );
8553                } else {
8554                        out1str(command);
8555                }
8556                break;
8557
8558        default:
8559                if (describe_command_verbose) {
8560                        out1str(": not found\n");
8561                }
8562                return 127;
8563        }
8564 out:
8565        out1str("\n");
8566        return 0;
8567}
8568
8569static int FAST_FUNC
8570typecmd(int argc UNUSED_PARAM, char **argv)
8571{
8572        int i = 1;
8573        int err = 0;
8574        int verbose = 1;
8575
8576        /* type -p ... ? (we don't bother checking for 'p') */
8577        if (argv[1] && argv[1][0] == '-') {
8578                i++;
8579                verbose = 0;
8580        }
8581        while (argv[i]) {
8582                err |= describe_command(argv[i++], NULL, verbose);
8583        }
8584        return err;
8585}
8586
8587#if ENABLE_ASH_CMDCMD
8588/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8589static char **
8590parse_command_args(char **argv, const char **path)
8591{
8592        char *cp, c;
8593
8594        for (;;) {
8595                cp = *++argv;
8596                if (!cp)
8597                        return NULL;
8598                if (*cp++ != '-')
8599                        break;
8600                c = *cp++;
8601                if (!c)
8602                        break;
8603                if (c == '-' && !*cp) {
8604                        if (!*++argv)
8605                                return NULL;
8606                        break;
8607                }
8608                do {
8609                        switch (c) {
8610                        case 'p':
8611                                *path = bb_default_path;
8612                                break;
8613                        default:
8614                                /* run 'typecmd' for other options */
8615                                return NULL;
8616                        }
8617                        c = *cp++;
8618                } while (c);
8619        }
8620        return argv;
8621}
8622
8623static int FAST_FUNC
8624commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8625{
8626        char *cmd;
8627        int c;
8628        enum {
8629                VERIFY_BRIEF = 1,
8630                VERIFY_VERBOSE = 2,
8631        } verify = 0;
8632        const char *path = NULL;
8633
8634        /* "command [-p] PROG ARGS" (that is, without -V or -v)
8635         * never reaches this function.
8636         */
8637
8638        while ((c = nextopt("pvV")) != '\0')
8639                if (c == 'V')
8640                        verify |= VERIFY_VERBOSE;
8641                else if (c == 'v')
8642                        /*verify |= VERIFY_BRIEF*/;
8643#if DEBUG
8644                else if (c != 'p')
8645                        abort();
8646#endif
8647                else
8648                        path = bb_default_path;
8649
8650        /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8651        cmd = *argptr;
8652        if (/*verify && */ cmd)
8653                return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8654
8655        return 0;
8656}
8657#endif
8658
8659
8660/*static int funcblocksize;     // size of structures in function */
8661/*static int funcstringsize;    // size of strings in node */
8662static void *funcblock;         /* block to allocate function from */
8663static char *funcstring_end;    /* end of block to allocate strings from */
8664
8665static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8666        [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
8667        [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
8668        [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
8669        [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8670        [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8671        [NAND     ] = SHELL_ALIGN(sizeof(struct nbinary)),
8672        [NOR      ] = SHELL_ALIGN(sizeof(struct nbinary)),
8673        [NSEMI    ] = SHELL_ALIGN(sizeof(struct nbinary)),
8674        [NIF      ] = SHELL_ALIGN(sizeof(struct nif)),
8675        [NWHILE   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8676        [NUNTIL   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8677        [NFOR     ] = SHELL_ALIGN(sizeof(struct nfor)),
8678        [NCASE    ] = SHELL_ALIGN(sizeof(struct ncase)),
8679        [NCLIST   ] = SHELL_ALIGN(sizeof(struct nclist)),
8680        [NDEFUN   ] = SHELL_ALIGN(sizeof(struct narg)),
8681        [NARG     ] = SHELL_ALIGN(sizeof(struct narg)),
8682        [NTO      ] = SHELL_ALIGN(sizeof(struct nfile)),
8683#if BASH_REDIR_OUTPUT
8684        [NTO2     ] = SHELL_ALIGN(sizeof(struct nfile)),
8685#endif
8686        [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8687        [NFROM    ] = SHELL_ALIGN(sizeof(struct nfile)),
8688        [NFROMTO  ] = SHELL_ALIGN(sizeof(struct nfile)),
8689        [NAPPEND  ] = SHELL_ALIGN(sizeof(struct nfile)),
8690        [NTOFD    ] = SHELL_ALIGN(sizeof(struct ndup)),
8691        [NFROMFD  ] = SHELL_ALIGN(sizeof(struct ndup)),
8692        [NHERE    ] = SHELL_ALIGN(sizeof(struct nhere)),
8693        [NXHERE   ] = SHELL_ALIGN(sizeof(struct nhere)),
8694        [NNOT     ] = SHELL_ALIGN(sizeof(struct nnot)),
8695};
8696
8697static int calcsize(int funcblocksize, union node *n);
8698
8699static int
8700sizenodelist(int funcblocksize, struct nodelist *lp)
8701{
8702        while (lp) {
8703                funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8704                funcblocksize = calcsize(funcblocksize, lp->n);
8705                lp = lp->next;
8706        }
8707        return funcblocksize;
8708}
8709
8710static int
8711calcsize(int funcblocksize, union node *n)
8712{
8713        if (n == NULL)
8714                return funcblocksize;
8715        funcblocksize += nodesize[n->type];
8716        switch (n->type) {
8717        case NCMD:
8718                funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8719                funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8720                funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8721                break;
8722        case NPIPE:
8723                funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8724                break;
8725        case NREDIR:
8726        case NBACKGND:
8727        case NSUBSHELL:
8728                funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8729                funcblocksize = calcsize(funcblocksize, n->nredir.n);
8730                break;
8731        case NAND:
8732        case NOR:
8733        case NSEMI:
8734        case NWHILE:
8735        case NUNTIL:
8736                funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8737                funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
8738                break;
8739        case NIF:
8740                funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8741                funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8742                funcblocksize = calcsize(funcblocksize, n->nif.test);
8743                break;
8744        case NFOR:
8745                funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
8746                funcblocksize = calcsize(funcblocksize, n->nfor.body);
8747                funcblocksize = calcsize(funcblocksize, n->nfor.args);
8748                break;
8749        case NCASE:
8750                funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8751                funcblocksize = calcsize(funcblocksize, n->ncase.expr);
8752                break;
8753        case NCLIST:
8754                funcblocksize = calcsize(funcblocksize, n->nclist.body);
8755                funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8756                funcblocksize = calcsize(funcblocksize, n->nclist.next);
8757                break;
8758        case NDEFUN:
8759                funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8760                funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8761                break;
8762        case NARG:
8763                funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
8764                funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
8765                funcblocksize = calcsize(funcblocksize, n->narg.next);
8766                break;
8767        case NTO:
8768#if BASH_REDIR_OUTPUT
8769        case NTO2:
8770#endif
8771        case NCLOBBER:
8772        case NFROM:
8773        case NFROMTO:
8774        case NAPPEND:
8775                funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8776                funcblocksize = calcsize(funcblocksize, n->nfile.next);
8777                break;
8778        case NTOFD:
8779        case NFROMFD:
8780                funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8781                funcblocksize = calcsize(funcblocksize, n->ndup.next);
8782        break;
8783        case NHERE:
8784        case NXHERE:
8785                funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8786                funcblocksize = calcsize(funcblocksize, n->nhere.next);
8787                break;
8788        case NNOT:
8789                funcblocksize = calcsize(funcblocksize, n->nnot.com);
8790                break;
8791        };
8792        return funcblocksize;
8793}
8794
8795static char *
8796nodeckstrdup(char *s)
8797{
8798        funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
8799        return strcpy(funcstring_end, s);
8800}
8801
8802static union node *copynode(union node *);
8803
8804static struct nodelist *
8805copynodelist(struct nodelist *lp)
8806{
8807        struct nodelist *start;
8808        struct nodelist **lpp;
8809
8810        lpp = &start;
8811        while (lp) {
8812                *lpp = funcblock;
8813                funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8814                (*lpp)->n = copynode(lp->n);
8815                lp = lp->next;
8816                lpp = &(*lpp)->next;
8817        }
8818        *lpp = NULL;
8819        return start;
8820}
8821
8822static union node *
8823copynode(union node *n)
8824{
8825        union node *new;
8826
8827        if (n == NULL)
8828                return NULL;
8829        new = funcblock;
8830        funcblock = (char *) funcblock + nodesize[n->type];
8831
8832        switch (n->type) {
8833        case NCMD:
8834                new->ncmd.redirect = copynode(n->ncmd.redirect);
8835                new->ncmd.args = copynode(n->ncmd.args);
8836                new->ncmd.assign = copynode(n->ncmd.assign);
8837                new->ncmd.linno = n->ncmd.linno;
8838                break;
8839        case NPIPE:
8840                new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8841                new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8842                break;
8843        case NREDIR:
8844        case NBACKGND:
8845        case NSUBSHELL:
8846                new->nredir.redirect = copynode(n->nredir.redirect);
8847                new->nredir.n = copynode(n->nredir.n);
8848                new->nredir.linno = n->nredir.linno;
8849                break;
8850        case NAND:
8851        case NOR:
8852        case NSEMI:
8853        case NWHILE:
8854        case NUNTIL:
8855                new->nbinary.ch2 = copynode(n->nbinary.ch2);
8856                new->nbinary.ch1 = copynode(n->nbinary.ch1);
8857                break;
8858        case NIF:
8859                new->nif.elsepart = copynode(n->nif.elsepart);
8860                new->nif.ifpart = copynode(n->nif.ifpart);
8861                new->nif.test = copynode(n->nif.test);
8862                break;
8863        case NFOR:
8864                new->nfor.var = nodeckstrdup(n->nfor.var);
8865                new->nfor.body = copynode(n->nfor.body);
8866                new->nfor.args = copynode(n->nfor.args);
8867                new->nfor.linno = n->nfor.linno;
8868                break;
8869        case NCASE:
8870                new->ncase.cases = copynode(n->ncase.cases);
8871                new->ncase.expr = copynode(n->ncase.expr);
8872                new->ncase.linno = n->ncase.linno;
8873                break;
8874        case NCLIST:
8875                new->nclist.body = copynode(n->nclist.body);
8876                new->nclist.pattern = copynode(n->nclist.pattern);
8877                new->nclist.next = copynode(n->nclist.next);
8878                break;
8879        case NDEFUN:
8880                new->ndefun.body = copynode(n->ndefun.body);
8881                new->ndefun.text = nodeckstrdup(n->ndefun.text);
8882                new->ndefun.linno = n->ndefun.linno;
8883                break;
8884        case NARG:
8885                new->narg.backquote = copynodelist(n->narg.backquote);
8886                new->narg.text = nodeckstrdup(n->narg.text);
8887                new->narg.next = copynode(n->narg.next);
8888                break;
8889        case NTO:
8890#if BASH_REDIR_OUTPUT
8891        case NTO2:
8892#endif
8893        case NCLOBBER:
8894        case NFROM:
8895        case NFROMTO:
8896        case NAPPEND:
8897                new->nfile.fname = copynode(n->nfile.fname);
8898                new->nfile.fd = n->nfile.fd;
8899                new->nfile.next = copynode(n->nfile.next);
8900                break;
8901        case NTOFD:
8902        case NFROMFD:
8903                new->ndup.vname = copynode(n->ndup.vname);
8904                new->ndup.dupfd = n->ndup.dupfd;
8905                new->ndup.fd = n->ndup.fd;
8906                new->ndup.next = copynode(n->ndup.next);
8907                break;
8908        case NHERE:
8909        case NXHERE:
8910                new->nhere.doc = copynode(n->nhere.doc);
8911                new->nhere.fd = n->nhere.fd;
8912                new->nhere.next = copynode(n->nhere.next);
8913                break;
8914        case NNOT:
8915                new->nnot.com = copynode(n->nnot.com);
8916                break;
8917        };
8918        new->type = n->type;
8919        return new;
8920}
8921
8922/*
8923 * Make a copy of a parse tree.
8924 */
8925static struct funcnode *
8926copyfunc(union node *n)
8927{
8928        struct funcnode *f;
8929        size_t blocksize;
8930
8931        /*funcstringsize = 0;*/
8932        blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8933        f = ckzalloc(blocksize /* + funcstringsize */);
8934        funcblock = (char *) f + offsetof(struct funcnode, n);
8935        funcstring_end = (char *) f + blocksize;
8936        copynode(n);
8937        /* f->count = 0; - ckzalloc did it */
8938        return f;
8939}
8940
8941/*
8942 * Define a shell function.
8943 */
8944static void
8945defun(union node *func)
8946{
8947        struct cmdentry entry;
8948
8949        INT_OFF;
8950        entry.cmdtype = CMDFUNCTION;
8951        entry.u.func = copyfunc(func);
8952        addcmdentry(func->ndefun.text, &entry);
8953        INT_ON;
8954}
8955
8956/* Reasons for skipping commands (see comment on breakcmd routine) */
8957#define SKIPBREAK      (1 << 0)
8958#define SKIPCONT       (1 << 1)
8959#define SKIPFUNC       (1 << 2)
8960static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
8961static int skipcount;           /* number of levels to skip */
8962static int loopnest;            /* current loop nesting level */
8963static int funcline;            /* starting line number of current function, or 0 if not in a function */
8964
8965/* Forward decl way out to parsing code - dotrap needs it */
8966static int evalstring(char *s, int flags);
8967
8968/* Called to execute a trap.
8969 * Single callsite - at the end of evaltree().
8970 * If we return non-zero, evaltree raises EXEXIT exception.
8971 *
8972 * Perhaps we should avoid entering new trap handlers
8973 * while we are executing a trap handler. [is it a TODO?]
8974 */
8975static void
8976dotrap(void)
8977{
8978        uint8_t *g;
8979        int sig;
8980        uint8_t last_status;
8981
8982        if (!pending_sig)
8983                return;
8984
8985        last_status = exitstatus;
8986        pending_sig = 0;
8987        barrier();
8988
8989        TRACE(("dotrap entered\n"));
8990        for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8991                char *p;
8992
8993                if (!*g)
8994                        continue;
8995
8996                if (evalskip) {
8997                        pending_sig = sig;
8998                        break;
8999                }
9000
9001                p = trap[sig];
9002                /* non-trapped SIGINT is handled separately by raise_interrupt,
9003                 * don't upset it by resetting gotsig[SIGINT-1] */
9004                if (sig == SIGINT && !p)
9005                        continue;
9006
9007                TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
9008                *g = 0;
9009                if (!p)
9010                        continue;
9011                evalstring(p, 0);
9012        }
9013        exitstatus = last_status;
9014        TRACE(("dotrap returns\n"));
9015}
9016
9017/* forward declarations - evaluation is fairly recursive business... */
9018static int evalloop(union node *, int);
9019static int evalfor(union node *, int);
9020static int evalcase(union node *, int);
9021static int evalsubshell(union node *, int);
9022static void expredir(union node *);
9023static int evalpipe(union node *, int);
9024static int evalcommand(union node *, int);
9025static int evalbltin(const struct builtincmd *, int, char **, int);
9026static void prehash(union node *);
9027
9028/*
9029 * Evaluate a parse tree.  The value is left in the global variable
9030 * exitstatus.
9031 */
9032static int
9033evaltree(union node *n, int flags)
9034{
9035        int checkexit = 0;
9036        int (*evalfn)(union node *, int);
9037        int status = 0;
9038
9039        if (n == NULL) {
9040                TRACE(("evaltree(NULL) called\n"));
9041                goto out;
9042        }
9043        TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
9044
9045        dotrap();
9046
9047        switch (n->type) {
9048        default:
9049#if DEBUG
9050                out1fmt("Node type = %d\n", n->type);
9051                fflush_all();
9052                break;
9053#endif
9054        case NNOT:
9055                status = !evaltree(n->nnot.com, EV_TESTED);
9056                goto setstatus;
9057        case NREDIR:
9058                errlinno = lineno = n->nredir.linno;
9059                if (funcline)
9060                        lineno -= funcline - 1;
9061                expredir(n->nredir.redirect);
9062                pushredir(n->nredir.redirect);
9063                status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9064                if (!status) {
9065                        status = evaltree(n->nredir.n, flags & EV_TESTED);
9066                }
9067                if (n->nredir.redirect)
9068                        popredir(/*drop:*/ 0);
9069                goto setstatus;
9070        case NCMD:
9071                evalfn = evalcommand;
9072 checkexit:
9073                if (eflag && !(flags & EV_TESTED))
9074                        checkexit = ~0;
9075                goto calleval;
9076        case NFOR:
9077                evalfn = evalfor;
9078                goto calleval;
9079        case NWHILE:
9080        case NUNTIL:
9081                evalfn = evalloop;
9082                goto calleval;
9083        case NSUBSHELL:
9084        case NBACKGND:
9085                evalfn = evalsubshell;
9086                goto checkexit;
9087        case NPIPE:
9088                evalfn = evalpipe;
9089                goto checkexit;
9090        case NCASE:
9091                evalfn = evalcase;
9092                goto calleval;
9093        case NAND:
9094        case NOR:
9095        case NSEMI: {
9096
9097#if NAND + 1 != NOR
9098#error NAND + 1 != NOR
9099#endif
9100#if NOR + 1 != NSEMI
9101#error NOR + 1 != NSEMI
9102#endif
9103                unsigned is_or = n->type - NAND;
9104                status = evaltree(
9105                        n->nbinary.ch1,
9106                        (flags | ((is_or >> 1) - 1)) & EV_TESTED
9107                );
9108                if ((!status) == is_or || evalskip)
9109                        break;
9110                n = n->nbinary.ch2;
9111 evaln:
9112                evalfn = evaltree;
9113 calleval:
9114                status = evalfn(n, flags);
9115                goto setstatus;
9116        }
9117        case NIF:
9118                status = evaltree(n->nif.test, EV_TESTED);
9119                if (evalskip)
9120                        break;
9121                if (!status) {
9122                        n = n->nif.ifpart;
9123                        goto evaln;
9124                }
9125                if (n->nif.elsepart) {
9126                        n = n->nif.elsepart;
9127                        goto evaln;
9128                }
9129                status = 0;
9130                goto setstatus;
9131        case NDEFUN:
9132                defun(n);
9133                /* Not necessary. To test it:
9134                 * "false; f() { qwerty; }; echo $?" should print 0.
9135                 */
9136                /* status = 0; */
9137 setstatus:
9138                exitstatus = status;
9139                break;
9140        }
9141 out:
9142        /* Order of checks below is important:
9143         * signal handlers trigger before exit caused by "set -e".
9144         */
9145        dotrap();
9146
9147        if (checkexit & status)
9148                raise_exception(EXEXIT);
9149        if (flags & EV_EXIT)
9150                raise_exception(EXEXIT);
9151
9152        TRACE(("leaving evaltree (no interrupts)\n"));
9153        return exitstatus;
9154}
9155
9156static int
9157skiploop(void)
9158{
9159        int skip = evalskip;
9160
9161        switch (skip) {
9162        case 0:
9163                break;
9164        case SKIPBREAK:
9165        case SKIPCONT:
9166                if (--skipcount <= 0) {
9167                        evalskip = 0;
9168                        break;
9169                }
9170                skip = SKIPBREAK;
9171                break;
9172        }
9173        return skip;
9174}
9175
9176static int
9177evalloop(union node *n, int flags)
9178{
9179        int skip;
9180        int status;
9181
9182        loopnest++;
9183        status = 0;
9184        flags &= EV_TESTED;
9185        do {
9186                int i;
9187
9188                i = evaltree(n->nbinary.ch1, EV_TESTED);
9189                skip = skiploop();
9190                if (skip == SKIPFUNC)
9191                        status = i;
9192                if (skip)
9193                        continue;
9194                if (n->type != NWHILE)
9195                        i = !i;
9196                if (i != 0)
9197                        break;
9198                status = evaltree(n->nbinary.ch2, flags);
9199                skip = skiploop();
9200        } while (!(skip & ~SKIPCONT));
9201        loopnest--;
9202
9203        return status;
9204}
9205
9206static int
9207evalfor(union node *n, int flags)
9208{
9209        struct arglist arglist;
9210        union node *argp;
9211        struct strlist *sp;
9212        struct stackmark smark;
9213        int status = 0;
9214
9215        errlinno = lineno = n->ncase.linno;
9216        if (funcline)
9217                lineno -= funcline - 1;
9218
9219        setstackmark(&smark);
9220        arglist.list = NULL;
9221        arglist.lastp = &arglist.list;
9222        for (argp = n->nfor.args; argp; argp = argp->narg.next) {
9223                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9224        }
9225        *arglist.lastp = NULL;
9226
9227        loopnest++;
9228        flags &= EV_TESTED;
9229        for (sp = arglist.list; sp; sp = sp->next) {
9230                setvar0(n->nfor.var, sp->text);
9231                status = evaltree(n->nfor.body, flags);
9232                if (skiploop() & ~SKIPCONT)
9233                        break;
9234        }
9235        loopnest--;
9236        popstackmark(&smark);
9237
9238        return status;
9239}
9240
9241static int
9242evalcase(union node *n, int flags)
9243{
9244        union node *cp;
9245        union node *patp;
9246        struct arglist arglist;
9247        struct stackmark smark;
9248        int status = 0;
9249
9250        errlinno = lineno = n->ncase.linno;
9251        if (funcline)
9252                lineno -= funcline - 1;
9253
9254        setstackmark(&smark);
9255        arglist.list = NULL;
9256        arglist.lastp = &arglist.list;
9257        expandarg(n->ncase.expr, &arglist, EXP_TILDE);
9258        for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9259                for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
9260                        if (casematch(patp, arglist.list->text)) {
9261                                /* Ensure body is non-empty as otherwise
9262                                 * EV_EXIT may prevent us from setting the
9263                                 * exit status.
9264                                 */
9265                                if (evalskip == 0 && cp->nclist.body) {
9266                                        status = evaltree(cp->nclist.body, flags);
9267                                }
9268                                goto out;
9269                        }
9270                }
9271        }
9272 out:
9273        popstackmark(&smark);
9274
9275        return status;
9276}
9277
9278/*
9279 * Kick off a subshell to evaluate a tree.
9280 */
9281static int
9282evalsubshell(union node *n, int flags)
9283{
9284        struct job *jp;
9285        int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9286        int status;
9287
9288        errlinno = lineno = n->nredir.linno;
9289        if (funcline)
9290                lineno -= funcline - 1;
9291
9292        expredir(n->nredir.redirect);
9293        if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9294                goto nofork;
9295        INT_OFF;
9296        if (backgnd == FORK_FG)
9297                get_tty_state();
9298        jp = makejob(/*n,*/ 1);
9299        if (forkshell(jp, n, backgnd) == 0) {
9300                /* child */
9301                INT_ON;
9302                flags |= EV_EXIT;
9303                if (backgnd)
9304                        flags &= ~EV_TESTED;
9305 nofork:
9306                redirect(n->nredir.redirect, 0);
9307                evaltreenr(n->nredir.n, flags);
9308                /* never returns */
9309        }
9310        /* parent */
9311        status = 0;
9312        if (backgnd == FORK_FG)
9313                status = waitforjob(jp);
9314        INT_ON;
9315        return status;
9316}
9317
9318/*
9319 * Compute the names of the files in a redirection list.
9320 */
9321static void fixredir(union node *, const char *, int);
9322static void
9323expredir(union node *n)
9324{
9325        union node *redir;
9326
9327        for (redir = n; redir; redir = redir->nfile.next) {
9328                struct arglist fn;
9329
9330                fn.list = NULL;
9331                fn.lastp = &fn.list;
9332                switch (redir->type) {
9333                case NFROMTO:
9334                case NFROM:
9335                case NTO:
9336#if BASH_REDIR_OUTPUT
9337                case NTO2:
9338#endif
9339                case NCLOBBER:
9340                case NAPPEND:
9341                        expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
9342                        TRACE(("expredir expanded to '%s'\n", fn.list->text));
9343#if BASH_REDIR_OUTPUT
9344 store_expfname:
9345#endif
9346#if 0
9347// By the design of stack allocator, the loop of this kind:
9348//      while true; do while true; do break; done </dev/null; done
9349// will look like a memory leak: ash plans to free expfname's
9350// of "/dev/null" as soon as it finishes running the loop
9351// (in this case, never).
9352// This "fix" is wrong:
9353                        if (redir->nfile.expfname)
9354                                stunalloc(redir->nfile.expfname);
9355// It results in corrupted state of stacked allocations.
9356#endif
9357                        redir->nfile.expfname = fn.list->text;
9358                        break;
9359                case NFROMFD:
9360                case NTOFD: /* >& */
9361                        if (redir->ndup.vname) {
9362                                expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
9363                                if (fn.list == NULL)
9364                                        ash_msg_and_raise_error("redir error");
9365#if BASH_REDIR_OUTPUT
9366//FIXME: we used expandarg with different args!
9367                                if (!isdigit_str9(fn.list->text)) {
9368                                        /* >&file, not >&fd */
9369                                        if (redir->nfile.fd != 1) /* 123>&file - BAD */
9370                                                ash_msg_and_raise_error("redir error");
9371                                        redir->type = NTO2;
9372                                        goto store_expfname;
9373                                }
9374#endif
9375                                fixredir(redir, fn.list->text, 1);
9376                        }
9377                        break;
9378                }
9379        }
9380}
9381
9382/*
9383 * Evaluate a pipeline.  All the processes in the pipeline are children
9384 * of the process creating the pipeline.  (This differs from some versions
9385 * of the shell, which make the last process in a pipeline the parent
9386 * of all the rest.)
9387 */
9388static int
9389evalpipe(union node *n, int flags)
9390{
9391        struct job *jp;
9392        struct nodelist *lp;
9393        int pipelen;
9394        int prevfd;
9395        int pip[2];
9396        int status = 0;
9397
9398        TRACE(("evalpipe(0x%lx) called\n", (long)n));
9399        pipelen = 0;
9400        for (lp = n->npipe.cmdlist; lp; lp = lp->next)
9401                pipelen++;
9402        flags |= EV_EXIT;
9403        INT_OFF;
9404        if (n->npipe.pipe_backgnd == 0)
9405                get_tty_state();
9406        jp = makejob(/*n,*/ pipelen);
9407        prevfd = -1;
9408        for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
9409                prehash(lp->n);
9410                pip[1] = -1;
9411                if (lp->next) {
9412                        if (pipe(pip) < 0) {
9413                                close(prevfd);
9414                                ash_msg_and_raise_perror("can't create pipe");
9415                        }
9416                }
9417                if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9418                        /* child */
9419                        INT_ON;
9420                        if (pip[1] >= 0) {
9421                                close(pip[0]);
9422                        }
9423                        if (prevfd > 0) {
9424                                dup2(prevfd, 0);
9425                                close(prevfd);
9426                        }
9427                        if (pip[1] > 1) {
9428                                dup2(pip[1], 1);
9429                                close(pip[1]);
9430                        }
9431                        evaltreenr(lp->n, flags);
9432                        /* never returns */
9433                }
9434                /* parent */
9435                if (prevfd >= 0)
9436                        close(prevfd);
9437                prevfd = pip[0];
9438                /* Don't want to trigger debugging */
9439                if (pip[1] != -1)
9440                        close(pip[1]);
9441        }
9442        if (n->npipe.pipe_backgnd == 0) {
9443                status = waitforjob(jp);
9444                TRACE(("evalpipe:  job done exit status %d\n", status));
9445        }
9446        INT_ON;
9447
9448        return status;
9449}
9450
9451/*
9452 * Controls whether the shell is interactive or not.
9453 */
9454static void
9455setinteractive(int on)
9456{
9457        static smallint is_interactive;
9458
9459        if (++on == is_interactive)
9460                return;
9461        is_interactive = on;
9462        setsignal(SIGINT);
9463        setsignal(SIGQUIT);
9464        setsignal(SIGTERM);
9465#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9466        if (is_interactive > 1) {
9467                /* Looks like they want an interactive shell */
9468                static smallint did_banner;
9469
9470                if (!did_banner) {
9471                        /* note: ash and hush share this string */
9472                        out1fmt("\n\n%s %s\n"
9473                                IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9474                                "\n",
9475                                bb_banner,
9476                                "built-in shell (ash)"
9477                        );
9478                        did_banner = 1;
9479                }
9480        }
9481#endif
9482}
9483
9484static void
9485optschanged(void)
9486{
9487#if DEBUG
9488        opentrace();
9489#endif
9490        setinteractive(iflag);
9491        setjobctl(mflag);
9492#if ENABLE_FEATURE_EDITING_VI
9493        if (viflag)
9494                line_input_state->flags |= VI_MODE;
9495        else
9496                line_input_state->flags &= ~VI_MODE;
9497#else
9498        viflag = 0; /* forcibly keep the option off */
9499#endif
9500}
9501
9502struct localvar_list {
9503        struct localvar_list *next;
9504        struct localvar *lv;
9505};
9506
9507static struct localvar_list *localvar_stack;
9508
9509/*
9510 * Called after a function returns.
9511 * Interrupts must be off.
9512 */
9513static void
9514poplocalvars(int keep)
9515{
9516        struct localvar_list *ll;
9517        struct localvar *lvp, *next;
9518        struct var *vp;
9519
9520        INT_OFF;
9521        ll = localvar_stack;
9522        localvar_stack = ll->next;
9523
9524        next = ll->lv;
9525        free(ll);
9526
9527        while ((lvp = next) != NULL) {
9528                next = lvp->next;
9529                vp = lvp->vp;
9530                TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9531                if (keep) {
9532                        int bits = VSTRFIXED;
9533
9534                        if (lvp->flags != VUNSET) {
9535                                if (vp->var_text == lvp->text)
9536                                        bits |= VTEXTFIXED;
9537                                else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9538                                        free((char*)lvp->text);
9539                        }
9540
9541                        vp->flags &= ~bits;
9542                        vp->flags |= (lvp->flags & bits);
9543
9544                        if ((vp->flags &
9545                             (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9546                                unsetvar(vp->var_text);
9547                } else if (vp == NULL) {        /* $- saved */
9548                        memcpy(optlist, lvp->text, sizeof(optlist));
9549                        free((char*)lvp->text);
9550                        optschanged();
9551                } else if (lvp->flags == VUNSET) {
9552                        vp->flags &= ~(VSTRFIXED|VREADONLY);
9553                        unsetvar(vp->var_text);
9554                } else {
9555                        if (vp->var_func)
9556                                vp->var_func(var_end(lvp->text));
9557                        if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9558                                free((char*)vp->var_text);
9559                        vp->flags = lvp->flags;
9560                        vp->var_text = lvp->text;
9561                }
9562                free(lvp);
9563        }
9564        INT_ON;
9565}
9566
9567/*
9568 * Create a new localvar environment.
9569 */
9570static struct localvar_list *
9571pushlocalvars(void)
9572{
9573        struct localvar_list *ll;
9574
9575        INT_OFF;
9576        ll = ckzalloc(sizeof(*ll));
9577        /*ll->lv = NULL; - zalloc did it */
9578        ll->next = localvar_stack;
9579        localvar_stack = ll;
9580        INT_ON;
9581
9582        return ll->next;
9583}
9584
9585static void
9586unwindlocalvars(struct localvar_list *stop)
9587{
9588        while (localvar_stack != stop)
9589                poplocalvars(0);
9590}
9591
9592static int
9593evalfun(struct funcnode *func, int argc, char **argv, int flags)
9594{
9595        volatile struct shparam saveparam;
9596        struct jmploc *volatile savehandler;
9597        struct jmploc jmploc;
9598        int e;
9599        int savefuncline;
9600
9601        saveparam = shellparam;
9602        savefuncline = funcline;
9603        savehandler = exception_handler;
9604        e = setjmp(jmploc.loc);
9605        if (e) {
9606                goto funcdone;
9607        }
9608        INT_OFF;
9609        exception_handler = &jmploc;
9610        shellparam.malloced = 0;
9611        func->count++;
9612        funcline = func->n.ndefun.linno;
9613        INT_ON;
9614        shellparam.nparam = argc - 1;
9615        shellparam.p = argv + 1;
9616#if ENABLE_ASH_GETOPTS
9617        shellparam.optind = 1;
9618        shellparam.optoff = -1;
9619#endif
9620        evaltree(func->n.ndefun.body, flags & EV_TESTED);
9621 funcdone:
9622        INT_OFF;
9623        funcline = savefuncline;
9624        freefunc(func);
9625        freeparam(&shellparam);
9626        shellparam = saveparam;
9627        exception_handler = savehandler;
9628        INT_ON;
9629        evalskip &= ~SKIPFUNC;
9630        return e;
9631}
9632
9633/*
9634 * Make a variable a local variable.  When a variable is made local, it's
9635 * value and flags are saved in a localvar structure.  The saved values
9636 * will be restored when the shell function returns.  We handle the name
9637 * "-" as a special case: it makes changes to "set +-options" local
9638 * (options will be restored on return from the function).
9639 */
9640static void
9641mklocal(char *name)
9642{
9643        struct localvar *lvp;
9644        struct var **vpp;
9645        struct var *vp;
9646        char *eq = strchr(name, '=');
9647
9648        INT_OFF;
9649        /* Cater for duplicate "local". Examples:
9650         * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9651         * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9652         */
9653        lvp = localvar_stack->lv;
9654        while (lvp) {
9655                if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9656                        if (eq)
9657                                setvareq(name, 0);
9658                        /* else:
9659                         * it's a duplicate "local VAR" declaration, do nothing
9660                         */
9661                        goto ret;
9662                }
9663                lvp = lvp->next;
9664        }
9665
9666        lvp = ckzalloc(sizeof(*lvp));
9667        if (LONE_DASH(name)) {
9668                char *p;
9669                p = ckmalloc(sizeof(optlist));
9670                lvp->text = memcpy(p, optlist, sizeof(optlist));
9671                vp = NULL;
9672        } else {
9673                vpp = hashvar(name);
9674                vp = *findvar(vpp, name);
9675                if (vp == NULL) {
9676                        /* variable did not exist yet */
9677                        if (eq)
9678                                vp = setvareq(name, VSTRFIXED);
9679                        else
9680                                vp = setvar(name, NULL, VSTRFIXED);
9681                        lvp->flags = VUNSET;
9682                } else {
9683                        lvp->text = vp->var_text;
9684                        lvp->flags = vp->flags;
9685                        /* make sure neither "struct var" nor string gets freed
9686                         * during (un)setting:
9687                         */
9688                        vp->flags |= VSTRFIXED|VTEXTFIXED;
9689                        if (eq)
9690                                setvareq(name, 0);
9691                        else
9692                                /* "local VAR" unsets VAR: */
9693                                setvar0(name, NULL);
9694                }
9695        }
9696        lvp->vp = vp;
9697        lvp->next = localvar_stack->lv;
9698        localvar_stack->lv = lvp;
9699 ret:
9700        INT_ON;
9701}
9702
9703/*
9704 * The "local" command.
9705 */
9706static int FAST_FUNC
9707localcmd(int argc UNUSED_PARAM, char **argv)
9708{
9709        char *name;
9710
9711        if (!localvar_stack)
9712                ash_msg_and_raise_error("not in a function");
9713
9714        argv = argptr;
9715        while ((name = *argv++) != NULL) {
9716                mklocal(name);
9717        }
9718        return 0;
9719}
9720
9721static int FAST_FUNC
9722falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9723{
9724        return 1;
9725}
9726
9727static int FAST_FUNC
9728truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9729{
9730        return 0;
9731}
9732
9733static int FAST_FUNC
9734execcmd(int argc UNUSED_PARAM, char **argv)
9735{
9736        optionarg = NULL;
9737        while (nextopt("a:") != '\0')
9738                /* nextopt() sets optionarg to "-a ARGV0" */;
9739
9740        argv = argptr;
9741        if (argv[0]) {
9742                char *prog;
9743
9744                iflag = 0;              /* exit on error */
9745                mflag = 0;
9746                optschanged();
9747                /* We should set up signals for "exec CMD"
9748                 * the same way as for "CMD" without "exec".
9749                 * But optschanged->setinteractive->setsignal
9750                 * still thought we are a root shell. Therefore, for example,
9751                 * SIGQUIT is still set to IGN. Fix it:
9752                 */
9753                shlvl++;
9754                setsignal(SIGQUIT);
9755                /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9756                /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9757                /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9758
9759                prog = argv[0];
9760                if (optionarg)
9761                        argv[0] = optionarg;
9762                shellexec(prog, argv, pathval(), 0);
9763                /* NOTREACHED */
9764        }
9765        return 0;
9766}
9767
9768/*
9769 * The return command.
9770 */
9771static int FAST_FUNC
9772returncmd(int argc UNUSED_PARAM, char **argv)
9773{
9774        /*
9775         * If called outside a function, do what ksh does;
9776         * skip the rest of the file.
9777         */
9778        evalskip = SKIPFUNC;
9779        return argv[1] ? number(argv[1]) : exitstatus;
9780}
9781
9782/* Forward declarations for builtintab[] */
9783static int breakcmd(int, char **) FAST_FUNC;
9784static int dotcmd(int, char **) FAST_FUNC;
9785static int evalcmd(int, char **, int) FAST_FUNC;
9786static int exitcmd(int, char **) FAST_FUNC;
9787static int exportcmd(int, char **) FAST_FUNC;
9788#if ENABLE_ASH_GETOPTS
9789static int getoptscmd(int, char **) FAST_FUNC;
9790#endif
9791#if ENABLE_ASH_HELP
9792static int helpcmd(int, char **) FAST_FUNC;
9793#endif
9794#if MAX_HISTORY
9795static int historycmd(int, char **) FAST_FUNC;
9796#endif
9797#if ENABLE_FEATURE_SH_MATH
9798static int letcmd(int, char **) FAST_FUNC;
9799#endif
9800static int readcmd(int, char **) FAST_FUNC;
9801static int setcmd(int, char **) FAST_FUNC;
9802static int shiftcmd(int, char **) FAST_FUNC;
9803static int timescmd(int, char **) FAST_FUNC;
9804static int trapcmd(int, char **) FAST_FUNC;
9805static int umaskcmd(int, char **) FAST_FUNC;
9806static int unsetcmd(int, char **) FAST_FUNC;
9807static int ulimitcmd(int, char **) FAST_FUNC;
9808
9809#define BUILTIN_NOSPEC          "0"
9810#define BUILTIN_SPECIAL         "1"
9811#define BUILTIN_REGULAR         "2"
9812#define BUILTIN_SPEC_REG        "3"
9813#define BUILTIN_ASSIGN          "4"
9814#define BUILTIN_SPEC_ASSG       "5"
9815#define BUILTIN_REG_ASSG        "6"
9816#define BUILTIN_SPEC_REG_ASSG   "7"
9817
9818/* Stubs for calling non-FAST_FUNC's */
9819#if ENABLE_ASH_ECHO
9820static int FAST_FUNC echocmd(int argc, char **argv)   { return echo_main(argc, argv); }
9821#endif
9822#if ENABLE_ASH_PRINTF
9823static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
9824#endif
9825#if ENABLE_ASH_TEST || BASH_TEST2
9826static int FAST_FUNC testcmd(int argc, char **argv)   { return test_main(argc, argv); }
9827#endif
9828
9829/* Keep these in proper order since it is searched via bsearch() */
9830static const struct builtincmd builtintab[] = {
9831        { BUILTIN_SPEC_REG      "."       , dotcmd     },
9832        { BUILTIN_SPEC_REG      ":"       , truecmd    },
9833#if ENABLE_ASH_TEST
9834        { BUILTIN_REGULAR       "["       , testcmd    },
9835#endif
9836#if BASH_TEST2
9837        { BUILTIN_REGULAR       "[["      , testcmd    },
9838#endif
9839#if ENABLE_ASH_ALIAS
9840        { BUILTIN_REG_ASSG      "alias"   , aliascmd   },
9841#endif
9842#if JOBS
9843        { BUILTIN_REGULAR       "bg"      , fg_bgcmd   },
9844#endif
9845        { BUILTIN_SPEC_REG      "break"   , breakcmd   },
9846        { BUILTIN_REGULAR       "cd"      , cdcmd      },
9847        { BUILTIN_NOSPEC        "chdir"   , cdcmd      },
9848#if ENABLE_ASH_CMDCMD
9849        { BUILTIN_REGULAR       "command" , commandcmd },
9850#endif
9851        { BUILTIN_SPEC_REG      "continue", breakcmd   },
9852#if ENABLE_ASH_ECHO
9853        { BUILTIN_REGULAR       "echo"    , echocmd    },
9854#endif
9855        { BUILTIN_SPEC_REG      "eval"    , NULL       }, /*evalcmd() has a differing prototype*/
9856        { BUILTIN_SPEC_REG      "exec"    , execcmd    },
9857        { BUILTIN_SPEC_REG      "exit"    , exitcmd    },
9858        { BUILTIN_SPEC_REG_ASSG "export"  , exportcmd  },
9859        { BUILTIN_REGULAR       "false"   , falsecmd   },
9860#if JOBS
9861        { BUILTIN_REGULAR       "fg"      , fg_bgcmd   },
9862#endif
9863#if ENABLE_ASH_GETOPTS
9864        { BUILTIN_REGULAR       "getopts" , getoptscmd },
9865#endif
9866        { BUILTIN_NOSPEC        "hash"    , hashcmd    },
9867#if ENABLE_ASH_HELP
9868        { BUILTIN_NOSPEC        "help"    , helpcmd    },
9869#endif
9870#if MAX_HISTORY
9871        { BUILTIN_NOSPEC        "history" , historycmd },
9872#endif
9873#if JOBS
9874        { BUILTIN_REGULAR       "jobs"    , jobscmd    },
9875        { BUILTIN_REGULAR       "kill"    , killcmd    },
9876#endif
9877#if ENABLE_FEATURE_SH_MATH
9878        { BUILTIN_NOSPEC        "let"     , letcmd     },
9879#endif
9880        { BUILTIN_SPEC_REG_ASSG "local"   , localcmd   },
9881#if ENABLE_ASH_PRINTF
9882        { BUILTIN_REGULAR       "printf"  , printfcmd  },
9883#endif
9884        { BUILTIN_NOSPEC        "pwd"     , pwdcmd     },
9885        { BUILTIN_REGULAR       "read"    , readcmd    },
9886        { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd  },
9887        { BUILTIN_SPEC_REG      "return"  , returncmd  },
9888        { BUILTIN_SPEC_REG      "set"     , setcmd     },
9889        { BUILTIN_SPEC_REG      "shift"   , shiftcmd   },
9890#if BASH_SOURCE
9891        { BUILTIN_SPEC_REG      "source"  , dotcmd     },
9892#endif
9893#if ENABLE_ASH_TEST
9894        { BUILTIN_REGULAR       "test"    , testcmd    },
9895#endif
9896        { BUILTIN_SPEC_REG      "times"   , timescmd   },
9897        { BUILTIN_SPEC_REG      "trap"    , trapcmd    },
9898        { BUILTIN_REGULAR       "true"    , truecmd    },
9899        { BUILTIN_NOSPEC        "type"    , typecmd    },
9900        { BUILTIN_NOSPEC        "ulimit"  , ulimitcmd  },
9901        { BUILTIN_REGULAR       "umask"   , umaskcmd   },
9902#if ENABLE_ASH_ALIAS
9903        { BUILTIN_REGULAR       "unalias" , unaliascmd },
9904#endif
9905        { BUILTIN_SPEC_REG      "unset"   , unsetcmd   },
9906        { BUILTIN_REGULAR       "wait"    , waitcmd    },
9907};
9908
9909/* Should match the above table! */
9910#define COMMANDCMD (builtintab + \
9911        /* . : */       2 + \
9912        /* [ */         1 * ENABLE_ASH_TEST + \
9913        /* [[ */        1 * BASH_TEST2 + \
9914        /* alias */     1 * ENABLE_ASH_ALIAS + \
9915        /* bg */        1 * ENABLE_ASH_JOB_CONTROL + \
9916        /* break cd cddir  */   3)
9917#define EVALCMD (COMMANDCMD + \
9918        /* command */   1 * ENABLE_ASH_CMDCMD + \
9919        /* continue */  1 + \
9920        /* echo */      1 * ENABLE_ASH_ECHO + \
9921        0)
9922#define EXECCMD (EVALCMD + \
9923        /* eval */      1)
9924
9925/*
9926 * Search the table of builtin commands.
9927 */
9928static int
9929pstrcmp1(const void *a, const void *b)
9930{
9931        return strcmp((char*)a, *(char**)b + 1);
9932}
9933static struct builtincmd *
9934find_builtin(const char *name)
9935{
9936        struct builtincmd *bp;
9937
9938        bp = bsearch(
9939                name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9940                pstrcmp1
9941        );
9942        return bp;
9943}
9944
9945/*
9946 * Execute a simple command.
9947 */
9948static void unwindfiles(struct parsefile *stop);
9949static int
9950isassignment(const char *p)
9951{
9952        const char *q = endofname(p);
9953        if (p == q)
9954                return 0;
9955        return *q == '=';
9956}
9957static int FAST_FUNC
9958bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9959{
9960        /* Preserve exitstatus of a previous possible redirection
9961         * as POSIX mandates */
9962        return back_exitstatus;
9963}
9964static int
9965evalcommand(union node *cmd, int flags)
9966{
9967        static const struct builtincmd null_bltin = {
9968                "\0\0", bltincmd /* why three NULs? */
9969        };
9970        struct localvar_list *localvar_stop;
9971        struct parsefile *file_stop;
9972        struct redirtab *redir_stop;
9973        struct stackmark smark;
9974        union node *argp;
9975        struct arglist arglist;
9976        struct arglist varlist;
9977        char **argv;
9978        int argc;
9979        const struct strlist *sp;
9980        struct cmdentry cmdentry;
9981        struct job *jp;
9982        char *lastarg;
9983        const char *path;
9984        int spclbltin;
9985        int status;
9986        char **nargv;
9987        smallint cmd_is_exec;
9988
9989        errlinno = lineno = cmd->ncmd.linno;
9990        if (funcline)
9991                lineno -= funcline - 1;
9992
9993        /* First expand the arguments. */
9994        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9995        setstackmark(&smark);
9996        localvar_stop = pushlocalvars();
9997        file_stop = g_parsefile;
9998        back_exitstatus = 0;
9999
10000        cmdentry.cmdtype = CMDBUILTIN;
10001        cmdentry.u.cmd = &null_bltin;
10002        varlist.lastp = &varlist.list;
10003        *varlist.lastp = NULL;
10004        arglist.lastp = &arglist.list;
10005        *arglist.lastp = NULL;
10006
10007        argc = 0;
10008        if (cmd->ncmd.args) {
10009                struct builtincmd *bcmd;
10010                smallint pseudovarflag;
10011
10012                bcmd = find_builtin(cmd->ncmd.args->narg.text);
10013                pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
10014
10015                for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
10016                        struct strlist **spp;
10017
10018                        spp = arglist.lastp;
10019                        if (pseudovarflag && isassignment(argp->narg.text))
10020                                expandarg(argp, &arglist, EXP_VARTILDE);
10021                        else
10022                                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
10023
10024                        for (sp = *spp; sp; sp = sp->next)
10025                                argc++;
10026                }
10027        }
10028
10029        /* Reserve one extra spot at the front for shellexec. */
10030        nargv = stalloc(sizeof(char *) * (argc + 2));
10031        argv = ++nargv;
10032        for (sp = arglist.list; sp; sp = sp->next) {
10033                TRACE(("evalcommand arg: %s\n", sp->text));
10034                *nargv++ = sp->text;
10035        }
10036        *nargv = NULL;
10037
10038        lastarg = NULL;
10039        if (iflag && funcline == 0 && argc > 0)
10040                lastarg = nargv[-1];
10041
10042        expredir(cmd->ncmd.redirect);
10043        redir_stop = pushredir(cmd->ncmd.redirect);
10044        preverrout_fd = 2;
10045        if (BASH_XTRACEFD && xflag) {
10046                /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10047                 * we do not emulate this. We only use its value.
10048                 */
10049                const char *xtracefd = lookupvar("BASH_XTRACEFD");
10050                if (xtracefd && is_number(xtracefd))
10051                        preverrout_fd = atoi(xtracefd);
10052
10053        }
10054        status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10055
10056        path = vpath.var_text;
10057        for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10058                struct strlist **spp;
10059                char *p;
10060
10061                spp = varlist.lastp;
10062                expandarg(argp, &varlist, EXP_VARTILDE);
10063
10064                mklocal((*spp)->text);
10065
10066                /*
10067                 * Modify the command lookup path, if a PATH= assignment
10068                 * is present
10069                 */
10070                p = (*spp)->text;
10071                if (varcmp(p, path) == 0)
10072                        path = p;
10073        }
10074
10075        /* Print the command if xflag is set. */
10076        if (xflag) {
10077                const char *pfx = "";
10078
10079                fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
10080
10081                sp = varlist.list;
10082                while (sp) {
10083                        char *varval = sp->text;
10084                        char *eq = strchrnul(varval, '=');
10085                        if (*eq)
10086                                eq++;
10087                        fdprintf(preverrout_fd, "%s%.*s%s",
10088                                pfx,
10089                                (int)(eq - varval), varval,
10090                                maybe_single_quote(eq)
10091                        );
10092                        sp = sp->next;
10093                        pfx = " ";
10094                }
10095
10096                sp = arglist.list;
10097                while (sp) {
10098                        fdprintf(preverrout_fd, "%s%s",
10099                                pfx,
10100                                /* always quote if matches reserved word: */
10101                                findkwd(sp->text)
10102                                ? single_quote(sp->text)
10103                                : maybe_single_quote(sp->text)
10104                        );
10105                        sp = sp->next;
10106                        pfx = " ";
10107                }
10108                safe_write(preverrout_fd, "\n", 1);
10109        }
10110
10111        cmd_is_exec = 0;
10112        spclbltin = -1;
10113
10114        /* Now locate the command. */
10115        if (argc) {
10116                int cmd_flag = DO_ERR;
10117#if ENABLE_ASH_CMDCMD
10118                const char *oldpath = path + 5;
10119#endif
10120                path += 5;
10121                for (;;) {
10122                        find_command(argv[0], &cmdentry, cmd_flag, path);
10123                        if (cmdentry.cmdtype == CMDUNKNOWN) {
10124                                flush_stdout_stderr();
10125                                status = 127;
10126                                goto bail;
10127                        }
10128
10129                        /* implement bltin and command here */
10130                        if (cmdentry.cmdtype != CMDBUILTIN)
10131                                break;
10132                        if (spclbltin < 0)
10133                                spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10134                        if (cmdentry.u.cmd == EXECCMD)
10135                                cmd_is_exec = 1;
10136#if ENABLE_ASH_CMDCMD
10137                        if (cmdentry.u.cmd == COMMANDCMD) {
10138                                path = oldpath;
10139                                nargv = parse_command_args(argv, &path);
10140                                if (!nargv)
10141                                        break;
10142                                /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10143                                 * nargv => "PROG". path is updated if -p.
10144                                 */
10145                                argc -= nargv - argv;
10146                                argv = nargv;
10147                                cmd_flag |= DO_NOFUNC;
10148                        } else
10149#endif
10150                                break;
10151                }
10152        }
10153
10154        if (status) {
10155 bail:
10156                exitstatus = status;
10157
10158                /* We have a redirection error. */
10159                if (spclbltin > 0)
10160                        raise_exception(EXERROR);
10161
10162                goto out;
10163        }
10164
10165        /* Execute the command. */
10166        switch (cmdentry.cmdtype) {
10167        default: {
10168
10169#if ENABLE_FEATURE_SH_STANDALONE \
10170 && ENABLE_FEATURE_SH_NOFORK \
10171 && NUM_APPLETS > 1
10172/* (1) BUG: if variables are set, we need to fork, or save/restore them
10173 *     around run_nofork_applet() call.
10174 * (2) Should this check also be done in forkshell()?
10175 *     (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10176 */
10177                /* find_command() encodes applet_no as (-2 - applet_no) */
10178                int applet_no = (- cmdentry.u.index - 2);
10179                if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10180                        char **sv_environ;
10181
10182                        INT_OFF;
10183                        sv_environ = environ;
10184                        environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
10185                        /*
10186                         * Run <applet>_main().
10187                         * Signals (^C) can't interrupt here.
10188                         * Otherwise we can mangle stdio or malloc internal state.
10189                         * This makes applets which can run for a long time
10190                         * and/or wait for user input ineligible for NOFORK:
10191                         * for example, "yes" or "rm" (rm -i waits for input).
10192                         */
10193                        status = run_nofork_applet(applet_no, argv);
10194                        environ = sv_environ;
10195                        /*
10196                         * Try enabling NOFORK for "yes" applet.
10197                         * ^C _will_ stop it (write returns EINTR),
10198                         * but this causes stdout FILE to be stuck
10199                         * and needing clearerr(). What if other applets
10200                         * also can get EINTRs? Do we need to switch
10201                         * our signals to SA_RESTART?
10202                         */
10203                        /*clearerr(stdout);*/
10204                        INT_ON;
10205                        break;
10206                }
10207#endif
10208                /* Can we avoid forking? For example, very last command
10209                 * in a script or a subshell does not need forking,
10210                 * we can just exec it.
10211                 */
10212                if (!(flags & EV_EXIT) || may_have_traps) {
10213                        /* No, forking off a child is necessary */
10214                        INT_OFF;
10215                        get_tty_state();
10216                        jp = makejob(/*cmd,*/ 1);
10217                        if (forkshell(jp, cmd, FORK_FG) != 0) {
10218                                /* parent */
10219                                status = waitforjob(jp);
10220                                INT_ON;
10221                                TRACE(("forked child exited with %d\n", status));
10222                                break;
10223                        }
10224                        /* child */
10225                        FORCE_INT_ON;
10226                        /* fall through to exec'ing external program */
10227                }
10228                listsetvar(varlist.list, VEXPORT|VSTACK);
10229                shellexec(argv[0], argv, path, cmdentry.u.index);
10230                /* NOTREACHED */
10231        } /* default */
10232        case CMDBUILTIN:
10233                if (spclbltin > 0 || argc == 0) {
10234                        poplocalvars(1);
10235                        if (cmd_is_exec && argc > 1)
10236                                listsetvar(varlist.list, VEXPORT);
10237                }
10238
10239                /* Tight loop with builtins only:
10240                 * "while kill -0 $child; do true; done"
10241                 * will never exit even if $child died, unless we do this
10242                 * to reap the zombie and make kill detect that it's gone: */
10243                dowait(DOWAIT_NONBLOCK, NULL);
10244
10245                if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
10246                        if (exception_type == EXERROR && spclbltin <= 0) {
10247                                FORCE_INT_ON;
10248                                goto readstatus;
10249                        }
10250 raise:
10251                        longjmp(exception_handler->loc, 1);
10252                }
10253                goto readstatus;
10254
10255        case CMDFUNCTION:
10256                /* See above for the rationale */
10257                dowait(DOWAIT_NONBLOCK, NULL);
10258                if (evalfun(cmdentry.u.func, argc, argv, flags))
10259                        goto raise;
10260 readstatus:
10261                status = exitstatus;
10262                break;
10263        } /* switch */
10264
10265 out:
10266        if (cmd->ncmd.redirect)
10267                popredir(/*drop:*/ cmd_is_exec);
10268        unwindredir(redir_stop);
10269        unwindfiles(file_stop);
10270        unwindlocalvars(localvar_stop);
10271        if (lastarg) {
10272                /* dsl: I think this is intended to be used to support
10273                 * '_' in 'vi' command mode during line editing...
10274                 * However I implemented that within libedit itself.
10275                 */
10276                setvar0("_", lastarg);
10277        }
10278        popstackmark(&smark);
10279
10280        return status;
10281}
10282
10283static int
10284evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
10285{
10286        char *volatile savecmdname;
10287        struct jmploc *volatile savehandler;
10288        struct jmploc jmploc;
10289        int status;
10290        int i;
10291
10292        savecmdname = commandname;
10293        savehandler = exception_handler;
10294        i = setjmp(jmploc.loc);
10295        if (i)
10296                goto cmddone;
10297        exception_handler = &jmploc;
10298        commandname = argv[0];
10299        argptr = argv + 1;
10300        optptr = NULL;                  /* initialize nextopt */
10301        if (cmd == EVALCMD)
10302                status = evalcmd(argc, argv, flags);
10303        else
10304                status = (*cmd->builtin)(argc, argv);
10305        flush_stdout_stderr();
10306        status |= ferror(stdout);
10307        exitstatus = status;
10308 cmddone:
10309        clearerr(stdout);
10310        commandname = savecmdname;
10311        exception_handler = savehandler;
10312
10313        return i;
10314}
10315
10316static int
10317goodname(const char *p)
10318{
10319        return endofname(p)[0] == '\0';
10320}
10321
10322
10323/*
10324 * Search for a command.  This is called before we fork so that the
10325 * location of the command will be available in the parent as well as
10326 * the child.  The check for "goodname" is an overly conservative
10327 * check that the name will not be subject to expansion.
10328 */
10329static void
10330prehash(union node *n)
10331{
10332        struct cmdentry entry;
10333
10334        if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10335                find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
10336}
10337
10338
10339/* ============ Builtin commands
10340 *
10341 * Builtin commands whose functions are closely tied to evaluation
10342 * are implemented here.
10343 */
10344
10345/*
10346 * Handle break and continue commands.  Break, continue, and return are
10347 * all handled by setting the evalskip flag.  The evaluation routines
10348 * above all check this flag, and if it is set they start skipping
10349 * commands rather than executing them.  The variable skipcount is
10350 * the number of loops to break/continue, or the number of function
10351 * levels to return.  (The latter is always 1.)  It should probably
10352 * be an error to break out of more loops than exist, but it isn't
10353 * in the standard shell so we don't make it one here.
10354 */
10355static int FAST_FUNC
10356breakcmd(int argc UNUSED_PARAM, char **argv)
10357{
10358        int n = argv[1] ? number(argv[1]) : 1;
10359
10360        if (n <= 0)
10361                ash_msg_and_raise_error(msg_illnum, argv[1]);
10362        if (n > loopnest)
10363                n = loopnest;
10364        if (n > 0) {
10365                evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
10366                skipcount = n;
10367        }
10368        return 0;
10369}
10370
10371
10372/*
10373 * This implements the input routines used by the parser.
10374 */
10375
10376enum {
10377        INPUT_PUSH_FILE = 1,
10378        INPUT_NOFILE_OK = 2,
10379};
10380
10381static smallint checkkwd;
10382/* values of checkkwd variable */
10383#define CHKALIAS        0x1
10384#define CHKKWD          0x2
10385#define CHKNL           0x4
10386#define CHKEOFMARK      0x8
10387
10388/*
10389 * Push a string back onto the input at this current parsefile level.
10390 * We handle aliases this way.
10391 */
10392#if !ENABLE_ASH_ALIAS
10393#define pushstring(s, ap) pushstring(s)
10394#endif
10395static void
10396pushstring(char *s, struct alias *ap)
10397{
10398        struct strpush *sp;
10399        int len;
10400
10401        len = strlen(s);
10402        INT_OFF;
10403        if (g_parsefile->strpush) {
10404                sp = ckzalloc(sizeof(*sp));
10405                sp->prev = g_parsefile->strpush;
10406        } else {
10407                sp = &(g_parsefile->basestrpush);
10408        }
10409        g_parsefile->strpush = sp;
10410        sp->prev_string = g_parsefile->next_to_pgetc;
10411        sp->prev_left_in_line = g_parsefile->left_in_line;
10412        sp->unget = g_parsefile->unget;
10413        memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
10414#if ENABLE_ASH_ALIAS
10415        sp->ap = ap;
10416        if (ap) {
10417                ap->flag |= ALIASINUSE;
10418                sp->string = s;
10419        }
10420#endif
10421        g_parsefile->next_to_pgetc = s;
10422        g_parsefile->left_in_line = len;
10423        g_parsefile->unget = 0;
10424        INT_ON;
10425}
10426
10427static void
10428popstring(void)
10429{
10430        struct strpush *sp = g_parsefile->strpush;
10431
10432        INT_OFF;
10433#if ENABLE_ASH_ALIAS
10434        if (sp->ap) {
10435                if (g_parsefile->next_to_pgetc[-1] == ' '
10436                 || g_parsefile->next_to_pgetc[-1] == '\t'
10437                ) {
10438                        checkkwd |= CHKALIAS;
10439                }
10440                if (sp->string != sp->ap->val) {
10441                        free(sp->string);
10442                }
10443                sp->ap->flag &= ~ALIASINUSE;
10444                if (sp->ap->flag & ALIASDEAD) {
10445                        unalias(sp->ap->name);
10446                }
10447        }
10448#endif
10449        g_parsefile->next_to_pgetc = sp->prev_string;
10450        g_parsefile->left_in_line = sp->prev_left_in_line;
10451        g_parsefile->unget = sp->unget;
10452        memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
10453        g_parsefile->strpush = sp->prev;
10454        if (sp != &(g_parsefile->basestrpush))
10455                free(sp);
10456        INT_ON;
10457}
10458
10459static int
10460preadfd(void)
10461{
10462        int nr;
10463        char *buf = g_parsefile->buf;
10464
10465        g_parsefile->next_to_pgetc = buf;
10466#if ENABLE_FEATURE_EDITING
10467 retry:
10468        if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10469                nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10470        else {
10471# if ENABLE_ASH_IDLE_TIMEOUT
10472                int timeout = -1;
10473                if (iflag) {
10474                        const char *tmout_var = lookupvar("TMOUT");
10475                        if (tmout_var) {
10476                                timeout = atoi(tmout_var) * 1000;
10477                                if (timeout <= 0)
10478                                        timeout = -1;
10479                        }
10480                }
10481                line_input_state->timeout = timeout;
10482# endif
10483# if ENABLE_FEATURE_TAB_COMPLETION
10484                line_input_state->path_lookup = pathval();
10485# endif
10486                reinit_unicode_for_ash();
10487                nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10488                if (nr == 0) {
10489                        /* ^C pressed, "convert" to SIGINT */
10490                        write(STDOUT_FILENO, "^C", 2);
10491                        if (trap[SIGINT]) {
10492                                buf[0] = '\n';
10493                                buf[1] = '\0';
10494                                raise(SIGINT);
10495                                return 1;
10496                        }
10497                        exitstatus = 128 + SIGINT;
10498                        bb_putchar('\n');
10499                        goto retry;
10500                }
10501                if (nr < 0) {
10502                        if (errno == 0) {
10503                                /* Ctrl+D pressed */
10504                                nr = 0;
10505                        }
10506# if ENABLE_ASH_IDLE_TIMEOUT
10507                        else if (errno == EAGAIN && timeout > 0) {
10508                                puts("\007timed out waiting for input: auto-logout");
10509                                exitshell();
10510                        }
10511# endif
10512                }
10513        }
10514#else
10515        nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10516#endif
10517
10518#if 0 /* disabled: nonblock_immune_read() handles this problem */
10519        if (nr < 0) {
10520                if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10521                        int flags = fcntl(0, F_GETFL);
10522                        if (flags >= 0 && (flags & O_NONBLOCK)) {
10523                                flags &= ~O_NONBLOCK;
10524                                if (fcntl(0, F_SETFL, flags) >= 0) {
10525                                        out2str("sh: turning off NDELAY mode\n");
10526                                        goto retry;
10527                                }
10528                        }
10529                }
10530        }
10531#endif
10532        return nr;
10533}
10534
10535/*
10536 * Refill the input buffer and return the next input character:
10537 *
10538 * 1) If a string was pushed back on the input, pop it;
10539 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10540 *    or we are reading from a string so we can't refill the buffer,
10541 *    return EOF.
10542 * 3) If there is more stuff in this buffer, use it else call read to fill it.
10543 * 4) Process input up to the next newline, deleting nul characters.
10544 */
10545//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10546#define pgetc_debug(...) ((void)0)
10547static int pgetc(void);
10548static int
10549preadbuffer(void)
10550{
10551        char *q;
10552        int more;
10553
10554        if (g_parsefile->strpush) {
10555#if ENABLE_ASH_ALIAS
10556                if (g_parsefile->left_in_line == -1
10557                 && g_parsefile->strpush->ap
10558                 && g_parsefile->next_to_pgetc[-1] != ' '
10559                 && g_parsefile->next_to_pgetc[-1] != '\t'
10560                ) {
10561                        pgetc_debug("preadbuffer PEOA");
10562                        return PEOA;
10563                }
10564#endif
10565                popstring();
10566                return pgetc();
10567        }
10568        /* on both branches above g_parsefile->left_in_line < 0.
10569         * "pgetc" needs refilling.
10570         */
10571
10572        /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
10573         * pungetc() may increment it a few times.
10574         * Assuming it won't increment it to less than -90.
10575         */
10576        if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
10577                pgetc_debug("preadbuffer PEOF1");
10578                /* even in failure keep left_in_line and next_to_pgetc
10579                 * in lock step, for correct multi-layer pungetc.
10580                 * left_in_line was decremented before preadbuffer(),
10581                 * must inc next_to_pgetc: */
10582                g_parsefile->next_to_pgetc++;
10583                return PEOF;
10584        }
10585
10586        more = g_parsefile->left_in_buffer;
10587        if (more <= 0) {
10588                flush_stdout_stderr();
10589 again:
10590                more = preadfd();
10591                if (more <= 0) {
10592                        /* don't try reading again */
10593                        g_parsefile->left_in_line = -99;
10594                        pgetc_debug("preadbuffer PEOF2");
10595                        g_parsefile->next_to_pgetc++;
10596                        return PEOF;
10597                }
10598        }
10599
10600        /* Find out where's the end of line.
10601         * Set g_parsefile->left_in_line
10602         * and g_parsefile->left_in_buffer acordingly.
10603         * NUL chars are deleted.
10604         */
10605        q = g_parsefile->next_to_pgetc;
10606        for (;;) {
10607                char c;
10608
10609                more--;
10610
10611                c = *q;
10612                if (c == '\0') {
10613                        memmove(q, q + 1, more);
10614                } else {
10615                        q++;
10616                        if (c == '\n') {
10617                                g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10618                                break;
10619                        }
10620                }
10621
10622                if (more <= 0) {
10623                        g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10624                        if (g_parsefile->left_in_line < 0)
10625                                goto again;
10626                        break;
10627                }
10628        }
10629        g_parsefile->left_in_buffer = more;
10630
10631        if (vflag) {
10632                char save = *q;
10633                *q = '\0';
10634                out2str(g_parsefile->next_to_pgetc);
10635                *q = save;
10636        }
10637
10638        pgetc_debug("preadbuffer at %d:%p'%s'",
10639                        g_parsefile->left_in_line,
10640                        g_parsefile->next_to_pgetc,
10641                        g_parsefile->next_to_pgetc);
10642        return (unsigned char)*g_parsefile->next_to_pgetc++;
10643}
10644
10645static void
10646nlprompt(void)
10647{
10648        g_parsefile->linno++;
10649        setprompt_if(doprompt, 2);
10650}
10651static void
10652nlnoprompt(void)
10653{
10654        g_parsefile->linno++;
10655        needprompt = doprompt;
10656}
10657
10658static int
10659pgetc(void)
10660{
10661        int c;
10662
10663        pgetc_debug("pgetc at %d:%p'%s'",
10664                        g_parsefile->left_in_line,
10665                        g_parsefile->next_to_pgetc,
10666                        g_parsefile->next_to_pgetc);
10667        if (g_parsefile->unget)
10668                return g_parsefile->lastc[--g_parsefile->unget];
10669
10670        if (--g_parsefile->left_in_line >= 0)
10671                c = (unsigned char)*g_parsefile->next_to_pgetc++;
10672        else
10673                c = preadbuffer();
10674
10675        g_parsefile->lastc[1] = g_parsefile->lastc[0];
10676        g_parsefile->lastc[0] = c;
10677
10678        return c;
10679}
10680
10681#if ENABLE_ASH_ALIAS
10682static int
10683pgetc_without_PEOA(void)
10684{
10685        int c;
10686        do {
10687                pgetc_debug("pgetc at %d:%p'%s'",
10688                                g_parsefile->left_in_line,
10689                                g_parsefile->next_to_pgetc,
10690                                g_parsefile->next_to_pgetc);
10691                c = pgetc();
10692        } while (c == PEOA);
10693        return c;
10694}
10695#else
10696# define pgetc_without_PEOA() pgetc()
10697#endif
10698
10699/*
10700 * Undo a call to pgetc.  Only two characters may be pushed back.
10701 * PEOF may be pushed back.
10702 */
10703static void
10704pungetc(void)
10705{
10706        g_parsefile->unget++;
10707}
10708
10709/* This one eats backslash+newline */
10710static int
10711pgetc_eatbnl(void)
10712{
10713        int c;
10714
10715        while ((c = pgetc()) == '\\') {
10716                if (pgetc() != '\n') {
10717                        pungetc();
10718                        break;
10719                }
10720
10721                nlprompt();
10722        }
10723
10724        return c;
10725}
10726
10727struct synstack {
10728        smalluint syntax;
10729        uint8_t innerdq   :1;
10730        uint8_t varpushed :1;
10731        uint8_t dblquote  :1;
10732        int varnest;            /* levels of variables expansion */
10733        int dqvarnest;          /* levels of variables expansion within double quotes */
10734        int parenlevel;         /* levels of parens in arithmetic */
10735        struct synstack *prev;
10736        struct synstack *next;
10737};
10738
10739static void
10740synstack_push(struct synstack **stack, struct synstack *next, int syntax)
10741{
10742        memset(next, 0, sizeof(*next));
10743        next->syntax = syntax;
10744        next->next = *stack;
10745        (*stack)->prev = next;
10746        *stack = next;
10747}
10748
10749static ALWAYS_INLINE void
10750synstack_pop(struct synstack **stack)
10751{
10752        *stack = (*stack)->next;
10753}
10754
10755/*
10756 * To handle the "." command, a stack of input files is used.  Pushfile
10757 * adds a new entry to the stack and popfile restores the previous level.
10758 */
10759static void
10760pushfile(void)
10761{
10762        struct parsefile *pf;
10763
10764        pf = ckzalloc(sizeof(*pf));
10765        pf->prev = g_parsefile;
10766        pf->pf_fd = -1;
10767        /*pf->strpush = NULL; - ckzalloc did it */
10768        /*pf->basestrpush.prev = NULL;*/
10769        /*pf->unget = 0;*/
10770        g_parsefile = pf;
10771}
10772
10773static void
10774popfile(void)
10775{
10776        struct parsefile *pf = g_parsefile;
10777
10778        if (pf == &basepf)
10779                return;
10780
10781        INT_OFF;
10782        if (pf->pf_fd >= 0)
10783                close(pf->pf_fd);
10784        free(pf->buf);
10785        while (pf->strpush)
10786                popstring();
10787        g_parsefile = pf->prev;
10788        free(pf);
10789        INT_ON;
10790}
10791
10792static void
10793unwindfiles(struct parsefile *stop)
10794{
10795        while (g_parsefile != stop)
10796                popfile();
10797}
10798
10799/*
10800 * Return to top level.
10801 */
10802static void
10803popallfiles(void)
10804{
10805        unwindfiles(&basepf);
10806}
10807
10808/*
10809 * Close the file(s) that the shell is reading commands from.  Called
10810 * after a fork is done.
10811 */
10812static void
10813closescript(void)
10814{
10815        popallfiles();
10816        if (g_parsefile->pf_fd > 0) {
10817                close(g_parsefile->pf_fd);
10818                g_parsefile->pf_fd = 0;
10819        }
10820}
10821
10822/*
10823 * Like setinputfile, but takes an open file descriptor.  Call this with
10824 * interrupts off.
10825 */
10826static void
10827setinputfd(int fd, int push)
10828{
10829        if (push) {
10830                pushfile();
10831                g_parsefile->buf = NULL;
10832        }
10833        g_parsefile->pf_fd = fd;
10834        if (g_parsefile->buf == NULL)
10835                g_parsefile->buf = ckmalloc(IBUFSIZ);
10836        g_parsefile->left_in_buffer = 0;
10837        g_parsefile->left_in_line = 0;
10838        g_parsefile->linno = 1;
10839}
10840
10841/*
10842 * Set the input to take input from a file.  If push is set, push the
10843 * old input onto the stack first.
10844 */
10845static int
10846setinputfile(const char *fname, int flags)
10847{
10848        int fd;
10849
10850        INT_OFF;
10851        fd = open(fname, O_RDONLY | O_CLOEXEC);
10852        if (fd < 0) {
10853                if (flags & INPUT_NOFILE_OK)
10854                        goto out;
10855                exitstatus = 127;
10856                ash_msg_and_raise_perror("can't open '%s'", fname);
10857        }
10858        if (fd < 10)
10859                fd = savefd(fd);
10860        else if (O_CLOEXEC == 0) /* old libc */
10861                close_on_exec_on(fd);
10862
10863        setinputfd(fd, flags & INPUT_PUSH_FILE);
10864 out:
10865        INT_ON;
10866        return fd;
10867}
10868
10869/*
10870 * Like setinputfile, but takes input from a string.
10871 */
10872static void
10873setinputstring(char *string)
10874{
10875        INT_OFF;
10876        pushfile();
10877        g_parsefile->next_to_pgetc = string;
10878        g_parsefile->left_in_line = strlen(string);
10879        g_parsefile->buf = NULL;
10880        g_parsefile->linno = 1;
10881        INT_ON;
10882}
10883
10884
10885/*
10886 * Routines to check for mail.
10887 */
10888
10889#if ENABLE_ASH_MAIL
10890
10891/* Hash of mtimes of mailboxes */
10892static unsigned mailtime_hash;
10893/* Set if MAIL or MAILPATH is changed. */
10894static smallint mail_var_path_changed;
10895
10896/*
10897 * Print appropriate message(s) if mail has arrived.
10898 * If mail_var_path_changed is set,
10899 * then the value of MAIL has mail_var_path_changed,
10900 * so we just update the values.
10901 */
10902static void
10903chkmail(void)
10904{
10905        const char *mpath;
10906        char *p;
10907        char *q;
10908        unsigned new_hash;
10909        struct stackmark smark;
10910        struct stat statb;
10911
10912        setstackmark(&smark);
10913        mpath = mpathset() ? mpathval() : mailval();
10914        new_hash = 0;
10915        for (;;) {
10916                p = path_advance(&mpath, nullstr);
10917                if (p == NULL)
10918                        break;
10919                if (*p == '\0')
10920                        continue;
10921                for (q = p; *q; q++)
10922                        continue;
10923#if DEBUG
10924                if (q[-1] != '/')
10925                        abort();
10926#endif
10927                q[-1] = '\0';                   /* delete trailing '/' */
10928                if (stat(p, &statb) < 0) {
10929                        continue;
10930                }
10931                /* Very simplistic "hash": just a sum of all mtimes */
10932                new_hash += (unsigned)statb.st_mtime;
10933        }
10934        if (!mail_var_path_changed && mailtime_hash != new_hash) {
10935                if (mailtime_hash != 0)
10936                        out2str("you have mail\n");
10937                mailtime_hash = new_hash;
10938        }
10939        mail_var_path_changed = 0;
10940        popstackmark(&smark);
10941}
10942
10943static void FAST_FUNC
10944changemail(const char *val UNUSED_PARAM)
10945{
10946        mail_var_path_changed = 1;
10947}
10948
10949#endif /* ASH_MAIL */
10950
10951
10952/* ============ ??? */
10953
10954/*
10955 * Set the shell parameters.
10956 */
10957static void
10958setparam(char **argv)
10959{
10960        char **newparam;
10961        char **ap;
10962        int nparam;
10963
10964        for (nparam = 0; argv[nparam]; nparam++)
10965                continue;
10966        ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10967        while (*argv) {
10968                *ap++ = ckstrdup(*argv++);
10969        }
10970        *ap = NULL;
10971        freeparam(&shellparam);
10972        shellparam.malloced = 1;
10973        shellparam.nparam = nparam;
10974        shellparam.p = newparam;
10975#if ENABLE_ASH_GETOPTS
10976        shellparam.optind = 1;
10977        shellparam.optoff = -1;
10978#endif
10979}
10980
10981/*
10982 * Process shell options.  The global variable argptr contains a pointer
10983 * to the argument list; we advance it past the options.
10984 *
10985 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10986 * For a non-interactive shell, an error condition encountered
10987 * by a special built-in ... shall cause the shell to write a diagnostic message
10988 * to standard error and exit as shown in the following table:
10989 * Error                                           Special Built-In
10990 * ...
10991 * Utility syntax error (option or operand error)  Shall exit
10992 * ...
10993 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10994 * we see that bash does not do that (set "finishes" with error code 1 instead,
10995 * and shell continues), and people rely on this behavior!
10996 * Testcase:
10997 * set -o barfoo 2>/dev/null
10998 * echo $?
10999 *
11000 * Oh well. Let's mimic that.
11001 */
11002static int
11003plus_minus_o(char *name, int val)
11004{
11005        int i;
11006
11007        if (name) {
11008                for (i = 0; i < NOPTS; i++) {
11009                        if (strcmp(name, optnames(i)) == 0) {
11010                                optlist[i] = val;
11011                                return 0;
11012                        }
11013                }
11014                ash_msg("illegal option %co %s", val ? '-' : '+', name);
11015                return 1;
11016        }
11017        for (i = 0; i < NOPTS; i++) {
11018                if (val) {
11019                        out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11020                } else {
11021                        out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11022                }
11023        }
11024        return 0;
11025}
11026static void
11027setoption(int flag, int val)
11028{
11029        int i;
11030
11031        for (i = 0; i < NOPTS; i++) {
11032                if (optletters(i) == flag) {
11033                        optlist[i] = val;
11034                        return;
11035                }
11036        }
11037        ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
11038        /* NOTREACHED */
11039}
11040static int
11041options(int cmdline, int *login_sh)
11042{
11043        char *p;
11044        int val;
11045        int c;
11046
11047        if (cmdline)
11048                minusc = NULL;
11049        while ((p = *argptr) != NULL) {
11050                c = *p++;
11051                if (c != '-' && c != '+')
11052                        break;
11053                argptr++;
11054                val = 0; /* val = 0 if c == '+' */
11055                if (c == '-') {
11056                        val = 1;
11057                        if (p[0] == '\0' || LONE_DASH(p)) {
11058                                if (!cmdline) {
11059                                        /* "-" means turn off -x and -v */
11060                                        if (p[0] == '\0')
11061                                                xflag = vflag = 0;
11062                                        /* "--" means reset params */
11063                                        else if (*argptr == NULL)
11064                                                setparam(argptr);
11065                                }
11066                                break;    /* "-" or "--" terminates options */
11067                        }
11068                }
11069                /* first char was + or - */
11070                while ((c = *p++) != '\0') {
11071                        /* bash 3.2 indeed handles -c CMD and +c CMD the same */
11072                        if (c == 'c' && cmdline) {
11073                                minusc = p;     /* command is after shell args */
11074                        } else if (c == 'o') {
11075                                if (plus_minus_o(*argptr, val)) {
11076                                        /* it already printed err message */
11077                                        return 1; /* error */
11078                                }
11079                                if (*argptr)
11080                                        argptr++;
11081                        } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
11082                                if (login_sh)
11083                                        *login_sh = 1;
11084                        /* bash does not accept +-login, we also won't */
11085                        } else if (cmdline && val && (c == '-')) { /* long options */
11086                                if (strcmp(p, "login") == 0) {
11087                                        if (login_sh)
11088                                                *login_sh = 1;
11089                                }
11090                                break;
11091                        } else {
11092                                setoption(c, val);
11093                        }
11094                }
11095        }
11096        return 0;
11097}
11098
11099/*
11100 * The shift builtin command.
11101 */
11102static int FAST_FUNC
11103shiftcmd(int argc UNUSED_PARAM, char **argv)
11104{
11105        int n;
11106        char **ap1, **ap2;
11107
11108        n = 1;
11109        if (argv[1])
11110                n = number(argv[1]);
11111        if (n > shellparam.nparam)
11112                return 1;
11113        INT_OFF;
11114        shellparam.nparam -= n;
11115        for (ap1 = shellparam.p; --n >= 0; ap1++) {
11116                if (shellparam.malloced)
11117                        free(*ap1);
11118        }
11119        ap2 = shellparam.p;
11120        while ((*ap2++ = *ap1++) != NULL)
11121                continue;
11122#if ENABLE_ASH_GETOPTS
11123        shellparam.optind = 1;
11124        shellparam.optoff = -1;
11125#endif
11126        INT_ON;
11127        return 0;
11128}
11129
11130/*
11131 * POSIX requires that 'set' (but not export or readonly) output the
11132 * variables in lexicographic order - by the locale's collating order (sigh).
11133 * Maybe we could keep them in an ordered balanced binary tree
11134 * instead of hashed lists.
11135 * For now just roll 'em through qsort for printing...
11136 */
11137static int
11138showvars(const char *sep_prefix, int on, int off)
11139{
11140        const char *sep;
11141        char **ep, **epend;
11142
11143        ep = listvars(on, off, /*strlist:*/ NULL, &epend);
11144        qsort(ep, epend - ep, sizeof(char *), vpcmp);
11145
11146        sep = *sep_prefix ? " " : sep_prefix;
11147
11148        for (; ep < epend; ep++) {
11149                const char *p;
11150                const char *q;
11151
11152                p = endofname(*ep);
11153/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11154 * makes "export -p" to have output not suitable for "eval":
11155 * import os
11156 * os.environ["test-test"]="test"
11157 * if os.fork() == 0:
11158 *   os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ])  # fixes this
11159 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11160 */
11161                q = nullstr;
11162                if (*p == '=')
11163                        q = single_quote(++p);
11164                out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11165        }
11166        return 0;
11167}
11168
11169/*
11170 * The set command builtin.
11171 */
11172static int FAST_FUNC
11173setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11174{
11175        int retval;
11176
11177        if (!argv[1])
11178                return showvars(nullstr, 0, VUNSET);
11179
11180        INT_OFF;
11181        retval = options(/*cmdline:*/ 0, NULL);
11182        if (retval == 0) { /* if no parse error... */
11183                optschanged();
11184                if (*argptr != NULL) {
11185                        setparam(argptr);
11186                }
11187        }
11188        INT_ON;
11189        return retval;
11190}
11191
11192#if ENABLE_ASH_RANDOM_SUPPORT
11193static void FAST_FUNC
11194change_random(const char *value)
11195{
11196        uint32_t t;
11197
11198        if (value == NULL) {
11199                /* "get", generate */
11200                t = next_random(&random_gen);
11201                /* set without recursion */
11202                setvar(vrandom.var_text, utoa(t), VNOFUNC);
11203                vrandom.flags &= ~VNOFUNC;
11204        } else {
11205                /* set/reset */
11206                t = strtoul(value, NULL, 10);
11207                INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
11208        }
11209}
11210#endif
11211
11212#if ENABLE_ASH_GETOPTS
11213static int
11214getopts(char *optstr, char *optvar, char **optfirst)
11215{
11216        char *p, *q;
11217        char c = '?';
11218        int done = 0;
11219        char sbuf[2];
11220        char **optnext;
11221        int ind = shellparam.optind;
11222        int off = shellparam.optoff;
11223
11224        sbuf[1] = '\0';
11225
11226        shellparam.optind = -1;
11227        optnext = optfirst + ind - 1;
11228
11229        if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
11230                p = NULL;
11231        else
11232                p = optnext[-1] + off;
11233        if (p == NULL || *p == '\0') {
11234                /* Current word is done, advance */
11235                p = *optnext;
11236                if (p == NULL || *p != '-' || *++p == '\0') {
11237 atend:
11238                        unsetvar("OPTARG");
11239                        p = NULL;
11240                        done = 1;
11241                        goto out;
11242                }
11243                optnext++;
11244                if (LONE_DASH(p))        /* check for "--" */
11245                        goto atend;
11246        }
11247
11248        c = *p++;
11249        for (q = optstr; *q != c;) {
11250                if (*q == '\0') {
11251                        /* OPTERR is a bashism */
11252                        const char *cp = lookupvar("OPTERR");
11253                        if ((cp && LONE_CHAR(cp, '0'))
11254                         || (optstr[0] == ':')
11255                        ) {
11256                                sbuf[0] = c;
11257                                /*sbuf[1] = '\0'; - already is */
11258                                setvar0("OPTARG", sbuf);
11259                        } else {
11260                                fprintf(stderr, "Illegal option -%c\n", c);
11261                                unsetvar("OPTARG");
11262                        }
11263                        c = '?';
11264                        goto out;
11265                }
11266                if (*++q == ':')
11267                        q++;
11268        }
11269
11270        if (*++q == ':') {
11271                if (*p == '\0' && (p = *optnext) == NULL) {
11272                        /* OPTERR is a bashism */
11273                        const char *cp = lookupvar("OPTERR");
11274                        if ((cp && LONE_CHAR(cp, '0'))
11275                         || (optstr[0] == ':')
11276                        ) {
11277                                sbuf[0] = c;
11278                                /*sbuf[1] = '\0'; - already is */
11279                                setvar0("OPTARG", sbuf);
11280                                c = ':';
11281                        } else {
11282                                fprintf(stderr, "No arg for -%c option\n", c);
11283                                unsetvar("OPTARG");
11284                                c = '?';
11285                        }
11286                        goto out;
11287                }
11288
11289                if (p == *optnext)
11290                        optnext++;
11291                setvar0("OPTARG", p);
11292                p = NULL;
11293        } else
11294                setvar0("OPTARG", nullstr);
11295 out:
11296        ind = optnext - optfirst + 1;
11297        setvar("OPTIND", itoa(ind), VNOFUNC);
11298        sbuf[0] = c;
11299        /*sbuf[1] = '\0'; - already is */
11300        setvar0(optvar, sbuf);
11301
11302        shellparam.optoff = p ? p - *(optnext - 1) : -1;
11303        shellparam.optind = ind;
11304
11305        return done;
11306}
11307
11308/*
11309 * The getopts builtin.  Shellparam.optnext points to the next argument
11310 * to be processed.  Shellparam.optptr points to the next character to
11311 * be processed in the current argument.  If shellparam.optnext is NULL,
11312 * then it's the first time getopts has been called.
11313 */
11314static int FAST_FUNC
11315getoptscmd(int argc, char **argv)
11316{
11317        char **optbase;
11318
11319        if (argc < 3)
11320                ash_msg_and_raise_error("usage: getopts optstring var [arg]");
11321        if (argc == 3) {
11322                optbase = shellparam.p;
11323                if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
11324                        shellparam.optind = 1;
11325                        shellparam.optoff = -1;
11326                }
11327        } else {
11328                optbase = &argv[3];
11329                if ((unsigned)shellparam.optind > argc - 2) {
11330                        shellparam.optind = 1;
11331                        shellparam.optoff = -1;
11332                }
11333        }
11334
11335        return getopts(argv[1], argv[2], optbase);
11336}
11337#endif /* ASH_GETOPTS */
11338
11339
11340/* ============ Shell parser */
11341
11342struct heredoc {
11343        struct heredoc *next;   /* next here document in list */
11344        union node *here;       /* redirection node */
11345        char *eofmark;          /* string indicating end of input */
11346        smallint striptabs;     /* if set, strip leading tabs */
11347};
11348
11349static smallint tokpushback;           /* last token pushed back */
11350static smallint quoteflag;             /* set if (part of) last token was quoted */
11351static token_id_t lasttoken;           /* last token read (integer id Txxx) */
11352static struct heredoc *heredoclist;    /* list of here documents to read */
11353static char *wordtext;                 /* text of last word returned by readtoken */
11354static struct nodelist *backquotelist;
11355static union node *redirnode;
11356static struct heredoc *heredoc;
11357
11358static const char *
11359tokname(char *buf, int tok)
11360{
11361        if (tok < TSEMI)
11362                return tokname_array[tok];
11363        sprintf(buf, "\"%s\"", tokname_array[tok]);
11364        return buf;
11365}
11366
11367/* raise_error_unexpected_syntax:
11368 * Called when an unexpected token is read during the parse.  The argument
11369 * is the token that is expected, or -1 if more than one type of token can
11370 * occur at this point.
11371 */
11372static void raise_error_unexpected_syntax(int) NORETURN;
11373static void
11374raise_error_unexpected_syntax(int token)
11375{
11376        char msg[64];
11377        char buf[16];
11378        int l;
11379
11380        l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
11381        if (token >= 0)
11382                sprintf(msg + l, " (expecting %s)", tokname(buf, token));
11383        raise_error_syntax(msg);
11384        /* NOTREACHED */
11385}
11386
11387/* parsing is heavily cross-recursive, need these forward decls */
11388static union node *andor(void);
11389static union node *pipeline(void);
11390static union node *parse_command(void);
11391static void parseheredoc(void);
11392static int peektoken(void);
11393static int readtoken(void);
11394
11395static union node *
11396list(int nlflag)
11397{
11398        union node *n1, *n2, *n3;
11399        int tok;
11400
11401        n1 = NULL;
11402        for (;;) {
11403                switch (peektoken()) {
11404                case TNL:
11405                        if (!(nlflag & 1))
11406                                break;
11407                        parseheredoc();
11408                        return n1;
11409
11410                case TEOF:
11411                        if (!n1 && (nlflag & 1))
11412                                n1 = NODE_EOF;
11413                        parseheredoc();
11414                        return n1;
11415                }
11416
11417                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11418                if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
11419                        return n1;
11420                nlflag |= 2;
11421
11422                n2 = andor();
11423                tok = readtoken();
11424                if (tok == TBACKGND) {
11425                        if (n2->type == NPIPE) {
11426                                n2->npipe.pipe_backgnd = 1;
11427                        } else {
11428                                if (n2->type != NREDIR) {
11429                                        n3 = stzalloc(sizeof(struct nredir));
11430                                        n3->nredir.n = n2;
11431                                        /*n3->nredir.redirect = NULL; - stzalloc did it */
11432                                        n2 = n3;
11433                                }
11434                                n2->type = NBACKGND;
11435                        }
11436                }
11437                if (n1 == NULL) {
11438                        n1 = n2;
11439                } else {
11440                        n3 = stzalloc(sizeof(struct nbinary));
11441                        n3->type = NSEMI;
11442                        n3->nbinary.ch1 = n1;
11443                        n3->nbinary.ch2 = n2;
11444                        n1 = n3;
11445                }
11446                switch (tok) {
11447                case TNL:
11448                case TEOF:
11449                        tokpushback = 1;
11450                        /* fall through */
11451                case TBACKGND:
11452                case TSEMI:
11453                        break;
11454                default:
11455                        if ((nlflag & 1))
11456                                raise_error_unexpected_syntax(-1);
11457                        tokpushback = 1;
11458                        return n1;
11459                }
11460        }
11461}
11462
11463static union node *
11464andor(void)
11465{
11466        union node *n1, *n2, *n3;
11467        int t;
11468
11469        n1 = pipeline();
11470        for (;;) {
11471                t = readtoken();
11472                if (t == TAND) {
11473                        t = NAND;
11474                } else if (t == TOR) {
11475                        t = NOR;
11476                } else {
11477                        tokpushback = 1;
11478                        return n1;
11479                }
11480                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11481                n2 = pipeline();
11482                n3 = stzalloc(sizeof(struct nbinary));
11483                n3->type = t;
11484                n3->nbinary.ch1 = n1;
11485                n3->nbinary.ch2 = n2;
11486                n1 = n3;
11487        }
11488}
11489
11490static union node *
11491pipeline(void)
11492{
11493        union node *n1, *n2, *pipenode;
11494        struct nodelist *lp, *prev;
11495        int negate;
11496
11497        negate = 0;
11498        TRACE(("pipeline: entered\n"));
11499        if (readtoken() == TNOT) {
11500                negate = !negate;
11501                checkkwd = CHKKWD | CHKALIAS;
11502        } else
11503                tokpushback = 1;
11504        n1 = parse_command();
11505        if (readtoken() == TPIPE) {
11506                pipenode = stzalloc(sizeof(struct npipe));
11507                pipenode->type = NPIPE;
11508                /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
11509                lp = stzalloc(sizeof(struct nodelist));
11510                pipenode->npipe.cmdlist = lp;
11511                lp->n = n1;
11512                do {
11513                        prev = lp;
11514                        lp = stzalloc(sizeof(struct nodelist));
11515                        checkkwd = CHKNL | CHKKWD | CHKALIAS;
11516                        lp->n = parse_command();
11517                        prev->next = lp;
11518                } while (readtoken() == TPIPE);
11519                lp->next = NULL;
11520                n1 = pipenode;
11521        }
11522        tokpushback = 1;
11523        if (negate) {
11524                n2 = stzalloc(sizeof(struct nnot));
11525                n2->type = NNOT;
11526                n2->nnot.com = n1;
11527                return n2;
11528        }
11529        return n1;
11530}
11531
11532static union node *
11533makename(void)
11534{
11535        union node *n;
11536
11537        n = stzalloc(sizeof(struct narg));
11538        n->type = NARG;
11539        /*n->narg.next = NULL; - stzalloc did it */
11540        n->narg.text = wordtext;
11541        n->narg.backquote = backquotelist;
11542        return n;
11543}
11544
11545static void
11546fixredir(union node *n, const char *text, int err)
11547{
11548        int fd;
11549
11550        TRACE(("Fix redir %s %d\n", text, err));
11551        if (!err)
11552                n->ndup.vname = NULL;
11553
11554        fd = bb_strtou(text, NULL, 10);
11555        if (!errno && fd >= 0)
11556                n->ndup.dupfd = fd;
11557        else if (LONE_DASH(text))
11558                n->ndup.dupfd = -1;
11559        else {
11560                if (err)
11561                        raise_error_syntax("bad fd number");
11562                n->ndup.vname = makename();
11563        }
11564}
11565
11566static void
11567parsefname(void)
11568{
11569        union node *n = redirnode;
11570
11571        if (n->type == NHERE)
11572                checkkwd = CHKEOFMARK;
11573        if (readtoken() != TWORD)
11574                raise_error_unexpected_syntax(-1);
11575        if (n->type == NHERE) {
11576                struct heredoc *here = heredoc;
11577                struct heredoc *p;
11578
11579                if (quoteflag == 0)
11580                        n->type = NXHERE;
11581                TRACE(("Here document %d\n", n->type));
11582                rmescapes(wordtext, 0, NULL);
11583                here->eofmark = wordtext;
11584                here->next = NULL;
11585                if (heredoclist == NULL)
11586                        heredoclist = here;
11587                else {
11588                        for (p = heredoclist; p->next; p = p->next)
11589                                continue;
11590                        p->next = here;
11591                }
11592        } else if (n->type == NTOFD || n->type == NFROMFD) {
11593                fixredir(n, wordtext, 0);
11594        } else {
11595                n->nfile.fname = makename();
11596        }
11597}
11598
11599static union node *
11600simplecmd(void)
11601{
11602        union node *args, **app;
11603        union node *n = NULL;
11604        union node *vars, **vpp;
11605        union node **rpp, *redir;
11606        int savecheckkwd;
11607        int savelinno;
11608#if BASH_TEST2
11609        smallint double_brackets_flag = 0;
11610#endif
11611        IF_BASH_FUNCTION(smallint function_flag = 0;)
11612
11613        args = NULL;
11614        app = &args;
11615        vars = NULL;
11616        vpp = &vars;
11617        redir = NULL;
11618        rpp = &redir;
11619
11620        savecheckkwd = CHKALIAS;
11621        savelinno = g_parsefile->linno;
11622        for (;;) {
11623                int t;
11624                checkkwd = savecheckkwd;
11625                t = readtoken();
11626                switch (t) {
11627#if BASH_FUNCTION
11628                case TFUNCTION:
11629                        if (peektoken() != TWORD)
11630                                raise_error_unexpected_syntax(TWORD);
11631                        function_flag = 1;
11632                        break;
11633#endif
11634#if BASH_TEST2
11635                case TAND: /* "&&" */
11636                case TOR: /* "||" */
11637                        if (!double_brackets_flag) {
11638                                tokpushback = 1;
11639                                goto out;
11640                        }
11641                        wordtext = (char *) (t == TAND ? "-a" : "-o");
11642#endif
11643                case TWORD:
11644                        n = stzalloc(sizeof(struct narg));
11645                        n->type = NARG;
11646                        /*n->narg.next = NULL; - stzalloc did it */
11647                        n->narg.text = wordtext;
11648#if BASH_TEST2
11649                        if (strcmp("[[", wordtext) == 0)
11650                                double_brackets_flag = 1;
11651                        else if (strcmp("]]", wordtext) == 0)
11652                                double_brackets_flag = 0;
11653#endif
11654                        n->narg.backquote = backquotelist;
11655                        if (savecheckkwd && isassignment(wordtext)) {
11656                                *vpp = n;
11657                                vpp = &n->narg.next;
11658                        } else {
11659                                *app = n;
11660                                app = &n->narg.next;
11661                                savecheckkwd = 0;
11662                        }
11663#if BASH_FUNCTION
11664                        if (function_flag) {
11665                                checkkwd = CHKNL | CHKKWD;
11666                                switch (peektoken()) {
11667                                case TBEGIN:
11668                                case TIF:
11669                                case TCASE:
11670                                case TUNTIL:
11671                                case TWHILE:
11672                                case TFOR:
11673                                        goto do_func;
11674                                case TLP:
11675                                        function_flag = 0;
11676                                        break;
11677# if BASH_TEST2
11678                                case TWORD:
11679                                        if (strcmp("[[", wordtext) == 0)
11680                                                goto do_func;
11681                                        /* fall through */
11682# endif
11683                                default:
11684                                        raise_error_unexpected_syntax(-1);
11685                                }
11686                        }
11687#endif
11688                        break;
11689                case TREDIR:
11690                        *rpp = n = redirnode;
11691                        rpp = &n->nfile.next;
11692                        parsefname();   /* read name of redirection file */
11693                        break;
11694                case TLP:
11695 IF_BASH_FUNCTION(do_func:)
11696                        if (args && app == &args->narg.next
11697                         && !vars && !redir
11698                        ) {
11699                                struct builtincmd *bcmd;
11700                                const char *name;
11701
11702                                /* We have a function */
11703                                if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
11704                                        raise_error_unexpected_syntax(TRP);
11705                                name = n->narg.text;
11706                                if (!goodname(name)
11707                                 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11708                                ) {
11709                                        raise_error_syntax("bad function name");
11710                                }
11711                                n->type = NDEFUN;
11712                                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11713                                n->ndefun.text = n->narg.text;
11714                                n->ndefun.linno = g_parsefile->linno;
11715                                n->ndefun.body = parse_command();
11716                                return n;
11717                        }
11718                        IF_BASH_FUNCTION(function_flag = 0;)
11719                        /* fall through */
11720                default:
11721                        tokpushback = 1;
11722                        goto out;
11723                }
11724        }
11725 out:
11726        *app = NULL;
11727        *vpp = NULL;
11728        *rpp = NULL;
11729        n = stzalloc(sizeof(struct ncmd));
11730        if (NCMD != 0)
11731                n->type = NCMD;
11732        n->ncmd.linno = savelinno;
11733        n->ncmd.args = args;
11734        n->ncmd.assign = vars;
11735        n->ncmd.redirect = redir;
11736        return n;
11737}
11738
11739static union node *
11740parse_command(void)
11741{
11742        union node *n1, *n2;
11743        union node *ap, **app;
11744        union node *cp, **cpp;
11745        union node *redir, **rpp;
11746        union node **rpp2;
11747        int t;
11748        int savelinno;
11749
11750        redir = NULL;
11751        rpp2 = &redir;
11752
11753        savelinno = g_parsefile->linno;
11754
11755        switch (readtoken()) {
11756        default:
11757                raise_error_unexpected_syntax(-1);
11758                /* NOTREACHED */
11759        case TIF:
11760                n1 = stzalloc(sizeof(struct nif));
11761                n1->type = NIF;
11762                n1->nif.test = list(0);
11763                if (readtoken() != TTHEN)
11764                        raise_error_unexpected_syntax(TTHEN);
11765                n1->nif.ifpart = list(0);
11766                n2 = n1;
11767                while (readtoken() == TELIF) {
11768                        n2->nif.elsepart = stzalloc(sizeof(struct nif));
11769                        n2 = n2->nif.elsepart;
11770                        n2->type = NIF;
11771                        n2->nif.test = list(0);
11772                        if (readtoken() != TTHEN)
11773                                raise_error_unexpected_syntax(TTHEN);
11774                        n2->nif.ifpart = list(0);
11775                }
11776                if (lasttoken == TELSE)
11777                        n2->nif.elsepart = list(0);
11778                else {
11779                        n2->nif.elsepart = NULL;
11780                        tokpushback = 1;
11781                }
11782                t = TFI;
11783                break;
11784        case TWHILE:
11785        case TUNTIL: {
11786                int got;
11787                n1 = stzalloc(sizeof(struct nbinary));
11788                n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
11789                n1->nbinary.ch1 = list(0);
11790                got = readtoken();
11791                if (got != TDO) {
11792                        TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
11793                                        got == TWORD ? wordtext : ""));
11794                        raise_error_unexpected_syntax(TDO);
11795                }
11796                n1->nbinary.ch2 = list(0);
11797                t = TDONE;
11798                break;
11799        }
11800        case TFOR:
11801                if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
11802                        raise_error_syntax("bad for loop variable");
11803                n1 = stzalloc(sizeof(struct nfor));
11804                n1->type = NFOR;
11805                n1->nfor.linno = savelinno;
11806                n1->nfor.var = wordtext;
11807                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11808                if (readtoken() == TIN) {
11809                        app = &ap;
11810                        while (readtoken() == TWORD) {
11811                                n2 = stzalloc(sizeof(struct narg));
11812                                n2->type = NARG;
11813                                /*n2->narg.next = NULL; - stzalloc did it */
11814                                n2->narg.text = wordtext;
11815                                n2->narg.backquote = backquotelist;
11816                                *app = n2;
11817                                app = &n2->narg.next;
11818                        }
11819                        *app = NULL;
11820                        n1->nfor.args = ap;
11821                        if (lasttoken != TNL && lasttoken != TSEMI)
11822                                raise_error_unexpected_syntax(-1);
11823                } else {
11824                        n2 = stzalloc(sizeof(struct narg));
11825                        n2->type = NARG;
11826                        /*n2->narg.next = NULL; - stzalloc did it */
11827                        n2->narg.text = (char *)dolatstr;
11828                        /*n2->narg.backquote = NULL;*/
11829                        n1->nfor.args = n2;
11830                        /*
11831                         * Newline or semicolon here is optional (but note
11832                         * that the original Bourne shell only allowed NL).
11833                         */
11834                        if (lasttoken != TSEMI)
11835                                tokpushback = 1;
11836                }
11837                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11838                if (readtoken() != TDO)
11839                        raise_error_unexpected_syntax(TDO);
11840                n1->nfor.body = list(0);
11841                t = TDONE;
11842                break;
11843        case TCASE:
11844                n1 = stzalloc(sizeof(struct ncase));
11845                n1->type = NCASE;
11846                n1->ncase.linno = savelinno;
11847                if (readtoken() != TWORD)
11848                        raise_error_unexpected_syntax(TWORD);
11849                n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
11850                n2->type = NARG;
11851                /*n2->narg.next = NULL; - stzalloc did it */
11852                n2->narg.text = wordtext;
11853                n2->narg.backquote = backquotelist;
11854                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11855                if (readtoken() != TIN)
11856                        raise_error_unexpected_syntax(TIN);
11857                cpp = &n1->ncase.cases;
11858 next_case:
11859                checkkwd = CHKNL | CHKKWD;
11860                t = readtoken();
11861                while (t != TESAC) {
11862                        if (lasttoken == TLP)
11863                                readtoken();
11864                        *cpp = cp = stzalloc(sizeof(struct nclist));
11865                        cp->type = NCLIST;
11866                        app = &cp->nclist.pattern;
11867                        for (;;) {
11868                                *app = ap = stzalloc(sizeof(struct narg));
11869                                ap->type = NARG;
11870                                /*ap->narg.next = NULL; - stzalloc did it */
11871                                ap->narg.text = wordtext;
11872                                ap->narg.backquote = backquotelist;
11873                                if (readtoken() != TPIPE)
11874                                        break;
11875                                app = &ap->narg.next;
11876                                readtoken();
11877                        }
11878                        //ap->narg.next = NULL;
11879                        if (lasttoken != TRP)
11880                                raise_error_unexpected_syntax(TRP);
11881                        cp->nclist.body = list(2);
11882
11883                        cpp = &cp->nclist.next;
11884
11885                        checkkwd = CHKNL | CHKKWD;
11886                        t = readtoken();
11887                        if (t != TESAC) {
11888                                if (t != TENDCASE)
11889                                        raise_error_unexpected_syntax(TENDCASE);
11890                                goto next_case;
11891                        }
11892                }
11893                *cpp = NULL;
11894                goto redir;
11895        case TLP:
11896                n1 = stzalloc(sizeof(struct nredir));
11897                n1->type = NSUBSHELL;
11898                n1->nredir.linno = savelinno;
11899                n1->nredir.n = list(0);
11900                /*n1->nredir.redirect = NULL; - stzalloc did it */
11901                t = TRP;
11902                break;
11903        case TBEGIN:
11904                n1 = list(0);
11905                t = TEND;
11906                break;
11907        IF_BASH_FUNCTION(case TFUNCTION:)
11908        case TWORD:
11909        case TREDIR:
11910                tokpushback = 1;
11911                return simplecmd();
11912        }
11913
11914        if (readtoken() != t)
11915                raise_error_unexpected_syntax(t);
11916
11917 redir:
11918        /* Now check for redirection which may follow command */
11919        checkkwd = CHKKWD | CHKALIAS;
11920        rpp = rpp2;
11921        while (readtoken() == TREDIR) {
11922                *rpp = n2 = redirnode;
11923                rpp = &n2->nfile.next;
11924                parsefname();
11925        }
11926        tokpushback = 1;
11927        *rpp = NULL;
11928        if (redir) {
11929                if (n1->type != NSUBSHELL) {
11930                        n2 = stzalloc(sizeof(struct nredir));
11931                        n2->type = NREDIR;
11932                        n2->nredir.linno = savelinno;
11933                        n2->nredir.n = n1;
11934                        n1 = n2;
11935                }
11936                n1->nredir.redirect = redir;
11937        }
11938        return n1;
11939}
11940
11941#if BASH_DOLLAR_SQUOTE
11942static int
11943decode_dollar_squote(void)
11944{
11945        static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11946        int c, cnt;
11947        char *p;
11948        char buf[4];
11949
11950        c = pgetc();
11951        p = strchr(C_escapes, c);
11952        if (p) {
11953                buf[0] = c;
11954                p = buf;
11955                cnt = 3;
11956                if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11957                        do {
11958                                c = pgetc();
11959                                *++p = c;
11960                        } while ((unsigned char)(c - '0') <= 7 && --cnt);
11961                        pungetc();
11962                } else if (c == 'x') { /* \xHH */
11963                        do {
11964                                c = pgetc();
11965                                *++p = c;
11966                        } while (isxdigit(c) && --cnt);
11967                        pungetc();
11968                        if (cnt == 3) { /* \x but next char is "bad" */
11969                                c = 'x';
11970                                goto unrecognized;
11971                        }
11972                } else { /* simple seq like \\ or \t */
11973                        p++;
11974                }
11975                *p = '\0';
11976                p = buf;
11977                c = bb_process_escape_sequence((void*)&p);
11978        } else { /* unrecognized "\z": print both chars unless ' or " */
11979                if (c != '\'' && c != '"') {
11980 unrecognized:
11981                        c |= 0x100; /* "please encode \, then me" */
11982                }
11983        }
11984        return c;
11985}
11986#endif
11987
11988/* Used by expandstr to get here-doc like behaviour. */
11989#define FAKEEOFMARK ((char*)(uintptr_t)1)
11990
11991static ALWAYS_INLINE int
11992realeofmark(const char *eofmark)
11993{
11994        return eofmark && eofmark != FAKEEOFMARK;
11995}
11996
11997/*
11998 * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
11999 * is not NULL, read a here document.  In the latter case, eofmark is the
12000 * word which marks the end of the document and striptabs is true if
12001 * leading tabs should be stripped from the document.  The argument c
12002 * is the first character of the input token or document.
12003 *
12004 * Because C does not have internal subroutines, I have simulated them
12005 * using goto's to implement the subroutine linkage.  The following macros
12006 * will run code that appears at the end of readtoken1.
12007 */
12008#define CHECKEND()      {goto checkend; checkend_return:;}
12009#define PARSEREDIR()    {goto parseredir; parseredir_return:;}
12010#define PARSESUB()      {goto parsesub; parsesub_return:;}
12011#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
12012#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
12013#define PARSEARITH()    {goto parsearith; parsearith_return:;}
12014static int
12015readtoken1(int c, int syntax, char *eofmark, int striptabs)
12016{
12017        /* NB: syntax parameter fits into smallint */
12018        /* c parameter is an unsigned char or PEOF or PEOA */
12019        char *out;
12020        size_t len;
12021        struct nodelist *bqlist;
12022        smallint quotef;
12023        smallint oldstyle;
12024        smallint pssyntax;   /* we are expanding a prompt string */
12025        IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
12026        /* syntax stack */
12027        struct synstack synbase = { };
12028        struct synstack *synstack = &synbase;
12029
12030#if ENABLE_ASH_EXPAND_PRMT
12031        pssyntax = (syntax == PSSYNTAX);
12032        if (pssyntax)
12033                syntax = DQSYNTAX;
12034#else
12035        pssyntax = 0; /* constant */
12036#endif
12037        synstack->syntax = syntax;
12038
12039        if (syntax == DQSYNTAX)
12040                synstack->dblquote = 1;
12041        quotef = 0;
12042        bqlist = NULL;
12043
12044        STARTSTACKSTR(out);
12045 loop:
12046        /* For each line, until end of word */
12047        CHECKEND();     /* set c to PEOF if at end of here document */
12048        for (;;) {      /* until end of line or end of word */
12049                CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
12050                switch (SIT(c, synstack->syntax)) {
12051                case CNL:       /* '\n' */
12052                        if (synstack->syntax == BASESYNTAX
12053                         && !synstack->varnest
12054                        ) {
12055                                goto endword;   /* exit outer loop */
12056                        }
12057                        USTPUTC(c, out);
12058                        nlprompt();
12059                        c = pgetc();
12060                        goto loop;              /* continue outer loop */
12061                case CWORD:
12062                        USTPUTC(c, out);
12063                        break;
12064                case CCTL:
12065#if BASH_DOLLAR_SQUOTE
12066                        if (c == '\\' && bash_dollar_squote) {
12067                                c = decode_dollar_squote();
12068                                if (c == '\0') {
12069                                        /* skip $'\000', $'\x00' (like bash) */
12070                                        break;
12071                                }
12072                                if (c & 0x100) {
12073                                        /* Unknown escape. Encode as '\z' */
12074                                        c = (unsigned char)c;
12075                                        if (eofmark == NULL || synstack->dblquote)
12076                                                USTPUTC(CTLESC, out);
12077                                        USTPUTC('\\', out);
12078                                }
12079                        }
12080#endif
12081                        if (!eofmark || synstack->dblquote || synstack->varnest)
12082                                USTPUTC(CTLESC, out);
12083                        USTPUTC(c, out);
12084                        break;
12085                case CBACK:     /* backslash */
12086                        c = pgetc_without_PEOA();
12087                        if (c == PEOF) {
12088                                USTPUTC(CTLESC, out);
12089                                USTPUTC('\\', out);
12090                                pungetc();
12091                        } else if (c == '\n') {
12092                                nlprompt();
12093                        } else {
12094                                if (pssyntax && c == '$') {
12095                                        USTPUTC(CTLESC, out);
12096                                        USTPUTC('\\', out);
12097                                }
12098                                /* Backslash is retained if we are in "str"
12099                                 * and next char isn't dquote-special.
12100                                 */
12101                                if (synstack->dblquote
12102                                 && c != '\\'
12103                                 && c != '`'
12104                                 && c != '$'
12105                                 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12106                                 && (c != '}' || !synstack->varnest)
12107                                ) {
12108                                        USTPUTC(CTLESC, out); /* protect '\' from glob */
12109                                        USTPUTC('\\', out);
12110                                }
12111                                USTPUTC(CTLESC, out);
12112                                USTPUTC(c, out);
12113                                quotef = 1;
12114                        }
12115                        break;
12116                case CSQUOTE:
12117                        synstack->syntax = SQSYNTAX;
12118 quotemark:
12119                        if (eofmark == NULL) {
12120                                USTPUTC(CTLQUOTEMARK, out);
12121                        }
12122                        break;
12123                case CDQUOTE:
12124                        synstack->syntax = DQSYNTAX;
12125                        synstack->dblquote = 1;
12126 toggledq:
12127                        if (synstack->varnest)
12128                                synstack->innerdq ^= 1;
12129                        goto quotemark;
12130                case CENDQUOTE:
12131                        IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
12132                        if (eofmark != NULL && synstack->varnest == 0) {
12133                                USTPUTC(c, out);
12134                                break;
12135                        }
12136
12137                        if (synstack->dqvarnest == 0) {
12138                                synstack->syntax = BASESYNTAX;
12139                                synstack->dblquote = 0;
12140                        }
12141
12142                        quotef = 1;
12143
12144                        if (c == '"')
12145                                goto toggledq;
12146
12147                        goto quotemark;
12148                case CVAR:      /* '$' */
12149                        PARSESUB();             /* parse substitution */
12150                        break;
12151                case CENDVAR:   /* '}' */
12152                        if (!synstack->innerdq && synstack->varnest > 0) {
12153                                if (!--synstack->varnest && synstack->varpushed)
12154                                        synstack_pop(&synstack);
12155                                else if (synstack->dqvarnest > 0)
12156                                        synstack->dqvarnest--;
12157                                c = CTLENDVAR;
12158                        }
12159                        USTPUTC(c, out);
12160                        break;
12161#if ENABLE_FEATURE_SH_MATH
12162                case CLP:       /* '(' in arithmetic */
12163                        synstack->parenlevel++;
12164                        USTPUTC(c, out);
12165                        break;
12166                case CRP:       /* ')' in arithmetic */
12167                        if (synstack->parenlevel > 0) {
12168                                synstack->parenlevel--;
12169                        } else {
12170                                if (pgetc_eatbnl() == ')') {
12171                                        c = CTLENDARI;
12172                                        synstack_pop(&synstack);
12173                                } else {
12174                                        /*
12175                                         * unbalanced parens
12176                                         * (don't 2nd guess - no error)
12177                                         */
12178                                        pungetc();
12179                                }
12180                        }
12181                        USTPUTC(c, out);
12182                        break;
12183#endif
12184                case CBQUOTE:   /* '`' */
12185                        if (checkkwd & CHKEOFMARK) {
12186                                quotef = 1;
12187                                USTPUTC('`', out);
12188                                break;
12189                        }
12190
12191                        PARSEBACKQOLD();
12192                        break;
12193                case CENDFILE:
12194                        goto endword;           /* exit outer loop */
12195                case CIGN:
12196                        break;
12197                default:
12198                        if (synstack->varnest == 0) {
12199#if BASH_REDIR_OUTPUT
12200                                if (c == '&') {
12201//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
12202                                        if (pgetc() == '>')
12203                                                c = 0x100 + '>'; /* flag &> */
12204                                        pungetc();
12205                                }
12206#endif
12207                                goto endword;   /* exit outer loop */
12208                        }
12209                        IF_ASH_ALIAS(if (c != PEOA))
12210                                USTPUTC(c, out);
12211                }
12212                c = pgetc();
12213        } /* for (;;) */
12214 endword:
12215
12216#if ENABLE_FEATURE_SH_MATH
12217        if (synstack->syntax == ARISYNTAX)
12218                raise_error_syntax("missing '))'");
12219#endif
12220        if (synstack->syntax != BASESYNTAX && eofmark == NULL)
12221                raise_error_syntax("unterminated quoted string");
12222        if (synstack->varnest != 0) {
12223                /* { */
12224                raise_error_syntax("missing '}'");
12225        }
12226        USTPUTC('\0', out);
12227        len = out - (char *)stackblock();
12228        out = stackblock();
12229        if (eofmark == NULL) {
12230                if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
12231                 && quotef == 0
12232                ) {
12233                        if (isdigit_str9(out)) {
12234                                PARSEREDIR(); /* passed as params: out, c */
12235                                lasttoken = TREDIR;
12236                                return lasttoken;
12237                        }
12238                        /* else: non-number X seen, interpret it
12239                         * as "NNNX>file" = "NNNX >file" */
12240                }
12241                pungetc();
12242        }
12243        quoteflag = quotef;
12244        backquotelist = bqlist;
12245        grabstackblock(len);
12246        wordtext = out;
12247        lasttoken = TWORD;
12248        return lasttoken;
12249/* end of readtoken routine */
12250
12251/*
12252 * Check to see whether we are at the end of the here document.  When this
12253 * is called, c is set to the first character of the next input line.  If
12254 * we are at the end of the here document, this routine sets the c to PEOF.
12255 */
12256checkend: {
12257        if (realeofmark(eofmark)) {
12258                int markloc;
12259                char *p;
12260
12261#if ENABLE_ASH_ALIAS
12262                if (c == PEOA)
12263                        c = pgetc_without_PEOA();
12264#endif
12265                if (striptabs) {
12266                        while (c == '\t') {
12267                                c = pgetc_without_PEOA();
12268                        }
12269                }
12270
12271                markloc = out - (char *)stackblock();
12272                for (p = eofmark; STPUTC(c, out), *p; p++) {
12273                        if (c != *p)
12274                                goto more_heredoc;
12275
12276                        c = pgetc_without_PEOA();
12277                }
12278
12279                if (c == '\n' || c == PEOF) {
12280                        c = PEOF;
12281                        g_parsefile->linno++;
12282                        needprompt = doprompt;
12283                } else {
12284                        int len_here;
12285
12286 more_heredoc:
12287                        p = (char *)stackblock() + markloc + 1;
12288                        len_here = out - p;
12289
12290                        if (len_here) {
12291                                len_here -= (c >= PEOF);
12292                                c = p[-1];
12293
12294                                if (len_here) {
12295                                        char *str;
12296
12297                                        str = alloca(len_here + 1);
12298                                        *(char *)mempcpy(str, p, len_here) = '\0';
12299
12300                                        pushstring(str, NULL);
12301                                }
12302                        }
12303                }
12304
12305                STADJUST((char *)stackblock() + markloc - out, out);
12306        }
12307        goto checkend_return;
12308}
12309
12310/*
12311 * Parse a redirection operator.  The variable "out" points to a string
12312 * specifying the fd to be redirected.  The variable "c" contains the
12313 * first character of the redirection operator.
12314 */
12315parseredir: {
12316        /* out is already checked to be a valid number or "" */
12317        int fd = (*out == '\0' ? -1 : atoi(out));
12318        union node *np;
12319
12320        np = stzalloc(sizeof(struct nfile));
12321        if (c == '>') {
12322                np->nfile.fd = 1;
12323                c = pgetc_eatbnl();
12324                if (c == '>')
12325                        np->type = NAPPEND;
12326                else if (c == '|')
12327                        np->type = NCLOBBER;
12328                else if (c == '&')
12329                        np->type = NTOFD;
12330                        /* it also can be NTO2 (>&file), but we can't figure it out yet */
12331                else {
12332                        np->type = NTO;
12333                        pungetc();
12334                }
12335        }
12336#if BASH_REDIR_OUTPUT
12337        else if (c == 0x100 + '>') { /* this flags &> redirection */
12338                np->nfile.fd = 1;
12339                pgetc(); /* this is '>', no need to check */
12340                np->type = NTO2;
12341        }
12342#endif
12343        else { /* c == '<' */
12344                /*np->nfile.fd = 0; - stzalloc did it */
12345                c = pgetc_eatbnl();
12346                switch (c) {
12347                case '<':
12348                        if (sizeof(struct nfile) != sizeof(struct nhere)) {
12349                                np = stzalloc(sizeof(struct nhere));
12350                                /*np->nfile.fd = 0; - stzalloc did it */
12351                        }
12352                        np->type = NHERE;
12353                        heredoc = stzalloc(sizeof(struct heredoc));
12354                        heredoc->here = np;
12355                        c = pgetc_eatbnl();
12356                        if (c == '-') {
12357                                heredoc->striptabs = 1;
12358                        } else {
12359                                /*heredoc->striptabs = 0; - stzalloc did it */
12360                                pungetc();
12361                        }
12362                        break;
12363
12364                case '&':
12365                        np->type = NFROMFD;
12366                        break;
12367
12368                case '>':
12369                        np->type = NFROMTO;
12370                        break;
12371
12372                default:
12373                        np->type = NFROM;
12374                        pungetc();
12375                        break;
12376                }
12377        }
12378        if (fd >= 0)
12379                np->nfile.fd = fd;
12380        redirnode = np;
12381        goto parseredir_return;
12382}
12383
12384/*
12385 * Parse a substitution.  At this point, we have read the dollar sign
12386 * and nothing else.
12387 */
12388
12389/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12390 * (assuming ascii char codes, as the original implementation did) */
12391#define is_special(c) \
12392        (((unsigned)(c) - 33 < 32) \
12393                        && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
12394parsesub: {
12395        unsigned char subtype;
12396        int typeloc;
12397
12398        c = pgetc_eatbnl();
12399        if ((checkkwd & CHKEOFMARK)
12400         || c > 255 /* PEOA or PEOF */
12401         || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
12402        ) {
12403#if BASH_DOLLAR_SQUOTE
12404                if (synstack->syntax != DQSYNTAX && c == '\'')
12405                        bash_dollar_squote = 1;
12406                else
12407#endif
12408                        USTPUTC('$', out);
12409                pungetc();
12410        } else if (c == '(') {
12411                /* $(command) or $((arith)) */
12412                if (pgetc_eatbnl() == '(') {
12413#if ENABLE_FEATURE_SH_MATH
12414                        PARSEARITH();
12415#else
12416                        raise_error_syntax("support for $((arith)) is disabled");
12417#endif
12418                } else {
12419                        pungetc();
12420                        PARSEBACKQNEW();
12421                }
12422        } else {
12423                /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
12424                smalluint newsyn = synstack->syntax;
12425
12426                USTPUTC(CTLVAR, out);
12427                typeloc = out - (char *)stackblock();
12428                STADJUST(1, out);
12429                subtype = VSNORMAL;
12430                if (c == '{') {
12431                        c = pgetc_eatbnl();
12432                        subtype = 0;
12433                }
12434 varname:
12435                if (is_name(c)) {
12436                        /* $[{[#]]NAME[}] */
12437                        do {
12438                                STPUTC(c, out);
12439                                c = pgetc_eatbnl();
12440                        } while (is_in_name(c));
12441                } else if (isdigit(c)) {
12442                        /* $[{[#]]NUM[}] */
12443                        do {
12444                                STPUTC(c, out);
12445                                c = pgetc_eatbnl();
12446                        } while (isdigit(c));
12447                } else if (c != '}') {
12448                        /* $[{[#]]<specialchar>[}] */
12449                        int cc = c;
12450
12451                        c = pgetc_eatbnl();
12452                        if (!subtype && cc == '#') {
12453                                subtype = VSLENGTH;
12454                                if (c == '_' || isalnum(c))
12455                                        goto varname;
12456                                cc = c;
12457                                c = pgetc_eatbnl();
12458                                if (cc == '}' || c != '}') {
12459                                        pungetc();
12460                                        subtype = 0;
12461                                        c = cc;
12462                                        cc = '#';
12463                                }
12464                        }
12465
12466                        if (!is_special(cc)) {
12467                                if (subtype == VSLENGTH)
12468                                        subtype = 0;
12469                                goto badsub;
12470                        }
12471
12472                        USTPUTC(cc, out);
12473                } else
12474                        goto badsub;
12475
12476                if (c != '}' && subtype == VSLENGTH) {
12477                        /* ${#VAR didn't end with } */
12478                        goto badsub;
12479                }
12480
12481                if (subtype == 0) {
12482                        static const char types[] ALIGN1 = "}-+?=";
12483                        /* ${VAR...} but not $VAR or ${#VAR} */
12484                        /* c == first char after VAR */
12485                        int cc = c;
12486
12487                        switch (c) {
12488                        case ':':
12489                                c = pgetc_eatbnl();
12490#if BASH_SUBSTR
12491                                /* This check is only needed to not misinterpret
12492                                 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12493                                 * constructs.
12494                                 */
12495                                if (!strchr(types, c)) {
12496                                        subtype = VSSUBSTR;
12497                                        pungetc();
12498                                        break; /* "goto badsub" is bigger (!) */
12499                                }
12500#endif
12501                                subtype = VSNUL;
12502                                /*FALLTHROUGH*/
12503                        default: {
12504                                const char *p = strchr(types, c);
12505                                if (p == NULL)
12506                                        break;
12507                                subtype |= p - types + VSNORMAL;
12508                                break;
12509                        }
12510                        case '%':
12511                        case '#':
12512                                subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12513                                c = pgetc_eatbnl();
12514                                if (c == cc)
12515                                        subtype++;
12516                                else
12517                                        pungetc();
12518
12519                                newsyn = BASESYNTAX;
12520                                break;
12521#if BASH_PATTERN_SUBST
12522                        case '/':
12523                                /* ${v/[/]pattern/repl} */
12524//TODO: encode pattern and repl separately.
12525// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12526// are broken (should print "ONE")
12527                                subtype = VSREPLACE;
12528                                newsyn = BASESYNTAX;
12529                                c = pgetc_eatbnl();
12530                                if (c != '/')
12531                                        goto badsub;
12532                                subtype++; /* VSREPLACEALL */
12533                                break;
12534#endif
12535                        }
12536                } else {
12537 badsub:
12538                        pungetc();
12539                }
12540
12541                if (newsyn == ARISYNTAX)
12542                        newsyn = DQSYNTAX;
12543
12544                if ((newsyn != synstack->syntax || synstack->innerdq)
12545                 && subtype != VSNORMAL
12546                ) {
12547                        synstack_push(&synstack,
12548                                synstack->prev ?: alloca(sizeof(*synstack)),
12549                                newsyn);
12550
12551                        synstack->varpushed = 1;
12552                        synstack->dblquote = newsyn != BASESYNTAX;
12553                }
12554
12555                ((unsigned char *)stackblock())[typeloc] = subtype;
12556                if (subtype != VSNORMAL) {
12557                        synstack->varnest++;
12558                        if (synstack->dblquote)
12559                                synstack->dqvarnest++;
12560                }
12561                STPUTC('=', out);
12562        }
12563        goto parsesub_return;
12564}
12565
12566/*
12567 * Called to parse command substitutions.  Newstyle is set if the command
12568 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12569 * list of commands (passed by reference), and savelen is the number of
12570 * characters on the top of the stack which must be preserved.
12571 */
12572parsebackq: {
12573        struct nodelist **nlpp;
12574        union node *n;
12575        char *str;
12576        size_t savelen;
12577        smallint saveprompt = 0;
12578
12579        str = NULL;
12580        savelen = out - (char *)stackblock();
12581        if (savelen > 0) {
12582                /*
12583                 * FIXME: this can allocate very large block on stack and SEGV.
12584                 * Example:
12585                 * echo "..<100kbytes>..`true` $(true) `true` ..."
12586                 * allocates 100kb for every command subst. With about
12587                 * a hundred command substitutions stack overflows.
12588                 * With larger prepended string, SEGV happens sooner.
12589                 */
12590                str = alloca(savelen);
12591                memcpy(str, stackblock(), savelen);
12592        }
12593
12594        if (oldstyle) {
12595                /* We must read until the closing backquote, giving special
12596                 * treatment to some slashes, and then push the string and
12597                 * reread it as input, interpreting it normally.
12598                 */
12599                char *pout;
12600                size_t psavelen;
12601                char *pstr;
12602
12603                STARTSTACKSTR(pout);
12604                for (;;) {
12605                        int pc;
12606
12607                        setprompt_if(needprompt, 2);
12608                        pc = pgetc_eatbnl();
12609                        switch (pc) {
12610                        case '`':
12611                                goto done;
12612
12613                        case '\\':
12614                                pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
12615                                if (pc != '\\' && pc != '`' && pc != '$'
12616                                 && (!synstack->dblquote || pc != '"')
12617                                ) {
12618                                        STPUTC('\\', pout);
12619                                }
12620                                if (pc <= 255 /* not PEOA or PEOF */) {
12621                                        break;
12622                                }
12623                                /* fall through */
12624
12625                        case PEOF:
12626                        IF_ASH_ALIAS(case PEOA:)
12627                                raise_error_syntax("EOF in backquote substitution");
12628
12629                        case '\n':
12630                                nlnoprompt();
12631                                break;
12632
12633                        default:
12634                                break;
12635                        }
12636                        STPUTC(pc, pout);
12637                }
12638 done:
12639                STPUTC('\0', pout);
12640                psavelen = pout - (char *)stackblock();
12641                if (psavelen > 0) {
12642                        pstr = grabstackstr(pout);
12643                        setinputstring(pstr);
12644                }
12645        }
12646        nlpp = &bqlist;
12647        while (*nlpp)
12648                nlpp = &(*nlpp)->next;
12649        *nlpp = stzalloc(sizeof(**nlpp));
12650        /* (*nlpp)->next = NULL; - stzalloc did it */
12651
12652        if (oldstyle) {
12653                saveprompt = doprompt;
12654                doprompt = 0;
12655        }
12656
12657        n = list(2);
12658
12659        if (oldstyle)
12660                doprompt = saveprompt;
12661        else if (readtoken() != TRP)
12662                raise_error_unexpected_syntax(TRP);
12663
12664        (*nlpp)->n = n;
12665        if (oldstyle) {
12666                /*
12667                 * Start reading from old file again, ignoring any pushed back
12668                 * tokens left from the backquote parsing
12669                 */
12670                popfile();
12671                tokpushback = 0;
12672        }
12673        while (stackblocksize() <= savelen)
12674                growstackblock();
12675        STARTSTACKSTR(out);
12676        if (str) {
12677                memcpy(out, str, savelen);
12678                STADJUST(savelen, out);
12679        }
12680        USTPUTC(CTLBACKQ, out);
12681        if (oldstyle)
12682                goto parsebackq_oldreturn;
12683        goto parsebackq_newreturn;
12684}
12685
12686#if ENABLE_FEATURE_SH_MATH
12687/*
12688 * Parse an arithmetic expansion (indicate start of one and set state)
12689 */
12690parsearith: {
12691
12692        synstack_push(&synstack,
12693                        synstack->prev ?: alloca(sizeof(*synstack)),
12694                        ARISYNTAX);
12695        synstack->dblquote = 1;
12696        USTPUTC(CTLARI, out);
12697        goto parsearith_return;
12698}
12699#endif
12700} /* end of readtoken */
12701
12702/*
12703 * Read the next input token.
12704 * If the token is a word, we set backquotelist to the list of cmds in
12705 *      backquotes.  We set quoteflag to true if any part of the word was
12706 *      quoted.
12707 * If the token is TREDIR, then we set redirnode to a structure containing
12708 *      the redirection.
12709 *
12710 * [Change comment:  here documents and internal procedures]
12711 * [Readtoken shouldn't have any arguments.  Perhaps we should make the
12712 *  word parsing code into a separate routine.  In this case, readtoken
12713 *  doesn't need to have any internal procedures, but parseword does.
12714 *  We could also make parseoperator in essence the main routine, and
12715 *  have parseword (readtoken1?) handle both words and redirection.]
12716 */
12717#define NEW_xxreadtoken
12718#ifdef NEW_xxreadtoken
12719/* singles must be first! */
12720static const char xxreadtoken_chars[7] ALIGN1 = {
12721        '\n', '(', ')', /* singles */
12722        '&', '|', ';',  /* doubles */
12723        0
12724};
12725
12726#define xxreadtoken_singles 3
12727#define xxreadtoken_doubles 3
12728
12729static const char xxreadtoken_tokens[] ALIGN1 = {
12730        TNL, TLP, TRP,          /* only single occurrence allowed */
12731        TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12732        TEOF,                   /* corresponds to trailing nul */
12733        TAND, TOR, TENDCASE     /* if double occurrence */
12734};
12735
12736static int
12737xxreadtoken(void)
12738{
12739        int c;
12740
12741        if (tokpushback) {
12742                tokpushback = 0;
12743                return lasttoken;
12744        }
12745        setprompt_if(needprompt, 2);
12746        for (;;) {                      /* until token or start of word found */
12747                c = pgetc_eatbnl();
12748                if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
12749                        continue;
12750
12751                if (c == '#') {
12752                        while ((c = pgetc()) != '\n' && c != PEOF)
12753                                continue;
12754                        pungetc();
12755                } else if (c == '\\') {
12756                        break; /* return readtoken1(...) */
12757                } else {
12758                        const char *p;
12759
12760                        p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12761                        if (c != PEOF) {
12762                                if (c == '\n') {
12763                                        nlnoprompt();
12764                                }
12765
12766                                p = strchr(xxreadtoken_chars, c);
12767                                if (p == NULL)
12768                                        break; /* return readtoken1(...) */
12769
12770                                if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12771                                        int cc = pgetc_eatbnl();
12772                                        if (cc == c) {    /* double occurrence? */
12773                                                p += xxreadtoken_doubles + 1;
12774                                        } else {
12775                                                pungetc();
12776#if BASH_REDIR_OUTPUT
12777                                                if (c == '&' && cc == '>') /* &> */
12778                                                        break; /* return readtoken1(...) */
12779#endif
12780                                        }
12781                                }
12782                        }
12783                        lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12784                        return lasttoken;
12785                }
12786        } /* for (;;) */
12787
12788        return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
12789}
12790#else /* old xxreadtoken */
12791#define RETURN(token)   return lasttoken = token
12792static int
12793xxreadtoken(void)
12794{
12795        int c;
12796
12797        if (tokpushback) {
12798                tokpushback = 0;
12799                return lasttoken;
12800        }
12801        setprompt_if(needprompt, 2);
12802        for (;;) {      /* until token or start of word found */
12803                c = pgetc_eatbnl();
12804                switch (c) {
12805                case ' ': case '\t':
12806                IF_ASH_ALIAS(case PEOA:)
12807                        continue;
12808                case '#':
12809                        while ((c = pgetc()) != '\n' && c != PEOF)
12810                                continue;
12811                        pungetc();
12812                        continue;
12813                case '\n':
12814                        nlnoprompt();
12815                        RETURN(TNL);
12816                case PEOF:
12817                        RETURN(TEOF);
12818                case '&':
12819                        if (pgetc_eatbnl() == '&')
12820                                RETURN(TAND);
12821                        pungetc();
12822                        RETURN(TBACKGND);
12823                case '|':
12824                        if (pgetc_eatbnl() == '|')
12825                                RETURN(TOR);
12826                        pungetc();
12827                        RETURN(TPIPE);
12828                case ';':
12829                        if (pgetc_eatbnl() == ';')
12830                                RETURN(TENDCASE);
12831                        pungetc();
12832                        RETURN(TSEMI);
12833                case '(':
12834                        RETURN(TLP);
12835                case ')':
12836                        RETURN(TRP);
12837                }
12838                break;
12839        }
12840        return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12841#undef RETURN
12842}
12843#endif /* old xxreadtoken */
12844
12845static int
12846readtoken(void)
12847{
12848        int t;
12849        int kwd = checkkwd;
12850#if DEBUG
12851        smallint alreadyseen = tokpushback;
12852#endif
12853
12854#if ENABLE_ASH_ALIAS
12855 top:
12856#endif
12857
12858        t = xxreadtoken();
12859
12860        /*
12861         * eat newlines
12862         */
12863        if (kwd & CHKNL) {
12864                while (t == TNL) {
12865                        parseheredoc();
12866                        t = xxreadtoken();
12867                }
12868        }
12869
12870        if (t != TWORD || quoteflag) {
12871                goto out;
12872        }
12873
12874        /*
12875         * check for keywords
12876         */
12877        if (kwd & CHKKWD) {
12878                const char *const *pp;
12879
12880                pp = findkwd(wordtext);
12881                if (pp) {
12882                        lasttoken = t = pp - tokname_array;
12883                        TRACE(("keyword '%s' recognized\n", tokname_array[t]));
12884                        goto out;
12885                }
12886        }
12887
12888        if (checkkwd & CHKALIAS) {
12889#if ENABLE_ASH_ALIAS
12890                struct alias *ap;
12891                ap = lookupalias(wordtext, 1);
12892                if (ap != NULL) {
12893                        if (*ap->val) {
12894                                pushstring(ap->val, ap);
12895                        }
12896                        goto top;
12897                }
12898#endif
12899        }
12900 out:
12901        checkkwd = 0;
12902#if DEBUG
12903        if (!alreadyseen)
12904                TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12905        else
12906                TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12907#endif
12908        return t;
12909}
12910
12911static int
12912peektoken(void)
12913{
12914        int t;
12915
12916        t = readtoken();
12917        tokpushback = 1;
12918        return t;
12919}
12920
12921/*
12922 * Read and parse a command.  Returns NODE_EOF on end of file.
12923 * (NULL is a valid parse tree indicating a blank line.)
12924 */
12925static union node *
12926parsecmd(int interact)
12927{
12928        tokpushback = 0;
12929        checkkwd = 0;
12930        heredoclist = 0;
12931        doprompt = interact;
12932        setprompt_if(doprompt, doprompt);
12933        needprompt = 0;
12934        return list(1);
12935}
12936
12937/*
12938 * Input any here documents.
12939 */
12940static void
12941parseheredoc(void)
12942{
12943        struct heredoc *here;
12944        union node *n;
12945
12946        here = heredoclist;
12947        heredoclist = NULL;
12948
12949        while (here) {
12950                tokpushback = 0;
12951                setprompt_if(needprompt, 2);
12952                readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
12953                                here->eofmark, here->striptabs);
12954                n = stzalloc(sizeof(struct narg));
12955                n->narg.type = NARG;
12956                /*n->narg.next = NULL; - stzalloc did it */
12957                n->narg.text = wordtext;
12958                n->narg.backquote = backquotelist;
12959                here->here->nhere.doc = n;
12960                here = here->next;
12961        }
12962}
12963
12964
12965static const char *
12966expandstr(const char *ps, int syntax_type)
12967{
12968        union node n;
12969        int saveprompt;
12970
12971        /* XXX Fix (char *) cast. */
12972        setinputstring((char *)ps);
12973
12974        saveprompt = doprompt;
12975        doprompt = 0;
12976
12977        /* readtoken1() might die horribly.
12978         * Try a prompt with syntactically wrong command:
12979         * PS1='$(date "+%H:%M:%S) > '
12980         */
12981        {
12982                volatile int saveint;
12983                struct jmploc *volatile savehandler = exception_handler;
12984                struct jmploc jmploc;
12985                SAVE_INT(saveint);
12986                if (setjmp(jmploc.loc) == 0) {
12987                        exception_handler = &jmploc;
12988                        readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
12989                }
12990                exception_handler = savehandler;
12991                RESTORE_INT(saveint);
12992        }
12993
12994        doprompt = saveprompt;
12995
12996        popfile();
12997
12998        n.narg.type = NARG;
12999        n.narg.next = NULL;
13000        n.narg.text = wordtext;
13001        n.narg.backquote = backquotelist;
13002
13003        expandarg(&n, NULL, EXP_QUOTED);
13004        return stackblock();
13005}
13006
13007static inline int
13008parser_eof(void)
13009{
13010        return tokpushback && lasttoken == TEOF;
13011}
13012
13013/*
13014 * Execute a command or commands contained in a string.
13015 */
13016static int
13017evalstring(char *s, int flags)
13018{
13019        struct jmploc *volatile savehandler;
13020        struct jmploc jmploc;
13021        int ex;
13022
13023        union node *n;
13024        struct stackmark smark;
13025        int status;
13026
13027        s = sstrdup(s);
13028        setinputstring(s);
13029        setstackmark(&smark);
13030
13031        status = 0;
13032        /* On exception inside execution loop, we must popfile().
13033         * Try interactively:
13034         *      readonly a=a
13035         *      command eval "a=b"  # throws "is read only" error
13036         * "command BLTIN" is not supposed to abort (even in non-interactive use).
13037         * But if we skip popfile(), we hit EOF in eval's string, and exit.
13038         */
13039        savehandler = exception_handler;
13040        ex = setjmp(jmploc.loc);
13041        if (ex)
13042                goto out;
13043        exception_handler = &jmploc;
13044
13045        while ((n = parsecmd(0)) != NODE_EOF) {
13046                int i;
13047
13048                i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
13049                if (n)
13050                        status = i;
13051                popstackmark(&smark);
13052                if (evalskip)
13053                        break;
13054        }
13055 out:
13056        popstackmark(&smark);
13057        popfile();
13058        stunalloc(s);
13059
13060        exception_handler = savehandler;
13061        if (ex)
13062                longjmp(exception_handler->loc, ex);
13063
13064        return status;
13065}
13066
13067/*
13068 * The eval command.
13069 */
13070static int FAST_FUNC
13071evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
13072{
13073        char *p;
13074        char *concat;
13075
13076        if (argv[1]) {
13077                p = argv[1];
13078                argv += 2;
13079                if (argv[0]) {
13080                        STARTSTACKSTR(concat);
13081                        for (;;) {
13082                                concat = stack_putstr(p, concat);
13083                                p = *argv++;
13084                                if (p == NULL)
13085                                        break;
13086                                STPUTC(' ', concat);
13087                        }
13088                        STPUTC('\0', concat);
13089                        p = grabstackstr(concat);
13090                }
13091                return evalstring(p, flags & EV_TESTED);
13092        }
13093        return 0;
13094}
13095
13096/*
13097 * Read and execute commands.
13098 * "Top" is nonzero for the top level command loop;
13099 * it turns on prompting if the shell is interactive.
13100 */
13101static int
13102cmdloop(int top)
13103{
13104        union node *n;
13105        struct stackmark smark;
13106        int inter;
13107        int status = 0;
13108        int numeof = 0;
13109
13110        TRACE(("cmdloop(%d) called\n", top));
13111        for (;;) {
13112                int skip;
13113
13114                setstackmark(&smark);
13115#if JOBS
13116                if (doing_jobctl)
13117                        showjobs(SHOW_CHANGED|SHOW_STDERR);
13118#endif
13119                inter = 0;
13120                if (iflag && top) {
13121                        inter++;
13122                        chkmail();
13123                }
13124                n = parsecmd(inter);
13125#if DEBUG
13126                if (DEBUG > 2 && debug && (n != NODE_EOF))
13127                        showtree(n);
13128#endif
13129                if (n == NODE_EOF) {
13130                        if (!top || numeof >= 50)
13131                                break;
13132                        if (!stoppedjobs()) {
13133                                if (!Iflag)
13134                                        break;
13135                                out2str("\nUse \"exit\" to leave shell.\n");
13136                        }
13137                        numeof++;
13138                } else if (nflag == 0) {
13139                        int i;
13140
13141                        /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13142                        job_warning >>= 1;
13143                        numeof = 0;
13144                        i = evaltree(n, 0);
13145                        if (n)
13146                                status = i;
13147                }
13148                popstackmark(&smark);
13149                skip = evalskip;
13150
13151                if (skip) {
13152                        evalskip &= ~SKIPFUNC;
13153                        break;
13154                }
13155        }
13156        return status;
13157}
13158
13159/*
13160 * Take commands from a file.  To be compatible we should do a path
13161 * search for the file, which is necessary to find sub-commands.
13162 */
13163static char *
13164find_dot_file(char *name)
13165{
13166        char *fullname;
13167        const char *path = pathval();
13168        struct stat statb;
13169
13170        /* don't try this for absolute or relative paths */
13171        if (strchr(name, '/'))
13172                return name;
13173
13174        while ((fullname = path_advance(&path, name)) != NULL) {
13175                if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
13176                        /*
13177                         * Don't bother freeing here, since it will
13178                         * be freed by the caller.
13179                         */
13180                        return fullname;
13181                }
13182                if (fullname != name)
13183                        stunalloc(fullname);
13184        }
13185        /* not found in PATH */
13186
13187#if ENABLE_ASH_BASH_SOURCE_CURDIR
13188        return name;
13189#else
13190        ash_msg_and_raise_error("%s: not found", name);
13191        /* NOTREACHED */
13192#endif
13193}
13194
13195static int FAST_FUNC
13196dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
13197{
13198        /* "false; . empty_file; echo $?" should print 0, not 1: */
13199        int status = 0;
13200        char *fullname;
13201        char **argv;
13202        char *args_need_save;
13203        volatile struct shparam saveparam;
13204
13205//???
13206//      struct strlist *sp;
13207//      for (sp = cmdenviron; sp; sp = sp->next)
13208//              setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
13209
13210        nextopt(nullstr); /* handle possible "--" */
13211        argv = argptr;
13212
13213        if (!argv[0]) {
13214                /* bash says: "bash: .: filename argument required" */
13215                return 2; /* bash compat */
13216        }
13217
13218        /* This aborts if file isn't found, which is POSIXly correct.
13219         * bash returns exitcode 1 instead.
13220         */
13221        fullname = find_dot_file(argv[0]);
13222        argv++;
13223        args_need_save = argv[0];
13224        if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
13225                int argc;
13226                saveparam = shellparam;
13227                shellparam.malloced = 0;
13228                argc = 1;
13229                while (argv[argc])
13230                        argc++;
13231                shellparam.nparam = argc;
13232                shellparam.p = argv;
13233        };
13234
13235        /* This aborts if file can't be opened, which is POSIXly correct.
13236         * bash returns exitcode 1 instead.
13237         */
13238        setinputfile(fullname, INPUT_PUSH_FILE);
13239        commandname = fullname;
13240        status = cmdloop(0);
13241        popfile();
13242
13243        if (args_need_save) {
13244                freeparam(&shellparam);
13245                shellparam = saveparam;
13246        };
13247
13248        return status;
13249}
13250
13251static int FAST_FUNC
13252exitcmd(int argc UNUSED_PARAM, char **argv)
13253{
13254        if (stoppedjobs())
13255                return 0;
13256        if (argv[1])
13257                exitstatus = number(argv[1]);
13258        raise_exception(EXEXIT);
13259        /* NOTREACHED */
13260}
13261
13262/*
13263 * Read a file containing shell functions.
13264 */
13265static void
13266readcmdfile(char *name)
13267{
13268        setinputfile(name, INPUT_PUSH_FILE);
13269        cmdloop(0);
13270        popfile();
13271}
13272
13273
13274/* ============ find_command inplementation */
13275
13276/*
13277 * Resolve a command name.  If you change this routine, you may have to
13278 * change the shellexec routine as well.
13279 */
13280static void
13281find_command(char *name, struct cmdentry *entry, int act, const char *path)
13282{
13283        struct tblentry *cmdp;
13284        int idx;
13285        int prev;
13286        char *fullname;
13287        struct stat statb;
13288        int e;
13289        int updatetbl;
13290        struct builtincmd *bcmd;
13291
13292        /* If name contains a slash, don't use PATH or hash table */
13293        if (strchr(name, '/') != NULL) {
13294                entry->u.index = -1;
13295                if (act & DO_ABS) {
13296                        while (stat(name, &statb) < 0) {
13297#ifdef SYSV
13298                                if (errno == EINTR)
13299                                        continue;
13300#endif
13301                                entry->cmdtype = CMDUNKNOWN;
13302                                return;
13303                        }
13304                }
13305                entry->cmdtype = CMDNORMAL;
13306                return;
13307        }
13308
13309/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
13310
13311        updatetbl = (path == pathval());
13312        if (!updatetbl) {
13313                act |= DO_ALTPATH;
13314                if (strstr(path, "%builtin") != NULL)
13315                        act |= DO_ALTBLTIN;
13316        }
13317
13318        /* If name is in the table, check answer will be ok */
13319        cmdp = cmdlookup(name, 0);
13320        if (cmdp != NULL) {
13321                int bit;
13322
13323                switch (cmdp->cmdtype) {
13324                default:
13325#if DEBUG
13326                        abort();
13327#endif
13328                case CMDNORMAL:
13329                        bit = DO_ALTPATH;
13330                        break;
13331                case CMDFUNCTION:
13332                        bit = DO_NOFUNC;
13333                        break;
13334                case CMDBUILTIN:
13335                        bit = DO_ALTBLTIN;
13336                        break;
13337                }
13338                if (act & bit) {
13339                        updatetbl = 0;
13340                        cmdp = NULL;
13341                } else if (cmdp->rehash == 0)
13342                        /* if not invalidated by cd, we're done */
13343                        goto success;
13344        }
13345
13346        /* If %builtin not in path, check for builtin next */
13347        bcmd = find_builtin(name);
13348        if (bcmd) {
13349                if (IS_BUILTIN_REGULAR(bcmd))
13350                        goto builtin_success;
13351                if (act & DO_ALTPATH) {
13352                        if (!(act & DO_ALTBLTIN))
13353                                goto builtin_success;
13354                } else if (builtinloc <= 0) {
13355                        goto builtin_success;
13356                }
13357        }
13358
13359#if ENABLE_FEATURE_SH_STANDALONE
13360        {
13361                int applet_no = find_applet_by_name(name);
13362                if (applet_no >= 0) {
13363                        entry->cmdtype = CMDNORMAL;
13364                        entry->u.index = -2 - applet_no;
13365                        return;
13366                }
13367        }
13368#endif
13369
13370        /* We have to search path. */
13371        prev = -1;              /* where to start */
13372        if (cmdp && cmdp->rehash) {     /* doing a rehash */
13373                if (cmdp->cmdtype == CMDBUILTIN)
13374                        prev = builtinloc;
13375                else
13376                        prev = cmdp->param.index;
13377        }
13378
13379        e = ENOENT;
13380        idx = -1;
13381 loop:
13382        while ((fullname = path_advance(&path, name)) != NULL) {
13383                stunalloc(fullname);
13384                /* NB: code below will still use fullname
13385                 * despite it being "unallocated" */
13386                idx++;
13387                if (pathopt) {
13388                        if (prefix(pathopt, "builtin")) {
13389                                if (bcmd)
13390                                        goto builtin_success;
13391                                continue;
13392                        }
13393                        if ((act & DO_NOFUNC)
13394                         || !prefix(pathopt, "func")
13395                        ) {     /* ignore unimplemented options */
13396                                continue;
13397                        }
13398                }
13399                /* if rehash, don't redo absolute path names */
13400                if (fullname[0] == '/' && idx <= prev) {
13401                        if (idx < prev)
13402                                continue;
13403                        TRACE(("searchexec \"%s\": no change\n", name));
13404                        goto success;
13405                }
13406                while (stat(fullname, &statb) < 0) {
13407#ifdef SYSV
13408                        if (errno == EINTR)
13409                                continue;
13410#endif
13411                        if (errno != ENOENT && errno != ENOTDIR)
13412                                e = errno;
13413                        goto loop;
13414                }
13415                e = EACCES;     /* if we fail, this will be the error */
13416                if (!S_ISREG(statb.st_mode))
13417                        continue;
13418                if (pathopt) {          /* this is a %func directory */
13419                        stalloc(strlen(fullname) + 1);
13420                        /* NB: stalloc will return space pointed by fullname
13421                         * (because we don't have any intervening allocations
13422                         * between stunalloc above and this stalloc) */
13423                        readcmdfile(fullname);
13424                        cmdp = cmdlookup(name, 0);
13425                        if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13426                                ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13427                        stunalloc(fullname);
13428                        goto success;
13429                }
13430                TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13431                if (!updatetbl) {
13432                        entry->cmdtype = CMDNORMAL;
13433                        entry->u.index = idx;
13434                        return;
13435                }
13436                INT_OFF;
13437                cmdp = cmdlookup(name, 1);
13438                cmdp->cmdtype = CMDNORMAL;
13439                cmdp->param.index = idx;
13440                INT_ON;
13441                goto success;
13442        }
13443
13444        /* We failed.  If there was an entry for this command, delete it */
13445        if (cmdp && updatetbl)
13446                delete_cmd_entry();
13447        if (act & DO_ERR) {
13448#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13449                struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13450                if (hookp && hookp->cmdtype == CMDFUNCTION) {
13451                        char *argv[3];
13452                        argv[0] = (char*) "command_not_found_handle";
13453                        argv[1] = name;
13454                        argv[2] = NULL;
13455                        evalfun(hookp->param.func, 2, argv, 0);
13456                        entry->cmdtype = CMDUNKNOWN;
13457                        return;
13458                }
13459#endif
13460                ash_msg("%s: %s", name, errmsg(e, "not found"));
13461        }
13462        entry->cmdtype = CMDUNKNOWN;
13463        return;
13464
13465 builtin_success:
13466        if (!updatetbl) {
13467                entry->cmdtype = CMDBUILTIN;
13468                entry->u.cmd = bcmd;
13469                return;
13470        }
13471        INT_OFF;
13472        cmdp = cmdlookup(name, 1);
13473        cmdp->cmdtype = CMDBUILTIN;
13474        cmdp->param.cmd = bcmd;
13475        INT_ON;
13476 success:
13477        cmdp->rehash = 0;
13478        entry->cmdtype = cmdp->cmdtype;
13479        entry->u = cmdp->param;
13480}
13481
13482
13483/*
13484 * The trap builtin.
13485 */
13486static int FAST_FUNC
13487trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13488{
13489        char *action;
13490        char **ap;
13491        int signo, exitcode;
13492
13493        nextopt(nullstr);
13494        ap = argptr;
13495        if (!*ap) {
13496                for (signo = 0; signo < NSIG; signo++) {
13497                        char *tr = trap_ptr[signo];
13498                        if (tr) {
13499                                /* note: bash adds "SIG", but only if invoked
13500                                 * as "bash". If called as "sh", or if set -o posix,
13501                                 * then it prints short signal names.
13502                                 * We are printing short names: */
13503                                out1fmt("trap -- %s %s\n",
13504                                                single_quote(tr),
13505                                                get_signame(signo));
13506                /* trap_ptr != trap only if we are in special-cased `trap` code.
13507                 * In this case, we will exit very soon, no need to free(). */
13508                                /* if (trap_ptr != trap && tp[0]) */
13509                                /*      free(tr); */
13510                        }
13511                }
13512                /*
13513                if (trap_ptr != trap) {
13514                        free(trap_ptr);
13515                        trap_ptr = trap;
13516                }
13517                */
13518                return 0;
13519        }
13520
13521        /* Why the second check?
13522         * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13523         * In this case, NUM is signal no, not an action.
13524         */
13525        action = NULL;
13526        if (ap[1] && !is_number(ap[0]))
13527                action = *ap++;
13528
13529        exitcode = 0;
13530        while (*ap) {
13531                signo = get_signum(*ap);
13532                if (signo < 0) {
13533                        /* Mimic bash message exactly */
13534                        ash_msg("%s: invalid signal specification", *ap);
13535                        exitcode = 1;
13536                        goto next;
13537                }
13538                INT_OFF;
13539                if (action) {
13540                        if (LONE_DASH(action))
13541                                action = NULL;
13542                        else {
13543                                if (action[0]) /* not NULL and not "" and not "-" */
13544                                        may_have_traps = 1;
13545                                action = ckstrdup(action);
13546                        }
13547                }
13548                free(trap[signo]);
13549                trap[signo] = action;
13550                if (signo != 0)
13551                        setsignal(signo);
13552                INT_ON;
13553 next:
13554                ap++;
13555        }
13556        return exitcode;
13557}
13558
13559
13560/* ============ Builtins */
13561
13562#if ENABLE_ASH_HELP
13563static int FAST_FUNC
13564helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13565{
13566        unsigned col;
13567        unsigned i;
13568
13569        out1fmt(
13570                "Built-in commands:\n"
13571                "------------------\n");
13572        for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
13573                col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
13574                                        builtintab[i].name + 1);
13575                if (col > 60) {
13576                        out1fmt("\n");
13577                        col = 0;
13578                }
13579        }
13580# if ENABLE_FEATURE_SH_STANDALONE
13581        {
13582                const char *a = applet_names;
13583                while (*a) {
13584                        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13585                        if (col > 60) {
13586                                out1fmt("\n");
13587                                col = 0;
13588                        }
13589                        while (*a++ != '\0')
13590                                continue;
13591                }
13592        }
13593# endif
13594        newline_and_flush(stdout);
13595        return EXIT_SUCCESS;
13596}
13597#endif
13598
13599#if MAX_HISTORY
13600static int FAST_FUNC
13601historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13602{
13603        show_history(line_input_state);
13604        return EXIT_SUCCESS;
13605}
13606#endif
13607
13608/*
13609 * The export and readonly commands.
13610 */
13611static int FAST_FUNC
13612exportcmd(int argc UNUSED_PARAM, char **argv)
13613{
13614        struct var *vp;
13615        char *name;
13616        const char *p;
13617        char **aptr;
13618        char opt;
13619        int flag;
13620        int flag_off;
13621
13622        /* "readonly" in bash accepts, but ignores -n.
13623         * We do the same: it saves a conditional in nextopt's param.
13624         */
13625        flag_off = 0;
13626        while ((opt = nextopt("np")) != '\0') {
13627                if (opt == 'n')
13628                        flag_off = VEXPORT;
13629        }
13630        flag = VEXPORT;
13631        if (argv[0][0] == 'r') {
13632                flag = VREADONLY;
13633                flag_off = 0; /* readonly ignores -n */
13634        }
13635        flag_off = ~flag_off;
13636
13637        /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
13638        {
13639                aptr = argptr;
13640                name = *aptr;
13641                if (name) {
13642                        do {
13643                                p = strchr(name, '=');
13644                                if (p != NULL) {
13645                                        p++;
13646                                } else {
13647                                        vp = *findvar(hashvar(name), name);
13648                                        if (vp) {
13649                                                vp->flags = ((vp->flags | flag) & flag_off);
13650                                                continue;
13651                                        }
13652                                }
13653                                setvar(name, p, (flag & flag_off));
13654                        } while ((name = *++aptr) != NULL);
13655                        return 0;
13656                }
13657        }
13658
13659        /* No arguments. Show the list of exported or readonly vars.
13660         * -n is ignored.
13661         */
13662        showvars(argv[0], flag, 0);
13663        return 0;
13664}
13665
13666/*
13667 * Delete a function if it exists.
13668 */
13669static void
13670unsetfunc(const char *name)
13671{
13672        struct tblentry *cmdp;
13673
13674        cmdp = cmdlookup(name, 0);
13675        if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
13676                delete_cmd_entry();
13677}
13678
13679/*
13680 * The unset builtin command.  We unset the function before we unset the
13681 * variable to allow a function to be unset when there is a readonly variable
13682 * with the same name.
13683 */
13684static int FAST_FUNC
13685unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13686{
13687        char **ap;
13688        int i;
13689        int flag = 0;
13690
13691        while ((i = nextopt("vf")) != 0) {
13692                flag = i;
13693        }
13694
13695        for (ap = argptr; *ap; ap++) {
13696                if (flag != 'f') {
13697                        unsetvar(*ap);
13698                        continue;
13699                }
13700                if (flag != 'v')
13701                        unsetfunc(*ap);
13702        }
13703        return 0;
13704}
13705
13706static const unsigned char timescmd_str[] ALIGN1 = {
13707        ' ',  offsetof(struct tms, tms_utime),
13708        '\n', offsetof(struct tms, tms_stime),
13709        ' ',  offsetof(struct tms, tms_cutime),
13710        '\n', offsetof(struct tms, tms_cstime),
13711        0
13712};
13713static int FAST_FUNC
13714timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13715{
13716        unsigned clk_tck;
13717        const unsigned char *p;
13718        struct tms buf;
13719
13720        clk_tck = bb_clk_tck();
13721
13722        times(&buf);
13723        p = timescmd_str;
13724        do {
13725                unsigned sec, frac;
13726                unsigned long t;
13727                t = *(clock_t *)(((char *) &buf) + p[1]);
13728                sec = t / clk_tck;
13729                frac = t % clk_tck;
13730                out1fmt("%um%u.%03us%c",
13731                        sec / 60, sec % 60,
13732                        (frac * 1000) / clk_tck,
13733                        p[0]);
13734                p += 2;
13735        } while (*p);
13736
13737        return 0;
13738}
13739
13740#if ENABLE_FEATURE_SH_MATH
13741/*
13742 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
13743 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
13744 *
13745 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13746 */
13747static int FAST_FUNC
13748letcmd(int argc UNUSED_PARAM, char **argv)
13749{
13750        arith_t i;
13751
13752        argv++;
13753        if (!*argv)
13754                ash_msg_and_raise_error("expression expected");
13755        do {
13756                i = ash_arith(*argv);
13757        } while (*++argv);
13758
13759        return !i;
13760}
13761#endif
13762
13763/*
13764 * The read builtin. Options:
13765 *      -r              Do not interpret '\' specially
13766 *      -s              Turn off echo (tty only)
13767 *      -n NCHARS       Read NCHARS max
13768 *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
13769 *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
13770 *      -u FD           Read from given FD instead of fd 0
13771 *      -d DELIM        End on DELIM char, not newline
13772 * This uses unbuffered input, which may be avoidable in some cases.
13773 * TODO: bash also has:
13774 *      -a ARRAY        Read into array[0],[1],etc
13775 *      -e              Use line editing (tty only)
13776 */
13777static int FAST_FUNC
13778readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13779{
13780        struct builtin_read_params params;
13781        const char *r;
13782        int i;
13783
13784        memset(&params, 0, sizeof(params));
13785
13786        while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
13787                switch (i) {
13788                case 'p':
13789                        params.opt_p = optionarg;
13790                        break;
13791                case 'n':
13792                        params.opt_n = optionarg;
13793                        break;
13794                case 's':
13795                        params.read_flags |= BUILTIN_READ_SILENT;
13796                        break;
13797                case 't':
13798                        params.opt_t = optionarg;
13799                        break;
13800                case 'r':
13801                        params.read_flags |= BUILTIN_READ_RAW;
13802                        break;
13803                case 'u':
13804                        params.opt_u = optionarg;
13805                        break;
13806#if BASH_READ_D
13807                case 'd':
13808                        params.opt_d = optionarg;
13809                        break;
13810#endif
13811                default:
13812                        break;
13813                }
13814        }
13815
13816        params.argv = argptr;
13817        params.setvar = setvar0;
13818        params.ifs = bltinlookup("IFS"); /* can be NULL */
13819
13820        /* "read -s" needs to save/restore termios, can't allow ^C
13821         * to jump out of it.
13822         */
13823 again:
13824        INT_OFF;
13825        r = shell_builtin_read(&params);
13826        INT_ON;
13827
13828        if ((uintptr_t)r == 1 && errno == EINTR) {
13829                /* To get SIGCHLD: sleep 1 & read x; echo $x
13830                 * Correct behavior is to not exit "read"
13831                 */
13832                if (pending_sig == 0)
13833                        goto again;
13834        }
13835
13836        if ((uintptr_t)r > 1)
13837                ash_msg_and_raise_error(r);
13838
13839        return (uintptr_t)r;
13840}
13841
13842static int FAST_FUNC
13843umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13844{
13845        static const char permuser[3] ALIGN1 = "ogu";
13846
13847        mode_t mask;
13848        int symbolic_mode = 0;
13849
13850        while (nextopt("S") != '\0') {
13851                symbolic_mode = 1;
13852        }
13853
13854        INT_OFF;
13855        mask = umask(0);
13856        umask(mask);
13857        INT_ON;
13858
13859        if (*argptr == NULL) {
13860                if (symbolic_mode) {
13861                        char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
13862                        char *p = buf;
13863                        int i;
13864
13865                        i = 2;
13866                        for (;;) {
13867                                *p++ = ',';
13868                                *p++ = permuser[i];
13869                                *p++ = '=';
13870                                /* mask is 0..0uuugggooo. i=2 selects uuu bits */
13871                                if (!(mask & 0400)) *p++ = 'r';
13872                                if (!(mask & 0200)) *p++ = 'w';
13873                                if (!(mask & 0100)) *p++ = 'x';
13874                                mask <<= 3;
13875                                if (--i < 0)
13876                                        break;
13877                        }
13878                        *p = '\0';
13879                        puts(buf + 1);
13880                } else {
13881                        out1fmt("%04o\n", mask);
13882                }
13883        } else {
13884                char *modestr = *argptr;
13885                /* numeric umasks are taken as-is */
13886                /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13887                if (!isdigit(modestr[0]))
13888                        mask ^= 0777;
13889                mask = bb_parse_mode(modestr, mask);
13890                if ((unsigned)mask > 0777) {
13891                        ash_msg_and_raise_error("illegal mode: %s", modestr);
13892                }
13893                if (!isdigit(modestr[0]))
13894                        mask ^= 0777;
13895                umask(mask);
13896        }
13897        return 0;
13898}
13899
13900static int FAST_FUNC
13901ulimitcmd(int argc UNUSED_PARAM, char **argv)
13902{
13903        return shell_builtin_ulimit(argv);
13904}
13905
13906/* ============ main() and helpers */
13907
13908/*
13909 * Called to exit the shell.
13910 */
13911static void
13912exitshell(void)
13913{
13914        struct jmploc loc;
13915        char *p;
13916        int status;
13917
13918#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13919        save_history(line_input_state);
13920#endif
13921        status = exitstatus;
13922        TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13923        if (setjmp(loc.loc)) {
13924                if (exception_type == EXEXIT)
13925                        status = exitstatus;
13926                goto out;
13927        }
13928        exception_handler = &loc;
13929        p = trap[0];
13930        if (p) {
13931                trap[0] = NULL;
13932                evalskip = 0;
13933                evalstring(p, 0);
13934                /*free(p); - we'll exit soon */
13935        }
13936 out:
13937        /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13938         * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13939         */
13940        setjobctl(0);
13941        flush_stdout_stderr();
13942        _exit(status);
13943        /* NOTREACHED */
13944}
13945
13946/* Don't inline: conserve stack of caller from having our locals too */
13947static NOINLINE void
13948init(void)
13949{
13950        /* we will never free this */
13951        basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
13952        basepf.linno = 1;
13953
13954        sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
13955        setsignal(SIGCHLD);
13956
13957        /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13958         * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13959         */
13960        signal(SIGHUP, SIG_DFL);
13961
13962        {
13963                char **envp;
13964                const char *p;
13965
13966                initvar();
13967                for (envp = environ; envp && *envp; envp++) {
13968/* Used to have
13969 *                      p = endofname(*envp);
13970 *                      if (p != *envp && *p == '=') {
13971 * here to weed out badly-named variables, but this breaks
13972 * scenarios where people do want them passed to children:
13973 * import os
13974 * os.environ["test-test"]="test"
13975 * if os.fork() == 0:
13976 *   os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ])  # fixes this
13977 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])  # breaks this
13978 */
13979                        if (strchr(*envp, '=')) {
13980                                setvareq(*envp, VEXPORT|VTEXTFIXED);
13981                        }
13982                }
13983
13984                setvareq((char*)defifsvar, VTEXTFIXED);
13985                setvareq((char*)defoptindvar, VTEXTFIXED);
13986
13987                setvar0("PPID", utoa(getppid()));
13988#if BASH_SHLVL_VAR
13989                p = lookupvar("SHLVL");
13990                setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
13991#endif
13992#if BASH_HOSTNAME_VAR
13993                if (!lookupvar("HOSTNAME")) {
13994                        struct utsname uts;
13995                        uname(&uts);
13996                        setvar0("HOSTNAME", uts.nodename);
13997                }
13998#endif
13999                p = lookupvar("PWD");
14000                if (p) {
14001                        struct stat st1, st2;
14002                        if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
14003                         || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14004                        ) {
14005                                p = NULL;
14006                        }
14007                }
14008                setpwd(p, 0);
14009        }
14010}
14011
14012
14013//usage:#define ash_trivial_usage
14014//usage:        "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
14015//usage:#define ash_full_usage "\n\n"
14016//usage:        "Unix shell interpreter"
14017
14018/*
14019 * Process the shell command line arguments.
14020 */
14021static int
14022procargs(char **argv)
14023{
14024        int i;
14025        const char *xminusc;
14026        char **xargv;
14027        int login_sh;
14028
14029        xargv = argv;
14030        login_sh = xargv[0] && xargv[0][0] == '-';
14031#if NUM_SCRIPTS > 0
14032        if (minusc)
14033                goto setarg0;
14034#endif
14035        arg0 = xargv[0];
14036        /* if (xargv[0]) - mmm, this is always true! */
14037                xargv++;
14038        argptr = xargv;
14039        for (i = 0; i < NOPTS; i++)
14040                optlist[i] = 2;
14041        if (options(/*cmdline:*/ 1, &login_sh)) {
14042                /* it already printed err message */
14043                raise_exception(EXERROR);
14044        }
14045        xargv = argptr;
14046        xminusc = minusc;
14047        if (*xargv == NULL) {
14048                if (xminusc)
14049                        ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14050                sflag = 1;
14051        }
14052        if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
14053                iflag = 1;
14054        if (mflag == 2)
14055                mflag = iflag;
14056        for (i = 0; i < NOPTS; i++)
14057                if (optlist[i] == 2)
14058                        optlist[i] = 0;
14059#if DEBUG == 2
14060        debug = 1;
14061#endif
14062        /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
14063        if (xminusc) {
14064                minusc = *xargv++;
14065                if (*xargv)
14066                        goto setarg0;
14067        } else if (!sflag) {
14068                setinputfile(*xargv, 0);
14069 setarg0:
14070                arg0 = *xargv++;
14071                commandname = arg0;
14072        }
14073
14074        shellparam.p = xargv;
14075#if ENABLE_ASH_GETOPTS
14076        shellparam.optind = 1;
14077        shellparam.optoff = -1;
14078#endif
14079        /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
14080        while (*xargv) {
14081                shellparam.nparam++;
14082                xargv++;
14083        }
14084        optschanged();
14085
14086        return login_sh;
14087}
14088
14089/*
14090 * Read /etc/profile, ~/.profile, $ENV.
14091 */
14092static void
14093read_profile(const char *name)
14094{
14095        name = expandstr(name, DQSYNTAX);
14096        if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14097                return;
14098        cmdloop(0);
14099        popfile();
14100}
14101
14102/*
14103 * This routine is called when an error or an interrupt occurs in an
14104 * interactive shell and control is returned to the main command loop.
14105 * (In dash, this function is auto-generated by build machinery).
14106 */
14107static void
14108reset(void)
14109{
14110        /* from eval.c: */
14111        evalskip = 0;
14112        loopnest = 0;
14113
14114        /* from expand.c: */
14115        ifsfree();
14116
14117        /* from input.c: */
14118        g_parsefile->left_in_buffer = 0;
14119        g_parsefile->left_in_line = 0;      /* clear input buffer */
14120        popallfiles();
14121
14122        /* from redir.c: */
14123        unwindredir(NULL);
14124
14125        /* from var.c: */
14126        unwindlocalvars(NULL);
14127}
14128
14129#if PROFILE
14130static short profile_buf[16384];
14131extern int etext();
14132#endif
14133
14134/*
14135 * Main routine.  We initialize things, parse the arguments, execute
14136 * profiles if we're a login shell, and then call cmdloop to execute
14137 * commands.  The setjmp call sets up the location to jump to when an
14138 * exception occurs.  When an exception occurs the variable "state"
14139 * is used to figure out how far we had gotten.
14140 */
14141int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14142#if NUM_SCRIPTS > 0
14143int ash_main(int argc, char **argv)
14144#else
14145int ash_main(int argc UNUSED_PARAM, char **argv)
14146#endif
14147/* note: 'argc' is used only if embedded scripts are enabled */
14148{
14149        volatile smallint state;
14150        struct jmploc jmploc;
14151        struct stackmark smark;
14152        int login_sh;
14153
14154        /* Initialize global data */
14155        INIT_G_misc();
14156        INIT_G_memstack();
14157        INIT_G_var();
14158#if ENABLE_ASH_ALIAS
14159        INIT_G_alias();
14160#endif
14161        INIT_G_cmdtable();
14162
14163#if PROFILE
14164        monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14165#endif
14166
14167#if ENABLE_FEATURE_EDITING
14168        line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
14169#endif
14170        state = 0;
14171        if (setjmp(jmploc.loc)) {
14172                smallint e;
14173                smallint s;
14174
14175                reset();
14176
14177                e = exception_type;
14178                s = state;
14179                if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
14180                        exitshell();
14181                }
14182                if (e == EXINT) {
14183                        newline_and_flush(stderr);
14184                }
14185
14186                popstackmark(&smark);
14187                FORCE_INT_ON; /* enable interrupts */
14188                if (s == 1)
14189                        goto state1;
14190                if (s == 2)
14191                        goto state2;
14192                if (s == 3)
14193                        goto state3;
14194                goto state4;
14195        }
14196        exception_handler = &jmploc;
14197        rootpid = getpid();
14198
14199        init();
14200        setstackmark(&smark);
14201
14202#if NUM_SCRIPTS > 0
14203        if (argc < 0)
14204                /* Non-NULL minusc tells procargs that an embedded script is being run */
14205                minusc = get_script_content(-argc - 1);
14206#endif
14207        login_sh = procargs(argv);
14208#if DEBUG
14209        TRACE(("Shell args: "));
14210        trace_puts_args(argv);
14211#endif
14212
14213        if (login_sh) {
14214                const char *hp;
14215
14216                state = 1;
14217                read_profile("/etc/profile");
14218 state1:
14219                state = 2;
14220                hp = lookupvar("HOME");
14221                if (hp)
14222                        read_profile("$HOME/.profile");
14223        }
14224 state2:
14225        state = 3;
14226        if (
14227#ifndef linux
14228         getuid() == geteuid() && getgid() == getegid() &&
14229#endif
14230         iflag
14231        ) {
14232                const char *shinit = lookupvar("ENV");
14233                if (shinit != NULL && *shinit != '\0')
14234                        read_profile(shinit);
14235        }
14236        popstackmark(&smark);
14237 state3:
14238        state = 4;
14239        if (minusc) {
14240                /* evalstring pushes parsefile stack.
14241                 * Ensure we don't falsely claim that 0 (stdin)
14242                 * is one of stacked source fds.
14243                 * Testcase: ash -c 'exec 1>&0' must not complain. */
14244                // if (!sflag) g_parsefile->pf_fd = -1;
14245                // ^^ not necessary since now we special-case fd 0
14246                // in save_fd_on_redirect()
14247                evalstring(minusc, sflag ? 0 : EV_EXIT);
14248        }
14249
14250        if (sflag || minusc == NULL) {
14251#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
14252                if (iflag) {
14253                        const char *hp = lookupvar("HISTFILE");
14254                        if (!hp) {
14255                                hp = lookupvar("HOME");
14256                                if (hp) {
14257                                        INT_OFF;
14258                                        hp = concat_path_file(hp, ".ash_history");
14259                                        setvar0("HISTFILE", hp);
14260                                        free((char*)hp);
14261                                        INT_ON;
14262                                        hp = lookupvar("HISTFILE");
14263                                }
14264                        }
14265                        if (hp)
14266                                line_input_state->hist_file = hp;
14267# if ENABLE_FEATURE_SH_HISTFILESIZE
14268                        hp = lookupvar("HISTFILESIZE");
14269                        line_input_state->max_history = size_from_HISTFILESIZE(hp);
14270# endif
14271                }
14272#endif
14273 state4: /* XXX ??? - why isn't this before the "if" statement */
14274                cmdloop(1);
14275        }
14276#if PROFILE
14277        monitor(0);
14278#endif
14279#ifdef GPROF
14280        {
14281                extern void _mcleanup(void);
14282                _mcleanup();
14283        }
14284#endif
14285        TRACE(("End of main reached\n"));
14286        exitshell();
14287        /* NOTREACHED */
14288}
14289
14290
14291/*-
14292 * Copyright (c) 1989, 1991, 1993, 1994
14293 *      The Regents of the University of California.  All rights reserved.
14294 *
14295 * This code is derived from software contributed to Berkeley by
14296 * Kenneth Almquist.
14297 *
14298 * Redistribution and use in source and binary forms, with or without
14299 * modification, are permitted provided that the following conditions
14300 * are met:
14301 * 1. Redistributions of source code must retain the above copyright
14302 *    notice, this list of conditions and the following disclaimer.
14303 * 2. Redistributions in binary form must reproduce the above copyright
14304 *    notice, this list of conditions and the following disclaimer in the
14305 *    documentation and/or other materials provided with the distribution.
14306 * 3. Neither the name of the University nor the names of its contributors
14307 *    may be used to endorse or promote products derived from this software
14308 *    without specific prior written permission.
14309 *
14310 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
14311 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14312 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14313 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14314 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14315 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14316 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14317 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14318 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14319 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14320 * SUCH DAMAGE.
14321 */
14322