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 (77 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
 185/* So far, all bash compat is controlled by one config option */
 186/* Separate defines document which part of code implements what */
 187/* function keyword */
 188#define    BASH_FUNCTION        ENABLE_ASH_BASH_COMPAT
 189#define IF_BASH_FUNCTION            IF_ASH_BASH_COMPAT
 190/* &>file */
 191#define    BASH_REDIR_OUTPUT    ENABLE_ASH_BASH_COMPAT
 192#define IF_BASH_REDIR_OUTPUT        IF_ASH_BASH_COMPAT
 193/* $'...' */
 194#define    BASH_DOLLAR_SQUOTE   ENABLE_ASH_BASH_COMPAT
 195#define IF_BASH_DOLLAR_SQUOTE       IF_ASH_BASH_COMPAT
 196#define    BASH_PATTERN_SUBST   ENABLE_ASH_BASH_COMPAT
 197#define IF_BASH_PATTERN_SUBST       IF_ASH_BASH_COMPAT
 198#define    BASH_SUBSTR          ENABLE_ASH_BASH_COMPAT
 199#define IF_BASH_SUBSTR              IF_ASH_BASH_COMPAT
 200/* BASH_TEST2: [[ EXPR ]]
 201 * Status of [[ support:
 202 * We replace && and || with -a and -o
 203 * TODO:
 204 * singleword+noglob expansion:
 205 *   v='a b'; [[ $v = 'a b' ]]; echo 0:$?
 206 *   [[ /bin/n* ]]; echo 0:$?
 207 * -a/-o are not AND/OR ops! (they are just strings)
 208 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
 209 * = is glob match operator, not equality operator: STR = GLOB
 210 * (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
 211 * == same as =
 212 * add =~ regex match operator: STR =~ REGEX
 213 */
 214#define    BASH_TEST2           (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
 215#define    BASH_SOURCE          ENABLE_ASH_BASH_COMPAT
 216#define    BASH_PIPEFAIL        ENABLE_ASH_BASH_COMPAT
 217#define    BASH_HOSTNAME_VAR    ENABLE_ASH_BASH_COMPAT
 218#define    BASH_SHLVL_VAR       ENABLE_ASH_BASH_COMPAT
 219#define    BASH_XTRACEFD        ENABLE_ASH_BASH_COMPAT
 220#define    BASH_READ_D          ENABLE_ASH_BASH_COMPAT
 221#define IF_BASH_READ_D              IF_ASH_BASH_COMPAT
 222
 223#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
 224/* Bionic at least up to version 24 has no glob() */
 225# undef  ENABLE_ASH_INTERNAL_GLOB
 226# define ENABLE_ASH_INTERNAL_GLOB 1
 227#endif
 228
 229#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
 230# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
 231# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
 232# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
 233# error glob() should unbackslash them and match. uClibc does not unbackslash,
 234# error fails to match dirname, subsequently not expanding <pattern> in it.
 235// Testcase:
 236// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
 237// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
 238#endif
 239
 240#if !ENABLE_ASH_INTERNAL_GLOB
 241# include <glob.h>
 242#endif
 243
 244#include "unicode.h"
 245#include "shell_common.h"
 246#if ENABLE_FEATURE_SH_MATH
 247# include "math.h"
 248#else
 249typedef long arith_t;
 250# define ARITH_FMT "%ld"
 251#endif
 252#if ENABLE_ASH_RANDOM_SUPPORT
 253# include "random.h"
 254#else
 255# define CLEAR_RANDOM_T(rnd) ((void)0)
 256#endif
 257
 258#include "NUM_APPLETS.h"
 259#if NUM_APPLETS == 1
 260/* STANDALONE does not make sense, and won't compile */
 261# undef CONFIG_FEATURE_SH_STANDALONE
 262# undef ENABLE_FEATURE_SH_STANDALONE
 263# undef IF_FEATURE_SH_STANDALONE
 264# undef IF_NOT_FEATURE_SH_STANDALONE
 265# define ENABLE_FEATURE_SH_STANDALONE 0
 266# define IF_FEATURE_SH_STANDALONE(...)
 267# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 268#endif
 269
 270#ifndef F_DUPFD_CLOEXEC
 271# define F_DUPFD_CLOEXEC F_DUPFD
 272#endif
 273#ifndef O_CLOEXEC
 274# define O_CLOEXEC 0
 275#endif
 276#ifndef PIPE_BUF
 277# define PIPE_BUF 4096           /* amount of buffering in a pipe */
 278#endif
 279
 280#if !BB_MMU
 281# error "Do not even bother, ash will not run on NOMMU machine"
 282#endif
 283
 284/* We use a trick to have more optimized code (fewer pointer reloads):
 285 *  ash.c:   extern struct globals *const ash_ptr_to_globals;
 286 *  ash_ptr_hack.c: struct globals *ash_ptr_to_globals;
 287 * This way, compiler in ash.c knows the pointer can not change.
 288 *
 289 * However, this may break on weird arches or toolchains. In this case,
 290 * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable
 291 * this optimization.
 292 */
 293#ifndef BB_GLOBAL_CONST
 294# define BB_GLOBAL_CONST const
 295#endif
 296
 297
 298/* ============ Hash table sizes. Configurable. */
 299
 300#define VTABSIZE 39
 301#define ATABSIZE 39
 302#define CMDTABLESIZE 31         /* should be prime */
 303
 304
 305/* ============ Shell options */
 306
 307static const char *const optletters_optnames[] = {
 308        "e"   "errexit",
 309        "f"   "noglob",
 310        "I"   "ignoreeof",
 311        "i"   "interactive",
 312        "m"   "monitor",
 313        "n"   "noexec",
 314        "s"   "stdin",
 315        "x"   "xtrace",
 316        "v"   "verbose",
 317        "C"   "noclobber",
 318        "a"   "allexport",
 319        "b"   "notify",
 320        "u"   "nounset",
 321        "\0"  "vi"
 322#if BASH_PIPEFAIL
 323        ,"\0"  "pipefail"
 324#endif
 325#if DEBUG
 326        ,"\0"  "nolog"
 327        ,"\0"  "debug"
 328#endif
 329};
 330
 331#define optletters(n)  optletters_optnames[n][0]
 332#define optnames(n)   (optletters_optnames[n] + 1)
 333
 334enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
 335
 336
 337/* ============ Misc data */
 338
 339#define msg_illnum "Illegal number: %s"
 340
 341/*
 342 * We enclose jmp_buf in a structure so that we can declare pointers to
 343 * jump locations.  The global variable handler contains the location to
 344 * jump to when an exception occurs, and the global variable exception_type
 345 * contains a code identifying the exception.  To implement nested
 346 * exception handlers, the user should save the value of handler on entry
 347 * to an inner scope, set handler to point to a jmploc structure for the
 348 * inner scope, and restore handler on exit from the scope.
 349 */
 350struct jmploc {
 351        jmp_buf loc;
 352};
 353
 354struct globals_misc {
 355        uint8_t exitstatus;     /* exit status of last command */
 356        uint8_t back_exitstatus;/* exit status of backquoted command */
 357        smallint job_warning;   /* user was warned about stopped jobs (can be 2, 1 or 0). */
 358        int rootpid;            /* pid of main shell */
 359        /* shell level: 0 for the main shell, 1 for its children, and so on */
 360        int shlvl;
 361#define rootshell (!shlvl)
 362        int errlinno;
 363
 364        char *minusc;  /* argument to -c option */
 365
 366        char *curdir; // = nullstr;     /* current working directory */
 367        char *physdir; // = nullstr;    /* physical working directory */
 368
 369        char *arg0; /* value of $0 */
 370
 371        struct jmploc *exception_handler;
 372
 373        volatile int suppress_int; /* counter */
 374        volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
 375        volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
 376        volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
 377        smallint exception_type; /* kind of exception (0..5) */
 378        /* exceptions */
 379#define EXINT 0         /* SIGINT received */
 380#define EXERROR 1       /* a generic error */
 381#define EXEXIT 4        /* exit the shell */
 382
 383        char nullstr[1];        /* zero length string */
 384
 385        char optlist[NOPTS];
 386#define eflag optlist[0]
 387#define fflag optlist[1]
 388#define Iflag optlist[2]
 389#define iflag optlist[3]
 390#define mflag optlist[4]
 391#define nflag optlist[5]
 392#define sflag optlist[6]
 393#define xflag optlist[7]
 394#define vflag optlist[8]
 395#define Cflag optlist[9]
 396#define aflag optlist[10]
 397#define bflag optlist[11]
 398#define uflag optlist[12]
 399#define viflag optlist[13]
 400#if BASH_PIPEFAIL
 401# define pipefail optlist[14]
 402#else
 403# define pipefail 0
 404#endif
 405#if DEBUG
 406# define nolog optlist[14 + BASH_PIPEFAIL]
 407# define debug optlist[15 + BASH_PIPEFAIL]
 408#endif
 409
 410        /* trap handler commands */
 411        /*
 412         * Sigmode records the current value of the signal handlers for the various
 413         * modes.  A value of zero means that the current handler is not known.
 414         * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
 415         */
 416        char sigmode[NSIG - 1];
 417#define S_DFL      1            /* default signal handling (SIG_DFL) */
 418#define S_CATCH    2            /* signal is caught */
 419#define S_IGN      3            /* signal is ignored (SIG_IGN) */
 420#define S_HARD_IGN 4            /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
 421
 422        /* indicates specified signal received */
 423        uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
 424        uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
 425        char *trap[NSIG];
 426        char **trap_ptr;        /* used only by "trap hack" */
 427
 428        /* Rarely referenced stuff */
 429#if ENABLE_ASH_RANDOM_SUPPORT
 430        random_t random_gen;
 431#endif
 432        pid_t backgndpid;        /* pid of last background process */
 433};
 434extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
 435#define G_misc (*ash_ptr_to_globals_misc)
 436#define exitstatus        (G_misc.exitstatus )
 437#define back_exitstatus   (G_misc.back_exitstatus )
 438#define job_warning       (G_misc.job_warning)
 439#define rootpid     (G_misc.rootpid    )
 440#define shlvl       (G_misc.shlvl      )
 441#define errlinno    (G_misc.errlinno   )
 442#define minusc      (G_misc.minusc     )
 443#define curdir      (G_misc.curdir     )
 444#define physdir     (G_misc.physdir    )
 445#define arg0        (G_misc.arg0       )
 446#define exception_handler (G_misc.exception_handler)
 447#define exception_type    (G_misc.exception_type   )
 448#define suppress_int      (G_misc.suppress_int     )
 449#define pending_int       (G_misc.pending_int      )
 450#define got_sigchld       (G_misc.got_sigchld      )
 451#define pending_sig       (G_misc.pending_sig      )
 452#define nullstr     (G_misc.nullstr    )
 453#define optlist     (G_misc.optlist    )
 454#define sigmode     (G_misc.sigmode    )
 455#define gotsig      (G_misc.gotsig     )
 456#define may_have_traps    (G_misc.may_have_traps   )
 457#define trap        (G_misc.trap       )
 458#define trap_ptr    (G_misc.trap_ptr   )
 459#define random_gen  (G_misc.random_gen )
 460#define backgndpid  (G_misc.backgndpid )
 461#define INIT_G_misc() do { \
 462        (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
 463        barrier(); \
 464        curdir = nullstr; \
 465        physdir = nullstr; \
 466        trap_ptr = trap; \
 467} while (0)
 468
 469
 470/* ============ DEBUG */
 471#if DEBUG
 472static void trace_printf(const char *fmt, ...);
 473static void trace_vprintf(const char *fmt, va_list va);
 474# define TRACE(param)    trace_printf param
 475# define TRACEV(param)   trace_vprintf param
 476# define close(fd) do { \
 477        int dfd = (fd); \
 478        if (close(dfd) < 0) \
 479                bb_error_msg("bug on %d: closing %d(0x%x)", \
 480                        __LINE__, dfd, dfd); \
 481} while (0)
 482#else
 483# define TRACE(param)
 484# define TRACEV(param)
 485#endif
 486
 487
 488/* ============ Utility functions */
 489#define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
 490#define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
 491
 492static int
 493isdigit_str9(const char *str)
 494{
 495        int maxlen = 9 + 1; /* max 9 digits: 999999999 */
 496        while (--maxlen && isdigit(*str))
 497                str++;
 498        return (*str == '\0');
 499}
 500
 501static const char *
 502var_end(const char *var)
 503{
 504        while (*var)
 505                if (*var++ == '=')
 506                        break;
 507        return var;
 508}
 509
 510
 511/* ============ Interrupts / exceptions */
 512
 513static void exitshell(void) NORETURN;
 514
 515/*
 516 * These macros allow the user to suspend the handling of interrupt signals
 517 * over a period of time.  This is similar to SIGHOLD or to sigblock, but
 518 * much more efficient and portable.  (But hacking the kernel is so much
 519 * more fun than worrying about efficiency and portability. :-))
 520 */
 521#if DEBUG_INTONOFF
 522# define INT_OFF do { \
 523        TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
 524        suppress_int++; \
 525        barrier(); \
 526} while (0)
 527#else
 528# define INT_OFF do { \
 529        suppress_int++; \
 530        barrier(); \
 531} while (0)
 532#endif
 533
 534/*
 535 * Called to raise an exception.  Since C doesn't include exceptions, we
 536 * just do a longjmp to the exception handler.  The type of exception is
 537 * stored in the global variable "exception_type".
 538 */
 539static void raise_exception(int) NORETURN;
 540static void
 541raise_exception(int e)
 542{
 543#if DEBUG
 544        if (exception_handler == NULL)
 545                abort();
 546#endif
 547        INT_OFF;
 548        exception_type = e;
 549        longjmp(exception_handler->loc, 1);
 550}
 551#if DEBUG
 552#define raise_exception(e) do { \
 553        TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
 554        raise_exception(e); \
 555} while (0)
 556#endif
 557
 558/*
 559 * Called when a SIGINT is received.  (If the user specifies
 560 * that SIGINT is to be trapped or ignored using the trap builtin, then
 561 * this routine is not called.)  Suppressint is nonzero when interrupts
 562 * are held using the INT_OFF macro.  (The test for iflag is just
 563 * defensive programming.)
 564 */
 565static void raise_interrupt(void) NORETURN;
 566static void
 567raise_interrupt(void)
 568{
 569        pending_int = 0;
 570        /* Signal is not automatically unmasked after it is raised,
 571         * do it ourself - unmask all signals */
 572        sigprocmask_allsigs(SIG_UNBLOCK);
 573        /* pending_sig = 0; - now done in signal_handler() */
 574
 575        if (!(rootshell && iflag)) {
 576                /* Kill ourself with SIGINT */
 577                signal(SIGINT, SIG_DFL);
 578                raise(SIGINT);
 579        }
 580        /* bash: ^C even on empty command line sets $? */
 581        exitstatus = SIGINT + 128;
 582        raise_exception(EXINT);
 583        /* NOTREACHED */
 584}
 585#if DEBUG
 586#define raise_interrupt() do { \
 587        TRACE(("raising interrupt on line %d\n", __LINE__)); \
 588        raise_interrupt(); \
 589} while (0)
 590#endif
 591
 592static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 593int_on(void)
 594{
 595        barrier();
 596        if (--suppress_int == 0 && pending_int) {
 597                raise_interrupt();
 598        }
 599}
 600#if DEBUG_INTONOFF
 601# define INT_ON do { \
 602        TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
 603        int_on(); \
 604} while (0)
 605#else
 606# define INT_ON int_on()
 607#endif
 608static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 609force_int_on(void)
 610{
 611        barrier();
 612        suppress_int = 0;
 613        if (pending_int)
 614                raise_interrupt();
 615}
 616#define FORCE_INT_ON force_int_on()
 617
 618#define SAVE_INT(v) ((v) = suppress_int)
 619
 620#define RESTORE_INT(v) do { \
 621        barrier(); \
 622        suppress_int = (v); \
 623        if (suppress_int == 0 && pending_int) \
 624                raise_interrupt(); \
 625} while (0)
 626
 627
 628/* ============ Stdout/stderr output */
 629
 630static void
 631outstr(const char *p, FILE *file)
 632{
 633        INT_OFF;
 634        fputs(p, file);
 635        INT_ON;
 636}
 637
 638static void
 639flush_stdout_stderr(void)
 640{
 641        INT_OFF;
 642        fflush_all();
 643        INT_ON;
 644}
 645
 646/* Was called outcslow(c,FILE*), but c was always '\n' */
 647static void
 648newline_and_flush(FILE *dest)
 649{
 650        INT_OFF;
 651        putc('\n', dest);
 652        fflush(dest);
 653        INT_ON;
 654}
 655
 656static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
 657static int
 658out1fmt(const char *fmt, ...)
 659{
 660        va_list ap;
 661        int r;
 662
 663        INT_OFF;
 664        va_start(ap, fmt);
 665        r = vprintf(fmt, ap);
 666        va_end(ap);
 667        INT_ON;
 668        return r;
 669}
 670
 671static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
 672static int
 673fmtstr(char *outbuf, size_t length, const char *fmt, ...)
 674{
 675        va_list ap;
 676        int ret;
 677
 678        INT_OFF;
 679        va_start(ap, fmt);
 680        ret = vsnprintf(outbuf, length, fmt, ap);
 681        va_end(ap);
 682        INT_ON;
 683        return ret;
 684}
 685
 686static void
 687out1str(const char *p)
 688{
 689        outstr(p, stdout);
 690}
 691
 692static void
 693out2str(const char *p)
 694{
 695        outstr(p, stderr);
 696        flush_stdout_stderr();
 697}
 698
 699
 700/* ============ Parser structures */
 701
 702/* control characters in argument strings */
 703#define CTL_FIRST CTLESC
 704#define CTLESC       ((unsigned char)'\201')    /* escape next character */
 705#define CTLVAR       ((unsigned char)'\202')    /* variable defn */
 706#define CTLENDVAR    ((unsigned char)'\203')
 707#define CTLBACKQ     ((unsigned char)'\204')
 708#define CTLARI       ((unsigned char)'\206')    /* arithmetic expression */
 709#define CTLENDARI    ((unsigned char)'\207')
 710#define CTLQUOTEMARK ((unsigned char)'\210')
 711#define CTL_LAST CTLQUOTEMARK
 712
 713/* variable substitution byte (follows CTLVAR) */
 714#define VSTYPE  0x0f            /* type of variable substitution */
 715#define VSNUL   0x10            /* colon--treat the empty string as unset */
 716
 717/* values of VSTYPE field */
 718#define VSNORMAL        0x1     /* normal variable:  $var or ${var} */
 719#define VSMINUS         0x2     /* ${var-text} */
 720#define VSPLUS          0x3     /* ${var+text} */
 721#define VSQUESTION      0x4     /* ${var?message} */
 722#define VSASSIGN        0x5     /* ${var=text} */
 723#define VSTRIMRIGHT     0x6     /* ${var%pattern} */
 724#define VSTRIMRIGHTMAX  0x7     /* ${var%%pattern} */
 725#define VSTRIMLEFT      0x8     /* ${var#pattern} */
 726#define VSTRIMLEFTMAX   0x9     /* ${var##pattern} */
 727#define VSLENGTH        0xa     /* ${#var} */
 728#if BASH_SUBSTR
 729#define VSSUBSTR        0xc     /* ${var:position:length} */
 730#endif
 731#if BASH_PATTERN_SUBST
 732#define VSREPLACE       0xd     /* ${var/pattern/replacement} */
 733#define VSREPLACEALL    0xe     /* ${var//pattern/replacement} */
 734#endif
 735
 736static const char dolatstr[] ALIGN1 = {
 737        CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
 738};
 739#define DOLATSTRLEN 6
 740
 741#define NCMD      0
 742#define NPIPE     1
 743#define NREDIR    2
 744#define NBACKGND  3
 745#define NSUBSHELL 4
 746#define NAND      5
 747#define NOR       6
 748#define NSEMI     7
 749#define NIF       8
 750#define NWHILE    9
 751#define NUNTIL   10
 752#define NFOR     11
 753#define NCASE    12
 754#define NCLIST   13
 755#define NDEFUN   14
 756#define NARG     15
 757#define NTO      16
 758#if BASH_REDIR_OUTPUT
 759#define NTO2     17
 760#endif
 761#define NCLOBBER 18
 762#define NFROM    19
 763#define NFROMTO  20
 764#define NAPPEND  21
 765#define NTOFD    22
 766#define NFROMFD  23
 767#define NHERE    24
 768#define NXHERE   25
 769#define NNOT     26
 770#define N_NUMBER 27
 771
 772union node;
 773
 774struct ncmd {
 775        smallint type; /* Nxxxx */
 776        int linno;
 777        union node *assign;
 778        union node *args;
 779        union node *redirect;
 780};
 781
 782struct npipe {
 783        smallint type;
 784        smallint pipe_backgnd;
 785        struct nodelist *cmdlist;
 786};
 787
 788struct nredir {
 789        smallint type;
 790        int linno;
 791        union node *n;
 792        union node *redirect;
 793};
 794
 795struct nbinary {
 796        smallint type;
 797        union node *ch1;
 798        union node *ch2;
 799};
 800
 801struct nif {
 802        smallint type;
 803        union node *test;
 804        union node *ifpart;
 805        union node *elsepart;
 806};
 807
 808struct nfor {
 809        smallint type;
 810        int linno;
 811        union node *args;
 812        union node *body;
 813        char *var;
 814};
 815
 816struct ncase {
 817        smallint type;
 818        int linno;
 819        union node *expr;
 820        union node *cases;
 821};
 822
 823struct nclist {
 824        smallint type;
 825        union node *next;
 826        union node *pattern;
 827        union node *body;
 828};
 829
 830struct ndefun {
 831        smallint type;
 832        int linno;
 833        char *text;
 834        union node *body;
 835};
 836
 837struct narg {
 838        smallint type;
 839        union node *next;
 840        char *text;
 841        struct nodelist *backquote;
 842};
 843
 844/* nfile and ndup layout must match!
 845 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
 846 * that it is actually NTO2 (>&file), and change its type.
 847 */
 848struct nfile {
 849        smallint type;
 850        union node *next;
 851        int fd;
 852        int _unused_dupfd;
 853        union node *fname;
 854        char *expfname;
 855};
 856
 857struct ndup {
 858        smallint type;
 859        union node *next;
 860        int fd;
 861        int dupfd;
 862        union node *vname;
 863        char *_unused_expfname;
 864};
 865
 866struct nhere {
 867        smallint type;
 868        union node *next;
 869        int fd;
 870        union node *doc;
 871};
 872
 873struct nnot {
 874        smallint type;
 875        union node *com;
 876};
 877
 878union node {
 879        smallint type;
 880        struct ncmd ncmd;
 881        struct npipe npipe;
 882        struct nredir nredir;
 883        struct nbinary nbinary;
 884        struct nif nif;
 885        struct nfor nfor;
 886        struct ncase ncase;
 887        struct nclist nclist;
 888        struct ndefun ndefun;
 889        struct narg narg;
 890        struct nfile nfile;
 891        struct ndup ndup;
 892        struct nhere nhere;
 893        struct nnot nnot;
 894};
 895
 896/*
 897 * NODE_EOF is returned by parsecmd when it encounters an end of file.
 898 * It must be distinct from NULL.
 899 */
 900#define NODE_EOF ((union node *) -1L)
 901
 902struct nodelist {
 903        struct nodelist *next;
 904        union node *n;
 905};
 906
 907struct funcnode {
 908        int count;
 909        union node n;
 910};
 911
 912/*
 913 * Free a parse tree.
 914 */
 915static void
 916freefunc(struct funcnode *f)
 917{
 918        if (f && --f->count < 0)
 919                free(f);
 920}
 921
 922
 923/* ============ Debugging output */
 924
 925#if DEBUG
 926
 927static FILE *tracefile;
 928
 929static void
 930trace_printf(const char *fmt, ...)
 931{
 932        va_list va;
 933
 934        if (debug != 1)
 935                return;
 936        if (DEBUG_TIME)
 937                fprintf(tracefile, "%u ", (int) time(NULL));
 938        if (DEBUG_PID)
 939                fprintf(tracefile, "[%u] ", (int) getpid());
 940        if (DEBUG_SIG)
 941                fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
 942        va_start(va, fmt);
 943        vfprintf(tracefile, fmt, va);
 944        va_end(va);
 945}
 946
 947static void
 948trace_vprintf(const char *fmt, va_list va)
 949{
 950        if (debug != 1)
 951                return;
 952        vfprintf(tracefile, fmt, va);
 953        fprintf(tracefile, "\n");
 954}
 955
 956static void
 957trace_puts(const char *s)
 958{
 959        if (debug != 1)
 960                return;
 961        fputs(s, tracefile);
 962}
 963
 964static void
 965trace_puts_quoted(char *s)
 966{
 967        char *p;
 968        char c;
 969
 970        if (debug != 1)
 971                return;
 972        putc('"', tracefile);
 973        for (p = s; *p; p++) {
 974                switch ((unsigned char)*p) {
 975                case '\n': c = 'n'; goto backslash;
 976                case '\t': c = 't'; goto backslash;
 977                case '\r': c = 'r'; goto backslash;
 978                case '\"': c = '\"'; goto backslash;
 979                case '\\': c = '\\'; goto backslash;
 980                case CTLESC: c = 'e'; goto backslash;
 981                case CTLVAR: c = 'v'; goto backslash;
 982                case CTLBACKQ: c = 'q'; goto backslash;
 983 backslash:
 984                        putc('\\', tracefile);
 985                        putc(c, tracefile);
 986                        break;
 987                default:
 988                        if (*p >= ' ' && *p <= '~')
 989                                putc(*p, tracefile);
 990                        else {
 991                                putc('\\', tracefile);
 992                                putc((*p >> 6) & 03, tracefile);
 993                                putc((*p >> 3) & 07, tracefile);
 994                                putc(*p & 07, tracefile);
 995                        }
 996                        break;
 997                }
 998        }
 999        putc('"', tracefile);
1000}
1001
1002static void
1003trace_puts_args(char **ap)
1004{
1005        if (debug != 1)
1006                return;
1007        if (!*ap)
1008                return;
1009        while (1) {
1010                trace_puts_quoted(*ap);
1011                if (!*++ap) {
1012                        putc('\n', tracefile);
1013                        break;
1014                }
1015                putc(' ', tracefile);
1016        }
1017}
1018
1019static void
1020opentrace(void)
1021{
1022        char s[100];
1023#ifdef O_APPEND
1024        int flags;
1025#endif
1026
1027        if (debug != 1) {
1028                if (tracefile)
1029                        fflush(tracefile);
1030                /* leave open because libedit might be using it */
1031                return;
1032        }
1033        strcpy(s, "./trace");
1034        if (tracefile) {
1035                if (!freopen(s, "a", tracefile)) {
1036                        fprintf(stderr, "Can't re-open %s\n", s);
1037                        debug = 0;
1038                        return;
1039                }
1040        } else {
1041                tracefile = fopen(s, "a");
1042                if (tracefile == NULL) {
1043                        fprintf(stderr, "Can't open %s\n", s);
1044                        debug = 0;
1045                        return;
1046                }
1047        }
1048#ifdef O_APPEND
1049        flags = fcntl(fileno(tracefile), F_GETFL);
1050        if (flags >= 0)
1051                fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1052#endif
1053        setlinebuf(tracefile);
1054        fputs("\nTracing started.\n", tracefile);
1055}
1056
1057static void
1058indent(int amount, char *pfx, FILE *fp)
1059{
1060        int i;
1061
1062        for (i = 0; i < amount; i++) {
1063                if (pfx && i == amount - 1)
1064                        fputs(pfx, fp);
1065                putc('\t', fp);
1066        }
1067}
1068
1069/* little circular references here... */
1070static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1071
1072static void
1073sharg(union node *arg, FILE *fp)
1074{
1075        char *p;
1076        struct nodelist *bqlist;
1077        unsigned char subtype;
1078
1079        if (arg->type != NARG) {
1080                out1fmt("<node type %d>\n", arg->type);
1081                abort();
1082        }
1083        bqlist = arg->narg.backquote;
1084        for (p = arg->narg.text; *p; p++) {
1085                switch ((unsigned char)*p) {
1086                case CTLESC:
1087                        p++;
1088                        putc(*p, fp);
1089                        break;
1090                case CTLVAR:
1091                        putc('$', fp);
1092                        putc('{', fp);
1093                        subtype = *++p;
1094                        if (subtype == VSLENGTH)
1095                                putc('#', fp);
1096
1097                        while (*p != '=') {
1098                                putc(*p, fp);
1099                                p++;
1100                        }
1101
1102                        if (subtype & VSNUL)
1103                                putc(':', fp);
1104
1105                        switch (subtype & VSTYPE) {
1106                        case VSNORMAL:
1107                                putc('}', fp);
1108                                break;
1109                        case VSMINUS:
1110                                putc('-', fp);
1111                                break;
1112                        case VSPLUS:
1113                                putc('+', fp);
1114                                break;
1115                        case VSQUESTION:
1116                                putc('?', fp);
1117                                break;
1118                        case VSASSIGN:
1119                                putc('=', fp);
1120                                break;
1121                        case VSTRIMLEFT:
1122                                putc('#', fp);
1123                                break;
1124                        case VSTRIMLEFTMAX:
1125                                putc('#', fp);
1126                                putc('#', fp);
1127                                break;
1128                        case VSTRIMRIGHT:
1129                                putc('%', fp);
1130                                break;
1131                        case VSTRIMRIGHTMAX:
1132                                putc('%', fp);
1133                                putc('%', fp);
1134                                break;
1135                        case VSLENGTH:
1136                                break;
1137                        default:
1138                                out1fmt("<subtype %d>", subtype);
1139                        }
1140                        break;
1141                case CTLENDVAR:
1142                        putc('}', fp);
1143                        break;
1144                case CTLBACKQ:
1145                        putc('$', fp);
1146                        putc('(', fp);
1147                        shtree(bqlist->n, -1, NULL, fp);
1148                        putc(')', fp);
1149                        break;
1150                default:
1151                        putc(*p, fp);
1152                        break;
1153                }
1154        }
1155}
1156
1157static void
1158shcmd(union node *cmd, FILE *fp)
1159{
1160        union node *np;
1161        int first;
1162        const char *s;
1163        int dftfd;
1164
1165        first = 1;
1166        for (np = cmd->ncmd.args; np; np = np->narg.next) {
1167                if (!first)
1168                        putc(' ', fp);
1169                sharg(np, fp);
1170                first = 0;
1171        }
1172        for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1173                if (!first)
1174                        putc(' ', fp);
1175                dftfd = 0;
1176                switch (np->nfile.type) {
1177                case NTO:      s = ">>"+1; dftfd = 1; break;
1178                case NCLOBBER: s = ">|"; dftfd = 1; break;
1179                case NAPPEND:  s = ">>"; dftfd = 1; break;
1180#if BASH_REDIR_OUTPUT
1181                case NTO2:
1182#endif
1183                case NTOFD:    s = ">&"; dftfd = 1; break;
1184                case NFROM:    s = "<"; break;
1185                case NFROMFD:  s = "<&"; break;
1186                case NFROMTO:  s = "<>"; break;
1187                default:       s = "*error*"; break;
1188                }
1189                if (np->nfile.fd != dftfd)
1190                        fprintf(fp, "%d", np->nfile.fd);
1191                fputs(s, fp);
1192                if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1193                        fprintf(fp, "%d", np->ndup.dupfd);
1194                } else {
1195                        sharg(np->nfile.fname, fp);
1196                }
1197                first = 0;
1198        }
1199}
1200
1201static void
1202shtree(union node *n, int ind, char *pfx, FILE *fp)
1203{
1204        struct nodelist *lp;
1205        const char *s;
1206
1207        if (n == NULL)
1208                return;
1209
1210        indent(ind, pfx, fp);
1211
1212        if (n == NODE_EOF) {
1213                fputs("<EOF>", fp);
1214                return;
1215        }
1216
1217        switch (n->type) {
1218        case NSEMI:
1219                s = "; ";
1220                goto binop;
1221        case NAND:
1222                s = " && ";
1223                goto binop;
1224        case NOR:
1225                s = " || ";
1226 binop:
1227                shtree(n->nbinary.ch1, ind, NULL, fp);
1228                /* if (ind < 0) */
1229                        fputs(s, fp);
1230                shtree(n->nbinary.ch2, ind, NULL, fp);
1231                break;
1232        case NCMD:
1233                shcmd(n, fp);
1234                if (ind >= 0)
1235                        putc('\n', fp);
1236                break;
1237        case NPIPE:
1238                for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1239                        shtree(lp->n, 0, NULL, fp);
1240                        if (lp->next)
1241                                fputs(" | ", fp);
1242                }
1243                if (n->npipe.pipe_backgnd)
1244                        fputs(" &", fp);
1245                if (ind >= 0)
1246                        putc('\n', fp);
1247                break;
1248        default:
1249                fprintf(fp, "<node type %d>", n->type);
1250                if (ind >= 0)
1251                        putc('\n', fp);
1252                break;
1253        }
1254}
1255
1256static void
1257showtree(union node *n)
1258{
1259        trace_puts("showtree called\n");
1260        shtree(n, 1, NULL, stderr);
1261}
1262
1263#endif /* DEBUG */
1264
1265
1266/* ============ Parser data */
1267
1268/*
1269 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1270 */
1271struct strlist {
1272        struct strlist *next;
1273        char *text;
1274};
1275
1276struct alias;
1277
1278struct strpush {
1279        struct strpush *prev;   /* preceding string on stack */
1280        char *prev_string;
1281        int prev_left_in_line;
1282#if ENABLE_ASH_ALIAS
1283        struct alias *ap;       /* if push was associated with an alias */
1284#endif
1285        char *string;           /* remember the string since it may change */
1286
1287        /* Remember last two characters for pungetc. */
1288        int lastc[2];
1289
1290        /* Number of outstanding calls to pungetc. */
1291        int unget;
1292};
1293
1294/*
1295 * The parsefile structure pointed to by the global variable parsefile
1296 * contains information about the current file being read.
1297 */
1298struct parsefile {
1299        struct parsefile *prev; /* preceding file on stack */
1300        int linno;              /* current line */
1301        int pf_fd;              /* file descriptor (or -1 if string) */
1302        int left_in_line;       /* number of chars left in this line */
1303        int left_in_buffer;     /* number of chars left in this buffer past the line */
1304        char *next_to_pgetc;    /* next char in buffer */
1305        char *buf;              /* input buffer */
1306        struct strpush *strpush; /* for pushing strings at this level */
1307        struct strpush basestrpush; /* so pushing one is fast */
1308
1309        /* Remember last two characters for pungetc. */
1310        int lastc[2];
1311
1312        /* Number of outstanding calls to pungetc. */
1313        int unget;
1314};
1315
1316static struct parsefile basepf;        /* top level input file */
1317static struct parsefile *g_parsefile = &basepf;  /* current input file */
1318static char *commandname;              /* currently executing command */
1319
1320
1321/* ============ Message printing */
1322
1323static void
1324ash_vmsg(const char *msg, va_list ap)
1325{
1326        fprintf(stderr, "%s: ", arg0);
1327        if (commandname) {
1328                if (strcmp(arg0, commandname))
1329                        fprintf(stderr, "%s: ", commandname);
1330                if (!iflag || g_parsefile->pf_fd > 0)
1331                        fprintf(stderr, "line %d: ", errlinno);
1332        }
1333        vfprintf(stderr, msg, ap);
1334        newline_and_flush(stderr);
1335}
1336
1337/*
1338 * Exverror is called to raise the error exception.  If the second argument
1339 * is not NULL then error prints an error message using printf style
1340 * formatting.  It then raises the error exception.
1341 */
1342static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1343static void
1344ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1345{
1346#if DEBUG
1347        if (msg) {
1348                TRACE(("ash_vmsg_and_raise(%d):", cond));
1349                TRACEV((msg, ap));
1350        } else
1351                TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1352        if (msg)
1353#endif
1354                ash_vmsg(msg, ap);
1355
1356        flush_stdout_stderr();
1357        raise_exception(cond);
1358        /* NOTREACHED */
1359}
1360
1361static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1362static void
1363ash_msg_and_raise_error(const char *msg, ...)
1364{
1365        va_list ap;
1366
1367        exitstatus = 2;
1368
1369        va_start(ap, msg);
1370        ash_vmsg_and_raise(EXERROR, msg, ap);
1371        /* NOTREACHED */
1372        va_end(ap);
1373}
1374
1375/*
1376 * 'fmt' must be a string literal.
1377 */
1378#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
1379
1380static void raise_error_syntax(const char *) NORETURN;
1381static void
1382raise_error_syntax(const char *msg)
1383{
1384        errlinno = g_parsefile->linno;
1385        ash_msg_and_raise_error("syntax error: %s", msg);
1386        /* NOTREACHED */
1387}
1388
1389static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1390static void
1391ash_msg_and_raise(int cond, const char *msg, ...)
1392{
1393        va_list ap;
1394
1395        va_start(ap, msg);
1396        ash_vmsg_and_raise(cond, msg, ap);
1397        /* NOTREACHED */
1398        va_end(ap);
1399}
1400
1401/*
1402 * error/warning routines for external builtins
1403 */
1404static void
1405ash_msg(const char *fmt, ...)
1406{
1407        va_list ap;
1408
1409        va_start(ap, fmt);
1410        ash_vmsg(fmt, ap);
1411        va_end(ap);
1412}
1413
1414/*
1415 * Return a string describing an error.  The returned string may be a
1416 * pointer to a static buffer that will be overwritten on the next call.
1417 * Action describes the operation that got the error.
1418 */
1419static const char *
1420errmsg(int e, const char *em)
1421{
1422        if (e == ENOENT || e == ENOTDIR) {
1423                return em;
1424        }
1425        return strerror(e);
1426}
1427
1428
1429/* ============ Memory allocation */
1430
1431#if 0
1432/* I consider these wrappers nearly useless:
1433 * ok, they return you to nearest exception handler, but
1434 * how much memory do you leak in the process, making
1435 * memory starvation worse?
1436 */
1437static void *
1438ckrealloc(void * p, size_t nbytes)
1439{
1440        p = realloc(p, nbytes);
1441        if (!p)
1442                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1443        return p;
1444}
1445
1446static void *
1447ckmalloc(size_t nbytes)
1448{
1449        return ckrealloc(NULL, nbytes);
1450}
1451
1452static void *
1453ckzalloc(size_t nbytes)
1454{
1455        return memset(ckmalloc(nbytes), 0, nbytes);
1456}
1457
1458static char *
1459ckstrdup(const char *s)
1460{
1461        char *p = strdup(s);
1462        if (!p)
1463                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1464        return p;
1465}
1466#else
1467/* Using bbox equivalents. They exit if out of memory */
1468# define ckrealloc xrealloc
1469# define ckmalloc  xmalloc
1470# define ckzalloc  xzalloc
1471# define ckstrdup  xstrdup
1472#endif
1473
1474/*
1475 * It appears that grabstackstr() will barf with such alignments
1476 * because stalloc() will return a string allocated in a new stackblock.
1477 */
1478#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1479enum {
1480        /* Most machines require the value returned from malloc to be aligned
1481         * in some way.  The following macro will get this right
1482         * on many machines.  */
1483        SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1484        /* Minimum size of a block */
1485        MINSIZE = SHELL_ALIGN(504),
1486};
1487
1488struct stack_block {
1489        struct stack_block *prev;
1490        char space[MINSIZE];
1491};
1492
1493struct stackmark {
1494        struct stack_block *stackp;
1495        char *stacknxt;
1496        size_t stacknleft;
1497};
1498
1499
1500struct globals_memstack {
1501        struct stack_block *g_stackp; // = &stackbase;
1502        char *g_stacknxt; // = stackbase.space;
1503        char *sstrend; // = stackbase.space + MINSIZE;
1504        size_t g_stacknleft; // = MINSIZE;
1505        struct stack_block stackbase;
1506};
1507extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1508#define G_memstack (*ash_ptr_to_globals_memstack)
1509#define g_stackp     (G_memstack.g_stackp    )
1510#define g_stacknxt   (G_memstack.g_stacknxt  )
1511#define sstrend      (G_memstack.sstrend     )
1512#define g_stacknleft (G_memstack.g_stacknleft)
1513#define stackbase    (G_memstack.stackbase   )
1514#define INIT_G_memstack() do { \
1515        (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1516        barrier(); \
1517        g_stackp = &stackbase; \
1518        g_stacknxt = stackbase.space; \
1519        g_stacknleft = MINSIZE; \
1520        sstrend = stackbase.space + MINSIZE; \
1521} while (0)
1522
1523
1524#define stackblock()     ((void *)g_stacknxt)
1525#define stackblocksize() g_stacknleft
1526
1527/*
1528 * Parse trees for commands are allocated in lifo order, so we use a stack
1529 * to make this more efficient, and also to avoid all sorts of exception
1530 * handling code to handle interrupts in the middle of a parse.
1531 *
1532 * The size 504 was chosen because the Ultrix malloc handles that size
1533 * well.
1534 */
1535static void *
1536stalloc(size_t nbytes)
1537{
1538        char *p;
1539        size_t aligned;
1540
1541        aligned = SHELL_ALIGN(nbytes);
1542        if (aligned > g_stacknleft) {
1543                size_t len;
1544                size_t blocksize;
1545                struct stack_block *sp;
1546
1547                blocksize = aligned;
1548                if (blocksize < MINSIZE)
1549                        blocksize = MINSIZE;
1550                len = sizeof(struct stack_block) - MINSIZE + blocksize;
1551                if (len < blocksize)
1552                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
1553                INT_OFF;
1554                sp = ckmalloc(len);
1555                sp->prev = g_stackp;
1556                g_stacknxt = sp->space;
1557                g_stacknleft = blocksize;
1558                sstrend = g_stacknxt + blocksize;
1559                g_stackp = sp;
1560                INT_ON;
1561        }
1562        p = g_stacknxt;
1563        g_stacknxt += aligned;
1564        g_stacknleft -= aligned;
1565        return p;
1566}
1567
1568static void *
1569stzalloc(size_t nbytes)
1570{
1571        return memset(stalloc(nbytes), 0, nbytes);
1572}
1573
1574static void
1575stunalloc(void *p)
1576{
1577#if DEBUG
1578        if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1579                write(STDERR_FILENO, "stunalloc\n", 10);
1580                abort();
1581        }
1582#endif
1583        g_stacknleft += g_stacknxt - (char *)p;
1584        g_stacknxt = p;
1585}
1586
1587/*
1588 * Like strdup but works with the ash stack.
1589 */
1590static char *
1591sstrdup(const char *p)
1592{
1593        size_t len = strlen(p) + 1;
1594        return memcpy(stalloc(len), p, len);
1595}
1596
1597static ALWAYS_INLINE void
1598grabstackblock(size_t len)
1599{
1600        stalloc(len);
1601}
1602
1603static void
1604pushstackmark(struct stackmark *mark, size_t len)
1605{
1606        mark->stackp = g_stackp;
1607        mark->stacknxt = g_stacknxt;
1608        mark->stacknleft = g_stacknleft;
1609        grabstackblock(len);
1610}
1611
1612static void
1613setstackmark(struct stackmark *mark)
1614{
1615        pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1616}
1617
1618static void
1619popstackmark(struct stackmark *mark)
1620{
1621        struct stack_block *sp;
1622
1623        if (!mark->stackp)
1624                return;
1625
1626        INT_OFF;
1627        while (g_stackp != mark->stackp) {
1628                sp = g_stackp;
1629                g_stackp = sp->prev;
1630                free(sp);
1631        }
1632        g_stacknxt = mark->stacknxt;
1633        g_stacknleft = mark->stacknleft;
1634        sstrend = mark->stacknxt + mark->stacknleft;
1635        INT_ON;
1636}
1637
1638/*
1639 * When the parser reads in a string, it wants to stick the string on the
1640 * stack and only adjust the stack pointer when it knows how big the
1641 * string is.  Stackblock (defined in stack.h) returns a pointer to a block
1642 * of space on top of the stack and stackblocklen returns the length of
1643 * this block.  Growstackblock will grow this space by at least one byte,
1644 * possibly moving it (like realloc).  Grabstackblock actually allocates the
1645 * part of the block that has been used.
1646 */
1647static void
1648growstackblock(void)
1649{
1650        size_t newlen;
1651
1652        newlen = g_stacknleft * 2;
1653        if (newlen < g_stacknleft)
1654                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1655        if (newlen < 128)
1656                newlen += 128;
1657
1658        if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1659                struct stack_block *sp;
1660                struct stack_block *prevstackp;
1661                size_t grosslen;
1662
1663                INT_OFF;
1664                sp = g_stackp;
1665                prevstackp = sp->prev;
1666                grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1667                sp = ckrealloc(sp, grosslen);
1668                sp->prev = prevstackp;
1669                g_stackp = sp;
1670                g_stacknxt = sp->space;
1671                g_stacknleft = newlen;
1672                sstrend = sp->space + newlen;
1673                INT_ON;
1674        } else {
1675                char *oldspace = g_stacknxt;
1676                size_t oldlen = g_stacknleft;
1677                char *p = stalloc(newlen);
1678
1679                /* free the space we just allocated */
1680                g_stacknxt = memcpy(p, oldspace, oldlen);
1681                g_stacknleft += newlen;
1682        }
1683}
1684
1685/*
1686 * The following routines are somewhat easier to use than the above.
1687 * The user declares a variable of type STACKSTR, which may be declared
1688 * to be a register.  The macro STARTSTACKSTR initializes things.  Then
1689 * the user uses the macro STPUTC to add characters to the string.  In
1690 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1691 * grown as necessary.  When the user is done, she can just leave the
1692 * string there and refer to it using stackblock().  Or she can allocate
1693 * the space for it using grabstackstr().  If it is necessary to allow
1694 * someone else to use the stack temporarily and then continue to grow
1695 * the string, the user should use grabstack to allocate the space, and
1696 * then call ungrabstr(p) to return to the previous mode of operation.
1697 *
1698 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1699 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1700 * is space for at least one character.
1701 */
1702static void *
1703growstackstr(void)
1704{
1705        size_t len = stackblocksize();
1706        growstackblock();
1707        return (char *)stackblock() + len;
1708}
1709
1710/*
1711 * Called from CHECKSTRSPACE.
1712 */
1713static char *
1714makestrspace(size_t newlen, char *p)
1715{
1716        size_t len = p - g_stacknxt;
1717        size_t size;
1718
1719        for (;;) {
1720                size_t nleft;
1721
1722                size = stackblocksize();
1723                nleft = size - len;
1724                if (nleft >= newlen)
1725                        break;
1726                growstackblock();
1727        }
1728        return (char *)stackblock() + len;
1729}
1730
1731static char *
1732stack_nputstr(const char *s, size_t n, char *p)
1733{
1734        p = makestrspace(n, p);
1735        p = (char *)mempcpy(p, s, n);
1736        return p;
1737}
1738
1739static char *
1740stack_putstr(const char *s, char *p)
1741{
1742        return stack_nputstr(s, strlen(s), p);
1743}
1744
1745static char *
1746_STPUTC(int c, char *p)
1747{
1748        if (p == sstrend)
1749                p = growstackstr();
1750        *p++ = c;
1751        return p;
1752}
1753
1754#define STARTSTACKSTR(p)        ((p) = stackblock())
1755#define STPUTC(c, p)            ((p) = _STPUTC((c), (p)))
1756#define CHECKSTRSPACE(n, p) do { \
1757        char *q = (p); \
1758        size_t l = (n); \
1759        size_t m = sstrend - q; \
1760        if (l > m) \
1761                (p) = makestrspace(l, q); \
1762} while (0)
1763#define USTPUTC(c, p)           (*(p)++ = (c))
1764#define STACKSTRNUL(p) do { \
1765        if ((p) == sstrend) \
1766                (p) = growstackstr(); \
1767        *(p) = '\0'; \
1768} while (0)
1769#define STUNPUTC(p)             (--(p))
1770#define STTOPC(p)               ((p)[-1])
1771#define STADJUST(amount, p)     ((p) += (amount))
1772
1773#define grabstackstr(p)         stalloc((char *)(p) - (char *)stackblock())
1774#define ungrabstackstr(s, p)    stunalloc(s)
1775#define stackstrend()           ((void *)sstrend)
1776
1777
1778/* ============ String helpers */
1779
1780/*
1781 * prefix -- see if pfx is a prefix of string.
1782 */
1783static char *
1784prefix(const char *string, const char *pfx)
1785{
1786        while (*pfx) {
1787                if (*pfx++ != *string++)
1788                        return NULL;
1789        }
1790        return (char *) string;
1791}
1792
1793/*
1794 * Check for a valid number.  This should be elsewhere.
1795 */
1796static int
1797is_number(const char *p)
1798{
1799        do {
1800                if (!isdigit(*p))
1801                        return 0;
1802        } while (*++p != '\0');
1803        return 1;
1804}
1805
1806/*
1807 * Convert a string of digits to an integer, printing an error message on
1808 * failure.
1809 */
1810static int
1811number(const char *s)
1812{
1813        if (!is_number(s))
1814                ash_msg_and_raise_error(msg_illnum, s);
1815        return atoi(s);
1816}
1817
1818/*
1819 * Produce a single quoted string suitable as input to the shell.
1820 * The return string is allocated on the stack.
1821 */
1822static char *
1823single_quote(const char *s)
1824{
1825        char *p;
1826
1827        STARTSTACKSTR(p);
1828
1829        do {
1830                char *q;
1831                size_t len;
1832
1833                len = strchrnul(s, '\'') - s;
1834
1835                q = p = makestrspace(len + 3, p);
1836
1837                *q++ = '\'';
1838                q = (char *)mempcpy(q, s, len);
1839                *q++ = '\'';
1840                s += len;
1841
1842                STADJUST(q - p, p);
1843
1844                if (*s != '\'')
1845                        break;
1846                len = 0;
1847                do len++; while (*++s == '\'');
1848
1849                q = p = makestrspace(len + 3, p);
1850
1851                *q++ = '"';
1852                q = (char *)mempcpy(q, s - len, len);
1853                *q++ = '"';
1854
1855                STADJUST(q - p, p);
1856        } while (*s);
1857
1858        USTPUTC('\0', p);
1859
1860        return stackblock();
1861}
1862
1863/*
1864 * Produce a possibly single quoted string suitable as input to the shell.
1865 * If quoting was done, the return string is allocated on the stack,
1866 * otherwise a pointer to the original string is returned.
1867 */
1868static const char *
1869maybe_single_quote(const char *s)
1870{
1871        const char *p = s;
1872
1873        while (*p) {
1874                /* Assuming ACSII */
1875                /* quote ctrl_chars space !"#$%&'()* */
1876                if (*p < '+')
1877                        goto need_quoting;
1878                /* quote ;<=>? */
1879                if (*p >= ';' && *p <= '?')
1880                        goto need_quoting;
1881                /* quote `[\ */
1882                if (*p == '`')
1883                        goto need_quoting;
1884                if (*p == '[')
1885                        goto need_quoting;
1886                if (*p == '\\')
1887                        goto need_quoting;
1888                /* quote {|}~ DEL and high bytes */
1889                if (*p > 'z')
1890                        goto need_quoting;
1891                /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1892                /* TODO: maybe avoid quoting % */
1893                p++;
1894        }
1895        return s;
1896
1897 need_quoting:
1898        return single_quote(s);
1899}
1900
1901
1902/* ============ nextopt */
1903
1904static char **argptr;                  /* argument list for builtin commands */
1905static char *optionarg;                /* set by nextopt (like getopt) */
1906static char *optptr;                   /* used by nextopt */
1907
1908/*
1909 * XXX - should get rid of. Have all builtins use getopt(3).
1910 * The library getopt must have the BSD extension static variable
1911 * "optreset", otherwise it can't be used within the shell safely.
1912 *
1913 * Standard option processing (a la getopt) for builtin routines.
1914 * The only argument that is passed to nextopt is the option string;
1915 * the other arguments are unnecessary. It returns the character,
1916 * or '\0' on end of input.
1917 */
1918static int
1919nextopt(const char *optstring)
1920{
1921        char *p;
1922        const char *q;
1923        char c;
1924
1925        p = optptr;
1926        if (p == NULL || *p == '\0') {
1927                /* We ate entire "-param", take next one */
1928                p = *argptr;
1929                if (p == NULL)
1930                        return '\0';
1931                if (*p != '-')
1932                        return '\0';
1933                if (*++p == '\0') /* just "-" ? */
1934                        return '\0';
1935                argptr++;
1936                if (LONE_DASH(p)) /* "--" ? */
1937                        return '\0';
1938                /* p => next "-param" */
1939        }
1940        /* p => some option char in the middle of a "-param" */
1941        c = *p++;
1942        for (q = optstring; *q != c;) {
1943                if (*q == '\0')
1944                        ash_msg_and_raise_error("illegal option -%c", c);
1945                if (*++q == ':')
1946                        q++;
1947        }
1948        if (*++q == ':') {
1949                if (*p == '\0') {
1950                        p = *argptr++;
1951                        if (p == NULL)
1952                                ash_msg_and_raise_error("no arg for -%c option", c);
1953                }
1954                optionarg = p;
1955                p = NULL;
1956        }
1957        optptr = p;
1958        return c;
1959}
1960
1961
1962/* ============ Shell variables */
1963
1964struct shparam {
1965        int nparam;             /* # of positional parameters (without $0) */
1966#if ENABLE_ASH_GETOPTS
1967        int optind;             /* next parameter to be processed by getopts */
1968        int optoff;             /* used by getopts */
1969#endif
1970        unsigned char malloced; /* if parameter list dynamically allocated */
1971        char **p;               /* parameter list */
1972};
1973
1974/*
1975 * Free the list of positional parameters.
1976 */
1977static void
1978freeparam(volatile struct shparam *param)
1979{
1980        if (param->malloced) {
1981                char **ap, **ap1;
1982                ap = ap1 = param->p;
1983                while (*ap)
1984                        free(*ap++);
1985                free(ap1);
1986        }
1987}
1988
1989#if ENABLE_ASH_GETOPTS
1990static void FAST_FUNC getoptsreset(const char *value);
1991#endif
1992
1993struct var {
1994        struct var *next;               /* next entry in hash list */
1995        int flags;                      /* flags are defined above */
1996        const char *var_text;           /* name=value */
1997        void (*var_func)(const char *) FAST_FUNC; /* function to be called when  */
1998                                        /* the variable gets set/unset */
1999};
2000
2001struct localvar {
2002        struct localvar *next;          /* next local variable in list */
2003        struct var *vp;                 /* the variable that was made local */
2004        int flags;                      /* saved flags */
2005        const char *text;               /* saved text */
2006};
2007
2008/* flags */
2009#define VEXPORT         0x01    /* variable is exported */
2010#define VREADONLY       0x02    /* variable cannot be modified */
2011#define VSTRFIXED       0x04    /* variable struct is statically allocated */
2012#define VTEXTFIXED      0x08    /* text is statically allocated */
2013#define VSTACK          0x10    /* text is allocated on the stack */
2014#define VUNSET          0x20    /* the variable is not set */
2015#define VNOFUNC         0x40    /* don't call the callback function */
2016#define VNOSET          0x80    /* do not set variable - just readonly test */
2017#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
2018#if ENABLE_ASH_RANDOM_SUPPORT
2019# define VDYNAMIC       0x200   /* dynamic variable */
2020#else
2021# define VDYNAMIC       0
2022#endif
2023
2024
2025/* Need to be before varinit_data[] */
2026#if ENABLE_LOCALE_SUPPORT
2027static void FAST_FUNC
2028change_lc_all(const char *value)
2029{
2030        if (value && *value != '\0')
2031                setlocale(LC_ALL, value);
2032}
2033static void FAST_FUNC
2034change_lc_ctype(const char *value)
2035{
2036        if (value && *value != '\0')
2037                setlocale(LC_CTYPE, value);
2038}
2039#endif
2040#if ENABLE_ASH_MAIL
2041static void chkmail(void);
2042static void changemail(const char *var_value) FAST_FUNC;
2043#else
2044# define chkmail()  ((void)0)
2045#endif
2046static void changepath(const char *) FAST_FUNC;
2047#if ENABLE_ASH_RANDOM_SUPPORT
2048static void change_random(const char *) FAST_FUNC;
2049#endif
2050
2051static const struct {
2052        int flags;
2053        const char *var_text;
2054        void (*var_func)(const char *) FAST_FUNC;
2055} varinit_data[] = {
2056        /*
2057         * Note: VEXPORT would not work correctly here for NOFORK applets:
2058         * some environment strings may be constant.
2059         */
2060        { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
2061#if ENABLE_ASH_MAIL
2062        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL"      , changemail      },
2063        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH"  , changemail      },
2064#endif
2065        { VSTRFIXED|VTEXTFIXED       , bb_PATH_root_path, changepath },
2066        { VSTRFIXED|VTEXTFIXED       , "PS1=$ "    , NULL            },
2067        { VSTRFIXED|VTEXTFIXED       , "PS2=> "    , NULL            },
2068        { VSTRFIXED|VTEXTFIXED       , "PS4=+ "    , NULL            },
2069#if ENABLE_ASH_GETOPTS
2070        { VSTRFIXED|VTEXTFIXED       , defoptindvar, getoptsreset    },
2071#endif
2072        { VSTRFIXED|VTEXTFIXED       , NULL /* inited to linenovar */, NULL },
2073#if ENABLE_ASH_RANDOM_SUPPORT
2074        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2075#endif
2076#if ENABLE_LOCALE_SUPPORT
2077        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL"    , change_lc_all   },
2078        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE"  , change_lc_ctype },
2079#endif
2080#if ENABLE_FEATURE_EDITING_SAVEHISTORY
2081        { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE"  , NULL            },
2082#endif
2083};
2084
2085struct redirtab;
2086
2087struct globals_var {
2088        struct shparam shellparam;      /* $@ current positional parameters */
2089        struct redirtab *redirlist;
2090        int preverrout_fd;   /* stderr fd: usually 2, unless redirect moved it */
2091        struct var *vartab[VTABSIZE];
2092        struct var varinit[ARRAY_SIZE(varinit_data)];
2093        int lineno;
2094        char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2095};
2096extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2097#define G_var (*ash_ptr_to_globals_var)
2098#define shellparam    (G_var.shellparam   )
2099//#define redirlist     (G_var.redirlist    )
2100#define preverrout_fd (G_var.preverrout_fd)
2101#define vartab        (G_var.vartab       )
2102#define varinit       (G_var.varinit      )
2103#define lineno        (G_var.lineno       )
2104#define linenovar     (G_var.linenovar    )
2105#define vifs      varinit[0]
2106#if ENABLE_ASH_MAIL
2107# define vmail    (&vifs)[1]
2108# define vmpath   (&vmail)[1]
2109# define vpath    (&vmpath)[1]
2110#else
2111# define vpath    (&vifs)[1]
2112#endif
2113#define vps1      (&vpath)[1]
2114#define vps2      (&vps1)[1]
2115#define vps4      (&vps2)[1]
2116#if ENABLE_ASH_GETOPTS
2117# define voptind  (&vps4)[1]
2118# define vlineno  (&voptind)[1]
2119# if ENABLE_ASH_RANDOM_SUPPORT
2120#  define vrandom (&vlineno)[1]
2121# endif
2122#else
2123# define vlineno  (&vps4)[1]
2124# if ENABLE_ASH_RANDOM_SUPPORT
2125#  define vrandom (&vlineno)[1]
2126# endif
2127#endif
2128#define INIT_G_var() do { \
2129        unsigned i; \
2130        (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2131        barrier(); \
2132        for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2133                varinit[i].flags    = varinit_data[i].flags; \
2134                varinit[i].var_text = varinit_data[i].var_text; \
2135                varinit[i].var_func = varinit_data[i].var_func; \
2136        } \
2137        strcpy(linenovar, "LINENO="); \
2138        vlineno.var_text = linenovar; \
2139} while (0)
2140
2141/*
2142 * The following macros access the values of the above variables.
2143 * They have to skip over the name.  They return the null string
2144 * for unset variables.
2145 */
2146#define ifsval()        (vifs.var_text + 4)
2147#define ifsset()        ((vifs.flags & VUNSET) == 0)
2148#if ENABLE_ASH_MAIL
2149# define mailval()      (vmail.var_text + 5)
2150# define mpathval()     (vmpath.var_text + 9)
2151# define mpathset()     ((vmpath.flags & VUNSET) == 0)
2152#endif
2153#define pathval()       (vpath.var_text + 5)
2154#define ps1val()        (vps1.var_text + 4)
2155#define ps2val()        (vps2.var_text + 4)
2156#define ps4val()        (vps4.var_text + 4)
2157#if ENABLE_ASH_GETOPTS
2158# define optindval()    (voptind.var_text + 7)
2159#endif
2160
2161#if ENABLE_ASH_GETOPTS
2162static void FAST_FUNC
2163getoptsreset(const char *value)
2164{
2165        shellparam.optind = 1;
2166        if (is_number(value))
2167                shellparam.optind = number(value) ?: 1;
2168        shellparam.optoff = -1;
2169}
2170#endif
2171
2172/*
2173 * Compares two strings up to the first = or '\0'.  The first
2174 * string must be terminated by '='; the second may be terminated by
2175 * either '=' or '\0'.
2176 */
2177static int
2178varcmp(const char *p, const char *q)
2179{
2180        int c, d;
2181
2182        while ((c = *p) == (d = *q)) {
2183                if (c == '\0' || c == '=')
2184                        goto out;
2185                p++;
2186                q++;
2187        }
2188        if (c == '=')
2189                c = '\0';
2190        if (d == '=')
2191                d = '\0';
2192 out:
2193        return c - d;
2194}
2195
2196/*
2197 * Find the appropriate entry in the hash table from the name.
2198 */
2199static struct var **
2200hashvar(const char *p)
2201{
2202        unsigned hashval;
2203
2204        hashval = ((unsigned char) *p) << 4;
2205        while (*p && *p != '=')
2206                hashval += (unsigned char) *p++;
2207        return &vartab[hashval % VTABSIZE];
2208}
2209
2210static int
2211vpcmp(const void *a, const void *b)
2212{
2213        return varcmp(*(const char **)a, *(const char **)b);
2214}
2215
2216/*
2217 * This routine initializes the builtin variables.
2218 */
2219static void
2220initvar(void)
2221{
2222        struct var *vp;
2223        struct var *end;
2224        struct var **vpp;
2225
2226        /*
2227         * PS1 depends on uid
2228         */
2229#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2230        vps1.var_text = "PS1=\\w \\$ ";
2231#else
2232        if (!geteuid())
2233                vps1.var_text = "PS1=# ";
2234#endif
2235        vp = varinit;
2236        end = vp + ARRAY_SIZE(varinit);
2237        do {
2238                vpp = hashvar(vp->var_text);
2239                vp->next = *vpp;
2240                *vpp = vp;
2241        } while (++vp < end);
2242}
2243
2244static struct var **
2245findvar(struct var **vpp, const char *name)
2246{
2247        for (; *vpp; vpp = &(*vpp)->next) {
2248                if (varcmp((*vpp)->var_text, name) == 0) {
2249                        break;
2250                }
2251        }
2252        return vpp;
2253}
2254
2255/*
2256 * Find the value of a variable.  Returns NULL if not set.
2257 */
2258static const char* FAST_FUNC
2259lookupvar(const char *name)
2260{
2261        struct var *v;
2262
2263        v = *findvar(hashvar(name), name);
2264        if (v) {
2265#if ENABLE_ASH_RANDOM_SUPPORT
2266        /*
2267         * Dynamic variables are implemented roughly the same way they are
2268         * in bash. Namely, they're "special" so long as they aren't unset.
2269         * As soon as they're unset, they're no longer dynamic, and dynamic
2270         * lookup will no longer happen at that point. -- PFM.
2271         */
2272                if (v->flags & VDYNAMIC)
2273                        v->var_func(NULL);
2274#endif
2275                if (!(v->flags & VUNSET)) {
2276                        if (v == &vlineno && v->var_text == linenovar) {
2277                                fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2278                        }
2279                        return var_end(v->var_text);
2280                }
2281        }
2282        return NULL;
2283}
2284
2285#if ENABLE_UNICODE_SUPPORT
2286static void
2287reinit_unicode_for_ash(void)
2288{
2289        /* Unicode support should be activated even if LANG is set
2290         * _during_ shell execution, not only if it was set when
2291         * shell was started. Therefore, re-check LANG every time:
2292         */
2293        if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2294         || ENABLE_UNICODE_USING_LOCALE
2295        ) {
2296                const char *s = lookupvar("LC_ALL");
2297                if (!s) s = lookupvar("LC_CTYPE");
2298                if (!s) s = lookupvar("LANG");
2299                reinit_unicode(s);
2300        }
2301}
2302#else
2303# define reinit_unicode_for_ash() ((void)0)
2304#endif
2305
2306/*
2307 * Search the environment of a builtin command.
2308 */
2309static ALWAYS_INLINE const char *
2310bltinlookup(const char *name)
2311{
2312        return lookupvar(name);
2313}
2314
2315/*
2316 * Same as setvar except that the variable and value are passed in
2317 * the first argument as name=value.  Since the first argument will
2318 * be actually stored in the table, it should not be a string that
2319 * will go away.
2320 * Called with interrupts off.
2321 */
2322static struct var *
2323setvareq(char *s, int flags)
2324{
2325        struct var *vp, **vpp;
2326
2327        vpp = hashvar(s);
2328        flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2329        vpp = findvar(vpp, s);
2330        vp = *vpp;
2331        if (vp) {
2332                if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2333                        const char *n;
2334
2335                        if (flags & VNOSAVE)
2336                                free(s);
2337                        n = vp->var_text;
2338                        exitstatus = 1;
2339                        ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2340                }
2341
2342                if (flags & VNOSET)
2343                        goto out;
2344
2345                if (vp->var_func && !(flags & VNOFUNC))
2346                        vp->var_func(var_end(s));
2347
2348                if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2349                        free((char*)vp->var_text);
2350
2351                if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2352                        *vpp = vp->next;
2353                        free(vp);
2354 out_free:
2355                        if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2356                                free(s);
2357                        goto out;
2358                }
2359
2360                flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2361        } else {
2362                /* variable s is not found */
2363                if (flags & VNOSET)
2364                        goto out;
2365                if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2366                        goto out_free;
2367                vp = ckzalloc(sizeof(*vp));
2368                vp->next = *vpp;
2369                /*vp->func = NULL; - ckzalloc did it */
2370                *vpp = vp;
2371        }
2372        if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2373                s = ckstrdup(s);
2374        vp->var_text = s;
2375        vp->flags = flags;
2376
2377 out:
2378        return vp;
2379}
2380
2381/*
2382 * Set the value of a variable.  The flags argument is ored with the
2383 * flags of the variable.  If val is NULL, the variable is unset.
2384 */
2385static struct var *
2386setvar(const char *name, const char *val, int flags)
2387{
2388        const char *q;
2389        char *p;
2390        char *nameeq;
2391        size_t namelen;
2392        size_t vallen;
2393        struct var *vp;
2394
2395        q = endofname(name);
2396        p = strchrnul(q, '=');
2397        namelen = p - name;
2398        if (!namelen || p != q)
2399                ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2400        vallen = 0;
2401        if (val == NULL) {
2402                flags |= VUNSET;
2403        } else {
2404                vallen = strlen(val);
2405        }
2406
2407        INT_OFF;
2408        nameeq = ckmalloc(namelen + vallen + 2);
2409        p = mempcpy(nameeq, name, namelen);
2410        if (val) {
2411                *p++ = '=';
2412                p = mempcpy(p, val, vallen);
2413        }
2414        *p = '\0';
2415        vp = setvareq(nameeq, flags | VNOSAVE);
2416        INT_ON;
2417
2418        return vp;
2419}
2420
2421static void FAST_FUNC
2422setvar0(const char *name, const char *val)
2423{
2424        setvar(name, val, 0);
2425}
2426
2427/*
2428 * Unset the specified variable.
2429 */
2430static void
2431unsetvar(const char *s)
2432{
2433        setvar(s, NULL, 0);
2434}
2435
2436/*
2437 * Process a linked list of variable assignments.
2438 */
2439static void
2440listsetvar(struct strlist *list_set_var, int flags)
2441{
2442        struct strlist *lp = list_set_var;
2443
2444        if (!lp)
2445                return;
2446        INT_OFF;
2447        do {
2448                setvareq(lp->text, flags);
2449                lp = lp->next;
2450        } while (lp);
2451        INT_ON;
2452}
2453
2454/*
2455 * Generate a list of variables satisfying the given conditions.
2456 */
2457#if !ENABLE_FEATURE_SH_NOFORK
2458# define listvars(on, off, lp, end) listvars(on, off, end)
2459#endif
2460static char **
2461listvars(int on, int off, struct strlist *lp, char ***end)
2462{
2463        struct var **vpp;
2464        struct var *vp;
2465        char **ep;
2466        int mask;
2467
2468        STARTSTACKSTR(ep);
2469        vpp = vartab;
2470        mask = on | off;
2471        do {
2472                for (vp = *vpp; vp; vp = vp->next) {
2473                        if ((vp->flags & mask) == on) {
2474#if ENABLE_FEATURE_SH_NOFORK
2475                                /* If variable with the same name is both
2476                                 * exported and temporarily set for a command:
2477                                 *  export ZVAR=5
2478                                 *  ZVAR=6 printenv
2479                                 * then "ZVAR=6" will be both in vartab and
2480                                 * lp lists. Do not pass it twice to printenv.
2481                                 */
2482                                struct strlist *lp1 = lp;
2483                                while (lp1) {
2484                                        if (strcmp(lp1->text, vp->var_text) == 0)
2485                                                goto skip;
2486                                        lp1 = lp1->next;
2487                                }
2488#endif
2489                                if (ep == stackstrend())
2490                                        ep = growstackstr();
2491                                *ep++ = (char*)vp->var_text;
2492#if ENABLE_FEATURE_SH_NOFORK
2493 skip: ;
2494#endif
2495                        }
2496                }
2497        } while (++vpp < vartab + VTABSIZE);
2498
2499#if ENABLE_FEATURE_SH_NOFORK
2500        while (lp) {
2501                if (ep == stackstrend())
2502                        ep = growstackstr();
2503                *ep++ = lp->text;
2504                lp = lp->next;
2505        }
2506#endif
2507
2508        if (ep == stackstrend())
2509                ep = growstackstr();
2510        if (end)
2511                *end = ep;
2512        *ep++ = NULL;
2513        return grabstackstr(ep);
2514}
2515
2516
2517/* ============ Path search helper
2518 *
2519 * The variable path (passed by reference) should be set to the start
2520 * of the path before the first call; path_advance will update
2521 * this value as it proceeds.  Successive calls to path_advance will return
2522 * the possible path expansions in sequence.  If an option (indicated by
2523 * a percent sign) appears in the path entry then the global variable
2524 * pathopt will be set to point to it; otherwise pathopt will be set to
2525 * NULL.
2526 */
2527static const char *pathopt;     /* set by path_advance */
2528
2529static char *
2530path_advance(const char **path, const char *name)
2531{
2532        const char *p;
2533        char *q;
2534        const char *start;
2535        size_t len;
2536
2537        if (*path == NULL)
2538                return NULL;
2539        start = *path;
2540        for (p = start; *p && *p != ':' && *p != '%'; p++)
2541                continue;
2542        len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
2543        while (stackblocksize() < len)
2544                growstackblock();
2545        q = stackblock();
2546        if (p != start) {
2547                q = mempcpy(q, start, p - start);
2548                *q++ = '/';
2549        }
2550        strcpy(q, name);
2551        pathopt = NULL;
2552        if (*p == '%') {
2553                pathopt = ++p;
2554                while (*p && *p != ':')
2555                        p++;
2556        }
2557        if (*p == ':')
2558                *path = p + 1;
2559        else
2560                *path = NULL;
2561        return stalloc(len);
2562}
2563
2564
2565/* ============ Prompt */
2566
2567static smallint doprompt;                   /* if set, prompt the user */
2568static smallint needprompt;                 /* true if interactive and at start of line */
2569
2570#if ENABLE_FEATURE_EDITING
2571static line_input_t *line_input_state;
2572static const char *cmdedit_prompt;
2573static void
2574putprompt(const char *s)
2575{
2576        if (ENABLE_ASH_EXPAND_PRMT) {
2577                free((char*)cmdedit_prompt);
2578                cmdedit_prompt = ckstrdup(s);
2579                return;
2580        }
2581        cmdedit_prompt = s;
2582}
2583#else
2584static void
2585putprompt(const char *s)
2586{
2587        out2str(s);
2588}
2589#endif
2590
2591/* expandstr() needs parsing machinery, so it is far away ahead... */
2592static const char *expandstr(const char *ps, int syntax_type);
2593/* Values for syntax param */
2594#define BASESYNTAX 0    /* not in quotes */
2595#define DQSYNTAX   1    /* in double quotes */
2596#define SQSYNTAX   2    /* in single quotes */
2597#define ARISYNTAX  3    /* in arithmetic */
2598#if ENABLE_ASH_EXPAND_PRMT
2599# define PSSYNTAX  4    /* prompt. never passed to SIT() */
2600#endif
2601/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
2602
2603/*
2604 * called by editline -- any expansions to the prompt should be added here.
2605 */
2606static void
2607setprompt_if(smallint do_set, int whichprompt)
2608{
2609        const char *prompt;
2610        IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2611
2612        if (!do_set)
2613                return;
2614
2615        needprompt = 0;
2616
2617        switch (whichprompt) {
2618        case 1:
2619                prompt = ps1val();
2620                break;
2621        case 2:
2622                prompt = ps2val();
2623                break;
2624        default:                        /* 0 */
2625                prompt = nullstr;
2626        }
2627#if ENABLE_ASH_EXPAND_PRMT
2628        pushstackmark(&smark, stackblocksize());
2629        putprompt(expandstr(prompt, PSSYNTAX));
2630        popstackmark(&smark);
2631#else
2632        putprompt(prompt);
2633#endif
2634}
2635
2636
2637/* ============ The cd and pwd commands */
2638
2639#define CD_PHYSICAL 1
2640#define CD_PRINT 2
2641
2642static int
2643cdopt(void)
2644{
2645        int flags = 0;
2646        int i, j;
2647
2648        j = 'L';
2649        while ((i = nextopt("LP")) != '\0') {
2650                if (i != j) {
2651                        flags ^= CD_PHYSICAL;
2652                        j = i;
2653                }
2654        }
2655
2656        return flags;
2657}
2658
2659/*
2660 * Update curdir (the name of the current directory) in response to a
2661 * cd command.
2662 */
2663static const char *
2664updatepwd(const char *dir)
2665{
2666        char *new;
2667        char *p;
2668        char *cdcomppath;
2669        const char *lim;
2670
2671        cdcomppath = sstrdup(dir);
2672        STARTSTACKSTR(new);
2673        if (*dir != '/') {
2674                if (curdir == nullstr)
2675                        return 0;
2676                new = stack_putstr(curdir, new);
2677        }
2678        new = makestrspace(strlen(dir) + 2, new);
2679        lim = (char *)stackblock() + 1;
2680        if (*dir != '/') {
2681                if (new[-1] != '/')
2682                        USTPUTC('/', new);
2683                if (new > lim && *lim == '/')
2684                        lim++;
2685        } else {
2686                USTPUTC('/', new);
2687                cdcomppath++;
2688                if (dir[1] == '/' && dir[2] != '/') {
2689                        USTPUTC('/', new);
2690                        cdcomppath++;
2691                        lim++;
2692                }
2693        }
2694        p = strtok(cdcomppath, "/");
2695        while (p) {
2696                switch (*p) {
2697                case '.':
2698                        if (p[1] == '.' && p[2] == '\0') {
2699                                while (new > lim) {
2700                                        STUNPUTC(new);
2701                                        if (new[-1] == '/')
2702                                                break;
2703                                }
2704                                break;
2705                        }
2706                        if (p[1] == '\0')
2707                                break;
2708                        /* fall through */
2709                default:
2710                        new = stack_putstr(p, new);
2711                        USTPUTC('/', new);
2712                }
2713                p = strtok(NULL, "/");
2714        }
2715        if (new > lim)
2716                STUNPUTC(new);
2717        *new = 0;
2718        return stackblock();
2719}
2720
2721/*
2722 * Find out what the current directory is. If we already know the current
2723 * directory, this routine returns immediately.
2724 */
2725static char *
2726getpwd(void)
2727{
2728        char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2729        return dir ? dir : nullstr;
2730}
2731
2732static void
2733setpwd(const char *val, int setold)
2734{
2735        char *oldcur, *dir;
2736
2737        oldcur = dir = curdir;
2738
2739        if (setold) {
2740                setvar("OLDPWD", oldcur, VEXPORT);
2741        }
2742        INT_OFF;
2743        if (physdir != nullstr) {
2744                if (physdir != oldcur)
2745                        free(physdir);
2746                physdir = nullstr;
2747        }
2748        if (oldcur == val || !val) {
2749                char *s = getpwd();
2750                physdir = s;
2751                if (!val)
2752                        dir = s;
2753        } else
2754                dir = ckstrdup(val);
2755        if (oldcur != dir && oldcur != nullstr) {
2756                free(oldcur);
2757        }
2758        curdir = dir;
2759        INT_ON;
2760        setvar("PWD", dir, VEXPORT);
2761}
2762
2763static void hashcd(void);
2764
2765/*
2766 * Actually do the chdir.  We also call hashcd to let other routines
2767 * know that the current directory has changed.
2768 */
2769static int
2770docd(const char *dest, int flags)
2771{
2772        const char *dir = NULL;
2773        int err;
2774
2775        TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2776
2777        INT_OFF;
2778        if (!(flags & CD_PHYSICAL)) {
2779                dir = updatepwd(dest);
2780                if (dir)
2781                        dest = dir;
2782        }
2783        err = chdir(dest);
2784        if (err)
2785                goto out;
2786        setpwd(dir, 1);
2787        hashcd();
2788 out:
2789        INT_ON;
2790        return err;
2791}
2792
2793static int FAST_FUNC
2794cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2795{
2796        const char *dest;
2797        const char *path;
2798        const char *p;
2799        char c;
2800        struct stat statb;
2801        int flags;
2802
2803        flags = cdopt();
2804        dest = *argptr;
2805        if (!dest)
2806                dest = bltinlookup("HOME");
2807        else if (LONE_DASH(dest)) {
2808                dest = bltinlookup("OLDPWD");
2809                flags |= CD_PRINT;
2810        }
2811        if (!dest)
2812                dest = nullstr;
2813        if (*dest == '/')
2814                goto step6;
2815        if (*dest == '.') {
2816                c = dest[1];
2817 dotdot:
2818                switch (c) {
2819                case '\0':
2820                case '/':
2821                        goto step6;
2822                case '.':
2823                        c = dest[2];
2824                        if (c != '.')
2825                                goto dotdot;
2826                }
2827        }
2828        if (!*dest)
2829                dest = ".";
2830        path = bltinlookup("CDPATH");
2831        while (path) {
2832                c = *path;
2833                p = path_advance(&path, dest);
2834                if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2835                        if (c && c != ':')
2836                                flags |= CD_PRINT;
2837 docd:
2838                        if (!docd(p, flags))
2839                                goto out;
2840                        goto err;
2841                }
2842        }
2843
2844 step6:
2845        p = dest;
2846        goto docd;
2847
2848 err:
2849        ash_msg_and_raise_perror("can't cd to %s", dest);
2850        /* NOTREACHED */
2851 out:
2852        if (flags & CD_PRINT)
2853                out1fmt("%s\n", curdir);
2854        return 0;
2855}
2856
2857static int FAST_FUNC
2858pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2859{
2860        int flags;
2861        const char *dir = curdir;
2862
2863        flags = cdopt();
2864        if (flags) {
2865                if (physdir == nullstr)
2866                        setpwd(dir, 0);
2867                dir = physdir;
2868        }
2869        out1fmt("%s\n", dir);
2870        return 0;
2871}
2872
2873
2874/* ============ ... */
2875
2876
2877#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2878
2879/* Syntax classes */
2880#define CWORD     0             /* character is nothing special */
2881#define CNL       1             /* newline character */
2882#define CBACK     2             /* a backslash character */
2883#define CSQUOTE   3             /* single quote */
2884#define CDQUOTE   4             /* double quote */
2885#define CENDQUOTE 5             /* a terminating quote */
2886#define CBQUOTE   6             /* backwards single quote */
2887#define CVAR      7             /* a dollar sign */
2888#define CENDVAR   8             /* a '}' character */
2889#define CLP       9             /* a left paren in arithmetic */
2890#define CRP      10             /* a right paren in arithmetic */
2891#define CENDFILE 11             /* end of file */
2892#define CCTL     12             /* like CWORD, except it must be escaped */
2893#define CSPCL    13             /* these terminate a word */
2894#define CIGN     14             /* character should be ignored */
2895
2896#define PEOF     256
2897#if ENABLE_ASH_ALIAS
2898# define PEOA    257
2899#endif
2900
2901#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2902
2903#if ENABLE_FEATURE_SH_MATH
2904# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2905#else
2906# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2907#endif
2908static const uint16_t S_I_T[] ALIGN2 = {
2909#if ENABLE_ASH_ALIAS
2910        SIT_ITEM(CSPCL   , CIGN     , CIGN , CIGN   ),    /* 0, PEOA */
2911#endif
2912        SIT_ITEM(CSPCL   , CWORD    , CWORD, CWORD  ),    /* 1, ' ' */
2913        SIT_ITEM(CNL     , CNL      , CNL  , CNL    ),    /* 2, \n */
2914        SIT_ITEM(CWORD   , CCTL     , CCTL , CWORD  ),    /* 3, !*-/:=?[]~ */
2915        SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD  ),    /* 4, '"' */
2916        SIT_ITEM(CVAR    , CVAR     , CWORD, CVAR   ),    /* 5, $ */
2917        SIT_ITEM(CSQUOTE , CWORD    , CENDQUOTE, CWORD),  /* 6, "'" */
2918        SIT_ITEM(CSPCL   , CWORD    , CWORD, CLP    ),    /* 7, ( */
2919        SIT_ITEM(CSPCL   , CWORD    , CWORD, CRP    ),    /* 8, ) */
2920        SIT_ITEM(CBACK   , CBACK    , CCTL , CBACK  ),    /* 9, \ */
2921        SIT_ITEM(CBQUOTE , CBQUOTE  , CWORD, CBQUOTE),    /* 10, ` */
2922        SIT_ITEM(CENDVAR , CENDVAR  , CWORD, CENDVAR),    /* 11, } */
2923#if !USE_SIT_FUNCTION
2924        SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2925        SIT_ITEM(CWORD   , CWORD    , CWORD, CWORD  ),    /* 13, 0-9A-Za-z */
2926        SIT_ITEM(CCTL    , CCTL     , CCTL , CCTL   )     /* 14, CTLESC ... */
2927#endif
2928#undef SIT_ITEM
2929};
2930/* Constants below must match table above */
2931enum {
2932#if ENABLE_ASH_ALIAS
2933        CSPCL_CIGN_CIGN_CIGN               , /*  0 */
2934#endif
2935        CSPCL_CWORD_CWORD_CWORD            , /*  1 */
2936        CNL_CNL_CNL_CNL                    , /*  2 */
2937        CWORD_CCTL_CCTL_CWORD              , /*  3 */
2938        CDQUOTE_CENDQUOTE_CWORD_CWORD      , /*  4 */
2939        CVAR_CVAR_CWORD_CVAR               , /*  5 */
2940        CSQUOTE_CWORD_CENDQUOTE_CWORD      , /*  6 */
2941        CSPCL_CWORD_CWORD_CLP              , /*  7 */
2942        CSPCL_CWORD_CWORD_CRP              , /*  8 */
2943        CBACK_CBACK_CCTL_CBACK             , /*  9 */
2944        CBQUOTE_CBQUOTE_CWORD_CBQUOTE      , /* 10 */
2945        CENDVAR_CENDVAR_CWORD_CENDVAR      , /* 11 */
2946        CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2947        CWORD_CWORD_CWORD_CWORD            , /* 13 */
2948        CCTL_CCTL_CCTL_CCTL                , /* 14 */
2949};
2950
2951/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2952 * caller must ensure proper cast on it if c is *char_ptr!
2953 */
2954#if USE_SIT_FUNCTION
2955
2956static int
2957SIT(int c, int syntax)
2958{
2959        /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2960        static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2961        /*
2962         * This causes '/' to be prepended with CTLESC in dquoted string,
2963         * making "./file"* treated incorrectly because we feed
2964         * ".\/file*" string to glob(), confusing it (see expandmeta func).
2965         * The "homegrown" glob implementation is okay with that,
2966         * but glibc one isn't. With '/' always treated as CWORD,
2967         * both work fine.
2968         */
2969# if ENABLE_ASH_ALIAS
2970        static const uint8_t syntax_index_table[] ALIGN1 = {
2971                1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
2972                7, 8, 3, 3,/*3,*/3, 1, 1,       /* "()*-/:;<" */
2973                3, 1, 3, 3, 9, 3, 10, 1,        /* "=>?[\\]`|" */
2974                11, 3                           /* "}~" */
2975        };
2976# else
2977        static const uint8_t syntax_index_table[] ALIGN1 = {
2978                0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
2979                6, 7, 2, 2,/*2,*/2, 0, 0,       /* "()*-/:;<" */
2980                2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
2981                10, 2                           /* "}~" */
2982        };
2983# endif
2984        const char *s;
2985        int indx;
2986
2987        if (c == PEOF)
2988                return CENDFILE;
2989# if ENABLE_ASH_ALIAS
2990        if (c == PEOA)
2991                indx = 0;
2992        else
2993# endif
2994        {
2995                /* Cast is purely for paranoia here,
2996                 * just in case someone passed signed char to us */
2997                if ((unsigned char)c >= CTL_FIRST
2998                 && (unsigned char)c <= CTL_LAST
2999                ) {
3000                        return CCTL;
3001                }
3002                s = strchrnul(spec_symbls, c);
3003                if (*s == '\0')
3004                        return CWORD;
3005                indx = syntax_index_table[s - spec_symbls];
3006        }
3007        return (S_I_T[indx] >> (syntax*4)) & 0xf;
3008}
3009
3010#else   /* !USE_SIT_FUNCTION */
3011
3012static const uint8_t syntax_index_table[] ALIGN1 = {
3013        /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
3014        /*   0      */ CWORD_CWORD_CWORD_CWORD,
3015        /*   1      */ CWORD_CWORD_CWORD_CWORD,
3016        /*   2      */ CWORD_CWORD_CWORD_CWORD,
3017        /*   3      */ CWORD_CWORD_CWORD_CWORD,
3018        /*   4      */ CWORD_CWORD_CWORD_CWORD,
3019        /*   5      */ CWORD_CWORD_CWORD_CWORD,
3020        /*   6      */ CWORD_CWORD_CWORD_CWORD,
3021        /*   7      */ CWORD_CWORD_CWORD_CWORD,
3022        /*   8      */ CWORD_CWORD_CWORD_CWORD,
3023        /*   9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3024        /*  10 "\n" */ CNL_CNL_CNL_CNL,
3025        /*  11      */ CWORD_CWORD_CWORD_CWORD,
3026        /*  12      */ CWORD_CWORD_CWORD_CWORD,
3027        /*  13      */ CWORD_CWORD_CWORD_CWORD,
3028        /*  14      */ CWORD_CWORD_CWORD_CWORD,
3029        /*  15      */ CWORD_CWORD_CWORD_CWORD,
3030        /*  16      */ CWORD_CWORD_CWORD_CWORD,
3031        /*  17      */ CWORD_CWORD_CWORD_CWORD,
3032        /*  18      */ CWORD_CWORD_CWORD_CWORD,
3033        /*  19      */ CWORD_CWORD_CWORD_CWORD,
3034        /*  20      */ CWORD_CWORD_CWORD_CWORD,
3035        /*  21      */ CWORD_CWORD_CWORD_CWORD,
3036        /*  22      */ CWORD_CWORD_CWORD_CWORD,
3037        /*  23      */ CWORD_CWORD_CWORD_CWORD,
3038        /*  24      */ CWORD_CWORD_CWORD_CWORD,
3039        /*  25      */ CWORD_CWORD_CWORD_CWORD,
3040        /*  26      */ CWORD_CWORD_CWORD_CWORD,
3041        /*  27      */ CWORD_CWORD_CWORD_CWORD,
3042        /*  28      */ CWORD_CWORD_CWORD_CWORD,
3043        /*  29      */ CWORD_CWORD_CWORD_CWORD,
3044        /*  30      */ CWORD_CWORD_CWORD_CWORD,
3045        /*  31      */ CWORD_CWORD_CWORD_CWORD,
3046        /*  32  " " */ CSPCL_CWORD_CWORD_CWORD,
3047        /*  33  "!" */ CWORD_CCTL_CCTL_CWORD,
3048        /*  34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3049        /*  35  "#" */ CWORD_CWORD_CWORD_CWORD,
3050        /*  36  "$" */ CVAR_CVAR_CWORD_CVAR,
3051        /*  37  "%" */ CWORD_CWORD_CWORD_CWORD,
3052        /*  38  "&" */ CSPCL_CWORD_CWORD_CWORD,
3053        /*  39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3054        /*  40  "(" */ CSPCL_CWORD_CWORD_CLP,
3055        /*  41  ")" */ CSPCL_CWORD_CWORD_CRP,
3056        /*  42  "*" */ CWORD_CCTL_CCTL_CWORD,
3057        /*  43  "+" */ CWORD_CWORD_CWORD_CWORD,
3058        /*  44  "," */ CWORD_CWORD_CWORD_CWORD,
3059        /*  45  "-" */ CWORD_CCTL_CCTL_CWORD,
3060        /*  46  "." */ CWORD_CWORD_CWORD_CWORD,
3061/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3062        /*  47  "/" */ CWORD_CWORD_CWORD_CWORD,
3063        /*  48  "0" */ CWORD_CWORD_CWORD_CWORD,
3064        /*  49  "1" */ CWORD_CWORD_CWORD_CWORD,
3065        /*  50  "2" */ CWORD_CWORD_CWORD_CWORD,
3066        /*  51  "3" */ CWORD_CWORD_CWORD_CWORD,
3067        /*  52  "4" */ CWORD_CWORD_CWORD_CWORD,
3068        /*  53  "5" */ CWORD_CWORD_CWORD_CWORD,
3069        /*  54  "6" */ CWORD_CWORD_CWORD_CWORD,
3070        /*  55  "7" */ CWORD_CWORD_CWORD_CWORD,
3071        /*  56  "8" */ CWORD_CWORD_CWORD_CWORD,
3072        /*  57  "9" */ CWORD_CWORD_CWORD_CWORD,
3073        /*  58  ":" */ CWORD_CCTL_CCTL_CWORD,
3074        /*  59  ";" */ CSPCL_CWORD_CWORD_CWORD,
3075        /*  60  "<" */ CSPCL_CWORD_CWORD_CWORD,
3076        /*  61  "=" */ CWORD_CCTL_CCTL_CWORD,
3077        /*  62  ">" */ CSPCL_CWORD_CWORD_CWORD,
3078        /*  63  "?" */ CWORD_CCTL_CCTL_CWORD,
3079        /*  64  "@" */ CWORD_CWORD_CWORD_CWORD,
3080        /*  65  "A" */ CWORD_CWORD_CWORD_CWORD,
3081        /*  66  "B" */ CWORD_CWORD_CWORD_CWORD,
3082        /*  67  "C" */ CWORD_CWORD_CWORD_CWORD,
3083        /*  68  "D" */ CWORD_CWORD_CWORD_CWORD,
3084        /*  69  "E" */ CWORD_CWORD_CWORD_CWORD,
3085        /*  70  "F" */ CWORD_CWORD_CWORD_CWORD,
3086        /*  71  "G" */ CWORD_CWORD_CWORD_CWORD,
3087        /*  72  "H" */ CWORD_CWORD_CWORD_CWORD,
3088        /*  73  "I" */ CWORD_CWORD_CWORD_CWORD,
3089        /*  74  "J" */ CWORD_CWORD_CWORD_CWORD,
3090        /*  75  "K" */ CWORD_CWORD_CWORD_CWORD,
3091        /*  76  "L" */ CWORD_CWORD_CWORD_CWORD,
3092        /*  77  "M" */ CWORD_CWORD_CWORD_CWORD,
3093        /*  78  "N" */ CWORD_CWORD_CWORD_CWORD,
3094        /*  79  "O" */ CWORD_CWORD_CWORD_CWORD,
3095        /*  80  "P" */ CWORD_CWORD_CWORD_CWORD,
3096        /*  81  "Q" */ CWORD_CWORD_CWORD_CWORD,
3097        /*  82  "R" */ CWORD_CWORD_CWORD_CWORD,
3098        /*  83  "S" */ CWORD_CWORD_CWORD_CWORD,
3099        /*  84  "T" */ CWORD_CWORD_CWORD_CWORD,
3100        /*  85  "U" */ CWORD_CWORD_CWORD_CWORD,
3101        /*  86  "V" */ CWORD_CWORD_CWORD_CWORD,
3102        /*  87  "W" */ CWORD_CWORD_CWORD_CWORD,
3103        /*  88  "X" */ CWORD_CWORD_CWORD_CWORD,
3104        /*  89  "Y" */ CWORD_CWORD_CWORD_CWORD,
3105        /*  90  "Z" */ CWORD_CWORD_CWORD_CWORD,
3106        /*  91  "[" */ CWORD_CCTL_CCTL_CWORD,
3107        /*  92  "\" */ CBACK_CBACK_CCTL_CBACK,
3108        /*  93  "]" */ CWORD_CCTL_CCTL_CWORD,
3109        /*  94  "^" */ CWORD_CWORD_CWORD_CWORD,
3110        /*  95  "_" */ CWORD_CWORD_CWORD_CWORD,
3111        /*  96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3112        /*  97  "a" */ CWORD_CWORD_CWORD_CWORD,
3113        /*  98  "b" */ CWORD_CWORD_CWORD_CWORD,
3114        /*  99  "c" */ CWORD_CWORD_CWORD_CWORD,
3115        /* 100  "d" */ CWORD_CWORD_CWORD_CWORD,
3116        /* 101  "e" */ CWORD_CWORD_CWORD_CWORD,
3117        /* 102  "f" */ CWORD_CWORD_CWORD_CWORD,
3118        /* 103  "g" */ CWORD_CWORD_CWORD_CWORD,
3119        /* 104  "h" */ CWORD_CWORD_CWORD_CWORD,
3120        /* 105  "i" */ CWORD_CWORD_CWORD_CWORD,
3121        /* 106  "j" */ CWORD_CWORD_CWORD_CWORD,
3122        /* 107  "k" */ CWORD_CWORD_CWORD_CWORD,
3123        /* 108  "l" */ CWORD_CWORD_CWORD_CWORD,
3124        /* 109  "m" */ CWORD_CWORD_CWORD_CWORD,
3125        /* 110  "n" */ CWORD_CWORD_CWORD_CWORD,
3126        /* 111  "o" */ CWORD_CWORD_CWORD_CWORD,
3127        /* 112  "p" */ CWORD_CWORD_CWORD_CWORD,
3128        /* 113  "q" */ CWORD_CWORD_CWORD_CWORD,
3129        /* 114  "r" */ CWORD_CWORD_CWORD_CWORD,
3130        /* 115  "s" */ CWORD_CWORD_CWORD_CWORD,
3131        /* 116  "t" */ CWORD_CWORD_CWORD_CWORD,
3132        /* 117  "u" */ CWORD_CWORD_CWORD_CWORD,
3133        /* 118  "v" */ CWORD_CWORD_CWORD_CWORD,
3134        /* 119  "w" */ CWORD_CWORD_CWORD_CWORD,
3135        /* 120  "x" */ CWORD_CWORD_CWORD_CWORD,
3136        /* 121  "y" */ CWORD_CWORD_CWORD_CWORD,
3137        /* 122  "z" */ CWORD_CWORD_CWORD_CWORD,
3138        /* 123  "{" */ CWORD_CWORD_CWORD_CWORD,
3139        /* 124  "|" */ CSPCL_CWORD_CWORD_CWORD,
3140        /* 125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3141        /* 126  "~" */ CWORD_CCTL_CCTL_CWORD,
3142        /* 127  del */ CWORD_CWORD_CWORD_CWORD,
3143        /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3144        /* 129 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
3145        /* 130 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
3146        /* 131 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
3147        /* 132 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
3148        /* 133 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
3149        /* 134 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
3150        /* 135 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
3151        /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3152        /* 137      */ CWORD_CWORD_CWORD_CWORD,
3153        /* 138      */ CWORD_CWORD_CWORD_CWORD,
3154        /* 139      */ CWORD_CWORD_CWORD_CWORD,
3155        /* 140      */ CWORD_CWORD_CWORD_CWORD,
3156        /* 141      */ CWORD_CWORD_CWORD_CWORD,
3157        /* 142      */ CWORD_CWORD_CWORD_CWORD,
3158        /* 143      */ CWORD_CWORD_CWORD_CWORD,
3159        /* 144      */ CWORD_CWORD_CWORD_CWORD,
3160        /* 145      */ CWORD_CWORD_CWORD_CWORD,
3161        /* 146      */ CWORD_CWORD_CWORD_CWORD,
3162        /* 147      */ CWORD_CWORD_CWORD_CWORD,
3163        /* 148      */ CWORD_CWORD_CWORD_CWORD,
3164        /* 149      */ CWORD_CWORD_CWORD_CWORD,
3165        /* 150      */ CWORD_CWORD_CWORD_CWORD,
3166        /* 151      */ CWORD_CWORD_CWORD_CWORD,
3167        /* 152      */ CWORD_CWORD_CWORD_CWORD,
3168        /* 153      */ CWORD_CWORD_CWORD_CWORD,
3169        /* 154      */ CWORD_CWORD_CWORD_CWORD,
3170        /* 155      */ CWORD_CWORD_CWORD_CWORD,
3171        /* 156      */ CWORD_CWORD_CWORD_CWORD,
3172        /* 157      */ CWORD_CWORD_CWORD_CWORD,
3173        /* 158      */ CWORD_CWORD_CWORD_CWORD,
3174        /* 159      */ CWORD_CWORD_CWORD_CWORD,
3175        /* 160      */ CWORD_CWORD_CWORD_CWORD,
3176        /* 161      */ CWORD_CWORD_CWORD_CWORD,
3177        /* 162      */ CWORD_CWORD_CWORD_CWORD,
3178        /* 163      */ CWORD_CWORD_CWORD_CWORD,
3179        /* 164      */ CWORD_CWORD_CWORD_CWORD,
3180        /* 165      */ CWORD_CWORD_CWORD_CWORD,
3181        /* 166      */ CWORD_CWORD_CWORD_CWORD,
3182        /* 167      */ CWORD_CWORD_CWORD_CWORD,
3183        /* 168      */ CWORD_CWORD_CWORD_CWORD,
3184        /* 169      */ CWORD_CWORD_CWORD_CWORD,
3185        /* 170      */ CWORD_CWORD_CWORD_CWORD,
3186        /* 171      */ CWORD_CWORD_CWORD_CWORD,
3187        /* 172      */ CWORD_CWORD_CWORD_CWORD,
3188        /* 173      */ CWORD_CWORD_CWORD_CWORD,
3189        /* 174      */ CWORD_CWORD_CWORD_CWORD,
3190        /* 175      */ CWORD_CWORD_CWORD_CWORD,
3191        /* 176      */ CWORD_CWORD_CWORD_CWORD,
3192        /* 177      */ CWORD_CWORD_CWORD_CWORD,
3193        /* 178      */ CWORD_CWORD_CWORD_CWORD,
3194        /* 179      */ CWORD_CWORD_CWORD_CWORD,
3195        /* 180      */ CWORD_CWORD_CWORD_CWORD,
3196        /* 181      */ CWORD_CWORD_CWORD_CWORD,
3197        /* 182      */ CWORD_CWORD_CWORD_CWORD,
3198        /* 183      */ CWORD_CWORD_CWORD_CWORD,
3199        /* 184      */ CWORD_CWORD_CWORD_CWORD,
3200        /* 185      */ CWORD_CWORD_CWORD_CWORD,
3201        /* 186      */ CWORD_CWORD_CWORD_CWORD,
3202        /* 187      */ CWORD_CWORD_CWORD_CWORD,
3203        /* 188      */ CWORD_CWORD_CWORD_CWORD,
3204        /* 189      */ CWORD_CWORD_CWORD_CWORD,
3205        /* 190      */ CWORD_CWORD_CWORD_CWORD,
3206        /* 191      */ CWORD_CWORD_CWORD_CWORD,
3207        /* 192      */ CWORD_CWORD_CWORD_CWORD,
3208        /* 193      */ CWORD_CWORD_CWORD_CWORD,
3209        /* 194      */ CWORD_CWORD_CWORD_CWORD,
3210        /* 195      */ CWORD_CWORD_CWORD_CWORD,
3211        /* 196      */ CWORD_CWORD_CWORD_CWORD,
3212        /* 197      */ CWORD_CWORD_CWORD_CWORD,
3213        /* 198      */ CWORD_CWORD_CWORD_CWORD,
3214        /* 199      */ CWORD_CWORD_CWORD_CWORD,
3215        /* 200      */ CWORD_CWORD_CWORD_CWORD,
3216        /* 201      */ CWORD_CWORD_CWORD_CWORD,
3217        /* 202      */ CWORD_CWORD_CWORD_CWORD,
3218        /* 203      */ CWORD_CWORD_CWORD_CWORD,
3219        /* 204      */ CWORD_CWORD_CWORD_CWORD,
3220        /* 205      */ CWORD_CWORD_CWORD_CWORD,
3221        /* 206      */ CWORD_CWORD_CWORD_CWORD,
3222        /* 207      */ CWORD_CWORD_CWORD_CWORD,
3223        /* 208      */ CWORD_CWORD_CWORD_CWORD,
3224        /* 209      */ CWORD_CWORD_CWORD_CWORD,
3225        /* 210      */ CWORD_CWORD_CWORD_CWORD,
3226        /* 211      */ CWORD_CWORD_CWORD_CWORD,
3227        /* 212      */ CWORD_CWORD_CWORD_CWORD,
3228        /* 213      */ CWORD_CWORD_CWORD_CWORD,
3229        /* 214      */ CWORD_CWORD_CWORD_CWORD,
3230        /* 215      */ CWORD_CWORD_CWORD_CWORD,
3231        /* 216      */ CWORD_CWORD_CWORD_CWORD,
3232        /* 217      */ CWORD_CWORD_CWORD_CWORD,
3233        /* 218      */ CWORD_CWORD_CWORD_CWORD,
3234        /* 219      */ CWORD_CWORD_CWORD_CWORD,
3235        /* 220      */ CWORD_CWORD_CWORD_CWORD,
3236        /* 221      */ CWORD_CWORD_CWORD_CWORD,
3237        /* 222      */ CWORD_CWORD_CWORD_CWORD,
3238        /* 223      */ CWORD_CWORD_CWORD_CWORD,
3239        /* 224      */ CWORD_CWORD_CWORD_CWORD,
3240        /* 225      */ CWORD_CWORD_CWORD_CWORD,
3241        /* 226      */ CWORD_CWORD_CWORD_CWORD,
3242        /* 227      */ CWORD_CWORD_CWORD_CWORD,
3243        /* 228      */ CWORD_CWORD_CWORD_CWORD,
3244        /* 229      */ CWORD_CWORD_CWORD_CWORD,
3245        /* 230      */ CWORD_CWORD_CWORD_CWORD,
3246        /* 231      */ CWORD_CWORD_CWORD_CWORD,
3247        /* 232      */ CWORD_CWORD_CWORD_CWORD,
3248        /* 233      */ CWORD_CWORD_CWORD_CWORD,
3249        /* 234      */ CWORD_CWORD_CWORD_CWORD,
3250        /* 235      */ CWORD_CWORD_CWORD_CWORD,
3251        /* 236      */ CWORD_CWORD_CWORD_CWORD,
3252        /* 237      */ CWORD_CWORD_CWORD_CWORD,
3253        /* 238      */ CWORD_CWORD_CWORD_CWORD,
3254        /* 239      */ CWORD_CWORD_CWORD_CWORD,
3255        /* 230      */ CWORD_CWORD_CWORD_CWORD,
3256        /* 241      */ CWORD_CWORD_CWORD_CWORD,
3257        /* 242      */ CWORD_CWORD_CWORD_CWORD,
3258        /* 243      */ CWORD_CWORD_CWORD_CWORD,
3259        /* 244      */ CWORD_CWORD_CWORD_CWORD,
3260        /* 245      */ CWORD_CWORD_CWORD_CWORD,
3261        /* 246      */ CWORD_CWORD_CWORD_CWORD,
3262        /* 247      */ CWORD_CWORD_CWORD_CWORD,
3263        /* 248      */ CWORD_CWORD_CWORD_CWORD,
3264        /* 249      */ CWORD_CWORD_CWORD_CWORD,
3265        /* 250      */ CWORD_CWORD_CWORD_CWORD,
3266        /* 251      */ CWORD_CWORD_CWORD_CWORD,
3267        /* 252      */ CWORD_CWORD_CWORD_CWORD,
3268        /* 253      */ CWORD_CWORD_CWORD_CWORD,
3269        /* 254      */ CWORD_CWORD_CWORD_CWORD,
3270        /* 255      */ CWORD_CWORD_CWORD_CWORD,
3271        /* PEOF */     CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3272# if ENABLE_ASH_ALIAS
3273        /* PEOA */     CSPCL_CIGN_CIGN_CIGN,
3274# endif
3275};
3276
3277#if 1
3278# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3279#else /* debug version, caught one signed char bug */
3280# define SIT(c, syntax) \
3281        ({ \
3282                if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3283                        bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3284                if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3285                        bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3286                ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3287        })
3288#endif
3289
3290#endif  /* !USE_SIT_FUNCTION */
3291
3292
3293/* ============ Alias handling */
3294
3295#if ENABLE_ASH_ALIAS
3296
3297#define ALIASINUSE 1
3298#define ALIASDEAD  2
3299
3300struct alias {
3301        struct alias *next;
3302        char *name;
3303        char *val;
3304        int flag;
3305};
3306
3307
3308static struct alias **atab; // [ATABSIZE];
3309#define INIT_G_alias() do { \
3310        atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3311} while (0)
3312
3313
3314static struct alias **
3315__lookupalias(const char *name)
3316{
3317        unsigned int hashval;
3318        struct alias **app;
3319        const char *p;
3320        unsigned int ch;
3321
3322        p = name;
3323
3324        ch = (unsigned char)*p;
3325        hashval = ch << 4;
3326        while (ch) {
3327                hashval += ch;
3328                ch = (unsigned char)*++p;
3329        }
3330        app = &atab[hashval % ATABSIZE];
3331
3332        for (; *app; app = &(*app)->next) {
3333                if (strcmp(name, (*app)->name) == 0) {
3334                        break;
3335                }
3336        }
3337
3338        return app;
3339}
3340
3341static struct alias *
3342lookupalias(const char *name, int check)
3343{
3344        struct alias *ap = *__lookupalias(name);
3345
3346        if (check && ap && (ap->flag & ALIASINUSE))
3347                return NULL;
3348        return ap;
3349}
3350
3351static struct alias *
3352freealias(struct alias *ap)
3353{
3354        struct alias *next;
3355
3356        if (ap->flag & ALIASINUSE) {
3357                ap->flag |= ALIASDEAD;
3358                return ap;
3359        }
3360
3361        next = ap->next;
3362        free(ap->name);
3363        free(ap->val);
3364        free(ap);
3365        return next;
3366}
3367
3368static void
3369setalias(const char *name, const char *val)
3370{
3371        struct alias *ap, **app;
3372
3373        app = __lookupalias(name);
3374        ap = *app;
3375        INT_OFF;
3376        if (ap) {
3377                if (!(ap->flag & ALIASINUSE)) {
3378                        free(ap->val);
3379                }
3380                ap->val = ckstrdup(val);
3381                ap->flag &= ~ALIASDEAD;
3382        } else {
3383                /* not found */
3384                ap = ckzalloc(sizeof(struct alias));
3385                ap->name = ckstrdup(name);
3386                ap->val = ckstrdup(val);
3387                /*ap->flag = 0; - ckzalloc did it */
3388                /*ap->next = NULL;*/
3389                *app = ap;
3390        }
3391        INT_ON;
3392}
3393
3394static int
3395unalias(const char *name)
3396{
3397        struct alias **app;
3398
3399        app = __lookupalias(name);
3400
3401        if (*app) {
3402                INT_OFF;
3403                *app = freealias(*app);
3404                INT_ON;
3405                return 0;
3406        }
3407
3408        return 1;
3409}
3410
3411static void
3412rmaliases(void)
3413{
3414        struct alias *ap, **app;
3415        int i;
3416
3417        INT_OFF;
3418        for (i = 0; i < ATABSIZE; i++) {
3419                app = &atab[i];
3420                for (ap = *app; ap; ap = *app) {
3421                        *app = freealias(*app);
3422                        if (ap == *app) {
3423                                app = &ap->next;
3424                        }
3425                }
3426        }
3427        INT_ON;
3428}
3429
3430static void
3431printalias(const struct alias *ap)
3432{
3433        out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3434}
3435
3436/*
3437 * TODO - sort output
3438 */
3439static int FAST_FUNC
3440aliascmd(int argc UNUSED_PARAM, char **argv)
3441{
3442        char *n, *v;
3443        int ret = 0;
3444        struct alias *ap;
3445
3446        if (!argv[1]) {
3447                int i;
3448
3449                for (i = 0; i < ATABSIZE; i++) {
3450                        for (ap = atab[i]; ap; ap = ap->next) {
3451                                printalias(ap);
3452                        }
3453                }
3454                return 0;
3455        }
3456        while ((n = *++argv) != NULL) {
3457                v = strchr(n+1, '=');
3458                if (v == NULL) { /* n+1: funny ksh stuff */
3459                        ap = *__lookupalias(n);
3460                        if (ap == NULL) {
3461                                fprintf(stderr, "%s: %s not found\n", "alias", n);
3462                                ret = 1;
3463                        } else
3464                                printalias(ap);
3465                } else {
3466                        *v++ = '\0';
3467                        setalias(n, v);
3468                }
3469        }
3470
3471        return ret;
3472}
3473
3474static int FAST_FUNC
3475unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3476{
3477        int i;
3478
3479        while (nextopt("a") != '\0') {
3480                rmaliases();
3481                return 0;
3482        }
3483        for (i = 0; *argptr; argptr++) {
3484                if (unalias(*argptr)) {
3485                        fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3486                        i = 1;
3487                }
3488        }
3489
3490        return i;
3491}
3492
3493#endif /* ASH_ALIAS */
3494
3495
3496/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
3497#define FORK_FG    0
3498#define FORK_BG    1
3499#define FORK_NOJOB 2
3500
3501/* mode flags for showjob(s) */
3502#define SHOW_ONLY_PGID  0x01    /* show only pgid (jobs -p) */
3503#define SHOW_PIDS       0x02    /* show individual pids, not just one line per job */
3504#define SHOW_CHANGED    0x04    /* only jobs whose state has changed */
3505#define SHOW_STDERR     0x08    /* print to stderr (else stdout) */
3506
3507/*
3508 * A job structure contains information about a job.  A job is either a
3509 * single process or a set of processes contained in a pipeline.  In the
3510 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3511 * array of pids.
3512 */
3513struct procstat {
3514        pid_t   ps_pid;         /* process id */
3515        int     ps_status;      /* last process status from wait() */
3516        char    *ps_cmd;        /* text of command being run */
3517};
3518
3519struct job {
3520        struct procstat ps0;    /* status of process */
3521        struct procstat *ps;    /* status or processes when more than one */
3522#if JOBS
3523        int stopstatus;         /* status of a stopped job */
3524#endif
3525        unsigned nprocs;        /* number of processes */
3526
3527#define JOBRUNNING      0       /* at least one proc running */
3528#define JOBSTOPPED      1       /* all procs are stopped */
3529#define JOBDONE         2       /* all procs are completed */
3530        unsigned
3531                state: 8,
3532#if JOBS
3533                sigint: 1,      /* job was killed by SIGINT */
3534                jobctl: 1,      /* job running under job control */
3535#endif
3536                waited: 1,      /* true if this entry has been waited for */
3537                used: 1,        /* true if this entry is in used */
3538                changed: 1;     /* true if status has changed */
3539        struct job *prev_job;   /* previous job */
3540};
3541
3542static struct job *makejob(/*union node *,*/ int);
3543static int forkshell(struct job *, union node *, int);
3544static int waitforjob(struct job *);
3545
3546#if !JOBS
3547enum { doing_jobctl = 0 };
3548#define setjobctl(on) do {} while (0)
3549#else
3550static smallint doing_jobctl; //references:8
3551static void setjobctl(int);
3552#endif
3553
3554/*
3555 * Ignore a signal.
3556 */
3557static void
3558ignoresig(int signo)
3559{
3560        /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3561        if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3562                /* No, need to do it */
3563                signal(signo, SIG_IGN);
3564        }
3565        sigmode[signo - 1] = S_HARD_IGN;
3566}
3567
3568/*
3569 * Only one usage site - in setsignal()
3570 */
3571static void
3572signal_handler(int signo)
3573{
3574        if (signo == SIGCHLD) {
3575                got_sigchld = 1;
3576                if (!trap[SIGCHLD])
3577                        return;
3578        }
3579
3580        gotsig[signo - 1] = 1;
3581        pending_sig = signo;
3582
3583        if (signo == SIGINT && !trap[SIGINT]) {
3584                if (!suppress_int) {
3585                        pending_sig = 0;
3586                        raise_interrupt(); /* does not return */
3587                }
3588                pending_int = 1;
3589        }
3590}
3591
3592/*
3593 * Set the signal handler for the specified signal.  The routine figures
3594 * out what it should be set to.
3595 */
3596static void
3597setsignal(int signo)
3598{
3599        char *t;
3600        char cur_act, new_act;
3601        struct sigaction act;
3602
3603        t = trap[signo];
3604        new_act = S_DFL;
3605        if (t != NULL) { /* trap for this sig is set */
3606                new_act = S_CATCH;
3607                if (t[0] == '\0') /* trap is "": ignore this sig */
3608                        new_act = S_IGN;
3609        }
3610
3611        if (rootshell && new_act == S_DFL) {
3612                switch (signo) {
3613                case SIGINT:
3614                        if (iflag || minusc || sflag == 0)
3615                                new_act = S_CATCH;
3616                        break;
3617                case SIGQUIT:
3618#if DEBUG
3619                        if (debug)
3620                                break;
3621#endif
3622                        /* man bash:
3623                         * "In all cases, bash ignores SIGQUIT. Non-builtin
3624                         * commands run by bash have signal handlers
3625                         * set to the values inherited by the shell
3626                         * from its parent". */
3627                        new_act = S_IGN;
3628                        break;
3629                case SIGTERM:
3630                        if (iflag)
3631                                new_act = S_IGN;
3632                        break;
3633#if JOBS
3634                case SIGTSTP:
3635                case SIGTTOU:
3636                        if (mflag)
3637                                new_act = S_IGN;
3638                        break;
3639#endif
3640                }
3641        }
3642        /* if !rootshell, we reset SIGQUIT to DFL,
3643         * whereas we have to restore it to what shell got on entry.
3644         * This is handled by the fact that if signal was IGNored on entry,
3645         * then cur_act is S_HARD_IGN and we never change its sigaction
3646         * (see code below).
3647         */
3648
3649        if (signo == SIGCHLD)
3650                new_act = S_CATCH;
3651
3652        t = &sigmode[signo - 1];
3653        cur_act = *t;
3654        if (cur_act == 0) {
3655                /* current setting is not yet known */
3656                if (sigaction(signo, NULL, &act)) {
3657                        /* pretend it worked; maybe we should give a warning,
3658                         * but other shells don't. We don't alter sigmode,
3659                         * so we retry every time.
3660                         * btw, in Linux it never fails. --vda */
3661                        return;
3662                }
3663                if (act.sa_handler == SIG_IGN) {
3664                        cur_act = S_HARD_IGN;
3665                        if (mflag
3666                         && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3667                        ) {
3668                                cur_act = S_IGN;   /* don't hard ignore these */
3669                        }
3670                }
3671                if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3672                        /* installing SIG_DFL over SIG_DFL is a no-op */
3673                        /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3674                        *t = S_DFL;
3675                        return;
3676                }
3677        }
3678        if (cur_act == S_HARD_IGN || cur_act == new_act)
3679                return;
3680
3681        *t = new_act;
3682
3683        act.sa_handler = SIG_DFL;
3684        switch (new_act) {
3685        case S_CATCH:
3686                act.sa_handler = signal_handler;
3687                break;
3688        case S_IGN:
3689                act.sa_handler = SIG_IGN;
3690                break;
3691        }
3692        /* flags and mask matter only if !DFL and !IGN, but we do it
3693         * for all cases for more deterministic behavior:
3694         */
3695        act.sa_flags = 0; //TODO: why not SA_RESTART?
3696        sigfillset(&act.sa_mask);
3697
3698        sigaction_set(signo, &act);
3699}
3700
3701/* mode flags for set_curjob */
3702#define CUR_DELETE 2
3703#define CUR_RUNNING 1
3704#define CUR_STOPPED 0
3705
3706#if JOBS
3707/* pgrp of shell on invocation */
3708static int initialpgrp; //references:2
3709static int ttyfd = -1; //5
3710#endif
3711/* array of jobs */
3712static struct job *jobtab; //5
3713/* size of array */
3714static unsigned njobs; //4
3715/* current job */
3716static struct job *curjob; //lots
3717/* number of presumed living untracked jobs */
3718static int jobless; //4
3719
3720#if 0
3721/* Bash has a feature: it restores termios after a successful wait for
3722 * a foreground job which had at least one stopped or sigkilled member.
3723 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3724 * properly restoring tty state. Should we do this too?
3725 * A reproducer: ^Z an interactive python:
3726 *
3727 * # python
3728 * Python 2.7.12 (...)
3729 * >>> ^Z
3730 *      { python leaves tty in -icanon -echo state. We do survive that... }
3731 *  [1]+  Stopped                    python
3732 *      { ...however, next program (python #2) does not survive it well: }
3733 * # python
3734 * Python 2.7.12 (...)
3735 * >>> Traceback (most recent call last):
3736 *      { above, I typed "qwerty<CR>", but -echo state is still in effect }
3737 *   File "<stdin>", line 1, in <module>
3738 * NameError: name 'qwerty' is not defined
3739 *
3740 * The implementation below is modeled on bash code and seems to work.
3741 * However, I'm not sure we should do this. For one: what if I'd fg
3742 * the stopped python instead? It'll be confused by "restored" tty state.
3743 */
3744static struct termios shell_tty_info;
3745static void
3746get_tty_state(void)
3747{
3748        if (rootshell && ttyfd >= 0)
3749                tcgetattr(ttyfd, &shell_tty_info);
3750}
3751static void
3752set_tty_state(void)
3753{
3754        /* if (rootshell) - caller ensures this */
3755        if (ttyfd >= 0)
3756                tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3757}
3758static int
3759job_signal_status(struct job *jp)
3760{
3761        int status;
3762        unsigned i;
3763        struct procstat *ps = jp->ps;
3764        for (i = 0; i < jp->nprocs; i++) {
3765                status = ps[i].ps_status;
3766                if (WIFSIGNALED(status) || WIFSTOPPED(status))
3767                        return status;
3768        }
3769        return 0;
3770}
3771static void
3772restore_tty_if_stopped_or_signaled(struct job *jp)
3773{
3774//TODO: check what happens if we come from waitforjob() in expbackq()
3775        if (rootshell) {
3776                int s = job_signal_status(jp);
3777                if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3778                        set_tty_state();
3779        }
3780}
3781#else
3782# define get_tty_state() ((void)0)
3783# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3784#endif
3785
3786static void
3787set_curjob(struct job *jp, unsigned mode)
3788{
3789        struct job *jp1;
3790        struct job **jpp, **curp;
3791
3792        /* first remove from list */
3793        jpp = curp = &curjob;
3794        while (1) {
3795                jp1 = *jpp;
3796                if (jp1 == jp)
3797                        break;
3798                jpp = &jp1->prev_job;
3799        }
3800        *jpp = jp1->prev_job;
3801
3802        /* Then re-insert in correct position */
3803        jpp = curp;
3804        switch (mode) {
3805        default:
3806#if DEBUG
3807                abort();
3808#endif
3809        case CUR_DELETE:
3810                /* job being deleted */
3811                break;
3812        case CUR_RUNNING:
3813                /* newly created job or backgrounded job,
3814                 * put after all stopped jobs.
3815                 */
3816                while (1) {
3817                        jp1 = *jpp;
3818#if JOBS
3819                        if (!jp1 || jp1->state != JOBSTOPPED)
3820#endif
3821                                break;
3822                        jpp = &jp1->prev_job;
3823                }
3824                /* FALLTHROUGH */
3825#if JOBS
3826        case CUR_STOPPED:
3827#endif
3828                /* newly stopped job - becomes curjob */
3829                jp->prev_job = *jpp;
3830                *jpp = jp;
3831                break;
3832        }
3833}
3834
3835#if JOBS || DEBUG
3836static int
3837jobno(const struct job *jp)
3838{
3839        return jp - jobtab + 1;
3840}
3841#endif
3842
3843/*
3844 * Convert a job name to a job structure.
3845 */
3846#if !JOBS
3847#define getjob(name, getctl) getjob(name)
3848#endif
3849static struct job *
3850getjob(const char *name, int getctl)
3851{
3852        struct job *jp;
3853        struct job *found;
3854        const char *err_msg = "%s: no such job";
3855        unsigned num;
3856        int c;
3857        const char *p;
3858        char *(*match)(const char *, const char *);
3859
3860        jp = curjob;
3861        p = name;
3862        if (!p)
3863                goto currentjob;
3864
3865        if (*p != '%')
3866                goto err;
3867
3868        c = *++p;
3869        if (!c)
3870                goto currentjob;
3871
3872        if (!p[1]) {
3873                if (c == '+' || c == '%') {
3874 currentjob:
3875                        err_msg = "No current job";
3876                        goto check;
3877                }
3878                if (c == '-') {
3879                        if (jp)
3880                                jp = jp->prev_job;
3881                        err_msg = "No previous job";
3882 check:
3883                        if (!jp)
3884                                goto err;
3885                        goto gotit;
3886                }
3887        }
3888
3889        if (is_number(p)) {
3890                num = atoi(p);
3891                if (num > 0 && num <= njobs) {
3892                        jp = jobtab + num - 1;
3893                        if (jp->used)
3894                                goto gotit;
3895                        goto err;
3896                }
3897        }
3898
3899        match = prefix;
3900        if (*p == '?') {
3901                match = strstr;
3902                p++;
3903        }
3904
3905        found = NULL;
3906        while (jp) {
3907                if (match(jp->ps[0].ps_cmd, p)) {
3908                        if (found)
3909                                goto err;
3910                        found = jp;
3911                        err_msg = "%s: ambiguous";
3912                }
3913                jp = jp->prev_job;
3914        }
3915        if (!found)
3916                goto err;
3917        jp = found;
3918
3919 gotit:
3920#if JOBS
3921        err_msg = "job %s not created under job control";
3922        if (getctl && jp->jobctl == 0)
3923                goto err;
3924#endif
3925        return jp;
3926 err:
3927        ash_msg_and_raise_error(err_msg, name);
3928}
3929
3930/*
3931 * Mark a job structure as unused.
3932 */
3933static void
3934freejob(struct job *jp)
3935{
3936        struct procstat *ps;
3937        int i;
3938
3939        INT_OFF;
3940        for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3941                if (ps->ps_cmd != nullstr)
3942                        free(ps->ps_cmd);
3943        }
3944        if (jp->ps != &jp->ps0)
3945                free(jp->ps);
3946        jp->used = 0;
3947        set_curjob(jp, CUR_DELETE);
3948        INT_ON;
3949}
3950
3951#if JOBS
3952static void
3953xtcsetpgrp(int fd, pid_t pgrp)
3954{
3955        if (tcsetpgrp(fd, pgrp))
3956                ash_msg_and_raise_perror("can't set tty process group");
3957}
3958
3959/*
3960 * Turn job control on and off.
3961 *
3962 * Note:  This code assumes that the third arg to ioctl is a character
3963 * pointer, which is true on Berkeley systems but not System V.  Since
3964 * System V doesn't have job control yet, this isn't a problem now.
3965 *
3966 * Called with interrupts off.
3967 */
3968static void
3969setjobctl(int on)
3970{
3971        int fd;
3972        int pgrp;
3973
3974        if (on == doing_jobctl || rootshell == 0)
3975                return;
3976        if (on) {
3977                int ofd;
3978                ofd = fd = open(_PATH_TTY, O_RDWR);
3979                if (fd < 0) {
3980        /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3981         * That sometimes helps to acquire controlling tty.
3982         * Obviously, a workaround for bugs when someone
3983         * failed to provide a controlling tty to bash! :) */
3984                        fd = 2;
3985                        while (!isatty(fd))
3986                                if (--fd < 0)
3987                                        goto out;
3988                }
3989                /* fd is a tty at this point */
3990                fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
3991                if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
3992                        close(ofd);
3993                if (fd < 0)
3994                        goto out; /* F_DUPFD failed */
3995                if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
3996                        close_on_exec_on(fd);
3997                while (1) { /* while we are in the background */
3998                        pgrp = tcgetpgrp(fd);
3999                        if (pgrp < 0) {
4000 out:
4001                                ash_msg("can't access tty; job control turned off");
4002                                mflag = on = 0;
4003                                goto close;
4004                        }
4005                        if (pgrp == getpgrp())
4006                                break;
4007                        killpg(0, SIGTTIN);
4008                }
4009                initialpgrp = pgrp;
4010
4011                setsignal(SIGTSTP);
4012                setsignal(SIGTTOU);
4013                setsignal(SIGTTIN);
4014                pgrp = rootpid;
4015                setpgid(0, pgrp);
4016                xtcsetpgrp(fd, pgrp);
4017        } else {
4018                /* turning job control off */
4019                fd = ttyfd;
4020                pgrp = initialpgrp;
4021                /* was xtcsetpgrp, but this can make exiting ash
4022                 * loop forever if pty is already deleted */
4023                tcsetpgrp(fd, pgrp);
4024                setpgid(0, pgrp);
4025                setsignal(SIGTSTP);
4026                setsignal(SIGTTOU);
4027                setsignal(SIGTTIN);
4028 close:
4029                if (fd >= 0)
4030                        close(fd);
4031                fd = -1;
4032        }
4033        ttyfd = fd;
4034        doing_jobctl = on;
4035}
4036
4037static int FAST_FUNC
4038killcmd(int argc, char **argv)
4039{
4040        if (argv[1] && strcmp(argv[1], "-l") != 0) {
4041                int i = 1;
4042                do {
4043                        if (argv[i][0] == '%') {
4044                                /*
4045                                 * "kill %N" - job kill
4046                                 * Converting to pgrp / pid kill
4047                                 */
4048                                struct job *jp;
4049                                char *dst;
4050                                int j, n;
4051
4052                                jp = getjob(argv[i], 0);
4053                                /*
4054                                 * In jobs started under job control, we signal
4055                                 * entire process group by kill -PGRP_ID.
4056                                 * This happens, f.e., in interactive shell.
4057                                 *
4058                                 * Otherwise, we signal each child via
4059                                 * kill PID1 PID2 PID3.
4060                                 * Testcases:
4061                                 * sh -c 'sleep 1|sleep 1 & kill %1'
4062                                 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4063                                 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4064                                 */
4065                                n = jp->nprocs; /* can't be 0 (I hope) */
4066                                if (jp->jobctl)
4067                                        n = 1;
4068                                dst = alloca(n * sizeof(int)*4);
4069                                argv[i] = dst;
4070                                for (j = 0; j < n; j++) {
4071                                        struct procstat *ps = &jp->ps[j];
4072                                        /* Skip non-running and not-stopped members
4073                                         * (i.e. dead members) of the job
4074                                         */
4075                                        if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4076                                                continue;
4077                                        /*
4078                                         * kill_main has matching code to expect
4079                                         * leading space. Needed to not confuse
4080                                         * negative pids with "kill -SIGNAL_NO" syntax
4081                                         */
4082                                        dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4083                                }
4084                                *dst = '\0';
4085                        }
4086                } while (argv[++i]);
4087        }
4088        return kill_main(argc, argv);
4089}
4090
4091static void
4092showpipe(struct job *jp /*, FILE *out*/)
4093{
4094        struct procstat *ps;
4095        struct procstat *psend;
4096
4097        psend = jp->ps + jp->nprocs;
4098        for (ps = jp->ps + 1; ps < psend; ps++)
4099                printf(" | %s", ps->ps_cmd);
4100        newline_and_flush(stdout);
4101        flush_stdout_stderr();
4102}
4103
4104
4105static int
4106restartjob(struct job *jp, int mode)
4107{
4108        struct procstat *ps;
4109        int i;
4110        int status;
4111        pid_t pgid;
4112
4113        INT_OFF;
4114        if (jp->state == JOBDONE)
4115                goto out;
4116        jp->state = JOBRUNNING;
4117        pgid = jp->ps[0].ps_pid;
4118        if (mode == FORK_FG) {
4119                get_tty_state();
4120                xtcsetpgrp(ttyfd, pgid);
4121        }
4122        killpg(pgid, SIGCONT);
4123        ps = jp->ps;
4124        i = jp->nprocs;
4125        do {
4126                if (WIFSTOPPED(ps->ps_status)) {
4127                        ps->ps_status = -1;
4128                }
4129                ps++;
4130        } while (--i);
4131 out:
4132        status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4133        INT_ON;
4134        return status;
4135}
4136
4137static int FAST_FUNC
4138fg_bgcmd(int argc UNUSED_PARAM, char **argv)
4139{
4140        struct job *jp;
4141        int mode;
4142        int retval;
4143
4144        mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4145        nextopt(nullstr);
4146        argv = argptr;
4147        do {
4148                jp = getjob(*argv, 1);
4149                if (mode == FORK_BG) {
4150                        set_curjob(jp, CUR_RUNNING);
4151                        printf("[%d] ", jobno(jp));
4152                }
4153                out1str(jp->ps[0].ps_cmd);
4154                showpipe(jp /*, stdout*/);
4155                retval = restartjob(jp, mode);
4156        } while (*argv && *++argv);
4157        return retval;
4158}
4159#endif
4160
4161static int
4162sprint_status48(char *s, int status, int sigonly)
4163{
4164        int col;
4165        int st;
4166
4167        col = 0;
4168        if (!WIFEXITED(status)) {
4169#if JOBS
4170                if (WIFSTOPPED(status))
4171                        st = WSTOPSIG(status);
4172                else
4173#endif
4174                        st = WTERMSIG(status);
4175                if (sigonly) {
4176                        if (st == SIGINT || st == SIGPIPE)
4177                                goto out;
4178#if JOBS
4179                        if (WIFSTOPPED(status))
4180                                goto out;
4181#endif
4182                }
4183                st &= 0x7f;
4184//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
4185                col = fmtstr(s, 32, strsignal(st));
4186                if (WCOREDUMP(status)) {
4187                        strcpy(s + col, " (core dumped)");
4188                        col += sizeof(" (core dumped)")-1;
4189                }
4190        } else if (!sigonly) {
4191                st = WEXITSTATUS(status);
4192                col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
4193        }
4194 out:
4195        return col;
4196}
4197
4198static int
4199wait_block_or_sig(int *status)
4200{
4201        int pid;
4202
4203        do {
4204                sigset_t mask;
4205
4206                /* Poll all children for changes in their state */
4207                got_sigchld = 0;
4208                /* if job control is active, accept stopped processes too */
4209                pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
4210                if (pid != 0)
4211                        break; /* Error (e.g. EINTR, ECHILD) or pid */
4212
4213                /* Children exist, but none are ready. Sleep until interesting signal */
4214#if 1
4215                sigfillset(&mask);
4216                sigprocmask(SIG_SETMASK, &mask, &mask);
4217                while (!got_sigchld && !pending_sig)
4218                        sigsuspend(&mask);
4219                sigprocmask(SIG_SETMASK, &mask, NULL);
4220#else /* unsafe: a signal can set pending_sig after check, but before pause() */
4221                while (!got_sigchld && !pending_sig)
4222                        pause();
4223#endif
4224
4225                /* If it was SIGCHLD, poll children again */
4226        } while (got_sigchld);
4227
4228        return pid;
4229}
4230
4231#define DOWAIT_NONBLOCK 0
4232#define DOWAIT_BLOCK    1
4233#define DOWAIT_BLOCK_OR_SIG 2
4234
4235static int
4236dowait(int block, struct job *job)
4237{
4238        int pid;
4239        int status;
4240        struct job *jp;
4241        struct job *thisjob = NULL;
4242
4243        TRACE(("dowait(0x%x) called\n", block));
4244
4245        /* It's wrong to call waitpid() outside of INT_OFF region:
4246         * signal can arrive just after syscall return and handler can
4247         * longjmp away, losing stop/exit notification processing.
4248         * Thus, for "jobs" builtin, and for waiting for a fg job,
4249         * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4250         *
4251         * However, for "wait" builtin it is wrong to simply call waitpid()
4252         * in INT_OFF region: "wait" needs to wait for any running job
4253         * to change state, but should exit on any trap too.
4254         * In INT_OFF region, a signal just before syscall entry can set
4255         * pending_sig variables, but we can't check them, and we would
4256         * either enter a sleeping waitpid() (BUG), or need to busy-loop.
4257         *
4258         * Because of this, we run inside INT_OFF, but use a special routine
4259         * which combines waitpid() and sigsuspend().
4260         * This is the reason why we need to have a handler for SIGCHLD:
4261         * SIG_DFL handler does not wake sigsuspend().
4262         */
4263        INT_OFF;
4264        if (block == DOWAIT_BLOCK_OR_SIG) {
4265                pid = wait_block_or_sig(&status);
4266        } else {
4267                int wait_flags = 0;
4268                if (block == DOWAIT_NONBLOCK)
4269                        wait_flags = WNOHANG;
4270                /* if job control is active, accept stopped processes too */
4271                if (doing_jobctl)
4272                        wait_flags |= WUNTRACED;
4273                /* NB: _not_ safe_waitpid, we need to detect EINTR */
4274                pid = waitpid(-1, &status, wait_flags);
4275        }
4276        TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4277                                pid, status, errno, strerror(errno)));
4278        if (pid <= 0)
4279                goto out;
4280
4281        thisjob = NULL;
4282        for (jp = curjob; jp; jp = jp->prev_job) {
4283                int jobstate;
4284                struct procstat *ps;
4285                struct procstat *psend;
4286                if (jp->state == JOBDONE)
4287                        continue;
4288                jobstate = JOBDONE;
4289                ps = jp->ps;
4290                psend = ps + jp->nprocs;
4291                do {
4292                        if (ps->ps_pid == pid) {
4293                                TRACE(("Job %d: changing status of proc %d "
4294                                        "from 0x%x to 0x%x\n",
4295                                        jobno(jp), pid, ps->ps_status, status));
4296                                ps->ps_status = status;
4297                                thisjob = jp;
4298                        }
4299                        if (ps->ps_status == -1)
4300                                jobstate = JOBRUNNING;
4301#if JOBS
4302                        if (jobstate == JOBRUNNING)
4303                                continue;
4304                        if (WIFSTOPPED(ps->ps_status)) {
4305                                jp->stopstatus = ps->ps_status;
4306                                jobstate = JOBSTOPPED;
4307                        }
4308#endif
4309                } while (++ps < psend);
4310                if (!thisjob)
4311                        continue;
4312
4313                /* Found the job where one of its processes changed its state.
4314                 * Is there at least one live and running process in this job? */
4315                if (jobstate != JOBRUNNING) {
4316                        /* No. All live processes in the job are stopped
4317                         * (JOBSTOPPED) or there are no live processes (JOBDONE)
4318                         */
4319                        thisjob->changed = 1;
4320                        if (thisjob->state != jobstate) {
4321                                TRACE(("Job %d: changing state from %d to %d\n",
4322                                        jobno(thisjob), thisjob->state, jobstate));
4323                                thisjob->state = jobstate;
4324#if JOBS
4325                                if (jobstate == JOBSTOPPED)
4326                                        set_curjob(thisjob, CUR_STOPPED);
4327#endif
4328                        }
4329                }
4330                goto out;
4331        }
4332        /* The process wasn't found in job list */
4333#if JOBS
4334        if (!WIFSTOPPED(status))
4335                jobless--;
4336#endif
4337 out:
4338        INT_ON;
4339
4340        if (thisjob && thisjob == job) {
4341                char s[48 + 1];
4342                int len;
4343
4344                len = sprint_status48(s, status, 1);
4345                if (len) {
4346                        s[len] = '\n';
4347                        s[len + 1] = '\0';
4348                        out2str(s);
4349                }
4350        }
4351        return pid;
4352}
4353
4354#if JOBS
4355static void
4356showjob(struct job *jp, int mode)
4357{
4358        struct procstat *ps;
4359        struct procstat *psend;
4360        int col;
4361        int indent_col;
4362        char s[16 + 16 + 48];
4363        FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4364
4365        ps = jp->ps;
4366
4367        if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4368                /* just output process (group) id of pipeline */
4369                fprintf(out, "%d\n", ps->ps_pid);
4370                return;
4371        }
4372
4373        col = fmtstr(s, 16, "[%d]   ", jobno(jp));
4374        indent_col = col;
4375
4376        if (jp == curjob)
4377                s[col - 3] = '+';
4378        else if (curjob && jp == curjob->prev_job)
4379                s[col - 3] = '-';
4380
4381        if (mode & SHOW_PIDS)
4382                col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4383
4384        psend = ps + jp->nprocs;
4385
4386        if (jp->state == JOBRUNNING) {
4387                strcpy(s + col, "Running");
4388                col += sizeof("Running") - 1;
4389        } else {
4390                int status = psend[-1].ps_status;
4391                if (jp->state == JOBSTOPPED)
4392                        status = jp->stopstatus;
4393                col += sprint_status48(s + col, status, 0);
4394        }
4395        /* By now, "[JOBID]*  [maybe PID] STATUS" is printed */
4396
4397        /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4398         * or prints several "PID             | <cmdN>" lines,
4399         * depending on SHOW_PIDS bit.
4400         * We do not print status of individual processes
4401         * between PID and <cmdN>. bash does it, but not very well:
4402         * first line shows overall job status, not process status,
4403         * making it impossible to know 1st process status.
4404         */
4405        goto start;
4406        do {
4407                /* for each process */
4408                s[0] = '\0';
4409                col = 33;
4410                if (mode & SHOW_PIDS)
4411                        col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4412 start:
4413                fprintf(out, "%s%*c%s%s",
4414                                s,
4415                                33 - col >= 0 ? 33 - col : 0, ' ',
4416                                ps == jp->ps ? "" : "| ",
4417                                ps->ps_cmd
4418                );
4419        } while (++ps != psend);
4420        newline_and_flush(out);
4421
4422        jp->changed = 0;
4423
4424        if (jp->state == JOBDONE) {
4425                TRACE(("showjob: freeing job %d\n", jobno(jp)));
4426                freejob(jp);
4427        }
4428}
4429
4430/*
4431 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
4432 * statuses have changed since the last call to showjobs.
4433 */
4434static void
4435showjobs(int mode)
4436{
4437        struct job *jp;
4438
4439        TRACE(("showjobs(0x%x) called\n", mode));
4440
4441        /* Handle all finished jobs */
4442        while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
4443                continue;
4444
4445        for (jp = curjob; jp; jp = jp->prev_job) {
4446                if (!(mode & SHOW_CHANGED) || jp->changed) {
4447                        showjob(jp, mode);
4448                }
4449        }
4450}
4451
4452static int FAST_FUNC
4453jobscmd(int argc UNUSED_PARAM, char **argv)
4454{
4455        int mode, m;
4456
4457        mode = 0;
4458        while ((m = nextopt("lp")) != '\0') {
4459                if (m == 'l')
4460                        mode |= SHOW_PIDS;
4461                else
4462                        mode |= SHOW_ONLY_PGID;
4463        }
4464
4465        argv = argptr;
4466        if (*argv) {
4467                do
4468                        showjob(getjob(*argv, 0), mode);
4469                while (*++argv);
4470        } else {
4471                showjobs(mode);
4472        }
4473
4474        return 0;
4475}
4476#endif /* JOBS */
4477
4478/* Called only on finished or stopped jobs (no members are running) */
4479static int
4480getstatus(struct job *job)
4481{
4482        int status;
4483        int retval;
4484        struct procstat *ps;
4485
4486        /* Fetch last member's status */
4487        ps = job->ps + job->nprocs - 1;
4488        status = ps->ps_status;
4489        if (pipefail) {
4490                /* "set -o pipefail" mode: use last _nonzero_ status */
4491                while (status == 0 && --ps >= job->ps)
4492                        status = ps->ps_status;
4493        }
4494
4495        retval = WEXITSTATUS(status);
4496        if (!WIFEXITED(status)) {
4497#if JOBS
4498                retval = WSTOPSIG(status);
4499                if (!WIFSTOPPED(status))
4500#endif
4501                {
4502                        /* XXX: limits number of signals */
4503                        retval = WTERMSIG(status);
4504#if JOBS
4505                        if (retval == SIGINT)
4506                                job->sigint = 1;
4507#endif
4508                }
4509                retval += 128;
4510        }
4511        TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4512                jobno(job), job->nprocs, status, retval));
4513        return retval;
4514}
4515
4516static int FAST_FUNC
4517waitcmd(int argc UNUSED_PARAM, char **argv)
4518{
4519        struct job *job;
4520        int retval;
4521        struct job *jp;
4522
4523        nextopt(nullstr);
4524        retval = 0;
4525
4526        argv = argptr;
4527        if (!*argv) {
4528                /* wait for all jobs */
4529                for (;;) {
4530                        jp = curjob;
4531                        while (1) {
4532                                if (!jp) /* no running procs */
4533                                        goto ret;
4534                                if (jp->state == JOBRUNNING)
4535                                        break;
4536                                jp->waited = 1;
4537                                jp = jp->prev_job;
4538                        }
4539        /* man bash:
4540         * "When bash is waiting for an asynchronous command via
4541         * the wait builtin, the reception of a signal for which a trap
4542         * has been set will cause the wait builtin to return immediately
4543         * with an exit status greater than 128, immediately after which
4544         * the trap is executed."
4545         */
4546                        dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4547        /* if child sends us a signal *and immediately exits*,
4548         * dowait() returns pid > 0. Check this case,
4549         * not "if (dowait() < 0)"!
4550         */
4551                        if (pending_sig)
4552                                goto sigout;
4553                }
4554        }
4555
4556        retval = 127;
4557        do {
4558                if (**argv != '%') {
4559                        pid_t pid = number(*argv);
4560                        job = curjob;
4561                        while (1) {
4562                                if (!job)
4563                                        goto repeat;
4564                                if (job->ps[job->nprocs - 1].ps_pid == pid)
4565                                        break;
4566                                job = job->prev_job;
4567                        }
4568                } else {
4569                        job = getjob(*argv, 0);
4570                }
4571                /* loop until process terminated or stopped */
4572                while (job->state == JOBRUNNING) {
4573                        dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4574                        if (pending_sig)
4575                                goto sigout;
4576                }
4577                job->waited = 1;
4578                retval = getstatus(job);
4579 repeat: ;
4580        } while (*++argv);
4581
4582 ret:
4583        return retval;
4584 sigout:
4585        retval = 128 + pending_sig;
4586        return retval;
4587}
4588
4589static struct job *
4590growjobtab(void)
4591{
4592        size_t len;
4593        ptrdiff_t offset;
4594        struct job *jp, *jq;
4595
4596        len = njobs * sizeof(*jp);
4597        jq = jobtab;
4598        jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4599
4600        offset = (char *)jp - (char *)jq;
4601        if (offset) {
4602                /* Relocate pointers */
4603                size_t l = len;
4604
4605                jq = (struct job *)((char *)jq + l);
4606                while (l) {
4607                        l -= sizeof(*jp);
4608                        jq--;
4609#define joff(p) ((struct job *)((char *)(p) + l))
4610#define jmove(p) (p) = (void *)((char *)(p) + offset)
4611                        if (joff(jp)->ps == &jq->ps0)
4612                                jmove(joff(jp)->ps);
4613                        if (joff(jp)->prev_job)
4614                                jmove(joff(jp)->prev_job);
4615                }
4616                if (curjob)
4617                        jmove(curjob);
4618#undef joff
4619#undef jmove
4620        }
4621
4622        njobs += 4;
4623        jobtab = jp;
4624        jp = (struct job *)((char *)jp + len);
4625        jq = jp + 3;
4626        do {
4627                jq->used = 0;
4628        } while (--jq >= jp);
4629        return jp;
4630}
4631
4632/*
4633 * Return a new job structure.
4634 * Called with interrupts off.
4635 */
4636static struct job *
4637makejob(/*union node *node,*/ int nprocs)
4638{
4639        int i;
4640        struct job *jp;
4641
4642        for (i = njobs, jp = jobtab; ; jp++) {
4643                if (--i < 0) {
4644                        jp = growjobtab();
4645                        break;
4646                }
4647                if (jp->used == 0)
4648                        break;
4649                if (jp->state != JOBDONE || !jp->waited)
4650                        continue;
4651#if JOBS
4652                if (doing_jobctl)
4653                        continue;
4654#endif
4655                freejob(jp);
4656                break;
4657        }
4658        memset(jp, 0, sizeof(*jp));
4659#if JOBS
4660        /* jp->jobctl is a bitfield.
4661         * "jp->jobctl |= doing_jobctl" likely to give awful code */
4662        if (doing_jobctl)
4663                jp->jobctl = 1;
4664#endif
4665        jp->prev_job = curjob;
4666        curjob = jp;
4667        jp->used = 1;
4668        jp->ps = &jp->ps0;
4669        if (nprocs > 1) {
4670                jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4671        }
4672        TRACE(("makejob(%d) returns %%%d\n", nprocs,
4673                                jobno(jp)));
4674        return jp;
4675}
4676
4677#if JOBS
4678/*
4679 * Return a string identifying a command (to be printed by the
4680 * jobs command).
4681 */
4682static char *cmdnextc;
4683
4684static void
4685cmdputs(const char *s)
4686{
4687        static const char vstype[VSTYPE + 1][3] = {
4688                "", "}", "-", "+", "?", "=",
4689                "%", "%%", "#", "##"
4690                IF_BASH_SUBSTR(, ":")
4691                IF_BASH_PATTERN_SUBST(, "/", "//")
4692        };
4693
4694        const char *p, *str;
4695        char cc[2];
4696        char *nextc;
4697        unsigned char c;
4698        unsigned char subtype = 0;
4699        int quoted = 0;
4700
4701        cc[1] = '\0';
4702        nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4703        p = s;
4704        while ((c = *p++) != '\0') {
4705                str = NULL;
4706                switch (c) {
4707                case CTLESC:
4708                        c = *p++;
4709                        break;
4710                case CTLVAR:
4711                        subtype = *p++;
4712                        if ((subtype & VSTYPE) == VSLENGTH)
4713                                str = "${#";
4714                        else
4715                                str = "${";
4716                        goto dostr;
4717                case CTLENDVAR:
4718                        str = "\"}" + !(quoted & 1);
4719                        quoted >>= 1;
4720                        subtype = 0;
4721                        goto dostr;
4722                case CTLBACKQ:
4723                        str = "$(...)";
4724                        goto dostr;
4725#if ENABLE_FEATURE_SH_MATH
4726                case CTLARI:
4727                        str = "$((";
4728                        goto dostr;
4729                case CTLENDARI:
4730                        str = "))";
4731                        goto dostr;
4732#endif
4733                case CTLQUOTEMARK:
4734                        quoted ^= 1;
4735                        c = '"';
4736                        break;
4737                case '=':
4738                        if (subtype == 0)
4739                                break;
4740                        if ((subtype & VSTYPE) != VSNORMAL)
4741                                quoted <<= 1;
4742                        str = vstype[subtype & VSTYPE];
4743                        if (subtype & VSNUL)
4744                                c = ':';
4745                        else
4746                                goto checkstr;
4747                        break;
4748                case '\'':
4749                case '\\':
4750                case '"':
4751                case '$':
4752                        /* These can only happen inside quotes */
4753                        cc[0] = c;
4754                        str = cc;
4755//FIXME:
4756// $ true $$ &
4757// $ <cr>
4758// [1]+  Done    true ${\$}   <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
4759                        c = '\\';
4760                        break;
4761                default:
4762                        break;
4763                }
4764                USTPUTC(c, nextc);
4765 checkstr:
4766                if (!str)
4767                        continue;
4768 dostr:
4769                while ((c = *str++) != '\0') {
4770                        USTPUTC(c, nextc);
4771                }
4772        } /* while *p++ not NUL */
4773
4774        if (quoted & 1) {
4775                USTPUTC('"', nextc);
4776        }
4777        *nextc = 0;
4778        cmdnextc = nextc;
4779}
4780
4781/* cmdtxt() and cmdlist() call each other */
4782static void cmdtxt(union node *n);
4783
4784static void
4785cmdlist(union node *np, int sep)
4786{
4787        for (; np; np = np->narg.next) {
4788                if (!sep)
4789                        cmdputs(" ");
4790                cmdtxt(np);
4791                if (sep && np->narg.next)
4792                        cmdputs(" ");
4793        }
4794}
4795
4796static void
4797cmdtxt(union node *n)
4798{
4799        union node *np;
4800        struct nodelist *lp;
4801        const char *p;
4802
4803        if (!n)
4804                return;
4805        switch (n->type) {
4806        default:
4807#if DEBUG
4808                abort();
4809#endif
4810        case NPIPE:
4811                lp = n->npipe.cmdlist;
4812                for (;;) {
4813                        cmdtxt(lp->n);
4814                        lp = lp->next;
4815                        if (!lp)
4816                                break;
4817                        cmdputs(" | ");
4818                }
4819                break;
4820        case NSEMI:
4821                p = "; ";
4822                goto binop;
4823        case NAND:
4824                p = " && ";
4825                goto binop;
4826        case NOR:
4827                p = " || ";
4828 binop:
4829                cmdtxt(n->nbinary.ch1);
4830                cmdputs(p);
4831                n = n->nbinary.ch2;
4832                goto donode;
4833        case NREDIR:
4834        case NBACKGND:
4835                n = n->nredir.n;
4836                goto donode;
4837        case NNOT:
4838                cmdputs("!");
4839                n = n->nnot.com;
4840 donode:
4841                cmdtxt(n);
4842                break;
4843        case NIF:
4844                cmdputs("if ");
4845                cmdtxt(n->nif.test);
4846                cmdputs("; then ");
4847                if (n->nif.elsepart) {
4848                        cmdtxt(n->nif.ifpart);
4849                        cmdputs("; else ");
4850                        n = n->nif.elsepart;
4851                } else {
4852                        n = n->nif.ifpart;
4853                }
4854                p = "; fi";
4855                goto dotail;
4856        case NSUBSHELL:
4857                cmdputs("(");
4858                n = n->nredir.n;
4859                p = ")";
4860                goto dotail;
4861        case NWHILE:
4862                p = "while ";
4863                goto until;
4864        case NUNTIL:
4865                p = "until ";
4866 until:
4867                cmdputs(p);
4868                cmdtxt(n->nbinary.ch1);
4869                n = n->nbinary.ch2;
4870                p = "; done";
4871 dodo:
4872                cmdputs("; do ");
4873 dotail:
4874                cmdtxt(n);
4875                goto dotail2;
4876        case NFOR:
4877                cmdputs("for ");
4878                cmdputs(n->nfor.var);
4879                cmdputs(" in ");
4880                cmdlist(n->nfor.args, 1);
4881                n = n->nfor.body;
4882                p = "; done";
4883                goto dodo;
4884        case NDEFUN:
4885                cmdputs(n->ndefun.text);
4886                p = "() { ... }";
4887                goto dotail2;
4888        case NCMD:
4889                cmdlist(n->ncmd.args, 1);
4890                cmdlist(n->ncmd.redirect, 0);
4891                break;
4892        case NARG:
4893                p = n->narg.text;
4894 dotail2:
4895                cmdputs(p);
4896                break;
4897        case NHERE:
4898        case NXHERE:
4899                p = "<<...";
4900                goto dotail2;
4901        case NCASE:
4902                cmdputs("case ");
4903                cmdputs(n->ncase.expr->narg.text);
4904                cmdputs(" in ");
4905                for (np = n->ncase.cases; np; np = np->nclist.next) {
4906                        cmdtxt(np->nclist.pattern);
4907                        cmdputs(") ");
4908                        cmdtxt(np->nclist.body);
4909                        cmdputs(";; ");
4910                }
4911                p = "esac";
4912                goto dotail2;
4913        case NTO:
4914                p = ">";
4915                goto redir;
4916        case NCLOBBER:
4917                p = ">|";
4918                goto redir;
4919        case NAPPEND:
4920                p = ">>";
4921                goto redir;
4922#if BASH_REDIR_OUTPUT
4923        case NTO2:
4924#endif
4925        case NTOFD:
4926                p = ">&";
4927                goto redir;
4928        case NFROM:
4929                p = "<";
4930                goto redir;
4931        case NFROMFD:
4932                p = "<&";
4933                goto redir;
4934        case NFROMTO:
4935                p = "<>";
4936 redir:
4937                cmdputs(utoa(n->nfile.fd));
4938                cmdputs(p);
4939                if (n->type == NTOFD || n->type == NFROMFD) {
4940                        if (n->ndup.dupfd >= 0)
4941                                cmdputs(utoa(n->ndup.dupfd));
4942                        else
4943                                cmdputs("-");
4944                        break;
4945                }
4946                n = n->nfile.fname;
4947                goto donode;
4948        }
4949}
4950
4951static char *
4952commandtext(union node *n)
4953{
4954        char *name;
4955
4956        STARTSTACKSTR(cmdnextc);
4957        cmdtxt(n);
4958        name = stackblock();
4959        TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
4960        return ckstrdup(name);
4961}
4962#endif /* JOBS */
4963
4964/*
4965 * Fork off a subshell.  If we are doing job control, give the subshell its
4966 * own process group.  Jp is a job structure that the job is to be added to.
4967 * N is the command that will be evaluated by the child.  Both jp and n may
4968 * be NULL.  The mode parameter can be one of the following:
4969 *      FORK_FG - Fork off a foreground process.
4970 *      FORK_BG - Fork off a background process.
4971 *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
4972 *                   process group even if job control is on.
4973 *
4974 * When job control is turned off, background processes have their standard
4975 * input redirected to /dev/null (except for the second and later processes
4976 * in a pipeline).
4977 *
4978 * Called with interrupts off.
4979 */
4980/*
4981 * Clear traps on a fork.
4982 */
4983static void
4984clear_traps(void)
4985{
4986        char **tp;
4987
4988        INT_OFF;
4989        for (tp = trap; tp < &trap[NSIG]; tp++) {
4990                if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */
4991                        if (trap_ptr == trap)
4992                                free(*tp);
4993                        /* else: it "belongs" to trap_ptr vector, don't free */
4994                        *tp = NULL;
4995                        if ((tp - trap) != 0)
4996                                setsignal(tp - trap);
4997                }
4998        }
4999        may_have_traps = 0;
5000        INT_ON;
5001}
5002
5003/* Lives far away from here, needed for forkchild */
5004static void closescript(void);
5005
5006/* Called after fork(), in child */
5007/* jp and n are NULL when called by openhere() for heredoc support */
5008static NOINLINE void
5009forkchild(struct job *jp, union node *n, int mode)
5010{
5011        int oldlvl;
5012
5013        TRACE(("Child shell %d\n", getpid()));
5014        oldlvl = shlvl;
5015        shlvl++;
5016
5017        /* man bash: "Non-builtin commands run by bash have signal handlers
5018         * set to the values inherited by the shell from its parent".
5019         * Do we do it correctly? */
5020
5021        closescript();
5022
5023        if (mode == FORK_NOJOB          /* is it `xxx` ? */
5024         && n && n->type == NCMD        /* is it single cmd? */
5025        /* && n->ncmd.args->type == NARG - always true? */
5026         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
5027         && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5028        /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5029        ) {
5030                TRACE(("Trap hack\n"));
5031                /* Awful hack for `trap` or $(trap).
5032                 *
5033                 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5034                 * contains an example where "trap" is executed in a subshell:
5035                 *
5036                 * save_traps=$(trap)
5037                 * ...
5038                 * eval "$save_traps"
5039                 *
5040                 * Standard does not say that "trap" in subshell shall print
5041                 * parent shell's traps. It only says that its output
5042                 * must have suitable form, but then, in the above example
5043                 * (which is not supposed to be normative), it implies that.
5044                 *
5045                 * bash (and probably other shell) does implement it
5046                 * (traps are reset to defaults, but "trap" still shows them),
5047                 * but as a result, "trap" logic is hopelessly messed up:
5048                 *
5049                 * # trap
5050                 * trap -- 'echo Ho' SIGWINCH  <--- we have a handler
5051                 * # (trap)        <--- trap is in subshell - no output (correct, traps are reset)
5052                 * # true | trap   <--- trap is in subshell - no output (ditto)
5053                 * # echo `true | trap`    <--- in subshell - output (but traps are reset!)
5054                 * trap -- 'echo Ho' SIGWINCH
5055                 * # echo `(trap)`         <--- in subshell in subshell - output
5056                 * trap -- 'echo Ho' SIGWINCH
5057                 * # echo `true | (trap)`  <--- in subshell in subshell in subshell - output!
5058                 * trap -- 'echo Ho' SIGWINCH
5059                 *
5060                 * The rules when to forget and when to not forget traps
5061                 * get really complex and nonsensical.
5062                 *
5063                 * Our solution: ONLY bare $(trap) or `trap` is special.
5064                 */
5065                /* Save trap handler strings for trap builtin to print */
5066                trap_ptr = xmemdup(trap, sizeof(trap));
5067                /* Fall through into clearing traps */
5068        }
5069        clear_traps();
5070#if JOBS
5071        /* do job control only in root shell */
5072        doing_jobctl = 0;
5073        if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
5074                pid_t pgrp;
5075
5076                if (jp->nprocs == 0)
5077                        pgrp = getpid();
5078                else
5079                        pgrp = jp->ps[0].ps_pid;
5080                /* this can fail because we are doing it in the parent also */
5081                setpgid(0, pgrp);
5082                if (mode == FORK_FG)
5083                        xtcsetpgrp(ttyfd, pgrp);
5084                setsignal(SIGTSTP);
5085                setsignal(SIGTTOU);
5086        } else
5087#endif
5088        if (mode == FORK_BG) {
5089                /* man bash: "When job control is not in effect,
5090                 * asynchronous commands ignore SIGINT and SIGQUIT" */
5091                ignoresig(SIGINT);
5092                ignoresig(SIGQUIT);
5093                if (jp->nprocs == 0) {
5094                        close(0);
5095                        if (open(bb_dev_null, O_RDONLY) != 0)
5096                                ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
5097                }
5098        }
5099        if (oldlvl == 0) {
5100                if (iflag) { /* why if iflag only? */
5101                        setsignal(SIGINT);
5102                        setsignal(SIGTERM);
5103                }
5104                /* man bash:
5105                 * "In all cases, bash ignores SIGQUIT. Non-builtin
5106                 * commands run by bash have signal handlers
5107                 * set to the values inherited by the shell
5108                 * from its parent".
5109                 * Take care of the second rule: */
5110                setsignal(SIGQUIT);
5111        }
5112#if JOBS
5113        if (n && n->type == NCMD
5114         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
5115        ) {
5116                TRACE(("Job hack\n"));
5117                /* "jobs": we do not want to clear job list for it,
5118                 * instead we remove only _its_ own_ job from job list.
5119                 * This makes "jobs .... | cat" more useful.
5120                 */
5121                freejob(curjob);
5122                return;
5123        }
5124#endif
5125        for (jp = curjob; jp; jp = jp->prev_job)
5126                freejob(jp);
5127        jobless = 0;
5128}
5129
5130/* Called after fork(), in parent */
5131#if !JOBS
5132#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5133#endif
5134static void
5135forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5136{
5137        TRACE(("In parent shell: child = %d\n", pid));
5138        if (!jp) {
5139                /* jp is NULL when called by openhere() for heredoc support */
5140                while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5141                        continue;
5142                jobless++;
5143                return;
5144        }
5145#if JOBS
5146        if (mode != FORK_NOJOB && jp->jobctl) {
5147                int pgrp;
5148
5149                if (jp->nprocs == 0)
5150                        pgrp = pid;
5151                else
5152                        pgrp = jp->ps[0].ps_pid;
5153                /* This can fail because we are doing it in the child also */
5154                setpgid(pid, pgrp);
5155        }
5156#endif
5157        if (mode == FORK_BG) {
5158                backgndpid = pid;               /* set $! */
5159                set_curjob(jp, CUR_RUNNING);
5160        }
5161        if (jp) {
5162                struct procstat *ps = &jp->ps[jp->nprocs++];
5163                ps->ps_pid = pid;
5164                ps->ps_status = -1;
5165                ps->ps_cmd = nullstr;
5166#if JOBS
5167                if (doing_jobctl && n)
5168                        ps->ps_cmd = commandtext(n);
5169#endif
5170        }
5171}
5172
5173/* jp and n are NULL when called by openhere() for heredoc support */
5174static int
5175forkshell(struct job *jp, union node *n, int mode)
5176{
5177        int pid;
5178
5179        TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5180        pid = fork();
5181        if (pid < 0) {
5182                TRACE(("Fork failed, errno=%d", errno));
5183                if (jp)
5184                        freejob(jp);
5185                ash_msg_and_raise_perror("can't fork");
5186        }
5187        if (pid == 0) {
5188                CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
5189                forkchild(jp, n, mode);
5190        } else {
5191                forkparent(jp, n, mode, pid);
5192        }
5193        return pid;
5194}
5195
5196/*
5197 * Wait for job to finish.
5198 *
5199 * Under job control we have the problem that while a child process
5200 * is running interrupts generated by the user are sent to the child
5201 * but not to the shell.  This means that an infinite loop started by
5202 * an interactive user may be hard to kill.  With job control turned off,
5203 * an interactive user may place an interactive program inside a loop.
5204 * If the interactive program catches interrupts, the user doesn't want
5205 * these interrupts to also abort the loop.  The approach we take here
5206 * is to have the shell ignore interrupt signals while waiting for a
5207 * foreground process to terminate, and then send itself an interrupt
5208 * signal if the child process was terminated by an interrupt signal.
5209 * Unfortunately, some programs want to do a bit of cleanup and then
5210 * exit on interrupt; unless these processes terminate themselves by
5211 * sending a signal to themselves (instead of calling exit) they will
5212 * confuse this approach.
5213 *
5214 * Called with interrupts off.
5215 */
5216static int
5217waitforjob(struct job *jp)
5218{
5219        int st;
5220
5221        TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
5222
5223        INT_OFF;
5224        while (jp->state == JOBRUNNING) {
5225                /* In non-interactive shells, we _can_ get
5226                 * a keyboard signal here and be EINTRed,
5227                 * but we just loop back, waiting for command to complete.
5228                 *
5229                 * man bash:
5230                 * "If bash is waiting for a command to complete and receives
5231                 * a signal for which a trap has been set, the trap
5232                 * will not be executed until the command completes."
5233                 *
5234                 * Reality is that even if trap is not set, bash
5235                 * will not act on the signal until command completes.
5236                 * Try this. sleep5intoff.c:
5237                 * #include <signal.h>
5238                 * #include <unistd.h>
5239                 * int main() {
5240                 *         sigset_t set;
5241                 *         sigemptyset(&set);
5242                 *         sigaddset(&set, SIGINT);
5243                 *         sigaddset(&set, SIGQUIT);
5244                 *         sigprocmask(SIG_BLOCK, &set, NULL);
5245                 *         sleep(5);
5246                 *         return 0;
5247                 * }
5248                 * $ bash -c './sleep5intoff; echo hi'
5249                 * ^C^C^C^C <--- pressing ^C once a second
5250                 * $ _
5251                 * $ bash -c './sleep5intoff; echo hi'
5252                 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5253                 * $ _
5254                 */
5255                dowait(DOWAIT_BLOCK, jp);
5256        }
5257        INT_ON;
5258
5259        st = getstatus(jp);
5260#if JOBS
5261        if (jp->jobctl) {
5262                xtcsetpgrp(ttyfd, rootpid);
5263                restore_tty_if_stopped_or_signaled(jp);
5264
5265                /*
5266                 * This is truly gross.
5267                 * If we're doing job control, then we did a TIOCSPGRP which
5268                 * caused us (the shell) to no longer be in the controlling
5269                 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
5270                 * intuit from the subprocess exit status whether a SIGINT
5271                 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
5272                 */
5273                if (jp->sigint) /* TODO: do the same with all signals */
5274                        raise(SIGINT); /* ... by raise(jp->sig) instead? */
5275        }
5276        if (jp->state == JOBDONE)
5277#endif
5278                freejob(jp);
5279        return st;
5280}
5281
5282/*
5283 * return 1 if there are stopped jobs, otherwise 0
5284 */
5285static int
5286stoppedjobs(void)
5287{
5288        struct job *jp;
5289        int retval;
5290
5291        retval = 0;
5292        if (job_warning)
5293                goto out;
5294        jp = curjob;
5295        if (jp && jp->state == JOBSTOPPED) {
5296                out2str("You have stopped jobs.\n");
5297                job_warning = 2;
5298                retval++;
5299        }
5300 out:
5301        return retval;
5302}
5303
5304
5305/*
5306 * Code for dealing with input/output redirection.
5307 */
5308
5309#undef EMPTY
5310#undef CLOSED
5311#define EMPTY -2                /* marks an unused slot in redirtab */
5312#define CLOSED -1               /* marks a slot of previously-closed fd */
5313
5314/*
5315 * Handle here documents.  Normally we fork off a process to write the
5316 * data to a pipe.  If the document is short, we can stuff the data in
5317 * the pipe without forking.
5318 */
5319/* openhere needs this forward reference */
5320static void expandhere(union node *arg, int fd);
5321static int
5322openhere(union node *redir)
5323{
5324        int pip[2];
5325        size_t len = 0;
5326
5327        if (pipe(pip) < 0)
5328                ash_msg_and_raise_perror("can't create pipe");
5329        if (redir->type == NHERE) {
5330                len = strlen(redir->nhere.doc->narg.text);
5331                if (len <= PIPE_BUF) {
5332                        full_write(pip[1], redir->nhere.doc->narg.text, len);
5333                        goto out;
5334                }
5335        }
5336        if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5337                /* child */
5338                close(pip[0]);
5339                ignoresig(SIGINT);  //signal(SIGINT, SIG_IGN);
5340                ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5341                ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
5342                ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5343                signal(SIGPIPE, SIG_DFL);
5344                if (redir->type == NHERE)
5345                        full_write(pip[1], redir->nhere.doc->narg.text, len);
5346                else /* NXHERE */
5347                        expandhere(redir->nhere.doc, pip[1]);
5348                _exit(EXIT_SUCCESS);
5349        }
5350 out:
5351        close(pip[1]);
5352        return pip[0];
5353}
5354
5355static int
5356openredirect(union node *redir)
5357{
5358        struct stat sb;
5359        char *fname;
5360        int f;
5361
5362        switch (redir->nfile.type) {
5363/* Can't happen, our single caller does this itself */
5364//      case NTOFD:
5365//      case NFROMFD:
5366//              return -1;
5367        case NHERE:
5368        case NXHERE:
5369                return openhere(redir);
5370        }
5371
5372        /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5373         * allocated space. Do it only when we know it is safe.
5374         */
5375        fname = redir->nfile.expfname;
5376
5377        switch (redir->nfile.type) {
5378        default:
5379#if DEBUG
5380                abort();
5381#endif
5382        case NFROM:
5383                f = open(fname, O_RDONLY);
5384                if (f < 0)
5385                        goto eopen;
5386                break;
5387        case NFROMTO:
5388                f = open(fname, O_RDWR|O_CREAT, 0666);
5389                if (f < 0)
5390                        goto ecreate;
5391                break;
5392        case NTO:
5393#if BASH_REDIR_OUTPUT
5394        case NTO2:
5395#endif
5396                /* Take care of noclobber mode. */
5397                if (Cflag) {
5398                        if (stat(fname, &sb) < 0) {
5399                                f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5400                                if (f < 0)
5401                                        goto ecreate;
5402                        } else if (!S_ISREG(sb.st_mode)) {
5403                                f = open(fname, O_WRONLY, 0666);
5404                                if (f < 0)
5405                                        goto ecreate;
5406                                if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
5407                                        close(f);
5408                                        errno = EEXIST;
5409                                        goto ecreate;
5410                                }
5411                        } else {
5412                                errno = EEXIST;
5413                                goto ecreate;
5414                        }
5415                        break;
5416                }
5417                /* FALLTHROUGH */
5418        case NCLOBBER:
5419                f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5420                if (f < 0)
5421                        goto ecreate;
5422                break;
5423        case NAPPEND:
5424                f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5425                if (f < 0)
5426                        goto ecreate;
5427                break;
5428        }
5429
5430        return f;
5431 ecreate:
5432        ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5433 eopen:
5434        ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5435}
5436
5437/*
5438 * Copy a file descriptor to be >= 10. Throws exception on error.
5439 */
5440static int
5441savefd(int from)
5442{
5443        int newfd;
5444        int err;
5445
5446        newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
5447        err = newfd < 0 ? errno : 0;
5448        if (err != EBADF) {
5449                if (err)
5450                        ash_msg_and_raise_perror("%d", from);
5451                close(from);
5452                if (F_DUPFD_CLOEXEC == F_DUPFD)
5453                        close_on_exec_on(newfd);
5454        }
5455
5456        return newfd;
5457}
5458static int
5459dup2_or_raise(int from, int to)
5460{
5461        int newfd;
5462
5463        newfd = (from != to) ? dup2(from, to) : to;
5464        if (newfd < 0) {
5465                /* Happens when source fd is not open: try "echo >&99" */
5466                ash_msg_and_raise_perror("%d", from);
5467        }
5468        return newfd;
5469}
5470static int
5471dup_CLOEXEC(int fd, int avoid_fd)
5472{
5473        int newfd;
5474 repeat:
5475        newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5476        if (newfd >= 0) {
5477                if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
5478                        close_on_exec_on(newfd);
5479        } else { /* newfd < 0 */
5480                if (errno == EBUSY)
5481                        goto repeat;
5482                if (errno == EINTR)
5483                        goto repeat;
5484        }
5485        return newfd;
5486}
5487static int
5488xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5489{
5490        int newfd;
5491 repeat:
5492        newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5493        if (newfd < 0) {
5494                if (errno == EBUSY)
5495                        goto repeat;
5496                if (errno == EINTR)
5497                        goto repeat;
5498                /* fd was not open? */
5499                if (errno == EBADF)
5500                        return fd;
5501                ash_msg_and_raise_perror("%d", newfd);
5502        }
5503        if (F_DUPFD_CLOEXEC == F_DUPFD)
5504                close_on_exec_on(newfd);
5505        close(fd);
5506        return newfd;
5507}
5508
5509/* Struct def and variable are moved down to the first usage site */
5510struct squirrel {
5511        int orig_fd;
5512        int moved_to;
5513};
5514struct redirtab {
5515        struct redirtab *next;
5516        int pair_count;
5517        struct squirrel two_fd[];
5518};
5519#define redirlist (G_var.redirlist)
5520
5521static void
5522add_squirrel_closed(struct redirtab *sq, int fd)
5523{
5524        int i;
5525
5526        if (!sq)
5527                return;
5528
5529        for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5530                /* If we collide with an already moved fd... */
5531                if (fd == sq->two_fd[i].orig_fd) {
5532                        /* Examples:
5533                         * "echo 3>FILE 3>&- 3>FILE"
5534                         * "echo 3>&- 3>FILE"
5535                         * No need for last redirect to insert
5536                         * another "need to close 3" indicator.
5537                         */
5538                        TRACE(("redirect_fd %d: already moved or closed\n", fd));
5539                        return;
5540                }
5541        }
5542        TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5543        sq->two_fd[i].orig_fd = fd;
5544        sq->two_fd[i].moved_to = CLOSED;
5545}
5546
5547static int
5548save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5549{
5550        int i, new_fd;
5551
5552        if (avoid_fd < 9) /* the important case here is that it can be -1 */
5553                avoid_fd = 9;
5554
5555#if JOBS
5556        if (fd == ttyfd) {
5557                /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5558                ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5559                TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5560                return 1; /* "we closed fd" */
5561        }
5562#endif
5563        /* Are we called from redirect(0)? E.g. redirect
5564         * in a forked child. No need to save fds,
5565         * we aren't going to use them anymore, ok to trash.
5566         */
5567        if (!sq)
5568                return 0;
5569
5570        /* If this one of script's fds? */
5571        if (fd != 0) {
5572                struct parsefile *pf = g_parsefile;
5573                while (pf) {
5574                        /* We skip fd == 0 case because of the following:
5575                         * $ ash  # running ash interactively
5576                         * $ . ./script.sh
5577                         * and in script.sh: "exec 9>&0".
5578                         * Even though top-level pf_fd _is_ 0,
5579                         * it's still ok to use it: "read" builtin uses it,
5580                         * why should we cripple "exec" builtin?
5581                         */
5582                        if (fd == pf->pf_fd) {
5583                                pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5584                                return 1; /* "we closed fd" */
5585                        }
5586                        pf = pf->prev;
5587                }
5588        }
5589
5590        /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5591
5592        /* First: do we collide with some already moved fds? */
5593        for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5594                /* If we collide with an already moved fd... */
5595                if (fd == sq->two_fd[i].moved_to) {
5596                        new_fd = dup_CLOEXEC(fd, avoid_fd);
5597                        sq->two_fd[i].moved_to = new_fd;
5598                        TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5599                        if (new_fd < 0) /* what? */
5600                                xfunc_die();
5601                        return 0; /* "we did not close fd" */
5602                }
5603                if (fd == sq->two_fd[i].orig_fd) {
5604                        /* Example: echo Hello >/dev/null 1>&2 */
5605                        TRACE(("redirect_fd %d: already moved\n", fd));
5606                        return 0; /* "we did not close fd" */
5607                }
5608        }
5609
5610        /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5611        new_fd = dup_CLOEXEC(fd, avoid_fd);
5612        TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5613        if (new_fd < 0) {
5614                if (errno != EBADF)
5615                        xfunc_die();
5616                /* new_fd = CLOSED; - already is -1 */
5617        }
5618        sq->two_fd[i].moved_to = new_fd;
5619        sq->two_fd[i].orig_fd = fd;
5620
5621        /* if we move stderr, let "set -x" code know */
5622        if (fd == preverrout_fd)
5623                preverrout_fd = new_fd;
5624
5625        return 0; /* "we did not close fd" */
5626}
5627
5628static int
5629internally_opened_fd(int fd, struct redirtab *sq)
5630{
5631        int i;
5632#if JOBS
5633        if (fd == ttyfd)
5634                return 1;
5635#endif
5636        /* If this one of script's fds? */
5637        if (fd != 0) {
5638                struct parsefile *pf = g_parsefile;
5639                while (pf) {
5640                        if (fd == pf->pf_fd)
5641                                return 1;
5642                        pf = pf->prev;
5643                }
5644        }
5645
5646        if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5647                if (fd == sq->two_fd[i].moved_to)
5648                        return 1;
5649        }
5650        return 0;
5651}
5652
5653/*
5654 * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
5655 * old file descriptors are stashed away so that the redirection can be
5656 * undone by calling popredir.
5657 */
5658/* flags passed to redirect */
5659#define REDIR_PUSH    01        /* save previous values of file descriptors */
5660static void
5661redirect(union node *redir, int flags)
5662{
5663        struct redirtab *sv;
5664
5665        if (!redir)
5666                return;
5667
5668        sv = NULL;
5669        INT_OFF;
5670        if (flags & REDIR_PUSH)
5671                sv = redirlist;
5672        do {
5673                int fd;
5674                int newfd;
5675                int close_fd;
5676                int closed;
5677
5678                fd = redir->nfile.fd;
5679                if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5680                        //bb_error_msg("doing %d > %d", fd, newfd);
5681                        newfd = redir->ndup.dupfd;
5682                        close_fd = -1;
5683                } else {
5684                        newfd = openredirect(redir); /* always >= 0 */
5685                        if (fd == newfd) {
5686                                /* open() gave us precisely the fd we wanted.
5687                                 * This means that this fd was not busy
5688                                 * (not opened to anywhere).
5689                                 * Remember to close it on restore:
5690                                 */
5691                                add_squirrel_closed(sv, fd);
5692                                continue;
5693                        }
5694                        close_fd = newfd;
5695                }
5696
5697                if (fd == newfd)
5698                        continue;
5699
5700                /* if "N>FILE": move newfd to fd */
5701                /* if "N>&M": dup newfd to fd */
5702                /* if "N>&-": close fd (newfd is -1) */
5703
5704 IF_BASH_REDIR_OUTPUT(redirect_more:)
5705
5706                closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5707                if (newfd == -1) {
5708                        /* "N>&-" means "close me" */
5709                        if (!closed) {
5710                                /* ^^^ optimization: saving may already
5711                                 * have closed it. If not... */
5712                                close(fd);
5713                        }
5714                } else {
5715                        /* if newfd is a script fd or saved fd, simulate EBADF */
5716                        if (internally_opened_fd(newfd, sv)) {
5717                                errno = EBADF;
5718                                ash_msg_and_raise_perror("%d", newfd);
5719                        }
5720                        dup2_or_raise(newfd, fd);
5721                        if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5722                                close(close_fd);
5723#if BASH_REDIR_OUTPUT
5724                        if (redir->nfile.type == NTO2 && fd == 1) {
5725                                /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5726                                fd = 2;
5727                                newfd = 1;
5728                                close_fd = -1;
5729                                goto redirect_more;
5730                        }
5731#endif
5732                }
5733        } while ((redir = redir->nfile.next) != NULL);
5734        INT_ON;
5735
5736//dash:#define REDIR_SAVEFD2 03        /* set preverrout */
5737#define REDIR_SAVEFD2 0
5738        // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5739        // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5740        // not only for calls with flags containing REDIR_SAVEFD2.
5741        // We do this unconditionally (see save_fd_on_redirect()).
5742        //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5743        //      preverrout_fd = copied_fd2;
5744}
5745
5746static int
5747redirectsafe(union node *redir, int flags)
5748{
5749        int err;
5750        volatile int saveint;
5751        struct jmploc *volatile savehandler = exception_handler;
5752        struct jmploc jmploc;
5753
5754        SAVE_INT(saveint);
5755        /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5756        err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
5757        if (!err) {
5758                exception_handler = &jmploc;
5759                redirect(redir, flags);
5760        }
5761        exception_handler = savehandler;
5762        if (err && exception_type != EXERROR)
5763                longjmp(exception_handler->loc, 1);
5764        RESTORE_INT(saveint);
5765        return err;
5766}
5767
5768static struct redirtab*
5769pushredir(union node *redir)
5770{
5771        struct redirtab *sv;
5772        int i;
5773
5774        if (!redir)
5775                return redirlist;
5776
5777        i = 0;
5778        do {
5779                i++;
5780#if BASH_REDIR_OUTPUT
5781                if (redir->nfile.type == NTO2)
5782                        i++;
5783#endif
5784                redir = redir->nfile.next;
5785        } while (redir);
5786
5787        sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5788        sv->pair_count = i;
5789        while (--i >= 0)
5790                sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
5791        sv->next = redirlist;
5792        redirlist = sv;
5793        return sv->next;
5794}
5795
5796/*
5797 * Undo the effects of the last redirection.
5798 */
5799static void
5800popredir(int drop)
5801{
5802        struct redirtab *rp;
5803        int i;
5804
5805        if (redirlist == NULL)
5806                return;
5807        INT_OFF;
5808        rp = redirlist;
5809        for (i = 0; i < rp->pair_count; i++) {
5810                int fd = rp->two_fd[i].orig_fd;
5811                int copy = rp->two_fd[i].moved_to;
5812                if (copy == CLOSED) {
5813                        if (!drop)
5814                                close(fd);
5815                        continue;
5816                }
5817                if (copy != EMPTY) {
5818                        if (!drop) {
5819                                /*close(fd);*/
5820                                dup2_or_raise(copy, fd);
5821                        }
5822                        close(copy);
5823                }
5824        }
5825        redirlist = rp->next;
5826        free(rp);
5827        INT_ON;
5828}
5829
5830static void
5831unwindredir(struct redirtab *stop)
5832{
5833        while (redirlist != stop)
5834                popredir(/*drop:*/ 0);
5835}
5836
5837
5838/* ============ Routines to expand arguments to commands
5839 *
5840 * We have to deal with backquotes, shell variables, and file metacharacters.
5841 */
5842
5843#if ENABLE_FEATURE_SH_MATH
5844static arith_t
5845ash_arith(const char *s)
5846{
5847        arith_state_t math_state;
5848        arith_t result;
5849
5850        math_state.lookupvar = lookupvar;
5851        math_state.setvar    = setvar0;
5852        //math_state.endofname = endofname;
5853
5854        INT_OFF;
5855        result = arith(&math_state, s);
5856        if (math_state.errmsg)
5857                ash_msg_and_raise_error(math_state.errmsg);
5858        INT_ON;
5859
5860        return result;
5861}
5862#endif
5863#if BASH_SUBSTR
5864# if ENABLE_FEATURE_SH_MATH
5865static int substr_atoi(const char *s)
5866{
5867        arith_t t = ash_arith(s);
5868        if (sizeof(t) > sizeof(int)) {
5869                /* clamp very large or very large negative nums for ${v:N:M}:
5870                 * else "${v:0:0x100000001}" would work as "${v:0:1}"
5871                 */
5872                if (t > INT_MAX)
5873                        t = INT_MAX;
5874                if (t < INT_MIN)
5875                        t = INT_MIN;
5876        }
5877        return t;
5878}
5879# else
5880#  define substr_atoi(s) number(s)
5881# endif
5882#endif
5883
5884/*
5885 * expandarg flags
5886 */
5887#define EXP_FULL        0x1     /* perform word splitting & file globbing */
5888#define EXP_TILDE       0x2     /* do normal tilde expansion */
5889#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
5890#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
5891/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5892 * POSIX says for this case:
5893 *  Pathname expansion shall not be performed on the word by a
5894 *  non-interactive shell; an interactive shell may perform it, but shall
5895 *  do so only when the expansion would result in one word.
5896 * Currently, our code complies to the above rule by never globbing
5897 * redirection filenames.
5898 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5899 * (this means that on a typical Linux distro, bash almost always
5900 * performs globbing, and thus diverges from what we do).
5901 */
5902#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
5903#define EXP_VARTILDE2   0x20    /* expand tildes after colons only */
5904#define EXP_WORD        0x40    /* expand word in parameter expansion */
5905#define EXP_QUOTED      0x80    /* expand word in double quotes */
5906/*
5907 * rmescape() flags
5908 */
5909#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
5910#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
5911#define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
5912#define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
5913
5914/* Add CTLESC when necessary. */
5915#define QUOTES_ESC     (EXP_FULL | EXP_CASE)
5916/* Do not skip NUL characters. */
5917#define QUOTES_KEEPNUL EXP_TILDE
5918
5919/*
5920 * Structure specifying which parts of the string should be searched
5921 * for IFS characters.
5922 */
5923struct ifsregion {
5924        struct ifsregion *next; /* next region in list */
5925        int begoff;             /* offset of start of region */
5926        int endoff;             /* offset of end of region */
5927        int nulonly;            /* search for nul bytes only */
5928};
5929
5930struct arglist {
5931        struct strlist *list;
5932        struct strlist **lastp;
5933};
5934
5935/* output of current string */
5936static char *expdest;
5937/* list of back quote expressions */
5938static struct nodelist *argbackq;
5939/* first struct in list of ifs regions */
5940static struct ifsregion ifsfirst;
5941/* last struct in list */
5942static struct ifsregion *ifslastp;
5943/* holds expanded arg list */
5944static struct arglist exparg;
5945
5946/*
5947 * Our own itoa().
5948 * cvtnum() is used even if math support is off (to prepare $? values and such).
5949 */
5950static int
5951cvtnum(arith_t num)
5952{
5953        int len;
5954
5955        /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5956        len = sizeof(arith_t) * 3;
5957        /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5958        if (sizeof(arith_t) < 4) len += 2;
5959
5960        expdest = makestrspace(len, expdest);
5961        len = fmtstr(expdest, len, ARITH_FMT, num);
5962        STADJUST(len, expdest);
5963        return len;
5964}
5965
5966/*
5967 * Break the argument string into pieces based upon IFS and add the
5968 * strings to the argument list.  The regions of the string to be
5969 * searched for IFS characters have been stored by recordregion.
5970 */
5971static void
5972ifsbreakup(char *string, struct arglist *arglist)
5973{
5974        struct ifsregion *ifsp;
5975        struct strlist *sp;
5976        char *start;
5977        char *p;
5978        char *q;
5979        const char *ifs, *realifs;
5980        int ifsspc;
5981        int nulonly;
5982
5983        start = string;
5984        if (ifslastp != NULL) {
5985                ifsspc = 0;
5986                nulonly = 0;
5987                realifs = ifsset() ? ifsval() : defifs;
5988                ifsp = &ifsfirst;
5989                do {
5990                        int afternul;
5991
5992                        p = string + ifsp->begoff;
5993                        afternul = nulonly;
5994                        nulonly = ifsp->nulonly;
5995                        ifs = nulonly ? nullstr : realifs;
5996                        ifsspc = 0;
5997                        while (p < string + ifsp->endoff) {
5998                                q = p;
5999                                if ((unsigned char)*p == CTLESC)
6000                                        p++;
6001                                if (!strchr(ifs, *p)) {
6002                                        p++;
6003                                        continue;
6004                                }
6005                                if (!(afternul || nulonly))
6006                                        ifsspc = (strchr(defifs, *p) != NULL);
6007                                /* Ignore IFS whitespace at start */
6008                                if (q == start && ifsspc) {
6009                                        p++;
6010                                        start = p;
6011                                        continue;
6012                                }
6013                                *q = '\0';
6014                                sp = stzalloc(sizeof(*sp));
6015                                sp->text = start;
6016                                *arglist->lastp = sp;
6017                                arglist->lastp = &sp->next;
6018                                p++;
6019                                if (!nulonly) {
6020                                        for (;;) {
6021                                                if (p >= string + ifsp->endoff) {
6022                                                        break;
6023                                                }
6024                                                q = p;
6025                                                if ((unsigned char)*p == CTLESC)
6026                                                        p++;
6027                                                if (strchr(ifs, *p) == NULL) {
6028                                                        p = q;
6029                                                        break;
6030                                                }
6031                                                if (strchr(defifs, *p) == NULL) {
6032                                                        if (ifsspc) {
6033                                                                p++;
6034                                                                ifsspc = 0;
6035                                                        } else {
6036                                                                p = q;
6037                                                                break;
6038                                                        }
6039                                                } else
6040                                                        p++;
6041                                        }
6042                                }
6043                                start = p;
6044                        } /* while */
6045                        ifsp = ifsp->next;
6046                } while (ifsp != NULL);
6047                if (nulonly)
6048                        goto add;
6049        }
6050
6051        if (!*start)
6052                return;
6053
6054 add:
6055        sp = stzalloc(sizeof(*sp));
6056        sp->text = start;
6057        *arglist->lastp = sp;
6058        arglist->lastp = &sp->next;
6059}
6060
6061static void
6062ifsfree(void)
6063{
6064        struct ifsregion *p = ifsfirst.next;
6065
6066        if (!p)
6067                goto out;
6068
6069        INT_OFF;
6070        do {
6071                struct ifsregion *ifsp;
6072                ifsp = p->next;
6073                free(p);
6074                p = ifsp;
6075        } while (p);
6076        ifsfirst.next = NULL;
6077        INT_ON;
6078 out:
6079        ifslastp = NULL;
6080}
6081
6082static size_t
6083esclen(const char *start, const char *p)
6084{
6085        size_t esc = 0;
6086
6087        while (p > start && (unsigned char)*--p == CTLESC) {
6088                esc++;
6089        }
6090        return esc;
6091}
6092
6093/*
6094 * Remove any CTLESC characters from a string.
6095 */
6096#if !BASH_PATTERN_SUBST
6097#define rmescapes(str, flag, slash_position) \
6098        rmescapes(str, flag)
6099#endif
6100static char *
6101rmescapes(char *str, int flag, int *slash_position)
6102{
6103        static const char qchars[] ALIGN1 = {
6104                IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
6105
6106        char *p, *q, *r;
6107        unsigned protect_against_glob;
6108        unsigned globbing;
6109
6110        p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
6111        if (!p)
6112                return str;
6113
6114        q = p;
6115        r = str;
6116        if (flag & RMESCAPE_ALLOC) {
6117                size_t len = p - str;
6118                size_t fulllen = len + strlen(p) + 1;
6119
6120                if (flag & RMESCAPE_GROW) {
6121                        int strloc = str - (char *)stackblock();
6122                        r = makestrspace(fulllen, expdest);
6123                        /* p and str may be invalidated by makestrspace */
6124                        str = (char *)stackblock() + strloc;
6125                        p = str + len;
6126                } else if (flag & RMESCAPE_HEAP) {
6127                        r = ckmalloc(fulllen);
6128                } else {
6129                        r = stalloc(fulllen);
6130                }
6131                q = r;
6132                if (len > 0) {
6133                        q = (char *)mempcpy(q, str, len);
6134                }
6135        }
6136
6137        globbing = flag & RMESCAPE_GLOB;
6138        protect_against_glob = globbing;
6139        while (*p) {
6140                if ((unsigned char)*p == CTLQUOTEMARK) {
6141// Note: protect_against_glob only affect whether
6142// CTLESC,<ch> gets converted to <ch> or to \<ch>
6143                        p++;
6144                        protect_against_glob = globbing;
6145                        continue;
6146                }
6147                if (*p == '\\') {
6148                        /* naked back slash */
6149                        protect_against_glob = 0;
6150                        goto copy;
6151                }
6152                if ((unsigned char)*p == CTLESC) {
6153                        p++;
6154#if DEBUG
6155                        if (*p == '\0')
6156                                ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6157#endif
6158                        if (protect_against_glob) {
6159                                /*
6160                                 * We used to trust glob() and fnmatch() to eat
6161                                 * superfluous escapes (\z where z has no
6162                                 * special meaning anyway). But this causes
6163                                 * bugs such as string of one greek letter rho
6164                                 * (unicode-encoded as two bytes "cf,81")
6165                                 * getting encoded as "cf,CTLESC,81"
6166                                 * and here, converted to "cf,\,81" -
6167                                 * which does not go well with some flavors
6168                                 * of fnmatch() in unicode locales
6169                                 * (for example, glibc <= 2.22).
6170                                 *
6171                                 * Lets add "\" only on the chars which need it.
6172                                 * Testcases for less obvious chars are shown.
6173                                 */
6174                                if (*p == '*'
6175                                 || *p == '?'
6176                                 || *p == '['
6177                                 || *p == '\\' /* case '\' in \\    ) echo ok;; *) echo WRONG;; esac */
6178                                 || *p == ']'  /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6179                                 || *p == '-'  /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6180                                 || *p == '!'  /* case '!' in [\!]  ) echo ok;; *) echo WRONG;; esac */
6181                                /* Some libc support [^negate], that's why "^" also needs love */
6182                                 || *p == '^'  /* case '^' in [\^]  ) echo ok;; *) echo WRONG;; esac */
6183                                ) {
6184                                        *q++ = '\\';
6185                                }
6186                        }
6187                }
6188#if BASH_PATTERN_SUBST
6189                else if (slash_position && p == str + *slash_position) {
6190                        /* stop handling globbing */
6191                        globbing = 0;
6192                        *slash_position = q - r;
6193                        slash_position = NULL;
6194                }
6195#endif
6196                protect_against_glob = globbing;
6197 copy:
6198                *q++ = *p++;
6199        }
6200        *q = '\0';
6201        if (flag & RMESCAPE_GROW) {
6202                expdest = r;
6203                STADJUST(q - r + 1, expdest);
6204        }
6205        return r;
6206}
6207#define pmatch(a, b) !fnmatch((a), (b), 0)
6208
6209/*
6210 * Prepare a pattern for a expmeta (internal glob(3)) call.
6211 *
6212 * Returns an stalloced string.
6213 */
6214static char *
6215preglob(const char *pattern, int flag)
6216{
6217        return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
6218}
6219
6220/*
6221 * Put a string on the stack.
6222 */
6223static void
6224memtodest(const char *p, size_t len, int syntax, int quotes)
6225{
6226        char *q;
6227
6228        if (!len)
6229                return;
6230
6231        q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6232
6233        do {
6234                unsigned char c = *p++;
6235                if (c) {
6236                        if (quotes & QUOTES_ESC) {
6237                                int n = SIT(c, syntax);
6238                                if (n == CCTL
6239                                 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6240                                     && n == CBACK
6241                                    )
6242                                ) {
6243                                        USTPUTC(CTLESC, q);
6244                                }
6245                        }
6246                } else if (!(quotes & QUOTES_KEEPNUL))
6247                        continue;
6248                USTPUTC(c, q);
6249        } while (--len);
6250
6251        expdest = q;
6252}
6253
6254static size_t
6255strtodest(const char *p, int syntax, int quotes)
6256{
6257        size_t len = strlen(p);
6258        memtodest(p, len, syntax, quotes);
6259        return len;
6260}
6261
6262/*
6263 * Record the fact that we have to scan this region of the
6264 * string for IFS characters.
6265 */
6266static void
6267recordregion(int start, int end, int nulonly)
6268{
6269        struct ifsregion *ifsp;
6270
6271        if (ifslastp == NULL) {
6272                ifsp = &ifsfirst;
6273        } else {
6274                INT_OFF;
6275                ifsp = ckzalloc(sizeof(*ifsp));
6276                /*ifsp->next = NULL; - ckzalloc did it */
6277                ifslastp->next = ifsp;
6278                INT_ON;
6279        }
6280        ifslastp = ifsp;
6281        ifslastp->begoff = start;
6282        ifslastp->endoff = end;
6283        ifslastp->nulonly = nulonly;
6284}
6285
6286static void
6287removerecordregions(int endoff)
6288{
6289        if (ifslastp == NULL)
6290                return;
6291
6292        if (ifsfirst.endoff > endoff) {
6293                while (ifsfirst.next) {
6294                        struct ifsregion *ifsp;
6295                        INT_OFF;
6296                        ifsp = ifsfirst.next->next;
6297                        free(ifsfirst.next);
6298                        ifsfirst.next = ifsp;
6299                        INT_ON;
6300                }
6301                if (ifsfirst.begoff > endoff) {
6302                        ifslastp = NULL;
6303                } else {
6304                        ifslastp = &ifsfirst;
6305                        ifsfirst.endoff = endoff;
6306                }
6307                return;
6308        }
6309
6310        ifslastp = &ifsfirst;
6311        while (ifslastp->next && ifslastp->next->begoff < endoff)
6312                ifslastp = ifslastp->next;
6313        while (ifslastp->next) {
6314                struct ifsregion *ifsp;
6315                INT_OFF;
6316                ifsp = ifslastp->next->next;
6317                free(ifslastp->next);
6318                ifslastp->next = ifsp;
6319                INT_ON;
6320        }
6321        if (ifslastp->endoff > endoff)
6322                ifslastp->endoff = endoff;
6323}
6324
6325static char *
6326exptilde(char *startp, char *p, int flags)
6327{
6328        unsigned char c;
6329        char *name;
6330        struct passwd *pw;
6331        const char *home;
6332        int quotes = flags & QUOTES_ESC;
6333
6334        name = p + 1;
6335
6336        while ((c = *++p) != '\0') {
6337                switch (c) {
6338                case CTLESC:
6339                        return startp;
6340                case CTLQUOTEMARK:
6341                        return startp;
6342                case ':':
6343                        if (flags & EXP_VARTILDE)
6344                                goto done;
6345                        break;
6346                case '/':
6347                case CTLENDVAR:
6348                        goto done;
6349                }
6350        }
6351 done:
6352        *p = '\0';
6353        if (*name == '\0') {
6354                home = lookupvar("HOME");
6355        } else {
6356                pw = getpwnam(name);
6357                if (pw == NULL)
6358                        goto lose;
6359                home = pw->pw_dir;
6360        }
6361        if (!home || !*home)
6362                goto lose;
6363        *p = c;
6364        strtodest(home, SQSYNTAX, quotes);
6365        return p;
6366 lose:
6367        *p = c;
6368        return startp;
6369}
6370
6371/*
6372 * Execute a command inside back quotes.  If it's a builtin command, we
6373 * want to save its output in a block obtained from malloc.  Otherwise
6374 * we fork off a subprocess and get the output of the command via a pipe.
6375 * Should be called with interrupts off.
6376 */
6377struct backcmd {                /* result of evalbackcmd */
6378        int fd;                 /* file descriptor to read from */
6379        int nleft;              /* number of chars in buffer */
6380        char *buf;              /* buffer */
6381        struct job *jp;         /* job structure for command */
6382};
6383
6384/* These forward decls are needed to use "eval" code for backticks handling: */
6385/* flags in argument to evaltree */
6386#define EV_EXIT    01           /* exit after evaluating tree */
6387#define EV_TESTED  02           /* exit status is checked; ignore -e flag */
6388static int evaltree(union node *, int);
6389
6390/* An evaltree() which is known to never return.
6391 * Used to use an alias:
6392 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6393 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6394 */
6395static ALWAYS_INLINE NORETURN void
6396evaltreenr(union node *n, int flags)
6397{
6398        evaltree(n, flags);
6399        bb_unreachable(abort());
6400        /* NOTREACHED */
6401}
6402
6403static void FAST_FUNC
6404evalbackcmd(union node *n, struct backcmd *result)
6405{
6406        int pip[2];
6407        struct job *jp;
6408
6409        result->fd = -1;
6410        result->buf = NULL;
6411        result->nleft = 0;
6412        result->jp = NULL;
6413        if (n == NULL) {
6414                goto out;
6415        }
6416
6417        if (pipe(pip) < 0)
6418                ash_msg_and_raise_perror("can't create pipe");
6419        jp = makejob(/*n,*/ 1);
6420        if (forkshell(jp, n, FORK_NOJOB) == 0) {
6421                /* child */
6422                FORCE_INT_ON;
6423                close(pip[0]);
6424                if (pip[1] != 1) {
6425                        /*close(1);*/
6426                        dup2_or_raise(pip[1], 1);
6427                        close(pip[1]);
6428                }
6429/* TODO: eflag clearing makes the following not abort:
6430 *  ash -c 'set -e; z=$(false;echo foo); echo $z'
6431 * which is what bash does (unless it is in POSIX mode).
6432 * dash deleted "eflag = 0" line in the commit
6433 *  Date: Mon, 28 Jun 2010 17:11:58 +1000
6434 *  [EVAL] Don't clear eflag in evalbackcmd
6435 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6436 */
6437                eflag = 0;
6438                ifsfree();
6439                evaltreenr(n, EV_EXIT);
6440                /* NOTREACHED */
6441        }
6442        /* parent */
6443        close(pip[1]);
6444        result->fd = pip[0];
6445        result->jp = jp;
6446
6447 out:
6448        TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6449                result->fd, result->buf, result->nleft, result->jp));
6450}
6451
6452/*
6453 * Expand stuff in backwards quotes.
6454 */
6455static void
6456expbackq(union node *cmd, int flag)
6457{
6458        struct backcmd in;
6459        int i;
6460        char buf[128];
6461        char *p;
6462        char *dest;
6463        int startloc;
6464        int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6465        struct stackmark smark;
6466
6467        INT_OFF;
6468        startloc = expdest - (char *)stackblock();
6469        pushstackmark(&smark, startloc);
6470        evalbackcmd(cmd, &in);
6471        popstackmark(&smark);
6472
6473        p = in.buf;
6474        i = in.nleft;
6475        if (i == 0)
6476                goto read;
6477        for (;;) {
6478                memtodest(p, i, syntax, flag & QUOTES_ESC);
6479 read:
6480                if (in.fd < 0)
6481                        break;
6482                i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6483                TRACE(("expbackq: read returns %d\n", i));
6484                if (i <= 0)
6485                        break;
6486                p = buf;
6487        }
6488
6489        free(in.buf);
6490        if (in.fd >= 0) {
6491                close(in.fd);
6492                back_exitstatus = waitforjob(in.jp);
6493        }
6494        INT_ON;
6495
6496        /* Eat all trailing newlines */
6497        dest = expdest;
6498        for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6499                STUNPUTC(dest);
6500        expdest = dest;
6501
6502        if (!(flag & EXP_QUOTED))
6503                recordregion(startloc, dest - (char *)stackblock(), 0);
6504        TRACE(("evalbackq: size:%d:'%.*s'\n",
6505                (int)((dest - (char *)stackblock()) - startloc),
6506                (int)((dest - (char *)stackblock()) - startloc),
6507                stackblock() + startloc));
6508}
6509
6510#if ENABLE_FEATURE_SH_MATH
6511/*
6512 * Expand arithmetic expression.  Backup to start of expression,
6513 * evaluate, place result in (backed up) result, adjust string position.
6514 */
6515static void
6516expari(int flag)
6517{
6518        char *p, *start;
6519        int begoff;
6520        int len;
6521
6522        /* ifsfree(); */
6523
6524        /*
6525         * This routine is slightly over-complicated for
6526         * efficiency.  Next we scan backwards looking for the
6527         * start of arithmetic.
6528         */
6529        start = stackblock();
6530        p = expdest - 1;
6531        *p = '\0';
6532        p--;
6533        while (1) {
6534                int esc;
6535
6536                while ((unsigned char)*p != CTLARI) {
6537                        p--;
6538#if DEBUG
6539                        if (p < start) {
6540                                ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6541                        }
6542#endif
6543                }
6544
6545                esc = esclen(start, p);
6546                if (!(esc % 2)) {
6547                        break;
6548                }
6549
6550                p -= esc + 1;
6551        }
6552
6553        begoff = p - start;
6554
6555        removerecordregions(begoff);
6556
6557        expdest = p;
6558
6559        if (flag & QUOTES_ESC)
6560                rmescapes(p + 1, 0, NULL);
6561
6562        len = cvtnum(ash_arith(p + 1));
6563
6564        if (!(flag & EXP_QUOTED))
6565                recordregion(begoff, begoff + len, 0);
6566}
6567#endif
6568
6569/* argstr needs it */
6570static char *evalvar(char *p, int flags);
6571
6572/*
6573 * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
6574 * characters to allow for further processing.  Otherwise treat
6575 * $@ like $* since no splitting will be performed.
6576 */
6577static void
6578argstr(char *p, int flags)
6579{
6580        static const char spclchars[] ALIGN1 = {
6581                '=',
6582                ':',
6583                CTLQUOTEMARK,
6584                CTLENDVAR,
6585                CTLESC,
6586                CTLVAR,
6587                CTLBACKQ,
6588#if ENABLE_FEATURE_SH_MATH
6589                CTLENDARI,
6590#endif
6591                '\0'
6592        };
6593        const char *reject = spclchars;
6594        int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6595        int inquotes;
6596        size_t length;
6597        int startloc;
6598
6599        if (!(flags & EXP_VARTILDE)) {
6600                reject += 2;
6601        } else if (flags & EXP_VARTILDE2) {
6602                reject++;
6603        }
6604        inquotes = 0;
6605        length = 0;
6606        if (flags & EXP_TILDE) {
6607                char *q;
6608
6609                flags &= ~EXP_TILDE;
6610 tilde:
6611                q = p;
6612                if (*q == '~')
6613                        p = exptilde(p, q, flags);
6614        }
6615 start:
6616        startloc = expdest - (char *)stackblock();
6617        for (;;) {
6618                unsigned char c;
6619
6620                length += strcspn(p + length, reject);
6621                c = p[length];
6622                if (c) {
6623                        if (!(c & 0x80)
6624                        IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6625                        ) {
6626                                /* c == '=' || c == ':' || c == CTLENDARI */
6627                                length++;
6628                        }
6629                }
6630                if (length > 0) {
6631                        int newloc;
6632                        expdest = stack_nputstr(p, length, expdest);
6633                        newloc = expdest - (char *)stackblock();
6634                        if (breakall && !inquotes && newloc > startloc) {
6635                                recordregion(startloc, newloc, 0);
6636                        }
6637                        startloc = newloc;
6638                }
6639                p += length + 1;
6640                length = 0;
6641
6642                switch (c) {
6643                case '\0':
6644                        goto breakloop;
6645                case '=':
6646                        if (flags & EXP_VARTILDE2) {
6647                                p--;
6648                                continue;
6649                        }
6650                        flags |= EXP_VARTILDE2;
6651                        reject++;
6652                        /* fall through */
6653                case ':':
6654                        /*
6655                         * sort of a hack - expand tildes in variable
6656                         * assignments (after the first '=' and after ':'s).
6657                         */
6658                        if (*--p == '~') {
6659                                goto tilde;
6660                        }
6661                        continue;
6662                }
6663
6664                switch (c) {
6665                case CTLENDVAR: /* ??? */
6666                        goto breakloop;
6667                case CTLQUOTEMARK:
6668                        /* "$@" syntax adherence hack */
6669                        if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6670                                p = evalvar(p + 1, flags | EXP_QUOTED) + 1;
6671                                goto start;
6672                        }
6673                        inquotes ^= EXP_QUOTED;
6674 addquote:
6675                        if (flags & QUOTES_ESC) {
6676                                p--;
6677                                length++;
6678                                startloc++;
6679                        }
6680                        break;
6681                case CTLESC:
6682                        startloc++;
6683                        length++;
6684                        goto addquote;
6685                case CTLVAR:
6686                        TRACE(("argstr: evalvar('%s')\n", p));
6687                        p = evalvar(p, flags | inquotes);
6688                        TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6689                        goto start;
6690                case CTLBACKQ:
6691                        expbackq(argbackq->n, flags | inquotes);
6692                        argbackq = argbackq->next;
6693                        goto start;
6694#if ENABLE_FEATURE_SH_MATH
6695                case CTLENDARI:
6696                        p--;
6697                        expari(flags | inquotes);
6698                        goto start;
6699#endif
6700                }
6701        }
6702 breakloop: ;
6703}
6704
6705static char *
6706scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6707                char *pattern, int quotes, int zero)
6708{
6709        char *loc, *loc2;
6710        char c;
6711
6712        loc = startp;
6713        loc2 = rmesc;
6714        do {
6715                int match;
6716                const char *s = loc2;
6717
6718                c = *loc2;
6719                if (zero) {
6720                        *loc2 = '\0';
6721                        s = rmesc;
6722                }
6723                match = pmatch(pattern, s);
6724
6725                *loc2 = c;
6726                if (match)
6727                        return loc;
6728                if (quotes && (unsigned char)*loc == CTLESC)
6729                        loc++;
6730                loc++;
6731                loc2++;
6732        } while (c);
6733        return NULL;
6734}
6735
6736static char *
6737scanright(char *startp, char *rmesc, char *rmescend,
6738                char *pattern, int quotes, int match_at_start)
6739{
6740#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6741        int try2optimize = match_at_start;
6742#endif
6743        int esc = 0;
6744        char *loc;
6745        char *loc2;
6746
6747        /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6748         * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6749         * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6750         * Logic:
6751         * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6752         * and on each iteration they go back two/one char until they reach the beginning.
6753         * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6754         */
6755        /* TODO: document in what other circumstances we are called. */
6756
6757        for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6758                int match;
6759                char c = *loc2;
6760                const char *s = loc2;
6761                if (match_at_start) {
6762                        *loc2 = '\0';
6763                        s = rmesc;
6764                }
6765                match = pmatch(pattern, s);
6766                //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6767                *loc2 = c;
6768                if (match)
6769                        return loc;
6770#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6771                if (try2optimize) {
6772                        /* Maybe we can optimize this:
6773                         * if pattern ends with unescaped *, we can avoid checking
6774                         * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6775                         * it won't match truncated "raw_value_of_" strings too.
6776                         */
6777                        unsigned plen = strlen(pattern);
6778                        /* Does it end with "*"? */
6779                        if (plen != 0 && pattern[--plen] == '*') {
6780                                /* "xxxx*" is not escaped */
6781                                /* "xxx\*" is escaped */
6782                                /* "xx\\*" is not escaped */
6783                                /* "x\\\*" is escaped */
6784                                int slashes = 0;
6785                                while (plen != 0 && pattern[--plen] == '\\')
6786                                        slashes++;
6787                                if (!(slashes & 1))
6788                                        break; /* ends with unescaped "*" */
6789                        }
6790                        try2optimize = 0;
6791                }
6792#endif
6793                loc--;
6794                if (quotes) {
6795                        if (--esc < 0) {
6796                                esc = esclen(startp, loc);
6797                        }
6798                        if (esc % 2) {
6799                                esc--;
6800                                loc--;
6801                        }
6802                }
6803        }
6804        return NULL;
6805}
6806
6807static void varunset(const char *, const char *, const char *, int) NORETURN;
6808static void
6809varunset(const char *end, const char *var, const char *umsg, int varflags)
6810{
6811        const char *msg;
6812        const char *tail;
6813
6814        tail = nullstr;
6815        msg = "parameter not set";
6816        if (umsg) {
6817                if ((unsigned char)*end == CTLENDVAR) {
6818                        if (varflags & VSNUL)
6819                                tail = " or null";
6820                } else {
6821                        msg = umsg;
6822                }
6823        }
6824        ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6825}
6826
6827static const char *
6828subevalvar(char *p, char *varname, int strloc, int subtype,
6829                int startloc, int varflags, int flag)
6830{
6831        struct nodelist *saveargbackq = argbackq;
6832        int quotes = flag & QUOTES_ESC;
6833        char *startp;
6834        char *loc;
6835        char *rmesc, *rmescend;
6836        char *str;
6837        int amount, resetloc;
6838        int argstr_flags;
6839        IF_BASH_PATTERN_SUBST(int workloc;)
6840        IF_BASH_PATTERN_SUBST(int slash_pos;)
6841        IF_BASH_PATTERN_SUBST(char *repl;)
6842        int zero;
6843        char *(*scan)(char*, char*, char*, char*, int, int);
6844
6845        //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6846        //              p, varname, strloc, subtype, startloc, varflags, quotes);
6847
6848#if BASH_PATTERN_SUBST
6849        /* For "${v/pattern/repl}", we must find the delimiter _before_
6850         * argstr() call expands possible variable references in pattern:
6851         * think about "v=a; a=a/; echo ${v/$a/r}" case.
6852         */
6853        repl = NULL;
6854        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6855                /* Find '/' and replace with NUL */
6856                repl = p;
6857                for (;;) {
6858                        /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
6859                        if (*repl == '\0') {
6860                                repl = NULL;
6861                                break;
6862                        }
6863                        if (*repl == '/') {
6864                                *repl = '\0';
6865                                break;
6866                        }
6867                        if ((unsigned char)*repl == CTLESC && repl[1])
6868                                repl++;
6869                        repl++;
6870                }
6871        }
6872#endif
6873        argstr_flags = EXP_TILDE;
6874        if (subtype != VSASSIGN
6875         && subtype != VSQUESTION
6876#if BASH_SUBSTR
6877         && subtype != VSSUBSTR
6878#endif
6879        ) {
6880                /* EXP_CASE keeps CTLESC's */
6881                argstr_flags = EXP_TILDE | EXP_CASE;
6882        }
6883        argstr(p, argstr_flags);
6884        //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
6885#if BASH_PATTERN_SUBST
6886        slash_pos = -1;
6887        if (repl) {
6888                slash_pos = expdest - ((char *)stackblock() + strloc);
6889                STPUTC('/', expdest);
6890                //bb_error_msg("repl+1:'%s'", repl + 1);
6891                argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
6892                *repl = '/';
6893        }
6894#endif
6895        STPUTC('\0', expdest);
6896        argbackq = saveargbackq;
6897        startp = (char *)stackblock() + startloc;
6898        //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
6899
6900        switch (subtype) {
6901        case VSASSIGN:
6902                setvar0(varname, startp);
6903                amount = startp - expdest;
6904                STADJUST(amount, expdest);
6905                return startp;
6906
6907        case VSQUESTION:
6908                varunset(p, varname, startp, varflags);
6909                /* NOTREACHED */
6910
6911#if BASH_SUBSTR
6912        case VSSUBSTR: {
6913                int pos, len, orig_len;
6914                char *colon;
6915
6916                loc = str = stackblock() + strloc;
6917
6918                /* Read POS in ${var:POS:LEN} */
6919                colon = strchr(loc, ':');
6920                if (colon) *colon = '\0';
6921                pos = substr_atoi(loc);
6922                if (colon) *colon = ':';
6923
6924                /* Read LEN in ${var:POS:LEN} */
6925                len = str - startp - 1;
6926                /* *loc != '\0', guaranteed by parser */
6927                if (quotes) {
6928                        char *ptr;
6929                        /* Adjust the length by the number of escapes */
6930                        for (ptr = startp; ptr < (str - 1); ptr++) {
6931                                if ((unsigned char)*ptr == CTLESC) {
6932                                        len--;
6933                                        ptr++;
6934                                }
6935                        }
6936                }
6937                orig_len = len;
6938                if (*loc++ == ':') {
6939                        /* ${var::LEN} */
6940                        len = substr_atoi(loc);
6941                } else {
6942                        /* Skip POS in ${var:POS:LEN} */
6943                        len = orig_len;
6944                        while (*loc && *loc != ':')
6945                                loc++;
6946                        if (*loc++ == ':')
6947                                len = substr_atoi(loc);
6948                }
6949                if (pos < 0) {
6950                        /* ${VAR:$((-n)):l} starts n chars from the end */
6951                        pos = orig_len + pos;
6952                }
6953                if ((unsigned)pos >= orig_len) {
6954                        /* apart from obvious ${VAR:999999:l},
6955                         * covers ${VAR:$((-9999999)):l} - result is ""
6956                         * (bash compat)
6957                         */
6958                        pos = 0;
6959                        len = 0;
6960                }
6961                if (len < 0) {
6962                        /* ${VAR:N:-M} sets LEN to strlen()-M */
6963                        len = (orig_len - pos) + len;
6964                }
6965                if ((unsigned)len > (orig_len - pos))
6966                        len = orig_len - pos;
6967
6968                for (str = startp; pos; str++, pos--) {
6969                        if (quotes && (unsigned char)*str == CTLESC)
6970                                str++;
6971                }
6972                for (loc = startp; len; len--) {
6973                        if (quotes && (unsigned char)*str == CTLESC)
6974                                *loc++ = *str++;
6975                        *loc++ = *str++;
6976                }
6977                *loc = '\0';
6978                amount = loc - expdest;
6979                STADJUST(amount, expdest);
6980                return loc;
6981        }
6982#endif /* BASH_SUBSTR */
6983        }
6984
6985        resetloc = expdest - (char *)stackblock();
6986
6987#if BASH_PATTERN_SUBST
6988        repl = NULL;
6989
6990        /* We'll comeback here if we grow the stack while handling
6991         * a VSREPLACE or VSREPLACEALL, since our pointers into the
6992         * stack will need rebasing, and we'll need to remove our work
6993         * areas each time
6994         */
6995 restart:
6996#endif
6997
6998        amount = expdest - ((char *)stackblock() + resetloc);
6999        STADJUST(-amount, expdest);
7000        startp = (char *)stackblock() + startloc;
7001
7002        rmesc = startp;
7003        rmescend = (char *)stackblock() + strloc;
7004        //bb_error_msg("str7:'%s'", rmescend);
7005        if (quotes) {
7006//TODO: how to handle slash_pos here if string changes (shortens?)
7007                rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
7008                if (rmesc != startp) {
7009                        rmescend = expdest;
7010                        startp = (char *)stackblock() + startloc;
7011                }
7012        }
7013        rmescend--;
7014        str = (char *)stackblock() + strloc;
7015        /*
7016         * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7017         * The result is a_\_z_c (not a\_\_z_c)!
7018         *
7019         * The search pattern and replace string treat backslashes differently!
7020         * "&slash_pos" causes rmescapes() to work differently on the pattern
7021         * and string.  It's only used on the first call.
7022         */
7023        //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7024        rmescapes(str, RMESCAPE_GLOB,
7025                repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7026        );
7027
7028#if BASH_PATTERN_SUBST
7029        workloc = expdest - (char *)stackblock();
7030        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7031                int len;
7032                char *idx, *end;
7033
7034                if (!repl) {
7035                        //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
7036                        repl = nullstr;
7037                        if (slash_pos >= 0) {
7038                                repl = str + slash_pos;
7039                                *repl++ = '\0';
7040                        }
7041                }
7042                //bb_error_msg("str:'%s' repl:'%s'", str, repl);
7043
7044                /* If there's no pattern to match, return the expansion unmolested */
7045                if (str[0] == '\0')
7046                        return NULL;
7047
7048                len = 0;
7049                idx = startp;
7050                end = str - 1;
7051                while (idx < end) {
7052 try_to_match:
7053                        loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
7054                        //bb_error_msg("scanright('%s'):'%s'", str, loc);
7055                        if (!loc) {
7056                                /* No match, advance */
7057                                char *restart_detect = stackblock();
7058 skip_matching:
7059                                STPUTC(*idx, expdest);
7060                                if (quotes && (unsigned char)*idx == CTLESC) {
7061                                        idx++;
7062                                        len++;
7063                                        STPUTC(*idx, expdest);
7064                                }
7065                                if (stackblock() != restart_detect)
7066                                        goto restart;
7067                                idx++;
7068                                len++;
7069                                rmesc++;
7070                                /* continue; - prone to quadratic behavior, smarter code: */
7071                                if (idx >= end)
7072                                        break;
7073                                if (str[0] == '*') {
7074                                        /* Pattern is "*foo". If "*foo" does not match "long_string",
7075                                         * it would never match "ong_string" etc, no point in trying.
7076                                         */
7077                                        goto skip_matching;
7078                                }
7079                                goto try_to_match;
7080                        }
7081
7082                        if (subtype == VSREPLACEALL) {
7083                                while (idx < loc) {
7084                                        if (quotes && (unsigned char)*idx == CTLESC)
7085                                                idx++;
7086                                        idx++;
7087                                        rmesc++;
7088                                }
7089                        } else {
7090                                idx = loc;
7091                        }
7092
7093                        //bb_error_msg("repl:'%s'", repl);
7094                        for (loc = (char*)repl; *loc; loc++) {
7095                                char *restart_detect = stackblock();
7096                                if (quotes && *loc == '\\') {
7097                                        STPUTC(CTLESC, expdest);
7098                                        len++;
7099                                }
7100                                STPUTC(*loc, expdest);
7101                                if (stackblock() != restart_detect)
7102                                        goto restart;
7103                                len++;
7104                        }
7105
7106                        if (subtype == VSREPLACE) {
7107                                //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
7108                                while (*idx) {
7109                                        char *restart_detect = stackblock();
7110                                        STPUTC(*idx, expdest);
7111                                        if (stackblock() != restart_detect)
7112                                                goto restart;
7113                                        len++;
7114                                        idx++;
7115                                }
7116                                break;
7117                        }
7118                }
7119
7120                /* We've put the replaced text into a buffer at workloc, now
7121                 * move it to the right place and adjust the stack.
7122                 */
7123                STPUTC('\0', expdest);
7124                startp = (char *)stackblock() + startloc;
7125                memmove(startp, (char *)stackblock() + workloc, len + 1);
7126                //bb_error_msg("startp:'%s'", startp);
7127                amount = expdest - (startp + len);
7128                STADJUST(-amount, expdest);
7129                return startp;
7130        }
7131#endif /* BASH_PATTERN_SUBST */
7132
7133        subtype -= VSTRIMRIGHT;
7134#if DEBUG
7135        if (subtype < 0 || subtype > 7)
7136                abort();
7137#endif
7138        /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
7139        zero = subtype >> 1;
7140        /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7141        scan = (subtype & 1) ^ zero ? scanleft : scanright;
7142
7143        loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7144        if (loc) {
7145                if (zero) {
7146                        memmove(startp, loc, str - loc);
7147                        loc = startp + (str - loc) - 1;
7148                }
7149                *loc = '\0';
7150                amount = loc - expdest;
7151                STADJUST(amount, expdest);
7152        }
7153        return loc;
7154}
7155
7156/*
7157 * Add the value of a specialized variable to the stack string.
7158 * name parameter (examples):
7159 * ash -c 'echo $1'      name:'1='
7160 * ash -c 'echo $qwe'    name:'qwe='
7161 * ash -c 'echo $$'      name:'$='
7162 * ash -c 'echo ${$}'    name:'$='
7163 * ash -c 'echo ${$##q}' name:'$=q'
7164 * ash -c 'echo ${#$}'   name:'$='
7165 * note: examples with bad shell syntax:
7166 * ash -c 'echo ${#$1}'  name:'$=1'
7167 * ash -c 'echo ${#1#}'  name:'1=#'
7168 */
7169static NOINLINE ssize_t
7170varvalue(char *name, int varflags, int flags, int *quotedp)
7171{
7172        const char *p;
7173        int num;
7174        int i;
7175        ssize_t len = 0;
7176        int sep;
7177        int quoted = *quotedp;
7178        int subtype = varflags & VSTYPE;
7179        int discard = subtype == VSPLUS || subtype == VSLENGTH;
7180        int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
7181        int syntax;
7182
7183        sep = (flags & EXP_FULL) << CHAR_BIT;
7184        syntax = quoted ? DQSYNTAX : BASESYNTAX;
7185
7186        switch (*name) {
7187        case '$':
7188                num = rootpid;
7189                goto numvar;
7190        case '?':
7191                num = exitstatus;
7192                goto numvar;
7193        case '#':
7194                num = shellparam.nparam;
7195                goto numvar;
7196        case '!':
7197                num = backgndpid;
7198                if (num == 0)
7199                        return -1;
7200 numvar:
7201                len = cvtnum(num);
7202                goto check_1char_name;
7203        case '-':
7204                expdest = makestrspace(NOPTS, expdest);
7205                for (i = NOPTS - 1; i >= 0; i--) {
7206                        if (optlist[i] && optletters(i)) {
7207                                USTPUTC(optletters(i), expdest);
7208                                len++;
7209                        }
7210                }
7211 check_1char_name:
7212#if 0
7213                /* handles cases similar to ${#$1} */
7214                if (name[2] != '\0')
7215                        raise_error_syntax("bad substitution");
7216#endif
7217                break;
7218        case '@':
7219                if (quoted && sep)
7220                        goto param;
7221                /* fall through */
7222        case '*': {
7223                char **ap;
7224                char sepc;
7225
7226                if (quoted)
7227                        sep = 0;
7228                sep |= ifsset() ? ifsval()[0] : ' ';
7229 param:
7230                sepc = sep;
7231                *quotedp = !sepc;
7232                ap = shellparam.p;
7233                if (!ap)
7234                        return -1;
7235                while ((p = *ap++) != NULL) {
7236                        len += strtodest(p, syntax, quotes);
7237
7238                        if (*ap && sep) {
7239                                len++;
7240                                memtodest(&sepc, 1, syntax, quotes);
7241                        }
7242                }
7243                break;
7244        } /* case '*' */
7245        case '0':
7246        case '1':
7247        case '2':
7248        case '3':
7249        case '4':
7250        case '5':
7251        case '6':
7252        case '7':
7253        case '8':
7254        case '9':
7255                num = atoi(name); /* number(name) fails on ${N#str} etc */
7256                if (num < 0 || num > shellparam.nparam)
7257                        return -1;
7258                p = num ? shellparam.p[num - 1] : arg0;
7259                goto value;
7260        default:
7261                /* NB: name has form "VAR=..." */
7262                p = lookupvar(name);
7263 value:
7264                if (!p)
7265                        return -1;
7266
7267                len = strtodest(p, syntax, quotes);
7268#if ENABLE_UNICODE_SUPPORT
7269                if (subtype == VSLENGTH && len > 0) {
7270                        reinit_unicode_for_ash();
7271                        if (unicode_status == UNICODE_ON) {
7272                                STADJUST(-len, expdest);
7273                                discard = 0;
7274                                len = unicode_strlen(p);
7275                        }
7276                }
7277#endif
7278                break;
7279        }
7280
7281        if (discard)
7282                STADJUST(-len, expdest);
7283        return len;
7284}
7285
7286/*
7287 * Expand a variable, and return a pointer to the next character in the
7288 * input string.
7289 */
7290static char *
7291evalvar(char *p, int flag)
7292{
7293        char varflags;
7294        char subtype;
7295        int quoted;
7296        char easy;
7297        char *var;
7298        int patloc;
7299        int startloc;
7300        ssize_t varlen;
7301
7302        varflags = (unsigned char) *p++;
7303        subtype = varflags & VSTYPE;
7304
7305        if (!subtype)
7306                raise_error_syntax("bad substitution");
7307
7308        quoted = flag & EXP_QUOTED;
7309        var = p;
7310        easy = (!quoted || (*var == '@' && shellparam.nparam));
7311        startloc = expdest - (char *)stackblock();
7312        p = strchr(p, '=') + 1; //TODO: use var_end(p)?
7313
7314 again:
7315        varlen = varvalue(var, varflags, flag, &quoted);
7316        if (varflags & VSNUL)
7317                varlen--;
7318
7319        if (subtype == VSPLUS) {
7320                varlen = -1 - varlen;
7321                goto vsplus;
7322        }
7323
7324        if (subtype == VSMINUS) {
7325 vsplus:
7326                if (varlen < 0) {
7327                        argstr(
7328                                p,
7329                                flag | EXP_TILDE | EXP_WORD
7330                        );
7331                        goto end;
7332                }
7333                goto record;
7334        }
7335
7336        if (subtype == VSASSIGN || subtype == VSQUESTION) {
7337                if (varlen >= 0)
7338                        goto record;
7339
7340                subevalvar(p, var, 0, subtype, startloc, varflags,
7341                           flag & ~QUOTES_ESC);
7342                varflags &= ~VSNUL;
7343                /*
7344                 * Remove any recorded regions beyond
7345                 * start of variable
7346                 */
7347                removerecordregions(startloc);
7348                goto again;
7349        }
7350
7351        if (varlen < 0 && uflag)
7352                varunset(p, var, 0, 0);
7353
7354        if (subtype == VSLENGTH) {
7355                cvtnum(varlen > 0 ? varlen : 0);
7356                goto record;
7357        }
7358
7359        if (subtype == VSNORMAL) {
7360 record:
7361                if (!easy)
7362                        goto end;
7363                recordregion(startloc, expdest - (char *)stackblock(), quoted);
7364                goto end;
7365        }
7366
7367#if DEBUG
7368        switch (subtype) {
7369        case VSTRIMLEFT:
7370        case VSTRIMLEFTMAX:
7371        case VSTRIMRIGHT:
7372        case VSTRIMRIGHTMAX:
7373#if BASH_SUBSTR
7374        case VSSUBSTR:
7375#endif
7376#if BASH_PATTERN_SUBST
7377        case VSREPLACE:
7378        case VSREPLACEALL:
7379#endif
7380                break;
7381        default:
7382                abort();
7383        }
7384#endif
7385
7386        if (varlen >= 0) {
7387                /*
7388                 * Terminate the string and start recording the pattern
7389                 * right after it
7390                 */
7391                STPUTC('\0', expdest);
7392                patloc = expdest - (char *)stackblock();
7393                if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
7394                                startloc, varflags, flag)) {
7395                        int amount = expdest - (
7396                                (char *)stackblock() + patloc - 1
7397                        );
7398                        STADJUST(-amount, expdest);
7399                }
7400                /* Remove any recorded regions beyond start of variable */
7401                removerecordregions(startloc);
7402                goto record;
7403        }
7404
7405 end:
7406        if (subtype != VSNORMAL) {      /* skip to end of alternative */
7407                int nesting = 1;
7408                for (;;) {
7409                        unsigned char c = *p++;
7410                        if (c == CTLESC)
7411                                p++;
7412                        else if (c == CTLBACKQ) {
7413                                if (varlen >= 0)
7414                                        argbackq = argbackq->next;
7415                        } else if (c == CTLVAR) {
7416                                if ((*p++ & VSTYPE) != VSNORMAL)
7417                                        nesting++;
7418                        } else if (c == CTLENDVAR) {
7419                                if (--nesting == 0)
7420                                        break;
7421                        }
7422                }
7423        }
7424        return p;
7425}
7426
7427/*
7428 * Add a file name to the list.
7429 */
7430static void
7431addfname(const char *name)
7432{
7433        struct strlist *sp;
7434
7435        sp = stzalloc(sizeof(*sp));
7436        sp->text = sstrdup(name);
7437        *exparg.lastp = sp;
7438        exparg.lastp = &sp->next;
7439}
7440
7441/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7442static int
7443hasmeta(const char *p)
7444{
7445        static const char chars[] ALIGN1 = {
7446                '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7447        };
7448
7449        for (;;) {
7450                p = strpbrk(p, chars);
7451                if (!p)
7452                        break;
7453                switch ((unsigned char)*p) {
7454                case CTLQUOTEMARK:
7455                        for (;;) {
7456                                p++;
7457                                if ((unsigned char)*p == CTLQUOTEMARK)
7458                                        break;
7459                                if ((unsigned char)*p == CTLESC)
7460                                        p++;
7461                                if (*p == '\0') /* huh? */
7462                                        return 0;
7463                        }
7464                        break;
7465                case '\\':
7466                case CTLESC:
7467                        p++;
7468                        if (*p == '\0')
7469                                return 0;
7470                        break;
7471                case '[':
7472                        if (!strchr(p + 1, ']')) {
7473                                /* It's not a properly closed [] pattern,
7474                                 * but other metas may follow. Continue checking.
7475                                 * my[file* _is_ globbed by bash
7476                                 * and matches filenames like "my[file1".
7477                                 */
7478                                break;
7479                        }
7480                        /* fallthrough */
7481                default:
7482                /* case '*': */
7483                /* case '?': */
7484                        return 1;
7485                }
7486                p++;
7487        }
7488
7489        return 0;
7490}
7491
7492/* If we want to use glob() from libc... */
7493#if !ENABLE_ASH_INTERNAL_GLOB
7494
7495/* Add the result of glob() to the list */
7496static void
7497addglob(const glob_t *pglob)
7498{
7499        char **p = pglob->gl_pathv;
7500
7501        do {
7502                addfname(*p);
7503        } while (*++p);
7504}
7505static void
7506expandmeta(struct strlist *str /*, int flag*/)
7507{
7508        /* TODO - EXP_REDIR */
7509
7510        while (str) {
7511                char *p;
7512                glob_t pglob;
7513                int i;
7514
7515                if (fflag)
7516                        goto nometa;
7517
7518                if (!hasmeta(str->text))
7519                        goto nometa;
7520
7521                INT_OFF;
7522                p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7523// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7524// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7525//
7526// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7527// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7528// Which means you need to unescape the string, right? Not so fast:
7529// if there _is_ a file named "file\?" (with backslash), it is returned
7530// as "file\?" too (whichever pattern you used to find it, say, "file*").
7531// You DON'T KNOW by looking at the result whether you need to unescape it.
7532//
7533// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7534// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7535// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7536// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7537//              i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7538//              i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7539                i = glob(p, 0, NULL, &pglob);
7540                //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7541                if (p != str->text)
7542                        free(p);
7543                switch (i) {
7544                case 0:
7545#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7546                        /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7547                        if (!(pglob.gl_flags & GLOB_MAGCHAR))
7548                                goto nometa2;
7549#endif
7550                        addglob(&pglob);
7551                        globfree(&pglob);
7552                        INT_ON;
7553                        break;
7554                case GLOB_NOMATCH:
7555 //nometa2:
7556                        globfree(&pglob);
7557                        INT_ON;
7558 nometa:
7559                        *exparg.lastp = str;
7560                        rmescapes(str->text, 0, NULL);
7561                        exparg.lastp = &str->next;
7562                        break;
7563                default:        /* GLOB_NOSPACE */
7564                        globfree(&pglob);
7565                        INT_ON;
7566                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
7567                }
7568                str = str->next;
7569        }
7570}
7571
7572#else
7573/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7574
7575/*
7576 * Do metacharacter (i.e. *, ?, [...]) expansion.
7577 */
7578typedef struct exp_t {
7579        char *dir;
7580        unsigned dir_max;
7581} exp_t;
7582static void
7583expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7584{
7585#define expdir exp->dir
7586#define expdir_max exp->dir_max
7587        char *enddir = expdir + expdir_len;
7588        char *p;
7589        const char *cp;
7590        char *start;
7591        char *endname;
7592        int metaflag;
7593        struct stat statb;
7594        DIR *dirp;
7595        struct dirent *dp;
7596        int atend;
7597        int matchdot;
7598        int esc;
7599
7600        metaflag = 0;
7601        start = name;
7602        for (p = name; esc = 0, *p; p += esc + 1) {
7603                if (*p == '*' || *p == '?')
7604                        metaflag = 1;
7605                else if (*p == '[') {
7606                        char *q = p + 1;
7607                        if (*q == '!')
7608                                q++;
7609                        for (;;) {
7610                                if (*q == '\\')
7611                                        q++;
7612                                if (*q == '/' || *q == '\0')
7613                                        break;
7614                                if (*++q == ']') {
7615                                        metaflag = 1;
7616                                        break;
7617                                }
7618                        }
7619                } else {
7620                        if (*p == '\\')
7621                                esc++;
7622                        if (p[esc] == '/') {
7623                                if (metaflag)
7624                                        break;
7625                                start = p + esc + 1;
7626                        }
7627                }
7628        }
7629        if (metaflag == 0) {    /* we've reached the end of the file name */
7630                if (!expdir_len)
7631                        return;
7632                p = name;
7633                do {
7634                        if (*p == '\\')
7635                                p++;
7636                        *enddir++ = *p;
7637                } while (*p++);
7638                if (lstat(expdir, &statb) == 0)
7639                        addfname(expdir);
7640                return;
7641        }
7642        endname = p;
7643        if (name < start) {
7644                p = name;
7645                do {
7646                        if (*p == '\\')
7647                                p++;
7648                        *enddir++ = *p++;
7649                } while (p < start);
7650        }
7651        *enddir = '\0';
7652        cp = expdir;
7653        expdir_len = enddir - cp;
7654        if (!expdir_len)
7655                cp = ".";
7656        dirp = opendir(cp);
7657        if (dirp == NULL)
7658                return;
7659        if (*endname == 0) {
7660                atend = 1;
7661        } else {
7662                atend = 0;
7663                *endname = '\0';
7664                endname += esc + 1;
7665        }
7666        name_len -= endname - name;
7667        matchdot = 0;
7668        p = start;
7669        if (*p == '\\')
7670                p++;
7671        if (*p == '.')
7672                matchdot++;
7673        while (!pending_int && (dp = readdir(dirp)) != NULL) {
7674                if (dp->d_name[0] == '.' && !matchdot)
7675                        continue;
7676                if (pmatch(start, dp->d_name)) {
7677                        if (atend) {
7678                                strcpy(enddir, dp->d_name);
7679                                addfname(expdir);
7680                        } else {
7681                                unsigned offset;
7682                                unsigned len;
7683
7684                                p = stpcpy(enddir, dp->d_name);
7685                                *p = '/';
7686
7687                                offset = p - expdir + 1;
7688                                len = offset + name_len + NAME_MAX;
7689                                if (len > expdir_max) {
7690                                        len += PATH_MAX;
7691                                        expdir = ckrealloc(expdir, len);
7692                                        expdir_max = len;
7693                                }
7694
7695                                expmeta(exp, endname, name_len, offset);
7696                                enddir = expdir + expdir_len;
7697                        }
7698                }
7699        }
7700        closedir(dirp);
7701        if (!atend)
7702                endname[-esc - 1] = esc ? '\\' : '/';
7703#undef expdir
7704#undef expdir_max
7705}
7706
7707static struct strlist *
7708msort(struct strlist *list, int len)
7709{
7710        struct strlist *p, *q = NULL;
7711        struct strlist **lpp;
7712        int half;
7713        int n;
7714
7715        if (len <= 1)
7716                return list;
7717        half = len >> 1;
7718        p = list;
7719        for (n = half; --n >= 0;) {
7720                q = p;
7721                p = p->next;
7722        }
7723        q->next = NULL;                 /* terminate first half of list */
7724        q = msort(list, half);          /* sort first half of list */
7725        p = msort(p, len - half);               /* sort second half */
7726        lpp = &list;
7727        for (;;) {
7728#if ENABLE_LOCALE_SUPPORT
7729                if (strcoll(p->text, q->text) < 0)
7730#else
7731                if (strcmp(p->text, q->text) < 0)
7732#endif
7733                                                {
7734                        *lpp = p;
7735                        lpp = &p->next;
7736                        p = *lpp;
7737                        if (p == NULL) {
7738                                *lpp = q;
7739                                break;
7740                        }
7741                } else {
7742                        *lpp = q;
7743                        lpp = &q->next;
7744                        q = *lpp;
7745                        if (q == NULL) {
7746                                *lpp = p;
7747                                break;
7748                        }
7749                }
7750        }
7751        return list;
7752}
7753
7754/*
7755 * Sort the results of file name expansion.  It calculates the number of
7756 * strings to sort and then calls msort (short for merge sort) to do the
7757 * work.
7758 */
7759static struct strlist *
7760expsort(struct strlist *str)
7761{
7762        int len;
7763        struct strlist *sp;
7764
7765        len = 0;
7766        for (sp = str; sp; sp = sp->next)
7767                len++;
7768        return msort(str, len);
7769}
7770
7771static void
7772expandmeta(struct strlist *str /*, int flag*/)
7773{
7774        /* TODO - EXP_REDIR */
7775
7776        while (str) {
7777                exp_t exp;
7778                struct strlist **savelastp;
7779                struct strlist *sp;
7780                char *p;
7781                unsigned len;
7782
7783                if (fflag)
7784                        goto nometa;
7785                if (!hasmeta(str->text))
7786                        goto nometa;
7787                savelastp = exparg.lastp;
7788
7789                INT_OFF;
7790                p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7791                len = strlen(p);
7792                exp.dir_max = len + PATH_MAX;
7793                exp.dir = ckmalloc(exp.dir_max);
7794
7795                expmeta(&exp, p, len, 0);
7796                free(exp.dir);
7797                if (p != str->text)
7798                        free(p);
7799                INT_ON;
7800                if (exparg.lastp == savelastp) {
7801                        /*
7802                         * no matches
7803                         */
7804 nometa:
7805                        *exparg.lastp = str;
7806                        rmescapes(str->text, 0, NULL);
7807                        exparg.lastp = &str->next;
7808                } else {
7809                        *exparg.lastp = NULL;
7810                        *savelastp = sp = expsort(*savelastp);
7811                        while (sp->next != NULL)
7812                                sp = sp->next;
7813                        exparg.lastp = &sp->next;
7814                }
7815                str = str->next;
7816        }
7817}
7818#endif /* ENABLE_ASH_INTERNAL_GLOB */
7819
7820/*
7821 * Perform variable substitution and command substitution on an argument,
7822 * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
7823 * perform splitting and file name expansion.  When arglist is NULL, perform
7824 * here document expansion.
7825 */
7826static void
7827expandarg(union node *arg, struct arglist *arglist, int flag)
7828{
7829        struct strlist *sp;
7830        char *p;
7831
7832        argbackq = arg->narg.backquote;
7833        STARTSTACKSTR(expdest);
7834        TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7835        argstr(arg->narg.text, flag);
7836        p = _STPUTC('\0', expdest);
7837        expdest = p - 1;
7838        if (arglist == NULL) {
7839                /* here document expanded */
7840                goto out;
7841        }
7842        p = grabstackstr(p);
7843        TRACE(("expandarg: p:'%s'\n", p));
7844        exparg.lastp = &exparg.list;
7845        /*
7846         * TODO - EXP_REDIR
7847         */
7848        if (flag & EXP_FULL) {
7849                ifsbreakup(p, &exparg);
7850                *exparg.lastp = NULL;
7851                exparg.lastp = &exparg.list;
7852                expandmeta(exparg.list /*, flag*/);
7853        } else {
7854                sp = stzalloc(sizeof(*sp));
7855                sp->text = p;
7856                *exparg.lastp = sp;
7857                exparg.lastp = &sp->next;
7858        }
7859        *exparg.lastp = NULL;
7860        if (exparg.list) {
7861                *arglist->lastp = exparg.list;
7862                arglist->lastp = exparg.lastp;
7863        }
7864
7865 out:
7866        ifsfree();
7867}
7868
7869/*
7870 * Expand shell variables and backquotes inside a here document.
7871 */
7872static void
7873expandhere(union node *arg, int fd)
7874{
7875        expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7876        full_write(fd, stackblock(), expdest - (char *)stackblock());
7877}
7878
7879/*
7880 * Returns true if the pattern matches the string.
7881 */
7882static int
7883patmatch(char *pattern, const char *string)
7884{
7885        char *p = preglob(pattern, 0);
7886        int r = pmatch(p, string);
7887        //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7888        return r;
7889}
7890
7891/*
7892 * See if a pattern matches in a case statement.
7893 */
7894static int
7895casematch(union node *pattern, char *val)
7896{
7897        struct stackmark smark;
7898        int result;
7899
7900        setstackmark(&smark);
7901        argbackq = pattern->narg.backquote;
7902        STARTSTACKSTR(expdest);
7903        argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
7904        STACKSTRNUL(expdest);
7905        ifsfree();
7906        result = patmatch(stackblock(), val);
7907        popstackmark(&smark);
7908        return result;
7909}
7910
7911
7912/* ============ find_command */
7913
7914struct builtincmd {
7915        const char *name;
7916        int (*builtin)(int, char **) FAST_FUNC;
7917        /* unsigned flags; */
7918};
7919#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7920/* "regular" builtins always take precedence over commands,
7921 * regardless of PATH=....%builtin... position */
7922#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7923#define IS_BUILTIN_ASSIGN(b)  ((b)->name[0] & 4)
7924
7925struct cmdentry {
7926        smallint cmdtype;       /* CMDxxx */
7927        union param {
7928                int index;
7929                /* index >= 0 for commands without path (slashes) */
7930                /* (TODO: what exactly does the value mean? PATH position?) */
7931                /* index == -1 for commands with slashes */
7932                /* index == (-2 - applet_no) for NOFORK applets */
7933                const struct builtincmd *cmd;
7934                struct funcnode *func;
7935        } u;
7936};
7937/* values of cmdtype */
7938#define CMDUNKNOWN      -1      /* no entry in table for command */
7939#define CMDNORMAL       0       /* command is an executable program */
7940#define CMDFUNCTION     1       /* command is a shell function */
7941#define CMDBUILTIN      2       /* command is a shell builtin */
7942
7943/* action to find_command() */
7944#define DO_ERR          0x01    /* prints errors */
7945#define DO_ABS          0x02    /* checks absolute paths */
7946#define DO_NOFUNC       0x04    /* don't return shell functions, for command */
7947#define DO_ALTPATH      0x08    /* using alternate path */
7948#define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
7949
7950static void find_command(char *, struct cmdentry *, int, const char *);
7951
7952
7953/* ============ Hashing commands */
7954
7955/*
7956 * When commands are first encountered, they are entered in a hash table.
7957 * This ensures that a full path search will not have to be done for them
7958 * on each invocation.
7959 *
7960 * We should investigate converting to a linear search, even though that
7961 * would make the command name "hash" a misnomer.
7962 */
7963
7964struct tblentry {
7965        struct tblentry *next;  /* next entry in hash chain */
7966        union param param;      /* definition of builtin function */
7967        smallint cmdtype;       /* CMDxxx */
7968        char rehash;            /* if set, cd done since entry created */
7969        char cmdname[1];        /* name of command */
7970};
7971
7972static struct tblentry **cmdtable;
7973#define INIT_G_cmdtable() do { \
7974        cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7975} while (0)
7976
7977static int builtinloc = -1;     /* index in path of %builtin, or -1 */
7978
7979
7980static void
7981tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
7982{
7983#if ENABLE_FEATURE_SH_STANDALONE
7984        if (applet_no >= 0) {
7985                if (APPLET_IS_NOEXEC(applet_no)) {
7986                        clearenv();
7987                        while (*envp)
7988                                putenv(*envp++);
7989                        popredir(/*drop:*/ 1);
7990                        run_noexec_applet_and_exit(applet_no, cmd, argv);
7991                }
7992                /* re-exec ourselves with the new arguments */
7993                execve(bb_busybox_exec_path, argv, envp);
7994                /* If they called chroot or otherwise made the binary no longer
7995                 * executable, fall through */
7996        }
7997#endif
7998
7999 repeat:
8000#ifdef SYSV
8001        do {
8002                execve(cmd, argv, envp);
8003        } while (errno == EINTR);
8004#else
8005        execve(cmd, argv, envp);
8006#endif
8007        if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
8008                /* Run "cmd" as a shell script:
8009                 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8010                 * "If the execve() function fails with ENOEXEC, the shell
8011                 * shall execute a command equivalent to having a shell invoked
8012                 * with the command name as its first operand,
8013                 * with any remaining arguments passed to the new shell"
8014                 *
8015                 * That is, do not use $SHELL, user's shell, or /bin/sh;
8016                 * just call ourselves.
8017                 *
8018                 * Note that bash reads ~80 chars of the file, and if it sees
8019                 * a zero byte before it sees newline, it doesn't try to
8020                 * interpret it, but fails with "cannot execute binary file"
8021                 * message and exit code 126. For one, this prevents attempts
8022                 * to interpret foreign ELF binaries as shell scripts.
8023                 */
8024                argv[0] = (char*) cmd;
8025                cmd = bb_busybox_exec_path;
8026                /* NB: this is only possible because all callers of shellexec()
8027                 * ensure that the argv[-1] slot exists!
8028                 */
8029                argv--;
8030                argv[0] = (char*) "ash";
8031                goto repeat;
8032        }
8033}
8034
8035/*
8036 * Exec a program.  Never returns.  If you change this routine, you may
8037 * have to change the find_command routine as well.
8038 * argv[-1] must exist and be writable! See tryexec() for why.
8039 */
8040static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8041static void shellexec(char *prog, char **argv, const char *path, int idx)
8042{
8043        char *cmdname;
8044        int e;
8045        char **envp;
8046        int exerrno;
8047        int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
8048
8049        envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
8050        if (strchr(prog, '/') != NULL
8051#if ENABLE_FEATURE_SH_STANDALONE
8052         || (applet_no = find_applet_by_name(prog)) >= 0
8053#endif
8054        ) {
8055                tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
8056                if (applet_no >= 0) {
8057                        /* We tried execing ourself, but it didn't work.
8058                         * Maybe /proc/self/exe doesn't exist?
8059                         * Try $PATH search.
8060                         */
8061                        goto try_PATH;
8062                }
8063                e = errno;
8064        } else {
8065 try_PATH:
8066                e = ENOENT;
8067                while ((cmdname = path_advance(&path, prog)) != NULL) {
8068                        if (--idx < 0 && pathopt == NULL) {
8069                                tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
8070                                if (errno != ENOENT && errno != ENOTDIR)
8071                                        e = errno;
8072                        }
8073                        stunalloc(cmdname);
8074                }
8075        }
8076
8077        /* Map to POSIX errors */
8078        switch (e) {
8079        case EACCES:
8080                exerrno = 126;
8081                break;
8082        case ENOENT:
8083                exerrno = 127;
8084                break;
8085        default:
8086                exerrno = 2;
8087                break;
8088        }
8089        exitstatus = exerrno;
8090        TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
8091                prog, e, suppress_int));
8092        ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
8093        /* NOTREACHED */
8094}
8095
8096static void
8097printentry(struct tblentry *cmdp)
8098{
8099        int idx;
8100        const char *path;
8101        char *name;
8102
8103        idx = cmdp->param.index;
8104        path = pathval();
8105        do {
8106                name = path_advance(&path, cmdp->cmdname);
8107                stunalloc(name);
8108        } while (--idx >= 0);
8109        out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8110}
8111
8112/*
8113 * Clear out command entries.  The argument specifies the first entry in
8114 * PATH which has changed.
8115 */
8116static void
8117clearcmdentry(int firstchange)
8118{
8119        struct tblentry **tblp;
8120        struct tblentry **pp;
8121        struct tblentry *cmdp;
8122
8123        INT_OFF;
8124        for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8125                pp = tblp;
8126                while ((cmdp = *pp) != NULL) {
8127                        if ((cmdp->cmdtype == CMDNORMAL &&
8128                             cmdp->param.index >= firstchange)
8129                         || (cmdp->cmdtype == CMDBUILTIN &&
8130                             builtinloc >= firstchange)
8131                        ) {
8132                                *pp = cmdp->next;
8133                                free(cmdp);
8134                        } else {
8135                                pp = &cmdp->next;
8136                        }
8137                }
8138        }
8139        INT_ON;
8140}
8141
8142/*
8143 * Locate a command in the command hash table.  If "add" is nonzero,
8144 * add the command to the table if it is not already present.  The
8145 * variable "lastcmdentry" is set to point to the address of the link
8146 * pointing to the entry, so that delete_cmd_entry can delete the
8147 * entry.
8148 *
8149 * Interrupts must be off if called with add != 0.
8150 */
8151static struct tblentry **lastcmdentry;
8152
8153static struct tblentry *
8154cmdlookup(const char *name, int add)
8155{
8156        unsigned int hashval;
8157        const char *p;
8158        struct tblentry *cmdp;
8159        struct tblentry **pp;
8160
8161        p = name;
8162        hashval = (unsigned char)*p << 4;
8163        while (*p)
8164                hashval += (unsigned char)*p++;
8165        hashval &= 0x7FFF;
8166        pp = &cmdtable[hashval % CMDTABLESIZE];
8167        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8168                if (strcmp(cmdp->cmdname, name) == 0)
8169                        break;
8170                pp = &cmdp->next;
8171        }
8172        if (add && cmdp == NULL) {
8173                cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8174                                + strlen(name)
8175                                /* + 1 - already done because
8176                                 * tblentry::cmdname is char[1] */);
8177                /*cmdp->next = NULL; - ckzalloc did it */
8178                cmdp->cmdtype = CMDUNKNOWN;
8179                strcpy(cmdp->cmdname, name);
8180        }
8181        lastcmdentry = pp;
8182        return cmdp;
8183}
8184
8185/*
8186 * Delete the command entry returned on the last lookup.
8187 */
8188static void
8189delete_cmd_entry(void)
8190{
8191        struct tblentry *cmdp;
8192
8193        INT_OFF;
8194        cmdp = *lastcmdentry;
8195        *lastcmdentry = cmdp->next;
8196        if (cmdp->cmdtype == CMDFUNCTION)
8197                freefunc(cmdp->param.func);
8198        free(cmdp);
8199        INT_ON;
8200}
8201
8202/*
8203 * Add a new command entry, replacing any existing command entry for
8204 * the same name - except special builtins.
8205 */
8206static void
8207addcmdentry(char *name, struct cmdentry *entry)
8208{
8209        struct tblentry *cmdp;
8210
8211        cmdp = cmdlookup(name, 1);
8212        if (cmdp->cmdtype == CMDFUNCTION) {
8213                freefunc(cmdp->param.func);
8214        }
8215        cmdp->cmdtype = entry->cmdtype;
8216        cmdp->param = entry->u;
8217        cmdp->rehash = 0;
8218}
8219
8220static int FAST_FUNC
8221hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8222{
8223        struct tblentry **pp;
8224        struct tblentry *cmdp;
8225        int c;
8226        struct cmdentry entry;
8227        char *name;
8228
8229        if (nextopt("r") != '\0') {
8230                clearcmdentry(0);
8231                return 0;
8232        }
8233
8234        if (*argptr == NULL) {
8235                for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8236                        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8237                                if (cmdp->cmdtype == CMDNORMAL)
8238                                        printentry(cmdp);
8239                        }
8240                }
8241                return 0;
8242        }
8243
8244        c = 0;
8245        while ((name = *argptr) != NULL) {
8246                cmdp = cmdlookup(name, 0);
8247                if (cmdp != NULL
8248                 && (cmdp->cmdtype == CMDNORMAL
8249                     || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8250                ) {
8251                        delete_cmd_entry();
8252                }
8253                find_command(name, &entry, DO_ERR, pathval());
8254                if (entry.cmdtype == CMDUNKNOWN)
8255                        c = 1;
8256                argptr++;
8257        }
8258        return c;
8259}
8260
8261/*
8262 * Called when a cd is done.  Marks all commands so the next time they
8263 * are executed they will be rehashed.
8264 */
8265static void
8266hashcd(void)
8267{
8268        struct tblentry **pp;
8269        struct tblentry *cmdp;
8270
8271        for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8272                for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8273                        if (cmdp->cmdtype == CMDNORMAL
8274                         || (cmdp->cmdtype == CMDBUILTIN
8275                             && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8276                             && builtinloc > 0)
8277                        ) {
8278                                cmdp->rehash = 1;
8279                        }
8280                }
8281        }
8282}
8283
8284/*
8285 * Fix command hash table when PATH changed.
8286 * Called before PATH is changed.  The argument is the new value of PATH;
8287 * pathval() still returns the old value at this point.
8288 * Called with interrupts off.
8289 */
8290static void FAST_FUNC
8291changepath(const char *new)
8292{
8293        const char *old;
8294        int firstchange;
8295        int idx;
8296        int idx_bltin;
8297
8298        old = pathval();
8299        firstchange = 9999;     /* assume no change */
8300        idx = 0;
8301        idx_bltin = -1;
8302        for (;;) {
8303                if (*old != *new) {
8304                        firstchange = idx;
8305                        if ((*old == '\0' && *new == ':')
8306                         || (*old == ':' && *new == '\0')
8307                        ) {
8308                                firstchange++;
8309                        }
8310                        old = new;      /* ignore subsequent differences */
8311                }
8312                if (*new == '\0')
8313                        break;
8314                if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8315                        idx_bltin = idx;
8316                if (*new == ':')
8317                        idx++;
8318                new++;
8319                old++;
8320        }
8321        if (builtinloc < 0 && idx_bltin >= 0)
8322                builtinloc = idx_bltin;             /* zap builtins */
8323        if (builtinloc >= 0 && idx_bltin < 0)
8324                firstchange = 0;
8325        clearcmdentry(firstchange);
8326        builtinloc = idx_bltin;
8327}
8328enum {
8329        TEOF,
8330        TNL,
8331        TREDIR,
8332        TWORD,
8333        TSEMI,
8334        TBACKGND,
8335        TAND,
8336        TOR,
8337        TPIPE,
8338        TLP,
8339        TRP,
8340        TENDCASE,
8341        TENDBQUOTE,
8342        TNOT,
8343        TCASE,
8344        TDO,
8345        TDONE,
8346        TELIF,
8347        TELSE,
8348        TESAC,
8349        TFI,
8350        TFOR,
8351#if BASH_FUNCTION
8352        TFUNCTION,
8353#endif
8354        TIF,
8355        TIN,
8356        TTHEN,
8357        TUNTIL,
8358        TWHILE,
8359        TBEGIN,
8360        TEND
8361};
8362typedef smallint token_id_t;
8363
8364/* Nth bit indicates if token marks the end of a list */
8365enum {
8366        tokendlist = 0
8367        /*  0 */ | (1u << TEOF)
8368        /*  1 */ | (0u << TNL)
8369        /*  2 */ | (0u << TREDIR)
8370        /*  3 */ | (0u << TWORD)
8371        /*  4 */ | (0u << TSEMI)
8372        /*  5 */ | (0u << TBACKGND)
8373        /*  6 */ | (0u << TAND)
8374        /*  7 */ | (0u << TOR)
8375        /*  8 */ | (0u << TPIPE)
8376        /*  9 */ | (0u << TLP)
8377        /* 10 */ | (1u << TRP)
8378        /* 11 */ | (1u << TENDCASE)
8379        /* 12 */ | (1u << TENDBQUOTE)
8380        /* 13 */ | (0u << TNOT)
8381        /* 14 */ | (0u << TCASE)
8382        /* 15 */ | (1u << TDO)
8383        /* 16 */ | (1u << TDONE)
8384        /* 17 */ | (1u << TELIF)
8385        /* 18 */ | (1u << TELSE)
8386        /* 19 */ | (1u << TESAC)
8387        /* 20 */ | (1u << TFI)
8388        /* 21 */ | (0u << TFOR)
8389#if BASH_FUNCTION
8390        /* 22 */ | (0u << TFUNCTION)
8391#endif
8392        /* 23 */ | (0u << TIF)
8393        /* 24 */ | (0u << TIN)
8394        /* 25 */ | (1u << TTHEN)
8395        /* 26 */ | (0u << TUNTIL)
8396        /* 27 */ | (0u << TWHILE)
8397        /* 28 */ | (0u << TBEGIN)
8398        /* 29 */ | (1u << TEND)
8399        , /* thus far 29 bits used */
8400};
8401
8402static const char *const tokname_array[] = {
8403        "end of file",
8404        "newline",
8405        "redirection",
8406        "word",
8407        ";",
8408        "&",
8409        "&&",
8410        "||",
8411        "|",
8412        "(",
8413        ")",
8414        ";;",
8415        "`",
8416#define KWDOFFSET 13
8417        /* the following are keywords */
8418        "!",
8419        "case",
8420        "do",
8421        "done",
8422        "elif",
8423        "else",
8424        "esac",
8425        "fi",
8426        "for",
8427#if BASH_FUNCTION
8428        "function",
8429#endif
8430        "if",
8431        "in",
8432        "then",
8433        "until",
8434        "while",
8435        "{",
8436        "}",
8437};
8438
8439/* Wrapper around strcmp for qsort/bsearch/... */
8440static int
8441pstrcmp(const void *a, const void *b)
8442{
8443        return strcmp((char*)a, *(char**)b);
8444}
8445
8446static const char *const *
8447findkwd(const char *s)
8448{
8449        return bsearch(s, tokname_array + KWDOFFSET,
8450                        ARRAY_SIZE(tokname_array) - KWDOFFSET,
8451                        sizeof(tokname_array[0]), pstrcmp);
8452}
8453
8454/*
8455 * Locate and print what a word is...
8456 */
8457static int
8458describe_command(char *command, const char *path, int describe_command_verbose)
8459{
8460        struct cmdentry entry;
8461#if ENABLE_ASH_ALIAS
8462        const struct alias *ap;
8463#endif
8464
8465        path = path ? path : pathval();
8466
8467        if (describe_command_verbose) {
8468                out1str(command);
8469        }
8470
8471        /* First look at the keywords */
8472        if (findkwd(command)) {
8473                out1str(describe_command_verbose ? " is a shell keyword" : command);
8474                goto out;
8475        }
8476
8477#if ENABLE_ASH_ALIAS
8478        /* Then look at the aliases */
8479        ap = lookupalias(command, 0);
8480        if (ap != NULL) {
8481                if (!describe_command_verbose) {
8482                        out1str("alias ");
8483                        printalias(ap);
8484                        return 0;
8485                }
8486                out1fmt(" is an alias for %s", ap->val);
8487                goto out;
8488        }
8489#endif
8490        /* Brute force */
8491        find_command(command, &entry, DO_ABS, path);
8492
8493        switch (entry.cmdtype) {
8494        case CMDNORMAL: {
8495                int j = entry.u.index;
8496                char *p;
8497                if (j < 0) {
8498                        p = command;
8499                } else {
8500                        do {
8501                                p = path_advance(&path, command);
8502                                stunalloc(p);
8503                        } while (--j >= 0);
8504                }
8505                if (describe_command_verbose) {
8506                        out1fmt(" is %s", p);
8507                } else {
8508                        out1str(p);
8509                }
8510                break;
8511        }
8512
8513        case CMDFUNCTION:
8514                if (describe_command_verbose) {
8515                        out1str(" is a shell function");
8516                } else {
8517                        out1str(command);
8518                }
8519                break;
8520
8521        case CMDBUILTIN:
8522                if (describe_command_verbose) {
8523                        out1fmt(" is a %sshell builtin",
8524                                IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8525                                        "special " : nullstr
8526                        );
8527                } else {
8528                        out1str(command);
8529                }
8530                break;
8531
8532        default:
8533                if (describe_command_verbose) {
8534                        out1str(": not found\n");
8535                }
8536                return 127;
8537        }
8538 out:
8539        out1str("\n");
8540        return 0;
8541}
8542
8543static int FAST_FUNC
8544typecmd(int argc UNUSED_PARAM, char **argv)
8545{
8546        int i = 1;
8547        int err = 0;
8548        int verbose = 1;
8549
8550        /* type -p ... ? (we don't bother checking for 'p') */
8551        if (argv[1] && argv[1][0] == '-') {
8552                i++;
8553                verbose = 0;
8554        }
8555        while (argv[i]) {
8556                err |= describe_command(argv[i++], NULL, verbose);
8557        }
8558        return err;
8559}
8560
8561#if ENABLE_ASH_CMDCMD
8562/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8563static char **
8564parse_command_args(char **argv, const char **path)
8565{
8566        char *cp, c;
8567
8568        for (;;) {
8569                cp = *++argv;
8570                if (!cp)
8571                        return NULL;
8572                if (*cp++ != '-')
8573                        break;
8574                c = *cp++;
8575                if (!c)
8576                        break;
8577                if (c == '-' && !*cp) {
8578                        if (!*++argv)
8579                                return NULL;
8580                        break;
8581                }
8582                do {
8583                        switch (c) {
8584                        case 'p':
8585                                *path = bb_default_path;
8586                                break;
8587                        default:
8588                                /* run 'typecmd' for other options */
8589                                return NULL;
8590                        }
8591                        c = *cp++;
8592                } while (c);
8593        }
8594        return argv;
8595}
8596
8597static int FAST_FUNC
8598commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8599{
8600        char *cmd;
8601        int c;
8602        enum {
8603                VERIFY_BRIEF = 1,
8604                VERIFY_VERBOSE = 2,
8605        } verify = 0;
8606        const char *path = NULL;
8607
8608        /* "command [-p] PROG ARGS" (that is, without -V or -v)
8609         * never reaches this function.
8610         */
8611
8612        while ((c = nextopt("pvV")) != '\0')
8613                if (c == 'V')
8614                        verify |= VERIFY_VERBOSE;
8615                else if (c == 'v')
8616                        /*verify |= VERIFY_BRIEF*/;
8617#if DEBUG
8618                else if (c != 'p')
8619                        abort();
8620#endif
8621                else
8622                        path = bb_default_path;
8623
8624        /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8625        cmd = *argptr;
8626        if (/*verify && */ cmd)
8627                return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8628
8629        return 0;
8630}
8631#endif
8632
8633
8634/*static int funcblocksize;     // size of structures in function */
8635/*static int funcstringsize;    // size of strings in node */
8636static void *funcblock;         /* block to allocate function from */
8637static char *funcstring_end;    /* end of block to allocate strings from */
8638
8639static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8640        [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
8641        [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
8642        [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
8643        [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8644        [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8645        [NAND     ] = SHELL_ALIGN(sizeof(struct nbinary)),
8646        [NOR      ] = SHELL_ALIGN(sizeof(struct nbinary)),
8647        [NSEMI    ] = SHELL_ALIGN(sizeof(struct nbinary)),
8648        [NIF      ] = SHELL_ALIGN(sizeof(struct nif)),
8649        [NWHILE   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8650        [NUNTIL   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8651        [NFOR     ] = SHELL_ALIGN(sizeof(struct nfor)),
8652        [NCASE    ] = SHELL_ALIGN(sizeof(struct ncase)),
8653        [NCLIST   ] = SHELL_ALIGN(sizeof(struct nclist)),
8654        [NDEFUN   ] = SHELL_ALIGN(sizeof(struct narg)),
8655        [NARG     ] = SHELL_ALIGN(sizeof(struct narg)),
8656        [NTO      ] = SHELL_ALIGN(sizeof(struct nfile)),
8657#if BASH_REDIR_OUTPUT
8658        [NTO2     ] = SHELL_ALIGN(sizeof(struct nfile)),
8659#endif
8660        [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8661        [NFROM    ] = SHELL_ALIGN(sizeof(struct nfile)),
8662        [NFROMTO  ] = SHELL_ALIGN(sizeof(struct nfile)),
8663        [NAPPEND  ] = SHELL_ALIGN(sizeof(struct nfile)),
8664        [NTOFD    ] = SHELL_ALIGN(sizeof(struct ndup)),
8665        [NFROMFD  ] = SHELL_ALIGN(sizeof(struct ndup)),
8666        [NHERE    ] = SHELL_ALIGN(sizeof(struct nhere)),
8667        [NXHERE   ] = SHELL_ALIGN(sizeof(struct nhere)),
8668        [NNOT     ] = SHELL_ALIGN(sizeof(struct nnot)),
8669};
8670
8671static int calcsize(int funcblocksize, union node *n);
8672
8673static int
8674sizenodelist(int funcblocksize, struct nodelist *lp)
8675{
8676        while (lp) {
8677                funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8678                funcblocksize = calcsize(funcblocksize, lp->n);
8679                lp = lp->next;
8680        }
8681        return funcblocksize;
8682}
8683
8684static int
8685calcsize(int funcblocksize, union node *n)
8686{
8687        if (n == NULL)
8688                return funcblocksize;
8689        funcblocksize += nodesize[n->type];
8690        switch (n->type) {
8691        case NCMD:
8692                funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8693                funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8694                funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8695                break;
8696        case NPIPE:
8697                funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8698                break;
8699        case NREDIR:
8700        case NBACKGND:
8701        case NSUBSHELL:
8702                funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8703                funcblocksize = calcsize(funcblocksize, n->nredir.n);
8704                break;
8705        case NAND:
8706        case NOR:
8707        case NSEMI:
8708        case NWHILE:
8709        case NUNTIL:
8710                funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8711                funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
8712                break;
8713        case NIF:
8714                funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8715                funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8716                funcblocksize = calcsize(funcblocksize, n->nif.test);
8717                break;
8718        case NFOR:
8719                funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
8720                funcblocksize = calcsize(funcblocksize, n->nfor.body);
8721                funcblocksize = calcsize(funcblocksize, n->nfor.args);
8722                break;
8723        case NCASE:
8724                funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8725                funcblocksize = calcsize(funcblocksize, n->ncase.expr);
8726                break;
8727        case NCLIST:
8728                funcblocksize = calcsize(funcblocksize, n->nclist.body);
8729                funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8730                funcblocksize = calcsize(funcblocksize, n->nclist.next);
8731                break;
8732        case NDEFUN:
8733                funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8734                funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8735                break;
8736        case NARG:
8737                funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
8738                funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
8739                funcblocksize = calcsize(funcblocksize, n->narg.next);
8740                break;
8741        case NTO:
8742#if BASH_REDIR_OUTPUT
8743        case NTO2:
8744#endif
8745        case NCLOBBER:
8746        case NFROM:
8747        case NFROMTO:
8748        case NAPPEND:
8749                funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8750                funcblocksize = calcsize(funcblocksize, n->nfile.next);
8751                break;
8752        case NTOFD:
8753        case NFROMFD:
8754                funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8755                funcblocksize = calcsize(funcblocksize, n->ndup.next);
8756        break;
8757        case NHERE:
8758        case NXHERE:
8759                funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8760                funcblocksize = calcsize(funcblocksize, n->nhere.next);
8761                break;
8762        case NNOT:
8763                funcblocksize = calcsize(funcblocksize, n->nnot.com);
8764                break;
8765        };
8766        return funcblocksize;
8767}
8768
8769static char *
8770nodeckstrdup(char *s)
8771{
8772        funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
8773        return strcpy(funcstring_end, s);
8774}
8775
8776static union node *copynode(union node *);
8777
8778static struct nodelist *
8779copynodelist(struct nodelist *lp)
8780{
8781        struct nodelist *start;
8782        struct nodelist **lpp;
8783
8784        lpp = &start;
8785        while (lp) {
8786                *lpp = funcblock;
8787                funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8788                (*lpp)->n = copynode(lp->n);
8789                lp = lp->next;
8790                lpp = &(*lpp)->next;
8791        }
8792        *lpp = NULL;
8793        return start;
8794}
8795
8796static union node *
8797copynode(union node *n)
8798{
8799        union node *new;
8800
8801        if (n == NULL)
8802                return NULL;
8803        new = funcblock;
8804        funcblock = (char *) funcblock + nodesize[n->type];
8805
8806        switch (n->type) {
8807        case NCMD:
8808                new->ncmd.redirect = copynode(n->ncmd.redirect);
8809                new->ncmd.args = copynode(n->ncmd.args);
8810                new->ncmd.assign = copynode(n->ncmd.assign);
8811                new->ncmd.linno = n->ncmd.linno;
8812                break;
8813        case NPIPE:
8814                new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8815                new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8816                break;
8817        case NREDIR:
8818        case NBACKGND:
8819        case NSUBSHELL:
8820                new->nredir.redirect = copynode(n->nredir.redirect);
8821                new->nredir.n = copynode(n->nredir.n);
8822                new->nredir.linno = n->nredir.linno;
8823                break;
8824        case NAND:
8825        case NOR:
8826        case NSEMI:
8827        case NWHILE:
8828        case NUNTIL:
8829                new->nbinary.ch2 = copynode(n->nbinary.ch2);
8830                new->nbinary.ch1 = copynode(n->nbinary.ch1);
8831                break;
8832        case NIF:
8833                new->nif.elsepart = copynode(n->nif.elsepart);
8834                new->nif.ifpart = copynode(n->nif.ifpart);
8835                new->nif.test = copynode(n->nif.test);
8836                break;
8837        case NFOR:
8838                new->nfor.var = nodeckstrdup(n->nfor.var);
8839                new->nfor.body = copynode(n->nfor.body);
8840                new->nfor.args = copynode(n->nfor.args);
8841                new->nfor.linno = n->nfor.linno;
8842                break;
8843        case NCASE:
8844                new->ncase.cases = copynode(n->ncase.cases);
8845                new->ncase.expr = copynode(n->ncase.expr);
8846                new->ncase.linno = n->ncase.linno;
8847                break;
8848        case NCLIST:
8849                new->nclist.body = copynode(n->nclist.body);
8850                new->nclist.pattern = copynode(n->nclist.pattern);
8851                new->nclist.next = copynode(n->nclist.next);
8852                break;
8853        case NDEFUN:
8854                new->ndefun.body = copynode(n->ndefun.body);
8855                new->ndefun.text = nodeckstrdup(n->ndefun.text);
8856                new->ndefun.linno = n->ndefun.linno;
8857                break;
8858        case NARG:
8859                new->narg.backquote = copynodelist(n->narg.backquote);
8860                new->narg.text = nodeckstrdup(n->narg.text);
8861                new->narg.next = copynode(n->narg.next);
8862                break;
8863        case NTO:
8864#if BASH_REDIR_OUTPUT
8865        case NTO2:
8866#endif
8867        case NCLOBBER:
8868        case NFROM:
8869        case NFROMTO:
8870        case NAPPEND:
8871                new->nfile.fname = copynode(n->nfile.fname);
8872                new->nfile.fd = n->nfile.fd;
8873                new->nfile.next = copynode(n->nfile.next);
8874                break;
8875        case NTOFD:
8876        case NFROMFD:
8877                new->ndup.vname = copynode(n->ndup.vname);
8878                new->ndup.dupfd = n->ndup.dupfd;
8879                new->ndup.fd = n->ndup.fd;
8880                new->ndup.next = copynode(n->ndup.next);
8881                break;
8882        case NHERE:
8883        case NXHERE:
8884                new->nhere.doc = copynode(n->nhere.doc);
8885                new->nhere.fd = n->nhere.fd;
8886                new->nhere.next = copynode(n->nhere.next);
8887                break;
8888        case NNOT:
8889                new->nnot.com = copynode(n->nnot.com);
8890                break;
8891        };
8892        new->type = n->type;
8893        return new;
8894}
8895
8896/*
8897 * Make a copy of a parse tree.
8898 */
8899static struct funcnode *
8900copyfunc(union node *n)
8901{
8902        struct funcnode *f;
8903        size_t blocksize;
8904
8905        /*funcstringsize = 0;*/
8906        blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8907        f = ckzalloc(blocksize /* + funcstringsize */);
8908        funcblock = (char *) f + offsetof(struct funcnode, n);
8909        funcstring_end = (char *) f + blocksize;
8910        copynode(n);
8911        /* f->count = 0; - ckzalloc did it */
8912        return f;
8913}
8914
8915/*
8916 * Define a shell function.
8917 */
8918static void
8919defun(union node *func)
8920{
8921        struct cmdentry entry;
8922
8923        INT_OFF;
8924        entry.cmdtype = CMDFUNCTION;
8925        entry.u.func = copyfunc(func);
8926        addcmdentry(func->ndefun.text, &entry);
8927        INT_ON;
8928}
8929
8930/* Reasons for skipping commands (see comment on breakcmd routine) */
8931#define SKIPBREAK      (1 << 0)
8932#define SKIPCONT       (1 << 1)
8933#define SKIPFUNC       (1 << 2)
8934static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
8935static int skipcount;           /* number of levels to skip */
8936static int loopnest;            /* current loop nesting level */
8937static int funcline;            /* starting line number of current function, or 0 if not in a function */
8938
8939/* Forward decl way out to parsing code - dotrap needs it */
8940static int evalstring(char *s, int flags);
8941
8942/* Called to execute a trap.
8943 * Single callsite - at the end of evaltree().
8944 * If we return non-zero, evaltree raises EXEXIT exception.
8945 *
8946 * Perhaps we should avoid entering new trap handlers
8947 * while we are executing a trap handler. [is it a TODO?]
8948 */
8949static void
8950dotrap(void)
8951{
8952        uint8_t *g;
8953        int sig;
8954        uint8_t last_status;
8955
8956        if (!pending_sig)
8957                return;
8958
8959        last_status = exitstatus;
8960        pending_sig = 0;
8961        barrier();
8962
8963        TRACE(("dotrap entered\n"));
8964        for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8965                char *p;
8966
8967                if (!*g)
8968                        continue;
8969
8970                if (evalskip) {
8971                        pending_sig = sig;
8972                        break;
8973                }
8974
8975                p = trap[sig];
8976                /* non-trapped SIGINT is handled separately by raise_interrupt,
8977                 * don't upset it by resetting gotsig[SIGINT-1] */
8978                if (sig == SIGINT && !p)
8979                        continue;
8980
8981                TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
8982                *g = 0;
8983                if (!p)
8984                        continue;
8985                evalstring(p, 0);
8986        }
8987        exitstatus = last_status;
8988        TRACE(("dotrap returns\n"));
8989}
8990
8991/* forward declarations - evaluation is fairly recursive business... */
8992static int evalloop(union node *, int);
8993static int evalfor(union node *, int);
8994static int evalcase(union node *, int);
8995static int evalsubshell(union node *, int);
8996static void expredir(union node *);
8997static int evalpipe(union node *, int);
8998static int evalcommand(union node *, int);
8999static int evalbltin(const struct builtincmd *, int, char **, int);
9000static void prehash(union node *);
9001
9002/*
9003 * Evaluate a parse tree.  The value is left in the global variable
9004 * exitstatus.
9005 */
9006static int
9007evaltree(union node *n, int flags)
9008{
9009        int checkexit = 0;
9010        int (*evalfn)(union node *, int);
9011        int status = 0;
9012
9013        if (n == NULL) {
9014                TRACE(("evaltree(NULL) called\n"));
9015                goto out;
9016        }
9017        TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
9018
9019        dotrap();
9020
9021        switch (n->type) {
9022        default:
9023#if DEBUG
9024                out1fmt("Node type = %d\n", n->type);
9025                fflush_all();
9026                break;
9027#endif
9028        case NNOT:
9029                status = !evaltree(n->nnot.com, EV_TESTED);
9030                goto setstatus;
9031        case NREDIR:
9032                errlinno = lineno = n->nredir.linno;
9033                if (funcline)
9034                        lineno -= funcline - 1;
9035                expredir(n->nredir.redirect);
9036                pushredir(n->nredir.redirect);
9037                status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9038                if (!status) {
9039                        status = evaltree(n->nredir.n, flags & EV_TESTED);
9040                }
9041                if (n->nredir.redirect)
9042                        popredir(/*drop:*/ 0);
9043                goto setstatus;
9044        case NCMD:
9045                evalfn = evalcommand;
9046 checkexit:
9047                if (eflag && !(flags & EV_TESTED))
9048                        checkexit = ~0;
9049                goto calleval;
9050        case NFOR:
9051                evalfn = evalfor;
9052                goto calleval;
9053        case NWHILE:
9054        case NUNTIL:
9055                evalfn = evalloop;
9056                goto calleval;
9057        case NSUBSHELL:
9058        case NBACKGND:
9059                evalfn = evalsubshell;
9060                goto checkexit;
9061        case NPIPE:
9062                evalfn = evalpipe;
9063                goto checkexit;
9064        case NCASE:
9065                evalfn = evalcase;
9066                goto calleval;
9067        case NAND:
9068        case NOR:
9069        case NSEMI: {
9070
9071#if NAND + 1 != NOR
9072#error NAND + 1 != NOR
9073#endif
9074#if NOR + 1 != NSEMI
9075#error NOR + 1 != NSEMI
9076#endif
9077                unsigned is_or = n->type - NAND;
9078                status = evaltree(
9079                        n->nbinary.ch1,
9080                        (flags | ((is_or >> 1) - 1)) & EV_TESTED
9081                );
9082                if ((!status) == is_or || evalskip)
9083                        break;
9084                n = n->nbinary.ch2;
9085 evaln:
9086                evalfn = evaltree;
9087 calleval:
9088                status = evalfn(n, flags);
9089                goto setstatus;
9090        }
9091        case NIF:
9092                status = evaltree(n->nif.test, EV_TESTED);
9093                if (evalskip)
9094                        break;
9095                if (!status) {
9096                        n = n->nif.ifpart;
9097                        goto evaln;
9098                }
9099                if (n->nif.elsepart) {
9100                        n = n->nif.elsepart;
9101                        goto evaln;
9102                }
9103                status = 0;
9104                goto setstatus;
9105        case NDEFUN:
9106                defun(n);
9107                /* Not necessary. To test it:
9108                 * "false; f() { qwerty; }; echo $?" should print 0.
9109                 */
9110                /* status = 0; */
9111 setstatus:
9112                exitstatus = status;
9113                break;
9114        }
9115 out:
9116        /* Order of checks below is important:
9117         * signal handlers trigger before exit caused by "set -e".
9118         */
9119        dotrap();
9120
9121        if (checkexit & status)
9122                raise_exception(EXEXIT);
9123        if (flags & EV_EXIT)
9124                raise_exception(EXEXIT);
9125
9126        TRACE(("leaving evaltree (no interrupts)\n"));
9127        return exitstatus;
9128}
9129
9130static int
9131skiploop(void)
9132{
9133        int skip = evalskip;
9134
9135        switch (skip) {
9136        case 0:
9137                break;
9138        case SKIPBREAK:
9139        case SKIPCONT:
9140                if (--skipcount <= 0) {
9141                        evalskip = 0;
9142                        break;
9143                }
9144                skip = SKIPBREAK;
9145                break;
9146        }
9147        return skip;
9148}
9149
9150static int
9151evalloop(union node *n, int flags)
9152{
9153        int skip;
9154        int status;
9155
9156        loopnest++;
9157        status = 0;
9158        flags &= EV_TESTED;
9159        do {
9160                int i;
9161
9162                i = evaltree(n->nbinary.ch1, EV_TESTED);
9163                skip = skiploop();
9164                if (skip == SKIPFUNC)
9165                        status = i;
9166                if (skip)
9167                        continue;
9168                if (n->type != NWHILE)
9169                        i = !i;
9170                if (i != 0)
9171                        break;
9172                status = evaltree(n->nbinary.ch2, flags);
9173                skip = skiploop();
9174        } while (!(skip & ~SKIPCONT));
9175        loopnest--;
9176
9177        return status;
9178}
9179
9180static int
9181evalfor(union node *n, int flags)
9182{
9183        struct arglist arglist;
9184        union node *argp;
9185        struct strlist *sp;
9186        struct stackmark smark;
9187        int status = 0;
9188
9189        errlinno = lineno = n->ncase.linno;
9190        if (funcline)
9191                lineno -= funcline - 1;
9192
9193        setstackmark(&smark);
9194        arglist.list = NULL;
9195        arglist.lastp = &arglist.list;
9196        for (argp = n->nfor.args; argp; argp = argp->narg.next) {
9197                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9198        }
9199        *arglist.lastp = NULL;
9200
9201        loopnest++;
9202        flags &= EV_TESTED;
9203        for (sp = arglist.list; sp; sp = sp->next) {
9204                setvar0(n->nfor.var, sp->text);
9205                status = evaltree(n->nfor.body, flags);
9206                if (skiploop() & ~SKIPCONT)
9207                        break;
9208        }
9209        loopnest--;
9210        popstackmark(&smark);
9211
9212        return status;
9213}
9214
9215static int
9216evalcase(union node *n, int flags)
9217{
9218        union node *cp;
9219        union node *patp;
9220        struct arglist arglist;
9221        struct stackmark smark;
9222        int status = 0;
9223
9224        errlinno = lineno = n->ncase.linno;
9225        if (funcline)
9226                lineno -= funcline - 1;
9227
9228        setstackmark(&smark);
9229        arglist.list = NULL;
9230        arglist.lastp = &arglist.list;
9231        expandarg(n->ncase.expr, &arglist, EXP_TILDE);
9232        for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9233                for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
9234                        if (casematch(patp, arglist.list->text)) {
9235                                /* Ensure body is non-empty as otherwise
9236                                 * EV_EXIT may prevent us from setting the
9237                                 * exit status.
9238                                 */
9239                                if (evalskip == 0 && cp->nclist.body) {
9240                                        status = evaltree(cp->nclist.body, flags);
9241                                }
9242                                goto out;
9243                        }
9244                }
9245        }
9246 out:
9247        popstackmark(&smark);
9248
9249        return status;
9250}
9251
9252/*
9253 * Kick off a subshell to evaluate a tree.
9254 */
9255static int
9256evalsubshell(union node *n, int flags)
9257{
9258        struct job *jp;
9259        int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9260        int status;
9261
9262        errlinno = lineno = n->nredir.linno;
9263        if (funcline)
9264                lineno -= funcline - 1;
9265
9266        expredir(n->nredir.redirect);
9267        if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9268                goto nofork;
9269        INT_OFF;
9270        if (backgnd == FORK_FG)
9271                get_tty_state();
9272        jp = makejob(/*n,*/ 1);
9273        if (forkshell(jp, n, backgnd) == 0) {
9274                /* child */
9275                INT_ON;
9276                flags |= EV_EXIT;
9277                if (backgnd)
9278                        flags &= ~EV_TESTED;
9279 nofork:
9280                redirect(n->nredir.redirect, 0);
9281                evaltreenr(n->nredir.n, flags);
9282                /* never returns */
9283        }
9284        /* parent */
9285        status = 0;
9286        if (backgnd == FORK_FG)
9287                status = waitforjob(jp);
9288        INT_ON;
9289        return status;
9290}
9291
9292/*
9293 * Compute the names of the files in a redirection list.
9294 */
9295static void fixredir(union node *, const char *, int);
9296static void
9297expredir(union node *n)
9298{
9299        union node *redir;
9300
9301        for (redir = n; redir; redir = redir->nfile.next) {
9302                struct arglist fn;
9303
9304                fn.list = NULL;
9305                fn.lastp = &fn.list;
9306                switch (redir->type) {
9307                case NFROMTO:
9308                case NFROM:
9309                case NTO:
9310#if BASH_REDIR_OUTPUT
9311                case NTO2:
9312#endif
9313                case NCLOBBER:
9314                case NAPPEND:
9315                        expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
9316                        TRACE(("expredir expanded to '%s'\n", fn.list->text));
9317#if BASH_REDIR_OUTPUT
9318 store_expfname:
9319#endif
9320#if 0
9321// By the design of stack allocator, the loop of this kind:
9322//      while true; do while true; do break; done </dev/null; done
9323// will look like a memory leak: ash plans to free expfname's
9324// of "/dev/null" as soon as it finishes running the loop
9325// (in this case, never).
9326// This "fix" is wrong:
9327                        if (redir->nfile.expfname)
9328                                stunalloc(redir->nfile.expfname);
9329// It results in corrupted state of stacked allocations.
9330#endif
9331                        redir->nfile.expfname = fn.list->text;
9332                        break;
9333                case NFROMFD:
9334                case NTOFD: /* >& */
9335                        if (redir->ndup.vname) {
9336                                expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
9337                                if (fn.list == NULL)
9338                                        ash_msg_and_raise_error("redir error");
9339#if BASH_REDIR_OUTPUT
9340//FIXME: we used expandarg with different args!
9341                                if (!isdigit_str9(fn.list->text)) {
9342                                        /* >&file, not >&fd */
9343                                        if (redir->nfile.fd != 1) /* 123>&file - BAD */
9344                                                ash_msg_and_raise_error("redir error");
9345                                        redir->type = NTO2;
9346                                        goto store_expfname;
9347                                }
9348#endif
9349                                fixredir(redir, fn.list->text, 1);
9350                        }
9351                        break;
9352                }
9353        }
9354}
9355
9356/*
9357 * Evaluate a pipeline.  All the processes in the pipeline are children
9358 * of the process creating the pipeline.  (This differs from some versions
9359 * of the shell, which make the last process in a pipeline the parent
9360 * of all the rest.)
9361 */
9362static int
9363evalpipe(union node *n, int flags)
9364{
9365        struct job *jp;
9366        struct nodelist *lp;
9367        int pipelen;
9368        int prevfd;
9369        int pip[2];
9370        int status = 0;
9371
9372        TRACE(("evalpipe(0x%lx) called\n", (long)n));
9373        pipelen = 0;
9374        for (lp = n->npipe.cmdlist; lp; lp = lp->next)
9375                pipelen++;
9376        flags |= EV_EXIT;
9377        INT_OFF;
9378        if (n->npipe.pipe_backgnd == 0)
9379                get_tty_state();
9380        jp = makejob(/*n,*/ pipelen);
9381        prevfd = -1;
9382        for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
9383                prehash(lp->n);
9384                pip[1] = -1;
9385                if (lp->next) {
9386                        if (pipe(pip) < 0) {
9387                                close(prevfd);
9388                                ash_msg_and_raise_perror("can't create pipe");
9389                        }
9390                }
9391                if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9392                        /* child */
9393                        INT_ON;
9394                        if (pip[1] >= 0) {
9395                                close(pip[0]);
9396                        }
9397                        if (prevfd > 0) {
9398                                dup2(prevfd, 0);
9399                                close(prevfd);
9400                        }
9401                        if (pip[1] > 1) {
9402                                dup2(pip[1], 1);
9403                                close(pip[1]);
9404                        }
9405                        evaltreenr(lp->n, flags);
9406                        /* never returns */
9407                }
9408                /* parent */
9409                if (prevfd >= 0)
9410                        close(prevfd);
9411                prevfd = pip[0];
9412                /* Don't want to trigger debugging */
9413                if (pip[1] != -1)
9414                        close(pip[1]);
9415        }
9416        if (n->npipe.pipe_backgnd == 0) {
9417                status = waitforjob(jp);
9418                TRACE(("evalpipe:  job done exit status %d\n", status));
9419        }
9420        INT_ON;
9421
9422        return status;
9423}
9424
9425/*
9426 * Controls whether the shell is interactive or not.
9427 */
9428static void
9429setinteractive(int on)
9430{
9431        static smallint is_interactive;
9432
9433        if (++on == is_interactive)
9434                return;
9435        is_interactive = on;
9436        setsignal(SIGINT);
9437        setsignal(SIGQUIT);
9438        setsignal(SIGTERM);
9439#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9440        if (is_interactive > 1) {
9441                /* Looks like they want an interactive shell */
9442                static smallint did_banner;
9443
9444                if (!did_banner) {
9445                        /* note: ash and hush share this string */
9446                        out1fmt("\n\n%s %s\n"
9447                                IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9448                                "\n",
9449                                bb_banner,
9450                                "built-in shell (ash)"
9451                        );
9452                        did_banner = 1;
9453                }
9454        }
9455#endif
9456}
9457
9458static void
9459optschanged(void)
9460{
9461#if DEBUG
9462        opentrace();
9463#endif
9464        setinteractive(iflag);
9465        setjobctl(mflag);
9466#if ENABLE_FEATURE_EDITING_VI
9467        if (viflag)
9468                line_input_state->flags |= VI_MODE;
9469        else
9470                line_input_state->flags &= ~VI_MODE;
9471#else
9472        viflag = 0; /* forcibly keep the option off */
9473#endif
9474}
9475
9476struct localvar_list {
9477        struct localvar_list *next;
9478        struct localvar *lv;
9479};
9480
9481static struct localvar_list *localvar_stack;
9482
9483/*
9484 * Called after a function returns.
9485 * Interrupts must be off.
9486 */
9487static void
9488poplocalvars(int keep)
9489{
9490        struct localvar_list *ll;
9491        struct localvar *lvp, *next;
9492        struct var *vp;
9493
9494        INT_OFF;
9495        ll = localvar_stack;
9496        localvar_stack = ll->next;
9497
9498        next = ll->lv;
9499        free(ll);
9500
9501        while ((lvp = next) != NULL) {
9502                next = lvp->next;
9503                vp = lvp->vp;
9504                TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9505                if (keep) {
9506                        int bits = VSTRFIXED;
9507
9508                        if (lvp->flags != VUNSET) {
9509                                if (vp->var_text == lvp->text)
9510                                        bits |= VTEXTFIXED;
9511                                else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9512                                        free((char*)lvp->text);
9513                        }
9514
9515                        vp->flags &= ~bits;
9516                        vp->flags |= (lvp->flags & bits);
9517
9518                        if ((vp->flags &
9519                             (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9520                                unsetvar(vp->var_text);
9521                } else if (vp == NULL) {        /* $- saved */
9522                        memcpy(optlist, lvp->text, sizeof(optlist));
9523                        free((char*)lvp->text);
9524                        optschanged();
9525                } else if (lvp->flags == VUNSET) {
9526                        vp->flags &= ~(VSTRFIXED|VREADONLY);
9527                        unsetvar(vp->var_text);
9528                } else {
9529                        if (vp->var_func)
9530                                vp->var_func(var_end(lvp->text));
9531                        if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9532                                free((char*)vp->var_text);
9533                        vp->flags = lvp->flags;
9534                        vp->var_text = lvp->text;
9535                }
9536                free(lvp);
9537        }
9538        INT_ON;
9539}
9540
9541/*
9542 * Create a new localvar environment.
9543 */
9544static struct localvar_list *
9545pushlocalvars(void)
9546{
9547        struct localvar_list *ll;
9548
9549        INT_OFF;
9550        ll = ckzalloc(sizeof(*ll));
9551        /*ll->lv = NULL; - zalloc did it */
9552        ll->next = localvar_stack;
9553        localvar_stack = ll;
9554        INT_ON;
9555
9556        return ll->next;
9557}
9558
9559static void
9560unwindlocalvars(struct localvar_list *stop)
9561{
9562        while (localvar_stack != stop)
9563                poplocalvars(0);
9564}
9565
9566static int
9567evalfun(struct funcnode *func, int argc, char **argv, int flags)
9568{
9569        volatile struct shparam saveparam;
9570        struct jmploc *volatile savehandler;
9571        struct jmploc jmploc;
9572        int e;
9573        int savefuncline;
9574
9575        saveparam = shellparam;
9576        savefuncline = funcline;
9577        savehandler = exception_handler;
9578        e = setjmp(jmploc.loc);
9579        if (e) {
9580                goto funcdone;
9581        }
9582        INT_OFF;
9583        exception_handler = &jmploc;
9584        shellparam.malloced = 0;
9585        func->count++;
9586        funcline = func->n.ndefun.linno;
9587        INT_ON;
9588        shellparam.nparam = argc - 1;
9589        shellparam.p = argv + 1;
9590#if ENABLE_ASH_GETOPTS
9591        shellparam.optind = 1;
9592        shellparam.optoff = -1;
9593#endif
9594        pushlocalvars();
9595        evaltree(func->n.ndefun.body, flags & EV_TESTED);
9596        poplocalvars(0);
9597 funcdone:
9598        INT_OFF;
9599        funcline = savefuncline;
9600        freefunc(func);
9601        freeparam(&shellparam);
9602        shellparam = saveparam;
9603        exception_handler = savehandler;
9604        INT_ON;
9605        evalskip &= ~SKIPFUNC;
9606        return e;
9607}
9608
9609/*
9610 * Make a variable a local variable.  When a variable is made local, it's
9611 * value and flags are saved in a localvar structure.  The saved values
9612 * will be restored when the shell function returns.  We handle the name
9613 * "-" as a special case: it makes changes to "set +-options" local
9614 * (options will be restored on return from the function).
9615 */
9616static void
9617mklocal(char *name)
9618{
9619        struct localvar *lvp;
9620        struct var **vpp;
9621        struct var *vp;
9622        char *eq = strchr(name, '=');
9623
9624        INT_OFF;
9625        /* Cater for duplicate "local". Examples:
9626         * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9627         * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9628         */
9629        lvp = localvar_stack->lv;
9630        while (lvp) {
9631                if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9632                        if (eq)
9633                                setvareq(name, 0);
9634                        /* else:
9635                         * it's a duplicate "local VAR" declaration, do nothing
9636                         */
9637                        goto ret;
9638                }
9639                lvp = lvp->next;
9640        }
9641
9642        lvp = ckzalloc(sizeof(*lvp));
9643        if (LONE_DASH(name)) {
9644                char *p;
9645                p = ckmalloc(sizeof(optlist));
9646                lvp->text = memcpy(p, optlist, sizeof(optlist));
9647                vp = NULL;
9648        } else {
9649                vpp = hashvar(name);
9650                vp = *findvar(vpp, name);
9651                if (vp == NULL) {
9652                        /* variable did not exist yet */
9653                        if (eq)
9654                                vp = setvareq(name, VSTRFIXED);
9655                        else
9656                                vp = setvar(name, NULL, VSTRFIXED);
9657                        lvp->flags = VUNSET;
9658                } else {
9659                        lvp->text = vp->var_text;
9660                        lvp->flags = vp->flags;
9661                        /* make sure neither "struct var" nor string gets freed
9662                         * during (un)setting:
9663                         */
9664                        vp->flags |= VSTRFIXED|VTEXTFIXED;
9665                        if (eq)
9666                                setvareq(name, 0);
9667                        else
9668                                /* "local VAR" unsets VAR: */
9669                                setvar0(name, NULL);
9670                }
9671        }
9672        lvp->vp = vp;
9673        lvp->next = localvar_stack->lv;
9674        localvar_stack->lv = lvp;
9675 ret:
9676        INT_ON;
9677}
9678
9679/*
9680 * The "local" command.
9681 */
9682static int FAST_FUNC
9683localcmd(int argc UNUSED_PARAM, char **argv)
9684{
9685        char *name;
9686
9687        if (!localvar_stack)
9688                ash_msg_and_raise_error("not in a function");
9689
9690        argv = argptr;
9691        while ((name = *argv++) != NULL) {
9692                mklocal(name);
9693        }
9694        return 0;
9695}
9696
9697static int FAST_FUNC
9698falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9699{
9700        return 1;
9701}
9702
9703static int FAST_FUNC
9704truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9705{
9706        return 0;
9707}
9708
9709static int FAST_FUNC
9710execcmd(int argc UNUSED_PARAM, char **argv)
9711{
9712        optionarg = NULL;
9713        while (nextopt("a:") != '\0')
9714                /* nextopt() sets optionarg to "-a ARGV0" */;
9715
9716        argv = argptr;
9717        if (argv[0]) {
9718                char *prog;
9719
9720                iflag = 0;              /* exit on error */
9721                mflag = 0;
9722                optschanged();
9723                /* We should set up signals for "exec CMD"
9724                 * the same way as for "CMD" without "exec".
9725                 * But optschanged->setinteractive->setsignal
9726                 * still thought we are a root shell. Therefore, for example,
9727                 * SIGQUIT is still set to IGN. Fix it:
9728                 */
9729                shlvl++;
9730                setsignal(SIGQUIT);
9731                /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9732                /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9733                /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9734
9735                prog = argv[0];
9736                if (optionarg)
9737                        argv[0] = optionarg;
9738                shellexec(prog, argv, pathval(), 0);
9739                /* NOTREACHED */
9740        }
9741        return 0;
9742}
9743
9744/*
9745 * The return command.
9746 */
9747static int FAST_FUNC
9748returncmd(int argc UNUSED_PARAM, char **argv)
9749{
9750        /*
9751         * If called outside a function, do what ksh does;
9752         * skip the rest of the file.
9753         */
9754        evalskip = SKIPFUNC;
9755        return argv[1] ? number(argv[1]) : exitstatus;
9756}
9757
9758/* Forward declarations for builtintab[] */
9759static int breakcmd(int, char **) FAST_FUNC;
9760static int dotcmd(int, char **) FAST_FUNC;
9761static int evalcmd(int, char **, int) FAST_FUNC;
9762static int exitcmd(int, char **) FAST_FUNC;
9763static int exportcmd(int, char **) FAST_FUNC;
9764#if ENABLE_ASH_GETOPTS
9765static int getoptscmd(int, char **) FAST_FUNC;
9766#endif
9767#if ENABLE_ASH_HELP
9768static int helpcmd(int, char **) FAST_FUNC;
9769#endif
9770#if MAX_HISTORY
9771static int historycmd(int, char **) FAST_FUNC;
9772#endif
9773#if ENABLE_FEATURE_SH_MATH
9774static int letcmd(int, char **) FAST_FUNC;
9775#endif
9776static int readcmd(int, char **) FAST_FUNC;
9777static int setcmd(int, char **) FAST_FUNC;
9778static int shiftcmd(int, char **) FAST_FUNC;
9779static int timescmd(int, char **) FAST_FUNC;
9780static int trapcmd(int, char **) FAST_FUNC;
9781static int umaskcmd(int, char **) FAST_FUNC;
9782static int unsetcmd(int, char **) FAST_FUNC;
9783static int ulimitcmd(int, char **) FAST_FUNC;
9784
9785#define BUILTIN_NOSPEC          "0"
9786#define BUILTIN_SPECIAL         "1"
9787#define BUILTIN_REGULAR         "2"
9788#define BUILTIN_SPEC_REG        "3"
9789#define BUILTIN_ASSIGN          "4"
9790#define BUILTIN_SPEC_ASSG       "5"
9791#define BUILTIN_REG_ASSG        "6"
9792#define BUILTIN_SPEC_REG_ASSG   "7"
9793
9794/* Stubs for calling non-FAST_FUNC's */
9795#if ENABLE_ASH_ECHO
9796static int FAST_FUNC echocmd(int argc, char **argv)   { return echo_main(argc, argv); }
9797#endif
9798#if ENABLE_ASH_PRINTF
9799static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
9800#endif
9801#if ENABLE_ASH_TEST || BASH_TEST2
9802static int FAST_FUNC testcmd(int argc, char **argv)   { return test_main(argc, argv); }
9803#endif
9804
9805/* Keep these in proper order since it is searched via bsearch() */
9806static const struct builtincmd builtintab[] = {
9807        { BUILTIN_SPEC_REG      "."       , dotcmd     },
9808        { BUILTIN_SPEC_REG      ":"       , truecmd    },
9809#if ENABLE_ASH_TEST
9810        { BUILTIN_REGULAR       "["       , testcmd    },
9811#endif
9812#if BASH_TEST2
9813        { BUILTIN_REGULAR       "[["      , testcmd    },
9814#endif
9815#if ENABLE_ASH_ALIAS
9816        { BUILTIN_REG_ASSG      "alias"   , aliascmd   },
9817#endif
9818#if JOBS
9819        { BUILTIN_REGULAR       "bg"      , fg_bgcmd   },
9820#endif
9821        { BUILTIN_SPEC_REG      "break"   , breakcmd   },
9822        { BUILTIN_REGULAR       "cd"      , cdcmd      },
9823        { BUILTIN_NOSPEC        "chdir"   , cdcmd      },
9824#if ENABLE_ASH_CMDCMD
9825        { BUILTIN_REGULAR       "command" , commandcmd },
9826#endif
9827        { BUILTIN_SPEC_REG      "continue", breakcmd   },
9828#if ENABLE_ASH_ECHO
9829        { BUILTIN_REGULAR       "echo"    , echocmd    },
9830#endif
9831        { BUILTIN_SPEC_REG      "eval"    , NULL       }, /*evalcmd() has a differing prototype*/
9832        { BUILTIN_SPEC_REG      "exec"    , execcmd    },
9833        { BUILTIN_SPEC_REG      "exit"    , exitcmd    },
9834        { BUILTIN_SPEC_REG_ASSG "export"  , exportcmd  },
9835        { BUILTIN_REGULAR       "false"   , falsecmd   },
9836#if JOBS
9837        { BUILTIN_REGULAR       "fg"      , fg_bgcmd   },
9838#endif
9839#if ENABLE_ASH_GETOPTS
9840        { BUILTIN_REGULAR       "getopts" , getoptscmd },
9841#endif
9842        { BUILTIN_NOSPEC        "hash"    , hashcmd    },
9843#if ENABLE_ASH_HELP
9844        { BUILTIN_NOSPEC        "help"    , helpcmd    },
9845#endif
9846#if MAX_HISTORY
9847        { BUILTIN_NOSPEC        "history" , historycmd },
9848#endif
9849#if JOBS
9850        { BUILTIN_REGULAR       "jobs"    , jobscmd    },
9851        { BUILTIN_REGULAR       "kill"    , killcmd    },
9852#endif
9853#if ENABLE_FEATURE_SH_MATH
9854        { BUILTIN_NOSPEC        "let"     , letcmd     },
9855#endif
9856        { BUILTIN_SPEC_REG_ASSG "local"   , localcmd   },
9857#if ENABLE_ASH_PRINTF
9858        { BUILTIN_REGULAR       "printf"  , printfcmd  },
9859#endif
9860        { BUILTIN_NOSPEC        "pwd"     , pwdcmd     },
9861        { BUILTIN_REGULAR       "read"    , readcmd    },
9862        { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd  },
9863        { BUILTIN_SPEC_REG      "return"  , returncmd  },
9864        { BUILTIN_SPEC_REG      "set"     , setcmd     },
9865        { BUILTIN_SPEC_REG      "shift"   , shiftcmd   },
9866#if BASH_SOURCE
9867        { BUILTIN_SPEC_REG      "source"  , dotcmd     },
9868#endif
9869#if ENABLE_ASH_TEST
9870        { BUILTIN_REGULAR       "test"    , testcmd    },
9871#endif
9872        { BUILTIN_SPEC_REG      "times"   , timescmd   },
9873        { BUILTIN_SPEC_REG      "trap"    , trapcmd    },
9874        { BUILTIN_REGULAR       "true"    , truecmd    },
9875        { BUILTIN_NOSPEC        "type"    , typecmd    },
9876        { BUILTIN_NOSPEC        "ulimit"  , ulimitcmd  },
9877        { BUILTIN_REGULAR       "umask"   , umaskcmd   },
9878#if ENABLE_ASH_ALIAS
9879        { BUILTIN_REGULAR       "unalias" , unaliascmd },
9880#endif
9881        { BUILTIN_SPEC_REG      "unset"   , unsetcmd   },
9882        { BUILTIN_REGULAR       "wait"    , waitcmd    },
9883};
9884
9885/* Should match the above table! */
9886#define COMMANDCMD (builtintab + \
9887        /* . : */       2 + \
9888        /* [ */         1 * ENABLE_ASH_TEST + \
9889        /* [[ */        1 * BASH_TEST2 + \
9890        /* alias */     1 * ENABLE_ASH_ALIAS + \
9891        /* bg */        1 * ENABLE_ASH_JOB_CONTROL + \
9892        /* break cd cddir  */   3)
9893#define EVALCMD (COMMANDCMD + \
9894        /* command */   1 * ENABLE_ASH_CMDCMD + \
9895        /* continue */  1 + \
9896        /* echo */      1 * ENABLE_ASH_ECHO + \
9897        0)
9898#define EXECCMD (EVALCMD + \
9899        /* eval */      1)
9900
9901/*
9902 * Search the table of builtin commands.
9903 */
9904static int
9905pstrcmp1(const void *a, const void *b)
9906{
9907        return strcmp((char*)a, *(char**)b + 1);
9908}
9909static struct builtincmd *
9910find_builtin(const char *name)
9911{
9912        struct builtincmd *bp;
9913
9914        bp = bsearch(
9915                name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9916                pstrcmp1
9917        );
9918        return bp;
9919}
9920
9921/*
9922 * Execute a simple command.
9923 */
9924static int
9925isassignment(const char *p)
9926{
9927        const char *q = endofname(p);
9928        if (p == q)
9929                return 0;
9930        return *q == '=';
9931}
9932static int FAST_FUNC
9933bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9934{
9935        /* Preserve exitstatus of a previous possible redirection
9936         * as POSIX mandates */
9937        return back_exitstatus;
9938}
9939static int
9940evalcommand(union node *cmd, int flags)
9941{
9942        static const struct builtincmd null_bltin = {
9943                "\0\0", bltincmd /* why three NULs? */
9944        };
9945        struct localvar_list *localvar_stop;
9946        struct redirtab *redir_stop;
9947        struct stackmark smark;
9948        union node *argp;
9949        struct arglist arglist;
9950        struct arglist varlist;
9951        char **argv;
9952        int argc;
9953        const struct strlist *sp;
9954        struct cmdentry cmdentry;
9955        struct job *jp;
9956        char *lastarg;
9957        const char *path;
9958        int spclbltin;
9959        int status;
9960        char **nargv;
9961        smallint cmd_is_exec;
9962
9963        errlinno = lineno = cmd->ncmd.linno;
9964        if (funcline)
9965                lineno -= funcline - 1;
9966
9967        /* First expand the arguments. */
9968        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9969        setstackmark(&smark);
9970        localvar_stop = pushlocalvars();
9971        back_exitstatus = 0;
9972
9973        cmdentry.cmdtype = CMDBUILTIN;
9974        cmdentry.u.cmd = &null_bltin;
9975        varlist.lastp = &varlist.list;
9976        *varlist.lastp = NULL;
9977        arglist.lastp = &arglist.list;
9978        *arglist.lastp = NULL;
9979
9980        argc = 0;
9981        if (cmd->ncmd.args) {
9982                struct builtincmd *bcmd;
9983                smallint pseudovarflag;
9984
9985                bcmd = find_builtin(cmd->ncmd.args->narg.text);
9986                pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9987
9988                for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9989                        struct strlist **spp;
9990
9991                        spp = arglist.lastp;
9992                        if (pseudovarflag && isassignment(argp->narg.text))
9993                                expandarg(argp, &arglist, EXP_VARTILDE);
9994                        else
9995                                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9996
9997                        for (sp = *spp; sp; sp = sp->next)
9998                                argc++;
9999                }
10000        }
10001
10002        /* Reserve one extra spot at the front for shellexec. */
10003        nargv = stalloc(sizeof(char *) * (argc + 2));
10004        argv = ++nargv;
10005        for (sp = arglist.list; sp; sp = sp->next) {
10006                TRACE(("evalcommand arg: %s\n", sp->text));
10007                *nargv++ = sp->text;
10008        }
10009        *nargv = NULL;
10010
10011        lastarg = NULL;
10012        if (iflag && funcline == 0 && argc > 0)
10013                lastarg = nargv[-1];
10014
10015        expredir(cmd->ncmd.redirect);
10016        redir_stop = pushredir(cmd->ncmd.redirect);
10017        preverrout_fd = 2;
10018        if (BASH_XTRACEFD && xflag) {
10019                /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10020                 * we do not emulate this. We only use its value.
10021                 */
10022                const char *xtracefd = lookupvar("BASH_XTRACEFD");
10023                if (xtracefd && is_number(xtracefd))
10024                        preverrout_fd = atoi(xtracefd);
10025
10026        }
10027        status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10028
10029        path = vpath.var_text;
10030        for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10031                struct strlist **spp;
10032                char *p;
10033
10034                spp = varlist.lastp;
10035                expandarg(argp, &varlist, EXP_VARTILDE);
10036
10037                mklocal((*spp)->text);
10038
10039                /*
10040                 * Modify the command lookup path, if a PATH= assignment
10041                 * is present
10042                 */
10043                p = (*spp)->text;
10044                if (varcmp(p, path) == 0)
10045                        path = p;
10046        }
10047
10048        /* Print the command if xflag is set. */
10049        if (xflag) {
10050                const char *pfx = "";
10051
10052                fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
10053
10054                sp = varlist.list;
10055                while (sp) {
10056                        char *varval = sp->text;
10057                        char *eq = strchrnul(varval, '=');
10058                        if (*eq)
10059                                eq++;
10060                        fdprintf(preverrout_fd, "%s%.*s%s",
10061                                pfx,
10062                                (int)(eq - varval), varval,
10063                                maybe_single_quote(eq)
10064                        );
10065                        sp = sp->next;
10066                        pfx = " ";
10067                }
10068
10069                sp = arglist.list;
10070                while (sp) {
10071                        fdprintf(preverrout_fd, "%s%s",
10072                                pfx,
10073                                /* always quote if matches reserved word: */
10074                                findkwd(sp->text)
10075                                ? single_quote(sp->text)
10076                                : maybe_single_quote(sp->text)
10077                        );
10078                        sp = sp->next;
10079                        pfx = " ";
10080                }
10081                safe_write(preverrout_fd, "\n", 1);
10082        }
10083
10084        cmd_is_exec = 0;
10085        spclbltin = -1;
10086
10087        /* Now locate the command. */
10088        if (argc) {
10089                int cmd_flag = DO_ERR;
10090#if ENABLE_ASH_CMDCMD
10091                const char *oldpath = path + 5;
10092#endif
10093                path += 5;
10094                for (;;) {
10095                        find_command(argv[0], &cmdentry, cmd_flag, path);
10096                        if (cmdentry.cmdtype == CMDUNKNOWN) {
10097                                flush_stdout_stderr();
10098                                status = 127;
10099                                goto bail;
10100                        }
10101
10102                        /* implement bltin and command here */
10103                        if (cmdentry.cmdtype != CMDBUILTIN)
10104                                break;
10105                        if (spclbltin < 0)
10106                                spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10107                        if (cmdentry.u.cmd == EXECCMD)
10108                                cmd_is_exec = 1;
10109#if ENABLE_ASH_CMDCMD
10110                        if (cmdentry.u.cmd == COMMANDCMD) {
10111                                path = oldpath;
10112                                nargv = parse_command_args(argv, &path);
10113                                if (!nargv)
10114                                        break;
10115                                /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10116                                 * nargv => "PROG". path is updated if -p.
10117                                 */
10118                                argc -= nargv - argv;
10119                                argv = nargv;
10120                                cmd_flag |= DO_NOFUNC;
10121                        } else
10122#endif
10123                                break;
10124                }
10125        }
10126
10127        if (status) {
10128 bail:
10129                exitstatus = status;
10130
10131                /* We have a redirection error. */
10132                if (spclbltin > 0)
10133                        raise_exception(EXERROR);
10134
10135                goto out;
10136        }
10137
10138        /* Execute the command. */
10139        switch (cmdentry.cmdtype) {
10140        default: {
10141
10142#if ENABLE_FEATURE_SH_STANDALONE \
10143 && ENABLE_FEATURE_SH_NOFORK \
10144 && NUM_APPLETS > 1
10145/* (1) BUG: if variables are set, we need to fork, or save/restore them
10146 *     around run_nofork_applet() call.
10147 * (2) Should this check also be done in forkshell()?
10148 *     (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10149 */
10150                /* find_command() encodes applet_no as (-2 - applet_no) */
10151                int applet_no = (- cmdentry.u.index - 2);
10152                if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10153                        char **sv_environ;
10154
10155                        INT_OFF;
10156                        sv_environ = environ;
10157                        environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
10158                        /*
10159                         * Run <applet>_main().
10160                         * Signals (^C) can't interrupt here.
10161                         * Otherwise we can mangle stdio or malloc internal state.
10162                         * This makes applets which can run for a long time
10163                         * and/or wait for user input ineligible for NOFORK:
10164                         * for example, "yes" or "rm" (rm -i waits for input).
10165                         */
10166                        status = run_nofork_applet(applet_no, argv);
10167                        environ = sv_environ;
10168                        /*
10169                         * Try enabling NOFORK for "yes" applet.
10170                         * ^C _will_ stop it (write returns EINTR),
10171                         * but this causes stdout FILE to be stuck
10172                         * and needing clearerr(). What if other applets
10173                         * also can get EINTRs? Do we need to switch
10174                         * our signals to SA_RESTART?
10175                         */
10176                        /*clearerr(stdout);*/
10177                        INT_ON;
10178                        break;
10179                }
10180#endif
10181                /* Can we avoid forking? For example, very last command
10182                 * in a script or a subshell does not need forking,
10183                 * we can just exec it.
10184                 */
10185                if (!(flags & EV_EXIT) || may_have_traps) {
10186                        /* No, forking off a child is necessary */
10187                        INT_OFF;
10188                        get_tty_state();
10189                        jp = makejob(/*cmd,*/ 1);
10190                        if (forkshell(jp, cmd, FORK_FG) != 0) {
10191                                /* parent */
10192                                status = waitforjob(jp);
10193                                INT_ON;
10194                                TRACE(("forked child exited with %d\n", status));
10195                                break;
10196                        }
10197                        /* child */
10198                        FORCE_INT_ON;
10199                        /* fall through to exec'ing external program */
10200                }
10201                listsetvar(varlist.list, VEXPORT|VSTACK);
10202                shellexec(argv[0], argv, path, cmdentry.u.index);
10203                /* NOTREACHED */
10204        } /* default */
10205        case CMDBUILTIN:
10206                if (spclbltin > 0 || argc == 0) {
10207                        poplocalvars(1);
10208                        if (cmd_is_exec && argc > 1)
10209                                listsetvar(varlist.list, VEXPORT);
10210                }
10211
10212                /* Tight loop with builtins only:
10213                 * "while kill -0 $child; do true; done"
10214                 * will never exit even if $child died, unless we do this
10215                 * to reap the zombie and make kill detect that it's gone: */
10216                dowait(DOWAIT_NONBLOCK, NULL);
10217
10218                if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
10219                        if (exception_type == EXERROR && spclbltin <= 0) {
10220                                FORCE_INT_ON;
10221                                goto readstatus;
10222                        }
10223 raise:
10224                        longjmp(exception_handler->loc, 1);
10225                }
10226                goto readstatus;
10227
10228        case CMDFUNCTION:
10229                poplocalvars(1);
10230                /* See above for the rationale */
10231                dowait(DOWAIT_NONBLOCK, NULL);
10232                if (evalfun(cmdentry.u.func, argc, argv, flags))
10233                        goto raise;
10234 readstatus:
10235                status = exitstatus;
10236                break;
10237        } /* switch */
10238
10239 out:
10240        if (cmd->ncmd.redirect)
10241                popredir(/*drop:*/ cmd_is_exec);
10242        unwindredir(redir_stop);
10243        unwindlocalvars(localvar_stop);
10244        if (lastarg) {
10245                /* dsl: I think this is intended to be used to support
10246                 * '_' in 'vi' command mode during line editing...
10247                 * However I implemented that within libedit itself.
10248                 */
10249                setvar0("_", lastarg);
10250        }
10251        popstackmark(&smark);
10252
10253        return status;
10254}
10255
10256static int
10257evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
10258{
10259        char *volatile savecmdname;
10260        struct jmploc *volatile savehandler;
10261        struct jmploc jmploc;
10262        int status;
10263        int i;
10264
10265        savecmdname = commandname;
10266        savehandler = exception_handler;
10267        i = setjmp(jmploc.loc);
10268        if (i)
10269                goto cmddone;
10270        exception_handler = &jmploc;
10271        commandname = argv[0];
10272        argptr = argv + 1;
10273        optptr = NULL;                  /* initialize nextopt */
10274        if (cmd == EVALCMD)
10275                status = evalcmd(argc, argv, flags);
10276        else
10277                status = (*cmd->builtin)(argc, argv);
10278        flush_stdout_stderr();
10279        status |= ferror(stdout);
10280        exitstatus = status;
10281 cmddone:
10282        clearerr(stdout);
10283        commandname = savecmdname;
10284        exception_handler = savehandler;
10285
10286        return i;
10287}
10288
10289static int
10290goodname(const char *p)
10291{
10292        return endofname(p)[0] == '\0';
10293}
10294
10295
10296/*
10297 * Search for a command.  This is called before we fork so that the
10298 * location of the command will be available in the parent as well as
10299 * the child.  The check for "goodname" is an overly conservative
10300 * check that the name will not be subject to expansion.
10301 */
10302static void
10303prehash(union node *n)
10304{
10305        struct cmdentry entry;
10306
10307        if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10308                find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
10309}
10310
10311
10312/* ============ Builtin commands
10313 *
10314 * Builtin commands whose functions are closely tied to evaluation
10315 * are implemented here.
10316 */
10317
10318/*
10319 * Handle break and continue commands.  Break, continue, and return are
10320 * all handled by setting the evalskip flag.  The evaluation routines
10321 * above all check this flag, and if it is set they start skipping
10322 * commands rather than executing them.  The variable skipcount is
10323 * the number of loops to break/continue, or the number of function
10324 * levels to return.  (The latter is always 1.)  It should probably
10325 * be an error to break out of more loops than exist, but it isn't
10326 * in the standard shell so we don't make it one here.
10327 */
10328static int FAST_FUNC
10329breakcmd(int argc UNUSED_PARAM, char **argv)
10330{
10331        int n = argv[1] ? number(argv[1]) : 1;
10332
10333        if (n <= 0)
10334                ash_msg_and_raise_error(msg_illnum, argv[1]);
10335        if (n > loopnest)
10336                n = loopnest;
10337        if (n > 0) {
10338                evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
10339                skipcount = n;
10340        }
10341        return 0;
10342}
10343
10344
10345/*
10346 * This implements the input routines used by the parser.
10347 */
10348
10349enum {
10350        INPUT_PUSH_FILE = 1,
10351        INPUT_NOFILE_OK = 2,
10352};
10353
10354static smallint checkkwd;
10355/* values of checkkwd variable */
10356#define CHKALIAS        0x1
10357#define CHKKWD          0x2
10358#define CHKNL           0x4
10359#define CHKEOFMARK      0x8
10360
10361/*
10362 * Push a string back onto the input at this current parsefile level.
10363 * We handle aliases this way.
10364 */
10365#if !ENABLE_ASH_ALIAS
10366#define pushstring(s, ap) pushstring(s)
10367#endif
10368static void
10369pushstring(char *s, struct alias *ap)
10370{
10371        struct strpush *sp;
10372        int len;
10373
10374        len = strlen(s);
10375        INT_OFF;
10376        if (g_parsefile->strpush) {
10377                sp = ckzalloc(sizeof(*sp));
10378                sp->prev = g_parsefile->strpush;
10379        } else {
10380                sp = &(g_parsefile->basestrpush);
10381        }
10382        g_parsefile->strpush = sp;
10383        sp->prev_string = g_parsefile->next_to_pgetc;
10384        sp->prev_left_in_line = g_parsefile->left_in_line;
10385        sp->unget = g_parsefile->unget;
10386        memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
10387#if ENABLE_ASH_ALIAS
10388        sp->ap = ap;
10389        if (ap) {
10390                ap->flag |= ALIASINUSE;
10391                sp->string = s;
10392        }
10393#endif
10394        g_parsefile->next_to_pgetc = s;
10395        g_parsefile->left_in_line = len;
10396        g_parsefile->unget = 0;
10397        INT_ON;
10398}
10399
10400static void
10401popstring(void)
10402{
10403        struct strpush *sp = g_parsefile->strpush;
10404
10405        INT_OFF;
10406#if ENABLE_ASH_ALIAS
10407        if (sp->ap) {
10408                if (g_parsefile->next_to_pgetc[-1] == ' '
10409                 || g_parsefile->next_to_pgetc[-1] == '\t'
10410                ) {
10411                        checkkwd |= CHKALIAS;
10412                }
10413                if (sp->string != sp->ap->val) {
10414                        free(sp->string);
10415                }
10416                sp->ap->flag &= ~ALIASINUSE;
10417                if (sp->ap->flag & ALIASDEAD) {
10418                        unalias(sp->ap->name);
10419                }
10420        }
10421#endif
10422        g_parsefile->next_to_pgetc = sp->prev_string;
10423        g_parsefile->left_in_line = sp->prev_left_in_line;
10424        g_parsefile->unget = sp->unget;
10425        memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
10426        g_parsefile->strpush = sp->prev;
10427        if (sp != &(g_parsefile->basestrpush))
10428                free(sp);
10429        INT_ON;
10430}
10431
10432static int
10433preadfd(void)
10434{
10435        int nr;
10436        char *buf = g_parsefile->buf;
10437
10438        g_parsefile->next_to_pgetc = buf;
10439#if ENABLE_FEATURE_EDITING
10440 retry:
10441        if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10442                nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10443        else {
10444# if ENABLE_ASH_IDLE_TIMEOUT
10445                int timeout = -1;
10446                if (iflag) {
10447                        const char *tmout_var = lookupvar("TMOUT");
10448                        if (tmout_var) {
10449                                timeout = atoi(tmout_var) * 1000;
10450                                if (timeout <= 0)
10451                                        timeout = -1;
10452                        }
10453                }
10454                line_input_state->timeout = timeout;
10455# endif
10456# if ENABLE_FEATURE_TAB_COMPLETION
10457                line_input_state->path_lookup = pathval();
10458# endif
10459                reinit_unicode_for_ash();
10460                nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10461                if (nr == 0) {
10462                        /* ^C pressed, "convert" to SIGINT */
10463                        write(STDOUT_FILENO, "^C", 2);
10464                        if (trap[SIGINT]) {
10465                                buf[0] = '\n';
10466                                buf[1] = '\0';
10467                                raise(SIGINT);
10468                                return 1;
10469                        }
10470                        exitstatus = 128 + SIGINT;
10471                        bb_putchar('\n');
10472                        goto retry;
10473                }
10474                if (nr < 0) {
10475                        if (errno == 0) {
10476                                /* Ctrl+D pressed */
10477                                nr = 0;
10478                        }
10479# if ENABLE_ASH_IDLE_TIMEOUT
10480                        else if (errno == EAGAIN && timeout > 0) {
10481                                puts("\007timed out waiting for input: auto-logout");
10482                                exitshell();
10483                        }
10484# endif
10485                }
10486        }
10487#else
10488        nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10489#endif
10490
10491#if 0 /* disabled: nonblock_immune_read() handles this problem */
10492        if (nr < 0) {
10493                if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10494                        int flags = fcntl(0, F_GETFL);
10495                        if (flags >= 0 && (flags & O_NONBLOCK)) {
10496                                flags &= ~O_NONBLOCK;
10497                                if (fcntl(0, F_SETFL, flags) >= 0) {
10498                                        out2str("sh: turning off NDELAY mode\n");
10499                                        goto retry;
10500                                }
10501                        }
10502                }
10503        }
10504#endif
10505        return nr;
10506}
10507
10508/*
10509 * Refill the input buffer and return the next input character:
10510 *
10511 * 1) If a string was pushed back on the input, pop it;
10512 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10513 *    or we are reading from a string so we can't refill the buffer,
10514 *    return EOF.
10515 * 3) If there is more stuff in this buffer, use it else call read to fill it.
10516 * 4) Process input up to the next newline, deleting nul characters.
10517 */
10518//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10519#define pgetc_debug(...) ((void)0)
10520static int pgetc(void);
10521static int
10522preadbuffer(void)
10523{
10524        char *q;
10525        int more;
10526
10527        if (g_parsefile->strpush) {
10528#if ENABLE_ASH_ALIAS
10529                if (g_parsefile->left_in_line == -1
10530                 && g_parsefile->strpush->ap
10531                 && g_parsefile->next_to_pgetc[-1] != ' '
10532                 && g_parsefile->next_to_pgetc[-1] != '\t'
10533                ) {
10534                        pgetc_debug("preadbuffer PEOA");
10535                        return PEOA;
10536                }
10537#endif
10538                popstring();
10539                return pgetc();
10540        }
10541        /* on both branches above g_parsefile->left_in_line < 0.
10542         * "pgetc" needs refilling.
10543         */
10544
10545        /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
10546         * pungetc() may increment it a few times.
10547         * Assuming it won't increment it to less than -90.
10548         */
10549        if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
10550                pgetc_debug("preadbuffer PEOF1");
10551                /* even in failure keep left_in_line and next_to_pgetc
10552                 * in lock step, for correct multi-layer pungetc.
10553                 * left_in_line was decremented before preadbuffer(),
10554                 * must inc next_to_pgetc: */
10555                g_parsefile->next_to_pgetc++;
10556                return PEOF;
10557        }
10558
10559        more = g_parsefile->left_in_buffer;
10560        if (more <= 0) {
10561                flush_stdout_stderr();
10562 again:
10563                more = preadfd();
10564                if (more <= 0) {
10565                        /* don't try reading again */
10566                        g_parsefile->left_in_line = -99;
10567                        pgetc_debug("preadbuffer PEOF2");
10568                        g_parsefile->next_to_pgetc++;
10569                        return PEOF;
10570                }
10571        }
10572
10573        /* Find out where's the end of line.
10574         * Set g_parsefile->left_in_line
10575         * and g_parsefile->left_in_buffer acordingly.
10576         * NUL chars are deleted.
10577         */
10578        q = g_parsefile->next_to_pgetc;
10579        for (;;) {
10580                char c;
10581
10582                more--;
10583
10584                c = *q;
10585                if (c == '\0') {
10586                        memmove(q, q + 1, more);
10587                } else {
10588                        q++;
10589                        if (c == '\n') {
10590                                g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10591                                break;
10592                        }
10593                }
10594
10595                if (more <= 0) {
10596                        g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10597                        if (g_parsefile->left_in_line < 0)
10598                                goto again;
10599                        break;
10600                }
10601        }
10602        g_parsefile->left_in_buffer = more;
10603
10604        if (vflag) {
10605                char save = *q;
10606                *q = '\0';
10607                out2str(g_parsefile->next_to_pgetc);
10608                *q = save;
10609        }
10610
10611        pgetc_debug("preadbuffer at %d:%p'%s'",
10612                        g_parsefile->left_in_line,
10613                        g_parsefile->next_to_pgetc,
10614                        g_parsefile->next_to_pgetc);
10615        return (unsigned char)*g_parsefile->next_to_pgetc++;
10616}
10617
10618static void
10619nlprompt(void)
10620{
10621        g_parsefile->linno++;
10622        setprompt_if(doprompt, 2);
10623}
10624static void
10625nlnoprompt(void)
10626{
10627        g_parsefile->linno++;
10628        needprompt = doprompt;
10629}
10630
10631static int
10632pgetc(void)
10633{
10634        int c;
10635
10636        pgetc_debug("pgetc at %d:%p'%s'",
10637                        g_parsefile->left_in_line,
10638                        g_parsefile->next_to_pgetc,
10639                        g_parsefile->next_to_pgetc);
10640        if (g_parsefile->unget)
10641                return g_parsefile->lastc[--g_parsefile->unget];
10642
10643        if (--g_parsefile->left_in_line >= 0)
10644                c = (unsigned char)*g_parsefile->next_to_pgetc++;
10645        else
10646                c = preadbuffer();
10647
10648        g_parsefile->lastc[1] = g_parsefile->lastc[0];
10649        g_parsefile->lastc[0] = c;
10650
10651        return c;
10652}
10653
10654#if ENABLE_ASH_ALIAS
10655static int
10656pgetc_without_PEOA(void)
10657{
10658        int c;
10659        do {
10660                pgetc_debug("pgetc at %d:%p'%s'",
10661                                g_parsefile->left_in_line,
10662                                g_parsefile->next_to_pgetc,
10663                                g_parsefile->next_to_pgetc);
10664                c = pgetc();
10665        } while (c == PEOA);
10666        return c;
10667}
10668#else
10669# define pgetc_without_PEOA() pgetc()
10670#endif
10671
10672/*
10673 * Undo a call to pgetc.  Only two characters may be pushed back.
10674 * PEOF may be pushed back.
10675 */
10676static void
10677pungetc(void)
10678{
10679        g_parsefile->unget++;
10680}
10681
10682/* This one eats backslash+newline */
10683static int
10684pgetc_eatbnl(void)
10685{
10686        int c;
10687
10688        while ((c = pgetc()) == '\\') {
10689                if (pgetc() != '\n') {
10690                        pungetc();
10691                        break;
10692                }
10693
10694                nlprompt();
10695        }
10696
10697        return c;
10698}
10699
10700struct synstack {
10701        smalluint syntax;
10702        uint8_t innerdq   :1;
10703        uint8_t varpushed :1;
10704        uint8_t dblquote  :1;
10705        int varnest;            /* levels of variables expansion */
10706        int dqvarnest;          /* levels of variables expansion within double quotes */
10707        int parenlevel;         /* levels of parens in arithmetic */
10708        struct synstack *prev;
10709        struct synstack *next;
10710};
10711
10712static void
10713synstack_push(struct synstack **stack, struct synstack *next, int syntax)
10714{
10715        memset(next, 0, sizeof(*next));
10716        next->syntax = syntax;
10717        next->next = *stack;
10718        (*stack)->prev = next;
10719        *stack = next;
10720}
10721
10722static ALWAYS_INLINE void
10723synstack_pop(struct synstack **stack)
10724{
10725        *stack = (*stack)->next;
10726}
10727
10728/*
10729 * To handle the "." command, a stack of input files is used.  Pushfile
10730 * adds a new entry to the stack and popfile restores the previous level.
10731 */
10732static void
10733pushfile(void)
10734{
10735        struct parsefile *pf;
10736
10737        pf = ckzalloc(sizeof(*pf));
10738        pf->prev = g_parsefile;
10739        pf->pf_fd = -1;
10740        /*pf->strpush = NULL; - ckzalloc did it */
10741        /*pf->basestrpush.prev = NULL;*/
10742        /*pf->unget = 0;*/
10743        g_parsefile = pf;
10744}
10745
10746static void
10747popfile(void)
10748{
10749        struct parsefile *pf = g_parsefile;
10750
10751        if (pf == &basepf)
10752                return;
10753
10754        INT_OFF;
10755        if (pf->pf_fd >= 0)
10756                close(pf->pf_fd);
10757        free(pf->buf);
10758        while (pf->strpush)
10759                popstring();
10760        g_parsefile = pf->prev;
10761        free(pf);
10762        INT_ON;
10763}
10764
10765/*
10766 * Return to top level.
10767 */
10768static void
10769popallfiles(void)
10770{
10771        while (g_parsefile != &basepf)
10772                popfile();
10773}
10774
10775/*
10776 * Close the file(s) that the shell is reading commands from.  Called
10777 * after a fork is done.
10778 */
10779static void
10780closescript(void)
10781{
10782        popallfiles();
10783        if (g_parsefile->pf_fd > 0) {
10784                close(g_parsefile->pf_fd);
10785                g_parsefile->pf_fd = 0;
10786        }
10787}
10788
10789/*
10790 * Like setinputfile, but takes an open file descriptor.  Call this with
10791 * interrupts off.
10792 */
10793static void
10794setinputfd(int fd, int push)
10795{
10796        if (push) {
10797                pushfile();
10798                g_parsefile->buf = NULL;
10799        }
10800        g_parsefile->pf_fd = fd;
10801        if (g_parsefile->buf == NULL)
10802                g_parsefile->buf = ckmalloc(IBUFSIZ);
10803        g_parsefile->left_in_buffer = 0;
10804        g_parsefile->left_in_line = 0;
10805        g_parsefile->linno = 1;
10806}
10807
10808/*
10809 * Set the input to take input from a file.  If push is set, push the
10810 * old input onto the stack first.
10811 */
10812static int
10813setinputfile(const char *fname, int flags)
10814{
10815        int fd;
10816
10817        INT_OFF;
10818        fd = open(fname, O_RDONLY | O_CLOEXEC);
10819        if (fd < 0) {
10820                if (flags & INPUT_NOFILE_OK)
10821                        goto out;
10822                exitstatus = 127;
10823                ash_msg_and_raise_perror("can't open '%s'", fname);
10824        }
10825        if (fd < 10)
10826                fd = savefd(fd);
10827        else if (O_CLOEXEC == 0) /* old libc */
10828                close_on_exec_on(fd);
10829
10830        setinputfd(fd, flags & INPUT_PUSH_FILE);
10831 out:
10832        INT_ON;
10833        return fd;
10834}
10835
10836/*
10837 * Like setinputfile, but takes input from a string.
10838 */
10839static void
10840setinputstring(char *string)
10841{
10842        INT_OFF;
10843        pushfile();
10844        g_parsefile->next_to_pgetc = string;
10845        g_parsefile->left_in_line = strlen(string);
10846        g_parsefile->buf = NULL;
10847        g_parsefile->linno = 1;
10848        INT_ON;
10849}
10850
10851
10852/*
10853 * Routines to check for mail.
10854 */
10855
10856#if ENABLE_ASH_MAIL
10857
10858/* Hash of mtimes of mailboxes */
10859static unsigned mailtime_hash;
10860/* Set if MAIL or MAILPATH is changed. */
10861static smallint mail_var_path_changed;
10862
10863/*
10864 * Print appropriate message(s) if mail has arrived.
10865 * If mail_var_path_changed is set,
10866 * then the value of MAIL has mail_var_path_changed,
10867 * so we just update the values.
10868 */
10869static void
10870chkmail(void)
10871{
10872        const char *mpath;
10873        char *p;
10874        char *q;
10875        unsigned new_hash;
10876        struct stackmark smark;
10877        struct stat statb;
10878
10879        setstackmark(&smark);
10880        mpath = mpathset() ? mpathval() : mailval();
10881        new_hash = 0;
10882        for (;;) {
10883                p = path_advance(&mpath, nullstr);
10884                if (p == NULL)
10885                        break;
10886                if (*p == '\0')
10887                        continue;
10888                for (q = p; *q; q++)
10889                        continue;
10890#if DEBUG
10891                if (q[-1] != '/')
10892                        abort();
10893#endif
10894                q[-1] = '\0';                   /* delete trailing '/' */
10895                if (stat(p, &statb) < 0) {
10896                        continue;
10897                }
10898                /* Very simplistic "hash": just a sum of all mtimes */
10899                new_hash += (unsigned)statb.st_mtime;
10900        }
10901        if (!mail_var_path_changed && mailtime_hash != new_hash) {
10902                if (mailtime_hash != 0)
10903                        out2str("you have mail\n");
10904                mailtime_hash = new_hash;
10905        }
10906        mail_var_path_changed = 0;
10907        popstackmark(&smark);
10908}
10909
10910static void FAST_FUNC
10911changemail(const char *val UNUSED_PARAM)
10912{
10913        mail_var_path_changed = 1;
10914}
10915
10916#endif /* ASH_MAIL */
10917
10918
10919/* ============ ??? */
10920
10921/*
10922 * Set the shell parameters.
10923 */
10924static void
10925setparam(char **argv)
10926{
10927        char **newparam;
10928        char **ap;
10929        int nparam;
10930
10931        for (nparam = 0; argv[nparam]; nparam++)
10932                continue;
10933        ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10934        while (*argv) {
10935                *ap++ = ckstrdup(*argv++);
10936        }
10937        *ap = NULL;
10938        freeparam(&shellparam);
10939        shellparam.malloced = 1;
10940        shellparam.nparam = nparam;
10941        shellparam.p = newparam;
10942#if ENABLE_ASH_GETOPTS
10943        shellparam.optind = 1;
10944        shellparam.optoff = -1;
10945#endif
10946}
10947
10948/*
10949 * Process shell options.  The global variable argptr contains a pointer
10950 * to the argument list; we advance it past the options.
10951 *
10952 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10953 * For a non-interactive shell, an error condition encountered
10954 * by a special built-in ... shall cause the shell to write a diagnostic message
10955 * to standard error and exit as shown in the following table:
10956 * Error                                           Special Built-In
10957 * ...
10958 * Utility syntax error (option or operand error)  Shall exit
10959 * ...
10960 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10961 * we see that bash does not do that (set "finishes" with error code 1 instead,
10962 * and shell continues), and people rely on this behavior!
10963 * Testcase:
10964 * set -o barfoo 2>/dev/null
10965 * echo $?
10966 *
10967 * Oh well. Let's mimic that.
10968 */
10969static int
10970plus_minus_o(char *name, int val)
10971{
10972        int i;
10973
10974        if (name) {
10975                for (i = 0; i < NOPTS; i++) {
10976                        if (strcmp(name, optnames(i)) == 0) {
10977                                optlist[i] = val;
10978                                return 0;
10979                        }
10980                }
10981                ash_msg("illegal option %co %s", val ? '-' : '+', name);
10982                return 1;
10983        }
10984        for (i = 0; i < NOPTS; i++) {
10985                if (val) {
10986                        out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10987                } else {
10988                        out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10989                }
10990        }
10991        return 0;
10992}
10993static void
10994setoption(int flag, int val)
10995{
10996        int i;
10997
10998        for (i = 0; i < NOPTS; i++) {
10999                if (optletters(i) == flag) {
11000                        optlist[i] = val;
11001                        return;
11002                }
11003        }
11004        ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
11005        /* NOTREACHED */
11006}
11007static int
11008options(int cmdline, int *login_sh)
11009{
11010        char *p;
11011        int val;
11012        int c;
11013
11014        if (cmdline)
11015                minusc = NULL;
11016        while ((p = *argptr) != NULL) {
11017                c = *p++;
11018                if (c != '-' && c != '+')
11019                        break;
11020                argptr++;
11021                val = 0; /* val = 0 if c == '+' */
11022                if (c == '-') {
11023                        val = 1;
11024                        if (p[0] == '\0' || LONE_DASH(p)) {
11025                                if (!cmdline) {
11026                                        /* "-" means turn off -x and -v */
11027                                        if (p[0] == '\0')
11028                                                xflag = vflag = 0;
11029                                        /* "--" means reset params */
11030                                        else if (*argptr == NULL)
11031                                                setparam(argptr);
11032                                }
11033                                break;    /* "-" or "--" terminates options */
11034                        }
11035                }
11036                /* first char was + or - */
11037                while ((c = *p++) != '\0') {
11038                        /* bash 3.2 indeed handles -c CMD and +c CMD the same */
11039                        if (c == 'c' && cmdline) {
11040                                minusc = p;     /* command is after shell args */
11041                        } else if (c == 'o') {
11042                                if (plus_minus_o(*argptr, val)) {
11043                                        /* it already printed err message */
11044                                        return 1; /* error */
11045                                }
11046                                if (*argptr)
11047                                        argptr++;
11048                        } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
11049                                if (login_sh)
11050                                        *login_sh = 1;
11051                        /* bash does not accept +-login, we also won't */
11052                        } else if (cmdline && val && (c == '-')) { /* long options */
11053                                if (strcmp(p, "login") == 0) {
11054                                        if (login_sh)
11055                                                *login_sh = 1;
11056                                }
11057                                break;
11058                        } else {
11059                                setoption(c, val);
11060                        }
11061                }
11062        }
11063        return 0;
11064}
11065
11066/*
11067 * The shift builtin command.
11068 */
11069static int FAST_FUNC
11070shiftcmd(int argc UNUSED_PARAM, char **argv)
11071{
11072        int n;
11073        char **ap1, **ap2;
11074
11075        n = 1;
11076        if (argv[1])
11077                n = number(argv[1]);
11078        if (n > shellparam.nparam)
11079                return 1;
11080        INT_OFF;
11081        shellparam.nparam -= n;
11082        for (ap1 = shellparam.p; --n >= 0; ap1++) {
11083                if (shellparam.malloced)
11084                        free(*ap1);
11085        }
11086        ap2 = shellparam.p;
11087        while ((*ap2++ = *ap1++) != NULL)
11088                continue;
11089#if ENABLE_ASH_GETOPTS
11090        shellparam.optind = 1;
11091        shellparam.optoff = -1;
11092#endif
11093        INT_ON;
11094        return 0;
11095}
11096
11097/*
11098 * POSIX requires that 'set' (but not export or readonly) output the
11099 * variables in lexicographic order - by the locale's collating order (sigh).
11100 * Maybe we could keep them in an ordered balanced binary tree
11101 * instead of hashed lists.
11102 * For now just roll 'em through qsort for printing...
11103 */
11104static int
11105showvars(const char *sep_prefix, int on, int off)
11106{
11107        const char *sep;
11108        char **ep, **epend;
11109
11110        ep = listvars(on, off, /*strlist:*/ NULL, &epend);
11111        qsort(ep, epend - ep, sizeof(char *), vpcmp);
11112
11113        sep = *sep_prefix ? " " : sep_prefix;
11114
11115        for (; ep < epend; ep++) {
11116                const char *p;
11117                const char *q;
11118
11119                p = endofname(*ep);
11120/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11121 * makes "export -p" to have output not suitable for "eval":
11122 * import os
11123 * os.environ["test-test"]="test"
11124 * if os.fork() == 0:
11125 *   os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ])  # fixes this
11126 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11127 */
11128                q = nullstr;
11129                if (*p == '=')
11130                        q = single_quote(++p);
11131                out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11132        }
11133        return 0;
11134}
11135
11136/*
11137 * The set command builtin.
11138 */
11139static int FAST_FUNC
11140setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11141{
11142        int retval;
11143
11144        if (!argv[1])
11145                return showvars(nullstr, 0, VUNSET);
11146
11147        INT_OFF;
11148        retval = options(/*cmdline:*/ 0, NULL);
11149        if (retval == 0) { /* if no parse error... */
11150                optschanged();
11151                if (*argptr != NULL) {
11152                        setparam(argptr);
11153                }
11154        }
11155        INT_ON;
11156        return retval;
11157}
11158
11159#if ENABLE_ASH_RANDOM_SUPPORT
11160static void FAST_FUNC
11161change_random(const char *value)
11162{
11163        uint32_t t;
11164
11165        if (value == NULL) {
11166                /* "get", generate */
11167                t = next_random(&random_gen);
11168                /* set without recursion */
11169                setvar(vrandom.var_text, utoa(t), VNOFUNC);
11170                vrandom.flags &= ~VNOFUNC;
11171        } else {
11172                /* set/reset */
11173                t = strtoul(value, NULL, 10);
11174                INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
11175        }
11176}
11177#endif
11178
11179#if ENABLE_ASH_GETOPTS
11180static int
11181getopts(char *optstr, char *optvar, char **optfirst)
11182{
11183        char *p, *q;
11184        char c = '?';
11185        int done = 0;
11186        char sbuf[2];
11187        char **optnext;
11188        int ind = shellparam.optind;
11189        int off = shellparam.optoff;
11190
11191        sbuf[1] = '\0';
11192
11193        shellparam.optind = -1;
11194        optnext = optfirst + ind - 1;
11195
11196        if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
11197                p = NULL;
11198        else
11199                p = optnext[-1] + off;
11200        if (p == NULL || *p == '\0') {
11201                /* Current word is done, advance */
11202                p = *optnext;
11203                if (p == NULL || *p != '-' || *++p == '\0') {
11204 atend:
11205                        unsetvar("OPTARG");
11206                        p = NULL;
11207                        done = 1;
11208                        goto out;
11209                }
11210                optnext++;
11211                if (LONE_DASH(p))        /* check for "--" */
11212                        goto atend;
11213        }
11214
11215        c = *p++;
11216        for (q = optstr; *q != c;) {
11217                if (*q == '\0') {
11218                        /* OPTERR is a bashism */
11219                        const char *cp = lookupvar("OPTERR");
11220                        if ((cp && LONE_CHAR(cp, '0'))
11221                         || (optstr[0] == ':')
11222                        ) {
11223                                sbuf[0] = c;
11224                                /*sbuf[1] = '\0'; - already is */
11225                                setvar0("OPTARG", sbuf);
11226                        } else {
11227                                fprintf(stderr, "Illegal option -%c\n", c);
11228                                unsetvar("OPTARG");
11229                        }
11230                        c = '?';
11231                        goto out;
11232                }
11233                if (*++q == ':')
11234                        q++;
11235        }
11236
11237        if (*++q == ':') {
11238                if (*p == '\0' && (p = *optnext) == NULL) {
11239                        /* OPTERR is a bashism */
11240                        const char *cp = lookupvar("OPTERR");
11241                        if ((cp && LONE_CHAR(cp, '0'))
11242                         || (optstr[0] == ':')
11243                        ) {
11244                                sbuf[0] = c;
11245                                /*sbuf[1] = '\0'; - already is */
11246                                setvar0("OPTARG", sbuf);
11247                                c = ':';
11248                        } else {
11249                                fprintf(stderr, "No arg for -%c option\n", c);
11250                                unsetvar("OPTARG");
11251                                c = '?';
11252                        }
11253                        goto out;
11254                }
11255
11256                if (p == *optnext)
11257                        optnext++;
11258                setvar0("OPTARG", p);
11259                p = NULL;
11260        } else
11261                setvar0("OPTARG", nullstr);
11262 out:
11263        ind = optnext - optfirst + 1;
11264        setvar("OPTIND", itoa(ind), VNOFUNC);
11265        sbuf[0] = c;
11266        /*sbuf[1] = '\0'; - already is */
11267        setvar0(optvar, sbuf);
11268
11269        shellparam.optoff = p ? p - *(optnext - 1) : -1;
11270        shellparam.optind = ind;
11271
11272        return done;
11273}
11274
11275/*
11276 * The getopts builtin.  Shellparam.optnext points to the next argument
11277 * to be processed.  Shellparam.optptr points to the next character to
11278 * be processed in the current argument.  If shellparam.optnext is NULL,
11279 * then it's the first time getopts has been called.
11280 */
11281static int FAST_FUNC
11282getoptscmd(int argc, char **argv)
11283{
11284        char **optbase;
11285
11286        if (argc < 3)
11287                ash_msg_and_raise_error("usage: getopts optstring var [arg]");
11288        if (argc == 3) {
11289                optbase = shellparam.p;
11290                if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
11291                        shellparam.optind = 1;
11292                        shellparam.optoff = -1;
11293                }
11294        } else {
11295                optbase = &argv[3];
11296                if ((unsigned)shellparam.optind > argc - 2) {
11297                        shellparam.optind = 1;
11298                        shellparam.optoff = -1;
11299                }
11300        }
11301
11302        return getopts(argv[1], argv[2], optbase);
11303}
11304#endif /* ASH_GETOPTS */
11305
11306
11307/* ============ Shell parser */
11308
11309struct heredoc {
11310        struct heredoc *next;   /* next here document in list */
11311        union node *here;       /* redirection node */
11312        char *eofmark;          /* string indicating end of input */
11313        smallint striptabs;     /* if set, strip leading tabs */
11314};
11315
11316static smallint tokpushback;           /* last token pushed back */
11317static smallint quoteflag;             /* set if (part of) last token was quoted */
11318static token_id_t lasttoken;           /* last token read (integer id Txxx) */
11319static struct heredoc *heredoclist;    /* list of here documents to read */
11320static char *wordtext;                 /* text of last word returned by readtoken */
11321static struct nodelist *backquotelist;
11322static union node *redirnode;
11323static struct heredoc *heredoc;
11324
11325static const char *
11326tokname(char *buf, int tok)
11327{
11328        if (tok < TSEMI)
11329                return tokname_array[tok];
11330        sprintf(buf, "\"%s\"", tokname_array[tok]);
11331        return buf;
11332}
11333
11334/* raise_error_unexpected_syntax:
11335 * Called when an unexpected token is read during the parse.  The argument
11336 * is the token that is expected, or -1 if more than one type of token can
11337 * occur at this point.
11338 */
11339static void raise_error_unexpected_syntax(int) NORETURN;
11340static void
11341raise_error_unexpected_syntax(int token)
11342{
11343        char msg[64];
11344        char buf[16];
11345        int l;
11346
11347        l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
11348        if (token >= 0)
11349                sprintf(msg + l, " (expecting %s)", tokname(buf, token));
11350        raise_error_syntax(msg);
11351        /* NOTREACHED */
11352}
11353
11354/* parsing is heavily cross-recursive, need these forward decls */
11355static union node *andor(void);
11356static union node *pipeline(void);
11357static union node *parse_command(void);
11358static void parseheredoc(void);
11359static int peektoken(void);
11360static int readtoken(void);
11361
11362static union node *
11363list(int nlflag)
11364{
11365        union node *n1, *n2, *n3;
11366        int tok;
11367
11368        n1 = NULL;
11369        for (;;) {
11370                switch (peektoken()) {
11371                case TNL:
11372                        if (!(nlflag & 1))
11373                                break;
11374                        parseheredoc();
11375                        return n1;
11376
11377                case TEOF:
11378                        if (!n1 && (nlflag & 1))
11379                                n1 = NODE_EOF;
11380                        parseheredoc();
11381                        return n1;
11382                }
11383
11384                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11385                if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
11386                        return n1;
11387                nlflag |= 2;
11388
11389                n2 = andor();
11390                tok = readtoken();
11391                if (tok == TBACKGND) {
11392                        if (n2->type == NPIPE) {
11393                                n2->npipe.pipe_backgnd = 1;
11394                        } else {
11395                                if (n2->type != NREDIR) {
11396                                        n3 = stzalloc(sizeof(struct nredir));
11397                                        n3->nredir.n = n2;
11398                                        /*n3->nredir.redirect = NULL; - stzalloc did it */
11399                                        n2 = n3;
11400                                }
11401                                n2->type = NBACKGND;
11402                        }
11403                }
11404                if (n1 == NULL) {
11405                        n1 = n2;
11406                } else {
11407                        n3 = stzalloc(sizeof(struct nbinary));
11408                        n3->type = NSEMI;
11409                        n3->nbinary.ch1 = n1;
11410                        n3->nbinary.ch2 = n2;
11411                        n1 = n3;
11412                }
11413                switch (tok) {
11414                case TNL:
11415                case TEOF:
11416                        tokpushback = 1;
11417                        /* fall through */
11418                case TBACKGND:
11419                case TSEMI:
11420                        break;
11421                default:
11422                        if ((nlflag & 1))
11423                                raise_error_unexpected_syntax(-1);
11424                        tokpushback = 1;
11425                        return n1;
11426                }
11427        }
11428}
11429
11430static union node *
11431andor(void)
11432{
11433        union node *n1, *n2, *n3;
11434        int t;
11435
11436        n1 = pipeline();
11437        for (;;) {
11438                t = readtoken();
11439                if (t == TAND) {
11440                        t = NAND;
11441                } else if (t == TOR) {
11442                        t = NOR;
11443                } else {
11444                        tokpushback = 1;
11445                        return n1;
11446                }
11447                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11448                n2 = pipeline();
11449                n3 = stzalloc(sizeof(struct nbinary));
11450                n3->type = t;
11451                n3->nbinary.ch1 = n1;
11452                n3->nbinary.ch2 = n2;
11453                n1 = n3;
11454        }
11455}
11456
11457static union node *
11458pipeline(void)
11459{
11460        union node *n1, *n2, *pipenode;
11461        struct nodelist *lp, *prev;
11462        int negate;
11463
11464        negate = 0;
11465        TRACE(("pipeline: entered\n"));
11466        if (readtoken() == TNOT) {
11467                negate = !negate;
11468                checkkwd = CHKKWD | CHKALIAS;
11469        } else
11470                tokpushback = 1;
11471        n1 = parse_command();
11472        if (readtoken() == TPIPE) {
11473                pipenode = stzalloc(sizeof(struct npipe));
11474                pipenode->type = NPIPE;
11475                /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
11476                lp = stzalloc(sizeof(struct nodelist));
11477                pipenode->npipe.cmdlist = lp;
11478                lp->n = n1;
11479                do {
11480                        prev = lp;
11481                        lp = stzalloc(sizeof(struct nodelist));
11482                        checkkwd = CHKNL | CHKKWD | CHKALIAS;
11483                        lp->n = parse_command();
11484                        prev->next = lp;
11485                } while (readtoken() == TPIPE);
11486                lp->next = NULL;
11487                n1 = pipenode;
11488        }
11489        tokpushback = 1;
11490        if (negate) {
11491                n2 = stzalloc(sizeof(struct nnot));
11492                n2->type = NNOT;
11493                n2->nnot.com = n1;
11494                return n2;
11495        }
11496        return n1;
11497}
11498
11499static union node *
11500makename(void)
11501{
11502        union node *n;
11503
11504        n = stzalloc(sizeof(struct narg));
11505        n->type = NARG;
11506        /*n->narg.next = NULL; - stzalloc did it */
11507        n->narg.text = wordtext;
11508        n->narg.backquote = backquotelist;
11509        return n;
11510}
11511
11512static void
11513fixredir(union node *n, const char *text, int err)
11514{
11515        int fd;
11516
11517        TRACE(("Fix redir %s %d\n", text, err));
11518        if (!err)
11519                n->ndup.vname = NULL;
11520
11521        fd = bb_strtou(text, NULL, 10);
11522        if (!errno && fd >= 0)
11523                n->ndup.dupfd = fd;
11524        else if (LONE_DASH(text))
11525                n->ndup.dupfd = -1;
11526        else {
11527                if (err)
11528                        raise_error_syntax("bad fd number");
11529                n->ndup.vname = makename();
11530        }
11531}
11532
11533static void
11534parsefname(void)
11535{
11536        union node *n = redirnode;
11537
11538        if (n->type == NHERE)
11539                checkkwd = CHKEOFMARK;
11540        if (readtoken() != TWORD)
11541                raise_error_unexpected_syntax(-1);
11542        if (n->type == NHERE) {
11543                struct heredoc *here = heredoc;
11544                struct heredoc *p;
11545
11546                if (quoteflag == 0)
11547                        n->type = NXHERE;
11548                TRACE(("Here document %d\n", n->type));
11549                rmescapes(wordtext, 0, NULL);
11550                here->eofmark = wordtext;
11551                here->next = NULL;
11552                if (heredoclist == NULL)
11553                        heredoclist = here;
11554                else {
11555                        for (p = heredoclist; p->next; p = p->next)
11556                                continue;
11557                        p->next = here;
11558                }
11559        } else if (n->type == NTOFD || n->type == NFROMFD) {
11560                fixredir(n, wordtext, 0);
11561        } else {
11562                n->nfile.fname = makename();
11563        }
11564}
11565
11566static union node *
11567simplecmd(void)
11568{
11569        union node *args, **app;
11570        union node *n = NULL;
11571        union node *vars, **vpp;
11572        union node **rpp, *redir;
11573        int savecheckkwd;
11574        int savelinno;
11575#if BASH_TEST2
11576        smallint double_brackets_flag = 0;
11577#endif
11578        IF_BASH_FUNCTION(smallint function_flag = 0;)
11579
11580        args = NULL;
11581        app = &args;
11582        vars = NULL;
11583        vpp = &vars;
11584        redir = NULL;
11585        rpp = &redir;
11586
11587        savecheckkwd = CHKALIAS;
11588        savelinno = g_parsefile->linno;
11589        for (;;) {
11590                int t;
11591                checkkwd = savecheckkwd;
11592                t = readtoken();
11593                switch (t) {
11594#if BASH_FUNCTION
11595                case TFUNCTION:
11596                        if (peektoken() != TWORD)
11597                                raise_error_unexpected_syntax(TWORD);
11598                        function_flag = 1;
11599                        break;
11600#endif
11601#if BASH_TEST2
11602                case TAND: /* "&&" */
11603                case TOR: /* "||" */
11604                        if (!double_brackets_flag) {
11605                                tokpushback = 1;
11606                                goto out;
11607                        }
11608                        wordtext = (char *) (t == TAND ? "-a" : "-o");
11609#endif
11610                case TWORD:
11611                        n = stzalloc(sizeof(struct narg));
11612                        n->type = NARG;
11613                        /*n->narg.next = NULL; - stzalloc did it */
11614                        n->narg.text = wordtext;
11615#if BASH_TEST2
11616                        if (strcmp("[[", wordtext) == 0)
11617                                double_brackets_flag = 1;
11618                        else if (strcmp("]]", wordtext) == 0)
11619                                double_brackets_flag = 0;
11620#endif
11621                        n->narg.backquote = backquotelist;
11622                        if (savecheckkwd && isassignment(wordtext)) {
11623                                *vpp = n;
11624                                vpp = &n->narg.next;
11625                        } else {
11626                                *app = n;
11627                                app = &n->narg.next;
11628                                savecheckkwd = 0;
11629                        }
11630#if BASH_FUNCTION
11631                        if (function_flag) {
11632                                checkkwd = CHKNL | CHKKWD;
11633                                switch (peektoken()) {
11634                                case TBEGIN:
11635                                case TIF:
11636                                case TCASE:
11637                                case TUNTIL:
11638                                case TWHILE:
11639                                case TFOR:
11640                                        goto do_func;
11641                                case TLP:
11642                                        function_flag = 0;
11643                                        break;
11644# if BASH_TEST2
11645                                case TWORD:
11646                                        if (strcmp("[[", wordtext) == 0)
11647                                                goto do_func;
11648                                        /* fall through */
11649# endif
11650                                default:
11651                                        raise_error_unexpected_syntax(-1);
11652                                }
11653                        }
11654#endif
11655                        break;
11656                case TREDIR:
11657                        *rpp = n = redirnode;
11658                        rpp = &n->nfile.next;
11659                        parsefname();   /* read name of redirection file */
11660                        break;
11661                case TLP:
11662 IF_BASH_FUNCTION(do_func:)
11663                        if (args && app == &args->narg.next
11664                         && !vars && !redir
11665                        ) {
11666                                struct builtincmd *bcmd;
11667                                const char *name;
11668
11669                                /* We have a function */
11670                                if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
11671                                        raise_error_unexpected_syntax(TRP);
11672                                name = n->narg.text;
11673                                if (!goodname(name)
11674                                 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11675                                ) {
11676                                        raise_error_syntax("bad function name");
11677                                }
11678                                n->type = NDEFUN;
11679                                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11680                                n->ndefun.text = n->narg.text;
11681                                n->ndefun.linno = g_parsefile->linno;
11682                                n->ndefun.body = parse_command();
11683                                return n;
11684                        }
11685                        IF_BASH_FUNCTION(function_flag = 0;)
11686                        /* fall through */
11687                default:
11688                        tokpushback = 1;
11689                        goto out;
11690                }
11691        }
11692 out:
11693        *app = NULL;
11694        *vpp = NULL;
11695        *rpp = NULL;
11696        n = stzalloc(sizeof(struct ncmd));
11697        if (NCMD != 0)
11698                n->type = NCMD;
11699        n->ncmd.linno = savelinno;
11700        n->ncmd.args = args;
11701        n->ncmd.assign = vars;
11702        n->ncmd.redirect = redir;
11703        return n;
11704}
11705
11706static union node *
11707parse_command(void)
11708{
11709        union node *n1, *n2;
11710        union node *ap, **app;
11711        union node *cp, **cpp;
11712        union node *redir, **rpp;
11713        union node **rpp2;
11714        int t;
11715        int savelinno;
11716
11717        redir = NULL;
11718        rpp2 = &redir;
11719
11720        savelinno = g_parsefile->linno;
11721
11722        switch (readtoken()) {
11723        default:
11724                raise_error_unexpected_syntax(-1);
11725                /* NOTREACHED */
11726        case TIF:
11727                n1 = stzalloc(sizeof(struct nif));
11728                n1->type = NIF;
11729                n1->nif.test = list(0);
11730                if (readtoken() != TTHEN)
11731                        raise_error_unexpected_syntax(TTHEN);
11732                n1->nif.ifpart = list(0);
11733                n2 = n1;
11734                while (readtoken() == TELIF) {
11735                        n2->nif.elsepart = stzalloc(sizeof(struct nif));
11736                        n2 = n2->nif.elsepart;
11737                        n2->type = NIF;
11738                        n2->nif.test = list(0);
11739                        if (readtoken() != TTHEN)
11740                                raise_error_unexpected_syntax(TTHEN);
11741                        n2->nif.ifpart = list(0);
11742                }
11743                if (lasttoken == TELSE)
11744                        n2->nif.elsepart = list(0);
11745                else {
11746                        n2->nif.elsepart = NULL;
11747                        tokpushback = 1;
11748                }
11749                t = TFI;
11750                break;
11751        case TWHILE:
11752        case TUNTIL: {
11753                int got;
11754                n1 = stzalloc(sizeof(struct nbinary));
11755                n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
11756                n1->nbinary.ch1 = list(0);
11757                got = readtoken();
11758                if (got != TDO) {
11759                        TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
11760                                        got == TWORD ? wordtext : ""));
11761                        raise_error_unexpected_syntax(TDO);
11762                }
11763                n1->nbinary.ch2 = list(0);
11764                t = TDONE;
11765                break;
11766        }
11767        case TFOR:
11768                if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
11769                        raise_error_syntax("bad for loop variable");
11770                n1 = stzalloc(sizeof(struct nfor));
11771                n1->type = NFOR;
11772                n1->nfor.linno = savelinno;
11773                n1->nfor.var = wordtext;
11774                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11775                if (readtoken() == TIN) {
11776                        app = &ap;
11777                        while (readtoken() == TWORD) {
11778                                n2 = stzalloc(sizeof(struct narg));
11779                                n2->type = NARG;
11780                                /*n2->narg.next = NULL; - stzalloc did it */
11781                                n2->narg.text = wordtext;
11782                                n2->narg.backquote = backquotelist;
11783                                *app = n2;
11784                                app = &n2->narg.next;
11785                        }
11786                        *app = NULL;
11787                        n1->nfor.args = ap;
11788                        if (lasttoken != TNL && lasttoken != TSEMI)
11789                                raise_error_unexpected_syntax(-1);
11790                } else {
11791                        n2 = stzalloc(sizeof(struct narg));
11792                        n2->type = NARG;
11793                        /*n2->narg.next = NULL; - stzalloc did it */
11794                        n2->narg.text = (char *)dolatstr;
11795                        /*n2->narg.backquote = NULL;*/
11796                        n1->nfor.args = n2;
11797                        /*
11798                         * Newline or semicolon here is optional (but note
11799                         * that the original Bourne shell only allowed NL).
11800                         */
11801                        if (lasttoken != TSEMI)
11802                                tokpushback = 1;
11803                }
11804                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11805                if (readtoken() != TDO)
11806                        raise_error_unexpected_syntax(TDO);
11807                n1->nfor.body = list(0);
11808                t = TDONE;
11809                break;
11810        case TCASE:
11811                n1 = stzalloc(sizeof(struct ncase));
11812                n1->type = NCASE;
11813                n1->ncase.linno = savelinno;
11814                if (readtoken() != TWORD)
11815                        raise_error_unexpected_syntax(TWORD);
11816                n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
11817                n2->type = NARG;
11818                /*n2->narg.next = NULL; - stzalloc did it */
11819                n2->narg.text = wordtext;
11820                n2->narg.backquote = backquotelist;
11821                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11822                if (readtoken() != TIN)
11823                        raise_error_unexpected_syntax(TIN);
11824                cpp = &n1->ncase.cases;
11825 next_case:
11826                checkkwd = CHKNL | CHKKWD;
11827                t = readtoken();
11828                while (t != TESAC) {
11829                        if (lasttoken == TLP)
11830                                readtoken();
11831                        *cpp = cp = stzalloc(sizeof(struct nclist));
11832                        cp->type = NCLIST;
11833                        app = &cp->nclist.pattern;
11834                        for (;;) {
11835                                *app = ap = stzalloc(sizeof(struct narg));
11836                                ap->type = NARG;
11837                                /*ap->narg.next = NULL; - stzalloc did it */
11838                                ap->narg.text = wordtext;
11839                                ap->narg.backquote = backquotelist;
11840                                if (readtoken() != TPIPE)
11841                                        break;
11842                                app = &ap->narg.next;
11843                                readtoken();
11844                        }
11845                        //ap->narg.next = NULL;
11846                        if (lasttoken != TRP)
11847                                raise_error_unexpected_syntax(TRP);
11848                        cp->nclist.body = list(2);
11849
11850                        cpp = &cp->nclist.next;
11851
11852                        checkkwd = CHKNL | CHKKWD;
11853                        t = readtoken();
11854                        if (t != TESAC) {
11855                                if (t != TENDCASE)
11856                                        raise_error_unexpected_syntax(TENDCASE);
11857                                goto next_case;
11858                        }
11859                }
11860                *cpp = NULL;
11861                goto redir;
11862        case TLP:
11863                n1 = stzalloc(sizeof(struct nredir));
11864                n1->type = NSUBSHELL;
11865                n1->nredir.linno = savelinno;
11866                n1->nredir.n = list(0);
11867                /*n1->nredir.redirect = NULL; - stzalloc did it */
11868                t = TRP;
11869                break;
11870        case TBEGIN:
11871                n1 = list(0);
11872                t = TEND;
11873                break;
11874        IF_BASH_FUNCTION(case TFUNCTION:)
11875        case TWORD:
11876        case TREDIR:
11877                tokpushback = 1;
11878                return simplecmd();
11879        }
11880
11881        if (readtoken() != t)
11882                raise_error_unexpected_syntax(t);
11883
11884 redir:
11885        /* Now check for redirection which may follow command */
11886        checkkwd = CHKKWD | CHKALIAS;
11887        rpp = rpp2;
11888        while (readtoken() == TREDIR) {
11889                *rpp = n2 = redirnode;
11890                rpp = &n2->nfile.next;
11891                parsefname();
11892        }
11893        tokpushback = 1;
11894        *rpp = NULL;
11895        if (redir) {
11896                if (n1->type != NSUBSHELL) {
11897                        n2 = stzalloc(sizeof(struct nredir));
11898                        n2->type = NREDIR;
11899                        n2->nredir.linno = savelinno;
11900                        n2->nredir.n = n1;
11901                        n1 = n2;
11902                }
11903                n1->nredir.redirect = redir;
11904        }
11905        return n1;
11906}
11907
11908#if BASH_DOLLAR_SQUOTE
11909static int
11910decode_dollar_squote(void)
11911{
11912        static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11913        int c, cnt;
11914        char *p;
11915        char buf[4];
11916
11917        c = pgetc();
11918        p = strchr(C_escapes, c);
11919        if (p) {
11920                buf[0] = c;
11921                p = buf;
11922                cnt = 3;
11923                if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11924                        do {
11925                                c = pgetc();
11926                                *++p = c;
11927                        } while ((unsigned char)(c - '0') <= 7 && --cnt);
11928                        pungetc();
11929                } else if (c == 'x') { /* \xHH */
11930                        do {
11931                                c = pgetc();
11932                                *++p = c;
11933                        } while (isxdigit(c) && --cnt);
11934                        pungetc();
11935                        if (cnt == 3) { /* \x but next char is "bad" */
11936                                c = 'x';
11937                                goto unrecognized;
11938                        }
11939                } else { /* simple seq like \\ or \t */
11940                        p++;
11941                }
11942                *p = '\0';
11943                p = buf;
11944                c = bb_process_escape_sequence((void*)&p);
11945        } else { /* unrecognized "\z": print both chars unless ' or " */
11946                if (c != '\'' && c != '"') {
11947 unrecognized:
11948                        c |= 0x100; /* "please encode \, then me" */
11949                }
11950        }
11951        return c;
11952}
11953#endif
11954
11955/* Used by expandstr to get here-doc like behaviour. */
11956#define FAKEEOFMARK ((char*)(uintptr_t)1)
11957
11958static ALWAYS_INLINE int
11959realeofmark(const char *eofmark)
11960{
11961        return eofmark && eofmark != FAKEEOFMARK;
11962}
11963
11964/*
11965 * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
11966 * is not NULL, read a here document.  In the latter case, eofmark is the
11967 * word which marks the end of the document and striptabs is true if
11968 * leading tabs should be stripped from the document.  The argument c
11969 * is the first character of the input token or document.
11970 *
11971 * Because C does not have internal subroutines, I have simulated them
11972 * using goto's to implement the subroutine linkage.  The following macros
11973 * will run code that appears at the end of readtoken1.
11974 */
11975#define CHECKEND()      {goto checkend; checkend_return:;}
11976#define PARSEREDIR()    {goto parseredir; parseredir_return:;}
11977#define PARSESUB()      {goto parsesub; parsesub_return:;}
11978#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11979#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11980#define PARSEARITH()    {goto parsearith; parsearith_return:;}
11981static int
11982readtoken1(int c, int syntax, char *eofmark, int striptabs)
11983{
11984        /* NB: syntax parameter fits into smallint */
11985        /* c parameter is an unsigned char or PEOF or PEOA */
11986        char *out;
11987        size_t len;
11988        struct nodelist *bqlist;
11989        smallint quotef;
11990        smallint oldstyle;
11991        smallint pssyntax;   /* we are expanding a prompt string */
11992        IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
11993        /* syntax stack */
11994        struct synstack synbase = { };
11995        struct synstack *synstack = &synbase;
11996
11997#if ENABLE_ASH_EXPAND_PRMT
11998        pssyntax = (syntax == PSSYNTAX);
11999        if (pssyntax)
12000                syntax = DQSYNTAX;
12001#else
12002        pssyntax = 0; /* constant */
12003#endif
12004        synstack->syntax = syntax;
12005
12006        if (syntax == DQSYNTAX)
12007                synstack->dblquote = 1;
12008        quotef = 0;
12009        bqlist = NULL;
12010
12011        STARTSTACKSTR(out);
12012 loop:
12013        /* For each line, until end of word */
12014        CHECKEND();     /* set c to PEOF if at end of here document */
12015        for (;;) {      /* until end of line or end of word */
12016                CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
12017                switch (SIT(c, synstack->syntax)) {
12018                case CNL:       /* '\n' */
12019                        if (synstack->syntax == BASESYNTAX
12020                         && !synstack->varnest
12021                        ) {
12022                                goto endword;   /* exit outer loop */
12023                        }
12024                        USTPUTC(c, out);
12025                        nlprompt();
12026                        c = pgetc();
12027                        goto loop;              /* continue outer loop */
12028                case CWORD:
12029                        USTPUTC(c, out);
12030                        break;
12031                case CCTL:
12032#if BASH_DOLLAR_SQUOTE
12033                        if (c == '\\' && bash_dollar_squote) {
12034                                c = decode_dollar_squote();
12035                                if (c == '\0') {
12036                                        /* skip $'\000', $'\x00' (like bash) */
12037                                        break;
12038                                }
12039                                if (c & 0x100) {
12040                                        /* Unknown escape. Encode as '\z' */
12041                                        c = (unsigned char)c;
12042                                        if (eofmark == NULL || synstack->dblquote)
12043                                                USTPUTC(CTLESC, out);
12044                                        USTPUTC('\\', out);
12045                                }
12046                        }
12047#endif
12048                        if (!eofmark || synstack->dblquote || synstack->varnest)
12049                                USTPUTC(CTLESC, out);
12050                        USTPUTC(c, out);
12051                        break;
12052                case CBACK:     /* backslash */
12053                        c = pgetc_without_PEOA();
12054                        if (c == PEOF) {
12055                                USTPUTC(CTLESC, out);
12056                                USTPUTC('\\', out);
12057                                pungetc();
12058                        } else if (c == '\n') {
12059                                nlprompt();
12060                        } else {
12061                                if (pssyntax && c == '$') {
12062                                        USTPUTC(CTLESC, out);
12063                                        USTPUTC('\\', out);
12064                                }
12065                                /* Backslash is retained if we are in "str"
12066                                 * and next char isn't dquote-special.
12067                                 */
12068                                if (synstack->dblquote
12069                                 && c != '\\'
12070                                 && c != '`'
12071                                 && c != '$'
12072                                 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12073                                 && (c != '}' || !synstack->varnest)
12074                                ) {
12075                                        USTPUTC(CTLESC, out); /* protect '\' from glob */
12076                                        USTPUTC('\\', out);
12077                                }
12078                                USTPUTC(CTLESC, out);
12079                                USTPUTC(c, out);
12080                                quotef = 1;
12081                        }
12082                        break;
12083                case CSQUOTE:
12084                        synstack->syntax = SQSYNTAX;
12085 quotemark:
12086                        if (eofmark == NULL) {
12087                                USTPUTC(CTLQUOTEMARK, out);
12088                        }
12089                        break;
12090                case CDQUOTE:
12091                        synstack->syntax = DQSYNTAX;
12092                        synstack->dblquote = 1;
12093 toggledq:
12094                        if (synstack->varnest)
12095                                synstack->innerdq ^= 1;
12096                        goto quotemark;
12097                case CENDQUOTE:
12098                        IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
12099                        if (eofmark != NULL && synstack->varnest == 0) {
12100                                USTPUTC(c, out);
12101                                break;
12102                        }
12103
12104                        if (synstack->dqvarnest == 0) {
12105                                synstack->syntax = BASESYNTAX;
12106                                synstack->dblquote = 0;
12107                        }
12108
12109                        quotef = 1;
12110
12111                        if (c == '"')
12112                                goto toggledq;
12113
12114                        goto quotemark;
12115                case CVAR:      /* '$' */
12116                        PARSESUB();             /* parse substitution */
12117                        break;
12118                case CENDVAR:   /* '}' */
12119                        if (!synstack->innerdq && synstack->varnest > 0) {
12120                                if (!--synstack->varnest && synstack->varpushed)
12121                                        synstack_pop(&synstack);
12122                                else if (synstack->dqvarnest > 0)
12123                                        synstack->dqvarnest--;
12124                                c = CTLENDVAR;
12125                        }
12126                        USTPUTC(c, out);
12127                        break;
12128#if ENABLE_FEATURE_SH_MATH
12129                case CLP:       /* '(' in arithmetic */
12130                        synstack->parenlevel++;
12131                        USTPUTC(c, out);
12132                        break;
12133                case CRP:       /* ')' in arithmetic */
12134                        if (synstack->parenlevel > 0) {
12135                                synstack->parenlevel--;
12136                        } else {
12137                                if (pgetc_eatbnl() == ')') {
12138                                        c = CTLENDARI;
12139                                        synstack_pop(&synstack);
12140                                } else {
12141                                        /*
12142                                         * unbalanced parens
12143                                         * (don't 2nd guess - no error)
12144                                         */
12145                                        pungetc();
12146                                }
12147                        }
12148                        USTPUTC(c, out);
12149                        break;
12150#endif
12151                case CBQUOTE:   /* '`' */
12152                        if (checkkwd & CHKEOFMARK) {
12153                                quotef = 1;
12154                                USTPUTC('`', out);
12155                                break;
12156                        }
12157
12158                        PARSEBACKQOLD();
12159                        break;
12160                case CENDFILE:
12161                        goto endword;           /* exit outer loop */
12162                case CIGN:
12163                        break;
12164                default:
12165                        if (synstack->varnest == 0) {
12166#if BASH_REDIR_OUTPUT
12167                                if (c == '&') {
12168//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
12169                                        if (pgetc() == '>')
12170                                                c = 0x100 + '>'; /* flag &> */
12171                                        pungetc();
12172                                }
12173#endif
12174                                goto endword;   /* exit outer loop */
12175                        }
12176                        IF_ASH_ALIAS(if (c != PEOA))
12177                                USTPUTC(c, out);
12178                }
12179                c = pgetc();
12180        } /* for (;;) */
12181 endword:
12182
12183#if ENABLE_FEATURE_SH_MATH
12184        if (synstack->syntax == ARISYNTAX)
12185                raise_error_syntax("missing '))'");
12186#endif
12187        if (synstack->syntax != BASESYNTAX && eofmark == NULL)
12188                raise_error_syntax("unterminated quoted string");
12189        if (synstack->varnest != 0) {
12190                /* { */
12191                raise_error_syntax("missing '}'");
12192        }
12193        USTPUTC('\0', out);
12194        len = out - (char *)stackblock();
12195        out = stackblock();
12196        if (eofmark == NULL) {
12197                if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
12198                 && quotef == 0
12199                ) {
12200                        if (isdigit_str9(out)) {
12201                                PARSEREDIR(); /* passed as params: out, c */
12202                                lasttoken = TREDIR;
12203                                return lasttoken;
12204                        }
12205                        /* else: non-number X seen, interpret it
12206                         * as "NNNX>file" = "NNNX >file" */
12207                }
12208                pungetc();
12209        }
12210        quoteflag = quotef;
12211        backquotelist = bqlist;
12212        grabstackblock(len);
12213        wordtext = out;
12214        lasttoken = TWORD;
12215        return lasttoken;
12216/* end of readtoken routine */
12217
12218/*
12219 * Check to see whether we are at the end of the here document.  When this
12220 * is called, c is set to the first character of the next input line.  If
12221 * we are at the end of the here document, this routine sets the c to PEOF.
12222 */
12223checkend: {
12224        if (realeofmark(eofmark)) {
12225                int markloc;
12226                char *p;
12227
12228#if ENABLE_ASH_ALIAS
12229                if (c == PEOA)
12230                        c = pgetc_without_PEOA();
12231#endif
12232                if (striptabs) {
12233                        while (c == '\t') {
12234                                c = pgetc_without_PEOA();
12235                        }
12236                }
12237
12238                markloc = out - (char *)stackblock();
12239                for (p = eofmark; STPUTC(c, out), *p; p++) {
12240                        if (c != *p)
12241                                goto more_heredoc;
12242
12243                        c = pgetc_without_PEOA();
12244                }
12245
12246                if (c == '\n' || c == PEOF) {
12247                        c = PEOF;
12248                        g_parsefile->linno++;
12249                        needprompt = doprompt;
12250                } else {
12251                        int len_here;
12252
12253 more_heredoc:
12254                        p = (char *)stackblock() + markloc + 1;
12255                        len_here = out - p;
12256
12257                        if (len_here) {
12258                                len_here -= (c >= PEOF);
12259                                c = p[-1];
12260
12261                                if (len_here) {
12262                                        char *str;
12263
12264                                        str = alloca(len_here + 1);
12265                                        *(char *)mempcpy(str, p, len_here) = '\0';
12266
12267                                        pushstring(str, NULL);
12268                                }
12269                        }
12270                }
12271
12272                STADJUST((char *)stackblock() + markloc - out, out);
12273        }
12274        goto checkend_return;
12275}
12276
12277/*
12278 * Parse a redirection operator.  The variable "out" points to a string
12279 * specifying the fd to be redirected.  The variable "c" contains the
12280 * first character of the redirection operator.
12281 */
12282parseredir: {
12283        /* out is already checked to be a valid number or "" */
12284        int fd = (*out == '\0' ? -1 : atoi(out));
12285        union node *np;
12286
12287        np = stzalloc(sizeof(struct nfile));
12288        if (c == '>') {
12289                np->nfile.fd = 1;
12290                c = pgetc_eatbnl();
12291                if (c == '>')
12292                        np->type = NAPPEND;
12293                else if (c == '|')
12294                        np->type = NCLOBBER;
12295                else if (c == '&')
12296                        np->type = NTOFD;
12297                        /* it also can be NTO2 (>&file), but we can't figure it out yet */
12298                else {
12299                        np->type = NTO;
12300                        pungetc();
12301                }
12302        }
12303#if BASH_REDIR_OUTPUT
12304        else if (c == 0x100 + '>') { /* this flags &> redirection */
12305                np->nfile.fd = 1;
12306                pgetc(); /* this is '>', no need to check */
12307                np->type = NTO2;
12308        }
12309#endif
12310        else { /* c == '<' */
12311                /*np->nfile.fd = 0; - stzalloc did it */
12312                c = pgetc_eatbnl();
12313                switch (c) {
12314                case '<':
12315                        if (sizeof(struct nfile) != sizeof(struct nhere)) {
12316                                np = stzalloc(sizeof(struct nhere));
12317                                /*np->nfile.fd = 0; - stzalloc did it */
12318                        }
12319                        np->type = NHERE;
12320                        heredoc = stzalloc(sizeof(struct heredoc));
12321                        heredoc->here = np;
12322                        c = pgetc_eatbnl();
12323                        if (c == '-') {
12324                                heredoc->striptabs = 1;
12325                        } else {
12326                                /*heredoc->striptabs = 0; - stzalloc did it */
12327                                pungetc();
12328                        }
12329                        break;
12330
12331                case '&':
12332                        np->type = NFROMFD;
12333                        break;
12334
12335                case '>':
12336                        np->type = NFROMTO;
12337                        break;
12338
12339                default:
12340                        np->type = NFROM;
12341                        pungetc();
12342                        break;
12343                }
12344        }
12345        if (fd >= 0)
12346                np->nfile.fd = fd;
12347        redirnode = np;
12348        goto parseredir_return;
12349}
12350
12351/*
12352 * Parse a substitution.  At this point, we have read the dollar sign
12353 * and nothing else.
12354 */
12355
12356/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12357 * (assuming ascii char codes, as the original implementation did) */
12358#define is_special(c) \
12359        (((unsigned)(c) - 33 < 32) \
12360                        && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
12361parsesub: {
12362        unsigned char subtype;
12363        int typeloc;
12364
12365        c = pgetc_eatbnl();
12366        if ((checkkwd & CHKEOFMARK)
12367         || c > 255 /* PEOA or PEOF */
12368         || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
12369        ) {
12370#if BASH_DOLLAR_SQUOTE
12371                if (synstack->syntax != DQSYNTAX && c == '\'')
12372                        bash_dollar_squote = 1;
12373                else
12374#endif
12375                        USTPUTC('$', out);
12376                pungetc();
12377        } else if (c == '(') {
12378                /* $(command) or $((arith)) */
12379                if (pgetc_eatbnl() == '(') {
12380#if ENABLE_FEATURE_SH_MATH
12381                        PARSEARITH();
12382#else
12383                        raise_error_syntax("support for $((arith)) is disabled");
12384#endif
12385                } else {
12386                        pungetc();
12387                        PARSEBACKQNEW();
12388                }
12389        } else {
12390                /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
12391                smalluint newsyn = synstack->syntax;
12392
12393                USTPUTC(CTLVAR, out);
12394                typeloc = out - (char *)stackblock();
12395                STADJUST(1, out);
12396                subtype = VSNORMAL;
12397                if (c == '{') {
12398                        c = pgetc_eatbnl();
12399                        subtype = 0;
12400                }
12401 varname:
12402                if (is_name(c)) {
12403                        /* $[{[#]]NAME[}] */
12404                        do {
12405                                STPUTC(c, out);
12406                                c = pgetc_eatbnl();
12407                        } while (is_in_name(c));
12408                } else if (isdigit(c)) {
12409                        /* $[{[#]]NUM[}] */
12410                        do {
12411                                STPUTC(c, out);
12412                                c = pgetc_eatbnl();
12413                        } while (isdigit(c));
12414                } else {
12415                        /* $[{[#]]<specialchar>[}] */
12416                        int cc = c;
12417
12418                        c = pgetc_eatbnl();
12419                        if (!subtype && cc == '#') {
12420                                subtype = VSLENGTH;
12421                                if (c == '_' || isalnum(c))
12422                                        goto varname;
12423                                cc = c;
12424                                c = pgetc_eatbnl();
12425                                if (cc == '}' || c != '}') {
12426                                        pungetc();
12427                                        subtype = 0;
12428                                        c = cc;
12429                                        cc = '#';
12430                                }
12431                        }
12432
12433                        if (!is_special(cc)) {
12434                                if (subtype == VSLENGTH)
12435                                        subtype = 0;
12436                                goto badsub;
12437                        }
12438
12439                        USTPUTC(cc, out);
12440                }
12441
12442                if (c != '}' && subtype == VSLENGTH) {
12443                        /* ${#VAR didn't end with } */
12444                        goto badsub;
12445                }
12446
12447                if (subtype == 0) {
12448                        static const char types[] ALIGN1 = "}-+?=";
12449                        /* ${VAR...} but not $VAR or ${#VAR} */
12450                        /* c == first char after VAR */
12451                        int cc = c;
12452
12453                        switch (c) {
12454                        case ':':
12455                                c = pgetc_eatbnl();
12456#if BASH_SUBSTR
12457                                /* This check is only needed to not misinterpret
12458                                 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12459                                 * constructs.
12460                                 */
12461                                if (!strchr(types, c)) {
12462                                        subtype = VSSUBSTR;
12463                                        pungetc();
12464                                        break; /* "goto badsub" is bigger (!) */
12465                                }
12466#endif
12467                                subtype = VSNUL;
12468                                /*FALLTHROUGH*/
12469                        default: {
12470                                const char *p = strchr(types, c);
12471                                if (p == NULL)
12472                                        break;
12473                                subtype |= p - types + VSNORMAL;
12474                                break;
12475                        }
12476                        case '%':
12477                        case '#':
12478                                subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12479                                c = pgetc_eatbnl();
12480                                if (c == cc)
12481                                        subtype++;
12482                                else
12483                                        pungetc();
12484
12485                                newsyn = BASESYNTAX;
12486                                break;
12487#if BASH_PATTERN_SUBST
12488                        case '/':
12489                                /* ${v/[/]pattern/repl} */
12490//TODO: encode pattern and repl separately.
12491// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12492// are broken (should print "ONE")
12493                                subtype = VSREPLACE;
12494                                newsyn = BASESYNTAX;
12495                                c = pgetc_eatbnl();
12496                                if (c != '/')
12497                                        goto badsub;
12498                                subtype++; /* VSREPLACEALL */
12499                                break;
12500#endif
12501                        }
12502                } else {
12503 badsub:
12504                        pungetc();
12505                }
12506
12507                if (newsyn == ARISYNTAX)
12508                        newsyn = DQSYNTAX;
12509
12510                if ((newsyn != synstack->syntax || synstack->innerdq)
12511                 && subtype != VSNORMAL
12512                ) {
12513                        synstack_push(&synstack,
12514                                synstack->prev ?: alloca(sizeof(*synstack)),
12515                                newsyn);
12516
12517                        synstack->varpushed = 1;
12518                        synstack->dblquote = newsyn != BASESYNTAX;
12519                }
12520
12521                ((unsigned char *)stackblock())[typeloc] = subtype;
12522                if (subtype != VSNORMAL) {
12523                        synstack->varnest++;
12524                        if (synstack->dblquote)
12525                                synstack->dqvarnest++;
12526                }
12527                STPUTC('=', out);
12528        }
12529        goto parsesub_return;
12530}
12531
12532/*
12533 * Called to parse command substitutions.  Newstyle is set if the command
12534 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12535 * list of commands (passed by reference), and savelen is the number of
12536 * characters on the top of the stack which must be preserved.
12537 */
12538parsebackq: {
12539        struct nodelist **nlpp;
12540        union node *n;
12541        char *str;
12542        size_t savelen;
12543        smallint saveprompt = 0;
12544
12545        str = NULL;
12546        savelen = out - (char *)stackblock();
12547        if (savelen > 0) {
12548                /*
12549                 * FIXME: this can allocate very large block on stack and SEGV.
12550                 * Example:
12551                 * echo "..<100kbytes>..`true` $(true) `true` ..."
12552                 * allocates 100kb for every command subst. With about
12553                 * a hundred command substitutions stack overflows.
12554                 * With larger prepended string, SEGV happens sooner.
12555                 */
12556                str = alloca(savelen);
12557                memcpy(str, stackblock(), savelen);
12558        }
12559
12560        if (oldstyle) {
12561                /* We must read until the closing backquote, giving special
12562                 * treatment to some slashes, and then push the string and
12563                 * reread it as input, interpreting it normally.
12564                 */
12565                char *pout;
12566                size_t psavelen;
12567                char *pstr;
12568
12569                STARTSTACKSTR(pout);
12570                for (;;) {
12571                        int pc;
12572
12573                        setprompt_if(needprompt, 2);
12574                        pc = pgetc_eatbnl();
12575                        switch (pc) {
12576                        case '`':
12577                                goto done;
12578
12579                        case '\\':
12580                                pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
12581                                if (pc != '\\' && pc != '`' && pc != '$'
12582                                 && (!synstack->dblquote || pc != '"')
12583                                ) {
12584                                        STPUTC('\\', pout);
12585                                }
12586                                if (pc <= 255 /* not PEOA or PEOF */) {
12587                                        break;
12588                                }
12589                                /* fall through */
12590
12591                        case PEOF:
12592                        IF_ASH_ALIAS(case PEOA:)
12593                                raise_error_syntax("EOF in backquote substitution");
12594
12595                        case '\n':
12596                                nlnoprompt();
12597                                break;
12598
12599                        default:
12600                                break;
12601                        }
12602                        STPUTC(pc, pout);
12603                }
12604 done:
12605                STPUTC('\0', pout);
12606                psavelen = pout - (char *)stackblock();
12607                if (psavelen > 0) {
12608                        pstr = grabstackstr(pout);
12609                        setinputstring(pstr);
12610                }
12611        }
12612        nlpp = &bqlist;
12613        while (*nlpp)
12614                nlpp = &(*nlpp)->next;
12615        *nlpp = stzalloc(sizeof(**nlpp));
12616        /* (*nlpp)->next = NULL; - stzalloc did it */
12617
12618        if (oldstyle) {
12619                saveprompt = doprompt;
12620                doprompt = 0;
12621        }
12622
12623        n = list(2);
12624
12625        if (oldstyle)
12626                doprompt = saveprompt;
12627        else if (readtoken() != TRP)
12628                raise_error_unexpected_syntax(TRP);
12629
12630        (*nlpp)->n = n;
12631        if (oldstyle) {
12632                /*
12633                 * Start reading from old file again, ignoring any pushed back
12634                 * tokens left from the backquote parsing
12635                 */
12636                popfile();
12637                tokpushback = 0;
12638        }
12639        while (stackblocksize() <= savelen)
12640                growstackblock();
12641        STARTSTACKSTR(out);
12642        if (str) {
12643                memcpy(out, str, savelen);
12644                STADJUST(savelen, out);
12645        }
12646        USTPUTC(CTLBACKQ, out);
12647        if (oldstyle)
12648                goto parsebackq_oldreturn;
12649        goto parsebackq_newreturn;
12650}
12651
12652#if ENABLE_FEATURE_SH_MATH
12653/*
12654 * Parse an arithmetic expansion (indicate start of one and set state)
12655 */
12656parsearith: {
12657
12658        synstack_push(&synstack,
12659                        synstack->prev ?: alloca(sizeof(*synstack)),
12660                        ARISYNTAX);
12661        synstack->dblquote = 1;
12662        USTPUTC(CTLARI, out);
12663        goto parsearith_return;
12664}
12665#endif
12666} /* end of readtoken */
12667
12668/*
12669 * Read the next input token.
12670 * If the token is a word, we set backquotelist to the list of cmds in
12671 *      backquotes.  We set quoteflag to true if any part of the word was
12672 *      quoted.
12673 * If the token is TREDIR, then we set redirnode to a structure containing
12674 *      the redirection.
12675 *
12676 * [Change comment:  here documents and internal procedures]
12677 * [Readtoken shouldn't have any arguments.  Perhaps we should make the
12678 *  word parsing code into a separate routine.  In this case, readtoken
12679 *  doesn't need to have any internal procedures, but parseword does.
12680 *  We could also make parseoperator in essence the main routine, and
12681 *  have parseword (readtoken1?) handle both words and redirection.]
12682 */
12683#define NEW_xxreadtoken
12684#ifdef NEW_xxreadtoken
12685/* singles must be first! */
12686static const char xxreadtoken_chars[7] ALIGN1 = {
12687        '\n', '(', ')', /* singles */
12688        '&', '|', ';',  /* doubles */
12689        0
12690};
12691
12692#define xxreadtoken_singles 3
12693#define xxreadtoken_doubles 3
12694
12695static const char xxreadtoken_tokens[] ALIGN1 = {
12696        TNL, TLP, TRP,          /* only single occurrence allowed */
12697        TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12698        TEOF,                   /* corresponds to trailing nul */
12699        TAND, TOR, TENDCASE     /* if double occurrence */
12700};
12701
12702static int
12703xxreadtoken(void)
12704{
12705        int c;
12706
12707        if (tokpushback) {
12708                tokpushback = 0;
12709                return lasttoken;
12710        }
12711        setprompt_if(needprompt, 2);
12712        for (;;) {                      /* until token or start of word found */
12713                c = pgetc_eatbnl();
12714                if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
12715                        continue;
12716
12717                if (c == '#') {
12718                        while ((c = pgetc()) != '\n' && c != PEOF)
12719                                continue;
12720                        pungetc();
12721                } else if (c == '\\') {
12722                        break; /* return readtoken1(...) */
12723                } else {
12724                        const char *p;
12725
12726                        p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12727                        if (c != PEOF) {
12728                                if (c == '\n') {
12729                                        nlnoprompt();
12730                                }
12731
12732                                p = strchr(xxreadtoken_chars, c);
12733                                if (p == NULL)
12734                                        break; /* return readtoken1(...) */
12735
12736                                if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12737                                        int cc = pgetc_eatbnl();
12738                                        if (cc == c) {    /* double occurrence? */
12739                                                p += xxreadtoken_doubles + 1;
12740                                        } else {
12741                                                pungetc();
12742#if BASH_REDIR_OUTPUT
12743                                                if (c == '&' && cc == '>') /* &> */
12744                                                        break; /* return readtoken1(...) */
12745#endif
12746                                        }
12747                                }
12748                        }
12749                        lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12750                        return lasttoken;
12751                }
12752        } /* for (;;) */
12753
12754        return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
12755}
12756#else /* old xxreadtoken */
12757#define RETURN(token)   return lasttoken = token
12758static int
12759xxreadtoken(void)
12760{
12761        int c;
12762
12763        if (tokpushback) {
12764                tokpushback = 0;
12765                return lasttoken;
12766        }
12767        setprompt_if(needprompt, 2);
12768        for (;;) {      /* until token or start of word found */
12769                c = pgetc_eatbnl();
12770                switch (c) {
12771                case ' ': case '\t':
12772                IF_ASH_ALIAS(case PEOA:)
12773                        continue;
12774                case '#':
12775                        while ((c = pgetc()) != '\n' && c != PEOF)
12776                                continue;
12777                        pungetc();
12778                        continue;
12779                case '\n':
12780                        nlnoprompt();
12781                        RETURN(TNL);
12782                case PEOF:
12783                        RETURN(TEOF);
12784                case '&':
12785                        if (pgetc_eatbnl() == '&')
12786                                RETURN(TAND);
12787                        pungetc();
12788                        RETURN(TBACKGND);
12789                case '|':
12790                        if (pgetc_eatbnl() == '|')
12791                                RETURN(TOR);
12792                        pungetc();
12793                        RETURN(TPIPE);
12794                case ';':
12795                        if (pgetc_eatbnl() == ';')
12796                                RETURN(TENDCASE);
12797                        pungetc();
12798                        RETURN(TSEMI);
12799                case '(':
12800                        RETURN(TLP);
12801                case ')':
12802                        RETURN(TRP);
12803                }
12804                break;
12805        }
12806        return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12807#undef RETURN
12808}
12809#endif /* old xxreadtoken */
12810
12811static int
12812readtoken(void)
12813{
12814        int t;
12815        int kwd = checkkwd;
12816#if DEBUG
12817        smallint alreadyseen = tokpushback;
12818#endif
12819
12820#if ENABLE_ASH_ALIAS
12821 top:
12822#endif
12823
12824        t = xxreadtoken();
12825
12826        /*
12827         * eat newlines
12828         */
12829        if (kwd & CHKNL) {
12830                while (t == TNL) {
12831                        parseheredoc();
12832                        t = xxreadtoken();
12833                }
12834        }
12835
12836        if (t != TWORD || quoteflag) {
12837                goto out;
12838        }
12839
12840        /*
12841         * check for keywords
12842         */
12843        if (kwd & CHKKWD) {
12844                const char *const *pp;
12845
12846                pp = findkwd(wordtext);
12847                if (pp) {
12848                        lasttoken = t = pp - tokname_array;
12849                        TRACE(("keyword '%s' recognized\n", tokname_array[t]));
12850                        goto out;
12851                }
12852        }
12853
12854        if (checkkwd & CHKALIAS) {
12855#if ENABLE_ASH_ALIAS
12856                struct alias *ap;
12857                ap = lookupalias(wordtext, 1);
12858                if (ap != NULL) {
12859                        if (*ap->val) {
12860                                pushstring(ap->val, ap);
12861                        }
12862                        goto top;
12863                }
12864#endif
12865        }
12866 out:
12867        checkkwd = 0;
12868#if DEBUG
12869        if (!alreadyseen)
12870                TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12871        else
12872                TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12873#endif
12874        return t;
12875}
12876
12877static int
12878peektoken(void)
12879{
12880        int t;
12881
12882        t = readtoken();
12883        tokpushback = 1;
12884        return t;
12885}
12886
12887/*
12888 * Read and parse a command.  Returns NODE_EOF on end of file.
12889 * (NULL is a valid parse tree indicating a blank line.)
12890 */
12891static union node *
12892parsecmd(int interact)
12893{
12894        tokpushback = 0;
12895        checkkwd = 0;
12896        heredoclist = 0;
12897        doprompt = interact;
12898        setprompt_if(doprompt, doprompt);
12899        needprompt = 0;
12900        return list(1);
12901}
12902
12903/*
12904 * Input any here documents.
12905 */
12906static void
12907parseheredoc(void)
12908{
12909        struct heredoc *here;
12910        union node *n;
12911
12912        here = heredoclist;
12913        heredoclist = NULL;
12914
12915        while (here) {
12916                setprompt_if(needprompt, 2);
12917                readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
12918                                here->eofmark, here->striptabs);
12919                n = stzalloc(sizeof(struct narg));
12920                n->narg.type = NARG;
12921                /*n->narg.next = NULL; - stzalloc did it */
12922                n->narg.text = wordtext;
12923                n->narg.backquote = backquotelist;
12924                here->here->nhere.doc = n;
12925                here = here->next;
12926        }
12927}
12928
12929
12930static const char *
12931expandstr(const char *ps, int syntax_type)
12932{
12933        union node n;
12934        int saveprompt;
12935
12936        /* XXX Fix (char *) cast. */
12937        setinputstring((char *)ps);
12938
12939        saveprompt = doprompt;
12940        doprompt = 0;
12941
12942        /* readtoken1() might die horribly.
12943         * Try a prompt with syntactically wrong command:
12944         * PS1='$(date "+%H:%M:%S) > '
12945         */
12946        {
12947                volatile int saveint;
12948                struct jmploc *volatile savehandler = exception_handler;
12949                struct jmploc jmploc;
12950                SAVE_INT(saveint);
12951                if (setjmp(jmploc.loc) == 0) {
12952                        exception_handler = &jmploc;
12953                        readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
12954                }
12955                exception_handler = savehandler;
12956                RESTORE_INT(saveint);
12957        }
12958
12959        doprompt = saveprompt;
12960
12961        popfile();
12962
12963        n.narg.type = NARG;
12964        n.narg.next = NULL;
12965        n.narg.text = wordtext;
12966        n.narg.backquote = backquotelist;
12967
12968        expandarg(&n, NULL, EXP_QUOTED);
12969        return stackblock();
12970}
12971
12972static inline int
12973parser_eof(void)
12974{
12975        return tokpushback && lasttoken == TEOF;
12976}
12977
12978/*
12979 * Execute a command or commands contained in a string.
12980 */
12981static int
12982evalstring(char *s, int flags)
12983{
12984        struct jmploc *volatile savehandler;
12985        struct jmploc jmploc;
12986        int ex;
12987
12988        union node *n;
12989        struct stackmark smark;
12990        int status;
12991
12992        s = sstrdup(s);
12993        setinputstring(s);
12994        setstackmark(&smark);
12995
12996        status = 0;
12997        /* On exception inside execution loop, we must popfile().
12998         * Try interactively:
12999         *      readonly a=a
13000         *      command eval "a=b"  # throws "is read only" error
13001         * "command BLTIN" is not supposed to abort (even in non-interactive use).
13002         * But if we skip popfile(), we hit EOF in eval's string, and exit.
13003         */
13004        savehandler = exception_handler;
13005        ex = setjmp(jmploc.loc);
13006        if (ex)
13007                goto out;
13008        exception_handler = &jmploc;
13009
13010        while ((n = parsecmd(0)) != NODE_EOF) {
13011                int i;
13012
13013                i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
13014                if (n)
13015                        status = i;
13016                popstackmark(&smark);
13017                if (evalskip)
13018                        break;
13019        }
13020 out:
13021        popstackmark(&smark);
13022        popfile();
13023        stunalloc(s);
13024
13025        exception_handler = savehandler;
13026        if (ex)
13027                longjmp(exception_handler->loc, ex);
13028
13029        return status;
13030}
13031
13032/*
13033 * The eval command.
13034 */
13035static int FAST_FUNC
13036evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
13037{
13038        char *p;
13039        char *concat;
13040
13041        if (argv[1]) {
13042                p = argv[1];
13043                argv += 2;
13044                if (argv[0]) {
13045                        STARTSTACKSTR(concat);
13046                        for (;;) {
13047                                concat = stack_putstr(p, concat);
13048                                p = *argv++;
13049                                if (p == NULL)
13050                                        break;
13051                                STPUTC(' ', concat);
13052                        }
13053                        STPUTC('\0', concat);
13054                        p = grabstackstr(concat);
13055                }
13056                return evalstring(p, flags & EV_TESTED);
13057        }
13058        return 0;
13059}
13060
13061/*
13062 * Read and execute commands.
13063 * "Top" is nonzero for the top level command loop;
13064 * it turns on prompting if the shell is interactive.
13065 */
13066static int
13067cmdloop(int top)
13068{
13069        union node *n;
13070        struct stackmark smark;
13071        int inter;
13072        int status = 0;
13073        int numeof = 0;
13074
13075        TRACE(("cmdloop(%d) called\n", top));
13076        for (;;) {
13077                int skip;
13078
13079                setstackmark(&smark);
13080#if JOBS
13081                if (doing_jobctl)
13082                        showjobs(SHOW_CHANGED|SHOW_STDERR);
13083#endif
13084                inter = 0;
13085                if (iflag && top) {
13086                        inter++;
13087                        chkmail();
13088                }
13089                n = parsecmd(inter);
13090#if DEBUG
13091                if (DEBUG > 2 && debug && (n != NODE_EOF))
13092                        showtree(n);
13093#endif
13094                if (n == NODE_EOF) {
13095                        if (!top || numeof >= 50)
13096                                break;
13097                        if (!stoppedjobs()) {
13098                                if (!Iflag)
13099                                        break;
13100                                out2str("\nUse \"exit\" to leave shell.\n");
13101                        }
13102                        numeof++;
13103                } else if (nflag == 0) {
13104                        int i;
13105
13106                        /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13107                        job_warning >>= 1;
13108                        numeof = 0;
13109                        i = evaltree(n, 0);
13110                        if (n)
13111                                status = i;
13112                }
13113                popstackmark(&smark);
13114                skip = evalskip;
13115
13116                if (skip) {
13117                        evalskip &= ~SKIPFUNC;
13118                        break;
13119                }
13120        }
13121        return status;
13122}
13123
13124/*
13125 * Take commands from a file.  To be compatible we should do a path
13126 * search for the file, which is necessary to find sub-commands.
13127 */
13128static char *
13129find_dot_file(char *name)
13130{
13131        char *fullname;
13132        const char *path = pathval();
13133        struct stat statb;
13134
13135        /* don't try this for absolute or relative paths */
13136        if (strchr(name, '/'))
13137                return name;
13138
13139        while ((fullname = path_advance(&path, name)) != NULL) {
13140                if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
13141                        /*
13142                         * Don't bother freeing here, since it will
13143                         * be freed by the caller.
13144                         */
13145                        return fullname;
13146                }
13147                if (fullname != name)
13148                        stunalloc(fullname);
13149        }
13150        /* not found in PATH */
13151
13152#if ENABLE_ASH_BASH_SOURCE_CURDIR
13153        return name;
13154#else
13155        ash_msg_and_raise_error("%s: not found", name);
13156        /* NOTREACHED */
13157#endif
13158}
13159
13160static int FAST_FUNC
13161dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
13162{
13163        /* "false; . empty_file; echo $?" should print 0, not 1: */
13164        int status = 0;
13165        char *fullname;
13166        char **argv;
13167        char *args_need_save;
13168        volatile struct shparam saveparam;
13169
13170//???
13171//      struct strlist *sp;
13172//      for (sp = cmdenviron; sp; sp = sp->next)
13173//              setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
13174
13175        nextopt(nullstr); /* handle possible "--" */
13176        argv = argptr;
13177
13178        if (!argv[0]) {
13179                /* bash says: "bash: .: filename argument required" */
13180                return 2; /* bash compat */
13181        }
13182
13183        /* This aborts if file isn't found, which is POSIXly correct.
13184         * bash returns exitcode 1 instead.
13185         */
13186        fullname = find_dot_file(argv[0]);
13187        argv++;
13188        args_need_save = argv[0];
13189        if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
13190                int argc;
13191                saveparam = shellparam;
13192                shellparam.malloced = 0;
13193                argc = 1;
13194                while (argv[argc])
13195                        argc++;
13196                shellparam.nparam = argc;
13197                shellparam.p = argv;
13198        };
13199
13200        /* This aborts if file can't be opened, which is POSIXly correct.
13201         * bash returns exitcode 1 instead.
13202         */
13203        setinputfile(fullname, INPUT_PUSH_FILE);
13204        commandname = fullname;
13205        status = cmdloop(0);
13206        popfile();
13207
13208        if (args_need_save) {
13209                freeparam(&shellparam);
13210                shellparam = saveparam;
13211        };
13212
13213        return status;
13214}
13215
13216static int FAST_FUNC
13217exitcmd(int argc UNUSED_PARAM, char **argv)
13218{
13219        if (stoppedjobs())
13220                return 0;
13221        if (argv[1])
13222                exitstatus = number(argv[1]);
13223        raise_exception(EXEXIT);
13224        /* NOTREACHED */
13225}
13226
13227/*
13228 * Read a file containing shell functions.
13229 */
13230static void
13231readcmdfile(char *name)
13232{
13233        setinputfile(name, INPUT_PUSH_FILE);
13234        cmdloop(0);
13235        popfile();
13236}
13237
13238
13239/* ============ find_command inplementation */
13240
13241/*
13242 * Resolve a command name.  If you change this routine, you may have to
13243 * change the shellexec routine as well.
13244 */
13245static void
13246find_command(char *name, struct cmdentry *entry, int act, const char *path)
13247{
13248        struct tblentry *cmdp;
13249        int idx;
13250        int prev;
13251        char *fullname;
13252        struct stat statb;
13253        int e;
13254        int updatetbl;
13255        struct builtincmd *bcmd;
13256
13257        /* If name contains a slash, don't use PATH or hash table */
13258        if (strchr(name, '/') != NULL) {
13259                entry->u.index = -1;
13260                if (act & DO_ABS) {
13261                        while (stat(name, &statb) < 0) {
13262#ifdef SYSV
13263                                if (errno == EINTR)
13264                                        continue;
13265#endif
13266                                entry->cmdtype = CMDUNKNOWN;
13267                                return;
13268                        }
13269                }
13270                entry->cmdtype = CMDNORMAL;
13271                return;
13272        }
13273
13274/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
13275
13276        updatetbl = (path == pathval());
13277        if (!updatetbl) {
13278                act |= DO_ALTPATH;
13279                if (strstr(path, "%builtin") != NULL)
13280                        act |= DO_ALTBLTIN;
13281        }
13282
13283        /* If name is in the table, check answer will be ok */
13284        cmdp = cmdlookup(name, 0);
13285        if (cmdp != NULL) {
13286                int bit;
13287
13288                switch (cmdp->cmdtype) {
13289                default:
13290#if DEBUG
13291                        abort();
13292#endif
13293                case CMDNORMAL:
13294                        bit = DO_ALTPATH;
13295                        break;
13296                case CMDFUNCTION:
13297                        bit = DO_NOFUNC;
13298                        break;
13299                case CMDBUILTIN:
13300                        bit = DO_ALTBLTIN;
13301                        break;
13302                }
13303                if (act & bit) {
13304                        updatetbl = 0;
13305                        cmdp = NULL;
13306                } else if (cmdp->rehash == 0)
13307                        /* if not invalidated by cd, we're done */
13308                        goto success;
13309        }
13310
13311        /* If %builtin not in path, check for builtin next */
13312        bcmd = find_builtin(name);
13313        if (bcmd) {
13314                if (IS_BUILTIN_REGULAR(bcmd))
13315                        goto builtin_success;
13316                if (act & DO_ALTPATH) {
13317                        if (!(act & DO_ALTBLTIN))
13318                                goto builtin_success;
13319                } else if (builtinloc <= 0) {
13320                        goto builtin_success;
13321                }
13322        }
13323
13324#if ENABLE_FEATURE_SH_STANDALONE
13325        {
13326                int applet_no = find_applet_by_name(name);
13327                if (applet_no >= 0) {
13328                        entry->cmdtype = CMDNORMAL;
13329                        entry->u.index = -2 - applet_no;
13330                        return;
13331                }
13332        }
13333#endif
13334
13335        /* We have to search path. */
13336        prev = -1;              /* where to start */
13337        if (cmdp && cmdp->rehash) {     /* doing a rehash */
13338                if (cmdp->cmdtype == CMDBUILTIN)
13339                        prev = builtinloc;
13340                else
13341                        prev = cmdp->param.index;
13342        }
13343
13344        e = ENOENT;
13345        idx = -1;
13346 loop:
13347        while ((fullname = path_advance(&path, name)) != NULL) {
13348                stunalloc(fullname);
13349                /* NB: code below will still use fullname
13350                 * despite it being "unallocated" */
13351                idx++;
13352                if (pathopt) {
13353                        if (prefix(pathopt, "builtin")) {
13354                                if (bcmd)
13355                                        goto builtin_success;
13356                                continue;
13357                        }
13358                        if ((act & DO_NOFUNC)
13359                         || !prefix(pathopt, "func")
13360                        ) {     /* ignore unimplemented options */
13361                                continue;
13362                        }
13363                }
13364                /* if rehash, don't redo absolute path names */
13365                if (fullname[0] == '/' && idx <= prev) {
13366                        if (idx < prev)
13367                                continue;
13368                        TRACE(("searchexec \"%s\": no change\n", name));
13369                        goto success;
13370                }
13371                while (stat(fullname, &statb) < 0) {
13372#ifdef SYSV
13373                        if (errno == EINTR)
13374                                continue;
13375#endif
13376                        if (errno != ENOENT && errno != ENOTDIR)
13377                                e = errno;
13378                        goto loop;
13379                }
13380                e = EACCES;     /* if we fail, this will be the error */
13381                if (!S_ISREG(statb.st_mode))
13382                        continue;
13383                if (pathopt) {          /* this is a %func directory */
13384                        stalloc(strlen(fullname) + 1);
13385                        /* NB: stalloc will return space pointed by fullname
13386                         * (because we don't have any intervening allocations
13387                         * between stunalloc above and this stalloc) */
13388                        readcmdfile(fullname);
13389                        cmdp = cmdlookup(name, 0);
13390                        if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13391                                ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13392                        stunalloc(fullname);
13393                        goto success;
13394                }
13395                TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13396                if (!updatetbl) {
13397                        entry->cmdtype = CMDNORMAL;
13398                        entry->u.index = idx;
13399                        return;
13400                }
13401                INT_OFF;
13402                cmdp = cmdlookup(name, 1);
13403                cmdp->cmdtype = CMDNORMAL;
13404                cmdp->param.index = idx;
13405                INT_ON;
13406                goto success;
13407        }
13408
13409        /* We failed.  If there was an entry for this command, delete it */
13410        if (cmdp && updatetbl)
13411                delete_cmd_entry();
13412        if (act & DO_ERR) {
13413#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13414                struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13415                if (hookp && hookp->cmdtype == CMDFUNCTION) {
13416                        char *argv[3];
13417                        argv[0] = (char*) "command_not_found_handle";
13418                        argv[1] = name;
13419                        argv[2] = NULL;
13420                        evalfun(hookp->param.func, 2, argv, 0);
13421                        entry->cmdtype = CMDUNKNOWN;
13422                        return;
13423                }
13424#endif
13425                ash_msg("%s: %s", name, errmsg(e, "not found"));
13426        }
13427        entry->cmdtype = CMDUNKNOWN;
13428        return;
13429
13430 builtin_success:
13431        if (!updatetbl) {
13432                entry->cmdtype = CMDBUILTIN;
13433                entry->u.cmd = bcmd;
13434                return;
13435        }
13436        INT_OFF;
13437        cmdp = cmdlookup(name, 1);
13438        cmdp->cmdtype = CMDBUILTIN;
13439        cmdp->param.cmd = bcmd;
13440        INT_ON;
13441 success:
13442        cmdp->rehash = 0;
13443        entry->cmdtype = cmdp->cmdtype;
13444        entry->u = cmdp->param;
13445}
13446
13447
13448/*
13449 * The trap builtin.
13450 */
13451static int FAST_FUNC
13452trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13453{
13454        char *action;
13455        char **ap;
13456        int signo, exitcode;
13457
13458        nextopt(nullstr);
13459        ap = argptr;
13460        if (!*ap) {
13461                for (signo = 0; signo < NSIG; signo++) {
13462                        char *tr = trap_ptr[signo];
13463                        if (tr) {
13464                                /* note: bash adds "SIG", but only if invoked
13465                                 * as "bash". If called as "sh", or if set -o posix,
13466                                 * then it prints short signal names.
13467                                 * We are printing short names: */
13468                                out1fmt("trap -- %s %s\n",
13469                                                single_quote(tr),
13470                                                get_signame(signo));
13471                /* trap_ptr != trap only if we are in special-cased `trap` code.
13472                 * In this case, we will exit very soon, no need to free(). */
13473                                /* if (trap_ptr != trap && tp[0]) */
13474                                /*      free(tr); */
13475                        }
13476                }
13477                /*
13478                if (trap_ptr != trap) {
13479                        free(trap_ptr);
13480                        trap_ptr = trap;
13481                }
13482                */
13483                return 0;
13484        }
13485
13486        /* Why the second check?
13487         * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13488         * In this case, NUM is signal no, not an action.
13489         */
13490        action = NULL;
13491        if (ap[1] && !is_number(ap[0]))
13492                action = *ap++;
13493
13494        exitcode = 0;
13495        while (*ap) {
13496                signo = get_signum(*ap);
13497                if (signo < 0) {
13498                        /* Mimic bash message exactly */
13499                        ash_msg("%s: invalid signal specification", *ap);
13500                        exitcode = 1;
13501                        goto next;
13502                }
13503                INT_OFF;
13504                if (action) {
13505                        if (LONE_DASH(action))
13506                                action = NULL;
13507                        else {
13508                                if (action[0]) /* not NULL and not "" and not "-" */
13509                                        may_have_traps = 1;
13510                                action = ckstrdup(action);
13511                        }
13512                }
13513                free(trap[signo]);
13514                trap[signo] = action;
13515                if (signo != 0)
13516                        setsignal(signo);
13517                INT_ON;
13518 next:
13519                ap++;
13520        }
13521        return exitcode;
13522}
13523
13524
13525/* ============ Builtins */
13526
13527#if ENABLE_ASH_HELP
13528static int FAST_FUNC
13529helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13530{
13531        unsigned col;
13532        unsigned i;
13533
13534        out1fmt(
13535                "Built-in commands:\n"
13536                "------------------\n");
13537        for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
13538                col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
13539                                        builtintab[i].name + 1);
13540                if (col > 60) {
13541                        out1fmt("\n");
13542                        col = 0;
13543                }
13544        }
13545# if ENABLE_FEATURE_SH_STANDALONE
13546        {
13547                const char *a = applet_names;
13548                while (*a) {
13549                        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13550                        if (col > 60) {
13551                                out1fmt("\n");
13552                                col = 0;
13553                        }
13554                        while (*a++ != '\0')
13555                                continue;
13556                }
13557        }
13558# endif
13559        newline_and_flush(stdout);
13560        return EXIT_SUCCESS;
13561}
13562#endif
13563
13564#if MAX_HISTORY
13565static int FAST_FUNC
13566historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13567{
13568        show_history(line_input_state);
13569        return EXIT_SUCCESS;
13570}
13571#endif
13572
13573/*
13574 * The export and readonly commands.
13575 */
13576static int FAST_FUNC
13577exportcmd(int argc UNUSED_PARAM, char **argv)
13578{
13579        struct var *vp;
13580        char *name;
13581        const char *p;
13582        char **aptr;
13583        char opt;
13584        int flag;
13585        int flag_off;
13586
13587        /* "readonly" in bash accepts, but ignores -n.
13588         * We do the same: it saves a conditional in nextopt's param.
13589         */
13590        flag_off = 0;
13591        while ((opt = nextopt("np")) != '\0') {
13592                if (opt == 'n')
13593                        flag_off = VEXPORT;
13594        }
13595        flag = VEXPORT;
13596        if (argv[0][0] == 'r') {
13597                flag = VREADONLY;
13598                flag_off = 0; /* readonly ignores -n */
13599        }
13600        flag_off = ~flag_off;
13601
13602        /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
13603        {
13604                aptr = argptr;
13605                name = *aptr;
13606                if (name) {
13607                        do {
13608                                p = strchr(name, '=');
13609                                if (p != NULL) {
13610                                        p++;
13611                                } else {
13612                                        vp = *findvar(hashvar(name), name);
13613                                        if (vp) {
13614                                                vp->flags = ((vp->flags | flag) & flag_off);
13615                                                continue;
13616                                        }
13617                                }
13618                                setvar(name, p, (flag & flag_off));
13619                        } while ((name = *++aptr) != NULL);
13620                        return 0;
13621                }
13622        }
13623
13624        /* No arguments. Show the list of exported or readonly vars.
13625         * -n is ignored.
13626         */
13627        showvars(argv[0], flag, 0);
13628        return 0;
13629}
13630
13631/*
13632 * Delete a function if it exists.
13633 */
13634static void
13635unsetfunc(const char *name)
13636{
13637        struct tblentry *cmdp;
13638
13639        cmdp = cmdlookup(name, 0);
13640        if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
13641                delete_cmd_entry();
13642}
13643
13644/*
13645 * The unset builtin command.  We unset the function before we unset the
13646 * variable to allow a function to be unset when there is a readonly variable
13647 * with the same name.
13648 */
13649static int FAST_FUNC
13650unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13651{
13652        char **ap;
13653        int i;
13654        int flag = 0;
13655
13656        while ((i = nextopt("vf")) != 0) {
13657                flag = i;
13658        }
13659
13660        for (ap = argptr; *ap; ap++) {
13661                if (flag != 'f') {
13662                        unsetvar(*ap);
13663                        continue;
13664                }
13665                if (flag != 'v')
13666                        unsetfunc(*ap);
13667        }
13668        return 0;
13669}
13670
13671static const unsigned char timescmd_str[] ALIGN1 = {
13672        ' ',  offsetof(struct tms, tms_utime),
13673        '\n', offsetof(struct tms, tms_stime),
13674        ' ',  offsetof(struct tms, tms_cutime),
13675        '\n', offsetof(struct tms, tms_cstime),
13676        0
13677};
13678static int FAST_FUNC
13679timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13680{
13681        unsigned clk_tck;
13682        const unsigned char *p;
13683        struct tms buf;
13684
13685        clk_tck = bb_clk_tck();
13686
13687        times(&buf);
13688        p = timescmd_str;
13689        do {
13690                unsigned sec, frac;
13691                unsigned long t;
13692                t = *(clock_t *)(((char *) &buf) + p[1]);
13693                sec = t / clk_tck;
13694                frac = t % clk_tck;
13695                out1fmt("%um%u.%03us%c",
13696                        sec / 60, sec % 60,
13697                        (frac * 1000) / clk_tck,
13698                        p[0]);
13699                p += 2;
13700        } while (*p);
13701
13702        return 0;
13703}
13704
13705#if ENABLE_FEATURE_SH_MATH
13706/*
13707 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
13708 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
13709 *
13710 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13711 */
13712static int FAST_FUNC
13713letcmd(int argc UNUSED_PARAM, char **argv)
13714{
13715        arith_t i;
13716
13717        argv++;
13718        if (!*argv)
13719                ash_msg_and_raise_error("expression expected");
13720        do {
13721                i = ash_arith(*argv);
13722        } while (*++argv);
13723
13724        return !i;
13725}
13726#endif
13727
13728/*
13729 * The read builtin. Options:
13730 *      -r              Do not interpret '\' specially
13731 *      -s              Turn off echo (tty only)
13732 *      -n NCHARS       Read NCHARS max
13733 *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
13734 *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
13735 *      -u FD           Read from given FD instead of fd 0
13736 *      -d DELIM        End on DELIM char, not newline
13737 * This uses unbuffered input, which may be avoidable in some cases.
13738 * TODO: bash also has:
13739 *      -a ARRAY        Read into array[0],[1],etc
13740 *      -e              Use line editing (tty only)
13741 */
13742static int FAST_FUNC
13743readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13744{
13745        char *opt_n = NULL;
13746        char *opt_p = NULL;
13747        char *opt_t = NULL;
13748        char *opt_u = NULL;
13749        char *opt_d = NULL; /* optimized out if !BASH */
13750        int read_flags = 0;
13751        const char *r;
13752        int i;
13753
13754        while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
13755                switch (i) {
13756                case 'p':
13757                        opt_p = optionarg;
13758                        break;
13759                case 'n':
13760                        opt_n = optionarg;
13761                        break;
13762                case 's':
13763                        read_flags |= BUILTIN_READ_SILENT;
13764                        break;
13765                case 't':
13766                        opt_t = optionarg;
13767                        break;
13768                case 'r':
13769                        read_flags |= BUILTIN_READ_RAW;
13770                        break;
13771                case 'u':
13772                        opt_u = optionarg;
13773                        break;
13774#if BASH_READ_D
13775                case 'd':
13776                        opt_d = optionarg;
13777                        break;
13778#endif
13779                default:
13780                        break;
13781                }
13782        }
13783
13784        /* "read -s" needs to save/restore termios, can't allow ^C
13785         * to jump out of it.
13786         */
13787 again:
13788        INT_OFF;
13789        r = shell_builtin_read(setvar0,
13790                argptr,
13791                bltinlookup("IFS"), /* can be NULL */
13792                read_flags,
13793                opt_n,
13794                opt_p,
13795                opt_t,
13796                opt_u,
13797                opt_d
13798        );
13799        INT_ON;
13800
13801        if ((uintptr_t)r == 1 && errno == EINTR) {
13802                /* To get SIGCHLD: sleep 1 & read x; echo $x
13803                 * Correct behavior is to not exit "read"
13804                 */
13805                if (pending_sig == 0)
13806                        goto again;
13807        }
13808
13809        if ((uintptr_t)r > 1)
13810                ash_msg_and_raise_error(r);
13811
13812        return (uintptr_t)r;
13813}
13814
13815static int FAST_FUNC
13816umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13817{
13818        static const char permuser[3] ALIGN1 = "ogu";
13819
13820        mode_t mask;
13821        int symbolic_mode = 0;
13822
13823        while (nextopt("S") != '\0') {
13824                symbolic_mode = 1;
13825        }
13826
13827        INT_OFF;
13828        mask = umask(0);
13829        umask(mask);
13830        INT_ON;
13831
13832        if (*argptr == NULL) {
13833                if (symbolic_mode) {
13834                        char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
13835                        char *p = buf;
13836                        int i;
13837
13838                        i = 2;
13839                        for (;;) {
13840                                *p++ = ',';
13841                                *p++ = permuser[i];
13842                                *p++ = '=';
13843                                /* mask is 0..0uuugggooo. i=2 selects uuu bits */
13844                                if (!(mask & 0400)) *p++ = 'r';
13845                                if (!(mask & 0200)) *p++ = 'w';
13846                                if (!(mask & 0100)) *p++ = 'x';
13847                                mask <<= 3;
13848                                if (--i < 0)
13849                                        break;
13850                        }
13851                        *p = '\0';
13852                        puts(buf + 1);
13853                } else {
13854                        out1fmt("%04o\n", mask);
13855                }
13856        } else {
13857                char *modestr = *argptr;
13858                /* numeric umasks are taken as-is */
13859                /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13860                if (!isdigit(modestr[0]))
13861                        mask ^= 0777;
13862                mask = bb_parse_mode(modestr, mask);
13863                if ((unsigned)mask > 0777) {
13864                        ash_msg_and_raise_error("illegal mode: %s", modestr);
13865                }
13866                if (!isdigit(modestr[0]))
13867                        mask ^= 0777;
13868                umask(mask);
13869        }
13870        return 0;
13871}
13872
13873static int FAST_FUNC
13874ulimitcmd(int argc UNUSED_PARAM, char **argv)
13875{
13876        return shell_builtin_ulimit(argv);
13877}
13878
13879/* ============ main() and helpers */
13880
13881/*
13882 * Called to exit the shell.
13883 */
13884static void
13885exitshell(void)
13886{
13887        struct jmploc loc;
13888        char *p;
13889        int status;
13890
13891#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13892        save_history(line_input_state);
13893#endif
13894        status = exitstatus;
13895        TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13896        if (setjmp(loc.loc)) {
13897                if (exception_type == EXEXIT)
13898                        status = exitstatus;
13899                goto out;
13900        }
13901        exception_handler = &loc;
13902        p = trap[0];
13903        if (p) {
13904                trap[0] = NULL;
13905                evalskip = 0;
13906                evalstring(p, 0);
13907                /*free(p); - we'll exit soon */
13908        }
13909 out:
13910        /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13911         * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13912         */
13913        setjobctl(0);
13914        flush_stdout_stderr();
13915        _exit(status);
13916        /* NOTREACHED */
13917}
13918
13919/* Don't inline: conserve stack of caller from having our locals too */
13920static NOINLINE void
13921init(void)
13922{
13923        /* we will never free this */
13924        basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
13925        basepf.linno = 1;
13926
13927        sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
13928        setsignal(SIGCHLD);
13929
13930        /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13931         * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13932         */
13933        signal(SIGHUP, SIG_DFL);
13934
13935        {
13936                char **envp;
13937                const char *p;
13938
13939                initvar();
13940                for (envp = environ; envp && *envp; envp++) {
13941/* Used to have
13942 *                      p = endofname(*envp);
13943 *                      if (p != *envp && *p == '=') {
13944 * here to weed out badly-named variables, but this breaks
13945 * scenarios where people do want them passed to children:
13946 * import os
13947 * os.environ["test-test"]="test"
13948 * if os.fork() == 0:
13949 *   os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ])  # fixes this
13950 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])  # breaks this
13951 */
13952                        if (strchr(*envp, '=')) {
13953                                setvareq(*envp, VEXPORT|VTEXTFIXED);
13954                        }
13955                }
13956
13957                setvareq((char*)defoptindvar, VTEXTFIXED);
13958
13959                setvar0("PPID", utoa(getppid()));
13960#if BASH_SHLVL_VAR
13961                p = lookupvar("SHLVL");
13962                setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
13963#endif
13964#if BASH_HOSTNAME_VAR
13965                if (!lookupvar("HOSTNAME")) {
13966                        struct utsname uts;
13967                        uname(&uts);
13968                        setvar0("HOSTNAME", uts.nodename);
13969                }
13970#endif
13971                p = lookupvar("PWD");
13972                if (p) {
13973                        struct stat st1, st2;
13974                        if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
13975                         || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13976                        ) {
13977                                p = NULL;
13978                        }
13979                }
13980                setpwd(p, 0);
13981        }
13982}
13983
13984
13985//usage:#define ash_trivial_usage
13986//usage:        "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
13987//usage:#define ash_full_usage "\n\n"
13988//usage:        "Unix shell interpreter"
13989
13990/*
13991 * Process the shell command line arguments.
13992 */
13993static int
13994procargs(char **argv)
13995{
13996        int i;
13997        const char *xminusc;
13998        char **xargv;
13999        int login_sh;
14000
14001        xargv = argv;
14002        login_sh = xargv[0] && xargv[0][0] == '-';
14003        arg0 = xargv[0];
14004        /* if (xargv[0]) - mmm, this is always true! */
14005                xargv++;
14006        for (i = 0; i < NOPTS; i++)
14007                optlist[i] = 2;
14008        argptr = xargv;
14009        if (options(/*cmdline:*/ 1, &login_sh)) {
14010                /* it already printed err message */
14011                raise_exception(EXERROR);
14012        }
14013        xargv = argptr;
14014        xminusc = minusc;
14015        if (*xargv == NULL) {
14016                if (xminusc)
14017                        ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14018                sflag = 1;
14019        }
14020        if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
14021                iflag = 1;
14022        if (mflag == 2)
14023                mflag = iflag;
14024        for (i = 0; i < NOPTS; i++)
14025                if (optlist[i] == 2)
14026                        optlist[i] = 0;
14027#if DEBUG == 2
14028        debug = 1;
14029#endif
14030        /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
14031        if (xminusc) {
14032                minusc = *xargv++;
14033                if (*xargv)
14034                        goto setarg0;
14035        } else if (!sflag) {
14036                setinputfile(*xargv, 0);
14037 setarg0:
14038                arg0 = *xargv++;
14039                commandname = arg0;
14040        }
14041
14042        shellparam.p = xargv;
14043#if ENABLE_ASH_GETOPTS
14044        shellparam.optind = 1;
14045        shellparam.optoff = -1;
14046#endif
14047        /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
14048        while (*xargv) {
14049                shellparam.nparam++;
14050                xargv++;
14051        }
14052        optschanged();
14053
14054        return login_sh;
14055}
14056
14057/*
14058 * Read /etc/profile, ~/.profile, $ENV.
14059 */
14060static void
14061read_profile(const char *name)
14062{
14063        name = expandstr(name, DQSYNTAX);
14064        if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14065                return;
14066        cmdloop(0);
14067        popfile();
14068}
14069
14070/*
14071 * This routine is called when an error or an interrupt occurs in an
14072 * interactive shell and control is returned to the main command loop.
14073 * (In dash, this function is auto-generated by build machinery).
14074 */
14075static void
14076reset(void)
14077{
14078        /* from eval.c: */
14079        evalskip = 0;
14080        loopnest = 0;
14081
14082        /* from expand.c: */
14083        ifsfree();
14084
14085        /* from input.c: */
14086        g_parsefile->left_in_buffer = 0;
14087        g_parsefile->left_in_line = 0;      /* clear input buffer */
14088        popallfiles();
14089
14090        /* from redir.c: */
14091        unwindredir(NULL);
14092
14093        /* from var.c: */
14094        unwindlocalvars(NULL);
14095}
14096
14097#if PROFILE
14098static short profile_buf[16384];
14099extern int etext();
14100#endif
14101
14102/*
14103 * Main routine.  We initialize things, parse the arguments, execute
14104 * profiles if we're a login shell, and then call cmdloop to execute
14105 * commands.  The setjmp call sets up the location to jump to when an
14106 * exception occurs.  When an exception occurs the variable "state"
14107 * is used to figure out how far we had gotten.
14108 */
14109int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14110int ash_main(int argc UNUSED_PARAM, char **argv)
14111{
14112        volatile smallint state;
14113        struct jmploc jmploc;
14114        struct stackmark smark;
14115        int login_sh;
14116
14117        /* Initialize global data */
14118        INIT_G_misc();
14119        INIT_G_memstack();
14120        INIT_G_var();
14121#if ENABLE_ASH_ALIAS
14122        INIT_G_alias();
14123#endif
14124        INIT_G_cmdtable();
14125
14126#if PROFILE
14127        monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14128#endif
14129
14130#if ENABLE_FEATURE_EDITING
14131        line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
14132#endif
14133        state = 0;
14134        if (setjmp(jmploc.loc)) {
14135                smallint e;
14136                smallint s;
14137
14138                reset();
14139
14140                e = exception_type;
14141                s = state;
14142                if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
14143                        exitshell();
14144                }
14145                if (e == EXINT) {
14146                        newline_and_flush(stderr);
14147                }
14148
14149                popstackmark(&smark);
14150                FORCE_INT_ON; /* enable interrupts */
14151                if (s == 1)
14152                        goto state1;
14153                if (s == 2)
14154                        goto state2;
14155                if (s == 3)
14156                        goto state3;
14157                goto state4;
14158        }
14159        exception_handler = &jmploc;
14160        rootpid = getpid();
14161
14162        init();
14163        setstackmark(&smark);
14164        login_sh = procargs(argv);
14165#if DEBUG
14166        TRACE(("Shell args: "));
14167        trace_puts_args(argv);
14168#endif
14169
14170        if (login_sh) {
14171                const char *hp;
14172
14173                state = 1;
14174                read_profile("/etc/profile");
14175 state1:
14176                state = 2;
14177                hp = lookupvar("HOME");
14178                if (hp)
14179                        read_profile("$HOME/.profile");
14180        }
14181 state2:
14182        state = 3;
14183        if (
14184#ifndef linux
14185         getuid() == geteuid() && getgid() == getegid() &&
14186#endif
14187         iflag
14188        ) {
14189                const char *shinit = lookupvar("ENV");
14190                if (shinit != NULL && *shinit != '\0')
14191                        read_profile(shinit);
14192        }
14193        popstackmark(&smark);
14194 state3:
14195        state = 4;
14196        if (minusc) {
14197                /* evalstring pushes parsefile stack.
14198                 * Ensure we don't falsely claim that 0 (stdin)
14199                 * is one of stacked source fds.
14200                 * Testcase: ash -c 'exec 1>&0' must not complain. */
14201                // if (!sflag) g_parsefile->pf_fd = -1;
14202                // ^^ not necessary since now we special-case fd 0
14203                // in save_fd_on_redirect()
14204                evalstring(minusc, sflag ? 0 : EV_EXIT);
14205        }
14206
14207        if (sflag || minusc == NULL) {
14208#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
14209                if (iflag) {
14210                        const char *hp = lookupvar("HISTFILE");
14211                        if (!hp) {
14212                                hp = lookupvar("HOME");
14213                                if (hp) {
14214                                        INT_OFF;
14215                                        hp = concat_path_file(hp, ".ash_history");
14216                                        setvar0("HISTFILE", hp);
14217                                        free((char*)hp);
14218                                        INT_ON;
14219                                        hp = lookupvar("HISTFILE");
14220                                }
14221                        }
14222                        if (hp)
14223                                line_input_state->hist_file = hp;
14224# if ENABLE_FEATURE_SH_HISTFILESIZE
14225                        hp = lookupvar("HISTFILESIZE");
14226                        line_input_state->max_history = size_from_HISTFILESIZE(hp);
14227# endif
14228                }
14229#endif
14230 state4: /* XXX ??? - why isn't this before the "if" statement */
14231                cmdloop(1);
14232        }
14233#if PROFILE
14234        monitor(0);
14235#endif
14236#ifdef GPROF
14237        {
14238                extern void _mcleanup(void);
14239                _mcleanup();
14240        }
14241#endif
14242        TRACE(("End of main reached\n"));
14243        exitshell();
14244        /* NOTREACHED */
14245}
14246
14247
14248/*-
14249 * Copyright (c) 1989, 1991, 1993, 1994
14250 *      The Regents of the University of California.  All rights reserved.
14251 *
14252 * This code is derived from software contributed to Berkeley by
14253 * Kenneth Almquist.
14254 *
14255 * Redistribution and use in source and binary forms, with or without
14256 * modification, are permitted provided that the following conditions
14257 * are met:
14258 * 1. Redistributions of source code must retain the above copyright
14259 *    notice, this list of conditions and the following disclaimer.
14260 * 2. Redistributions in binary form must reproduce the above copyright
14261 *    notice, this list of conditions and the following disclaimer in the
14262 *    documentation and/or other materials provided with the distribution.
14263 * 3. Neither the name of the University nor the names of its contributors
14264 *    may be used to endorse or promote products derived from this software
14265 *    without specific prior written permission.
14266 *
14267 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
14268 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14269 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14270 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14271 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14272 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14273 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14274 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14275 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14276 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14277 * SUCH DAMAGE.
14278 */
14279