busybox/shell/ash.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * ash shell port for busybox
   4 *
   5 * This code is derived from software contributed to Berkeley by
   6 * Kenneth Almquist.
   7 *
   8 * Original BSD copyright notice is retained at the end of this file.
   9 *
  10 * Copyright (c) 1989, 1991, 1993, 1994
  11 *      The Regents of the University of California.  All rights reserved.
  12 *
  13 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
  14 * was re-ported from NetBSD and debianized.
  15 *
  16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  17 */
  18//config:config ASH
  19//config:       bool "ash (78 kb)"
  20//config:       default y
  21//config:       depends on !NOMMU
  22//config:       help
  23//config:       The most complete and most pedantically correct shell included with
  24//config:       busybox. This shell is actually a derivative of the Debian 'dash'
  25//config:       shell (by Herbert Xu), which was created by porting the 'ash' shell
  26//config:       (written by Kenneth Almquist) from NetBSD.
  27//config:
  28//config:# ash options
  29//config:# note: Don't remove !NOMMU part in the next line; it would break
  30//config:# menuconfig's indenting.
  31//config:if !NOMMU && (ASH || SH_IS_ASH || BASH_IS_ASH)
  32//config:
  33//config:config ASH_OPTIMIZE_FOR_SIZE
  34//config:       bool "Optimize for size instead of speed"
  35//config:       default y
  36//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  37//config:
  38//config:config ASH_INTERNAL_GLOB
  39//config:       bool "Use internal glob() implementation"
  40//config:       default y       # Y is bigger, but because of uclibc glob() bug, let Y be default for now
  41//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  42//config:       help
  43//config:       Do not use glob() function from libc, use internal implementation.
  44//config:       Use this if you are getting "glob.h: No such file or directory"
  45//config:       or similar build errors.
  46//config:       Note that as of now (2017-01), uclibc and musl glob() both have bugs
  47//config:       which would break ash if you select N here.
  48//config:
  49//config:config ASH_BASH_COMPAT
  50//config:       bool "bash-compatible extensions"
  51//config:       default y
  52//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  53//config:
  54//config:config ASH_BASH_SOURCE_CURDIR
  55//config:       bool "'source' and '.' builtins search current directory after $PATH"
  56//config:       default n   # do not encourage non-standard behavior
  57//config:       depends on ASH_BASH_COMPAT
  58//config:       help
  59//config:       This is not compliant with standards. Avoid if possible.
  60//config:
  61//config:config ASH_BASH_NOT_FOUND_HOOK
  62//config:       bool "command_not_found_handle hook support"
  63//config:       default y
  64//config:       depends on ASH_BASH_COMPAT
  65//config:       help
  66//config:       Enable support for the 'command_not_found_handle' hook function,
  67//config:       from GNU bash, which allows for alternative command not found
  68//config:       handling.
  69//config:
  70//config:config ASH_JOB_CONTROL
  71//config:       bool "Job control"
  72//config:       default y
  73//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  74//config:
  75//config:config ASH_ALIAS
  76//config:       bool "Alias support"
  77//config:       default y
  78//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  79//config:
  80//config:config ASH_RANDOM_SUPPORT
  81//config:       bool "Pseudorandom generator and $RANDOM variable"
  82//config:       default y
  83//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  84//config:       help
  85//config:       Enable pseudorandom generator and dynamic variable "$RANDOM".
  86//config:       Each read of "$RANDOM" will generate a new pseudorandom value.
  87//config:       You can reset the generator by using a specified start value.
  88//config:       After "unset RANDOM" the generator will switch off and this
  89//config:       variable will no longer have special treatment.
  90//config:
  91//config:config ASH_EXPAND_PRMT
  92//config:       bool "Expand prompt string"
  93//config:       default y
  94//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
  95//config:       help
  96//config:       $PS# may contain volatile content, such as backquote commands.
  97//config:       This option recreates the prompt string from the environment
  98//config:       variable each time it is displayed.
  99//config:
 100//config:config ASH_IDLE_TIMEOUT
 101//config:       bool "Idle timeout variable $TMOUT"
 102//config:       default y
 103//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 104//config:       help
 105//config:       Enable bash-like auto-logout after $TMOUT seconds of idle time.
 106//config:
 107//config:config ASH_MAIL
 108//config:       bool "Check for new mail in interactive shell"
 109//config:       default y
 110//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 111//config:       help
 112//config:       Enable "check for new mail" function:
 113//config:       if set, $MAIL file and $MAILPATH list of files
 114//config:       are checked for mtime changes, and "you have mail"
 115//config:       message is printed if change is detected.
 116//config:
 117//config:config ASH_ECHO
 118//config:       bool "echo builtin"
 119//config:       default y
 120//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 121//config:
 122//config:config ASH_PRINTF
 123//config:       bool "printf builtin"
 124//config:       default y
 125//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 126//config:
 127//config:config ASH_TEST
 128//config:       bool "test builtin"
 129//config:       default y
 130//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 131//config:
 132//config:config ASH_HELP
 133//config:       bool "help builtin"
 134//config:       default y
 135//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 136//config:
 137//config:config ASH_GETOPTS
 138//config:       bool "getopts builtin"
 139//config:       default y
 140//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 141//config:
 142//config:config ASH_CMDCMD
 143//config:       bool "command builtin"
 144//config:       default y
 145//config:       depends on ASH || SH_IS_ASH || BASH_IS_ASH
 146//config:       help
 147//config:       Enable support for the 'command' builtin, which allows
 148//config:       you to run the specified command or builtin,
 149//config:       even when there is a function with the same name.
 150//config:
 151//config:endif # ash options
 152
 153//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
 154//                      APPLET_ODDNAME:name  main location    suid_type     help
 155//applet:IF_SH_IS_ASH(  APPLET_ODDNAME(sh,   ash, BB_DIR_BIN, BB_SUID_DROP, ash))
 156//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
 157
 158//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
 159//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
 160//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
 161//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
 162
 163/*
 164 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
 165 * DEBUG=2 to compile in and turn on debugging.
 166 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
 167 * debugging info is written to ./trace, quit signal generates core dump.
 168 */
 169#define DEBUG 0
 170/* Tweak debug output verbosity here */
 171#define DEBUG_TIME 0
 172#define DEBUG_PID 1
 173#define DEBUG_SIG 1
 174#define DEBUG_INTONOFF 0
 175
 176#define PROFILE 0
 177
 178#define JOBS ENABLE_ASH_JOB_CONTROL
 179
 180#include <fnmatch.h>
 181#include <sys/times.h>
 182#include <sys/utsname.h> /* for setting $HOSTNAME */
 183#include "busybox.h" /* for applet_names */
 184#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
 185# include "embedded_scripts.h"
 186#else
 187# define NUM_SCRIPTS 0
 188#endif
 189
 190/* So far, all bash compat is controlled by one config option */
 191/* Separate defines document which part of code implements what */
 192/* function keyword */
 193#define    BASH_FUNCTION        ENABLE_ASH_BASH_COMPAT
 194#define IF_BASH_FUNCTION            IF_ASH_BASH_COMPAT
 195/* &>file */
 196#define    BASH_REDIR_OUTPUT    ENABLE_ASH_BASH_COMPAT
 197#define IF_BASH_REDIR_OUTPUT        IF_ASH_BASH_COMPAT
 198/* $'...' */
 199#define    BASH_DOLLAR_SQUOTE   ENABLE_ASH_BASH_COMPAT
 200#define IF_BASH_DOLLAR_SQUOTE       IF_ASH_BASH_COMPAT
 201#define    BASH_PATTERN_SUBST   ENABLE_ASH_BASH_COMPAT
 202#define IF_BASH_PATTERN_SUBST       IF_ASH_BASH_COMPAT
 203#define    BASH_SUBSTR          ENABLE_ASH_BASH_COMPAT
 204#define IF_BASH_SUBSTR              IF_ASH_BASH_COMPAT
 205/* BASH_TEST2: [[ EXPR ]]
 206 * Status of [[ support:
 207 * We replace && and || with -a and -o
 208 * TODO:
 209 * singleword+noglob expansion:
 210 *   v='a b'; [[ $v = 'a b' ]]; echo 0:$?
 211 *   [[ /bin/n* ]]; echo 0:$?
 212 * -a/-o are not AND/OR ops! (they are just strings)
 213 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
 214 * = is glob match operator, not equality operator: STR = GLOB
 215 * (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
 216 * == same as =
 217 * add =~ regex match operator: STR =~ REGEX
 218 */
 219#define    BASH_TEST2           (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
 220#define    BASH_SOURCE          ENABLE_ASH_BASH_COMPAT
 221#define    BASH_PIPEFAIL        ENABLE_ASH_BASH_COMPAT
 222#define    BASH_HOSTNAME_VAR    ENABLE_ASH_BASH_COMPAT
 223#define    BASH_EPOCH_VARS      ENABLE_ASH_BASH_COMPAT
 224#define    BASH_SHLVL_VAR       ENABLE_ASH_BASH_COMPAT
 225#define    BASH_XTRACEFD        ENABLE_ASH_BASH_COMPAT
 226#define    BASH_READ_D          ENABLE_ASH_BASH_COMPAT
 227#define IF_BASH_READ_D              IF_ASH_BASH_COMPAT
 228#define    BASH_WAIT_N          ENABLE_ASH_BASH_COMPAT
 229
 230#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
 231/* Bionic at least up to version 24 has no glob() */
 232# undef  ENABLE_ASH_INTERNAL_GLOB
 233# define ENABLE_ASH_INTERNAL_GLOB 1
 234#endif
 235
 236#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
 237# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
 238# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
 239# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
 240# error glob() should unbackslash them and match. uClibc does not unbackslash,
 241# error fails to match dirname, subsequently not expanding <pattern> in it.
 242// Testcase:
 243// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
 244// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
 245#endif
 246
 247#if !ENABLE_ASH_INTERNAL_GLOB
 248# include <glob.h>
 249#endif
 250
 251#include "unicode.h"
 252#include "shell_common.h"
 253#if ENABLE_FEATURE_SH_MATH
 254# include "math.h"
 255#else
 256typedef long arith_t;
 257# define ARITH_FMT "%ld"
 258#endif
 259#if ENABLE_ASH_RANDOM_SUPPORT
 260# include "random.h"
 261#else
 262# define CLEAR_RANDOM_T(rnd) ((void)0)
 263#endif
 264
 265#include "NUM_APPLETS.h"
 266#if NUM_APPLETS == 1
 267/* STANDALONE does not make sense, and won't compile */
 268# undef CONFIG_FEATURE_SH_STANDALONE
 269# undef ENABLE_FEATURE_SH_STANDALONE
 270# undef IF_FEATURE_SH_STANDALONE
 271# undef IF_NOT_FEATURE_SH_STANDALONE
 272# define ENABLE_FEATURE_SH_STANDALONE 0
 273# define IF_FEATURE_SH_STANDALONE(...)
 274# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 275#endif
 276
 277#ifndef F_DUPFD_CLOEXEC
 278# define F_DUPFD_CLOEXEC F_DUPFD
 279#endif
 280#ifndef O_CLOEXEC
 281# define O_CLOEXEC 0
 282#endif
 283#ifndef PIPE_BUF
 284# define PIPE_BUF 4096           /* amount of buffering in a pipe */
 285#endif
 286
 287#if !BB_MMU
 288# error "Do not even bother, ash will not run on NOMMU machine"
 289#endif
 290
 291/* We use a trick to have more optimized code (fewer pointer reloads):
 292 *  ash.c:   extern struct globals *const ash_ptr_to_globals;
 293 *  ash_ptr_hack.c: struct globals *ash_ptr_to_globals;
 294 * This way, compiler in ash.c knows the pointer can not change.
 295 *
 296 * However, this may break on weird arches or toolchains. In this case,
 297 * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable
 298 * this optimization.
 299 */
 300#ifndef BB_GLOBAL_CONST
 301# define BB_GLOBAL_CONST const
 302#endif
 303
 304
 305/* ============ Hash table sizes. Configurable. */
 306
 307#define VTABSIZE 39
 308#define ATABSIZE 39
 309#define CMDTABLESIZE 31         /* should be prime */
 310
 311
 312/* ============ Shell options */
 313
 314static const char *const optletters_optnames[] = {
 315        "e"   "errexit",
 316        "f"   "noglob",
 317        "I"   "ignoreeof",
 318/* The below allowed this invocation:
 319 * ash -c 'set -i; echo $-; sleep 5; echo $-'
 320 * to be ^C-ed and get to interactive ash prompt.
 321 * bash does not support such "set -i".
 322 * In our code, this is denoted by empty long name:
 323 */
 324        "i"   "",
 325        "m"   "monitor",
 326        "n"   "noexec",
 327/* Ditto: bash has no "set -s" */
 328        "s"   "",
 329        "c"   "",
 330        "x"   "xtrace",
 331        "v"   "verbose",
 332        "C"   "noclobber",
 333        "a"   "allexport",
 334        "b"   "notify",
 335        "u"   "nounset",
 336        "\0"  "vi"
 337#if BASH_PIPEFAIL
 338        ,"\0"  "pipefail"
 339#endif
 340#if DEBUG
 341        ,"\0"  "nolog"
 342        ,"\0"  "debug"
 343#endif
 344};
 345//bash 4.4.23 also has these opts (with these defaults):
 346//braceexpand           on
 347//emacs                 on
 348//errtrace              off
 349//functrace             off
 350//hashall               on
 351//histexpand            off
 352//history               on
 353//interactive-comments  on
 354//keyword               off
 355//onecmd                off
 356//physical              off
 357//posix                 off
 358//privileged            off
 359
 360#define optletters(n)  optletters_optnames[n][0]
 361#define optnames(n)   (optletters_optnames[n] + 1)
 362
 363enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
 364
 365
 366/* ============ Misc data */
 367
 368#define msg_illnum "Illegal number: %s"
 369
 370/*
 371 * We enclose jmp_buf in a structure so that we can declare pointers to
 372 * jump locations.  The global variable handler contains the location to
 373 * jump to when an exception occurs, and the global variable exception_type
 374 * contains a code identifying the exception.  To implement nested
 375 * exception handlers, the user should save the value of handler on entry
 376 * to an inner scope, set handler to point to a jmploc structure for the
 377 * inner scope, and restore handler on exit from the scope.
 378 */
 379struct jmploc {
 380        jmp_buf loc;
 381};
 382
 383struct globals_misc {
 384        uint8_t exitstatus;     /* exit status of last command */
 385        uint8_t back_exitstatus;/* exit status of backquoted command */
 386        smallint job_warning;   /* user was warned about stopped jobs (can be 2, 1 or 0). */
 387        int rootpid;            /* pid of main shell */
 388        /* shell level: 0 for the main shell, 1 for its children, and so on */
 389        int shlvl;
 390#define rootshell (!shlvl)
 391        int errlinno;
 392
 393        char *minusc;  /* argument to -c option */
 394
 395        char *curdir; // = nullstr;     /* current working directory */
 396        char *physdir; // = nullstr;    /* physical working directory */
 397
 398        char *arg0; /* value of $0 */
 399
 400        struct jmploc *exception_handler;
 401
 402        volatile int suppress_int; /* counter */
 403        volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
 404        volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
 405        volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
 406        smallint exception_type; /* kind of exception (0..5) */
 407        /* exceptions */
 408#define EXINT 0         /* SIGINT received */
 409#define EXERROR 1       /* a generic error */
 410#define EXEXIT 4        /* exit the shell */
 411
 412        char nullstr[1];        /* zero length string */
 413
 414        char optlist[NOPTS];
 415#define eflag optlist[0]
 416#define fflag optlist[1]
 417#define Iflag optlist[2]
 418#define iflag optlist[3]
 419#define mflag optlist[4]
 420#define nflag optlist[5]
 421#define sflag optlist[6]
 422#define cflag optlist[7]
 423#define xflag optlist[8]
 424#define vflag optlist[9]
 425#define Cflag optlist[10]
 426#define aflag optlist[11]
 427#define bflag optlist[12]
 428#define uflag optlist[13]
 429#define viflag optlist[14]
 430#if BASH_PIPEFAIL
 431# define pipefail optlist[15]
 432#else
 433# define pipefail 0
 434#endif
 435#if DEBUG
 436# define nolog optlist[15 + BASH_PIPEFAIL]
 437# define debug optlist[16 + BASH_PIPEFAIL]
 438#endif
 439
 440        /* trap handler commands */
 441        /*
 442         * Sigmode records the current value of the signal handlers for the various
 443         * modes.  A value of zero means that the current handler is not known.
 444         * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
 445         */
 446        char sigmode[NSIG - 1];
 447#define S_DFL      1            /* default signal handling (SIG_DFL) */
 448#define S_CATCH    2            /* signal is caught */
 449#define S_IGN      3            /* signal is ignored (SIG_IGN) */
 450#define S_HARD_IGN 4            /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
 451
 452        /* indicates specified signal received */
 453        uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
 454        uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
 455        char *trap[NSIG];
 456        char **trap_ptr;        /* used only by "trap hack" */
 457
 458        /* Rarely referenced stuff */
 459#if ENABLE_ASH_RANDOM_SUPPORT
 460        random_t random_gen;
 461#endif
 462        pid_t backgndpid;        /* pid of last background process */
 463};
 464extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
 465#define G_misc (*ash_ptr_to_globals_misc)
 466#define exitstatus        (G_misc.exitstatus )
 467#define back_exitstatus   (G_misc.back_exitstatus )
 468#define job_warning       (G_misc.job_warning)
 469#define rootpid     (G_misc.rootpid    )
 470#define shlvl       (G_misc.shlvl      )
 471#define errlinno    (G_misc.errlinno   )
 472#define minusc      (G_misc.minusc     )
 473#define curdir      (G_misc.curdir     )
 474#define physdir     (G_misc.physdir    )
 475#define arg0        (G_misc.arg0       )
 476#define exception_handler (G_misc.exception_handler)
 477#define exception_type    (G_misc.exception_type   )
 478#define suppress_int      (G_misc.suppress_int     )
 479#define pending_int       (G_misc.pending_int      )
 480#define got_sigchld       (G_misc.got_sigchld      )
 481#define pending_sig       (G_misc.pending_sig      )
 482#define nullstr     (G_misc.nullstr    )
 483#define optlist     (G_misc.optlist    )
 484#define sigmode     (G_misc.sigmode    )
 485#define gotsig      (G_misc.gotsig     )
 486#define may_have_traps    (G_misc.may_have_traps   )
 487#define trap        (G_misc.trap       )
 488#define trap_ptr    (G_misc.trap_ptr   )
 489#define random_gen  (G_misc.random_gen )
 490#define backgndpid  (G_misc.backgndpid )
 491#define INIT_G_misc() do { \
 492        (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
 493        barrier(); \
 494        curdir = nullstr; \
 495        physdir = nullstr; \
 496        trap_ptr = trap; \
 497} while (0)
 498
 499
 500/* ============ DEBUG */
 501#if DEBUG
 502static void trace_printf(const char *fmt, ...);
 503static void trace_vprintf(const char *fmt, va_list va);
 504# define TRACE(param)    trace_printf param
 505# define TRACEV(param)   trace_vprintf param
 506# define close(fd) do { \
 507        int dfd = (fd); \
 508        if (close(dfd) < 0) \
 509                bb_error_msg("bug on %d: closing %d(0x%x)", \
 510                        __LINE__, dfd, dfd); \
 511} while (0)
 512#else
 513# define TRACE(param)
 514# define TRACEV(param)
 515#endif
 516
 517
 518/* ============ Utility functions */
 519#define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
 520#define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
 521
 522static int
 523isdigit_str9(const char *str)
 524{
 525        int maxlen = 9 + 1; /* max 9 digits: 999999999 */
 526        while (--maxlen && isdigit(*str))
 527                str++;
 528        return (*str == '\0');
 529}
 530
 531static const char *
 532var_end(const char *var)
 533{
 534        while (*var)
 535                if (*var++ == '=')
 536                        break;
 537        return var;
 538}
 539
 540
 541/* ============ Interrupts / exceptions */
 542
 543static void exitshell(void) NORETURN;
 544
 545/*
 546 * These macros allow the user to suspend the handling of interrupt signals
 547 * over a period of time.  This is similar to SIGHOLD or to sigblock, but
 548 * much more efficient and portable.  (But hacking the kernel is so much
 549 * more fun than worrying about efficiency and portability. :-))
 550 */
 551#if DEBUG_INTONOFF
 552# define INT_OFF do { \
 553        TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
 554        suppress_int++; \
 555        barrier(); \
 556} while (0)
 557#else
 558# define INT_OFF do { \
 559        suppress_int++; \
 560        barrier(); \
 561} while (0)
 562#endif
 563
 564/*
 565 * Called to raise an exception.  Since C doesn't include exceptions, we
 566 * just do a longjmp to the exception handler.  The type of exception is
 567 * stored in the global variable "exception_type".
 568 */
 569static void raise_exception(int) NORETURN;
 570static void
 571raise_exception(int e)
 572{
 573#if DEBUG
 574        if (exception_handler == NULL)
 575                abort();
 576#endif
 577        INT_OFF;
 578        exception_type = e;
 579        longjmp(exception_handler->loc, 1);
 580}
 581#if DEBUG
 582#define raise_exception(e) do { \
 583        TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
 584        raise_exception(e); \
 585} while (0)
 586#endif
 587
 588/*
 589 * Called when a SIGINT is received.  (If the user specifies
 590 * that SIGINT is to be trapped or ignored using the trap builtin, then
 591 * this routine is not called.)  Suppressint is nonzero when interrupts
 592 * are held using the INT_OFF macro.  (The test for iflag is just
 593 * defensive programming.)
 594 */
 595static void raise_interrupt(void) NORETURN;
 596static void
 597raise_interrupt(void)
 598{
 599        pending_int = 0;
 600        /* Signal is not automatically unmasked after it is raised,
 601         * do it ourself - unmask all signals */
 602        sigprocmask_allsigs(SIG_UNBLOCK);
 603        /* pending_sig = 0; - now done in signal_handler() */
 604
 605        if (!(rootshell && iflag)) {
 606                /* Kill ourself with SIGINT */
 607                signal(SIGINT, SIG_DFL);
 608                raise(SIGINT);
 609        }
 610        /* bash: ^C even on empty command line sets $? */
 611        exitstatus = SIGINT + 128;
 612        raise_exception(EXINT);
 613        /* NOTREACHED */
 614}
 615#if DEBUG
 616#define raise_interrupt() do { \
 617        TRACE(("raising interrupt on line %d\n", __LINE__)); \
 618        raise_interrupt(); \
 619} while (0)
 620#endif
 621
 622static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 623int_on(void)
 624{
 625        barrier();
 626        if (--suppress_int == 0 && pending_int) {
 627                raise_interrupt();
 628        }
 629}
 630#if DEBUG_INTONOFF
 631# define INT_ON do { \
 632        TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
 633        int_on(); \
 634} while (0)
 635#else
 636# define INT_ON int_on()
 637#endif
 638static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 639force_int_on(void)
 640{
 641        barrier();
 642        suppress_int = 0;
 643        if (pending_int)
 644                raise_interrupt();
 645}
 646#define FORCE_INT_ON force_int_on()
 647
 648#define SAVE_INT(v) ((v) = suppress_int)
 649
 650#define RESTORE_INT(v) do { \
 651        barrier(); \
 652        suppress_int = (v); \
 653        if (suppress_int == 0 && pending_int) \
 654                raise_interrupt(); \
 655} while (0)
 656
 657
 658/* ============ Stdout/stderr output */
 659
 660static void
 661outstr(const char *p, FILE *file)
 662{
 663        INT_OFF;
 664        fputs(p, file);
 665        INT_ON;
 666}
 667
 668static void
 669flush_stdout_stderr(void)
 670{
 671        INT_OFF;
 672        fflush_all();
 673        INT_ON;
 674}
 675
 676/* Was called outcslow(c,FILE*), but c was always '\n' */
 677static void
 678newline_and_flush(FILE *dest)
 679{
 680        INT_OFF;
 681        putc('\n', dest);
 682        fflush(dest);
 683        INT_ON;
 684}
 685
 686static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
 687static int
 688out1fmt(const char *fmt, ...)
 689{
 690        va_list ap;
 691        int r;
 692
 693        INT_OFF;
 694        va_start(ap, fmt);
 695        r = vprintf(fmt, ap);
 696        va_end(ap);
 697        INT_ON;
 698        return r;
 699}
 700
 701static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
 702static int
 703fmtstr(char *outbuf, size_t length, const char *fmt, ...)
 704{
 705        va_list ap;
 706        int ret;
 707
 708        INT_OFF;
 709        va_start(ap, fmt);
 710        ret = vsnprintf(outbuf, length, fmt, ap);
 711        va_end(ap);
 712        INT_ON;
 713        return ret;
 714}
 715
 716static void
 717out1str(const char *p)
 718{
 719        outstr(p, stdout);
 720}
 721
 722static void
 723out2str(const char *p)
 724{
 725        outstr(p, stderr);
 726        flush_stdout_stderr();
 727}
 728
 729
 730/* ============ Parser structures */
 731
 732/* control characters in argument strings */
 733#define CTL_FIRST CTLESC
 734#define CTLESC       ((unsigned char)'\201')    /* escape next character */
 735#define CTLVAR       ((unsigned char)'\202')    /* variable defn */
 736#define CTLENDVAR    ((unsigned char)'\203')
 737#define CTLBACKQ     ((unsigned char)'\204')
 738#define CTLARI       ((unsigned char)'\206')    /* arithmetic expression */
 739#define CTLENDARI    ((unsigned char)'\207')
 740#define CTLQUOTEMARK ((unsigned char)'\210')
 741#define CTL_LAST CTLQUOTEMARK
 742
 743/* variable substitution byte (follows CTLVAR) */
 744#define VSTYPE  0x0f            /* type of variable substitution */
 745#define VSNUL   0x10            /* colon--treat the empty string as unset */
 746
 747/* values of VSTYPE field */
 748#define VSNORMAL        0x1     /* normal variable:  $var or ${var} */
 749#define VSMINUS         0x2     /* ${var-text} */
 750#define VSPLUS          0x3     /* ${var+text} */
 751#define VSQUESTION      0x4     /* ${var?message} */
 752#define VSASSIGN        0x5     /* ${var=text} */
 753#define VSTRIMRIGHT     0x6     /* ${var%pattern} */
 754#define VSTRIMRIGHTMAX  0x7     /* ${var%%pattern} */
 755#define VSTRIMLEFT      0x8     /* ${var#pattern} */
 756#define VSTRIMLEFTMAX   0x9     /* ${var##pattern} */
 757#define VSLENGTH        0xa     /* ${#var} */
 758#if BASH_SUBSTR
 759#define VSSUBSTR        0xc     /* ${var:position:length} */
 760#endif
 761#if BASH_PATTERN_SUBST
 762#define VSREPLACE       0xd     /* ${var/pattern/replacement} */
 763#define VSREPLACEALL    0xe     /* ${var//pattern/replacement} */
 764#endif
 765
 766static const char dolatstr[] ALIGN1 = {
 767        CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
 768};
 769#define DOLATSTRLEN 6
 770
 771#define NCMD      0
 772#define NPIPE     1
 773#define NREDIR    2
 774#define NBACKGND  3
 775#define NSUBSHELL 4
 776#define NAND      5
 777#define NOR       6
 778#define NSEMI     7
 779#define NIF       8
 780#define NWHILE    9
 781#define NUNTIL   10
 782#define NFOR     11
 783#define NCASE    12
 784#define NCLIST   13
 785#define NDEFUN   14
 786#define NARG     15
 787#define NTO      16
 788#if BASH_REDIR_OUTPUT
 789#define NTO2     17
 790#endif
 791#define NCLOBBER 18
 792#define NFROM    19
 793#define NFROMTO  20
 794#define NAPPEND  21
 795#define NTOFD    22
 796#define NFROMFD  23
 797#define NHERE    24
 798#define NXHERE   25
 799#define NNOT     26
 800#define N_NUMBER 27
 801
 802union node;
 803
 804struct ncmd {
 805        smallint type; /* Nxxxx */
 806        int linno;
 807        union node *assign;
 808        union node *args;
 809        union node *redirect;
 810};
 811
 812struct npipe {
 813        smallint type;
 814        smallint pipe_backgnd;
 815        struct nodelist *cmdlist;
 816};
 817
 818struct nredir {
 819        smallint type;
 820        int linno;
 821        union node *n;
 822        union node *redirect;
 823};
 824
 825struct nbinary {
 826        smallint type;
 827        union node *ch1;
 828        union node *ch2;
 829};
 830
 831struct nif {
 832        smallint type;
 833        union node *test;
 834        union node *ifpart;
 835        union node *elsepart;
 836};
 837
 838struct nfor {
 839        smallint type;
 840        int linno;
 841        union node *args;
 842        union node *body;
 843        char *var;
 844};
 845
 846struct ncase {
 847        smallint type;
 848        int linno;
 849        union node *expr;
 850        union node *cases;
 851};
 852
 853struct nclist {
 854        smallint type;
 855        union node *next;
 856        union node *pattern;
 857        union node *body;
 858};
 859
 860struct ndefun {
 861        smallint type;
 862        int linno;
 863        char *text;
 864        union node *body;
 865};
 866
 867struct narg {
 868        smallint type;
 869        union node *next;
 870        char *text;
 871        struct nodelist *backquote;
 872};
 873
 874/* nfile and ndup layout must match!
 875 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
 876 * that it is actually NTO2 (>&file), and change its type.
 877 */
 878struct nfile {
 879        smallint type;
 880        union node *next;
 881        int fd;
 882        int _unused_dupfd;
 883        union node *fname;
 884        char *expfname;
 885};
 886
 887struct ndup {
 888        smallint type;
 889        union node *next;
 890        int fd;
 891        int dupfd;
 892        union node *vname;
 893        char *_unused_expfname;
 894};
 895
 896struct nhere {
 897        smallint type;
 898        union node *next;
 899        int fd;
 900        union node *doc;
 901};
 902
 903struct nnot {
 904        smallint type;
 905        union node *com;
 906};
 907
 908union node {
 909        smallint type;
 910        struct ncmd ncmd;
 911        struct npipe npipe;
 912        struct nredir nredir;
 913        struct nbinary nbinary;
 914        struct nif nif;
 915        struct nfor nfor;
 916        struct ncase ncase;
 917        struct nclist nclist;
 918        struct ndefun ndefun;
 919        struct narg narg;
 920        struct nfile nfile;
 921        struct ndup ndup;
 922        struct nhere nhere;
 923        struct nnot nnot;
 924};
 925
 926/*
 927 * NODE_EOF is returned by parsecmd when it encounters an end of file.
 928 * It must be distinct from NULL.
 929 */
 930#define NODE_EOF ((union node *) -1L)
 931
 932struct nodelist {
 933        struct nodelist *next;
 934        union node *n;
 935};
 936
 937struct funcnode {
 938        int count;
 939        union node n;
 940};
 941
 942/*
 943 * Free a parse tree.
 944 */
 945static void
 946freefunc(struct funcnode *f)
 947{
 948        if (f && --f->count < 0)
 949                free(f);
 950}
 951
 952
 953/* ============ Debugging output */
 954
 955#if DEBUG
 956
 957static FILE *tracefile;
 958
 959static void
 960trace_printf(const char *fmt, ...)
 961{
 962        va_list va;
 963
 964        if (debug != 1)
 965                return;
 966        if (DEBUG_TIME)
 967                fprintf(tracefile, "%u ", (int) time(NULL));
 968        if (DEBUG_PID)
 969                fprintf(tracefile, "[%u] ", (int) getpid());
 970        if (DEBUG_SIG)
 971                fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
 972        va_start(va, fmt);
 973        vfprintf(tracefile, fmt, va);
 974        va_end(va);
 975}
 976
 977static void
 978trace_vprintf(const char *fmt, va_list va)
 979{
 980        if (debug != 1)
 981                return;
 982        vfprintf(tracefile, fmt, va);
 983        fprintf(tracefile, "\n");
 984}
 985
 986static void
 987trace_puts(const char *s)
 988{
 989        if (debug != 1)
 990                return;
 991        fputs(s, tracefile);
 992}
 993
 994static void
 995trace_puts_quoted(char *s)
 996{
 997        char *p;
 998        char c;
 999
1000        if (debug != 1)
1001                return;
1002        putc('"', tracefile);
1003        for (p = s; *p; p++) {
1004                switch ((unsigned char)*p) {
1005                case '\n': c = 'n'; goto backslash;
1006                case '\t': c = 't'; goto backslash;
1007                case '\r': c = 'r'; goto backslash;
1008                case '\"': c = '\"'; goto backslash;
1009                case '\\': c = '\\'; goto backslash;
1010                case CTLESC: c = 'e'; goto backslash;
1011                case CTLVAR: c = 'v'; goto backslash;
1012                case CTLBACKQ: c = 'q'; goto backslash;
1013 backslash:
1014                        putc('\\', tracefile);
1015                        putc(c, tracefile);
1016                        break;
1017                default:
1018                        if (*p >= ' ' && *p <= '~')
1019                                putc(*p, tracefile);
1020                        else {
1021                                putc('\\', tracefile);
1022                                putc((*p >> 6) & 03, tracefile);
1023                                putc((*p >> 3) & 07, tracefile);
1024                                putc(*p & 07, tracefile);
1025                        }
1026                        break;
1027                }
1028        }
1029        putc('"', tracefile);
1030}
1031
1032static void
1033trace_puts_args(char **ap)
1034{
1035        if (debug != 1)
1036                return;
1037        if (!*ap)
1038                return;
1039        while (1) {
1040                trace_puts_quoted(*ap);
1041                if (!*++ap) {
1042                        putc('\n', tracefile);
1043                        break;
1044                }
1045                putc(' ', tracefile);
1046        }
1047}
1048
1049static void
1050opentrace(void)
1051{
1052        char s[100];
1053#ifdef O_APPEND
1054        int flags;
1055#endif
1056
1057        if (debug != 1) {
1058                if (tracefile)
1059                        fflush(tracefile);
1060                /* leave open because libedit might be using it */
1061                return;
1062        }
1063        strcpy(s, "./trace");
1064        if (tracefile) {
1065                if (!freopen(s, "a", tracefile)) {
1066                        fprintf(stderr, "Can't re-open %s\n", s);
1067                        debug = 0;
1068                        return;
1069                }
1070        } else {
1071                tracefile = fopen(s, "a");
1072                if (tracefile == NULL) {
1073                        fprintf(stderr, "Can't open %s\n", s);
1074                        debug = 0;
1075                        return;
1076                }
1077        }
1078#ifdef O_APPEND
1079        flags = fcntl(fileno(tracefile), F_GETFL);
1080        if (flags >= 0)
1081                fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1082#endif
1083        setlinebuf(tracefile);
1084        fputs("\nTracing started.\n", tracefile);
1085}
1086
1087static void
1088indent(int amount, char *pfx, FILE *fp)
1089{
1090        int i;
1091
1092        for (i = 0; i < amount; i++) {
1093                if (pfx && i == amount - 1)
1094                        fputs(pfx, fp);
1095                putc('\t', fp);
1096        }
1097}
1098
1099/* little circular references here... */
1100static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1101
1102static void
1103sharg(union node *arg, FILE *fp)
1104{
1105        char *p;
1106        struct nodelist *bqlist;
1107        unsigned char subtype;
1108
1109        if (arg->type != NARG) {
1110                out1fmt("<node type %d>\n", arg->type);
1111                abort();
1112        }
1113        bqlist = arg->narg.backquote;
1114        for (p = arg->narg.text; *p; p++) {
1115                switch ((unsigned char)*p) {
1116                case CTLESC:
1117                        p++;
1118                        putc(*p, fp);
1119                        break;
1120                case CTLVAR:
1121                        putc('$', fp);
1122                        putc('{', fp);
1123                        subtype = *++p;
1124                        if (subtype == VSLENGTH)
1125                                putc('#', fp);
1126
1127                        while (*p != '=') {
1128                                putc(*p, fp);
1129                                p++;
1130                        }
1131
1132                        if (subtype & VSNUL)
1133                                putc(':', fp);
1134
1135                        switch (subtype & VSTYPE) {
1136                        case VSNORMAL:
1137                                putc('}', fp);
1138                                break;
1139                        case VSMINUS:
1140                                putc('-', fp);
1141                                break;
1142                        case VSPLUS:
1143                                putc('+', fp);
1144                                break;
1145                        case VSQUESTION:
1146                                putc('?', fp);
1147                                break;
1148                        case VSASSIGN:
1149                                putc('=', fp);
1150                                break;
1151                        case VSTRIMLEFT:
1152                                putc('#', fp);
1153                                break;
1154                        case VSTRIMLEFTMAX:
1155                                putc('#', fp);
1156                                putc('#', fp);
1157                                break;
1158                        case VSTRIMRIGHT:
1159                                putc('%', fp);
1160                                break;
1161                        case VSTRIMRIGHTMAX:
1162                                putc('%', fp);
1163                                putc('%', fp);
1164                                break;
1165                        case VSLENGTH:
1166                                break;
1167                        default:
1168                                out1fmt("<subtype %d>", subtype);
1169                        }
1170                        break;
1171                case CTLENDVAR:
1172                        putc('}', fp);
1173                        break;
1174                case CTLBACKQ:
1175                        putc('$', fp);
1176                        putc('(', fp);
1177                        shtree(bqlist->n, -1, NULL, fp);
1178                        putc(')', fp);
1179                        break;
1180                default:
1181                        putc(*p, fp);
1182                        break;
1183                }
1184        }
1185}
1186
1187static void
1188shcmd(union node *cmd, FILE *fp)
1189{
1190        union node *np;
1191        int first;
1192        const char *s;
1193        int dftfd;
1194
1195        first = 1;
1196        for (np = cmd->ncmd.args; np; np = np->narg.next) {
1197                if (!first)
1198                        putc(' ', fp);
1199                sharg(np, fp);
1200                first = 0;
1201        }
1202        for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1203                if (!first)
1204                        putc(' ', fp);
1205                dftfd = 0;
1206                switch (np->nfile.type) {
1207                case NTO:      s = ">>"+1; dftfd = 1; break;
1208                case NCLOBBER: s = ">|"; dftfd = 1; break;
1209                case NAPPEND:  s = ">>"; dftfd = 1; break;
1210#if BASH_REDIR_OUTPUT
1211                case NTO2:
1212#endif
1213                case NTOFD:    s = ">&"; dftfd = 1; break;
1214                case NFROM:    s = "<"; break;
1215                case NFROMFD:  s = "<&"; break;
1216                case NFROMTO:  s = "<>"; break;
1217                default:       s = "*error*"; break;
1218                }
1219                if (np->nfile.fd != dftfd)
1220                        fprintf(fp, "%d", np->nfile.fd);
1221                fputs(s, fp);
1222                if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1223                        fprintf(fp, "%d", np->ndup.dupfd);
1224                } else {
1225                        sharg(np->nfile.fname, fp);
1226                }
1227                first = 0;
1228        }
1229}
1230
1231static void
1232shtree(union node *n, int ind, char *pfx, FILE *fp)
1233{
1234        struct nodelist *lp;
1235        const char *s;
1236
1237        if (n == NULL)
1238                return;
1239
1240        indent(ind, pfx, fp);
1241
1242        if (n == NODE_EOF) {
1243                fputs("<EOF>", fp);
1244                return;
1245        }
1246
1247        switch (n->type) {
1248        case NSEMI:
1249                s = "; ";
1250                goto binop;
1251        case NAND:
1252                s = " && ";
1253                goto binop;
1254        case NOR:
1255                s = " || ";
1256 binop:
1257                shtree(n->nbinary.ch1, ind, NULL, fp);
1258                /* if (ind < 0) */
1259                        fputs(s, fp);
1260                shtree(n->nbinary.ch2, ind, NULL, fp);
1261                break;
1262        case NCMD:
1263                shcmd(n, fp);
1264                if (ind >= 0)
1265                        putc('\n', fp);
1266                break;
1267        case NPIPE:
1268                for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1269                        shtree(lp->n, 0, NULL, fp);
1270                        if (lp->next)
1271                                fputs(" | ", fp);
1272                }
1273                if (n->npipe.pipe_backgnd)
1274                        fputs(" &", fp);
1275                if (ind >= 0)
1276                        putc('\n', fp);
1277                break;
1278        default:
1279                fprintf(fp, "<node type %d>", n->type);
1280                if (ind >= 0)
1281                        putc('\n', fp);
1282                break;
1283        }
1284}
1285
1286static void
1287showtree(union node *n)
1288{
1289        trace_puts("showtree called\n");
1290        shtree(n, 1, NULL, stderr);
1291}
1292
1293#endif /* DEBUG */
1294
1295
1296/* ============ Parser data */
1297
1298/*
1299 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1300 */
1301struct strlist {
1302        struct strlist *next;
1303        char *text;
1304};
1305
1306struct alias;
1307
1308struct strpush {
1309        struct strpush *prev;   /* preceding string on stack */
1310        char *prev_string;
1311        int prev_left_in_line;
1312#if ENABLE_ASH_ALIAS
1313        struct alias *ap;       /* if push was associated with an alias */
1314#endif
1315        char *string;           /* remember the string since it may change */
1316
1317        /* Remember last two characters for pungetc. */
1318        int lastc[2];
1319
1320        /* Number of outstanding calls to pungetc. */
1321        int unget;
1322};
1323
1324/*
1325 * The parsefile structure pointed to by the global variable parsefile
1326 * contains information about the current file being read.
1327 */
1328struct parsefile {
1329        struct parsefile *prev; /* preceding file on stack */
1330        int linno;              /* current line */
1331        int pf_fd;              /* file descriptor (or -1 if string) */
1332        int left_in_line;       /* number of chars left in this line */
1333        int left_in_buffer;     /* number of chars left in this buffer past the line */
1334        char *next_to_pgetc;    /* next char in buffer */
1335        char *buf;              /* input buffer */
1336        struct strpush *strpush; /* for pushing strings at this level */
1337        struct strpush basestrpush; /* so pushing one is fast */
1338
1339        /* Remember last two characters for pungetc. */
1340        int lastc[2];
1341
1342        /* Number of outstanding calls to pungetc. */
1343        int unget;
1344};
1345
1346static struct parsefile basepf;        /* top level input file */
1347static struct parsefile *g_parsefile = &basepf;  /* current input file */
1348static char *commandname;              /* currently executing command */
1349
1350
1351/* ============ Message printing */
1352
1353static void
1354ash_vmsg(const char *msg, va_list ap)
1355{
1356        fprintf(stderr, "%s: ", arg0);
1357        if (commandname) {
1358                if (strcmp(arg0, commandname))
1359                        fprintf(stderr, "%s: ", commandname);
1360                if (!iflag || g_parsefile->pf_fd > 0)
1361                        fprintf(stderr, "line %d: ", errlinno);
1362        }
1363        vfprintf(stderr, msg, ap);
1364        newline_and_flush(stderr);
1365}
1366
1367/*
1368 * Exverror is called to raise the error exception.  If the second argument
1369 * is not NULL then error prints an error message using printf style
1370 * formatting.  It then raises the error exception.
1371 */
1372static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1373static void
1374ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1375{
1376#if DEBUG
1377        if (msg) {
1378                TRACE(("ash_vmsg_and_raise(%d):", cond));
1379                TRACEV((msg, ap));
1380        } else
1381                TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1382        if (msg)
1383#endif
1384                ash_vmsg(msg, ap);
1385
1386        flush_stdout_stderr();
1387        raise_exception(cond);
1388        /* NOTREACHED */
1389}
1390
1391static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1392static void
1393ash_msg_and_raise_error(const char *msg, ...)
1394{
1395        va_list ap;
1396
1397        exitstatus = 2;
1398
1399        va_start(ap, msg);
1400        ash_vmsg_and_raise(EXERROR, msg, ap);
1401        /* NOTREACHED */
1402        va_end(ap);
1403}
1404
1405/*
1406 * 'fmt' must be a string literal.
1407 */
1408#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
1409
1410static void raise_error_syntax(const char *) NORETURN;
1411static void
1412raise_error_syntax(const char *msg)
1413{
1414        errlinno = g_parsefile->linno;
1415        ash_msg_and_raise_error("syntax error: %s", msg);
1416        /* NOTREACHED */
1417}
1418
1419static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1420static void
1421ash_msg_and_raise(int cond, const char *msg, ...)
1422{
1423        va_list ap;
1424
1425        va_start(ap, msg);
1426        ash_vmsg_and_raise(cond, msg, ap);
1427        /* NOTREACHED */
1428        va_end(ap);
1429}
1430
1431/*
1432 * error/warning routines for external builtins
1433 */
1434static void
1435ash_msg(const char *fmt, ...)
1436{
1437        va_list ap;
1438
1439        va_start(ap, fmt);
1440        ash_vmsg(fmt, ap);
1441        va_end(ap);
1442}
1443
1444/*
1445 * Return a string describing an error.  The returned string may be a
1446 * pointer to a static buffer that will be overwritten on the next call.
1447 * Action describes the operation that got the error.
1448 */
1449static const char *
1450errmsg(int e, const char *em)
1451{
1452        if (e == ENOENT || e == ENOTDIR) {
1453                return em;
1454        }
1455        return strerror(e);
1456}
1457
1458
1459/* ============ Memory allocation */
1460
1461#if 0
1462/* I consider these wrappers nearly useless:
1463 * ok, they return you to nearest exception handler, but
1464 * how much memory do you leak in the process, making
1465 * memory starvation worse?
1466 */
1467static void *
1468ckrealloc(void * p, size_t nbytes)
1469{
1470        p = realloc(p, nbytes);
1471        if (!p)
1472                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1473        return p;
1474}
1475
1476static void *
1477ckmalloc(size_t nbytes)
1478{
1479        return ckrealloc(NULL, nbytes);
1480}
1481
1482static void *
1483ckzalloc(size_t nbytes)
1484{
1485        return memset(ckmalloc(nbytes), 0, nbytes);
1486}
1487
1488static char *
1489ckstrdup(const char *s)
1490{
1491        char *p = strdup(s);
1492        if (!p)
1493                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1494        return p;
1495}
1496#else
1497/* Using bbox equivalents. They exit if out of memory */
1498# define ckrealloc xrealloc
1499# define ckmalloc  xmalloc
1500# define ckzalloc  xzalloc
1501# define ckstrdup  xstrdup
1502#endif
1503
1504/*
1505 * It appears that grabstackstr() will barf with such alignments
1506 * because stalloc() will return a string allocated in a new stackblock.
1507 */
1508#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1509enum {
1510        /* Most machines require the value returned from malloc to be aligned
1511         * in some way.  The following macro will get this right
1512         * on many machines.  */
1513        SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1514        /* Minimum size of a block */
1515        MINSIZE = SHELL_ALIGN(504),
1516};
1517
1518struct stack_block {
1519        struct stack_block *prev;
1520        char space[MINSIZE];
1521};
1522
1523struct stackmark {
1524        struct stack_block *stackp;
1525        char *stacknxt;
1526        size_t stacknleft;
1527};
1528
1529
1530struct globals_memstack {
1531        struct stack_block *g_stackp; // = &stackbase;
1532        char *g_stacknxt; // = stackbase.space;
1533        char *sstrend; // = stackbase.space + MINSIZE;
1534        size_t g_stacknleft; // = MINSIZE;
1535        struct stack_block stackbase;
1536};
1537extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1538#define G_memstack (*ash_ptr_to_globals_memstack)
1539#define g_stackp     (G_memstack.g_stackp    )
1540#define g_stacknxt   (G_memstack.g_stacknxt  )
1541#define sstrend      (G_memstack.sstrend     )
1542#define g_stacknleft (G_memstack.g_stacknleft)
1543#define stackbase    (G_memstack.stackbase   )
1544#define INIT_G_memstack() do { \
1545        (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1546        barrier(); \
1547        g_stackp = &stackbase; \
1548        g_stacknxt = stackbase.space; \
1549        g_stacknleft = MINSIZE; \
1550        sstrend = stackbase.space + MINSIZE; \
1551} while (0)
1552
1553
1554#define stackblock()     ((void *)g_stacknxt)
1555#define stackblocksize() g_stacknleft
1556
1557/*
1558 * Parse trees for commands are allocated in lifo order, so we use a stack
1559 * to make this more efficient, and also to avoid all sorts of exception
1560 * handling code to handle interrupts in the middle of a parse.
1561 *
1562 * The size 504 was chosen because the Ultrix malloc handles that size
1563 * well.
1564 */
1565static void *
1566stalloc(size_t nbytes)
1567{
1568        char *p;
1569        size_t aligned;
1570
1571        aligned = SHELL_ALIGN(nbytes);
1572        if (aligned > g_stacknleft) {
1573                size_t len;
1574                size_t blocksize;
1575                struct stack_block *sp;
1576
1577                blocksize = aligned;
1578                if (blocksize < MINSIZE)
1579                        blocksize = MINSIZE;
1580                len = sizeof(struct stack_block) - MINSIZE + blocksize;
1581                if (len < blocksize)
1582                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
1583                INT_OFF;
1584                sp = ckmalloc(len);
1585                sp->prev = g_stackp;
1586                g_stacknxt = sp->space;
1587                g_stacknleft = blocksize;
1588                sstrend = g_stacknxt + blocksize;
1589                g_stackp = sp;
1590                INT_ON;
1591        }
1592        p = g_stacknxt;
1593        g_stacknxt += aligned;
1594        g_stacknleft -= aligned;
1595        return p;
1596}
1597
1598static void *
1599stzalloc(size_t nbytes)
1600{
1601        return memset(stalloc(nbytes), 0, nbytes);
1602}
1603
1604static void
1605stunalloc(void *p)
1606{
1607#if DEBUG
1608        if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1609                write(STDERR_FILENO, "stunalloc\n", 10);
1610                abort();
1611        }
1612#endif
1613        g_stacknleft += g_stacknxt - (char *)p;
1614        g_stacknxt = p;
1615}
1616
1617/*
1618 * Like strdup but works with the ash stack.
1619 */
1620static char *
1621sstrdup(const char *p)
1622{
1623        size_t len = strlen(p) + 1;
1624        return memcpy(stalloc(len), p, len);
1625}
1626
1627static ALWAYS_INLINE void
1628grabstackblock(size_t len)
1629{
1630        stalloc(len);
1631}
1632
1633static void
1634pushstackmark(struct stackmark *mark, size_t len)
1635{
1636        mark->stackp = g_stackp;
1637        mark->stacknxt = g_stacknxt;
1638        mark->stacknleft = g_stacknleft;
1639        grabstackblock(len);
1640}
1641
1642static void
1643setstackmark(struct stackmark *mark)
1644{
1645        pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1646}
1647
1648static void
1649popstackmark(struct stackmark *mark)
1650{
1651        struct stack_block *sp;
1652
1653        if (!mark->stackp)
1654                return;
1655
1656        INT_OFF;
1657        while (g_stackp != mark->stackp) {
1658                sp = g_stackp;
1659                g_stackp = sp->prev;
1660                free(sp);
1661        }
1662        g_stacknxt = mark->stacknxt;
1663        g_stacknleft = mark->stacknleft;
1664        sstrend = mark->stacknxt + mark->stacknleft;
1665        INT_ON;
1666}
1667
1668/*
1669 * When the parser reads in a string, it wants to stick the string on the
1670 * stack and only adjust the stack pointer when it knows how big the
1671 * string is.  Stackblock (defined in stack.h) returns a pointer to a block
1672 * of space on top of the stack and stackblocklen returns the length of
1673 * this block.  Growstackblock will grow this space by at least one byte,
1674 * possibly moving it (like realloc).  Grabstackblock actually allocates the
1675 * part of the block that has been used.
1676 */
1677static void
1678growstackblock(void)
1679{
1680        size_t newlen;
1681
1682        newlen = g_stacknleft * 2;
1683        if (newlen < g_stacknleft)
1684                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1685        if (newlen < 128)
1686                newlen += 128;
1687
1688        if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1689                struct stack_block *sp;
1690                struct stack_block *prevstackp;
1691                size_t grosslen;
1692
1693                INT_OFF;
1694                sp = g_stackp;
1695                prevstackp = sp->prev;
1696                grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1697                sp = ckrealloc(sp, grosslen);
1698                sp->prev = prevstackp;
1699                g_stackp = sp;
1700                g_stacknxt = sp->space;
1701                g_stacknleft = newlen;
1702                sstrend = sp->space + newlen;
1703                INT_ON;
1704        } else {
1705                char *oldspace = g_stacknxt;
1706                size_t oldlen = g_stacknleft;
1707                char *p = stalloc(newlen);
1708
1709                /* free the space we just allocated */
1710                g_stacknxt = memcpy(p, oldspace, oldlen);
1711                g_stacknleft += newlen;
1712        }
1713}
1714
1715/*
1716 * The following routines are somewhat easier to use than the above.
1717 * The user declares a variable of type STACKSTR, which may be declared
1718 * to be a register.  The macro STARTSTACKSTR initializes things.  Then
1719 * the user uses the macro STPUTC to add characters to the string.  In
1720 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1721 * grown as necessary.  When the user is done, she can just leave the
1722 * string there and refer to it using stackblock().  Or she can allocate
1723 * the space for it using grabstackstr().  If it is necessary to allow
1724 * someone else to use the stack temporarily and then continue to grow
1725 * the string, the user should use grabstack to allocate the space, and
1726 * then call ungrabstr(p) to return to the previous mode of operation.
1727 *
1728 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1729 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1730 * is space for at least one character.
1731 */
1732static void *
1733growstackstr(void)
1734{
1735        size_t len = stackblocksize();
1736        growstackblock();
1737        return (char *)stackblock() + len;
1738}
1739
1740/*
1741 * Called from CHECKSTRSPACE.
1742 */
1743static char *
1744makestrspace(size_t newlen, char *p)
1745{
1746        size_t len = p - g_stacknxt;
1747        size_t size;
1748
1749        for (;;) {
1750                size_t nleft;
1751
1752                size = stackblocksize();
1753                nleft = size - len;
1754                if (nleft >= newlen)
1755                        break;
1756                growstackblock();
1757        }
1758        return (char *)stackblock() + len;
1759}
1760
1761static char *
1762stack_nputstr(const char *s, size_t n, char *p)
1763{
1764        p = makestrspace(n, p);
1765        p = (char *)mempcpy(p, s, n);
1766        return p;
1767}
1768
1769static char *
1770stack_putstr(const char *s, char *p)
1771{
1772        return stack_nputstr(s, strlen(s), p);
1773}
1774
1775static char *
1776_STPUTC(int c, char *p)
1777{
1778        if (p == sstrend)
1779                p = growstackstr();
1780        *p++ = c;
1781        return p;
1782}
1783
1784#define STARTSTACKSTR(p)        ((p) = stackblock())
1785#define STPUTC(c, p)            ((p) = _STPUTC((c), (p)))
1786#define CHECKSTRSPACE(n, p) do { \
1787        char *q = (p); \
1788        size_t l = (n); \
1789        size_t m = sstrend - q; \
1790        if (l > m) \
1791                (p) = makestrspace(l, q); \
1792} while (0)
1793#define USTPUTC(c, p)           (*(p)++ = (c))
1794#define STACKSTRNUL(p) do { \
1795        if ((p) == sstrend) \
1796                (p) = growstackstr(); \
1797        *(p) = '\0'; \
1798} while (0)
1799#define STUNPUTC(p)             (--(p))
1800#define STTOPC(p)               ((p)[-1])
1801#define STADJUST(amount, p)     ((p) += (amount))
1802
1803#define grabstackstr(p)         stalloc((char *)(p) - (char *)stackblock())
1804#define ungrabstackstr(s, p)    stunalloc(s)
1805#define stackstrend()           ((void *)sstrend)
1806
1807
1808/* ============ String helpers */
1809
1810/*
1811 * prefix -- see if pfx is a prefix of string.
1812 */
1813static char *
1814prefix(const char *string, const char *pfx)
1815{
1816        while (*pfx) {
1817                if (*pfx++ != *string++)
1818                        return NULL;
1819        }
1820        return (char *) string;
1821}
1822
1823/*
1824 * Check for a valid number.  This should be elsewhere.
1825 */
1826static int
1827is_number(const char *p)
1828{
1829        do {
1830                if (!isdigit(*p))
1831                        return 0;
1832        } while (*++p != '\0');
1833        return 1;
1834}
1835
1836/*
1837 * Convert a string of digits to an integer, printing an error message on
1838 * failure.
1839 */
1840static int
1841number(const char *s)
1842{
1843        if (!is_number(s))
1844                ash_msg_and_raise_error(msg_illnum, s);
1845        return atoi(s);
1846}
1847
1848/*
1849 * Produce a single quoted string suitable as input to the shell.
1850 * The return string is allocated on the stack.
1851 */
1852static char *
1853single_quote(const char *s)
1854{
1855        char *p;
1856
1857        STARTSTACKSTR(p);
1858
1859        do {
1860                char *q;
1861                size_t len;
1862
1863                len = strchrnul(s, '\'') - s;
1864
1865                q = p = makestrspace(len + 3, p);
1866
1867                *q++ = '\'';
1868                q = (char *)mempcpy(q, s, len);
1869                *q++ = '\'';
1870                s += len;
1871
1872                STADJUST(q - p, p);
1873
1874                if (*s != '\'')
1875                        break;
1876                len = 0;
1877                do len++; while (*++s == '\'');
1878
1879                q = p = makestrspace(len + 3, p);
1880
1881                *q++ = '"';
1882                q = (char *)mempcpy(q, s - len, len);
1883                *q++ = '"';
1884
1885                STADJUST(q - p, p);
1886        } while (*s);
1887
1888        USTPUTC('\0', p);
1889
1890        return stackblock();
1891}
1892
1893/*
1894 * Produce a possibly single quoted string suitable as input to the shell.
1895 * If quoting was done, the return string is allocated on the stack,
1896 * otherwise a pointer to the original string is returned.
1897 */
1898static const char *
1899maybe_single_quote(const char *s)
1900{
1901        const char *p = s;
1902
1903        while (*p) {
1904                /* Assuming ACSII */
1905                /* quote ctrl_chars space !"#$%&'()* */
1906                if (*p < '+')
1907                        goto need_quoting;
1908                /* quote ;<=>? */
1909                if (*p >= ';' && *p <= '?')
1910                        goto need_quoting;
1911                /* quote `[\ */
1912                if (*p == '`')
1913                        goto need_quoting;
1914                if (*p == '[')
1915                        goto need_quoting;
1916                if (*p == '\\')
1917                        goto need_quoting;
1918                /* quote {|}~ DEL and high bytes */
1919                if (*p > 'z')
1920                        goto need_quoting;
1921                /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1922                /* TODO: maybe avoid quoting % */
1923                p++;
1924        }
1925        return s;
1926
1927 need_quoting:
1928        return single_quote(s);
1929}
1930
1931
1932/* ============ nextopt */
1933
1934static char **argptr;                  /* argument list for builtin commands */
1935static char *optionarg;                /* set by nextopt (like getopt) */
1936static char *optptr;                   /* used by nextopt */
1937
1938/*
1939 * XXX - should get rid of. Have all builtins use getopt(3).
1940 * The library getopt must have the BSD extension static variable
1941 * "optreset", otherwise it can't be used within the shell safely.
1942 *
1943 * Standard option processing (a la getopt) for builtin routines.
1944 * The only argument that is passed to nextopt is the option string;
1945 * the other arguments are unnecessary. It returns the character,
1946 * or '\0' on end of input.
1947 */
1948static int
1949nextopt(const char *optstring)
1950{
1951        char *p;
1952        const char *q;
1953        char c;
1954
1955        p = optptr;
1956        if (p == NULL || *p == '\0') {
1957                /* We ate entire "-param", take next one */
1958                p = *argptr;
1959                if (p == NULL)
1960                        return '\0';
1961                if (*p != '-')
1962                        return '\0';
1963                if (*++p == '\0') /* just "-" ? */
1964                        return '\0';
1965                argptr++;
1966                if (LONE_DASH(p)) /* "--" ? */
1967                        return '\0';
1968                /* p => next "-param" */
1969        }
1970        /* p => some option char in the middle of a "-param" */
1971        c = *p++;
1972        for (q = optstring; *q != c;) {
1973                if (*q == '\0')
1974                        ash_msg_and_raise_error("illegal option -%c", c);
1975                if (*++q == ':')
1976                        q++;
1977        }
1978        if (*++q == ':') {
1979                if (*p == '\0') {
1980                        p = *argptr++;
1981                        if (p == NULL)
1982                                ash_msg_and_raise_error("no arg for -%c option", c);
1983                }
1984                optionarg = p;
1985                p = NULL;
1986        }
1987        optptr = p;
1988        return c;
1989}
1990
1991
1992/* ============ Shell variables */
1993
1994struct shparam {
1995        int nparam;             /* # of positional parameters (without $0) */
1996#if ENABLE_ASH_GETOPTS
1997        int optind;             /* next parameter to be processed by getopts */
1998        int optoff;             /* used by getopts */
1999#endif
2000        unsigned char malloced; /* if parameter list dynamically allocated */
2001        char **p;               /* parameter list */
2002};
2003
2004/*
2005 * Free the list of positional parameters.
2006 */
2007static void
2008freeparam(volatile struct shparam *param)
2009{
2010        if (param->malloced) {
2011                char **ap, **ap1;
2012                ap = ap1 = param->p;
2013                while (*ap)
2014                        free(*ap++);
2015                free(ap1);
2016        }
2017}
2018
2019#if ENABLE_ASH_GETOPTS
2020static void FAST_FUNC getoptsreset(const char *value);
2021#endif
2022
2023struct var {
2024        struct var *next;               /* next entry in hash list */
2025        int flags;                      /* flags are defined above */
2026        const char *var_text;           /* name=value */
2027        void (*var_func)(const char *) FAST_FUNC; /* function to be called when  */
2028                                        /* the variable gets set/unset */
2029};
2030
2031struct localvar {
2032        struct localvar *next;          /* next local variable in list */
2033        struct var *vp;                 /* the variable that was made local */
2034        int flags;                      /* saved flags */
2035        const char *text;               /* saved text */
2036};
2037
2038/* flags */
2039#define VEXPORT         0x01    /* variable is exported */
2040#define VREADONLY       0x02    /* variable cannot be modified */
2041#define VSTRFIXED       0x04    /* variable struct is statically allocated */
2042#define VTEXTFIXED      0x08    /* text is statically allocated */
2043#define VSTACK          0x10    /* text is allocated on the stack */
2044#define VUNSET          0x20    /* the variable is not set */
2045#define VNOFUNC         0x40    /* don't call the callback function */
2046#define VNOSET          0x80    /* do not set variable - just readonly test */
2047#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
2048#if ENABLE_ASH_RANDOM_SUPPORT
2049# define VDYNAMIC       0x200   /* dynamic variable */
2050#else
2051# define VDYNAMIC       0
2052#endif
2053
2054
2055/* Need to be before varinit_data[] */
2056#if ENABLE_LOCALE_SUPPORT
2057static void FAST_FUNC
2058change_lc_all(const char *value)
2059{
2060        if (value && *value != '\0')
2061                setlocale(LC_ALL, value);
2062}
2063static void FAST_FUNC
2064change_lc_ctype(const char *value)
2065{
2066        if (value && *value != '\0')
2067                setlocale(LC_CTYPE, value);
2068}
2069#endif
2070#if ENABLE_ASH_MAIL
2071static void chkmail(void);
2072static void changemail(const char *var_value) FAST_FUNC;
2073#else
2074# define chkmail()  ((void)0)
2075#endif
2076static void changepath(const char *) FAST_FUNC;
2077#if ENABLE_ASH_RANDOM_SUPPORT
2078static void change_random(const char *) FAST_FUNC;
2079#endif
2080#if BASH_EPOCH_VARS
2081static void change_seconds(const char *) FAST_FUNC;
2082static void change_realtime(const char *) FAST_FUNC;
2083#endif
2084
2085static const struct {
2086        int flags;
2087        const char *var_text;
2088        void (*var_func)(const char *) FAST_FUNC;
2089} varinit_data[] = {
2090        /*
2091         * Note: VEXPORT would not work correctly here for NOFORK applets:
2092         * some environment strings may be constant.
2093         */
2094        { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
2095#if ENABLE_ASH_MAIL
2096        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL"      , changemail      },
2097        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH"  , changemail      },
2098#endif
2099        { VSTRFIXED|VTEXTFIXED       , bb_PATH_root_path, changepath },
2100        { VSTRFIXED|VTEXTFIXED       , "PS1=$ "    , NULL            },
2101        { VSTRFIXED|VTEXTFIXED       , "PS2=> "    , NULL            },
2102        { VSTRFIXED|VTEXTFIXED       , "PS4=+ "    , NULL            },
2103#if ENABLE_ASH_GETOPTS
2104        { VSTRFIXED|VTEXTFIXED       , defoptindvar, getoptsreset    },
2105#endif
2106        { VSTRFIXED|VTEXTFIXED       , NULL /* inited to linenovar */, NULL },
2107#if ENABLE_ASH_RANDOM_SUPPORT
2108        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2109#endif
2110#if BASH_EPOCH_VARS
2111        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHSECONDS", change_seconds },
2112        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHREALTIME", change_realtime },
2113#endif
2114#if ENABLE_LOCALE_SUPPORT
2115        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL"    , change_lc_all   },
2116        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE"  , change_lc_ctype },
2117#endif
2118#if ENABLE_FEATURE_EDITING_SAVEHISTORY
2119        { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE"  , NULL            },
2120#endif
2121};
2122
2123struct redirtab;
2124
2125struct globals_var {
2126        struct shparam shellparam;      /* $@ current positional parameters */
2127        struct redirtab *redirlist;
2128        int preverrout_fd;   /* stderr fd: usually 2, unless redirect moved it */
2129        struct var *vartab[VTABSIZE];
2130        struct var varinit[ARRAY_SIZE(varinit_data)];
2131        int lineno;
2132        char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2133};
2134extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2135#define G_var (*ash_ptr_to_globals_var)
2136#define shellparam    (G_var.shellparam   )
2137//#define redirlist     (G_var.redirlist    )
2138#define preverrout_fd (G_var.preverrout_fd)
2139#define vartab        (G_var.vartab       )
2140#define varinit       (G_var.varinit      )
2141#define lineno        (G_var.lineno       )
2142#define linenovar     (G_var.linenovar    )
2143#define vifs      varinit[0]
2144#if ENABLE_ASH_MAIL
2145# define vmail    varinit[1]
2146# define vmpath   varinit[2]
2147#endif
2148#define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
2149#define vpath     varinit[VAR_OFFSET1 + 1]
2150#define vps1      varinit[VAR_OFFSET1 + 2]
2151#define vps2      varinit[VAR_OFFSET1 + 3]
2152#define vps4      varinit[VAR_OFFSET1 + 4]
2153#if ENABLE_ASH_GETOPTS
2154# define voptind  varinit[VAR_OFFSET1 + 5]
2155#endif
2156#define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
2157#define vlineno   varinit[VAR_OFFSET2 + 5]
2158#if ENABLE_ASH_RANDOM_SUPPORT
2159# define vrandom  varinit[VAR_OFFSET2 + 6]
2160#endif
2161#define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
2162#if BASH_EPOCH_VARS
2163# define vepochs  varinit[VAR_OFFSET3 + 6]
2164# define vepochr  varinit[VAR_OFFSET3 + 7]
2165#endif
2166#define INIT_G_var() do { \
2167        unsigned i; \
2168        (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2169        barrier(); \
2170        for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2171                varinit[i].flags    = varinit_data[i].flags; \
2172                varinit[i].var_text = varinit_data[i].var_text; \
2173                varinit[i].var_func = varinit_data[i].var_func; \
2174        } \
2175        strcpy(linenovar, "LINENO="); \
2176        vlineno.var_text = linenovar; \
2177} while (0)
2178
2179/*
2180 * The following macros access the values of the above variables.
2181 * They have to skip over the name.  They return the null string
2182 * for unset variables.
2183 */
2184#define ifsval()        (vifs.var_text + 4)
2185#define ifsset()        ((vifs.flags & VUNSET) == 0)
2186#if ENABLE_ASH_MAIL
2187# define mailval()      (vmail.var_text + 5)
2188# define mpathval()     (vmpath.var_text + 9)
2189# define mpathset()     ((vmpath.flags & VUNSET) == 0)
2190#endif
2191#define pathval()       (vpath.var_text + 5)
2192#define ps1val()        (vps1.var_text + 4)
2193#define ps2val()        (vps2.var_text + 4)
2194#define ps4val()        (vps4.var_text + 4)
2195#if ENABLE_ASH_GETOPTS
2196# define optindval()    (voptind.var_text + 7)
2197#endif
2198
2199#if ENABLE_ASH_GETOPTS
2200static void FAST_FUNC
2201getoptsreset(const char *value)
2202{
2203        shellparam.optind = 1;
2204        if (is_number(value))
2205                shellparam.optind = number(value) ?: 1;
2206        shellparam.optoff = -1;
2207}
2208#endif
2209
2210/*
2211 * Compares two strings up to the first = or '\0'.  The first
2212 * string must be terminated by '='; the second may be terminated by
2213 * either '=' or '\0'.
2214 */
2215static int
2216varcmp(const char *p, const char *q)
2217{
2218        int c, d;
2219
2220        while ((c = *p) == (d = *q)) {
2221                if (c == '\0' || c == '=')
2222                        goto out;
2223                p++;
2224                q++;
2225        }
2226        if (c == '=')
2227                c = '\0';
2228        if (d == '=')
2229                d = '\0';
2230 out:
2231        return c - d;
2232}
2233
2234/*
2235 * Find the appropriate entry in the hash table from the name.
2236 */
2237static struct var **
2238hashvar(const char *p)
2239{
2240        unsigned hashval;
2241
2242        hashval = ((unsigned char) *p) << 4;
2243        while (*p && *p != '=')
2244                hashval += (unsigned char) *p++;
2245        return &vartab[hashval % VTABSIZE];
2246}
2247
2248static int
2249vpcmp(const void *a, const void *b)
2250{
2251        return varcmp(*(const char **)a, *(const char **)b);
2252}
2253
2254/*
2255 * This routine initializes the builtin variables.
2256 */
2257static void
2258initvar(void)
2259{
2260        struct var *vp;
2261        struct var *end;
2262        struct var **vpp;
2263
2264        /*
2265         * PS1 depends on uid
2266         */
2267#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2268        vps1.var_text = "PS1=\\w \\$ ";
2269#else
2270        if (!geteuid())
2271                vps1.var_text = "PS1=# ";
2272#endif
2273        vp = varinit;
2274        end = vp + ARRAY_SIZE(varinit);
2275        do {
2276                vpp = hashvar(vp->var_text);
2277                vp->next = *vpp;
2278                *vpp = vp;
2279        } while (++vp < end);
2280}
2281
2282static struct var **
2283findvar(struct var **vpp, const char *name)
2284{
2285        for (; *vpp; vpp = &(*vpp)->next) {
2286                if (varcmp((*vpp)->var_text, name) == 0) {
2287                        break;
2288                }
2289        }
2290        return vpp;
2291}
2292
2293/*
2294 * Find the value of a variable.  Returns NULL if not set.
2295 */
2296static const char* FAST_FUNC
2297lookupvar(const char *name)
2298{
2299        struct var *v;
2300
2301        v = *findvar(hashvar(name), name);
2302        if (v) {
2303#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2304        /*
2305         * Dynamic variables are implemented roughly the same way they are
2306         * in bash. Namely, they're "special" so long as they aren't unset.
2307         * As soon as they're unset, they're no longer dynamic, and dynamic
2308         * lookup will no longer happen at that point. -- PFM.
2309         */
2310                if (v->flags & VDYNAMIC)
2311                        v->var_func(NULL);
2312#endif
2313                if (!(v->flags & VUNSET)) {
2314                        if (v == &vlineno && v->var_text == linenovar) {
2315                                fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2316                        }
2317                        return var_end(v->var_text);
2318                }
2319        }
2320        return NULL;
2321}
2322
2323#if ENABLE_UNICODE_SUPPORT
2324static void
2325reinit_unicode_for_ash(void)
2326{
2327        /* Unicode support should be activated even if LANG is set
2328         * _during_ shell execution, not only if it was set when
2329         * shell was started. Therefore, re-check LANG every time:
2330         */
2331        if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2332         || ENABLE_UNICODE_USING_LOCALE
2333        ) {
2334                const char *s = lookupvar("LC_ALL");
2335                if (!s) s = lookupvar("LC_CTYPE");
2336                if (!s) s = lookupvar("LANG");
2337                reinit_unicode(s);
2338        }
2339}
2340#else
2341# define reinit_unicode_for_ash() ((void)0)
2342#endif
2343
2344/*
2345 * Search the environment of a builtin command.
2346 */
2347static ALWAYS_INLINE const char *
2348bltinlookup(const char *name)
2349{
2350        return lookupvar(name);
2351}
2352
2353/*
2354 * Same as setvar except that the variable and value are passed in
2355 * the first argument as name=value.  Since the first argument will
2356 * be actually stored in the table, it should not be a string that
2357 * will go away.
2358 * Called with interrupts off.
2359 */
2360static struct var *
2361setvareq(char *s, int flags)
2362{
2363        struct var *vp, **vpp;
2364
2365        vpp = hashvar(s);
2366        flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2367        vpp = findvar(vpp, s);
2368        vp = *vpp;
2369        if (vp) {
2370                if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2371                        const char *n;
2372
2373                        if (flags & VNOSAVE)
2374                                free(s);
2375                        n = vp->var_text;
2376                        exitstatus = 1;
2377                        ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2378                }
2379
2380                if (flags & VNOSET)
2381                        goto out;
2382
2383                if (vp->var_func && !(flags & VNOFUNC))
2384                        vp->var_func(var_end(s));
2385
2386                if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2387                        free((char*)vp->var_text);
2388
2389                if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2390                        *vpp = vp->next;
2391                        free(vp);
2392 out_free:
2393                        if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2394                                free(s);
2395                        goto out;
2396                }
2397
2398                flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2399#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2400                if (flags & VUNSET)
2401                        flags &= ~VDYNAMIC;
2402#endif
2403        } else {
2404                /* variable s is not found */
2405                if (flags & VNOSET)
2406                        goto out;
2407                if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2408                        goto out_free;
2409                vp = ckzalloc(sizeof(*vp));
2410                vp->next = *vpp;
2411                /*vp->func = NULL; - ckzalloc did it */
2412                *vpp = vp;
2413        }
2414        if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2415                s = ckstrdup(s);
2416        vp->var_text = s;
2417        vp->flags = flags;
2418
2419 out:
2420        return vp;
2421}
2422
2423/*
2424 * Set the value of a variable.  The flags argument is ored with the
2425 * flags of the variable.  If val is NULL, the variable is unset.
2426 */
2427static struct var *
2428setvar(const char *name, const char *val, int flags)
2429{
2430        const char *q;
2431        char *p;
2432        char *nameeq;
2433        size_t namelen;
2434        size_t vallen;
2435        struct var *vp;
2436
2437        q = endofname(name);
2438        p = strchrnul(q, '=');
2439        namelen = p - name;
2440        if (!namelen || p != q)
2441                ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2442        vallen = 0;
2443        if (val == NULL) {
2444                flags |= VUNSET;
2445        } else {
2446                vallen = strlen(val);
2447        }
2448
2449        INT_OFF;
2450        nameeq = ckzalloc(namelen + vallen + 2);
2451        p = mempcpy(nameeq, name, namelen);
2452        if (val) {
2453                *p++ = '=';
2454                memcpy(p, val, vallen);
2455        }
2456        vp = setvareq(nameeq, flags | VNOSAVE);
2457        INT_ON;
2458
2459        return vp;
2460}
2461
2462static void FAST_FUNC
2463setvar0(const char *name, const char *val)
2464{
2465        setvar(name, val, 0);
2466}
2467
2468/*
2469 * Unset the specified variable.
2470 */
2471static void
2472unsetvar(const char *s)
2473{
2474        setvar(s, NULL, 0);
2475}
2476
2477/*
2478 * Process a linked list of variable assignments.
2479 */
2480static void
2481listsetvar(struct strlist *list_set_var, int flags)
2482{
2483        struct strlist *lp = list_set_var;
2484
2485        if (!lp)
2486                return;
2487        INT_OFF;
2488        do {
2489                setvareq(lp->text, flags);
2490                lp = lp->next;
2491        } while (lp);
2492        INT_ON;
2493}
2494
2495/*
2496 * Generate a list of variables satisfying the given conditions.
2497 */
2498#if !ENABLE_FEATURE_SH_NOFORK
2499# define listvars(on, off, lp, end) listvars(on, off, end)
2500#endif
2501static char **
2502listvars(int on, int off, struct strlist *lp, char ***end)
2503{
2504        struct var **vpp;
2505        struct var *vp;
2506        char **ep;
2507        int mask;
2508
2509        STARTSTACKSTR(ep);
2510        vpp = vartab;
2511        mask = on | off;
2512        do {
2513                for (vp = *vpp; vp; vp = vp->next) {
2514                        if ((vp->flags & mask) == on) {
2515#if ENABLE_FEATURE_SH_NOFORK
2516                                /* If variable with the same name is both
2517                                 * exported and temporarily set for a command:
2518                                 *  export ZVAR=5
2519                                 *  ZVAR=6 printenv
2520                                 * then "ZVAR=6" will be both in vartab and
2521                                 * lp lists. Do not pass it twice to printenv.
2522                                 */
2523                                struct strlist *lp1 = lp;
2524                                while (lp1) {
2525                                        if (strcmp(lp1->text, vp->var_text) == 0)
2526                                                goto skip;
2527                                        lp1 = lp1->next;
2528                                }
2529#endif
2530                                if (ep == stackstrend())
2531                                        ep = growstackstr();
2532                                *ep++ = (char*)vp->var_text;
2533#if ENABLE_FEATURE_SH_NOFORK
2534 skip: ;
2535#endif
2536                        }
2537                }
2538        } while (++vpp < vartab + VTABSIZE);
2539
2540#if ENABLE_FEATURE_SH_NOFORK
2541        while (lp) {
2542                if (ep == stackstrend())
2543                        ep = growstackstr();
2544                *ep++ = lp->text;
2545                lp = lp->next;
2546        }
2547#endif
2548
2549        if (ep == stackstrend())
2550                ep = growstackstr();
2551        if (end)
2552                *end = ep;
2553        *ep++ = NULL;
2554        return grabstackstr(ep);
2555}
2556
2557
2558/* ============ Path search helper
2559 *
2560 * The variable path (passed by reference) should be set to the start
2561 * of the path before the first call; path_advance will update
2562 * this value as it proceeds.  Successive calls to path_advance will return
2563 * the possible path expansions in sequence.  If an option (indicated by
2564 * a percent sign) appears in the path entry then the global variable
2565 * pathopt will be set to point to it; otherwise pathopt will be set to
2566 * NULL.
2567 */
2568static const char *pathopt;     /* set by path_advance */
2569
2570static char *
2571path_advance(const char **path, const char *name)
2572{
2573        const char *p;
2574        char *q;
2575        const char *start;
2576        size_t len;
2577
2578        if (*path == NULL)
2579                return NULL;
2580        start = *path;
2581        for (p = start; *p && *p != ':' && *p != '%'; p++)
2582                continue;
2583        len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
2584        while (stackblocksize() < len)
2585                growstackblock();
2586        q = stackblock();
2587        if (p != start) {
2588                q = mempcpy(q, start, p - start);
2589                *q++ = '/';
2590        }
2591        strcpy(q, name);
2592        pathopt = NULL;
2593        if (*p == '%') {
2594                pathopt = ++p;
2595                while (*p && *p != ':')
2596                        p++;
2597        }
2598        if (*p == ':')
2599                *path = p + 1;
2600        else
2601                *path = NULL;
2602        return stalloc(len);
2603}
2604
2605
2606/* ============ Prompt */
2607
2608static smallint doprompt;                   /* if set, prompt the user */
2609static smallint needprompt;                 /* true if interactive and at start of line */
2610
2611#if ENABLE_FEATURE_EDITING
2612static line_input_t *line_input_state;
2613static const char *cmdedit_prompt;
2614static void
2615putprompt(const char *s)
2616{
2617        if (ENABLE_ASH_EXPAND_PRMT) {
2618                free((char*)cmdedit_prompt);
2619                cmdedit_prompt = ckstrdup(s);
2620                return;
2621        }
2622        cmdedit_prompt = s;
2623}
2624#else
2625static void
2626putprompt(const char *s)
2627{
2628        out2str(s);
2629}
2630#endif
2631
2632/* expandstr() needs parsing machinery, so it is far away ahead... */
2633static const char *expandstr(const char *ps, int syntax_type);
2634/* Values for syntax param */
2635#define BASESYNTAX 0    /* not in quotes */
2636#define DQSYNTAX   1    /* in double quotes */
2637#define SQSYNTAX   2    /* in single quotes */
2638#define ARISYNTAX  3    /* in arithmetic */
2639#if ENABLE_ASH_EXPAND_PRMT
2640# define PSSYNTAX  4    /* prompt. never passed to SIT() */
2641#endif
2642/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
2643
2644/*
2645 * called by editline -- any expansions to the prompt should be added here.
2646 */
2647static void
2648setprompt_if(smallint do_set, int whichprompt)
2649{
2650        const char *prompt;
2651        IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2652
2653        if (!do_set)
2654                return;
2655
2656        needprompt = 0;
2657
2658        switch (whichprompt) {
2659        case 1:
2660                prompt = ps1val();
2661                break;
2662        case 2:
2663                prompt = ps2val();
2664                break;
2665        default:                        /* 0 */
2666                prompt = nullstr;
2667        }
2668#if ENABLE_ASH_EXPAND_PRMT
2669        pushstackmark(&smark, stackblocksize());
2670        putprompt(expandstr(prompt, PSSYNTAX));
2671        popstackmark(&smark);
2672#else
2673        putprompt(prompt);
2674#endif
2675}
2676
2677
2678/* ============ The cd and pwd commands */
2679
2680#define CD_PHYSICAL 1
2681#define CD_PRINT 2
2682
2683static int
2684cdopt(void)
2685{
2686        int flags = 0;
2687        int i, j;
2688
2689        j = 'L';
2690        while ((i = nextopt("LP")) != '\0') {
2691                if (i != j) {
2692                        flags ^= CD_PHYSICAL;
2693                        j = i;
2694                }
2695        }
2696
2697        return flags;
2698}
2699
2700/*
2701 * Update curdir (the name of the current directory) in response to a
2702 * cd command.
2703 */
2704static const char *
2705updatepwd(const char *dir)
2706{
2707        char *new;
2708        char *p;
2709        char *cdcomppath;
2710        const char *lim;
2711
2712        cdcomppath = sstrdup(dir);
2713        STARTSTACKSTR(new);
2714        if (*dir != '/') {
2715                if (curdir == nullstr)
2716                        return 0;
2717                new = stack_putstr(curdir, new);
2718        }
2719        new = makestrspace(strlen(dir) + 2, new);
2720        lim = (char *)stackblock() + 1;
2721        if (*dir != '/') {
2722                if (new[-1] != '/')
2723                        USTPUTC('/', new);
2724                if (new > lim && *lim == '/')
2725                        lim++;
2726        } else {
2727                USTPUTC('/', new);
2728                cdcomppath++;
2729                if (dir[1] == '/' && dir[2] != '/') {
2730                        USTPUTC('/', new);
2731                        cdcomppath++;
2732                        lim++;
2733                }
2734        }
2735        p = strtok(cdcomppath, "/");
2736        while (p) {
2737                switch (*p) {
2738                case '.':
2739                        if (p[1] == '.' && p[2] == '\0') {
2740                                while (new > lim) {
2741                                        STUNPUTC(new);
2742                                        if (new[-1] == '/')
2743                                                break;
2744                                }
2745                                break;
2746                        }
2747                        if (p[1] == '\0')
2748                                break;
2749                        /* fall through */
2750                default:
2751                        new = stack_putstr(p, new);
2752                        USTPUTC('/', new);
2753                }
2754                p = strtok(NULL, "/");
2755        }
2756        if (new > lim)
2757                STUNPUTC(new);
2758        *new = 0;
2759        return stackblock();
2760}
2761
2762/*
2763 * Find out what the current directory is. If we already know the current
2764 * directory, this routine returns immediately.
2765 */
2766static char *
2767getpwd(void)
2768{
2769        char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2770        return dir ? dir : nullstr;
2771}
2772
2773static void
2774setpwd(const char *val, int setold)
2775{
2776        char *oldcur, *dir;
2777
2778        oldcur = dir = curdir;
2779
2780        if (setold) {
2781                setvar("OLDPWD", oldcur, VEXPORT);
2782        }
2783        INT_OFF;
2784        if (physdir != nullstr) {
2785                if (physdir != oldcur)
2786                        free(physdir);
2787                physdir = nullstr;
2788        }
2789        if (oldcur == val || !val) {
2790                char *s = getpwd();
2791                physdir = s;
2792                if (!val)
2793                        dir = s;
2794        } else
2795                dir = ckstrdup(val);
2796        if (oldcur != dir && oldcur != nullstr) {
2797                free(oldcur);
2798        }
2799        curdir = dir;
2800        INT_ON;
2801        setvar("PWD", dir, VEXPORT);
2802}
2803
2804static void hashcd(void);
2805
2806/*
2807 * Actually do the chdir.  We also call hashcd to let other routines
2808 * know that the current directory has changed.
2809 */
2810static int
2811docd(const char *dest, int flags)
2812{
2813        const char *dir = NULL;
2814        int err;
2815
2816        TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2817
2818        INT_OFF;
2819        if (!(flags & CD_PHYSICAL)) {
2820                dir = updatepwd(dest);
2821                if (dir)
2822                        dest = dir;
2823        }
2824        err = chdir(dest);
2825        if (err)
2826                goto out;
2827        setpwd(dir, 1);
2828        hashcd();
2829 out:
2830        INT_ON;
2831        return err;
2832}
2833
2834static int FAST_FUNC
2835cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2836{
2837        const char *dest;
2838        const char *path;
2839        const char *p;
2840        char c;
2841        struct stat statb;
2842        int flags;
2843
2844        flags = cdopt();
2845        dest = *argptr;
2846        if (!dest)
2847                dest = bltinlookup("HOME");
2848        else if (LONE_DASH(dest)) {
2849                dest = bltinlookup("OLDPWD");
2850                flags |= CD_PRINT;
2851        }
2852        if (!dest)
2853                dest = nullstr;
2854        if (*dest == '/')
2855                goto step6;
2856        if (*dest == '.') {
2857                c = dest[1];
2858 dotdot:
2859                switch (c) {
2860                case '\0':
2861                case '/':
2862                        goto step6;
2863                case '.':
2864                        c = dest[2];
2865                        if (c != '.')
2866                                goto dotdot;
2867                }
2868        }
2869        if (!*dest)
2870                dest = ".";
2871        path = bltinlookup("CDPATH");
2872        while (path) {
2873                c = *path;
2874                p = path_advance(&path, dest);
2875                if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2876                        if (c && c != ':')
2877                                flags |= CD_PRINT;
2878 docd:
2879                        if (!docd(p, flags))
2880                                goto out;
2881                        goto err;
2882                }
2883        }
2884
2885 step6:
2886        p = dest;
2887        goto docd;
2888
2889 err:
2890        ash_msg_and_raise_perror("can't cd to %s", dest);
2891        /* NOTREACHED */
2892 out:
2893        if (flags & CD_PRINT)
2894                out1fmt("%s\n", curdir);
2895        return 0;
2896}
2897
2898static int FAST_FUNC
2899pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2900{
2901        int flags;
2902        const char *dir = curdir;
2903
2904        flags = cdopt();
2905        if (flags) {
2906                if (physdir == nullstr)
2907                        setpwd(dir, 0);
2908                dir = physdir;
2909        }
2910        out1fmt("%s\n", dir);
2911        return 0;
2912}
2913
2914
2915/* ============ ... */
2916
2917
2918#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2919
2920/* Syntax classes */
2921#define CWORD     0             /* character is nothing special */
2922#define CNL       1             /* newline character */
2923#define CBACK     2             /* a backslash character */
2924#define CSQUOTE   3             /* single quote */
2925#define CDQUOTE   4             /* double quote */
2926#define CENDQUOTE 5             /* a terminating quote */
2927#define CBQUOTE   6             /* backwards single quote */
2928#define CVAR      7             /* a dollar sign */
2929#define CENDVAR   8             /* a '}' character */
2930#define CLP       9             /* a left paren in arithmetic */
2931#define CRP      10             /* a right paren in arithmetic */
2932#define CENDFILE 11             /* end of file */
2933#define CCTL     12             /* like CWORD, except it must be escaped */
2934#define CSPCL    13             /* these terminate a word */
2935#define CIGN     14             /* character should be ignored */
2936
2937#define PEOF     256
2938#if ENABLE_ASH_ALIAS
2939# define PEOA    257
2940#endif
2941
2942#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2943
2944#if ENABLE_FEATURE_SH_MATH
2945# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2946#else
2947# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2948#endif
2949static const uint16_t S_I_T[] ALIGN2 = {
2950#if ENABLE_ASH_ALIAS
2951        SIT_ITEM(CSPCL   , CIGN     , CIGN , CIGN   ),    /* 0, PEOA */
2952#endif
2953        SIT_ITEM(CSPCL   , CWORD    , CWORD, CWORD  ),    /* 1, ' ' */
2954        SIT_ITEM(CNL     , CNL      , CNL  , CNL    ),    /* 2, \n */
2955        SIT_ITEM(CWORD   , CCTL     , CCTL , CWORD  ),    /* 3, !*-/:=?[]~ */
2956        SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD  ),    /* 4, '"' */
2957        SIT_ITEM(CVAR    , CVAR     , CWORD, CVAR   ),    /* 5, $ */
2958        SIT_ITEM(CSQUOTE , CWORD    , CENDQUOTE, CWORD),  /* 6, "'" */
2959        SIT_ITEM(CSPCL   , CWORD    , CWORD, CLP    ),    /* 7, ( */
2960        SIT_ITEM(CSPCL   , CWORD    , CWORD, CRP    ),    /* 8, ) */
2961        SIT_ITEM(CBACK   , CBACK    , CCTL , CBACK  ),    /* 9, \ */
2962        SIT_ITEM(CBQUOTE , CBQUOTE  , CWORD, CBQUOTE),    /* 10, ` */
2963        SIT_ITEM(CENDVAR , CENDVAR  , CWORD, CENDVAR),    /* 11, } */
2964#if !USE_SIT_FUNCTION
2965        SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2966        SIT_ITEM(CWORD   , CWORD    , CWORD, CWORD  ),    /* 13, 0-9A-Za-z */
2967        SIT_ITEM(CCTL    , CCTL     , CCTL , CCTL   )     /* 14, CTLESC ... */
2968#endif
2969#undef SIT_ITEM
2970};
2971/* Constants below must match table above */
2972enum {
2973#if ENABLE_ASH_ALIAS
2974        CSPCL_CIGN_CIGN_CIGN               , /*  0 */
2975#endif
2976        CSPCL_CWORD_CWORD_CWORD            , /*  1 */
2977        CNL_CNL_CNL_CNL                    , /*  2 */
2978        CWORD_CCTL_CCTL_CWORD              , /*  3 */
2979        CDQUOTE_CENDQUOTE_CWORD_CWORD      , /*  4 */
2980        CVAR_CVAR_CWORD_CVAR               , /*  5 */
2981        CSQUOTE_CWORD_CENDQUOTE_CWORD      , /*  6 */
2982        CSPCL_CWORD_CWORD_CLP              , /*  7 */
2983        CSPCL_CWORD_CWORD_CRP              , /*  8 */
2984        CBACK_CBACK_CCTL_CBACK             , /*  9 */
2985        CBQUOTE_CBQUOTE_CWORD_CBQUOTE      , /* 10 */
2986        CENDVAR_CENDVAR_CWORD_CENDVAR      , /* 11 */
2987        CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2988        CWORD_CWORD_CWORD_CWORD            , /* 13 */
2989        CCTL_CCTL_CCTL_CCTL                , /* 14 */
2990};
2991
2992/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2993 * caller must ensure proper cast on it if c is *char_ptr!
2994 */
2995#if USE_SIT_FUNCTION
2996
2997static int
2998SIT(int c, int syntax)
2999{
3000        /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
3001        static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
3002        /*
3003         * This causes '/' to be prepended with CTLESC in dquoted string,
3004         * making "./file"* treated incorrectly because we feed
3005         * ".\/file*" string to glob(), confusing it (see expandmeta func).
3006         * The "homegrown" glob implementation is okay with that,
3007         * but glibc one isn't. With '/' always treated as CWORD,
3008         * both work fine.
3009         */
3010# if ENABLE_ASH_ALIAS
3011        static const uint8_t syntax_index_table[] ALIGN1 = {
3012                1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
3013                7, 8, 3, 3,/*3,*/3, 1, 1,       /* "()*-/:;<" */
3014                3, 1, 3, 3, 9, 3, 10, 1,        /* "=>?[\\]`|" */
3015                11, 3                           /* "}~" */
3016        };
3017# else
3018        static const uint8_t syntax_index_table[] ALIGN1 = {
3019                0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
3020                6, 7, 2, 2,/*2,*/2, 0, 0,       /* "()*-/:;<" */
3021                2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
3022                10, 2                           /* "}~" */
3023        };
3024# endif
3025        const char *s;
3026        int indx;
3027
3028        if (c == PEOF)
3029                return CENDFILE;
3030# if ENABLE_ASH_ALIAS
3031        if (c == PEOA)
3032                indx = 0;
3033        else
3034# endif
3035        {
3036                /* Cast is purely for paranoia here,
3037                 * just in case someone passed signed char to us */
3038                if ((unsigned char)c >= CTL_FIRST
3039                 && (unsigned char)c <= CTL_LAST
3040                ) {
3041                        return CCTL;
3042                }
3043                s = strchrnul(spec_symbls, c);
3044                if (*s == '\0')
3045                        return CWORD;
3046                indx = syntax_index_table[s - spec_symbls];
3047        }
3048        return (S_I_T[indx] >> (syntax*4)) & 0xf;
3049}
3050
3051#else   /* !USE_SIT_FUNCTION */
3052
3053static const uint8_t syntax_index_table[] ALIGN1 = {
3054        /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
3055        /*   0      */ CWORD_CWORD_CWORD_CWORD,
3056        /*   1      */ CWORD_CWORD_CWORD_CWORD,
3057        /*   2      */ CWORD_CWORD_CWORD_CWORD,
3058        /*   3      */ CWORD_CWORD_CWORD_CWORD,
3059        /*   4      */ CWORD_CWORD_CWORD_CWORD,
3060        /*   5      */ CWORD_CWORD_CWORD_CWORD,
3061        /*   6      */ CWORD_CWORD_CWORD_CWORD,
3062        /*   7      */ CWORD_CWORD_CWORD_CWORD,
3063        /*   8      */ CWORD_CWORD_CWORD_CWORD,
3064        /*   9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3065        /*  10 "\n" */ CNL_CNL_CNL_CNL,
3066        /*  11      */ CWORD_CWORD_CWORD_CWORD,
3067        /*  12      */ CWORD_CWORD_CWORD_CWORD,
3068        /*  13      */ CWORD_CWORD_CWORD_CWORD,
3069        /*  14      */ CWORD_CWORD_CWORD_CWORD,
3070        /*  15      */ CWORD_CWORD_CWORD_CWORD,
3071        /*  16      */ CWORD_CWORD_CWORD_CWORD,
3072        /*  17      */ CWORD_CWORD_CWORD_CWORD,
3073        /*  18      */ CWORD_CWORD_CWORD_CWORD,
3074        /*  19      */ CWORD_CWORD_CWORD_CWORD,
3075        /*  20      */ CWORD_CWORD_CWORD_CWORD,
3076        /*  21      */ CWORD_CWORD_CWORD_CWORD,
3077        /*  22      */ CWORD_CWORD_CWORD_CWORD,
3078        /*  23      */ CWORD_CWORD_CWORD_CWORD,
3079        /*  24      */ CWORD_CWORD_CWORD_CWORD,
3080        /*  25      */ CWORD_CWORD_CWORD_CWORD,
3081        /*  26      */ CWORD_CWORD_CWORD_CWORD,
3082        /*  27      */ CWORD_CWORD_CWORD_CWORD,
3083        /*  28      */ CWORD_CWORD_CWORD_CWORD,
3084        /*  29      */ CWORD_CWORD_CWORD_CWORD,
3085        /*  30      */ CWORD_CWORD_CWORD_CWORD,
3086        /*  31      */ CWORD_CWORD_CWORD_CWORD,
3087        /*  32  " " */ CSPCL_CWORD_CWORD_CWORD,
3088        /*  33  "!" */ CWORD_CCTL_CCTL_CWORD,
3089        /*  34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3090        /*  35  "#" */ CWORD_CWORD_CWORD_CWORD,
3091        /*  36  "$" */ CVAR_CVAR_CWORD_CVAR,
3092        /*  37  "%" */ CWORD_CWORD_CWORD_CWORD,
3093        /*  38  "&" */ CSPCL_CWORD_CWORD_CWORD,
3094        /*  39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3095        /*  40  "(" */ CSPCL_CWORD_CWORD_CLP,
3096        /*  41  ")" */ CSPCL_CWORD_CWORD_CRP,
3097        /*  42  "*" */ CWORD_CCTL_CCTL_CWORD,
3098        /*  43  "+" */ CWORD_CWORD_CWORD_CWORD,
3099        /*  44  "," */ CWORD_CWORD_CWORD_CWORD,
3100        /*  45  "-" */ CWORD_CCTL_CCTL_CWORD,
3101        /*  46  "." */ CWORD_CWORD_CWORD_CWORD,
3102/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3103        /*  47  "/" */ CWORD_CWORD_CWORD_CWORD,
3104        /*  48  "0" */ CWORD_CWORD_CWORD_CWORD,
3105        /*  49  "1" */ CWORD_CWORD_CWORD_CWORD,
3106        /*  50  "2" */ CWORD_CWORD_CWORD_CWORD,
3107        /*  51  "3" */ CWORD_CWORD_CWORD_CWORD,
3108        /*  52  "4" */ CWORD_CWORD_CWORD_CWORD,
3109        /*  53  "5" */ CWORD_CWORD_CWORD_CWORD,
3110        /*  54  "6" */ CWORD_CWORD_CWORD_CWORD,
3111        /*  55  "7" */ CWORD_CWORD_CWORD_CWORD,
3112        /*  56  "8" */ CWORD_CWORD_CWORD_CWORD,
3113        /*  57  "9" */ CWORD_CWORD_CWORD_CWORD,
3114        /*  58  ":" */ CWORD_CCTL_CCTL_CWORD,
3115        /*  59  ";" */ CSPCL_CWORD_CWORD_CWORD,
3116        /*  60  "<" */ CSPCL_CWORD_CWORD_CWORD,
3117        /*  61  "=" */ CWORD_CCTL_CCTL_CWORD,
3118        /*  62  ">" */ CSPCL_CWORD_CWORD_CWORD,
3119        /*  63  "?" */ CWORD_CCTL_CCTL_CWORD,
3120        /*  64  "@" */ CWORD_CWORD_CWORD_CWORD,
3121        /*  65  "A" */ CWORD_CWORD_CWORD_CWORD,
3122        /*  66  "B" */ CWORD_CWORD_CWORD_CWORD,
3123        /*  67  "C" */ CWORD_CWORD_CWORD_CWORD,
3124        /*  68  "D" */ CWORD_CWORD_CWORD_CWORD,
3125        /*  69  "E" */ CWORD_CWORD_CWORD_CWORD,
3126        /*  70  "F" */ CWORD_CWORD_CWORD_CWORD,
3127        /*  71  "G" */ CWORD_CWORD_CWORD_CWORD,
3128        /*  72  "H" */ CWORD_CWORD_CWORD_CWORD,
3129        /*  73  "I" */ CWORD_CWORD_CWORD_CWORD,
3130        /*  74  "J" */ CWORD_CWORD_CWORD_CWORD,
3131        /*  75  "K" */ CWORD_CWORD_CWORD_CWORD,
3132        /*  76  "L" */ CWORD_CWORD_CWORD_CWORD,
3133        /*  77  "M" */ CWORD_CWORD_CWORD_CWORD,
3134        /*  78  "N" */ CWORD_CWORD_CWORD_CWORD,
3135        /*  79  "O" */ CWORD_CWORD_CWORD_CWORD,
3136        /*  80  "P" */ CWORD_CWORD_CWORD_CWORD,
3137        /*  81  "Q" */ CWORD_CWORD_CWORD_CWORD,
3138        /*  82  "R" */ CWORD_CWORD_CWORD_CWORD,
3139        /*  83  "S" */ CWORD_CWORD_CWORD_CWORD,
3140        /*  84  "T" */ CWORD_CWORD_CWORD_CWORD,
3141        /*  85  "U" */ CWORD_CWORD_CWORD_CWORD,
3142        /*  86  "V" */ CWORD_CWORD_CWORD_CWORD,
3143        /*  87  "W" */ CWORD_CWORD_CWORD_CWORD,
3144        /*  88  "X" */ CWORD_CWORD_CWORD_CWORD,
3145        /*  89  "Y" */ CWORD_CWORD_CWORD_CWORD,
3146        /*  90  "Z" */ CWORD_CWORD_CWORD_CWORD,
3147        /*  91  "[" */ CWORD_CCTL_CCTL_CWORD,
3148        /*  92  "\" */ CBACK_CBACK_CCTL_CBACK,
3149        /*  93  "]" */ CWORD_CCTL_CCTL_CWORD,
3150        /*  94  "^" */ CWORD_CWORD_CWORD_CWORD,
3151        /*  95  "_" */ CWORD_CWORD_CWORD_CWORD,
3152        /*  96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3153        /*  97  "a" */ CWORD_CWORD_CWORD_CWORD,
3154        /*  98  "b" */ CWORD_CWORD_CWORD_CWORD,
3155        /*  99  "c" */ CWORD_CWORD_CWORD_CWORD,
3156        /* 100  "d" */ CWORD_CWORD_CWORD_CWORD,
3157        /* 101  "e" */ CWORD_CWORD_CWORD_CWORD,
3158        /* 102  "f" */ CWORD_CWORD_CWORD_CWORD,
3159        /* 103  "g" */ CWORD_CWORD_CWORD_CWORD,
3160        /* 104  "h" */ CWORD_CWORD_CWORD_CWORD,
3161        /* 105  "i" */ CWORD_CWORD_CWORD_CWORD,
3162        /* 106  "j" */ CWORD_CWORD_CWORD_CWORD,
3163        /* 107  "k" */ CWORD_CWORD_CWORD_CWORD,
3164        /* 108  "l" */ CWORD_CWORD_CWORD_CWORD,
3165        /* 109  "m" */ CWORD_CWORD_CWORD_CWORD,
3166        /* 110  "n" */ CWORD_CWORD_CWORD_CWORD,
3167        /* 111  "o" */ CWORD_CWORD_CWORD_CWORD,
3168        /* 112  "p" */ CWORD_CWORD_CWORD_CWORD,
3169        /* 113  "q" */ CWORD_CWORD_CWORD_CWORD,
3170        /* 114  "r" */ CWORD_CWORD_CWORD_CWORD,
3171        /* 115  "s" */ CWORD_CWORD_CWORD_CWORD,
3172        /* 116  "t" */ CWORD_CWORD_CWORD_CWORD,
3173        /* 117  "u" */ CWORD_CWORD_CWORD_CWORD,
3174        /* 118  "v" */ CWORD_CWORD_CWORD_CWORD,
3175        /* 119  "w" */ CWORD_CWORD_CWORD_CWORD,
3176        /* 120  "x" */ CWORD_CWORD_CWORD_CWORD,
3177        /* 121  "y" */ CWORD_CWORD_CWORD_CWORD,
3178        /* 122  "z" */ CWORD_CWORD_CWORD_CWORD,
3179        /* 123  "{" */ CWORD_CWORD_CWORD_CWORD,
3180        /* 124  "|" */ CSPCL_CWORD_CWORD_CWORD,
3181        /* 125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3182        /* 126  "~" */ CWORD_CCTL_CCTL_CWORD,
3183        /* 127  del */ CWORD_CWORD_CWORD_CWORD,
3184        /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3185        /* 129 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
3186        /* 130 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
3187        /* 131 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
3188        /* 132 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
3189        /* 133 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
3190        /* 134 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
3191        /* 135 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
3192        /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3193        /* 137      */ CWORD_CWORD_CWORD_CWORD,
3194        /* 138      */ CWORD_CWORD_CWORD_CWORD,
3195        /* 139      */ CWORD_CWORD_CWORD_CWORD,
3196        /* 140      */ CWORD_CWORD_CWORD_CWORD,
3197        /* 141      */ CWORD_CWORD_CWORD_CWORD,
3198        /* 142      */ CWORD_CWORD_CWORD_CWORD,
3199        /* 143      */ CWORD_CWORD_CWORD_CWORD,
3200        /* 144      */ CWORD_CWORD_CWORD_CWORD,
3201        /* 145      */ CWORD_CWORD_CWORD_CWORD,
3202        /* 146      */ CWORD_CWORD_CWORD_CWORD,
3203        /* 147      */ CWORD_CWORD_CWORD_CWORD,
3204        /* 148      */ CWORD_CWORD_CWORD_CWORD,
3205        /* 149      */ CWORD_CWORD_CWORD_CWORD,
3206        /* 150      */ CWORD_CWORD_CWORD_CWORD,
3207        /* 151      */ CWORD_CWORD_CWORD_CWORD,
3208        /* 152      */ CWORD_CWORD_CWORD_CWORD,
3209        /* 153      */ CWORD_CWORD_CWORD_CWORD,
3210        /* 154      */ CWORD_CWORD_CWORD_CWORD,
3211        /* 155      */ CWORD_CWORD_CWORD_CWORD,
3212        /* 156      */ CWORD_CWORD_CWORD_CWORD,
3213        /* 157      */ CWORD_CWORD_CWORD_CWORD,
3214        /* 158      */ CWORD_CWORD_CWORD_CWORD,
3215        /* 159      */ CWORD_CWORD_CWORD_CWORD,
3216        /* 160      */ CWORD_CWORD_CWORD_CWORD,
3217        /* 161      */ CWORD_CWORD_CWORD_CWORD,
3218        /* 162      */ CWORD_CWORD_CWORD_CWORD,
3219        /* 163      */ CWORD_CWORD_CWORD_CWORD,
3220        /* 164      */ CWORD_CWORD_CWORD_CWORD,
3221        /* 165      */ CWORD_CWORD_CWORD_CWORD,
3222        /* 166      */ CWORD_CWORD_CWORD_CWORD,
3223        /* 167      */ CWORD_CWORD_CWORD_CWORD,
3224        /* 168      */ CWORD_CWORD_CWORD_CWORD,
3225        /* 169      */ CWORD_CWORD_CWORD_CWORD,
3226        /* 170      */ CWORD_CWORD_CWORD_CWORD,
3227        /* 171      */ CWORD_CWORD_CWORD_CWORD,
3228        /* 172      */ CWORD_CWORD_CWORD_CWORD,
3229        /* 173      */ CWORD_CWORD_CWORD_CWORD,
3230        /* 174      */ CWORD_CWORD_CWORD_CWORD,
3231        /* 175      */ CWORD_CWORD_CWORD_CWORD,
3232        /* 176      */ CWORD_CWORD_CWORD_CWORD,
3233        /* 177      */ CWORD_CWORD_CWORD_CWORD,
3234        /* 178      */ CWORD_CWORD_CWORD_CWORD,
3235        /* 179      */ CWORD_CWORD_CWORD_CWORD,
3236        /* 180      */ CWORD_CWORD_CWORD_CWORD,
3237        /* 181      */ CWORD_CWORD_CWORD_CWORD,
3238        /* 182      */ CWORD_CWORD_CWORD_CWORD,
3239        /* 183      */ CWORD_CWORD_CWORD_CWORD,
3240        /* 184      */ CWORD_CWORD_CWORD_CWORD,
3241        /* 185      */ CWORD_CWORD_CWORD_CWORD,
3242        /* 186      */ CWORD_CWORD_CWORD_CWORD,
3243        /* 187      */ CWORD_CWORD_CWORD_CWORD,
3244        /* 188      */ CWORD_CWORD_CWORD_CWORD,
3245        /* 189      */ CWORD_CWORD_CWORD_CWORD,
3246        /* 190      */ CWORD_CWORD_CWORD_CWORD,
3247        /* 191      */ CWORD_CWORD_CWORD_CWORD,
3248        /* 192      */ CWORD_CWORD_CWORD_CWORD,
3249        /* 193      */ CWORD_CWORD_CWORD_CWORD,
3250        /* 194      */ CWORD_CWORD_CWORD_CWORD,
3251        /* 195      */ CWORD_CWORD_CWORD_CWORD,
3252        /* 196      */ CWORD_CWORD_CWORD_CWORD,
3253        /* 197      */ CWORD_CWORD_CWORD_CWORD,
3254        /* 198      */ CWORD_CWORD_CWORD_CWORD,
3255        /* 199      */ CWORD_CWORD_CWORD_CWORD,
3256        /* 200      */ CWORD_CWORD_CWORD_CWORD,
3257        /* 201      */ CWORD_CWORD_CWORD_CWORD,
3258        /* 202      */ CWORD_CWORD_CWORD_CWORD,
3259        /* 203      */ CWORD_CWORD_CWORD_CWORD,
3260        /* 204      */ CWORD_CWORD_CWORD_CWORD,
3261        /* 205      */ CWORD_CWORD_CWORD_CWORD,
3262        /* 206      */ CWORD_CWORD_CWORD_CWORD,
3263        /* 207      */ CWORD_CWORD_CWORD_CWORD,
3264        /* 208      */ CWORD_CWORD_CWORD_CWORD,
3265        /* 209      */ CWORD_CWORD_CWORD_CWORD,
3266        /* 210      */ CWORD_CWORD_CWORD_CWORD,
3267        /* 211      */ CWORD_CWORD_CWORD_CWORD,
3268        /* 212      */ CWORD_CWORD_CWORD_CWORD,
3269        /* 213      */ CWORD_CWORD_CWORD_CWORD,
3270        /* 214      */ CWORD_CWORD_CWORD_CWORD,
3271        /* 215      */ CWORD_CWORD_CWORD_CWORD,
3272        /* 216      */ CWORD_CWORD_CWORD_CWORD,
3273        /* 217      */ CWORD_CWORD_CWORD_CWORD,
3274        /* 218      */ CWORD_CWORD_CWORD_CWORD,
3275        /* 219      */ CWORD_CWORD_CWORD_CWORD,
3276        /* 220      */ CWORD_CWORD_CWORD_CWORD,
3277        /* 221      */ CWORD_CWORD_CWORD_CWORD,
3278        /* 222      */ CWORD_CWORD_CWORD_CWORD,
3279        /* 223      */ CWORD_CWORD_CWORD_CWORD,
3280        /* 224      */ CWORD_CWORD_CWORD_CWORD,
3281        /* 225      */ CWORD_CWORD_CWORD_CWORD,
3282        /* 226      */ CWORD_CWORD_CWORD_CWORD,
3283        /* 227      */ CWORD_CWORD_CWORD_CWORD,
3284        /* 228      */ CWORD_CWORD_CWORD_CWORD,
3285        /* 229      */ CWORD_CWORD_CWORD_CWORD,
3286        /* 230      */ CWORD_CWORD_CWORD_CWORD,
3287        /* 231      */ CWORD_CWORD_CWORD_CWORD,
3288        /* 232      */ CWORD_CWORD_CWORD_CWORD,
3289        /* 233      */ CWORD_CWORD_CWORD_CWORD,
3290        /* 234      */ CWORD_CWORD_CWORD_CWORD,
3291        /* 235      */ CWORD_CWORD_CWORD_CWORD,
3292        /* 236      */ CWORD_CWORD_CWORD_CWORD,
3293        /* 237      */ CWORD_CWORD_CWORD_CWORD,
3294        /* 238      */ CWORD_CWORD_CWORD_CWORD,
3295        /* 239      */ CWORD_CWORD_CWORD_CWORD,
3296        /* 230      */ CWORD_CWORD_CWORD_CWORD,
3297        /* 241      */ CWORD_CWORD_CWORD_CWORD,
3298        /* 242      */ CWORD_CWORD_CWORD_CWORD,
3299        /* 243      */ CWORD_CWORD_CWORD_CWORD,
3300        /* 244      */ CWORD_CWORD_CWORD_CWORD,
3301        /* 245      */ CWORD_CWORD_CWORD_CWORD,
3302        /* 246      */ CWORD_CWORD_CWORD_CWORD,
3303        /* 247      */ CWORD_CWORD_CWORD_CWORD,
3304        /* 248      */ CWORD_CWORD_CWORD_CWORD,
3305        /* 249      */ CWORD_CWORD_CWORD_CWORD,
3306        /* 250      */ CWORD_CWORD_CWORD_CWORD,
3307        /* 251      */ CWORD_CWORD_CWORD_CWORD,
3308        /* 252      */ CWORD_CWORD_CWORD_CWORD,
3309        /* 253      */ CWORD_CWORD_CWORD_CWORD,
3310        /* 254      */ CWORD_CWORD_CWORD_CWORD,
3311        /* 255      */ CWORD_CWORD_CWORD_CWORD,
3312        /* PEOF */     CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3313# if ENABLE_ASH_ALIAS
3314        /* PEOA */     CSPCL_CIGN_CIGN_CIGN,
3315# endif
3316};
3317
3318#if 1
3319# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3320#else /* debug version, caught one signed char bug */
3321# define SIT(c, syntax) \
3322        ({ \
3323                if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3324                        bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3325                if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3326                        bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3327                ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3328        })
3329#endif
3330
3331#endif  /* !USE_SIT_FUNCTION */
3332
3333
3334/* ============ Alias handling */
3335
3336#if ENABLE_ASH_ALIAS
3337
3338#define ALIASINUSE 1
3339#define ALIASDEAD  2
3340
3341struct alias {
3342        struct alias *next;
3343        char *name;
3344        char *val;
3345        int flag;
3346};
3347
3348
3349static struct alias **atab; // [ATABSIZE];
3350#define INIT_G_alias() do { \
3351        atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3352} while (0)
3353
3354
3355static struct alias **
3356__lookupalias(const char *name)
3357{
3358        unsigned int hashval;
3359        struct alias **app;
3360        const char *p;
3361        unsigned int ch;
3362
3363        p = name;
3364
3365        ch = (unsigned char)*p;
3366        hashval = ch << 4;
3367        while (ch) {
3368                hashval += ch;
3369                ch = (unsigned char)*++p;
3370        }
3371        app = &atab[hashval % ATABSIZE];
3372
3373        for (; *app; app = &(*app)->next) {
3374                if (strcmp(name, (*app)->name) == 0) {
3375                        break;
3376                }
3377        }
3378
3379        return app;
3380}
3381
3382static struct alias *
3383lookupalias(const char *name, int check)
3384{
3385        struct alias *ap = *__lookupalias(name);
3386
3387        if (check && ap && (ap->flag & ALIASINUSE))
3388                return NULL;
3389        return ap;
3390}
3391
3392static struct alias *
3393freealias(struct alias *ap)
3394{
3395        struct alias *next;
3396
3397        if (ap->flag & ALIASINUSE) {
3398                ap->flag |= ALIASDEAD;
3399                return ap;
3400        }
3401
3402        next = ap->next;
3403        free(ap->name);
3404        free(ap->val);
3405        free(ap);
3406        return next;
3407}
3408
3409static void
3410setalias(const char *name, const char *val)
3411{
3412        struct alias *ap, **app;
3413
3414        app = __lookupalias(name);
3415        ap = *app;
3416        INT_OFF;
3417        if (ap) {
3418                if (!(ap->flag & ALIASINUSE)) {
3419                        free(ap->val);
3420                }
3421                ap->val = ckstrdup(val);
3422                ap->flag &= ~ALIASDEAD;
3423        } else {
3424                /* not found */
3425                ap = ckzalloc(sizeof(struct alias));
3426                ap->name = ckstrdup(name);
3427                ap->val = ckstrdup(val);
3428                /*ap->flag = 0; - ckzalloc did it */
3429                /*ap->next = NULL;*/
3430                *app = ap;
3431        }
3432        INT_ON;
3433}
3434
3435static int
3436unalias(const char *name)
3437{
3438        struct alias **app;
3439
3440        app = __lookupalias(name);
3441
3442        if (*app) {
3443                INT_OFF;
3444                *app = freealias(*app);
3445                INT_ON;
3446                return 0;
3447        }
3448
3449        return 1;
3450}
3451
3452static void
3453rmaliases(void)
3454{
3455        struct alias *ap, **app;
3456        int i;
3457
3458        INT_OFF;
3459        for (i = 0; i < ATABSIZE; i++) {
3460                app = &atab[i];
3461                for (ap = *app; ap; ap = *app) {
3462                        *app = freealias(*app);
3463                        if (ap == *app) {
3464                                app = &ap->next;
3465                        }
3466                }
3467        }
3468        INT_ON;
3469}
3470
3471static void
3472printalias(const struct alias *ap)
3473{
3474        out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3475}
3476
3477/*
3478 * TODO - sort output
3479 */
3480static int FAST_FUNC
3481aliascmd(int argc UNUSED_PARAM, char **argv)
3482{
3483        char *n, *v;
3484        int ret = 0;
3485        struct alias *ap;
3486
3487        if (!argv[1]) {
3488                int i;
3489
3490                for (i = 0; i < ATABSIZE; i++) {
3491                        for (ap = atab[i]; ap; ap = ap->next) {
3492                                printalias(ap);
3493                        }
3494                }
3495                return 0;
3496        }
3497        while ((n = *++argv) != NULL) {
3498                v = strchr(n+1, '=');
3499                if (v == NULL) { /* n+1: funny ksh stuff */
3500                        ap = *__lookupalias(n);
3501                        if (ap == NULL) {
3502                                fprintf(stderr, "%s: %s not found\n", "alias", n);
3503                                ret = 1;
3504                        } else
3505                                printalias(ap);
3506                } else {
3507                        *v++ = '\0';
3508                        setalias(n, v);
3509                }
3510        }
3511
3512        return ret;
3513}
3514
3515static int FAST_FUNC
3516unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3517{
3518        int i;
3519
3520        while (nextopt("a") != '\0') {
3521                rmaliases();
3522                return 0;
3523        }
3524        for (i = 0; *argptr; argptr++) {
3525                if (unalias(*argptr)) {
3526                        fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3527                        i = 1;
3528                }
3529        }
3530
3531        return i;
3532}
3533
3534#endif /* ASH_ALIAS */
3535
3536
3537/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
3538#define FORK_FG    0
3539#define FORK_BG    1
3540#define FORK_NOJOB 2
3541
3542/* mode flags for showjob(s) */
3543#define SHOW_ONLY_PGID  0x01    /* show only pgid (jobs -p) */
3544#define SHOW_PIDS       0x02    /* show individual pids, not just one line per job */
3545#define SHOW_CHANGED    0x04    /* only jobs whose state has changed */
3546#define SHOW_STDERR     0x08    /* print to stderr (else stdout) */
3547
3548/*
3549 * A job structure contains information about a job.  A job is either a
3550 * single process or a set of processes contained in a pipeline.  In the
3551 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3552 * array of pids.
3553 */
3554struct procstat {
3555        pid_t   ps_pid;         /* process id */
3556        int     ps_status;      /* last process status from wait() */
3557        char    *ps_cmd;        /* text of command being run */
3558};
3559
3560struct job {
3561        struct procstat ps0;    /* status of process */
3562        struct procstat *ps;    /* status of processes when more than one */
3563#if JOBS
3564        int stopstatus;         /* status of a stopped job */
3565#endif
3566        unsigned nprocs;        /* number of processes */
3567
3568#define JOBRUNNING      0       /* at least one proc running */
3569#define JOBSTOPPED      1       /* all procs are stopped */
3570#define JOBDONE         2       /* all procs are completed */
3571        unsigned
3572                state: 8,
3573#if JOBS
3574                sigint: 1,      /* job was killed by SIGINT */
3575                jobctl: 1,      /* job running under job control */
3576#endif
3577                waited: 1,      /* true if this entry has been waited for */
3578                used: 1,        /* true if this entry is in used */
3579                changed: 1;     /* true if status has changed */
3580        struct job *prev_job;   /* previous job */
3581};
3582
3583static struct job *makejob(/*union node *,*/ int);
3584static int forkshell(struct job *, union node *, int);
3585static int waitforjob(struct job *);
3586
3587#if !JOBS
3588enum { doing_jobctl = 0 };
3589#define setjobctl(on) do {} while (0)
3590#else
3591static smallint doing_jobctl; //references:8
3592static void setjobctl(int);
3593#endif
3594
3595/*
3596 * Ignore a signal.
3597 */
3598static void
3599ignoresig(int signo)
3600{
3601        /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3602        if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3603                /* No, need to do it */
3604                signal(signo, SIG_IGN);
3605        }
3606        sigmode[signo - 1] = S_HARD_IGN;
3607}
3608
3609/*
3610 * Only one usage site - in setsignal()
3611 */
3612static void
3613signal_handler(int signo)
3614{
3615        if (signo == SIGCHLD) {
3616                got_sigchld = 1;
3617                if (!trap[SIGCHLD])
3618                        return;
3619        }
3620
3621        gotsig[signo - 1] = 1;
3622        pending_sig = signo;
3623
3624        if (signo == SIGINT && !trap[SIGINT]) {
3625                if (!suppress_int) {
3626                        pending_sig = 0;
3627                        raise_interrupt(); /* does not return */
3628                }
3629                pending_int = 1;
3630        }
3631}
3632
3633/*
3634 * Set the signal handler for the specified signal.  The routine figures
3635 * out what it should be set to.
3636 */
3637static void
3638setsignal(int signo)
3639{
3640        char *t;
3641        char cur_act, new_act;
3642        struct sigaction act;
3643
3644        t = trap[signo];
3645        new_act = S_DFL;
3646        if (t != NULL) { /* trap for this sig is set */
3647                new_act = S_CATCH;
3648                if (t[0] == '\0') /* trap is "": ignore this sig */
3649                        new_act = S_IGN;
3650        }
3651
3652        if (rootshell && new_act == S_DFL) {
3653                switch (signo) {
3654                case SIGINT:
3655                        if (iflag || minusc || sflag == 0)
3656                                new_act = S_CATCH;
3657                        break;
3658                case SIGQUIT:
3659#if DEBUG
3660                        if (debug)
3661                                break;
3662#endif
3663                        /* man bash:
3664                         * "In all cases, bash ignores SIGQUIT. Non-builtin
3665                         * commands run by bash have signal handlers
3666                         * set to the values inherited by the shell
3667                         * from its parent". */
3668                        new_act = S_IGN;
3669                        break;
3670                case SIGTERM:
3671                        if (iflag)
3672                                new_act = S_IGN;
3673                        break;
3674#if JOBS
3675                case SIGTSTP:
3676                case SIGTTOU:
3677                        if (mflag)
3678                                new_act = S_IGN;
3679                        break;
3680#endif
3681                }
3682        }
3683        /* if !rootshell, we reset SIGQUIT to DFL,
3684         * whereas we have to restore it to what shell got on entry.
3685         * This is handled by the fact that if signal was IGNored on entry,
3686         * then cur_act is S_HARD_IGN and we never change its sigaction
3687         * (see code below).
3688         */
3689
3690        if (signo == SIGCHLD)
3691                new_act = S_CATCH;
3692
3693        t = &sigmode[signo - 1];
3694        cur_act = *t;
3695        if (cur_act == 0) {
3696                /* current setting is not yet known */
3697                if (sigaction(signo, NULL, &act)) {
3698                        /* pretend it worked; maybe we should give a warning,
3699                         * but other shells don't. We don't alter sigmode,
3700                         * so we retry every time.
3701                         * btw, in Linux it never fails. --vda */
3702                        return;
3703                }
3704                if (act.sa_handler == SIG_IGN) {
3705                        cur_act = S_HARD_IGN;
3706                        if (mflag
3707                         && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3708                        ) {
3709                                cur_act = S_IGN;   /* don't hard ignore these */
3710                        }
3711                }
3712                if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3713                        /* installing SIG_DFL over SIG_DFL is a no-op */
3714                        /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3715                        *t = S_DFL;
3716                        return;
3717                }
3718        }
3719        if (cur_act == S_HARD_IGN || cur_act == new_act)
3720                return;
3721
3722        *t = new_act;
3723
3724        act.sa_handler = SIG_DFL;
3725        switch (new_act) {
3726        case S_CATCH:
3727                act.sa_handler = signal_handler;
3728                break;
3729        case S_IGN:
3730                act.sa_handler = SIG_IGN;
3731                break;
3732        }
3733        /* flags and mask matter only if !DFL and !IGN, but we do it
3734         * for all cases for more deterministic behavior:
3735         */
3736        act.sa_flags = 0; //TODO: why not SA_RESTART?
3737        sigfillset(&act.sa_mask);
3738
3739        sigaction_set(signo, &act);
3740}
3741
3742/* mode flags for set_curjob */
3743#define CUR_DELETE 2
3744#define CUR_RUNNING 1
3745#define CUR_STOPPED 0
3746
3747#if JOBS
3748/* pgrp of shell on invocation */
3749static int initialpgrp; //references:2
3750static int ttyfd = -1; //5
3751#endif
3752/* array of jobs */
3753static struct job *jobtab; //5
3754/* size of array */
3755static unsigned njobs; //4
3756/* current job */
3757static struct job *curjob; //lots
3758/* number of presumed living untracked jobs */
3759static int jobless; //4
3760
3761#if 0
3762/* Bash has a feature: it restores termios after a successful wait for
3763 * a foreground job which had at least one stopped or sigkilled member.
3764 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3765 * properly restoring tty state. Should we do this too?
3766 * A reproducer: ^Z an interactive python:
3767 *
3768 * # python
3769 * Python 2.7.12 (...)
3770 * >>> ^Z
3771 *      { python leaves tty in -icanon -echo state. We do survive that... }
3772 *  [1]+  Stopped                    python
3773 *      { ...however, next program (python #2) does not survive it well: }
3774 * # python
3775 * Python 2.7.12 (...)
3776 * >>> Traceback (most recent call last):
3777 *      { above, I typed "qwerty<CR>", but -echo state is still in effect }
3778 *   File "<stdin>", line 1, in <module>
3779 * NameError: name 'qwerty' is not defined
3780 *
3781 * The implementation below is modeled on bash code and seems to work.
3782 * However, I'm not sure we should do this. For one: what if I'd fg
3783 * the stopped python instead? It'll be confused by "restored" tty state.
3784 */
3785static struct termios shell_tty_info;
3786static void
3787get_tty_state(void)
3788{
3789        if (rootshell && ttyfd >= 0)
3790                tcgetattr(ttyfd, &shell_tty_info);
3791}
3792static void
3793set_tty_state(void)
3794{
3795        /* if (rootshell) - caller ensures this */
3796        if (ttyfd >= 0)
3797                tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3798}
3799static int
3800job_signal_status(struct job *jp)
3801{
3802        int status;
3803        unsigned i;
3804        struct procstat *ps = jp->ps;
3805        for (i = 0; i < jp->nprocs; i++) {
3806                status = ps[i].ps_status;
3807                if (WIFSIGNALED(status) || WIFSTOPPED(status))
3808                        return status;
3809        }
3810        return 0;
3811}
3812static void
3813restore_tty_if_stopped_or_signaled(struct job *jp)
3814{
3815//TODO: check what happens if we come from waitforjob() in expbackq()
3816        if (rootshell) {
3817                int s = job_signal_status(jp);
3818                if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3819                        set_tty_state();
3820        }
3821}
3822#else
3823# define get_tty_state() ((void)0)
3824# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3825#endif
3826
3827static void
3828set_curjob(struct job *jp, unsigned mode)
3829{
3830        struct job *jp1;
3831        struct job **jpp, **curp;
3832
3833        /* first remove from list */
3834        jpp = curp = &curjob;
3835        while (1) {
3836                jp1 = *jpp;
3837                if (jp1 == jp)
3838                        break;
3839                jpp = &jp1->prev_job;
3840        }
3841        *jpp = jp1->prev_job;
3842
3843        /* Then re-insert in correct position */
3844        jpp = curp;
3845        switch (mode) {
3846        default:
3847#if DEBUG
3848                abort();
3849#endif
3850        case CUR_DELETE:
3851                /* job being deleted */
3852                break;
3853        case CUR_RUNNING:
3854                /* newly created job or backgrounded job,
3855                 * put after all stopped jobs.
3856                 */
3857                while (1) {
3858                        jp1 = *jpp;
3859#if JOBS
3860                        if (!jp1 || jp1->state != JOBSTOPPED)
3861#endif
3862                                break;
3863                        jpp = &jp1->prev_job;
3864                }
3865                /* FALLTHROUGH */
3866#if JOBS
3867        case CUR_STOPPED:
3868#endif
3869                /* newly stopped job - becomes curjob */
3870                jp->prev_job = *jpp;
3871                *jpp = jp;
3872                break;
3873        }
3874}
3875
3876#if JOBS || DEBUG
3877static int
3878jobno(const struct job *jp)
3879{
3880        return jp - jobtab + 1;
3881}
3882#endif
3883
3884/*
3885 * Convert a job name to a job structure.
3886 */
3887#if !JOBS
3888#define getjob(name, getctl) getjob(name)
3889#endif
3890static struct job *
3891getjob(const char *name, int getctl)
3892{
3893        struct job *jp;
3894        struct job *found;
3895        const char *err_msg = "%s: no such job";
3896        unsigned num;
3897        int c;
3898        const char *p;
3899        char *(*match)(const char *, const char *);
3900
3901        jp = curjob;
3902        p = name;
3903        if (!p)
3904                goto currentjob;
3905
3906        if (*p != '%')
3907                goto err;
3908
3909        c = *++p;
3910        if (!c)
3911                goto currentjob;
3912
3913        if (!p[1]) {
3914                if (c == '+' || c == '%') {
3915 currentjob:
3916                        err_msg = "No current job";
3917                        goto check;
3918                }
3919                if (c == '-') {
3920                        if (jp)
3921                                jp = jp->prev_job;
3922                        err_msg = "No previous job";
3923 check:
3924                        if (!jp)
3925                                goto err;
3926                        goto gotit;
3927                }
3928        }
3929
3930        if (is_number(p)) {
3931                num = atoi(p);
3932                if (num > 0 && num <= njobs) {
3933                        jp = jobtab + num - 1;
3934                        if (jp->used)
3935                                goto gotit;
3936                        goto err;
3937                }
3938        }
3939
3940        match = prefix;
3941        if (*p == '?') {
3942                match = strstr;
3943                p++;
3944        }
3945
3946        found = NULL;
3947        while (jp) {
3948                if (match(jp->ps[0].ps_cmd, p)) {
3949                        if (found)
3950                                goto err;
3951                        found = jp;
3952                        err_msg = "%s: ambiguous";
3953                }
3954                jp = jp->prev_job;
3955        }
3956        if (!found)
3957                goto err;
3958        jp = found;
3959
3960 gotit:
3961#if JOBS
3962        err_msg = "job %s not created under job control";
3963        if (getctl && jp->jobctl == 0)
3964                goto err;
3965#endif
3966        return jp;
3967 err:
3968        ash_msg_and_raise_error(err_msg, name);
3969}
3970
3971/*
3972 * Mark a job structure as unused.
3973 */
3974static void
3975freejob(struct job *jp)
3976{
3977        struct procstat *ps;
3978        int i;
3979
3980        INT_OFF;
3981        for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3982                if (ps->ps_cmd != nullstr)
3983                        free(ps->ps_cmd);
3984        }
3985        if (jp->ps != &jp->ps0)
3986                free(jp->ps);
3987        jp->used = 0;
3988        set_curjob(jp, CUR_DELETE);
3989        INT_ON;
3990}
3991
3992#if JOBS
3993static void
3994xtcsetpgrp(int fd, pid_t pgrp)
3995{
3996        if (tcsetpgrp(fd, pgrp))
3997                ash_msg_and_raise_perror("can't set tty process group");
3998}
3999
4000/*
4001 * Turn job control on and off.
4002 *
4003 * Note:  This code assumes that the third arg to ioctl is a character
4004 * pointer, which is true on Berkeley systems but not System V.  Since
4005 * System V doesn't have job control yet, this isn't a problem now.
4006 *
4007 * Called with interrupts off.
4008 */
4009static void
4010setjobctl(int on)
4011{
4012        int fd;
4013        int pgrp;
4014
4015        if (on == doing_jobctl || rootshell == 0)
4016                return;
4017        if (on) {
4018                int ofd;
4019                ofd = fd = open(_PATH_TTY, O_RDWR);
4020                if (fd < 0) {
4021        /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
4022         * That sometimes helps to acquire controlling tty.
4023         * Obviously, a workaround for bugs when someone
4024         * failed to provide a controlling tty to bash! :) */
4025                        fd = 2;
4026                        while (!isatty(fd))
4027                                if (--fd < 0)
4028                                        goto out;
4029                }
4030                /* fd is a tty at this point */
4031                fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
4032                if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
4033                        close(ofd);
4034                if (fd < 0)
4035                        goto out; /* F_DUPFD failed */
4036                if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
4037                        close_on_exec_on(fd);
4038                while (1) { /* while we are in the background */
4039                        pgrp = tcgetpgrp(fd);
4040                        if (pgrp < 0) {
4041 out:
4042                                ash_msg("can't access tty; job control turned off");
4043                                mflag = on = 0;
4044                                goto close;
4045                        }
4046                        if (pgrp == getpgrp())
4047                                break;
4048                        killpg(0, SIGTTIN);
4049                }
4050                initialpgrp = pgrp;
4051
4052                setsignal(SIGTSTP);
4053                setsignal(SIGTTOU);
4054                setsignal(SIGTTIN);
4055                pgrp = rootpid;
4056                setpgid(0, pgrp);
4057                xtcsetpgrp(fd, pgrp);
4058        } else {
4059                /* turning job control off */
4060                fd = ttyfd;
4061                pgrp = initialpgrp;
4062                /* was xtcsetpgrp, but this can make exiting ash
4063                 * loop forever if pty is already deleted */
4064                tcsetpgrp(fd, pgrp);
4065                setpgid(0, pgrp);
4066                setsignal(SIGTSTP);
4067                setsignal(SIGTTOU);
4068                setsignal(SIGTTIN);
4069 close:
4070                if (fd >= 0)
4071                        close(fd);
4072                fd = -1;
4073        }
4074        ttyfd = fd;
4075        doing_jobctl = on;
4076}
4077
4078static int FAST_FUNC
4079killcmd(int argc, char **argv)
4080{
4081        if (argv[1] && strcmp(argv[1], "-l") != 0) {
4082                int i = 1;
4083                do {
4084                        if (argv[i][0] == '%') {
4085                                /*
4086                                 * "kill %N" - job kill
4087                                 * Converting to pgrp / pid kill
4088                                 */
4089                                struct job *jp;
4090                                char *dst;
4091                                int j, n;
4092
4093                                jp = getjob(argv[i], 0);
4094                                /*
4095                                 * In jobs started under job control, we signal
4096                                 * entire process group by kill -PGRP_ID.
4097                                 * This happens, f.e., in interactive shell.
4098                                 *
4099                                 * Otherwise, we signal each child via
4100                                 * kill PID1 PID2 PID3.
4101                                 * Testcases:
4102                                 * sh -c 'sleep 1|sleep 1 & kill %1'
4103                                 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4104                                 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4105                                 */
4106                                n = jp->nprocs; /* can't be 0 (I hope) */
4107                                if (jp->jobctl)
4108                                        n = 1;
4109                                dst = alloca(n * sizeof(int)*4);
4110                                argv[i] = dst;
4111                                for (j = 0; j < n; j++) {
4112                                        struct procstat *ps = &jp->ps[j];
4113                                        /* Skip non-running and not-stopped members
4114                                         * (i.e. dead members) of the job
4115                                         */
4116                                        if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4117                                                continue;
4118                                        /*
4119                                         * kill_main has matching code to expect
4120                                         * leading space. Needed to not confuse
4121                                         * negative pids with "kill -SIGNAL_NO" syntax
4122                                         */
4123                                        dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4124                                }
4125                                *dst = '\0';
4126                        }
4127                } while (argv[++i]);
4128        }
4129        return kill_main(argc, argv);
4130}
4131
4132static void
4133showpipe(struct job *jp /*, FILE *out*/)
4134{
4135        struct procstat *ps;
4136        struct procstat *psend;
4137
4138        psend = jp->ps + jp->nprocs;
4139        for (ps = jp->ps + 1; ps < psend; ps++)
4140                printf(" | %s", ps->ps_cmd);
4141        newline_and_flush(stdout);
4142        flush_stdout_stderr();
4143}
4144
4145
4146static int
4147restartjob(struct job *jp, int mode)
4148{
4149        struct procstat *ps;
4150        int i;
4151        int status;
4152        pid_t pgid;
4153
4154        INT_OFF;
4155        if (jp->state == JOBDONE)
4156                goto out;
4157        jp->state = JOBRUNNING;
4158        pgid = jp->ps[0].ps_pid;
4159        if (mode == FORK_FG) {
4160                get_tty_state();
4161                xtcsetpgrp(ttyfd, pgid);
4162        }
4163        killpg(pgid, SIGCONT);
4164        ps = jp->ps;
4165        i = jp->nprocs;
4166        do {
4167                if (WIFSTOPPED(ps->ps_status)) {
4168                        ps->ps_status = -1;
4169                }
4170                ps++;
4171        } while (--i);
4172 out:
4173        status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4174        INT_ON;
4175        return status;
4176}
4177
4178static int FAST_FUNC
4179fg_bgcmd(int argc UNUSED_PARAM, char **argv)
4180{
4181        struct job *jp;
4182        int mode;
4183        int retval;
4184
4185        mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4186        nextopt(nullstr);
4187        argv = argptr;
4188        do {
4189                jp = getjob(*argv, 1);
4190                if (mode == FORK_BG) {
4191                        set_curjob(jp, CUR_RUNNING);
4192                        printf("[%d] ", jobno(jp));
4193                }
4194                out1str(jp->ps[0].ps_cmd);
4195                showpipe(jp /*, stdout*/);
4196                retval = restartjob(jp, mode);
4197        } while (*argv && *++argv);
4198        return retval;
4199}
4200#endif
4201
4202static int
4203sprint_status48(char *s, int status, int sigonly)
4204{
4205        int col;
4206        int st;
4207
4208        col = 0;
4209        if (!WIFEXITED(status)) {
4210#if JOBS
4211                if (WIFSTOPPED(status))
4212                        st = WSTOPSIG(status);
4213                else
4214#endif
4215                        st = WTERMSIG(status);
4216                if (sigonly) {
4217                        if (st == SIGINT || st == SIGPIPE)
4218                                goto out;
4219#if JOBS
4220                        if (WIFSTOPPED(status))
4221                                goto out;
4222#endif
4223                }
4224                st &= 0x7f;
4225//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
4226                col = fmtstr(s, 32, strsignal(st));
4227                if (WCOREDUMP(status)) {
4228                        strcpy(s + col, " (core dumped)");
4229                        col += sizeof(" (core dumped)")-1;
4230                }
4231        } else if (!sigonly) {
4232                st = WEXITSTATUS(status);
4233                col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
4234        }
4235 out:
4236        return col;
4237}
4238
4239static int
4240wait_block_or_sig(int *status)
4241{
4242        int pid;
4243
4244        do {
4245                sigset_t mask;
4246
4247                /* Poll all children for changes in their state */
4248                got_sigchld = 0;
4249                /* if job control is active, accept stopped processes too */
4250                pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
4251                if (pid != 0)
4252                        break; /* Error (e.g. EINTR, ECHILD) or pid */
4253
4254                /* Children exist, but none are ready. Sleep until interesting signal */
4255#if 1
4256                sigfillset(&mask);
4257                sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */
4258                while (!got_sigchld && !pending_sig)
4259                        sigsuspend(&mask);
4260                sigprocmask(SIG_SETMASK, &mask, NULL);
4261#else /* unsafe: a signal can set pending_sig after check, but before pause() */
4262                while (!got_sigchld && !pending_sig)
4263                        pause();
4264#endif
4265
4266                /* If it was SIGCHLD, poll children again */
4267        } while (got_sigchld);
4268
4269        return pid;
4270}
4271
4272#define DOWAIT_NONBLOCK 0
4273#define DOWAIT_BLOCK    1
4274#define DOWAIT_BLOCK_OR_SIG 2
4275#if BASH_WAIT_N
4276# define DOWAIT_JOBSTATUS 0x10   /* OR this to get job's exitstatus instead of pid */
4277#endif
4278
4279static int
4280dowait(int block, struct job *job)
4281{
4282        int pid;
4283        int status;
4284        struct job *jp;
4285        struct job *thisjob;
4286#if BASH_WAIT_N
4287        bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
4288        block = (block & ~DOWAIT_JOBSTATUS);
4289#endif
4290
4291        TRACE(("dowait(0x%x) called\n", block));
4292
4293        /* It's wrong to call waitpid() outside of INT_OFF region:
4294         * signal can arrive just after syscall return and handler can
4295         * longjmp away, losing stop/exit notification processing.
4296         * Thus, for "jobs" builtin, and for waiting for a fg job,
4297         * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4298         *
4299         * However, for "wait" builtin it is wrong to simply call waitpid()
4300         * in INT_OFF region: "wait" needs to wait for any running job
4301         * to change state, but should exit on any trap too.
4302         * In INT_OFF region, a signal just before syscall entry can set
4303         * pending_sig variables, but we can't check them, and we would
4304         * either enter a sleeping waitpid() (BUG), or need to busy-loop.
4305         *
4306         * Because of this, we run inside INT_OFF, but use a special routine
4307         * which combines waitpid() and sigsuspend().
4308         * This is the reason why we need to have a handler for SIGCHLD:
4309         * SIG_DFL handler does not wake sigsuspend().
4310         */
4311        INT_OFF;
4312        if (block == DOWAIT_BLOCK_OR_SIG) {
4313                pid = wait_block_or_sig(&status);
4314        } else {
4315                int wait_flags = 0;
4316                if (block == DOWAIT_NONBLOCK)
4317                        wait_flags = WNOHANG;
4318                /* if job control is active, accept stopped processes too */
4319                if (doing_jobctl)
4320                        wait_flags |= WUNTRACED;
4321                /* NB: _not_ safe_waitpid, we need to detect EINTR */
4322                pid = waitpid(-1, &status, wait_flags);
4323        }
4324        TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4325                                pid, status, errno, strerror(errno)));
4326        thisjob = NULL;
4327        if (pid <= 0)
4328                goto out;
4329
4330        for (jp = curjob; jp; jp = jp->prev_job) {
4331                int jobstate;
4332                struct procstat *ps;
4333                struct procstat *psend;
4334                if (jp->state == JOBDONE)
4335                        continue;
4336                jobstate = JOBDONE;
4337                ps = jp->ps;
4338                psend = ps + jp->nprocs;
4339                do {
4340                        if (ps->ps_pid == pid) {
4341                                TRACE(("Job %d: changing status of proc %d "
4342                                        "from 0x%x to 0x%x\n",
4343                                        jobno(jp), pid, ps->ps_status, status));
4344                                ps->ps_status = status;
4345                                thisjob = jp;
4346                        }
4347                        if (ps->ps_status == -1)
4348                                jobstate = JOBRUNNING;
4349#if JOBS
4350                        if (jobstate == JOBRUNNING)
4351                                continue;
4352                        if (WIFSTOPPED(ps->ps_status)) {
4353                                jp->stopstatus = ps->ps_status;
4354                                jobstate = JOBSTOPPED;
4355                        }
4356#endif
4357                } while (++ps < psend);
4358                if (!thisjob)
4359                        continue;
4360
4361                /* Found the job where one of its processes changed its state.
4362                 * Is there at least one live and running process in this job? */
4363                if (jobstate != JOBRUNNING) {
4364                        /* No. All live processes in the job are stopped
4365                         * (JOBSTOPPED) or there are no live processes (JOBDONE)
4366                         */
4367                        thisjob->changed = 1;
4368                        if (thisjob->state != jobstate) {
4369                                TRACE(("Job %d: changing state from %d to %d\n",
4370                                        jobno(thisjob), thisjob->state, jobstate));
4371                                thisjob->state = jobstate;
4372#if JOBS
4373                                if (jobstate == JOBSTOPPED)
4374                                        set_curjob(thisjob, CUR_STOPPED);
4375#endif
4376                        }
4377                }
4378                goto out;
4379        }
4380        /* The process wasn't found in job list */
4381#if JOBS
4382        if (!WIFSTOPPED(status))
4383                jobless--;
4384#endif
4385 out:
4386        INT_ON;
4387
4388#if BASH_WAIT_N
4389        if (want_jobexitstatus) {
4390                pid = -1;
4391                if (thisjob && thisjob->state == JOBDONE)
4392                        pid = thisjob->ps[thisjob->nprocs - 1].ps_status;
4393        }
4394#endif
4395        if (thisjob && thisjob == job) {
4396                char s[48 + 1];
4397                int len;
4398
4399                len = sprint_status48(s, status, 1);
4400                if (len) {
4401                        s[len] = '\n';
4402                        s[len + 1] = '\0';
4403                        out2str(s);
4404                }
4405        }
4406        return pid;
4407}
4408
4409#if JOBS
4410static void
4411showjob(struct job *jp, int mode)
4412{
4413        struct procstat *ps;
4414        struct procstat *psend;
4415        int col;
4416        int indent_col;
4417        char s[16 + 16 + 48];
4418        FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4419
4420        ps = jp->ps;
4421
4422        if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4423                /* just output process (group) id of pipeline */
4424                fprintf(out, "%d\n", ps->ps_pid);
4425                return;
4426        }
4427
4428        col = fmtstr(s, 16, "[%d]   ", jobno(jp));
4429        indent_col = col;
4430
4431        if (jp == curjob)
4432                s[col - 3] = '+';
4433        else if (curjob && jp == curjob->prev_job)
4434                s[col - 3] = '-';
4435
4436        if (mode & SHOW_PIDS)
4437                col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4438
4439        psend = ps + jp->nprocs;
4440
4441        if (jp->state == JOBRUNNING) {
4442                strcpy(s + col, "Running");
4443                col += sizeof("Running") - 1;
4444        } else {
4445                int status = psend[-1].ps_status;
4446                if (jp->state == JOBSTOPPED)
4447                        status = jp->stopstatus;
4448                col += sprint_status48(s + col, status, 0);
4449        }
4450        /* By now, "[JOBID]*  [maybe PID] STATUS" is printed */
4451
4452        /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4453         * or prints several "PID             | <cmdN>" lines,
4454         * depending on SHOW_PIDS bit.
4455         * We do not print status of individual processes
4456         * between PID and <cmdN>. bash does it, but not very well:
4457         * first line shows overall job status, not process status,
4458         * making it impossible to know 1st process status.
4459         */
4460        goto start;
4461        do {
4462                /* for each process */
4463                s[0] = '\0';
4464                col = 33;
4465                if (mode & SHOW_PIDS)
4466                        col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4467 start:
4468                fprintf(out, "%s%*c%s%s",
4469                                s,
4470                                33 - col >= 0 ? 33 - col : 0, ' ',
4471                                ps == jp->ps ? "" : "| ",
4472                                ps->ps_cmd
4473                );
4474        } while (++ps != psend);
4475        newline_and_flush(out);
4476
4477        jp->changed = 0;
4478
4479        if (jp->state == JOBDONE) {
4480                TRACE(("showjob: freeing job %d\n", jobno(jp)));
4481                freejob(jp);
4482        }
4483}
4484
4485/*
4486 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
4487 * statuses have changed since the last call to showjobs.
4488 */
4489static void
4490showjobs(int mode)
4491{
4492        struct job *jp;
4493
4494        TRACE(("showjobs(0x%x) called\n", mode));
4495
4496        /* Handle all finished jobs */
4497        while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
4498                continue;
4499
4500        for (jp = curjob; jp; jp = jp->prev_job) {
4501                if (!(mode & SHOW_CHANGED) || jp->changed) {
4502                        showjob(jp, mode);
4503                }
4504        }
4505}
4506
4507static int FAST_FUNC
4508jobscmd(int argc UNUSED_PARAM, char **argv)
4509{
4510        int mode, m;
4511
4512        mode = 0;
4513        while ((m = nextopt("lp")) != '\0') {
4514                if (m == 'l')
4515                        mode |= SHOW_PIDS;
4516                else
4517                        mode |= SHOW_ONLY_PGID;
4518        }
4519
4520        argv = argptr;
4521        if (*argv) {
4522                do
4523                        showjob(getjob(*argv, 0), mode);
4524                while (*++argv);
4525        } else {
4526                showjobs(mode);
4527        }
4528
4529        return 0;
4530}
4531#endif /* JOBS */
4532
4533/* Called only on finished or stopped jobs (no members are running) */
4534static int
4535getstatus(struct job *job)
4536{
4537        int status;
4538        int retval;
4539        struct procstat *ps;
4540
4541        /* Fetch last member's status */
4542        ps = job->ps + job->nprocs - 1;
4543        status = ps->ps_status;
4544        if (pipefail) {
4545                /* "set -o pipefail" mode: use last _nonzero_ status */
4546                while (status == 0 && --ps >= job->ps)
4547                        status = ps->ps_status;
4548        }
4549
4550        retval = WEXITSTATUS(status);
4551        if (!WIFEXITED(status)) {
4552#if JOBS
4553                retval = WSTOPSIG(status);
4554                if (!WIFSTOPPED(status))
4555#endif
4556                {
4557                        /* XXX: limits number of signals */
4558                        retval = WTERMSIG(status);
4559#if JOBS
4560                        if (retval == SIGINT)
4561                                job->sigint = 1;
4562#endif
4563                }
4564                retval += 128;
4565        }
4566        TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4567                jobno(job), job->nprocs, status, retval));
4568        return retval;
4569}
4570
4571static int FAST_FUNC
4572waitcmd(int argc UNUSED_PARAM, char **argv)
4573{
4574        struct job *job;
4575        int retval;
4576        struct job *jp;
4577#if BASH_WAIT_N
4578        int status;
4579        char one = nextopt("n");
4580#else
4581        nextopt(nullstr);
4582#endif
4583        retval = 0;
4584
4585        argv = argptr;
4586        if (!argv[0]) {
4587                /* wait for all jobs / one job if -n */
4588                for (;;) {
4589                        jp = curjob;
4590#if BASH_WAIT_N
4591                        if (one && !jp)
4592                                /* exitcode of "wait -n" with nothing to wait for is 127, not 0 */
4593                                retval = 127;
4594#endif
4595                        while (1) {
4596                                if (!jp) /* no running procs */
4597                                        goto ret;
4598                                if (jp->state == JOBRUNNING)
4599                                        break;
4600                                jp->waited = 1;
4601                                jp = jp->prev_job;
4602                        }
4603        /* man bash:
4604         * "When bash is waiting for an asynchronous command via
4605         * the wait builtin, the reception of a signal for which a trap
4606         * has been set will cause the wait builtin to return immediately
4607         * with an exit status greater than 128, immediately after which
4608         * the trap is executed."
4609         */
4610#if BASH_WAIT_N
4611                        status = dowait(DOWAIT_BLOCK_OR_SIG | DOWAIT_JOBSTATUS, NULL);
4612#else
4613                        dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4614#endif
4615        /* if child sends us a signal *and immediately exits*,
4616         * dowait() returns pid > 0. Check this case,
4617         * not "if (dowait() < 0)"!
4618         */
4619                        if (pending_sig)
4620                                goto sigout;
4621#if BASH_WAIT_N
4622                        if (one) {
4623                                /* wait -n waits for one _job_, not one _process_.
4624                                 *  date; sleep 3 & sleep 2 | sleep 1 & wait -n; date
4625                                 * should wait for 2 seconds. Not 1 or 3.
4626                                 */
4627                                if (status != -1 && !WIFSTOPPED(status)) {
4628                                        retval = WEXITSTATUS(status);
4629                                        if (WIFSIGNALED(status))
4630                                                retval = WTERMSIG(status) + 128;
4631                                        goto ret;
4632                                }
4633                        }
4634#endif
4635                }
4636        }
4637
4638        retval = 127;
4639        do {
4640                if (**argv != '%') {
4641                        pid_t pid = number(*argv);
4642                        job = curjob;
4643                        while (1) {
4644                                if (!job)
4645                                        goto repeat;
4646                                if (job->ps[job->nprocs - 1].ps_pid == pid)
4647                                        break;
4648                                job = job->prev_job;
4649                        }
4650                } else {
4651                        job = getjob(*argv, 0);
4652                }
4653                /* loop until process terminated or stopped */
4654                while (job->state == JOBRUNNING) {
4655                        dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4656                        if (pending_sig)
4657                                goto sigout;
4658                }
4659                job->waited = 1;
4660                retval = getstatus(job);
4661 repeat: ;
4662        } while (*++argv);
4663
4664 ret:
4665        return retval;
4666 sigout:
4667        retval = 128 + pending_sig;
4668        return retval;
4669}
4670
4671static struct job *
4672growjobtab(void)
4673{
4674        size_t len;
4675        ptrdiff_t offset;
4676        struct job *jp, *jq;
4677
4678        len = njobs * sizeof(*jp);
4679        jq = jobtab;
4680        jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4681
4682        offset = (char *)jp - (char *)jq;
4683        if (offset) {
4684                /* Relocate pointers */
4685                size_t l = len;
4686
4687                jq = (struct job *)((char *)jq + l);
4688                while (l) {
4689                        l -= sizeof(*jp);
4690                        jq--;
4691#define joff(p) ((struct job *)((char *)(p) + l))
4692#define jmove(p) (p) = (void *)((char *)(p) + offset)
4693                        if (joff(jp)->ps == &jq->ps0)
4694                                jmove(joff(jp)->ps);
4695                        if (joff(jp)->prev_job)
4696                                jmove(joff(jp)->prev_job);
4697                }
4698                if (curjob)
4699                        jmove(curjob);
4700#undef joff
4701#undef jmove
4702        }
4703
4704        njobs += 4;
4705        jobtab = jp;
4706        jp = (struct job *)((char *)jp + len);
4707        jq = jp + 3;
4708        do {
4709                jq->used = 0;
4710        } while (--jq >= jp);
4711        return jp;
4712}
4713
4714/*
4715 * Return a new job structure.
4716 * Called with interrupts off.
4717 */
4718static struct job *
4719makejob(/*union node *node,*/ int nprocs)
4720{
4721        int i;
4722        struct job *jp;
4723
4724        for (i = njobs, jp = jobtab; ; jp++) {
4725                if (--i < 0) {
4726                        jp = growjobtab();
4727                        break;
4728                }
4729                if (jp->used == 0)
4730                        break;
4731                if (jp->state != JOBDONE || !jp->waited)
4732                        continue;
4733#if JOBS
4734                if (doing_jobctl)
4735                        continue;
4736#endif
4737                freejob(jp);
4738                break;
4739        }
4740        memset(jp, 0, sizeof(*jp));
4741#if JOBS
4742        /* jp->jobctl is a bitfield.
4743         * "jp->jobctl |= doing_jobctl" likely to give awful code */
4744        if (doing_jobctl)
4745                jp->jobctl = 1;
4746#endif
4747        jp->prev_job = curjob;
4748        curjob = jp;
4749        jp->used = 1;
4750        jp->ps = &jp->ps0;
4751        if (nprocs > 1) {
4752                jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4753        }
4754        TRACE(("makejob(%d) returns %%%d\n", nprocs,
4755                                jobno(jp)));
4756        return jp;
4757}
4758
4759#if JOBS
4760/*
4761 * Return a string identifying a command (to be printed by the
4762 * jobs command).
4763 */
4764static char *cmdnextc;
4765
4766static void
4767cmdputs(const char *s)
4768{
4769        static const char vstype[VSTYPE + 1][3] = {
4770                "", "}", "-", "+", "?", "=",
4771                "%", "%%", "#", "##"
4772                IF_BASH_SUBSTR(, ":")
4773                IF_BASH_PATTERN_SUBST(, "/", "//")
4774        };
4775
4776        const char *p, *str;
4777        char cc[2];
4778        char *nextc;
4779        unsigned char c;
4780        unsigned char subtype = 0;
4781        int quoted = 0;
4782
4783        cc[1] = '\0';
4784        nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4785        p = s;
4786        while ((c = *p++) != '\0') {
4787                str = NULL;
4788                switch (c) {
4789                case CTLESC:
4790                        c = *p++;
4791                        break;
4792                case CTLVAR:
4793                        subtype = *p++;
4794                        if ((subtype & VSTYPE) == VSLENGTH)
4795                                str = "${#";
4796                        else
4797                                str = "${";
4798                        goto dostr;
4799                case CTLENDVAR:
4800                        str = "\"}" + !(quoted & 1);
4801                        quoted >>= 1;
4802                        subtype = 0;
4803                        goto dostr;
4804                case CTLBACKQ:
4805                        str = "$(...)";
4806                        goto dostr;
4807#if ENABLE_FEATURE_SH_MATH
4808                case CTLARI:
4809                        str = "$((";
4810                        goto dostr;
4811                case CTLENDARI:
4812                        str = "))";
4813                        goto dostr;
4814#endif
4815                case CTLQUOTEMARK:
4816                        quoted ^= 1;
4817                        c = '"';
4818                        break;
4819                case '=':
4820                        if (subtype == 0)
4821                                break;
4822                        if ((subtype & VSTYPE) != VSNORMAL)
4823                                quoted <<= 1;
4824                        str = vstype[subtype & VSTYPE];
4825                        if (subtype & VSNUL)
4826                                c = ':';
4827                        else
4828                                goto checkstr;
4829                        break;
4830                case '\'':
4831                case '\\':
4832                case '"':
4833                case '$':
4834                        /* These can only happen inside quotes */
4835                        cc[0] = c;
4836                        str = cc;
4837//FIXME:
4838// $ true $$ &
4839// $ <cr>
4840// [1]+  Done    true ${\$}   <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
4841                        c = '\\';
4842                        break;
4843                default:
4844                        break;
4845                }
4846                USTPUTC(c, nextc);
4847 checkstr:
4848                if (!str)
4849                        continue;
4850 dostr:
4851                while ((c = *str++) != '\0') {
4852                        USTPUTC(c, nextc);
4853                }
4854        } /* while *p++ not NUL */
4855
4856        if (quoted & 1) {
4857                USTPUTC('"', nextc);
4858        }
4859        *nextc = 0;
4860        cmdnextc = nextc;
4861}
4862
4863/* cmdtxt() and cmdlist() call each other */
4864static void cmdtxt(union node *n);
4865
4866static void
4867cmdlist(union node *np, int sep)
4868{
4869        for (; np; np = np->narg.next) {
4870                if (!sep)
4871                        cmdputs(" ");
4872                cmdtxt(np);
4873                if (sep && np->narg.next)
4874                        cmdputs(" ");
4875        }
4876}
4877
4878static void
4879cmdtxt(union node *n)
4880{
4881        union node *np;
4882        struct nodelist *lp;
4883        const char *p;
4884
4885        if (!n)
4886                return;
4887        switch (n->type) {
4888        default:
4889#if DEBUG
4890                abort();
4891#endif
4892        case NPIPE:
4893                lp = n->npipe.cmdlist;
4894                for (;;) {
4895                        cmdtxt(lp->n);
4896                        lp = lp->next;
4897                        if (!lp)
4898                                break;
4899                        cmdputs(" | ");
4900                }
4901                break;
4902        case NSEMI:
4903                p = "; ";
4904                goto binop;
4905        case NAND:
4906                p = " && ";
4907                goto binop;
4908        case NOR:
4909                p = " || ";
4910 binop:
4911                cmdtxt(n->nbinary.ch1);
4912                cmdputs(p);
4913                n = n->nbinary.ch2;
4914                goto donode;
4915        case NREDIR:
4916        case NBACKGND:
4917                n = n->nredir.n;
4918                goto donode;
4919        case NNOT:
4920                cmdputs("!");
4921                n = n->nnot.com;
4922 donode:
4923                cmdtxt(n);
4924                break;
4925        case NIF:
4926                cmdputs("if ");
4927                cmdtxt(n->nif.test);
4928                cmdputs("; then ");
4929                if (n->nif.elsepart) {
4930                        cmdtxt(n->nif.ifpart);
4931                        cmdputs("; else ");
4932                        n = n->nif.elsepart;
4933                } else {
4934                        n = n->nif.ifpart;
4935                }
4936                p = "; fi";
4937                goto dotail;
4938        case NSUBSHELL:
4939                cmdputs("(");
4940                n = n->nredir.n;
4941                p = ")";
4942                goto dotail;
4943        case NWHILE:
4944                p = "while ";
4945                goto until;
4946        case NUNTIL:
4947                p = "until ";
4948 until:
4949                cmdputs(p);
4950                cmdtxt(n->nbinary.ch1);
4951                n = n->nbinary.ch2;
4952                p = "; done";
4953 dodo:
4954                cmdputs("; do ");
4955 dotail:
4956                cmdtxt(n);
4957                goto dotail2;
4958        case NFOR:
4959                cmdputs("for ");
4960                cmdputs(n->nfor.var);
4961                cmdputs(" in ");
4962                cmdlist(n->nfor.args, 1);
4963                n = n->nfor.body;
4964                p = "; done";
4965                goto dodo;
4966        case NDEFUN:
4967                cmdputs(n->ndefun.text);
4968                p = "() { ... }";
4969                goto dotail2;
4970        case NCMD:
4971                cmdlist(n->ncmd.args, 1);
4972                cmdlist(n->ncmd.redirect, 0);
4973                break;
4974        case NARG:
4975                p = n->narg.text;
4976 dotail2:
4977                cmdputs(p);
4978                break;
4979        case NHERE:
4980        case NXHERE:
4981                p = "<<...";
4982                goto dotail2;
4983        case NCASE:
4984                cmdputs("case ");
4985                cmdputs(n->ncase.expr->narg.text);
4986                cmdputs(" in ");
4987                for (np = n->ncase.cases; np; np = np->nclist.next) {
4988                        cmdtxt(np->nclist.pattern);
4989                        cmdputs(") ");
4990                        cmdtxt(np->nclist.body);
4991                        cmdputs(";; ");
4992                }
4993                p = "esac";
4994                goto dotail2;
4995        case NTO:
4996                p = ">";
4997                goto redir;
4998        case NCLOBBER:
4999                p = ">|";
5000                goto redir;
5001        case NAPPEND:
5002                p = ">>";
5003                goto redir;
5004#if BASH_REDIR_OUTPUT
5005        case NTO2:
5006#endif
5007        case NTOFD:
5008                p = ">&";
5009                goto redir;
5010        case NFROM:
5011                p = "<";
5012                goto redir;
5013        case NFROMFD:
5014                p = "<&";
5015                goto redir;
5016        case NFROMTO:
5017                p = "<>";
5018 redir:
5019                cmdputs(utoa(n->nfile.fd));
5020                cmdputs(p);
5021                if (n->type == NTOFD || n->type == NFROMFD) {
5022                        if (n->ndup.dupfd >= 0)
5023                                cmdputs(utoa(n->ndup.dupfd));
5024                        else
5025                                cmdputs("-");
5026                        break;
5027                }
5028                n = n->nfile.fname;
5029                goto donode;
5030        }
5031}
5032
5033static char *
5034commandtext(union node *n)
5035{
5036        char *name;
5037
5038        STARTSTACKSTR(cmdnextc);
5039        cmdtxt(n);
5040        name = stackblock();
5041        TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
5042        return ckstrdup(name);
5043}
5044#endif /* JOBS */
5045
5046/*
5047 * Fork off a subshell.  If we are doing job control, give the subshell its
5048 * own process group.  Jp is a job structure that the job is to be added to.
5049 * N is the command that will be evaluated by the child.  Both jp and n may
5050 * be NULL.  The mode parameter can be one of the following:
5051 *      FORK_FG - Fork off a foreground process.
5052 *      FORK_BG - Fork off a background process.
5053 *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
5054 *                   process group even if job control is on.
5055 *
5056 * When job control is turned off, background processes have their standard
5057 * input redirected to /dev/null (except for the second and later processes
5058 * in a pipeline).
5059 *
5060 * Called with interrupts off.
5061 */
5062/*
5063 * Clear traps on a fork.
5064 */
5065static void
5066clear_traps(void)
5067{
5068        char **tp;
5069
5070        INT_OFF;
5071        for (tp = trap; tp < &trap[NSIG]; tp++) {
5072                if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */
5073                        if (trap_ptr == trap)
5074                                free(*tp);
5075                        /* else: it "belongs" to trap_ptr vector, don't free */
5076                        *tp = NULL;
5077                        if ((tp - trap) != 0)
5078                                setsignal(tp - trap);
5079                }
5080        }
5081        may_have_traps = 0;
5082        INT_ON;
5083}
5084
5085/* Lives far away from here, needed for forkchild */
5086static void closescript(void);
5087
5088/* Called after fork(), in child */
5089/* jp and n are NULL when called by openhere() for heredoc support */
5090static NOINLINE void
5091forkchild(struct job *jp, union node *n, int mode)
5092{
5093        int oldlvl;
5094
5095        TRACE(("Child shell %d\n", getpid()));
5096        oldlvl = shlvl;
5097        shlvl++;
5098
5099        /* man bash: "Non-builtin commands run by bash have signal handlers
5100         * set to the values inherited by the shell from its parent".
5101         * Do we do it correctly? */
5102
5103        closescript();
5104
5105        if (mode == FORK_NOJOB          /* is it `xxx` ? */
5106         && n && n->type == NCMD        /* is it single cmd? */
5107        /* && n->ncmd.args->type == NARG - always true? */
5108         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
5109         && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5110        /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5111        ) {
5112                TRACE(("Trap hack\n"));
5113                /* Awful hack for `trap` or $(trap).
5114                 *
5115                 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5116                 * contains an example where "trap" is executed in a subshell:
5117                 *
5118                 * save_traps=$(trap)
5119                 * ...
5120                 * eval "$save_traps"
5121                 *
5122                 * Standard does not say that "trap" in subshell shall print
5123                 * parent shell's traps. It only says that its output
5124                 * must have suitable form, but then, in the above example
5125                 * (which is not supposed to be normative), it implies that.
5126                 *
5127                 * bash (and probably other shell) does implement it
5128                 * (traps are reset to defaults, but "trap" still shows them),
5129                 * but as a result, "trap" logic is hopelessly messed up:
5130                 *
5131                 * # trap
5132                 * trap -- 'echo Ho' SIGWINCH  <--- we have a handler
5133                 * # (trap)        <--- trap is in subshell - no output (correct, traps are reset)
5134                 * # true | trap   <--- trap is in subshell - no output (ditto)
5135                 * # echo `true | trap`    <--- in subshell - output (but traps are reset!)
5136                 * trap -- 'echo Ho' SIGWINCH
5137                 * # echo `(trap)`         <--- in subshell in subshell - output
5138                 * trap -- 'echo Ho' SIGWINCH
5139                 * # echo `true | (trap)`  <--- in subshell in subshell in subshell - output!
5140                 * trap -- 'echo Ho' SIGWINCH
5141                 *
5142                 * The rules when to forget and when to not forget traps
5143                 * get really complex and nonsensical.
5144                 *
5145                 * Our solution: ONLY bare $(trap) or `trap` is special.
5146                 */
5147                /* Save trap handler strings for trap builtin to print */
5148                trap_ptr = xmemdup(trap, sizeof(trap));
5149                /* Fall through into clearing traps */
5150        }
5151        clear_traps();
5152#if JOBS
5153        /* do job control only in root shell */
5154        doing_jobctl = 0;
5155        if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
5156                pid_t pgrp;
5157
5158                if (jp->nprocs == 0)
5159                        pgrp = getpid();
5160                else
5161                        pgrp = jp->ps[0].ps_pid;
5162                /* this can fail because we are doing it in the parent also */
5163                setpgid(0, pgrp);
5164                if (mode == FORK_FG)
5165                        xtcsetpgrp(ttyfd, pgrp);
5166                setsignal(SIGTSTP);
5167                setsignal(SIGTTOU);
5168        } else
5169#endif
5170        if (mode == FORK_BG) {
5171                /* man bash: "When job control is not in effect,
5172                 * asynchronous commands ignore SIGINT and SIGQUIT" */
5173                ignoresig(SIGINT);
5174                ignoresig(SIGQUIT);
5175                if (jp->nprocs == 0) {
5176                        close(0);
5177                        if (open(bb_dev_null, O_RDONLY) != 0)
5178                                ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
5179                }
5180        }
5181        if (oldlvl == 0) {
5182                if (iflag) { /* why if iflag only? */
5183                        setsignal(SIGINT);
5184                        setsignal(SIGTERM);
5185                }
5186                /* man bash:
5187                 * "In all cases, bash ignores SIGQUIT. Non-builtin
5188                 * commands run by bash have signal handlers
5189                 * set to the values inherited by the shell
5190                 * from its parent".
5191                 * Take care of the second rule: */
5192                setsignal(SIGQUIT);
5193        }
5194#if JOBS
5195        if (n && n->type == NCMD
5196         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
5197        ) {
5198                TRACE(("Job hack\n"));
5199                /* "jobs": we do not want to clear job list for it,
5200                 * instead we remove only _its_ own_ job from job list.
5201                 * This makes "jobs .... | cat" more useful.
5202                 */
5203                freejob(curjob);
5204                return;
5205        }
5206#endif
5207        for (jp = curjob; jp; jp = jp->prev_job)
5208                freejob(jp);
5209        jobless = 0;
5210}
5211
5212/* Called after fork(), in parent */
5213#if !JOBS
5214#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5215#endif
5216static void
5217forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5218{
5219        TRACE(("In parent shell: child = %d\n", pid));
5220        if (!jp) {
5221                /* jp is NULL when called by openhere() for heredoc support */
5222                while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5223                        continue;
5224                jobless++;
5225                return;
5226        }
5227#if JOBS
5228        if (mode != FORK_NOJOB && jp->jobctl) {
5229                int pgrp;
5230
5231                if (jp->nprocs == 0)
5232                        pgrp = pid;
5233                else
5234                        pgrp = jp->ps[0].ps_pid;
5235                /* This can fail because we are doing it in the child also */
5236                setpgid(pid, pgrp);
5237        }
5238#endif
5239        if (mode == FORK_BG) {
5240                backgndpid = pid;               /* set $! */
5241                set_curjob(jp, CUR_RUNNING);
5242        }
5243        if (jp) {
5244                struct procstat *ps = &jp->ps[jp->nprocs++];
5245                ps->ps_pid = pid;
5246                ps->ps_status = -1;
5247                ps->ps_cmd = nullstr;
5248#if JOBS
5249                if (doing_jobctl && n)
5250                        ps->ps_cmd = commandtext(n);
5251#endif
5252        }
5253}
5254
5255/* jp and n are NULL when called by openhere() for heredoc support */
5256static int
5257forkshell(struct job *jp, union node *n, int mode)
5258{
5259        int pid;
5260
5261        TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5262        pid = fork();
5263        if (pid < 0) {
5264                TRACE(("Fork failed, errno=%d", errno));
5265                if (jp)
5266                        freejob(jp);
5267                ash_msg_and_raise_perror("can't fork");
5268        }
5269        if (pid == 0) {
5270                CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
5271                forkchild(jp, n, mode);
5272        } else {
5273                forkparent(jp, n, mode, pid);
5274        }
5275        return pid;
5276}
5277
5278/*
5279 * Wait for job to finish.
5280 *
5281 * Under job control we have the problem that while a child process
5282 * is running interrupts generated by the user are sent to the child
5283 * but not to the shell.  This means that an infinite loop started by
5284 * an interactive user may be hard to kill.  With job control turned off,
5285 * an interactive user may place an interactive program inside a loop.
5286 * If the interactive program catches interrupts, the user doesn't want
5287 * these interrupts to also abort the loop.  The approach we take here
5288 * is to have the shell ignore interrupt signals while waiting for a
5289 * foreground process to terminate, and then send itself an interrupt
5290 * signal if the child process was terminated by an interrupt signal.
5291 * Unfortunately, some programs want to do a bit of cleanup and then
5292 * exit on interrupt; unless these processes terminate themselves by
5293 * sending a signal to themselves (instead of calling exit) they will
5294 * confuse this approach.
5295 *
5296 * Called with interrupts off.
5297 */
5298static int
5299waitforjob(struct job *jp)
5300{
5301        int st;
5302
5303        TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
5304
5305        INT_OFF;
5306        while (jp->state == JOBRUNNING) {
5307                /* In non-interactive shells, we _can_ get
5308                 * a keyboard signal here and be EINTRed,
5309                 * but we just loop back, waiting for command to complete.
5310                 *
5311                 * man bash:
5312                 * "If bash is waiting for a command to complete and receives
5313                 * a signal for which a trap has been set, the trap
5314                 * will not be executed until the command completes."
5315                 *
5316                 * Reality is that even if trap is not set, bash
5317                 * will not act on the signal until command completes.
5318                 * Try this. sleep5intoff.c:
5319                 * #include <signal.h>
5320                 * #include <unistd.h>
5321                 * int main() {
5322                 *         sigset_t set;
5323                 *         sigemptyset(&set);
5324                 *         sigaddset(&set, SIGINT);
5325                 *         sigaddset(&set, SIGQUIT);
5326                 *         sigprocmask(SIG_BLOCK, &set, NULL);
5327                 *         sleep(5);
5328                 *         return 0;
5329                 * }
5330                 * $ bash -c './sleep5intoff; echo hi'
5331                 * ^C^C^C^C <--- pressing ^C once a second
5332                 * $ _
5333                 * $ bash -c './sleep5intoff; echo hi'
5334                 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5335                 * $ _
5336                 */
5337                dowait(DOWAIT_BLOCK, jp);
5338        }
5339        INT_ON;
5340
5341        st = getstatus(jp);
5342#if JOBS
5343        if (jp->jobctl) {
5344                xtcsetpgrp(ttyfd, rootpid);
5345                restore_tty_if_stopped_or_signaled(jp);
5346
5347                /*
5348                 * This is truly gross.
5349                 * If we're doing job control, then we did a TIOCSPGRP which
5350                 * caused us (the shell) to no longer be in the controlling
5351                 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
5352                 * intuit from the subprocess exit status whether a SIGINT
5353                 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
5354                 */
5355                if (jp->sigint) /* TODO: do the same with all signals */
5356                        raise(SIGINT); /* ... by raise(jp->sig) instead? */
5357        }
5358        if (jp->state == JOBDONE)
5359#endif
5360                freejob(jp);
5361        return st;
5362}
5363
5364/*
5365 * return 1 if there are stopped jobs, otherwise 0
5366 */
5367static int
5368stoppedjobs(void)
5369{
5370        struct job *jp;
5371        int retval;
5372
5373        retval = 0;
5374        if (job_warning)
5375                goto out;
5376        jp = curjob;
5377        if (jp && jp->state == JOBSTOPPED) {
5378                out2str("You have stopped jobs.\n");
5379                job_warning = 2;
5380                retval++;
5381        }
5382 out:
5383        return retval;
5384}
5385
5386
5387/*
5388 * Code for dealing with input/output redirection.
5389 */
5390
5391#undef EMPTY
5392#undef CLOSED
5393#define EMPTY -2                /* marks an unused slot in redirtab */
5394#define CLOSED -1               /* marks a slot of previously-closed fd */
5395
5396/*
5397 * Handle here documents.  Normally we fork off a process to write the
5398 * data to a pipe.  If the document is short, we can stuff the data in
5399 * the pipe without forking.
5400 */
5401/* openhere needs this forward reference */
5402static void expandhere(union node *arg, int fd);
5403static int
5404openhere(union node *redir)
5405{
5406        int pip[2];
5407        size_t len = 0;
5408
5409        if (pipe(pip) < 0)
5410                ash_msg_and_raise_perror("can't create pipe");
5411        if (redir->type == NHERE) {
5412                len = strlen(redir->nhere.doc->narg.text);
5413                if (len <= PIPE_BUF) {
5414                        full_write(pip[1], redir->nhere.doc->narg.text, len);
5415                        goto out;
5416                }
5417        }
5418        if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5419                /* child */
5420                close(pip[0]);
5421                ignoresig(SIGINT);  //signal(SIGINT, SIG_IGN);
5422                ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5423                ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
5424                ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5425                signal(SIGPIPE, SIG_DFL);
5426                if (redir->type == NHERE)
5427                        full_write(pip[1], redir->nhere.doc->narg.text, len);
5428                else /* NXHERE */
5429                        expandhere(redir->nhere.doc, pip[1]);
5430                _exit(EXIT_SUCCESS);
5431        }
5432 out:
5433        close(pip[1]);
5434        return pip[0];
5435}
5436
5437static int
5438openredirect(union node *redir)
5439{
5440        struct stat sb;
5441        char *fname;
5442        int f;
5443
5444        switch (redir->nfile.type) {
5445/* Can't happen, our single caller does this itself */
5446//      case NTOFD:
5447//      case NFROMFD:
5448//              return -1;
5449        case NHERE:
5450        case NXHERE:
5451                return openhere(redir);
5452        }
5453
5454        /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5455         * allocated space. Do it only when we know it is safe.
5456         */
5457        fname = redir->nfile.expfname;
5458
5459        switch (redir->nfile.type) {
5460        default:
5461#if DEBUG
5462                abort();
5463#endif
5464        case NFROM:
5465                f = open(fname, O_RDONLY);
5466                if (f < 0)
5467                        goto eopen;
5468                break;
5469        case NFROMTO:
5470                f = open(fname, O_RDWR|O_CREAT, 0666);
5471                if (f < 0)
5472                        goto ecreate;
5473                break;
5474        case NTO:
5475#if BASH_REDIR_OUTPUT
5476        case NTO2:
5477#endif
5478                /* Take care of noclobber mode. */
5479                if (Cflag) {
5480                        if (stat(fname, &sb) < 0) {
5481                                f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5482                                if (f < 0)
5483                                        goto ecreate;
5484                        } else if (!S_ISREG(sb.st_mode)) {
5485                                f = open(fname, O_WRONLY, 0666);
5486                                if (f < 0)
5487                                        goto ecreate;
5488                                if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
5489                                        close(f);
5490                                        errno = EEXIST;
5491                                        goto ecreate;
5492                                }
5493                        } else {
5494                                errno = EEXIST;
5495                                goto ecreate;
5496                        }
5497                        break;
5498                }
5499                /* FALLTHROUGH */
5500        case NCLOBBER:
5501                f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5502                if (f < 0)
5503                        goto ecreate;
5504                break;
5505        case NAPPEND:
5506                f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5507                if (f < 0)
5508                        goto ecreate;
5509                break;
5510        }
5511
5512        return f;
5513 ecreate:
5514        ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5515 eopen:
5516        ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5517}
5518
5519/*
5520 * Copy a file descriptor to be >= 10. Throws exception on error.
5521 */
5522static int
5523savefd(int from)
5524{
5525        int newfd;
5526        int err;
5527
5528        newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
5529        err = newfd < 0 ? errno : 0;
5530        if (err != EBADF) {
5531                if (err)
5532                        ash_msg_and_raise_perror("%d", from);
5533                close(from);
5534                if (F_DUPFD_CLOEXEC == F_DUPFD)
5535                        close_on_exec_on(newfd);
5536        }
5537
5538        return newfd;
5539}
5540static int
5541dup2_or_raise(int from, int to)
5542{
5543        int newfd;
5544
5545        newfd = (from != to) ? dup2(from, to) : to;
5546        if (newfd < 0) {
5547                /* Happens when source fd is not open: try "echo >&99" */
5548                ash_msg_and_raise_perror("%d", from);
5549        }
5550        return newfd;
5551}
5552static int
5553dup_CLOEXEC(int fd, int avoid_fd)
5554{
5555        int newfd;
5556 repeat:
5557        newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5558        if (newfd >= 0) {
5559                if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
5560                        close_on_exec_on(newfd);
5561        } else { /* newfd < 0 */
5562                if (errno == EBUSY)
5563                        goto repeat;
5564                if (errno == EINTR)
5565                        goto repeat;
5566        }
5567        return newfd;
5568}
5569static int
5570xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5571{
5572        int newfd;
5573 repeat:
5574        newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5575        if (newfd < 0) {
5576                if (errno == EBUSY)
5577                        goto repeat;
5578                if (errno == EINTR)
5579                        goto repeat;
5580                /* fd was not open? */
5581                if (errno == EBADF)
5582                        return fd;
5583                ash_msg_and_raise_perror("%d", newfd);
5584        }
5585        if (F_DUPFD_CLOEXEC == F_DUPFD)
5586                close_on_exec_on(newfd);
5587        close(fd);
5588        return newfd;
5589}
5590
5591/* Struct def and variable are moved down to the first usage site */
5592struct squirrel {
5593        int orig_fd;
5594        int moved_to;
5595};
5596struct redirtab {
5597        struct redirtab *next;
5598        int pair_count;
5599        struct squirrel two_fd[];
5600};
5601#define redirlist (G_var.redirlist)
5602
5603static void
5604add_squirrel_closed(struct redirtab *sq, int fd)
5605{
5606        int i;
5607
5608        if (!sq)
5609                return;
5610
5611        for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5612                /* If we collide with an already moved fd... */
5613                if (fd == sq->two_fd[i].orig_fd) {
5614                        /* Examples:
5615                         * "echo 3>FILE 3>&- 3>FILE"
5616                         * "echo 3>&- 3>FILE"
5617                         * No need for last redirect to insert
5618                         * another "need to close 3" indicator.
5619                         */
5620                        TRACE(("redirect_fd %d: already moved or closed\n", fd));
5621                        return;
5622                }
5623        }
5624        TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5625        sq->two_fd[i].orig_fd = fd;
5626        sq->two_fd[i].moved_to = CLOSED;
5627}
5628
5629static int
5630save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5631{
5632        int i, new_fd;
5633
5634        if (avoid_fd < 9) /* the important case here is that it can be -1 */
5635                avoid_fd = 9;
5636
5637#if JOBS
5638        if (fd == ttyfd) {
5639                /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5640                ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5641                TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5642                return 1; /* "we closed fd" */
5643        }
5644#endif
5645        /* Are we called from redirect(0)? E.g. redirect
5646         * in a forked child. No need to save fds,
5647         * we aren't going to use them anymore, ok to trash.
5648         */
5649        if (!sq)
5650                return 0;
5651
5652        /* If this one of script's fds? */
5653        if (fd != 0) {
5654                struct parsefile *pf = g_parsefile;
5655                while (pf) {
5656                        /* We skip fd == 0 case because of the following:
5657                         * $ ash  # running ash interactively
5658                         * $ . ./script.sh
5659                         * and in script.sh: "exec 9>&0".
5660                         * Even though top-level pf_fd _is_ 0,
5661                         * it's still ok to use it: "read" builtin uses it,
5662                         * why should we cripple "exec" builtin?
5663                         */
5664                        if (fd == pf->pf_fd) {
5665                                pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5666                                return 1; /* "we closed fd" */
5667                        }
5668                        pf = pf->prev;
5669                }
5670        }
5671
5672        /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5673
5674        /* First: do we collide with some already moved fds? */
5675        for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5676                /* If we collide with an already moved fd... */
5677                if (fd == sq->two_fd[i].moved_to) {
5678                        new_fd = dup_CLOEXEC(fd, avoid_fd);
5679                        sq->two_fd[i].moved_to = new_fd;
5680                        TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5681                        if (new_fd < 0) /* what? */
5682                                xfunc_die();
5683                        return 0; /* "we did not close fd" */
5684                }
5685                if (fd == sq->two_fd[i].orig_fd) {
5686                        /* Example: echo Hello >/dev/null 1>&2 */
5687                        TRACE(("redirect_fd %d: already moved\n", fd));
5688                        return 0; /* "we did not close fd" */
5689                }
5690        }
5691
5692        /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5693        new_fd = dup_CLOEXEC(fd, avoid_fd);
5694        TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5695        if (new_fd < 0) {
5696                if (errno != EBADF)
5697                        xfunc_die();
5698                /* new_fd = CLOSED; - already is -1 */
5699        }
5700        sq->two_fd[i].moved_to = new_fd;
5701        sq->two_fd[i].orig_fd = fd;
5702
5703        /* if we move stderr, let "set -x" code know */
5704        if (fd == preverrout_fd)
5705                preverrout_fd = new_fd;
5706
5707        return 0; /* "we did not close fd" */
5708}
5709
5710static int
5711internally_opened_fd(int fd, struct redirtab *sq)
5712{
5713        int i;
5714#if JOBS
5715        if (fd == ttyfd)
5716                return 1;
5717#endif
5718        /* If this one of script's fds? */
5719        if (fd != 0) {
5720                struct parsefile *pf = g_parsefile;
5721                while (pf) {
5722                        if (fd == pf->pf_fd)
5723                                return 1;
5724                        pf = pf->prev;
5725                }
5726        }
5727
5728        if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5729                if (fd == sq->two_fd[i].moved_to)
5730                        return 1;
5731        }
5732        return 0;
5733}
5734
5735/*
5736 * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
5737 * old file descriptors are stashed away so that the redirection can be
5738 * undone by calling popredir.
5739 */
5740/* flags passed to redirect */
5741#define REDIR_PUSH    01        /* save previous values of file descriptors */
5742static void
5743redirect(union node *redir, int flags)
5744{
5745        struct redirtab *sv;
5746
5747        if (!redir)
5748                return;
5749
5750        sv = NULL;
5751        INT_OFF;
5752        if (flags & REDIR_PUSH)
5753                sv = redirlist;
5754        do {
5755                int fd;
5756                int newfd;
5757                int close_fd;
5758                int closed;
5759
5760                fd = redir->nfile.fd;
5761                if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5762                        //bb_error_msg("doing %d > %d", fd, newfd);
5763                        newfd = redir->ndup.dupfd;
5764                        close_fd = -1;
5765                } else {
5766                        newfd = openredirect(redir); /* always >= 0 */
5767                        if (fd == newfd) {
5768                                /* open() gave us precisely the fd we wanted.
5769                                 * This means that this fd was not busy
5770                                 * (not opened to anywhere).
5771                                 * Remember to close it on restore:
5772                                 */
5773                                add_squirrel_closed(sv, fd);
5774                                continue;
5775                        }
5776                        close_fd = newfd;
5777                }
5778
5779                if (fd == newfd)
5780                        continue;
5781
5782                /* if "N>FILE": move newfd to fd */
5783                /* if "N>&M": dup newfd to fd */
5784                /* if "N>&-": close fd (newfd is -1) */
5785
5786 IF_BASH_REDIR_OUTPUT(redirect_more:)
5787
5788                closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5789                if (newfd == -1) {
5790                        /* "N>&-" means "close me" */
5791                        if (!closed) {
5792                                /* ^^^ optimization: saving may already
5793                                 * have closed it. If not... */
5794                                close(fd);
5795                        }
5796                } else {
5797                        /* if newfd is a script fd or saved fd, simulate EBADF */
5798                        if (internally_opened_fd(newfd, sv)) {
5799                                errno = EBADF;
5800                                ash_msg_and_raise_perror("%d", newfd);
5801                        }
5802                        dup2_or_raise(newfd, fd);
5803                        if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5804                                close(close_fd);
5805#if BASH_REDIR_OUTPUT
5806                        if (redir->nfile.type == NTO2 && fd == 1) {
5807                                /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5808                                fd = 2;
5809                                newfd = 1;
5810                                close_fd = -1;
5811                                goto redirect_more;
5812                        }
5813#endif
5814                }
5815        } while ((redir = redir->nfile.next) != NULL);
5816        INT_ON;
5817
5818//dash:#define REDIR_SAVEFD2 03        /* set preverrout */
5819#define REDIR_SAVEFD2 0
5820        // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5821        // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5822        // not only for calls with flags containing REDIR_SAVEFD2.
5823        // We do this unconditionally (see save_fd_on_redirect()).
5824        //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5825        //      preverrout_fd = copied_fd2;
5826}
5827
5828static int
5829redirectsafe(union node *redir, int flags)
5830{
5831        int err;
5832        volatile int saveint;
5833        struct jmploc *volatile savehandler = exception_handler;
5834        struct jmploc jmploc;
5835
5836        SAVE_INT(saveint);
5837        /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5838        err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
5839        if (!err) {
5840                exception_handler = &jmploc;
5841                redirect(redir, flags);
5842        }
5843        exception_handler = savehandler;
5844        if (err && exception_type != EXERROR)
5845                longjmp(exception_handler->loc, 1);
5846        RESTORE_INT(saveint);
5847        return err;
5848}
5849
5850static struct redirtab*
5851pushredir(union node *redir)
5852{
5853        struct redirtab *sv;
5854        int i;
5855
5856        if (!redir)
5857                return redirlist;
5858
5859        i = 0;
5860        do {
5861                i++;
5862#if BASH_REDIR_OUTPUT
5863                if (redir->nfile.type == NTO2)
5864                        i++;
5865#endif
5866                redir = redir->nfile.next;
5867        } while (redir);
5868
5869        sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5870        sv->pair_count = i;
5871        while (--i >= 0)
5872                sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
5873        sv->next = redirlist;
5874        redirlist = sv;
5875        return sv->next;
5876}
5877
5878/*
5879 * Undo the effects of the last redirection.
5880 */
5881static void
5882popredir(int drop)
5883{
5884        struct redirtab *rp;
5885        int i;
5886
5887        if (redirlist == NULL)
5888                return;
5889        INT_OFF;
5890        rp = redirlist;
5891        for (i = 0; i < rp->pair_count; i++) {
5892                int fd = rp->two_fd[i].orig_fd;
5893                int copy = rp->two_fd[i].moved_to;
5894                if (copy == CLOSED) {
5895                        if (!drop)
5896                                close(fd);
5897                        continue;
5898                }
5899                if (copy != EMPTY) {
5900                        if (!drop) {
5901                                /*close(fd);*/
5902                                dup2_or_raise(copy, fd);
5903                        }
5904                        close(copy);
5905                }
5906        }
5907        redirlist = rp->next;
5908        free(rp);
5909        INT_ON;
5910}
5911
5912static void
5913unwindredir(struct redirtab *stop)
5914{
5915        while (redirlist != stop)
5916                popredir(/*drop:*/ 0);
5917}
5918
5919
5920/* ============ Routines to expand arguments to commands
5921 *
5922 * We have to deal with backquotes, shell variables, and file metacharacters.
5923 */
5924
5925#if ENABLE_FEATURE_SH_MATH
5926static arith_t
5927ash_arith(const char *s)
5928{
5929        arith_state_t math_state;
5930        arith_t result;
5931
5932        math_state.lookupvar = lookupvar;
5933        math_state.setvar    = setvar0;
5934        //math_state.endofname = endofname;
5935
5936        INT_OFF;
5937        result = arith(&math_state, s);
5938        if (math_state.errmsg)
5939                ash_msg_and_raise_error(math_state.errmsg);
5940        INT_ON;
5941
5942        return result;
5943}
5944#endif
5945#if BASH_SUBSTR
5946# if ENABLE_FEATURE_SH_MATH
5947static int substr_atoi(const char *s)
5948{
5949        arith_t t = ash_arith(s);
5950        if (sizeof(t) > sizeof(int)) {
5951                /* clamp very large or very large negative nums for ${v:N:M}:
5952                 * else "${v:0:0x100000001}" would work as "${v:0:1}"
5953                 */
5954                if (t > INT_MAX)
5955                        t = INT_MAX;
5956                if (t < INT_MIN)
5957                        t = INT_MIN;
5958        }
5959        return t;
5960}
5961# else
5962#  define substr_atoi(s) number(s)
5963# endif
5964#endif
5965
5966/*
5967 * expandarg flags
5968 */
5969#define EXP_FULL        0x1     /* perform word splitting & file globbing */
5970#define EXP_TILDE       0x2     /* do normal tilde expansion */
5971#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
5972#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
5973/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5974 * POSIX says for this case:
5975 *  Pathname expansion shall not be performed on the word by a
5976 *  non-interactive shell; an interactive shell may perform it, but shall
5977 *  do so only when the expansion would result in one word.
5978 * Currently, our code complies to the above rule by never globbing
5979 * redirection filenames.
5980 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5981 * (this means that on a typical Linux distro, bash almost always
5982 * performs globbing, and thus diverges from what we do).
5983 */
5984#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
5985#define EXP_VARTILDE2   0x20    /* expand tildes after colons only */
5986#define EXP_WORD        0x40    /* expand word in parameter expansion */
5987#define EXP_QUOTED      0x100   /* expand word in double quotes */
5988/*
5989 * rmescape() flags
5990 */
5991#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
5992#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
5993#define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
5994#define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
5995
5996/* Add CTLESC when necessary. */
5997#define QUOTES_ESC     (EXP_FULL | EXP_CASE)
5998/* Do not skip NUL characters. */
5999#define QUOTES_KEEPNUL EXP_TILDE
6000
6001/*
6002 * Structure specifying which parts of the string should be searched
6003 * for IFS characters.
6004 */
6005struct ifsregion {
6006        struct ifsregion *next; /* next region in list */
6007        int begoff;             /* offset of start of region */
6008        int endoff;             /* offset of end of region */
6009        int nulonly;            /* search for nul bytes only */
6010};
6011
6012struct arglist {
6013        struct strlist *list;
6014        struct strlist **lastp;
6015};
6016
6017/* output of current string */
6018static char *expdest;
6019/* list of back quote expressions */
6020static struct nodelist *argbackq;
6021/* first struct in list of ifs regions */
6022static struct ifsregion ifsfirst;
6023/* last struct in list */
6024static struct ifsregion *ifslastp;
6025/* holds expanded arg list */
6026static struct arglist exparg;
6027
6028/*
6029 * Our own itoa().
6030 * cvtnum() is used even if math support is off (to prepare $? values and such).
6031 */
6032static int
6033cvtnum(arith_t num)
6034{
6035        int len;
6036
6037        /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
6038        len = sizeof(arith_t) * 3;
6039        /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
6040        if (sizeof(arith_t) < 4) len += 2;
6041
6042        expdest = makestrspace(len, expdest);
6043        len = fmtstr(expdest, len, ARITH_FMT, num);
6044        STADJUST(len, expdest);
6045        return len;
6046}
6047
6048/*
6049 * Break the argument string into pieces based upon IFS and add the
6050 * strings to the argument list.  The regions of the string to be
6051 * searched for IFS characters have been stored by recordregion.
6052 */
6053static void
6054ifsbreakup(char *string, struct arglist *arglist)
6055{
6056        struct ifsregion *ifsp;
6057        struct strlist *sp;
6058        char *start;
6059        char *p;
6060        char *q;
6061        const char *ifs, *realifs;
6062        int ifsspc;
6063        int nulonly;
6064
6065        start = string;
6066        if (ifslastp != NULL) {
6067                ifsspc = 0;
6068                nulonly = 0;
6069                realifs = ifsset() ? ifsval() : defifs;
6070                ifsp = &ifsfirst;
6071                do {
6072                        int afternul;
6073
6074                        p = string + ifsp->begoff;
6075                        afternul = nulonly;
6076                        nulonly = ifsp->nulonly;
6077                        ifs = nulonly ? nullstr : realifs;
6078                        ifsspc = 0;
6079                        while (p < string + ifsp->endoff) {
6080                                q = p;
6081                                if ((unsigned char)*p == CTLESC)
6082                                        p++;
6083                                if (!strchr(ifs, *p)) {
6084                                        p++;
6085                                        continue;
6086                                }
6087                                if (!(afternul || nulonly))
6088                                        ifsspc = (strchr(defifs, *p) != NULL);
6089                                /* Ignore IFS whitespace at start */
6090                                if (q == start && ifsspc) {
6091                                        p++;
6092                                        start = p;
6093                                        continue;
6094                                }
6095                                *q = '\0';
6096                                sp = stzalloc(sizeof(*sp));
6097                                sp->text = start;
6098                                *arglist->lastp = sp;
6099                                arglist->lastp = &sp->next;
6100                                p++;
6101                                if (!nulonly) {
6102                                        for (;;) {
6103                                                if (p >= string + ifsp->endoff) {
6104                                                        break;
6105                                                }
6106                                                q = p;
6107                                                if ((unsigned char)*p == CTLESC)
6108                                                        p++;
6109                                                if (strchr(ifs, *p) == NULL) {
6110                                                        p = q;
6111                                                        break;
6112                                                }
6113                                                if (strchr(defifs, *p) == NULL) {
6114                                                        if (ifsspc) {
6115                                                                p++;
6116                                                                ifsspc = 0;
6117                                                        } else {
6118                                                                p = q;
6119                                                                break;
6120                                                        }
6121                                                } else
6122                                                        p++;
6123                                        }
6124                                }
6125                                start = p;
6126                        } /* while */
6127                        ifsp = ifsp->next;
6128                } while (ifsp != NULL);
6129                if (nulonly)
6130                        goto add;
6131        }
6132
6133        if (!*start)
6134                return;
6135
6136 add:
6137        sp = stzalloc(sizeof(*sp));
6138        sp->text = start;
6139        *arglist->lastp = sp;
6140        arglist->lastp = &sp->next;
6141}
6142
6143static void
6144ifsfree(void)
6145{
6146        struct ifsregion *p = ifsfirst.next;
6147
6148        if (!p)
6149                goto out;
6150
6151        INT_OFF;
6152        do {
6153                struct ifsregion *ifsp;
6154                ifsp = p->next;
6155                free(p);
6156                p = ifsp;
6157        } while (p);
6158        ifsfirst.next = NULL;
6159        INT_ON;
6160 out:
6161        ifslastp = NULL;
6162}
6163
6164static size_t
6165esclen(const char *start, const char *p)
6166{
6167        size_t esc = 0;
6168
6169        while (p > start && (unsigned char)*--p == CTLESC) {
6170                esc++;
6171        }
6172        return esc;
6173}
6174
6175/*
6176 * Remove any CTLESC characters from a string.
6177 */
6178#if !BASH_PATTERN_SUBST
6179#define rmescapes(str, flag, slash_position) \
6180        rmescapes(str, flag)
6181#endif
6182static char *
6183rmescapes(char *str, int flag, int *slash_position)
6184{
6185        static const char qchars[] ALIGN1 = {
6186                IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
6187
6188        char *p, *q, *r;
6189        unsigned protect_against_glob;
6190        unsigned globbing;
6191
6192        p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
6193        if (!p)
6194                return str;
6195
6196        q = p;
6197        r = str;
6198        if (flag & RMESCAPE_ALLOC) {
6199                size_t len = p - str;
6200                size_t fulllen = len + strlen(p) + 1;
6201
6202                if (flag & RMESCAPE_GROW) {
6203                        int strloc = str - (char *)stackblock();
6204                        r = makestrspace(fulllen, expdest);
6205                        /* p and str may be invalidated by makestrspace */
6206                        str = (char *)stackblock() + strloc;
6207                        p = str + len;
6208                } else if (flag & RMESCAPE_HEAP) {
6209                        r = ckmalloc(fulllen);
6210                } else {
6211                        r = stalloc(fulllen);
6212                }
6213                q = r;
6214                if (len > 0) {
6215                        q = (char *)mempcpy(q, str, len);
6216                }
6217        }
6218
6219        globbing = flag & RMESCAPE_GLOB;
6220        protect_against_glob = globbing;
6221        while (*p) {
6222                if ((unsigned char)*p == CTLQUOTEMARK) {
6223// Note: protect_against_glob only affect whether
6224// CTLESC,<ch> gets converted to <ch> or to \<ch>
6225                        p++;
6226                        protect_against_glob = globbing;
6227                        continue;
6228                }
6229                if (*p == '\\') {
6230                        /* naked back slash */
6231                        protect_against_glob = 0;
6232                        goto copy;
6233                }
6234                if ((unsigned char)*p == CTLESC) {
6235                        p++;
6236#if DEBUG
6237                        if (*p == '\0')
6238                                ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6239#endif
6240                        if (protect_against_glob) {
6241                                /*
6242                                 * We used to trust glob() and fnmatch() to eat
6243                                 * superfluous escapes (\z where z has no
6244                                 * special meaning anyway). But this causes
6245                                 * bugs such as string of one greek letter rho
6246                                 * (unicode-encoded as two bytes "cf,81")
6247                                 * getting encoded as "cf,CTLESC,81"
6248                                 * and here, converted to "cf,\,81" -
6249                                 * which does not go well with some flavors
6250                                 * of fnmatch() in unicode locales
6251                                 * (for example, glibc <= 2.22).
6252                                 *
6253                                 * Lets add "\" only on the chars which need it.
6254                                 * Testcases for less obvious chars are shown.
6255                                 */
6256                                if (*p == '*'
6257                                 || *p == '?'
6258                                 || *p == '['
6259                                 || *p == '\\' /* case '\' in \\    ) echo ok;; *) echo WRONG;; esac */
6260                                 || *p == ']'  /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6261                                 || *p == '-'  /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6262                                 || *p == '!'  /* case '!' in [\!]  ) echo ok;; *) echo WRONG;; esac */
6263                                /* Some libc support [^negate], that's why "^" also needs love */
6264                                 || *p == '^'  /* case '^' in [\^]  ) echo ok;; *) echo WRONG;; esac */
6265                                ) {
6266                                        *q++ = '\\';
6267                                }
6268                        }
6269                }
6270#if BASH_PATTERN_SUBST
6271                else if (slash_position && p == str + *slash_position) {
6272                        /* stop handling globbing */
6273                        globbing = 0;
6274                        *slash_position = q - r;
6275                        slash_position = NULL;
6276                }
6277#endif
6278                protect_against_glob = globbing;
6279 copy:
6280                *q++ = *p++;
6281        }
6282        *q = '\0';
6283        if (flag & RMESCAPE_GROW) {
6284                expdest = r;
6285                STADJUST(q - r + 1, expdest);
6286        }
6287        return r;
6288}
6289#define pmatch(a, b) !fnmatch((a), (b), 0)
6290
6291/*
6292 * Prepare a pattern for a expmeta (internal glob(3)) call.
6293 *
6294 * Returns an stalloced string.
6295 */
6296static char *
6297preglob(const char *pattern, int flag)
6298{
6299        return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
6300}
6301
6302/*
6303 * Put a string on the stack.
6304 */
6305static void
6306memtodest(const char *p, size_t len, int syntax, int quotes)
6307{
6308        char *q;
6309
6310        if (!len)
6311                return;
6312
6313        q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6314
6315        do {
6316                unsigned char c = *p++;
6317                if (c) {
6318                        if (quotes & QUOTES_ESC) {
6319                                int n = SIT(c, syntax);
6320                                if (n == CCTL
6321                                 || (syntax != BASESYNTAX && n == CBACK)
6322                                ) {
6323                                        USTPUTC(CTLESC, q);
6324                                }
6325                        }
6326                } else if (!(quotes & QUOTES_KEEPNUL))
6327                        continue;
6328                USTPUTC(c, q);
6329        } while (--len);
6330
6331        expdest = q;
6332}
6333
6334static size_t
6335strtodest(const char *p, int syntax, int quotes)
6336{
6337        size_t len = strlen(p);
6338        memtodest(p, len, syntax, quotes);
6339        return len;
6340}
6341
6342/*
6343 * Record the fact that we have to scan this region of the
6344 * string for IFS characters.
6345 */
6346static void
6347recordregion(int start, int end, int nulonly)
6348{
6349        struct ifsregion *ifsp;
6350
6351        if (ifslastp == NULL) {
6352                ifsp = &ifsfirst;
6353        } else {
6354                INT_OFF;
6355                ifsp = ckzalloc(sizeof(*ifsp));
6356                /*ifsp->next = NULL; - ckzalloc did it */
6357                ifslastp->next = ifsp;
6358                INT_ON;
6359        }
6360        ifslastp = ifsp;
6361        ifslastp->begoff = start;
6362        ifslastp->endoff = end;
6363        ifslastp->nulonly = nulonly;
6364}
6365
6366static void
6367removerecordregions(int endoff)
6368{
6369        if (ifslastp == NULL)
6370                return;
6371
6372        if (ifsfirst.endoff > endoff) {
6373                while (ifsfirst.next) {
6374                        struct ifsregion *ifsp;
6375                        INT_OFF;
6376                        ifsp = ifsfirst.next->next;
6377                        free(ifsfirst.next);
6378                        ifsfirst.next = ifsp;
6379                        INT_ON;
6380                }
6381                if (ifsfirst.begoff > endoff) {
6382                        ifslastp = NULL;
6383                } else {
6384                        ifslastp = &ifsfirst;
6385                        ifsfirst.endoff = endoff;
6386                }
6387                return;
6388        }
6389
6390        ifslastp = &ifsfirst;
6391        while (ifslastp->next && ifslastp->next->begoff < endoff)
6392                ifslastp = ifslastp->next;
6393        while (ifslastp->next) {
6394                struct ifsregion *ifsp;
6395                INT_OFF;
6396                ifsp = ifslastp->next->next;
6397                free(ifslastp->next);
6398                ifslastp->next = ifsp;
6399                INT_ON;
6400        }
6401        if (ifslastp->endoff > endoff)
6402                ifslastp->endoff = endoff;
6403}
6404
6405static char *
6406exptilde(char *startp, char *p, int flags)
6407{
6408        unsigned char c;
6409        char *name;
6410        struct passwd *pw;
6411        const char *home;
6412        int quotes = flags & QUOTES_ESC;
6413
6414        name = p + 1;
6415
6416        while ((c = *++p) != '\0') {
6417                switch (c) {
6418                case CTLESC:
6419                        return startp;
6420                case CTLQUOTEMARK:
6421                        return startp;
6422                case ':':
6423                        if (flags & EXP_VARTILDE)
6424                                goto done;
6425                        break;
6426                case '/':
6427                case CTLENDVAR:
6428                        goto done;
6429                }
6430        }
6431 done:
6432        *p = '\0';
6433        if (*name == '\0') {
6434                home = lookupvar("HOME");
6435        } else {
6436                pw = getpwnam(name);
6437                if (pw == NULL)
6438                        goto lose;
6439                home = pw->pw_dir;
6440        }
6441        if (!home || !*home)
6442                goto lose;
6443        *p = c;
6444        strtodest(home, SQSYNTAX, quotes);
6445        return p;
6446 lose:
6447        *p = c;
6448        return startp;
6449}
6450
6451/*
6452 * Execute a command inside back quotes.  If it's a builtin command, we
6453 * want to save its output in a block obtained from malloc.  Otherwise
6454 * we fork off a subprocess and get the output of the command via a pipe.
6455 * Should be called with interrupts off.
6456 */
6457struct backcmd {                /* result of evalbackcmd */
6458        int fd;                 /* file descriptor to read from */
6459        int nleft;              /* number of chars in buffer */
6460        char *buf;              /* buffer */
6461        struct job *jp;         /* job structure for command */
6462};
6463
6464/* These forward decls are needed to use "eval" code for backticks handling: */
6465/* flags in argument to evaltree */
6466#define EV_EXIT    01           /* exit after evaluating tree */
6467#define EV_TESTED  02           /* exit status is checked; ignore -e flag */
6468static int evaltree(union node *, int);
6469
6470/* An evaltree() which is known to never return.
6471 * Used to use an alias:
6472 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6473 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6474 */
6475static ALWAYS_INLINE NORETURN void
6476evaltreenr(union node *n, int flags)
6477{
6478        evaltree(n, flags);
6479        bb_unreachable(abort());
6480        /* NOTREACHED */
6481}
6482
6483static void FAST_FUNC
6484evalbackcmd(union node *n, struct backcmd *result)
6485{
6486        int pip[2];
6487        struct job *jp;
6488
6489        result->fd = -1;
6490        result->buf = NULL;
6491        result->nleft = 0;
6492        result->jp = NULL;
6493        if (n == NULL) {
6494                goto out;
6495        }
6496
6497        if (pipe(pip) < 0)
6498                ash_msg_and_raise_perror("can't create pipe");
6499        jp = makejob(/*n,*/ 1);
6500        if (forkshell(jp, n, FORK_NOJOB) == 0) {
6501                /* child */
6502                FORCE_INT_ON;
6503                close(pip[0]);
6504                if (pip[1] != 1) {
6505                        /*close(1);*/
6506                        dup2_or_raise(pip[1], 1);
6507                        close(pip[1]);
6508                }
6509/* TODO: eflag clearing makes the following not abort:
6510 *  ash -c 'set -e; z=$(false;echo foo); echo $z'
6511 * which is what bash does (unless it is in POSIX mode).
6512 * dash deleted "eflag = 0" line in the commit
6513 *  Date: Mon, 28 Jun 2010 17:11:58 +1000
6514 *  [EVAL] Don't clear eflag in evalbackcmd
6515 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6516 */
6517                eflag = 0;
6518                ifsfree();
6519                evaltreenr(n, EV_EXIT);
6520                /* NOTREACHED */
6521        }
6522        /* parent */
6523        close(pip[1]);
6524        result->fd = pip[0];
6525        result->jp = jp;
6526
6527 out:
6528        TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6529                result->fd, result->buf, result->nleft, result->jp));
6530}
6531
6532/*
6533 * Expand stuff in backwards quotes.
6534 */
6535static void
6536expbackq(union node *cmd, int flag)
6537{
6538        struct backcmd in;
6539        int i;
6540        char buf[128];
6541        char *p;
6542        char *dest;
6543        int startloc;
6544        int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6545        struct stackmark smark;
6546
6547        INT_OFF;
6548        startloc = expdest - (char *)stackblock();
6549        pushstackmark(&smark, startloc);
6550        evalbackcmd(cmd, &in);
6551        popstackmark(&smark);
6552
6553        p = in.buf;
6554        i = in.nleft;
6555        if (i == 0)
6556                goto read;
6557        for (;;) {
6558                memtodest(p, i, syntax, flag & QUOTES_ESC);
6559 read:
6560                if (in.fd < 0)
6561                        break;
6562                i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6563                TRACE(("expbackq: read returns %d\n", i));
6564                if (i <= 0)
6565                        break;
6566                p = buf;
6567        }
6568
6569        free(in.buf);
6570        if (in.fd >= 0) {
6571                close(in.fd);
6572                back_exitstatus = waitforjob(in.jp);
6573        }
6574        INT_ON;
6575
6576        /* Eat all trailing newlines */
6577        dest = expdest;
6578        for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6579                STUNPUTC(dest);
6580        expdest = dest;
6581
6582        if (!(flag & EXP_QUOTED))
6583                recordregion(startloc, dest - (char *)stackblock(), 0);
6584        TRACE(("evalbackq: size:%d:'%.*s'\n",
6585                (int)((dest - (char *)stackblock()) - startloc),
6586                (int)((dest - (char *)stackblock()) - startloc),
6587                stackblock() + startloc));
6588}
6589
6590#if ENABLE_FEATURE_SH_MATH
6591/*
6592 * Expand arithmetic expression.  Backup to start of expression,
6593 * evaluate, place result in (backed up) result, adjust string position.
6594 */
6595static void
6596expari(int flag)
6597{
6598        char *p, *start;
6599        int begoff;
6600        int len;
6601
6602        /* ifsfree(); */
6603
6604        /*
6605         * This routine is slightly over-complicated for
6606         * efficiency.  Next we scan backwards looking for the
6607         * start of arithmetic.
6608         */
6609        start = stackblock();
6610        p = expdest - 1;
6611        *p = '\0';
6612        p--;
6613        while (1) {
6614                int esc;
6615
6616                while ((unsigned char)*p != CTLARI) {
6617                        p--;
6618#if DEBUG
6619                        if (p < start) {
6620                                ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6621                        }
6622#endif
6623                }
6624
6625                esc = esclen(start, p);
6626                if (!(esc % 2)) {
6627                        break;
6628                }
6629
6630                p -= esc + 1;
6631        }
6632
6633        begoff = p - start;
6634
6635        removerecordregions(begoff);
6636
6637        expdest = p;
6638
6639        if (flag & QUOTES_ESC)
6640                rmescapes(p + 1, 0, NULL);
6641
6642        len = cvtnum(ash_arith(p + 1));
6643
6644        if (!(flag & EXP_QUOTED))
6645                recordregion(begoff, begoff + len, 0);
6646}
6647#endif
6648
6649/* argstr needs it */
6650static char *evalvar(char *p, int flags);
6651
6652/*
6653 * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
6654 * characters to allow for further processing.  Otherwise treat
6655 * $@ like $* since no splitting will be performed.
6656 */
6657static void
6658argstr(char *p, int flags)
6659{
6660        static const char spclchars[] ALIGN1 = {
6661                '=',
6662                ':',
6663                CTLQUOTEMARK,
6664                CTLENDVAR,
6665                CTLESC,
6666                CTLVAR,
6667                CTLBACKQ,
6668#if ENABLE_FEATURE_SH_MATH
6669                CTLENDARI,
6670#endif
6671                '\0'
6672        };
6673        const char *reject = spclchars;
6674        int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6675        int inquotes;
6676        size_t length;
6677        int startloc;
6678
6679        if (!(flags & EXP_VARTILDE)) {
6680                reject += 2;
6681        } else if (flags & EXP_VARTILDE2) {
6682                reject++;
6683        }
6684        inquotes = 0;
6685        length = 0;
6686        if (flags & EXP_TILDE) {
6687                char *q;
6688
6689                flags &= ~EXP_TILDE;
6690 tilde:
6691                q = p;
6692                if (*q == '~')
6693                        p = exptilde(p, q, flags);
6694        }
6695 start:
6696        startloc = expdest - (char *)stackblock();
6697        for (;;) {
6698                unsigned char c;
6699
6700                length += strcspn(p + length, reject);
6701                c = p[length];
6702                if (c) {
6703                        if (!(c & 0x80)
6704                        IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6705                        ) {
6706                                /* c == '=' || c == ':' || c == CTLENDARI */
6707                                length++;
6708                        }
6709                }
6710                if (length > 0) {
6711                        int newloc;
6712                        expdest = stack_nputstr(p, length, expdest);
6713                        newloc = expdest - (char *)stackblock();
6714                        if (breakall && !inquotes && newloc > startloc) {
6715                                recordregion(startloc, newloc, 0);
6716                        }
6717                        startloc = newloc;
6718                }
6719                p += length + 1;
6720                length = 0;
6721
6722                switch (c) {
6723                case '\0':
6724                        goto breakloop;
6725                case '=':
6726                        if (flags & EXP_VARTILDE2) {
6727                                p--;
6728                                continue;
6729                        }
6730                        flags |= EXP_VARTILDE2;
6731                        reject++;
6732                        /* fall through */
6733                case ':':
6734                        /*
6735                         * sort of a hack - expand tildes in variable
6736                         * assignments (after the first '=' and after ':'s).
6737                         */
6738                        if (*--p == '~') {
6739                                goto tilde;
6740                        }
6741                        continue;
6742                }
6743
6744                switch (c) {
6745                case CTLENDVAR: /* ??? */
6746                        goto breakloop;
6747                case CTLQUOTEMARK:
6748                        /* "$@" syntax adherence hack */
6749                        if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6750                                p = evalvar(p + 1, flags | EXP_QUOTED) + 1;
6751                                goto start;
6752                        }
6753                        inquotes ^= EXP_QUOTED;
6754 addquote:
6755                        if (flags & QUOTES_ESC) {
6756                                p--;
6757                                length++;
6758                                startloc++;
6759                        }
6760                        break;
6761                case CTLESC:
6762                        startloc++;
6763                        length++;
6764                        goto addquote;
6765                case CTLVAR:
6766                        TRACE(("argstr: evalvar('%s')\n", p));
6767                        p = evalvar(p, flags | inquotes);
6768                        TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6769                        goto start;
6770                case CTLBACKQ:
6771                        expbackq(argbackq->n, flags | inquotes);
6772                        argbackq = argbackq->next;
6773                        goto start;
6774#if ENABLE_FEATURE_SH_MATH
6775                case CTLENDARI:
6776                        p--;
6777                        expari(flags | inquotes);
6778                        goto start;
6779#endif
6780                }
6781        }
6782 breakloop: ;
6783}
6784
6785static char *
6786scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6787                char *pattern, int quotes, int zero)
6788{
6789        char *loc, *loc2;
6790        char c;
6791
6792        loc = startp;
6793        loc2 = rmesc;
6794        do {
6795                int match;
6796                const char *s = loc2;
6797
6798                c = *loc2;
6799                if (zero) {
6800                        *loc2 = '\0';
6801                        s = rmesc;
6802                }
6803                match = pmatch(pattern, s);
6804
6805                *loc2 = c;
6806                if (match)
6807                        return loc;
6808                if (quotes && (unsigned char)*loc == CTLESC)
6809                        loc++;
6810                loc++;
6811                loc2++;
6812        } while (c);
6813        return NULL;
6814}
6815
6816static char *
6817scanright(char *startp, char *rmesc, char *rmescend,
6818                char *pattern, int quotes, int match_at_start)
6819{
6820#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6821        int try2optimize = match_at_start;
6822#endif
6823        int esc = 0;
6824        char *loc;
6825        char *loc2;
6826
6827        /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6828         * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6829         * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6830         * Logic:
6831         * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6832         * and on each iteration they go back two/one char until they reach the beginning.
6833         * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6834         */
6835        /* TODO: document in what other circumstances we are called. */
6836
6837        for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6838                int match;
6839                char c = *loc2;
6840                const char *s = loc2;
6841                if (match_at_start) {
6842                        *loc2 = '\0';
6843                        s = rmesc;
6844                }
6845                match = pmatch(pattern, s);
6846                //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6847                *loc2 = c;
6848                if (match)
6849                        return loc;
6850#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6851                if (try2optimize) {
6852                        /* Maybe we can optimize this:
6853                         * if pattern ends with unescaped *, we can avoid checking
6854                         * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6855                         * it won't match truncated "raw_value_of_" strings too.
6856                         */
6857                        unsigned plen = strlen(pattern);
6858                        /* Does it end with "*"? */
6859                        if (plen != 0 && pattern[--plen] == '*') {
6860                                /* "xxxx*" is not escaped */
6861                                /* "xxx\*" is escaped */
6862                                /* "xx\\*" is not escaped */
6863                                /* "x\\\*" is escaped */
6864                                int slashes = 0;
6865                                while (plen != 0 && pattern[--plen] == '\\')
6866                                        slashes++;
6867                                if (!(slashes & 1))
6868                                        break; /* ends with unescaped "*" */
6869                        }
6870                        try2optimize = 0;
6871                }
6872#endif
6873                loc--;
6874                if (quotes) {
6875                        if (--esc < 0) {
6876                                esc = esclen(startp, loc);
6877                        }
6878                        if (esc % 2) {
6879                                esc--;
6880                                loc--;
6881                        }
6882                }
6883        }
6884        return NULL;
6885}
6886
6887static void varunset(const char *, const char *, const char *, int) NORETURN;
6888static void
6889varunset(const char *end, const char *var, const char *umsg, int varflags)
6890{
6891        const char *msg;
6892        const char *tail;
6893
6894        tail = nullstr;
6895        msg = "parameter not set";
6896        if (umsg) {
6897                if ((unsigned char)*end == CTLENDVAR) {
6898                        if (varflags & VSNUL)
6899                                tail = " or null";
6900                } else {
6901                        msg = umsg;
6902                }
6903        }
6904        ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6905}
6906
6907static const char *
6908subevalvar(char *p, char *varname, int strloc, int subtype,
6909                int startloc, int varflags, int flag)
6910{
6911        struct nodelist *saveargbackq = argbackq;
6912        int quotes = flag & QUOTES_ESC;
6913        char *startp;
6914        char *loc;
6915        char *rmesc, *rmescend;
6916        char *str;
6917        int amount, resetloc;
6918        int argstr_flags;
6919        IF_BASH_PATTERN_SUBST(int workloc;)
6920        IF_BASH_PATTERN_SUBST(int slash_pos;)
6921        IF_BASH_PATTERN_SUBST(char *repl;)
6922        int zero;
6923        char *(*scan)(char*, char*, char*, char*, int, int);
6924
6925        //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6926        //              p, varname, strloc, subtype, startloc, varflags, quotes);
6927
6928#if BASH_PATTERN_SUBST
6929        /* For "${v/pattern/repl}", we must find the delimiter _before_
6930         * argstr() call expands possible variable references in pattern:
6931         * think about "v=a; a=a/; echo ${v/$a/r}" case.
6932         */
6933        repl = NULL;
6934        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6935                /* Find '/' and replace with NUL */
6936                repl = p;
6937                /* The pattern can't be empty.
6938                 * IOW: if the first char after "${v//" is a slash,
6939                 * it does not terminate the pattern - it's the first char of the pattern:
6940                 *  v=/dev/ram; echo ${v////-}  prints -dev-ram (pattern is "/")
6941                 *  v=/dev/ram; echo ${v///r/-} prints /dev-am  (pattern is "/r")
6942                 */
6943                if (*repl == '/')
6944                        repl++;
6945                for (;;) {
6946                        if (*repl == '\0') {
6947                                repl = NULL;
6948                                break;
6949                        }
6950                        if (*repl == '/') {
6951                                *repl = '\0';
6952                                break;
6953                        }
6954                        /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
6955                        if ((unsigned char)*repl == CTLESC && repl[1])
6956                                repl++;
6957                        repl++;
6958                }
6959        }
6960#endif
6961        argstr_flags = EXP_TILDE;
6962        if (subtype != VSASSIGN
6963         && subtype != VSQUESTION
6964#if BASH_SUBSTR
6965         && subtype != VSSUBSTR
6966#endif
6967        ) {
6968                /* EXP_CASE keeps CTLESC's */
6969                argstr_flags = EXP_TILDE | EXP_CASE;
6970        }
6971        argstr(p, argstr_flags);
6972        //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
6973#if BASH_PATTERN_SUBST
6974        slash_pos = -1;
6975        if (repl) {
6976                slash_pos = expdest - ((char *)stackblock() + strloc);
6977                STPUTC('/', expdest);
6978                //bb_error_msg("repl+1:'%s'", repl + 1);
6979                argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
6980                *repl = '/';
6981        }
6982#endif
6983        STPUTC('\0', expdest);
6984        argbackq = saveargbackq;
6985        startp = (char *)stackblock() + startloc;
6986        //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
6987
6988        switch (subtype) {
6989        case VSASSIGN:
6990                setvar0(varname, startp);
6991                amount = startp - expdest;
6992                STADJUST(amount, expdest);
6993                return startp;
6994
6995        case VSQUESTION:
6996                varunset(p, varname, startp, varflags);
6997                /* NOTREACHED */
6998
6999#if BASH_SUBSTR
7000        case VSSUBSTR: {
7001                int pos, len, orig_len;
7002                char *colon;
7003
7004                loc = str = stackblock() + strloc;
7005
7006                /* Read POS in ${var:POS:LEN} */
7007                colon = strchr(loc, ':');
7008                if (colon) *colon = '\0';
7009                pos = substr_atoi(loc);
7010                if (colon) *colon = ':';
7011
7012                /* Read LEN in ${var:POS:LEN} */
7013                len = str - startp - 1;
7014                /* *loc != '\0', guaranteed by parser */
7015                if (quotes) {
7016                        char *ptr;
7017                        /* Adjust the length by the number of escapes */
7018                        for (ptr = startp; ptr < (str - 1); ptr++) {
7019                                if ((unsigned char)*ptr == CTLESC) {
7020                                        len--;
7021                                        ptr++;
7022                                }
7023                        }
7024                }
7025                orig_len = len;
7026                if (*loc++ == ':') {
7027                        /* ${var::LEN} */
7028                        len = substr_atoi(loc);
7029                } else {
7030                        /* Skip POS in ${var:POS:LEN} */
7031                        len = orig_len;
7032                        while (*loc && *loc != ':')
7033                                loc++;
7034                        if (*loc++ == ':')
7035                                len = substr_atoi(loc);
7036                }
7037                if (pos < 0) {
7038                        /* ${VAR:$((-n)):l} starts n chars from the end */
7039                        pos = orig_len + pos;
7040                }
7041                if ((unsigned)pos >= orig_len) {
7042                        /* apart from obvious ${VAR:999999:l},
7043                         * covers ${VAR:$((-9999999)):l} - result is ""
7044                         * (bash compat)
7045                         */
7046                        pos = 0;
7047                        len = 0;
7048                }
7049                if (len < 0) {
7050                        /* ${VAR:N:-M} sets LEN to strlen()-M */
7051                        len = (orig_len - pos) + len;
7052                }
7053                if ((unsigned)len > (orig_len - pos))
7054                        len = orig_len - pos;
7055
7056                for (str = startp; pos; str++, pos--) {
7057                        if (quotes && (unsigned char)*str == CTLESC)
7058                                str++;
7059                }
7060                for (loc = startp; len; len--) {
7061                        if (quotes && (unsigned char)*str == CTLESC)
7062                                *loc++ = *str++;
7063                        *loc++ = *str++;
7064                }
7065                *loc = '\0';
7066                amount = loc - expdest;
7067                STADJUST(amount, expdest);
7068                return loc;
7069        }
7070#endif /* BASH_SUBSTR */
7071        }
7072
7073        resetloc = expdest - (char *)stackblock();
7074
7075#if BASH_PATTERN_SUBST
7076        repl = NULL;
7077
7078        /* We'll comeback here if we grow the stack while handling
7079         * a VSREPLACE or VSREPLACEALL, since our pointers into the
7080         * stack will need rebasing, and we'll need to remove our work
7081         * areas each time
7082         */
7083 restart:
7084#endif
7085
7086        amount = expdest - ((char *)stackblock() + resetloc);
7087        STADJUST(-amount, expdest);
7088        startp = (char *)stackblock() + startloc;
7089
7090        rmesc = startp;
7091        rmescend = (char *)stackblock() + strloc;
7092        //bb_error_msg("str7:'%s'", rmescend);
7093        if (quotes) {
7094//TODO: how to handle slash_pos here if string changes (shortens?)
7095                rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
7096                if (rmesc != startp) {
7097                        rmescend = expdest;
7098                        startp = (char *)stackblock() + startloc;
7099                }
7100        }
7101        rmescend--;
7102        str = (char *)stackblock() + strloc;
7103        /*
7104         * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7105         * The result is a_\_z_c (not a\_\_z_c)!
7106         *
7107         * The search pattern and replace string treat backslashes differently!
7108         * "&slash_pos" causes rmescapes() to work differently on the pattern
7109         * and string.  It's only used on the first call.
7110         */
7111        //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7112        rmescapes(str, RMESCAPE_GLOB,
7113                repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7114        );
7115
7116#if BASH_PATTERN_SUBST
7117        workloc = expdest - (char *)stackblock();
7118        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7119                int len;
7120                char *idx, *end;
7121
7122                if (!repl) {
7123                        //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
7124                        repl = nullstr;
7125                        if (slash_pos >= 0) {
7126                                repl = str + slash_pos;
7127                                *repl++ = '\0';
7128                        }
7129                }
7130                //bb_error_msg("str:'%s' repl:'%s'", str, repl);
7131
7132                /* If there's no pattern to match, return the expansion unmolested */
7133                if (str[0] == '\0')
7134                        return NULL;
7135
7136                len = 0;
7137                idx = startp;
7138                end = str - 1;
7139                while (idx < end) {
7140 try_to_match:
7141                        loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
7142                        //bb_error_msg("scanright('%s'):'%s'", str, loc);
7143                        if (!loc) {
7144                                /* No match, advance */
7145                                char *restart_detect = stackblock();
7146 skip_matching:
7147                                STPUTC(*idx, expdest);
7148                                if (quotes && (unsigned char)*idx == CTLESC) {
7149                                        idx++;
7150                                        len++;
7151                                        STPUTC(*idx, expdest);
7152                                }
7153                                if (stackblock() != restart_detect)
7154                                        goto restart;
7155                                idx++;
7156                                len++;
7157                                rmesc++;
7158                                /* continue; - prone to quadratic behavior, smarter code: */
7159                                if (idx >= end)
7160                                        break;
7161                                if (str[0] == '*') {
7162                                        /* Pattern is "*foo". If "*foo" does not match "long_string",
7163                                         * it would never match "ong_string" etc, no point in trying.
7164                                         */
7165                                        goto skip_matching;
7166                                }
7167                                goto try_to_match;
7168                        }
7169
7170                        if (subtype == VSREPLACEALL) {
7171                                while (idx < loc) {
7172                                        if (quotes && (unsigned char)*idx == CTLESC)
7173                                                idx++;
7174                                        idx++;
7175                                        rmesc++;
7176                                }
7177                        } else {
7178                                idx = loc;
7179                        }
7180
7181                        //bb_error_msg("repl:'%s'", repl);
7182                        for (loc = (char*)repl; *loc; loc++) {
7183                                char *restart_detect = stackblock();
7184                                if (quotes && *loc == '\\') {
7185                                        STPUTC(CTLESC, expdest);
7186                                        len++;
7187                                }
7188                                STPUTC(*loc, expdest);
7189                                if (stackblock() != restart_detect)
7190                                        goto restart;
7191                                len++;
7192                        }
7193
7194                        if (subtype == VSREPLACE) {
7195                                //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
7196                                while (*idx) {
7197                                        char *restart_detect = stackblock();
7198                                        STPUTC(*idx, expdest);
7199                                        if (stackblock() != restart_detect)
7200                                                goto restart;
7201                                        len++;
7202                                        idx++;
7203                                }
7204                                break;
7205                        }
7206                }
7207
7208                /* We've put the replaced text into a buffer at workloc, now
7209                 * move it to the right place and adjust the stack.
7210                 */
7211                STPUTC('\0', expdest);
7212                startp = (char *)stackblock() + startloc;
7213                memmove(startp, (char *)stackblock() + workloc, len + 1);
7214                //bb_error_msg("startp:'%s'", startp);
7215                amount = expdest - (startp + len);
7216                STADJUST(-amount, expdest);
7217                return startp;
7218        }
7219#endif /* BASH_PATTERN_SUBST */
7220
7221        subtype -= VSTRIMRIGHT;
7222#if DEBUG
7223        if (subtype < 0 || subtype > 7)
7224                abort();
7225#endif
7226        /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
7227        zero = subtype >> 1;
7228        /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7229        scan = (subtype & 1) ^ zero ? scanleft : scanright;
7230
7231        loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7232        if (loc) {
7233                if (zero) {
7234                        memmove(startp, loc, str - loc);
7235                        loc = startp + (str - loc) - 1;
7236                }
7237                *loc = '\0';
7238                amount = loc - expdest;
7239                STADJUST(amount, expdest);
7240        }
7241        return loc;
7242}
7243
7244/*
7245 * Add the value of a specialized variable to the stack string.
7246 * name parameter (examples):
7247 * ash -c 'echo $1'      name:'1='
7248 * ash -c 'echo $qwe'    name:'qwe='
7249 * ash -c 'echo $$'      name:'$='
7250 * ash -c 'echo ${$}'    name:'$='
7251 * ash -c 'echo ${$##q}' name:'$=q'
7252 * ash -c 'echo ${#$}'   name:'$='
7253 * note: examples with bad shell syntax:
7254 * ash -c 'echo ${#$1}'  name:'$=1'
7255 * ash -c 'echo ${#1#}'  name:'1=#'
7256 */
7257static NOINLINE ssize_t
7258varvalue(char *name, int varflags, int flags, int quoted)
7259{
7260        const char *p;
7261        int num;
7262        int i;
7263        ssize_t len = 0;
7264        int sep;
7265        int subtype = varflags & VSTYPE;
7266        int discard = subtype == VSPLUS || subtype == VSLENGTH;
7267        int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
7268        int syntax;
7269
7270        sep = (flags & EXP_FULL) << CHAR_BIT;
7271        syntax = quoted ? DQSYNTAX : BASESYNTAX;
7272
7273        switch (*name) {
7274        case '$':
7275                num = rootpid;
7276                goto numvar;
7277        case '?':
7278                num = exitstatus;
7279                goto numvar;
7280        case '#':
7281                num = shellparam.nparam;
7282                goto numvar;
7283        case '!':
7284                num = backgndpid;
7285                if (num == 0)
7286                        return -1;
7287 numvar:
7288                len = cvtnum(num);
7289                goto check_1char_name;
7290        case '-':
7291                expdest = makestrspace(NOPTS, expdest);
7292                for (i = NOPTS - 1; i >= 0; i--) {
7293                        if (optlist[i] && optletters(i)) {
7294                                USTPUTC(optletters(i), expdest);
7295                                len++;
7296                        }
7297                }
7298 check_1char_name:
7299#if 0
7300                /* handles cases similar to ${#$1} */
7301                if (name[2] != '\0')
7302                        raise_error_syntax("bad substitution");
7303#endif
7304                break;
7305        case '@':
7306                if (quoted && sep)
7307                        goto param;
7308                /* fall through */
7309        case '*': {
7310                char **ap;
7311                char sepc;
7312                char c;
7313
7314                /* We will set c to 0 or ~0 depending on whether
7315                 * we're doing field splitting.  We won't do field
7316                 * splitting if either we're quoted or sep is zero.
7317                 *
7318                 * Instead of testing (quoted || !sep) the following
7319                 * trick optimises away any branches by using the
7320                 * fact that EXP_QUOTED (which is the only bit that
7321                 * can be set in quoted) is the same as EXP_FULL <<
7322                 * CHAR_BIT (which is the only bit that can be set
7323                 * in sep).
7324                 */
7325#if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7326#error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7327#endif
7328                c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7329                sep &= ~quoted;
7330                sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
7331 param:
7332                sepc = sep;
7333                ap = shellparam.p;
7334                if (!ap)
7335                        return -1;
7336                while ((p = *ap++) != NULL) {
7337                        len += strtodest(p, syntax, quotes);
7338
7339                        if (*ap && sep) {
7340                                len++;
7341                                memtodest(&sepc, 1, syntax, quotes);
7342                        }
7343                }
7344                break;
7345        } /* case '*' */
7346        case '0':
7347        case '1':
7348        case '2':
7349        case '3':
7350        case '4':
7351        case '5':
7352        case '6':
7353        case '7':
7354        case '8':
7355        case '9':
7356                num = atoi(name); /* number(name) fails on ${N#str} etc */
7357                if (num < 0 || num > shellparam.nparam)
7358                        return -1;
7359                p = num ? shellparam.p[num - 1] : arg0;
7360                goto value;
7361        default:
7362                /* NB: name has form "VAR=..." */
7363                p = lookupvar(name);
7364 value:
7365                if (!p)
7366                        return -1;
7367
7368                len = strtodest(p, syntax, quotes);
7369#if ENABLE_UNICODE_SUPPORT
7370                if (subtype == VSLENGTH && len > 0) {
7371                        reinit_unicode_for_ash();
7372                        if (unicode_status == UNICODE_ON) {
7373                                STADJUST(-len, expdest);
7374                                discard = 0;
7375                                len = unicode_strlen(p);
7376                        }
7377                }
7378#endif
7379                break;
7380        }
7381
7382        if (discard)
7383                STADJUST(-len, expdest);
7384        return len;
7385}
7386
7387/*
7388 * Expand a variable, and return a pointer to the next character in the
7389 * input string.
7390 */
7391static char *
7392evalvar(char *p, int flag)
7393{
7394        char varflags;
7395        char subtype;
7396        int quoted;
7397        char *var;
7398        int patloc;
7399        int startloc;
7400        ssize_t varlen;
7401
7402        varflags = (unsigned char) *p++;
7403        subtype = varflags & VSTYPE;
7404
7405        if (!subtype)
7406                raise_error_syntax("bad substitution");
7407
7408        quoted = flag & EXP_QUOTED;
7409        var = p;
7410        startloc = expdest - (char *)stackblock();
7411        p = strchr(p, '=') + 1; //TODO: use var_end(p)?
7412
7413 again:
7414        varlen = varvalue(var, varflags, flag, quoted);
7415        if (varflags & VSNUL)
7416                varlen--;
7417
7418        if (subtype == VSPLUS) {
7419                varlen = -1 - varlen;
7420                goto vsplus;
7421        }
7422
7423        if (subtype == VSMINUS) {
7424 vsplus:
7425                if (varlen < 0) {
7426                        argstr(
7427                                p,
7428                                flag | EXP_TILDE | EXP_WORD
7429                        );
7430                        goto end;
7431                }
7432                goto record;
7433        }
7434
7435        if (subtype == VSASSIGN || subtype == VSQUESTION) {
7436                if (varlen >= 0)
7437                        goto record;
7438
7439                subevalvar(p, var, 0, subtype, startloc, varflags,
7440                           flag & ~QUOTES_ESC);
7441                varflags &= ~VSNUL;
7442                /*
7443                 * Remove any recorded regions beyond
7444                 * start of variable
7445                 */
7446                removerecordregions(startloc);
7447                goto again;
7448        }
7449
7450        if (varlen < 0 && uflag)
7451                varunset(p, var, 0, 0);
7452
7453        if (subtype == VSLENGTH) {
7454                cvtnum(varlen > 0 ? varlen : 0);
7455                goto record;
7456        }
7457
7458        if (subtype == VSNORMAL) {
7459 record:
7460                if (quoted) {
7461                        quoted = *var == '@' && shellparam.nparam;
7462                        if (!quoted)
7463                                goto end;
7464                }
7465                recordregion(startloc, expdest - (char *)stackblock(), quoted);
7466                goto end;
7467        }
7468
7469#if DEBUG
7470        switch (subtype) {
7471        case VSTRIMLEFT:
7472        case VSTRIMLEFTMAX:
7473        case VSTRIMRIGHT:
7474        case VSTRIMRIGHTMAX:
7475#if BASH_SUBSTR
7476        case VSSUBSTR:
7477#endif
7478#if BASH_PATTERN_SUBST
7479        case VSREPLACE:
7480        case VSREPLACEALL:
7481#endif
7482                break;
7483        default:
7484                abort();
7485        }
7486#endif
7487
7488        if (varlen >= 0) {
7489                /*
7490                 * Terminate the string and start recording the pattern
7491                 * right after it
7492                 */
7493                STPUTC('\0', expdest);
7494                patloc = expdest - (char *)stackblock();
7495                if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
7496                                startloc, varflags, flag)) {
7497                        int amount = expdest - (
7498                                (char *)stackblock() + patloc - 1
7499                        );
7500                        STADJUST(-amount, expdest);
7501                }
7502                /* Remove any recorded regions beyond start of variable */
7503                removerecordregions(startloc);
7504                goto record;
7505        }
7506
7507 end:
7508        if (subtype != VSNORMAL) {      /* skip to end of alternative */
7509                int nesting = 1;
7510                for (;;) {
7511                        unsigned char c = *p++;
7512                        if (c == CTLESC)
7513                                p++;
7514                        else if (c == CTLBACKQ) {
7515                                if (varlen >= 0)
7516                                        argbackq = argbackq->next;
7517                        } else if (c == CTLVAR) {
7518                                if ((*p++ & VSTYPE) != VSNORMAL)
7519                                        nesting++;
7520                        } else if (c == CTLENDVAR) {
7521                                if (--nesting == 0)
7522                                        break;
7523                        }
7524                }
7525        }
7526        return p;
7527}
7528
7529/*
7530 * Add a file name to the list.
7531 */
7532static void
7533addfname(const char *name)
7534{
7535        struct strlist *sp;
7536
7537        sp = stzalloc(sizeof(*sp));
7538        sp->text = sstrdup(name);
7539        *exparg.lastp = sp;
7540        exparg.lastp = &sp->next;
7541}
7542
7543/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7544static int
7545hasmeta(const char *p)
7546{
7547        static const char chars[] ALIGN1 = {
7548                '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7549        };
7550
7551        for (;;) {
7552                p = strpbrk(p, chars);
7553                if (!p)
7554                        break;
7555                switch ((unsigned char)*p) {
7556                case CTLQUOTEMARK:
7557                        for (;;) {
7558                                p++;
7559                                if ((unsigned char)*p == CTLQUOTEMARK)
7560                                        break;
7561                                if ((unsigned char)*p == CTLESC)
7562                                        p++;
7563                                if (*p == '\0') /* huh? */
7564                                        return 0;
7565                        }
7566                        break;
7567                case '\\':
7568                case CTLESC:
7569                        p++;
7570                        if (*p == '\0')
7571                                return 0;
7572                        break;
7573                case '[':
7574                        if (!strchr(p + 1, ']')) {
7575                                /* It's not a properly closed [] pattern,
7576                                 * but other metas may follow. Continue checking.
7577                                 * my[file* _is_ globbed by bash
7578                                 * and matches filenames like "my[file1".
7579                                 */
7580                                break;
7581                        }
7582                        /* fallthrough */
7583                default:
7584                /* case '*': */
7585                /* case '?': */
7586                        return 1;
7587                }
7588                p++;
7589        }
7590
7591        return 0;
7592}
7593
7594/* If we want to use glob() from libc... */
7595#if !ENABLE_ASH_INTERNAL_GLOB
7596
7597/* Add the result of glob() to the list */
7598static void
7599addglob(const glob_t *pglob)
7600{
7601        char **p = pglob->gl_pathv;
7602
7603        do {
7604                addfname(*p);
7605        } while (*++p);
7606}
7607static void
7608expandmeta(struct strlist *str /*, int flag*/)
7609{
7610        /* TODO - EXP_REDIR */
7611
7612        while (str) {
7613                char *p;
7614                glob_t pglob;
7615                int i;
7616
7617                if (fflag)
7618                        goto nometa;
7619
7620                if (!hasmeta(str->text))
7621                        goto nometa;
7622
7623                INT_OFF;
7624                p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7625// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7626// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7627//
7628// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7629// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7630// Which means you need to unescape the string, right? Not so fast:
7631// if there _is_ a file named "file\?" (with backslash), it is returned
7632// as "file\?" too (whichever pattern you used to find it, say, "file*").
7633// You DON'T KNOW by looking at the result whether you need to unescape it.
7634//
7635// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7636// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7637// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7638// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7639//              i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7640//              i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7641                i = glob(p, 0, NULL, &pglob);
7642                //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7643                if (p != str->text)
7644                        free(p);
7645                switch (i) {
7646                case 0:
7647#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7648                        /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7649                        if (!(pglob.gl_flags & GLOB_MAGCHAR))
7650                                goto nometa2;
7651#endif
7652                        addglob(&pglob);
7653                        globfree(&pglob);
7654                        INT_ON;
7655                        break;
7656                case GLOB_NOMATCH:
7657 //nometa2:
7658                        globfree(&pglob);
7659                        INT_ON;
7660 nometa:
7661                        *exparg.lastp = str;
7662                        rmescapes(str->text, 0, NULL);
7663                        exparg.lastp = &str->next;
7664                        break;
7665                default:        /* GLOB_NOSPACE */
7666                        globfree(&pglob);
7667                        INT_ON;
7668                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
7669                }
7670                str = str->next;
7671        }
7672}
7673
7674#else
7675/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7676
7677/*
7678 * Do metacharacter (i.e. *, ?, [...]) expansion.
7679 */
7680typedef struct exp_t {
7681        char *dir;
7682        unsigned dir_max;
7683} exp_t;
7684static void
7685expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7686{
7687#define expdir exp->dir
7688#define expdir_max exp->dir_max
7689        char *enddir = expdir + expdir_len;
7690        char *p;
7691        const char *cp;
7692        char *start;
7693        char *endname;
7694        int metaflag;
7695        struct stat statb;
7696        DIR *dirp;
7697        struct dirent *dp;
7698        int atend;
7699        int matchdot;
7700        int esc;
7701
7702        metaflag = 0;
7703        start = name;
7704        for (p = name; esc = 0, *p; p += esc + 1) {
7705                if (*p == '*' || *p == '?')
7706                        metaflag = 1;
7707                else if (*p == '[') {
7708                        char *q = p + 1;
7709                        if (*q == '!')
7710                                q++;
7711                        for (;;) {
7712                                if (*q == '\\')
7713                                        q++;
7714                                if (*q == '/' || *q == '\0')
7715                                        break;
7716                                if (*++q == ']') {
7717                                        metaflag = 1;
7718                                        break;
7719                                }
7720                        }
7721                } else {
7722                        if (*p == '\\' && p[1])
7723                                esc++;
7724                        if (p[esc] == '/') {
7725                                if (metaflag)
7726                                        break;
7727                                start = p + esc + 1;
7728                        }
7729                }
7730        }
7731        if (metaflag == 0) {    /* we've reached the end of the file name */
7732                if (!expdir_len)
7733                        return;
7734                p = name;
7735                do {
7736                        if (*p == '\\' && p[1])
7737                                p++;
7738                        *enddir++ = *p;
7739                } while (*p++);
7740                if (lstat(expdir, &statb) == 0)
7741                        addfname(expdir);
7742                return;
7743        }
7744        endname = p;
7745        if (name < start) {
7746                p = name;
7747                do {
7748                        if (*p == '\\' && p[1])
7749                                p++;
7750                        *enddir++ = *p++;
7751                } while (p < start);
7752        }
7753        *enddir = '\0';
7754        cp = expdir;
7755        expdir_len = enddir - cp;
7756        if (!expdir_len)
7757                cp = ".";
7758        dirp = opendir(cp);
7759        if (dirp == NULL)
7760                return;
7761        if (*endname == 0) {
7762                atend = 1;
7763        } else {
7764                atend = 0;
7765                *endname = '\0';
7766                endname += esc + 1;
7767        }
7768        name_len -= endname - name;
7769        matchdot = 0;
7770        p = start;
7771        if (*p == '\\')
7772                p++;
7773        if (*p == '.')
7774                matchdot++;
7775        while (!pending_int && (dp = readdir(dirp)) != NULL) {
7776                if (dp->d_name[0] == '.' && !matchdot)
7777                        continue;
7778                if (pmatch(start, dp->d_name)) {
7779                        if (atend) {
7780                                strcpy(enddir, dp->d_name);
7781                                addfname(expdir);
7782                        } else {
7783                                unsigned offset;
7784                                unsigned len;
7785
7786                                p = stpcpy(enddir, dp->d_name);
7787                                *p = '/';
7788
7789                                offset = p - expdir + 1;
7790                                len = offset + name_len + NAME_MAX;
7791                                if (len > expdir_max) {
7792                                        len += PATH_MAX;
7793                                        expdir = ckrealloc(expdir, len);
7794                                        expdir_max = len;
7795                                }
7796
7797                                expmeta(exp, endname, name_len, offset);
7798                                enddir = expdir + expdir_len;
7799                        }
7800                }
7801        }
7802        closedir(dirp);
7803        if (!atend)
7804                endname[-esc - 1] = esc ? '\\' : '/';
7805#undef expdir
7806#undef expdir_max
7807}
7808
7809static struct strlist *
7810msort(struct strlist *list, int len)
7811{
7812        struct strlist *p, *q = NULL;
7813        struct strlist **lpp;
7814        int half;
7815        int n;
7816
7817        if (len <= 1)
7818                return list;
7819        half = len >> 1;
7820        p = list;
7821        for (n = half; --n >= 0;) {
7822                q = p;
7823                p = p->next;
7824        }
7825        q->next = NULL;                 /* terminate first half of list */
7826        q = msort(list, half);          /* sort first half of list */
7827        p = msort(p, len - half);               /* sort second half */
7828        lpp = &list;
7829        for (;;) {
7830#if ENABLE_LOCALE_SUPPORT
7831                if (strcoll(p->text, q->text) < 0)
7832#else
7833                if (strcmp(p->text, q->text) < 0)
7834#endif
7835                                                {
7836                        *lpp = p;
7837                        lpp = &p->next;
7838                        p = *lpp;
7839                        if (p == NULL) {
7840                                *lpp = q;
7841                                break;
7842                        }
7843                } else {
7844                        *lpp = q;
7845                        lpp = &q->next;
7846                        q = *lpp;
7847                        if (q == NULL) {
7848                                *lpp = p;
7849                                break;
7850                        }
7851                }
7852        }
7853        return list;
7854}
7855
7856/*
7857 * Sort the results of file name expansion.  It calculates the number of
7858 * strings to sort and then calls msort (short for merge sort) to do the
7859 * work.
7860 */
7861static struct strlist *
7862expsort(struct strlist *str)
7863{
7864        int len;
7865        struct strlist *sp;
7866
7867        len = 0;
7868        for (sp = str; sp; sp = sp->next)
7869                len++;
7870        return msort(str, len);
7871}
7872
7873static void
7874expandmeta(struct strlist *str /*, int flag*/)
7875{
7876        /* TODO - EXP_REDIR */
7877
7878        while (str) {
7879                exp_t exp;
7880                struct strlist **savelastp;
7881                struct strlist *sp;
7882                char *p;
7883                unsigned len;
7884
7885                if (fflag)
7886                        goto nometa;
7887                if (!hasmeta(str->text))
7888                        goto nometa;
7889                savelastp = exparg.lastp;
7890
7891                INT_OFF;
7892                p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7893                len = strlen(p);
7894                exp.dir_max = len + PATH_MAX;
7895                exp.dir = ckmalloc(exp.dir_max);
7896
7897                expmeta(&exp, p, len, 0);
7898                free(exp.dir);
7899                if (p != str->text)
7900                        free(p);
7901                INT_ON;
7902                if (exparg.lastp == savelastp) {
7903                        /*
7904                         * no matches
7905                         */
7906 nometa:
7907                        *exparg.lastp = str;
7908                        rmescapes(str->text, 0, NULL);
7909                        exparg.lastp = &str->next;
7910                } else {
7911                        *exparg.lastp = NULL;
7912                        *savelastp = sp = expsort(*savelastp);
7913                        while (sp->next != NULL)
7914                                sp = sp->next;
7915                        exparg.lastp = &sp->next;
7916                }
7917                str = str->next;
7918        }
7919}
7920#endif /* ENABLE_ASH_INTERNAL_GLOB */
7921
7922/*
7923 * Perform variable substitution and command substitution on an argument,
7924 * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
7925 * perform splitting and file name expansion.  When arglist is NULL, perform
7926 * here document expansion.
7927 */
7928static void
7929expandarg(union node *arg, struct arglist *arglist, int flag)
7930{
7931        struct strlist *sp;
7932        char *p;
7933
7934        argbackq = arg->narg.backquote;
7935        STARTSTACKSTR(expdest);
7936        TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7937        argstr(arg->narg.text, flag);
7938        p = _STPUTC('\0', expdest);
7939        expdest = p - 1;
7940        if (arglist == NULL) {
7941                /* here document expanded */
7942                goto out;
7943        }
7944        p = grabstackstr(p);
7945        TRACE(("expandarg: p:'%s'\n", p));
7946        exparg.lastp = &exparg.list;
7947        /*
7948         * TODO - EXP_REDIR
7949         */
7950        if (flag & EXP_FULL) {
7951                ifsbreakup(p, &exparg);
7952                *exparg.lastp = NULL;
7953                exparg.lastp = &exparg.list;
7954                expandmeta(exparg.list /*, flag*/);
7955        } else {
7956                sp = stzalloc(sizeof(*sp));
7957                sp->text = p;
7958                *exparg.lastp = sp;
7959                exparg.lastp = &sp->next;
7960        }
7961        *exparg.lastp = NULL;
7962        if (exparg.list) {
7963                *arglist->lastp = exparg.list;
7964                arglist->lastp = exparg.lastp;
7965        }
7966
7967 out:
7968        ifsfree();
7969}
7970
7971/*
7972 * Expand shell variables and backquotes inside a here document.
7973 */
7974static void
7975expandhere(union node *arg, int fd)
7976{
7977        expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7978        full_write(fd, stackblock(), expdest - (char *)stackblock());
7979}
7980
7981/*
7982 * Returns true if the pattern matches the string.
7983 */
7984static int
7985patmatch(char *pattern, const char *string)
7986{
7987        char *p = preglob(pattern, 0);
7988        int r = pmatch(p, string);
7989        //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7990        return r;
7991}
7992
7993/*
7994 * See if a pattern matches in a case statement.
7995 */
7996static int
7997casematch(union node *pattern, char *val)
7998{
7999        struct stackmark smark;
8000        int result;
8001
8002        setstackmark(&smark);
8003        argbackq = pattern->narg.backquote;
8004        STARTSTACKSTR(expdest);
8005        argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
8006        STACKSTRNUL(expdest);
8007        ifsfree();
8008        result = patmatch(stackblock(), val);
8009        popstackmark(&smark);
8010        return result;
8011}
8012
8013
8014/* ============ find_command */
8015
8016struct builtincmd {
8017        const char *name;
8018        int (*builtin)(int, char **) FAST_FUNC;
8019        /* unsigned flags; */
8020};
8021#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
8022/* "regular" builtins always take precedence over commands,
8023 * regardless of PATH=....%builtin... position */
8024#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
8025#define IS_BUILTIN_ASSIGN(b)  ((b)->name[0] & 4)
8026
8027struct cmdentry {
8028        smallint cmdtype;       /* CMDxxx */
8029        union param {
8030                int index;
8031                /* index >= 0 for commands without path (slashes) */
8032                /* (TODO: what exactly does the value mean? PATH position?) */
8033                /* index == -1 for commands with slashes */
8034                /* index == (-2 - applet_no) for NOFORK applets */
8035                const struct builtincmd *cmd;
8036                struct funcnode *func;
8037        } u;
8038};
8039/* values of cmdtype */
8040#define CMDUNKNOWN      -1      /* no entry in table for command */
8041#define CMDNORMAL       0       /* command is an executable program */
8042#define CMDFUNCTION     1       /* command is a shell function */
8043#define CMDBUILTIN      2       /* command is a shell builtin */
8044
8045/* action to find_command() */
8046#define DO_ERR          0x01    /* prints errors */
8047#define DO_ABS          0x02    /* checks absolute paths */
8048#define DO_NOFUNC       0x04    /* don't return shell functions, for command */
8049#define DO_ALTPATH      0x08    /* using alternate path */
8050#define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
8051
8052static void find_command(char *, struct cmdentry *, int, const char *);
8053
8054
8055/* ============ Hashing commands */
8056
8057/*
8058 * When commands are first encountered, they are entered in a hash table.
8059 * This ensures that a full path search will not have to be done for them
8060 * on each invocation.
8061 *
8062 * We should investigate converting to a linear search, even though that
8063 * would make the command name "hash" a misnomer.
8064 */
8065
8066struct tblentry {
8067        struct tblentry *next;  /* next entry in hash chain */
8068        union param param;      /* definition of builtin function */
8069        smallint cmdtype;       /* CMDxxx */
8070        char rehash;            /* if set, cd done since entry created */
8071        char cmdname[1];        /* name of command */
8072};
8073
8074static struct tblentry **cmdtable;
8075#define INIT_G_cmdtable() do { \
8076        cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
8077} while (0)
8078
8079static int builtinloc = -1;     /* index in path of %builtin, or -1 */
8080
8081
8082static void
8083tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
8084{
8085#if ENABLE_FEATURE_SH_STANDALONE
8086        if (applet_no >= 0) {
8087                if (APPLET_IS_NOEXEC(applet_no)) {
8088                        clearenv();
8089                        while (*envp)
8090                                putenv(*envp++);
8091                        popredir(/*drop:*/ 1);
8092                        run_noexec_applet_and_exit(applet_no, cmd, argv);
8093                }
8094                /* re-exec ourselves with the new arguments */
8095                execve(bb_busybox_exec_path, argv, envp);
8096                /* If they called chroot or otherwise made the binary no longer
8097                 * executable, fall through */
8098        }
8099#endif
8100
8101 repeat:
8102#ifdef SYSV
8103        do {
8104                execve(cmd, argv, envp);
8105        } while (errno == EINTR);
8106#else
8107        execve(cmd, argv, envp);
8108#endif
8109
8110        if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
8111                /* Run "cmd" as a shell script:
8112                 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8113                 * "If the execve() function fails with ENOEXEC, the shell
8114                 * shall execute a command equivalent to having a shell invoked
8115                 * with the command name as its first operand,
8116                 * with any remaining arguments passed to the new shell"
8117                 *
8118                 * That is, do not use $SHELL, user's shell, or /bin/sh;
8119                 * just call ourselves.
8120                 *
8121                 * Note that bash reads ~80 chars of the file, and if it sees
8122                 * a zero byte before it sees newline, it doesn't try to
8123                 * interpret it, but fails with "cannot execute binary file"
8124                 * message and exit code 126. For one, this prevents attempts
8125                 * to interpret foreign ELF binaries as shell scripts.
8126                 */
8127                argv[0] = (char*) cmd;
8128                cmd = bb_busybox_exec_path;
8129                /* NB: this is only possible because all callers of shellexec()
8130                 * ensure that the argv[-1] slot exists!
8131                 */
8132                argv--;
8133                argv[0] = (char*) "ash";
8134                goto repeat;
8135        }
8136}
8137
8138/*
8139 * Exec a program.  Never returns.  If you change this routine, you may
8140 * have to change the find_command routine as well.
8141 * argv[-1] must exist and be writable! See tryexec() for why.
8142 */
8143static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8144static void shellexec(char *prog, char **argv, const char *path, int idx)
8145{
8146        char *cmdname;
8147        int e;
8148        char **envp;
8149        int exerrno;
8150        int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
8151
8152        envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
8153        if (strchr(prog, '/') != NULL
8154#if ENABLE_FEATURE_SH_STANDALONE
8155         || (applet_no = find_applet_by_name(prog)) >= 0
8156#endif
8157        ) {
8158                tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
8159                if (applet_no >= 0) {
8160                        /* We tried execing ourself, but it didn't work.
8161                         * Maybe /proc/self/exe doesn't exist?
8162                         * Try $PATH search.
8163                         */
8164                        goto try_PATH;
8165                }
8166                e = errno;
8167        } else {
8168 try_PATH:
8169                e = ENOENT;
8170                while ((cmdname = path_advance(&path, prog)) != NULL) {
8171                        if (--idx < 0 && pathopt == NULL) {
8172                                tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
8173                                if (errno != ENOENT && errno != ENOTDIR)
8174                                        e = errno;
8175                        }
8176                        stunalloc(cmdname);
8177                }
8178        }
8179
8180        /* Map to POSIX errors */
8181        switch (e) {
8182        default:
8183                exerrno = 126;
8184                break;
8185        case ELOOP:
8186        case ENAMETOOLONG:
8187        case ENOENT:
8188        case ENOTDIR:
8189                exerrno = 127;
8190                break;
8191        }
8192        exitstatus = exerrno;
8193        TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
8194                prog, e, suppress_int));
8195        ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
8196        /* NOTREACHED */
8197}
8198
8199static void
8200printentry(struct tblentry *cmdp)
8201{
8202        int idx;
8203        const char *path;
8204        char *name;
8205
8206        idx = cmdp->param.index;
8207        path = pathval();
8208        do {
8209                name = path_advance(&path, cmdp->cmdname);
8210                stunalloc(name);
8211        } while (--idx >= 0);
8212        out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8213}
8214
8215/*
8216 * Clear out command entries.  The argument specifies the first entry in
8217 * PATH which has changed.
8218 */
8219static void
8220clearcmdentry(int firstchange)
8221{
8222        struct tblentry **tblp;
8223        struct tblentry **pp;
8224        struct tblentry *cmdp;
8225
8226        INT_OFF;
8227        for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8228                pp = tblp;
8229                while ((cmdp = *pp) != NULL) {
8230                        if ((cmdp->cmdtype == CMDNORMAL &&
8231                             cmdp->param.index >= firstchange)
8232                         || (cmdp->cmdtype == CMDBUILTIN &&
8233                             builtinloc >= firstchange)
8234                        ) {
8235                                *pp = cmdp->next;
8236                                free(cmdp);
8237                        } else {
8238                                pp = &cmdp->next;
8239                        }
8240                }
8241        }
8242        INT_ON;
8243}
8244
8245/*
8246 * Locate a command in the command hash table.  If "add" is nonzero,
8247 * add the command to the table if it is not already present.  The
8248 * variable "lastcmdentry" is set to point to the address of the link
8249 * pointing to the entry, so that delete_cmd_entry can delete the
8250 * entry.
8251 *
8252 * Interrupts must be off if called with add != 0.
8253 */
8254static struct tblentry **lastcmdentry;
8255
8256static struct tblentry *
8257cmdlookup(const char *name, int add)
8258{
8259        unsigned int hashval;
8260        const char *p;
8261        struct tblentry *cmdp;
8262        struct tblentry **pp;
8263
8264        p = name;
8265        hashval = (unsigned char)*p << 4;
8266        while (*p)
8267                hashval += (unsigned char)*p++;
8268        hashval &= 0x7FFF;
8269        pp = &cmdtable[hashval % CMDTABLESIZE];
8270        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8271                if (strcmp(cmdp->cmdname, name) == 0)
8272                        break;
8273                pp = &cmdp->next;
8274        }
8275        if (add && cmdp == NULL) {
8276                cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8277                                + strlen(name)
8278                                /* + 1 - already done because
8279                                 * tblentry::cmdname is char[1] */);
8280                /*cmdp->next = NULL; - ckzalloc did it */
8281                cmdp->cmdtype = CMDUNKNOWN;
8282                strcpy(cmdp->cmdname, name);
8283        }
8284        lastcmdentry = pp;
8285        return cmdp;
8286}
8287
8288/*
8289 * Delete the command entry returned on the last lookup.
8290 */
8291static void
8292delete_cmd_entry(void)
8293{
8294        struct tblentry *cmdp;
8295
8296        INT_OFF;
8297        cmdp = *lastcmdentry;
8298        *lastcmdentry = cmdp->next;
8299        if (cmdp->cmdtype == CMDFUNCTION)
8300                freefunc(cmdp->param.func);
8301        free(cmdp);
8302        INT_ON;
8303}
8304
8305/*
8306 * Add a new command entry, replacing any existing command entry for
8307 * the same name - except special builtins.
8308 */
8309static void
8310addcmdentry(char *name, struct cmdentry *entry)
8311{
8312        struct tblentry *cmdp;
8313
8314        cmdp = cmdlookup(name, 1);
8315        if (cmdp->cmdtype == CMDFUNCTION) {
8316                freefunc(cmdp->param.func);
8317        }
8318        cmdp->cmdtype = entry->cmdtype;
8319        cmdp->param = entry->u;
8320        cmdp->rehash = 0;
8321}
8322
8323static int FAST_FUNC
8324hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8325{
8326        struct tblentry **pp;
8327        struct tblentry *cmdp;
8328        int c;
8329        struct cmdentry entry;
8330        char *name;
8331
8332        if (nextopt("r") != '\0') {
8333                clearcmdentry(0);
8334                return 0;
8335        }
8336
8337        if (*argptr == NULL) {
8338                for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8339                        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8340                                if (cmdp->cmdtype == CMDNORMAL)
8341                                        printentry(cmdp);
8342                        }
8343                }
8344                return 0;
8345        }
8346
8347        c = 0;
8348        while ((name = *argptr) != NULL) {
8349                cmdp = cmdlookup(name, 0);
8350                if (cmdp != NULL
8351                 && (cmdp->cmdtype == CMDNORMAL
8352                     || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8353                ) {
8354                        delete_cmd_entry();
8355                }
8356                find_command(name, &entry, DO_ERR, pathval());
8357                if (entry.cmdtype == CMDUNKNOWN)
8358                        c = 1;
8359                argptr++;
8360        }
8361        return c;
8362}
8363
8364/*
8365 * Called when a cd is done.  Marks all commands so the next time they
8366 * are executed they will be rehashed.
8367 */
8368static void
8369hashcd(void)
8370{
8371        struct tblentry **pp;
8372        struct tblentry *cmdp;
8373
8374        for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8375                for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8376                        if (cmdp->cmdtype == CMDNORMAL
8377                         || (cmdp->cmdtype == CMDBUILTIN
8378                             && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8379                             && builtinloc > 0)
8380                        ) {
8381                                cmdp->rehash = 1;
8382                        }
8383                }
8384        }
8385}
8386
8387/*
8388 * Fix command hash table when PATH changed.
8389 * Called before PATH is changed.  The argument is the new value of PATH;
8390 * pathval() still returns the old value at this point.
8391 * Called with interrupts off.
8392 */
8393static void FAST_FUNC
8394changepath(const char *new)
8395{
8396        const char *old;
8397        int firstchange;
8398        int idx;
8399        int idx_bltin;
8400
8401        old = pathval();
8402        firstchange = 9999;     /* assume no change */
8403        idx = 0;
8404        idx_bltin = -1;
8405        for (;;) {
8406                if (*old != *new) {
8407                        firstchange = idx;
8408                        if ((*old == '\0' && *new == ':')
8409                         || (*old == ':' && *new == '\0')
8410                        ) {
8411                                firstchange++;
8412                        }
8413                        old = new;      /* ignore subsequent differences */
8414                }
8415                if (*new == '\0')
8416                        break;
8417                if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8418                        idx_bltin = idx;
8419                if (*new == ':')
8420                        idx++;
8421                new++;
8422                old++;
8423        }
8424        if (builtinloc < 0 && idx_bltin >= 0)
8425                builtinloc = idx_bltin;             /* zap builtins */
8426        if (builtinloc >= 0 && idx_bltin < 0)
8427                firstchange = 0;
8428        clearcmdentry(firstchange);
8429        builtinloc = idx_bltin;
8430}
8431enum {
8432        TEOF,
8433        TNL,
8434        TREDIR,
8435        TWORD,
8436        TSEMI,
8437        TBACKGND,
8438        TAND,
8439        TOR,
8440        TPIPE,
8441        TLP,
8442        TRP,
8443        TENDCASE,
8444        TENDBQUOTE,
8445        TNOT,
8446        TCASE,
8447        TDO,
8448        TDONE,
8449        TELIF,
8450        TELSE,
8451        TESAC,
8452        TFI,
8453        TFOR,
8454#if BASH_FUNCTION
8455        TFUNCTION,
8456#endif
8457        TIF,
8458        TIN,
8459        TTHEN,
8460        TUNTIL,
8461        TWHILE,
8462        TBEGIN,
8463        TEND
8464};
8465typedef smallint token_id_t;
8466
8467/* Nth bit indicates if token marks the end of a list */
8468enum {
8469        tokendlist = 0
8470        /*  0 */ | (1u << TEOF)
8471        /*  1 */ | (0u << TNL)
8472        /*  2 */ | (0u << TREDIR)
8473        /*  3 */ | (0u << TWORD)
8474        /*  4 */ | (0u << TSEMI)
8475        /*  5 */ | (0u << TBACKGND)
8476        /*  6 */ | (0u << TAND)
8477        /*  7 */ | (0u << TOR)
8478        /*  8 */ | (0u << TPIPE)
8479        /*  9 */ | (0u << TLP)
8480        /* 10 */ | (1u << TRP)
8481        /* 11 */ | (1u << TENDCASE)
8482        /* 12 */ | (1u << TENDBQUOTE)
8483        /* 13 */ | (0u << TNOT)
8484        /* 14 */ | (0u << TCASE)
8485        /* 15 */ | (1u << TDO)
8486        /* 16 */ | (1u << TDONE)
8487        /* 17 */ | (1u << TELIF)
8488        /* 18 */ | (1u << TELSE)
8489        /* 19 */ | (1u << TESAC)
8490        /* 20 */ | (1u << TFI)
8491        /* 21 */ | (0u << TFOR)
8492#if BASH_FUNCTION
8493        /* 22 */ | (0u << TFUNCTION)
8494#endif
8495        /* 23 */ | (0u << TIF)
8496        /* 24 */ | (0u << TIN)
8497        /* 25 */ | (1u << TTHEN)
8498        /* 26 */ | (0u << TUNTIL)
8499        /* 27 */ | (0u << TWHILE)
8500        /* 28 */ | (0u << TBEGIN)
8501        /* 29 */ | (1u << TEND)
8502        , /* thus far 29 bits used */
8503};
8504
8505static const char *const tokname_array[] = {
8506        "end of file",
8507        "newline",
8508        "redirection",
8509        "word",
8510        ";",
8511        "&",
8512        "&&",
8513        "||",
8514        "|",
8515        "(",
8516        ")",
8517        ";;",
8518        "`",
8519#define KWDOFFSET 13
8520        /* the following are keywords */
8521        "!",
8522        "case",
8523        "do",
8524        "done",
8525        "elif",
8526        "else",
8527        "esac",
8528        "fi",
8529        "for",
8530#if BASH_FUNCTION
8531        "function",
8532#endif
8533        "if",
8534        "in",
8535        "then",
8536        "until",
8537        "while",
8538        "{",
8539        "}",
8540};
8541
8542/* Wrapper around strcmp for qsort/bsearch/... */
8543static int
8544pstrcmp(const void *a, const void *b)
8545{
8546        return strcmp((char*)a, *(char**)b);
8547}
8548
8549static const char *const *
8550findkwd(const char *s)
8551{
8552        return bsearch(s, tokname_array + KWDOFFSET,
8553                        ARRAY_SIZE(tokname_array) - KWDOFFSET,
8554                        sizeof(tokname_array[0]), pstrcmp);
8555}
8556
8557/*
8558 * Locate and print what a word is...
8559 */
8560static int
8561describe_command(char *command, const char *path, int describe_command_verbose)
8562{
8563        struct cmdentry entry;
8564#if ENABLE_ASH_ALIAS
8565        const struct alias *ap;
8566#endif
8567
8568        path = path ? path : pathval();
8569
8570        if (describe_command_verbose) {
8571                out1str(command);
8572        }
8573
8574        /* First look at the keywords */
8575        if (findkwd(command)) {
8576                out1str(describe_command_verbose ? " is a shell keyword" : command);
8577                goto out;
8578        }
8579
8580#if ENABLE_ASH_ALIAS
8581        /* Then look at the aliases */
8582        ap = lookupalias(command, 0);
8583        if (ap != NULL) {
8584                if (!describe_command_verbose) {
8585                        out1str("alias ");
8586                        printalias(ap);
8587                        return 0;
8588                }
8589                out1fmt(" is an alias for %s", ap->val);
8590                goto out;
8591        }
8592#endif
8593        /* Brute force */
8594        find_command(command, &entry, DO_ABS, path);
8595
8596        switch (entry.cmdtype) {
8597        case CMDNORMAL: {
8598                int j = entry.u.index;
8599                char *p;
8600                if (j < 0) {
8601                        p = command;
8602                } else {
8603                        do {
8604                                p = path_advance(&path, command);
8605                                stunalloc(p);
8606                        } while (--j >= 0);
8607                }
8608                if (describe_command_verbose) {
8609                        out1fmt(" is %s", p);
8610                } else {
8611                        out1str(p);
8612                }
8613                break;
8614        }
8615
8616        case CMDFUNCTION:
8617                if (describe_command_verbose) {
8618                        /*out1str(" is a shell function");*/
8619                        out1str(" is a function"); /* bash says this */
8620                } else {
8621                        out1str(command);
8622                }
8623                break;
8624
8625        case CMDBUILTIN:
8626                if (describe_command_verbose) {
8627                        out1fmt(" is a %sshell builtin",
8628                                IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8629                                        "special " : nullstr
8630                        );
8631                } else {
8632                        out1str(command);
8633                }
8634                break;
8635
8636        default:
8637                if (describe_command_verbose) {
8638                        out1str(": not found\n");
8639                }
8640                return 127;
8641        }
8642 out:
8643        out1str("\n");
8644        return 0;
8645}
8646
8647static int FAST_FUNC
8648typecmd(int argc UNUSED_PARAM, char **argv)
8649{
8650        int i = 1;
8651        int err = 0;
8652        int verbose = 1;
8653
8654        /* type -p ... ? (we don't bother checking for 'p') */
8655        if (argv[1] && argv[1][0] == '-') {
8656                i++;
8657                verbose = 0;
8658        }
8659        while (argv[i]) {
8660                err |= describe_command(argv[i++], NULL, verbose);
8661        }
8662        return err;
8663}
8664
8665#if ENABLE_ASH_CMDCMD
8666/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8667static char **
8668parse_command_args(char **argv, const char **path)
8669{
8670        char *cp, c;
8671
8672        for (;;) {
8673                cp = *++argv;
8674                if (!cp)
8675                        return NULL;
8676                if (*cp++ != '-')
8677                        break;
8678                c = *cp++;
8679                if (!c)
8680                        break;
8681                if (c == '-' && !*cp) {
8682                        if (!*++argv)
8683                                return NULL;
8684                        break;
8685                }
8686                do {
8687                        switch (c) {
8688                        case 'p':
8689                                *path = bb_default_path;
8690                                break;
8691                        default:
8692                                /* run 'typecmd' for other options */
8693                                return NULL;
8694                        }
8695                        c = *cp++;
8696                } while (c);
8697        }
8698        return argv;
8699}
8700
8701static int FAST_FUNC
8702commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8703{
8704        char *cmd;
8705        int c;
8706        enum {
8707                VERIFY_BRIEF = 1,
8708                VERIFY_VERBOSE = 2,
8709        } verify = 0;
8710        const char *path = NULL;
8711
8712        /* "command [-p] PROG ARGS" (that is, without -V or -v)
8713         * never reaches this function.
8714         */
8715
8716        while ((c = nextopt("pvV")) != '\0')
8717                if (c == 'V')
8718                        verify |= VERIFY_VERBOSE;
8719                else if (c == 'v')
8720                        /*verify |= VERIFY_BRIEF*/;
8721#if DEBUG
8722                else if (c != 'p')
8723                        abort();
8724#endif
8725                else
8726                        path = bb_default_path;
8727
8728        /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8729        cmd = *argptr;
8730        if (/*verify && */ cmd)
8731                return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8732
8733        return 0;
8734}
8735#endif
8736
8737
8738/*static int funcblocksize;     // size of structures in function */
8739/*static int funcstringsize;    // size of strings in node */
8740static void *funcblock;         /* block to allocate function from */
8741static char *funcstring_end;    /* end of block to allocate strings from */
8742
8743static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8744        [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
8745        [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
8746        [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
8747        [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8748        [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8749        [NAND     ] = SHELL_ALIGN(sizeof(struct nbinary)),
8750        [NOR      ] = SHELL_ALIGN(sizeof(struct nbinary)),
8751        [NSEMI    ] = SHELL_ALIGN(sizeof(struct nbinary)),
8752        [NIF      ] = SHELL_ALIGN(sizeof(struct nif)),
8753        [NWHILE   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8754        [NUNTIL   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8755        [NFOR     ] = SHELL_ALIGN(sizeof(struct nfor)),
8756        [NCASE    ] = SHELL_ALIGN(sizeof(struct ncase)),
8757        [NCLIST   ] = SHELL_ALIGN(sizeof(struct nclist)),
8758        [NDEFUN   ] = SHELL_ALIGN(sizeof(struct narg)),
8759        [NARG     ] = SHELL_ALIGN(sizeof(struct narg)),
8760        [NTO      ] = SHELL_ALIGN(sizeof(struct nfile)),
8761#if BASH_REDIR_OUTPUT
8762        [NTO2     ] = SHELL_ALIGN(sizeof(struct nfile)),
8763#endif
8764        [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8765        [NFROM    ] = SHELL_ALIGN(sizeof(struct nfile)),
8766        [NFROMTO  ] = SHELL_ALIGN(sizeof(struct nfile)),
8767        [NAPPEND  ] = SHELL_ALIGN(sizeof(struct nfile)),
8768        [NTOFD    ] = SHELL_ALIGN(sizeof(struct ndup)),
8769        [NFROMFD  ] = SHELL_ALIGN(sizeof(struct ndup)),
8770        [NHERE    ] = SHELL_ALIGN(sizeof(struct nhere)),
8771        [NXHERE   ] = SHELL_ALIGN(sizeof(struct nhere)),
8772        [NNOT     ] = SHELL_ALIGN(sizeof(struct nnot)),
8773};
8774
8775static int calcsize(int funcblocksize, union node *n);
8776
8777static int
8778sizenodelist(int funcblocksize, struct nodelist *lp)
8779{
8780        while (lp) {
8781                funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8782                funcblocksize = calcsize(funcblocksize, lp->n);
8783                lp = lp->next;
8784        }
8785        return funcblocksize;
8786}
8787
8788static int
8789calcsize(int funcblocksize, union node *n)
8790{
8791        if (n == NULL)
8792                return funcblocksize;
8793        funcblocksize += nodesize[n->type];
8794        switch (n->type) {
8795        case NCMD:
8796                funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8797                funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8798                funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8799                break;
8800        case NPIPE:
8801                funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8802                break;
8803        case NREDIR:
8804        case NBACKGND:
8805        case NSUBSHELL:
8806                funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8807                funcblocksize = calcsize(funcblocksize, n->nredir.n);
8808                break;
8809        case NAND:
8810        case NOR:
8811        case NSEMI:
8812        case NWHILE:
8813        case NUNTIL:
8814                funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8815                funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
8816                break;
8817        case NIF:
8818                funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8819                funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8820                funcblocksize = calcsize(funcblocksize, n->nif.test);
8821                break;
8822        case NFOR:
8823                funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
8824                funcblocksize = calcsize(funcblocksize, n->nfor.body);
8825                funcblocksize = calcsize(funcblocksize, n->nfor.args);
8826                break;
8827        case NCASE:
8828                funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8829                funcblocksize = calcsize(funcblocksize, n->ncase.expr);
8830                break;
8831        case NCLIST:
8832                funcblocksize = calcsize(funcblocksize, n->nclist.body);
8833                funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8834                funcblocksize = calcsize(funcblocksize, n->nclist.next);
8835                break;
8836        case NDEFUN:
8837                funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8838                funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8839                break;
8840        case NARG:
8841                funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
8842                funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
8843                funcblocksize = calcsize(funcblocksize, n->narg.next);
8844                break;
8845        case NTO:
8846#if BASH_REDIR_OUTPUT
8847        case NTO2:
8848#endif
8849        case NCLOBBER:
8850        case NFROM:
8851        case NFROMTO:
8852        case NAPPEND:
8853                funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8854                funcblocksize = calcsize(funcblocksize, n->nfile.next);
8855                break;
8856        case NTOFD:
8857        case NFROMFD:
8858                funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8859                funcblocksize = calcsize(funcblocksize, n->ndup.next);
8860        break;
8861        case NHERE:
8862        case NXHERE:
8863                funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8864                funcblocksize = calcsize(funcblocksize, n->nhere.next);
8865                break;
8866        case NNOT:
8867                funcblocksize = calcsize(funcblocksize, n->nnot.com);
8868                break;
8869        };
8870        return funcblocksize;
8871}
8872
8873static char *
8874nodeckstrdup(char *s)
8875{
8876        funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
8877        return strcpy(funcstring_end, s);
8878}
8879
8880static union node *copynode(union node *);
8881
8882static struct nodelist *
8883copynodelist(struct nodelist *lp)
8884{
8885        struct nodelist *start;
8886        struct nodelist **lpp;
8887
8888        lpp = &start;
8889        while (lp) {
8890                *lpp = funcblock;
8891                funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8892                (*lpp)->n = copynode(lp->n);
8893                lp = lp->next;
8894                lpp = &(*lpp)->next;
8895        }
8896        *lpp = NULL;
8897        return start;
8898}
8899
8900static union node *
8901copynode(union node *n)
8902{
8903        union node *new;
8904
8905        if (n == NULL)
8906                return NULL;
8907        new = funcblock;
8908        funcblock = (char *) funcblock + nodesize[n->type];
8909
8910        switch (n->type) {
8911        case NCMD:
8912                new->ncmd.redirect = copynode(n->ncmd.redirect);
8913                new->ncmd.args = copynode(n->ncmd.args);
8914                new->ncmd.assign = copynode(n->ncmd.assign);
8915                new->ncmd.linno = n->ncmd.linno;
8916                break;
8917        case NPIPE:
8918                new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8919                new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8920                break;
8921        case NREDIR:
8922        case NBACKGND:
8923        case NSUBSHELL:
8924                new->nredir.redirect = copynode(n->nredir.redirect);
8925                new->nredir.n = copynode(n->nredir.n);
8926                new->nredir.linno = n->nredir.linno;
8927                break;
8928        case NAND:
8929        case NOR:
8930        case NSEMI:
8931        case NWHILE:
8932        case NUNTIL:
8933                new->nbinary.ch2 = copynode(n->nbinary.ch2);
8934                new->nbinary.ch1 = copynode(n->nbinary.ch1);
8935                break;
8936        case NIF:
8937                new->nif.elsepart = copynode(n->nif.elsepart);
8938                new->nif.ifpart = copynode(n->nif.ifpart);
8939                new->nif.test = copynode(n->nif.test);
8940                break;
8941        case NFOR:
8942                new->nfor.var = nodeckstrdup(n->nfor.var);
8943                new->nfor.body = copynode(n->nfor.body);
8944                new->nfor.args = copynode(n->nfor.args);
8945                new->nfor.linno = n->nfor.linno;
8946                break;
8947        case NCASE:
8948                new->ncase.cases = copynode(n->ncase.cases);
8949                new->ncase.expr = copynode(n->ncase.expr);
8950                new->ncase.linno = n->ncase.linno;
8951                break;
8952        case NCLIST:
8953                new->nclist.body = copynode(n->nclist.body);
8954                new->nclist.pattern = copynode(n->nclist.pattern);
8955                new->nclist.next = copynode(n->nclist.next);
8956                break;
8957        case NDEFUN:
8958                new->ndefun.body = copynode(n->ndefun.body);
8959                new->ndefun.text = nodeckstrdup(n->ndefun.text);
8960                new->ndefun.linno = n->ndefun.linno;
8961                break;
8962        case NARG:
8963                new->narg.backquote = copynodelist(n->narg.backquote);
8964                new->narg.text = nodeckstrdup(n->narg.text);
8965                new->narg.next = copynode(n->narg.next);
8966                break;
8967        case NTO:
8968#if BASH_REDIR_OUTPUT
8969        case NTO2:
8970#endif
8971        case NCLOBBER:
8972        case NFROM:
8973        case NFROMTO:
8974        case NAPPEND:
8975                new->nfile.fname = copynode(n->nfile.fname);
8976                new->nfile.fd = n->nfile.fd;
8977                new->nfile.next = copynode(n->nfile.next);
8978                break;
8979        case NTOFD:
8980        case NFROMFD:
8981                new->ndup.vname = copynode(n->ndup.vname);
8982                new->ndup.dupfd = n->ndup.dupfd;
8983                new->ndup.fd = n->ndup.fd;
8984                new->ndup.next = copynode(n->ndup.next);
8985                break;
8986        case NHERE:
8987        case NXHERE:
8988                new->nhere.doc = copynode(n->nhere.doc);
8989                new->nhere.fd = n->nhere.fd;
8990                new->nhere.next = copynode(n->nhere.next);
8991                break;
8992        case NNOT:
8993                new->nnot.com = copynode(n->nnot.com);
8994                break;
8995        };
8996        new->type = n->type;
8997        return new;
8998}
8999
9000/*
9001 * Make a copy of a parse tree.
9002 */
9003static struct funcnode *
9004copyfunc(union node *n)
9005{
9006        struct funcnode *f;
9007        size_t blocksize;
9008
9009        /*funcstringsize = 0;*/
9010        blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
9011        f = ckzalloc(blocksize /* + funcstringsize */);
9012        funcblock = (char *) f + offsetof(struct funcnode, n);
9013        funcstring_end = (char *) f + blocksize;
9014        copynode(n);
9015        /* f->count = 0; - ckzalloc did it */
9016        return f;
9017}
9018
9019/*
9020 * Define a shell function.
9021 */
9022static void
9023defun(union node *func)
9024{
9025        struct cmdentry entry;
9026
9027        INT_OFF;
9028        entry.cmdtype = CMDFUNCTION;
9029        entry.u.func = copyfunc(func);
9030        addcmdentry(func->ndefun.text, &entry);
9031        INT_ON;
9032}
9033
9034/* Reasons for skipping commands (see comment on breakcmd routine) */
9035#define SKIPBREAK      (1 << 0)
9036#define SKIPCONT       (1 << 1)
9037#define SKIPFUNC       (1 << 2)
9038static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
9039static int skipcount;           /* number of levels to skip */
9040static int loopnest;            /* current loop nesting level */
9041static int funcline;            /* starting line number of current function, or 0 if not in a function */
9042
9043/* Forward decl way out to parsing code - dotrap needs it */
9044static int evalstring(char *s, int flags);
9045
9046/* Called to execute a trap.
9047 * Single callsite - at the end of evaltree().
9048 * If we return non-zero, evaltree raises EXEXIT exception.
9049 *
9050 * Perhaps we should avoid entering new trap handlers
9051 * while we are executing a trap handler. [is it a TODO?]
9052 */
9053static void
9054dotrap(void)
9055{
9056        uint8_t *g;
9057        int sig;
9058        uint8_t last_status;
9059
9060        if (!pending_sig)
9061                return;
9062
9063        last_status = exitstatus;
9064        pending_sig = 0;
9065        barrier();
9066
9067        TRACE(("dotrap entered\n"));
9068        for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
9069                char *p;
9070
9071                if (!*g)
9072                        continue;
9073
9074                if (evalskip) {
9075                        pending_sig = sig;
9076                        break;
9077                }
9078
9079                p = trap[sig];
9080                /* non-trapped SIGINT is handled separately by raise_interrupt,
9081                 * don't upset it by resetting gotsig[SIGINT-1] */
9082                if (sig == SIGINT && !p)
9083                        continue;
9084
9085                TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
9086                *g = 0;
9087                if (!p)
9088                        continue;
9089                evalstring(p, 0);
9090        }
9091        exitstatus = last_status;
9092        TRACE(("dotrap returns\n"));
9093}
9094
9095/* forward declarations - evaluation is fairly recursive business... */
9096static int evalloop(union node *, int);
9097static int evalfor(union node *, int);
9098static int evalcase(union node *, int);
9099static int evalsubshell(union node *, int);
9100static void expredir(union node *);
9101static int evalpipe(union node *, int);
9102static int evalcommand(union node *, int);
9103static int evalbltin(const struct builtincmd *, int, char **, int);
9104static void prehash(union node *);
9105
9106/*
9107 * Evaluate a parse tree.  The value is left in the global variable
9108 * exitstatus.
9109 */
9110static int
9111evaltree(union node *n, int flags)
9112{
9113        int checkexit = 0;
9114        int (*evalfn)(union node *, int);
9115        struct stackmark smark;
9116        int status = 0;
9117
9118        setstackmark(&smark);
9119
9120        if (n == NULL) {
9121                TRACE(("evaltree(NULL) called\n"));
9122                goto out;
9123        }
9124        TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
9125
9126        dotrap();
9127
9128        switch (n->type) {
9129        default:
9130#if DEBUG
9131                out1fmt("Node type = %d\n", n->type);
9132                fflush_all();
9133                break;
9134#endif
9135        case NNOT:
9136                status = !evaltree(n->nnot.com, EV_TESTED);
9137                goto setstatus;
9138        case NREDIR:
9139                errlinno = lineno = n->nredir.linno;
9140                if (funcline)
9141                        lineno -= funcline - 1;
9142                expredir(n->nredir.redirect);
9143                pushredir(n->nredir.redirect);
9144                status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9145                if (!status) {
9146                        status = evaltree(n->nredir.n, flags & EV_TESTED);
9147                }
9148                if (n->nredir.redirect)
9149                        popredir(/*drop:*/ 0);
9150                goto setstatus;
9151        case NCMD:
9152                evalfn = evalcommand;
9153 checkexit:
9154                if (eflag && !(flags & EV_TESTED))
9155                        checkexit = ~0;
9156                goto calleval;
9157        case NFOR:
9158                evalfn = evalfor;
9159                goto calleval;
9160        case NWHILE:
9161        case NUNTIL:
9162                evalfn = evalloop;
9163                goto calleval;
9164        case NSUBSHELL:
9165        case NBACKGND:
9166                evalfn = evalsubshell;
9167                goto checkexit;
9168        case NPIPE:
9169                evalfn = evalpipe;
9170                goto checkexit;
9171        case NCASE:
9172                evalfn = evalcase;
9173                goto calleval;
9174        case NAND:
9175        case NOR:
9176        case NSEMI: {
9177
9178#if NAND + 1 != NOR
9179#error NAND + 1 != NOR
9180#endif
9181#if NOR + 1 != NSEMI
9182#error NOR + 1 != NSEMI
9183#endif
9184                unsigned is_or = n->type - NAND;
9185                status = evaltree(
9186                        n->nbinary.ch1,
9187                        (flags | ((is_or >> 1) - 1)) & EV_TESTED
9188                );
9189                if ((!status) == is_or || evalskip)
9190                        break;
9191                n = n->nbinary.ch2;
9192 evaln:
9193                evalfn = evaltree;
9194 calleval:
9195                status = evalfn(n, flags);
9196                goto setstatus;
9197        }
9198        case NIF:
9199                status = evaltree(n->nif.test, EV_TESTED);
9200                if (evalskip)
9201                        break;
9202                if (!status) {
9203                        n = n->nif.ifpart;
9204                        goto evaln;
9205                }
9206                if (n->nif.elsepart) {
9207                        n = n->nif.elsepart;
9208                        goto evaln;
9209                }
9210                status = 0;
9211                goto setstatus;
9212        case NDEFUN:
9213                defun(n);
9214                /* Not necessary. To test it:
9215                 * "false; f() { qwerty; }; echo $?" should print 0.
9216                 */
9217                /* status = 0; */
9218 setstatus:
9219                exitstatus = status;
9220                break;
9221        }
9222 out:
9223        /* Order of checks below is important:
9224         * signal handlers trigger before exit caused by "set -e".
9225         */
9226        dotrap();
9227
9228        if (checkexit & status)
9229                raise_exception(EXEXIT);
9230        if (flags & EV_EXIT)
9231                raise_exception(EXEXIT);
9232
9233        popstackmark(&smark);
9234        TRACE(("leaving evaltree (no interrupts)\n"));
9235        return exitstatus;
9236}
9237
9238static int
9239skiploop(void)
9240{
9241        int skip = evalskip;
9242
9243        switch (skip) {
9244        case 0:
9245                break;
9246        case SKIPBREAK:
9247        case SKIPCONT:
9248                if (--skipcount <= 0) {
9249                        evalskip = 0;
9250                        break;
9251                }
9252                skip = SKIPBREAK;
9253                break;
9254        }
9255        return skip;
9256}
9257
9258static int
9259evalloop(union node *n, int flags)
9260{
9261        int skip;
9262        int status;
9263
9264        loopnest++;
9265        status = 0;
9266        flags &= EV_TESTED;
9267        do {
9268                int i;
9269
9270                i = evaltree(n->nbinary.ch1, EV_TESTED);
9271                skip = skiploop();
9272                if (skip == SKIPFUNC)
9273                        status = i;
9274                if (skip)
9275                        continue;
9276                if (n->type != NWHILE)
9277                        i = !i;
9278                if (i != 0)
9279                        break;
9280                status = evaltree(n->nbinary.ch2, flags);
9281                skip = skiploop();
9282        } while (!(skip & ~SKIPCONT));
9283        loopnest--;
9284
9285        return status;
9286}
9287
9288static int
9289evalfor(union node *n, int flags)
9290{
9291        struct arglist arglist;
9292        union node *argp;
9293        struct strlist *sp;
9294        int status = 0;
9295
9296        errlinno = lineno = n->ncase.linno;
9297        if (funcline)
9298                lineno -= funcline - 1;
9299
9300        arglist.list = NULL;
9301        arglist.lastp = &arglist.list;
9302        for (argp = n->nfor.args; argp; argp = argp->narg.next) {
9303                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9304        }
9305        *arglist.lastp = NULL;
9306
9307        loopnest++;
9308        flags &= EV_TESTED;
9309        for (sp = arglist.list; sp; sp = sp->next) {
9310                setvar0(n->nfor.var, sp->text);
9311                status = evaltree(n->nfor.body, flags);
9312                if (skiploop() & ~SKIPCONT)
9313                        break;
9314        }
9315        loopnest--;
9316
9317        return status;
9318}
9319
9320static int
9321evalcase(union node *n, int flags)
9322{
9323        union node *cp;
9324        union node *patp;
9325        struct arglist arglist;
9326        int status = 0;
9327
9328        errlinno = lineno = n->ncase.linno;
9329        if (funcline)
9330                lineno -= funcline - 1;
9331
9332        arglist.list = NULL;
9333        arglist.lastp = &arglist.list;
9334        expandarg(n->ncase.expr, &arglist, EXP_TILDE);
9335        for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9336                for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
9337                        if (casematch(patp, arglist.list->text)) {
9338                                /* Ensure body is non-empty as otherwise
9339                                 * EV_EXIT may prevent us from setting the
9340                                 * exit status.
9341                                 */
9342                                if (evalskip == 0 && cp->nclist.body) {
9343                                        status = evaltree(cp->nclist.body, flags);
9344                                }
9345                                goto out;
9346                        }
9347                }
9348        }
9349 out:
9350        return status;
9351}
9352
9353/*
9354 * Kick off a subshell to evaluate a tree.
9355 */
9356static int
9357evalsubshell(union node *n, int flags)
9358{
9359        struct job *jp;
9360        int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9361        int status;
9362
9363        errlinno = lineno = n->nredir.linno;
9364        if (funcline)
9365                lineno -= funcline - 1;
9366
9367        expredir(n->nredir.redirect);
9368        if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9369                goto nofork;
9370        INT_OFF;
9371        if (backgnd == FORK_FG)
9372                get_tty_state();
9373        jp = makejob(/*n,*/ 1);
9374        if (forkshell(jp, n, backgnd) == 0) {
9375                /* child */
9376                INT_ON;
9377                flags |= EV_EXIT;
9378                if (backgnd)
9379                        flags &= ~EV_TESTED;
9380 nofork:
9381                redirect(n->nredir.redirect, 0);
9382                evaltreenr(n->nredir.n, flags);
9383                /* never returns */
9384        }
9385        /* parent */
9386        status = 0;
9387        if (backgnd == FORK_FG)
9388                status = waitforjob(jp);
9389        INT_ON;
9390        return status;
9391}
9392
9393/*
9394 * Compute the names of the files in a redirection list.
9395 */
9396static void fixredir(union node *, const char *, int);
9397static void
9398expredir(union node *n)
9399{
9400        union node *redir;
9401
9402        for (redir = n; redir; redir = redir->nfile.next) {
9403                struct arglist fn;
9404
9405                fn.list = NULL;
9406                fn.lastp = &fn.list;
9407                switch (redir->type) {
9408                case NFROMTO:
9409                case NFROM:
9410                case NTO:
9411#if BASH_REDIR_OUTPUT
9412                case NTO2:
9413#endif
9414                case NCLOBBER:
9415                case NAPPEND:
9416                        expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
9417                        TRACE(("expredir expanded to '%s'\n", fn.list->text));
9418#if BASH_REDIR_OUTPUT
9419 store_expfname:
9420#endif
9421#if 0
9422// By the design of stack allocator, the loop of this kind:
9423//      while true; do while true; do break; done </dev/null; done
9424// will look like a memory leak: ash plans to free expfname's
9425// of "/dev/null" as soon as it finishes running the loop
9426// (in this case, never).
9427// This "fix" is wrong:
9428                        if (redir->nfile.expfname)
9429                                stunalloc(redir->nfile.expfname);
9430// It results in corrupted state of stacked allocations.
9431#endif
9432                        redir->nfile.expfname = fn.list->text;
9433                        break;
9434                case NFROMFD:
9435                case NTOFD: /* >& */
9436                        if (redir->ndup.vname) {
9437                                expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
9438                                if (fn.list == NULL)
9439                                        ash_msg_and_raise_error("redir error");
9440#if BASH_REDIR_OUTPUT
9441//FIXME: we used expandarg with different args!
9442                                if (!isdigit_str9(fn.list->text)) {
9443                                        /* >&file, not >&fd */
9444                                        if (redir->nfile.fd != 1) /* 123>&file - BAD */
9445                                                ash_msg_and_raise_error("redir error");
9446                                        redir->type = NTO2;
9447                                        goto store_expfname;
9448                                }
9449#endif
9450                                fixredir(redir, fn.list->text, 1);
9451                        }
9452                        break;
9453                }
9454        }
9455}
9456
9457/*
9458 * Evaluate a pipeline.  All the processes in the pipeline are children
9459 * of the process creating the pipeline.  (This differs from some versions
9460 * of the shell, which make the last process in a pipeline the parent
9461 * of all the rest.)
9462 */
9463static int
9464evalpipe(union node *n, int flags)
9465{
9466        struct job *jp;
9467        struct nodelist *lp;
9468        int pipelen;
9469        int prevfd;
9470        int pip[2];
9471        int status = 0;
9472
9473        TRACE(("evalpipe(0x%lx) called\n", (long)n));
9474        pipelen = 0;
9475        for (lp = n->npipe.cmdlist; lp; lp = lp->next)
9476                pipelen++;
9477        flags |= EV_EXIT;
9478        INT_OFF;
9479        if (n->npipe.pipe_backgnd == 0)
9480                get_tty_state();
9481        jp = makejob(/*n,*/ pipelen);
9482        prevfd = -1;
9483        for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
9484                prehash(lp->n);
9485                pip[1] = -1;
9486                if (lp->next) {
9487                        if (pipe(pip) < 0) {
9488                                close(prevfd);
9489                                ash_msg_and_raise_perror("can't create pipe");
9490                        }
9491                }
9492                if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9493                        /* child */
9494                        INT_ON;
9495                        if (pip[1] >= 0) {
9496                                close(pip[0]);
9497                        }
9498                        if (prevfd > 0) {
9499                                dup2(prevfd, 0);
9500                                close(prevfd);
9501                        }
9502                        if (pip[1] > 1) {
9503                                dup2(pip[1], 1);
9504                                close(pip[1]);
9505                        }
9506                        evaltreenr(lp->n, flags);
9507                        /* never returns */
9508                }
9509                /* parent */
9510                if (prevfd >= 0)
9511                        close(prevfd);
9512                prevfd = pip[0];
9513                /* Don't want to trigger debugging */
9514                if (pip[1] != -1)
9515                        close(pip[1]);
9516        }
9517        if (n->npipe.pipe_backgnd == 0) {
9518                status = waitforjob(jp);
9519                TRACE(("evalpipe:  job done exit status %d\n", status));
9520        }
9521        INT_ON;
9522
9523        return status;
9524}
9525
9526/*
9527 * Controls whether the shell is interactive or not.
9528 */
9529static void
9530setinteractive(int on)
9531{
9532        static smallint is_interactive;
9533
9534        if (++on == is_interactive)
9535                return;
9536        is_interactive = on;
9537        setsignal(SIGINT);
9538        setsignal(SIGQUIT);
9539        setsignal(SIGTERM);
9540        if (is_interactive > 1) {
9541#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9542                /* Looks like they want an interactive shell */
9543                static smallint did_banner;
9544
9545                if (!did_banner) {
9546                        /* note: ash and hush share this string */
9547                        out1fmt("\n\n%s %s\n"
9548                                IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9549                                "\n",
9550                                bb_banner,
9551                                "built-in shell (ash)"
9552                        );
9553                        did_banner = 1;
9554                }
9555#endif
9556#if ENABLE_FEATURE_EDITING
9557                if (!line_input_state)
9558                        line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
9559#endif
9560        }
9561}
9562
9563static void
9564optschanged(void)
9565{
9566#if DEBUG
9567        opentrace();
9568#endif
9569        setinteractive(iflag);
9570        setjobctl(mflag);
9571#if ENABLE_FEATURE_EDITING_VI
9572        if (line_input_state) {
9573                if (viflag)
9574                        line_input_state->flags |= VI_MODE;
9575                else
9576                        line_input_state->flags &= ~VI_MODE;
9577        }
9578#else
9579        viflag = 0; /* forcibly keep the option off */
9580#endif
9581}
9582
9583struct localvar_list {
9584        struct localvar_list *next;
9585        struct localvar *lv;
9586};
9587
9588static struct localvar_list *localvar_stack;
9589
9590/*
9591 * Called after a function returns.
9592 * Interrupts must be off.
9593 */
9594static void
9595poplocalvars(int keep)
9596{
9597        struct localvar_list *ll;
9598        struct localvar *lvp, *next;
9599        struct var *vp;
9600
9601        INT_OFF;
9602        ll = localvar_stack;
9603        localvar_stack = ll->next;
9604
9605        next = ll->lv;
9606        free(ll);
9607
9608        while ((lvp = next) != NULL) {
9609                next = lvp->next;
9610                vp = lvp->vp;
9611                TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9612                if (keep) {
9613                        int bits = VSTRFIXED;
9614
9615                        if (lvp->flags != VUNSET) {
9616                                if (vp->var_text == lvp->text)
9617                                        bits |= VTEXTFIXED;
9618                                else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9619                                        free((char*)lvp->text);
9620                        }
9621
9622                        vp->flags &= ~bits;
9623                        vp->flags |= (lvp->flags & bits);
9624
9625                        if ((vp->flags &
9626                             (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9627                                unsetvar(vp->var_text);
9628                } else if (vp == NULL) {        /* $- saved */
9629                        memcpy(optlist, lvp->text, sizeof(optlist));
9630                        free((char*)lvp->text);
9631                        optschanged();
9632                } else if (lvp->flags == VUNSET) {
9633                        vp->flags &= ~(VSTRFIXED|VREADONLY);
9634                        unsetvar(vp->var_text);
9635                } else {
9636                        if (vp->var_func)
9637                                vp->var_func(var_end(lvp->text));
9638                        if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9639                                free((char*)vp->var_text);
9640                        vp->flags = lvp->flags;
9641                        vp->var_text = lvp->text;
9642                }
9643                free(lvp);
9644        }
9645        INT_ON;
9646}
9647
9648/*
9649 * Create a new localvar environment.
9650 */
9651static struct localvar_list *
9652pushlocalvars(void)
9653{
9654        struct localvar_list *ll;
9655
9656        INT_OFF;
9657        ll = ckzalloc(sizeof(*ll));
9658        /*ll->lv = NULL; - zalloc did it */
9659        ll->next = localvar_stack;
9660        localvar_stack = ll;
9661        INT_ON;
9662
9663        return ll->next;
9664}
9665
9666static void
9667unwindlocalvars(struct localvar_list *stop)
9668{
9669        while (localvar_stack != stop)
9670                poplocalvars(0);
9671}
9672
9673static int
9674evalfun(struct funcnode *func, int argc, char **argv, int flags)
9675{
9676        volatile struct shparam saveparam;
9677        struct jmploc *volatile savehandler;
9678        struct jmploc jmploc;
9679        int e;
9680        int savefuncline;
9681
9682        saveparam = shellparam;
9683        savefuncline = funcline;
9684        savehandler = exception_handler;
9685        e = setjmp(jmploc.loc);
9686        if (e) {
9687                goto funcdone;
9688        }
9689        INT_OFF;
9690        exception_handler = &jmploc;
9691        shellparam.malloced = 0;
9692        func->count++;
9693        funcline = func->n.ndefun.linno;
9694        INT_ON;
9695        shellparam.nparam = argc - 1;
9696        shellparam.p = argv + 1;
9697#if ENABLE_ASH_GETOPTS
9698        shellparam.optind = 1;
9699        shellparam.optoff = -1;
9700#endif
9701        evaltree(func->n.ndefun.body, flags & EV_TESTED);
9702 funcdone:
9703        INT_OFF;
9704        funcline = savefuncline;
9705        freefunc(func);
9706        freeparam(&shellparam);
9707        shellparam = saveparam;
9708        exception_handler = savehandler;
9709        INT_ON;
9710        evalskip &= ~SKIPFUNC;
9711        return e;
9712}
9713
9714/*
9715 * Make a variable a local variable.  When a variable is made local, it's
9716 * value and flags are saved in a localvar structure.  The saved values
9717 * will be restored when the shell function returns.  We handle the name
9718 * "-" as a special case: it makes changes to "set +-options" local
9719 * (options will be restored on return from the function).
9720 */
9721static void
9722mklocal(char *name)
9723{
9724        struct localvar *lvp;
9725        struct var **vpp;
9726        struct var *vp;
9727        char *eq = strchr(name, '=');
9728
9729        INT_OFF;
9730        /* Cater for duplicate "local". Examples:
9731         * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9732         * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9733         */
9734        lvp = localvar_stack->lv;
9735        while (lvp) {
9736                if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9737                        if (eq)
9738                                setvareq(name, 0);
9739                        /* else:
9740                         * it's a duplicate "local VAR" declaration, do nothing
9741                         */
9742                        goto ret;
9743                }
9744                lvp = lvp->next;
9745        }
9746
9747        lvp = ckzalloc(sizeof(*lvp));
9748        if (LONE_DASH(name)) {
9749                char *p;
9750                p = ckmalloc(sizeof(optlist));
9751                lvp->text = memcpy(p, optlist, sizeof(optlist));
9752                vp = NULL;
9753        } else {
9754                vpp = hashvar(name);
9755                vp = *findvar(vpp, name);
9756                if (vp == NULL) {
9757                        /* variable did not exist yet */
9758                        if (eq)
9759                                vp = setvareq(name, VSTRFIXED);
9760                        else
9761                                vp = setvar(name, NULL, VSTRFIXED);
9762                        lvp->flags = VUNSET;
9763                } else {
9764                        lvp->text = vp->var_text;
9765                        lvp->flags = vp->flags;
9766                        /* make sure neither "struct var" nor string gets freed
9767                         * during (un)setting:
9768                         */
9769                        vp->flags |= VSTRFIXED|VTEXTFIXED;
9770                        if (eq)
9771                                setvareq(name, 0);
9772                        else
9773                                /* "local VAR" unsets VAR: */
9774                                setvar0(name, NULL);
9775                }
9776        }
9777        lvp->vp = vp;
9778        lvp->next = localvar_stack->lv;
9779        localvar_stack->lv = lvp;
9780 ret:
9781        INT_ON;
9782}
9783
9784/*
9785 * The "local" command.
9786 */
9787static int FAST_FUNC
9788localcmd(int argc UNUSED_PARAM, char **argv)
9789{
9790        char *name;
9791
9792        if (!localvar_stack)
9793                ash_msg_and_raise_error("not in a function");
9794
9795        argv = argptr;
9796        while ((name = *argv++) != NULL) {
9797                mklocal(name);
9798        }
9799        return 0;
9800}
9801
9802static int FAST_FUNC
9803falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9804{
9805        return 1;
9806}
9807
9808static int FAST_FUNC
9809truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9810{
9811        return 0;
9812}
9813
9814static int FAST_FUNC
9815execcmd(int argc UNUSED_PARAM, char **argv)
9816{
9817        optionarg = NULL;
9818        while (nextopt("a:") != '\0')
9819                /* nextopt() sets optionarg to "-a ARGV0" */;
9820
9821        argv = argptr;
9822        if (argv[0]) {
9823                char *prog;
9824
9825                iflag = 0;              /* exit on error */
9826                mflag = 0;
9827                optschanged();
9828                /* We should set up signals for "exec CMD"
9829                 * the same way as for "CMD" without "exec".
9830                 * But optschanged->setinteractive->setsignal
9831                 * still thought we are a root shell. Therefore, for example,
9832                 * SIGQUIT is still set to IGN. Fix it:
9833                 */
9834                shlvl++;
9835                setsignal(SIGQUIT);
9836                /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9837                /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9838                /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9839
9840                prog = argv[0];
9841                if (optionarg)
9842                        argv[0] = optionarg;
9843                shellexec(prog, argv, pathval(), 0);
9844                /* NOTREACHED */
9845        }
9846        return 0;
9847}
9848
9849/*
9850 * The return command.
9851 */
9852static int FAST_FUNC
9853returncmd(int argc UNUSED_PARAM, char **argv)
9854{
9855        /*
9856         * If called outside a function, do what ksh does;
9857         * skip the rest of the file.
9858         */
9859        evalskip = SKIPFUNC;
9860        return argv[1] ? number(argv[1]) : exitstatus;
9861}
9862
9863/* Forward declarations for builtintab[] */
9864static int breakcmd(int, char **) FAST_FUNC;
9865static int dotcmd(int, char **) FAST_FUNC;
9866static int evalcmd(int, char **, int) FAST_FUNC;
9867static int exitcmd(int, char **) FAST_FUNC;
9868static int exportcmd(int, char **) FAST_FUNC;
9869#if ENABLE_ASH_GETOPTS
9870static int getoptscmd(int, char **) FAST_FUNC;
9871#endif
9872#if ENABLE_ASH_HELP
9873static int helpcmd(int, char **) FAST_FUNC;
9874#endif
9875#if MAX_HISTORY
9876static int historycmd(int, char **) FAST_FUNC;
9877#endif
9878#if ENABLE_FEATURE_SH_MATH
9879static int letcmd(int, char **) FAST_FUNC;
9880#endif
9881static int readcmd(int, char **) FAST_FUNC;
9882static int setcmd(int, char **) FAST_FUNC;
9883static int shiftcmd(int, char **) FAST_FUNC;
9884static int timescmd(int, char **) FAST_FUNC;
9885static int trapcmd(int, char **) FAST_FUNC;
9886static int umaskcmd(int, char **) FAST_FUNC;
9887static int unsetcmd(int, char **) FAST_FUNC;
9888static int ulimitcmd(int, char **) FAST_FUNC;
9889
9890#define BUILTIN_NOSPEC          "0"
9891#define BUILTIN_SPECIAL         "1"
9892#define BUILTIN_REGULAR         "2"
9893#define BUILTIN_SPEC_REG        "3"
9894#define BUILTIN_ASSIGN          "4"
9895#define BUILTIN_SPEC_ASSG       "5"
9896#define BUILTIN_REG_ASSG        "6"
9897#define BUILTIN_SPEC_REG_ASSG   "7"
9898
9899/* Stubs for calling non-FAST_FUNC's */
9900#if ENABLE_ASH_ECHO
9901static int FAST_FUNC echocmd(int argc, char **argv)   { return echo_main(argc, argv); }
9902#endif
9903#if ENABLE_ASH_PRINTF
9904static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
9905#endif
9906#if ENABLE_ASH_TEST || BASH_TEST2
9907static int FAST_FUNC testcmd(int argc, char **argv)   { return test_main(argc, argv); }
9908#endif
9909
9910/* Keep these in proper order since it is searched via bsearch() */
9911static const struct builtincmd builtintab[] = {
9912        { BUILTIN_SPEC_REG      "."       , dotcmd     },
9913        { BUILTIN_SPEC_REG      ":"       , truecmd    },
9914#if ENABLE_ASH_TEST
9915        { BUILTIN_REGULAR       "["       , testcmd    },
9916#endif
9917#if BASH_TEST2
9918        { BUILTIN_REGULAR       "[["      , testcmd    },
9919#endif
9920#if ENABLE_ASH_ALIAS
9921        { BUILTIN_REG_ASSG      "alias"   , aliascmd   },
9922#endif
9923#if JOBS
9924        { BUILTIN_REGULAR       "bg"      , fg_bgcmd   },
9925#endif
9926        { BUILTIN_SPEC_REG      "break"   , breakcmd   },
9927        { BUILTIN_REGULAR       "cd"      , cdcmd      },
9928        { BUILTIN_NOSPEC        "chdir"   , cdcmd      },
9929#if ENABLE_ASH_CMDCMD
9930        { BUILTIN_REGULAR       "command" , commandcmd },
9931#endif
9932        { BUILTIN_SPEC_REG      "continue", breakcmd   },
9933#if ENABLE_ASH_ECHO
9934        { BUILTIN_REGULAR       "echo"    , echocmd    },
9935#endif
9936        { BUILTIN_SPEC_REG      "eval"    , NULL       }, /*evalcmd() has a differing prototype*/
9937        { BUILTIN_SPEC_REG      "exec"    , execcmd    },
9938        { BUILTIN_SPEC_REG      "exit"    , exitcmd    },
9939        { BUILTIN_SPEC_REG_ASSG "export"  , exportcmd  },
9940        { BUILTIN_REGULAR       "false"   , falsecmd   },
9941#if JOBS
9942        { BUILTIN_REGULAR       "fg"      , fg_bgcmd   },
9943#endif
9944#if ENABLE_ASH_GETOPTS
9945        { BUILTIN_REGULAR       "getopts" , getoptscmd },
9946#endif
9947        { BUILTIN_NOSPEC        "hash"    , hashcmd    },
9948#if ENABLE_ASH_HELP
9949        { BUILTIN_NOSPEC        "help"    , helpcmd    },
9950#endif
9951#if MAX_HISTORY
9952        { BUILTIN_NOSPEC        "history" , historycmd },
9953#endif
9954#if JOBS
9955        { BUILTIN_REGULAR       "jobs"    , jobscmd    },
9956        { BUILTIN_REGULAR       "kill"    , killcmd    },
9957#endif
9958#if ENABLE_FEATURE_SH_MATH
9959        { BUILTIN_NOSPEC        "let"     , letcmd     },
9960#endif
9961        { BUILTIN_SPEC_REG_ASSG "local"   , localcmd   },
9962#if ENABLE_ASH_PRINTF
9963        { BUILTIN_REGULAR       "printf"  , printfcmd  },
9964#endif
9965        { BUILTIN_NOSPEC        "pwd"     , pwdcmd     },
9966        { BUILTIN_REGULAR       "read"    , readcmd    },
9967        { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd  },
9968        { BUILTIN_SPEC_REG      "return"  , returncmd  },
9969        { BUILTIN_SPEC_REG      "set"     , setcmd     },
9970        { BUILTIN_SPEC_REG      "shift"   , shiftcmd   },
9971#if BASH_SOURCE
9972        { BUILTIN_SPEC_REG      "source"  , dotcmd     },
9973#endif
9974#if ENABLE_ASH_TEST
9975        { BUILTIN_REGULAR       "test"    , testcmd    },
9976#endif
9977        { BUILTIN_SPEC_REG      "times"   , timescmd   },
9978        { BUILTIN_SPEC_REG      "trap"    , trapcmd    },
9979        { BUILTIN_REGULAR       "true"    , truecmd    },
9980        { BUILTIN_NOSPEC        "type"    , typecmd    },
9981        { BUILTIN_NOSPEC        "ulimit"  , ulimitcmd  },
9982        { BUILTIN_REGULAR       "umask"   , umaskcmd   },
9983#if ENABLE_ASH_ALIAS
9984        { BUILTIN_REGULAR       "unalias" , unaliascmd },
9985#endif
9986        { BUILTIN_SPEC_REG      "unset"   , unsetcmd   },
9987        { BUILTIN_REGULAR       "wait"    , waitcmd    },
9988};
9989
9990/* Should match the above table! */
9991#define COMMANDCMD (builtintab + \
9992        /* . : */       2 + \
9993        /* [ */         1 * ENABLE_ASH_TEST + \
9994        /* [[ */        1 * BASH_TEST2 + \
9995        /* alias */     1 * ENABLE_ASH_ALIAS + \
9996        /* bg */        1 * ENABLE_ASH_JOB_CONTROL + \
9997        /* break cd cddir  */   3)
9998#define EVALCMD (COMMANDCMD + \
9999        /* command */   1 * ENABLE_ASH_CMDCMD + \
10000        /* continue */  1 + \
10001        /* echo */      1 * ENABLE_ASH_ECHO + \
10002        0)
10003#define EXECCMD (EVALCMD + \
10004        /* eval */      1)
10005
10006/*
10007 * Search the table of builtin commands.
10008 */
10009static int
10010pstrcmp1(const void *a, const void *b)
10011{
10012        return strcmp((char*)a, *(char**)b + 1);
10013}
10014static struct builtincmd *
10015find_builtin(const char *name)
10016{
10017        struct builtincmd *bp;
10018
10019        bp = bsearch(
10020                name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
10021                pstrcmp1
10022        );
10023        return bp;
10024}
10025
10026/*
10027 * Execute a simple command.
10028 */
10029static void unwindfiles(struct parsefile *stop);
10030static int
10031isassignment(const char *p)
10032{
10033        const char *q = endofname(p);
10034        if (p == q)
10035                return 0;
10036        return *q == '=';
10037}
10038static int FAST_FUNC
10039bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10040{
10041        /* Preserve exitstatus of a previous possible redirection
10042         * as POSIX mandates */
10043        return back_exitstatus;
10044}
10045static int
10046evalcommand(union node *cmd, int flags)
10047{
10048        static const struct builtincmd null_bltin = {
10049                "\0\0", bltincmd /* why three NULs? */
10050        };
10051        struct localvar_list *localvar_stop;
10052        struct parsefile *file_stop;
10053        struct redirtab *redir_stop;
10054        union node *argp;
10055        struct arglist arglist;
10056        struct arglist varlist;
10057        char **argv;
10058        int argc;
10059        const struct strlist *sp;
10060        struct cmdentry cmdentry;
10061        struct job *jp;
10062        char *lastarg;
10063        const char *path;
10064        int spclbltin;
10065        int status;
10066        char **nargv;
10067        smallint cmd_is_exec;
10068
10069        errlinno = lineno = cmd->ncmd.linno;
10070        if (funcline)
10071                lineno -= funcline - 1;
10072
10073        /* First expand the arguments. */
10074        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
10075        localvar_stop = pushlocalvars();
10076        file_stop = g_parsefile;
10077        back_exitstatus = 0;
10078
10079        cmdentry.cmdtype = CMDBUILTIN;
10080        cmdentry.u.cmd = &null_bltin;
10081        varlist.lastp = &varlist.list;
10082        *varlist.lastp = NULL;
10083        arglist.lastp = &arglist.list;
10084        *arglist.lastp = NULL;
10085
10086        argc = 0;
10087        if (cmd->ncmd.args) {
10088                struct builtincmd *bcmd;
10089                smallint pseudovarflag;
10090
10091                bcmd = find_builtin(cmd->ncmd.args->narg.text);
10092                pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
10093
10094                for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
10095                        struct strlist **spp;
10096
10097                        spp = arglist.lastp;
10098                        if (pseudovarflag && isassignment(argp->narg.text))
10099                                expandarg(argp, &arglist, EXP_VARTILDE);
10100                        else
10101                                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
10102
10103                        for (sp = *spp; sp; sp = sp->next)
10104                                argc++;
10105                }
10106        }
10107
10108        /* Reserve one extra spot at the front for shellexec. */
10109        nargv = stalloc(sizeof(char *) * (argc + 2));
10110        argv = ++nargv;
10111        for (sp = arglist.list; sp; sp = sp->next) {
10112                TRACE(("evalcommand arg: %s\n", sp->text));
10113                *nargv++ = sp->text;
10114        }
10115        *nargv = NULL;
10116
10117        lastarg = NULL;
10118        if (iflag && funcline == 0 && argc > 0)
10119                lastarg = nargv[-1];
10120
10121        expredir(cmd->ncmd.redirect);
10122        redir_stop = pushredir(cmd->ncmd.redirect);
10123        preverrout_fd = 2;
10124        if (BASH_XTRACEFD && xflag) {
10125                /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10126                 * we do not emulate this. We only use its value.
10127                 */
10128                const char *xtracefd = lookupvar("BASH_XTRACEFD");
10129                if (xtracefd && is_number(xtracefd))
10130                        preverrout_fd = atoi(xtracefd);
10131
10132        }
10133        status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10134
10135        path = vpath.var_text;
10136        for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10137                struct strlist **spp;
10138                char *p;
10139
10140                spp = varlist.lastp;
10141                expandarg(argp, &varlist, EXP_VARTILDE);
10142
10143                mklocal((*spp)->text);
10144
10145                /*
10146                 * Modify the command lookup path, if a PATH= assignment
10147                 * is present
10148                 */
10149                p = (*spp)->text;
10150                if (varcmp(p, path) == 0)
10151                        path = p;
10152        }
10153
10154        /* Print the command if xflag is set. */
10155        if (xflag) {
10156                const char *pfx = "";
10157
10158                fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
10159
10160                sp = varlist.list;
10161                while (sp) {
10162                        char *varval = sp->text;
10163                        char *eq = strchrnul(varval, '=');
10164                        if (*eq)
10165                                eq++;
10166                        fdprintf(preverrout_fd, "%s%.*s%s",
10167                                pfx,
10168                                (int)(eq - varval), varval,
10169                                maybe_single_quote(eq)
10170                        );
10171                        sp = sp->next;
10172                        pfx = " ";
10173                }
10174
10175                sp = arglist.list;
10176                while (sp) {
10177                        fdprintf(preverrout_fd, "%s%s",
10178                                pfx,
10179                                /* always quote if matches reserved word: */
10180                                findkwd(sp->text)
10181                                ? single_quote(sp->text)
10182                                : maybe_single_quote(sp->text)
10183                        );
10184                        sp = sp->next;
10185                        pfx = " ";
10186                }
10187                safe_write(preverrout_fd, "\n", 1);
10188        }
10189
10190        cmd_is_exec = 0;
10191        spclbltin = -1;
10192
10193        /* Now locate the command. */
10194        if (argc) {
10195                int cmd_flag = DO_ERR;
10196#if ENABLE_ASH_CMDCMD
10197                const char *oldpath = path + 5;
10198#endif
10199                path += 5;
10200                for (;;) {
10201                        find_command(argv[0], &cmdentry, cmd_flag, path);
10202                        if (cmdentry.cmdtype == CMDUNKNOWN) {
10203                                flush_stdout_stderr();
10204                                status = 127;
10205                                goto bail;
10206                        }
10207
10208                        /* implement bltin and command here */
10209                        if (cmdentry.cmdtype != CMDBUILTIN)
10210                                break;
10211                        if (spclbltin < 0)
10212                                spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10213                        if (cmdentry.u.cmd == EXECCMD)
10214                                cmd_is_exec = 1;
10215#if ENABLE_ASH_CMDCMD
10216                        if (cmdentry.u.cmd == COMMANDCMD) {
10217                                path = oldpath;
10218                                nargv = parse_command_args(argv, &path);
10219                                if (!nargv)
10220                                        break;
10221                                /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10222                                 * nargv => "PROG". path is updated if -p.
10223                                 */
10224                                argc -= nargv - argv;
10225                                argv = nargv;
10226                                cmd_flag |= DO_NOFUNC;
10227                        } else
10228#endif
10229                                break;
10230                }
10231        }
10232
10233        if (status) {
10234 bail:
10235                exitstatus = status;
10236
10237                /* We have a redirection error. */
10238                if (spclbltin > 0)
10239                        raise_exception(EXERROR);
10240
10241                goto out;
10242        }
10243
10244        /* Execute the command. */
10245        switch (cmdentry.cmdtype) {
10246        default: {
10247
10248#if ENABLE_FEATURE_SH_STANDALONE \
10249 && ENABLE_FEATURE_SH_NOFORK \
10250 && NUM_APPLETS > 1
10251/* (1) BUG: if variables are set, we need to fork, or save/restore them
10252 *     around run_nofork_applet() call.
10253 * (2) Should this check also be done in forkshell()?
10254 *     (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10255 */
10256                /* find_command() encodes applet_no as (-2 - applet_no) */
10257                int applet_no = (- cmdentry.u.index - 2);
10258                if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10259                        char **sv_environ;
10260
10261                        INT_OFF;
10262                        sv_environ = environ;
10263                        environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
10264                        /*
10265                         * Run <applet>_main().
10266                         * Signals (^C) can't interrupt here.
10267                         * Otherwise we can mangle stdio or malloc internal state.
10268                         * This makes applets which can run for a long time
10269                         * and/or wait for user input ineligible for NOFORK:
10270                         * for example, "yes" or "rm" (rm -i waits for input).
10271                         */
10272                        status = run_nofork_applet(applet_no, argv);
10273                        environ = sv_environ;
10274                        /*
10275                         * Try enabling NOFORK for "yes" applet.
10276                         * ^C _will_ stop it (write returns EINTR),
10277                         * but this causes stdout FILE to be stuck
10278                         * and needing clearerr(). What if other applets
10279                         * also can get EINTRs? Do we need to switch
10280                         * our signals to SA_RESTART?
10281                         */
10282                        /*clearerr(stdout);*/
10283                        INT_ON;
10284                        break;
10285                }
10286#endif
10287                /* Can we avoid forking? For example, very last command
10288                 * in a script or a subshell does not need forking,
10289                 * we can just exec it.
10290                 */
10291                if (!(flags & EV_EXIT) || may_have_traps) {
10292                        /* No, forking off a child is necessary */
10293                        INT_OFF;
10294                        get_tty_state();
10295                        jp = makejob(/*cmd,*/ 1);
10296                        if (forkshell(jp, cmd, FORK_FG) != 0) {
10297                                /* parent */
10298                                status = waitforjob(jp);
10299                                INT_ON;
10300                                TRACE(("forked child exited with %d\n", status));
10301                                break;
10302                        }
10303                        /* child */
10304                        FORCE_INT_ON;
10305                        /* fall through to exec'ing external program */
10306                }
10307                listsetvar(varlist.list, VEXPORT|VSTACK);
10308                shellexec(argv[0], argv, path, cmdentry.u.index);
10309                /* NOTREACHED */
10310        } /* default */
10311        case CMDBUILTIN:
10312                if (spclbltin > 0 || argc == 0) {
10313                        poplocalvars(1);
10314                        if (cmd_is_exec && argc > 1)
10315                                listsetvar(varlist.list, VEXPORT);
10316                }
10317
10318                /* Tight loop with builtins only:
10319                 * "while kill -0 $child; do true; done"
10320                 * will never exit even if $child died, unless we do this
10321                 * to reap the zombie and make kill detect that it's gone: */
10322                dowait(DOWAIT_NONBLOCK, NULL);
10323
10324                if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
10325                        if (exception_type == EXERROR && spclbltin <= 0) {
10326                                FORCE_INT_ON;
10327                                goto readstatus;
10328                        }
10329 raise:
10330                        longjmp(exception_handler->loc, 1);
10331                }
10332                goto readstatus;
10333
10334        case CMDFUNCTION:
10335                /* See above for the rationale */
10336                dowait(DOWAIT_NONBLOCK, NULL);
10337                if (evalfun(cmdentry.u.func, argc, argv, flags))
10338                        goto raise;
10339 readstatus:
10340                status = exitstatus;
10341                break;
10342        } /* switch */
10343
10344 out:
10345        if (cmd->ncmd.redirect)
10346                popredir(/*drop:*/ cmd_is_exec);
10347        unwindredir(redir_stop);
10348        unwindfiles(file_stop);
10349        unwindlocalvars(localvar_stop);
10350        if (lastarg) {
10351                /* dsl: I think this is intended to be used to support
10352                 * '_' in 'vi' command mode during line editing...
10353                 * However I implemented that within libedit itself.
10354                 */
10355                setvar0("_", lastarg);
10356        }
10357
10358        return status;
10359}
10360
10361static int
10362evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
10363{
10364        char *volatile savecmdname;
10365        struct jmploc *volatile savehandler;
10366        struct jmploc jmploc;
10367        int status;
10368        int i;
10369
10370        savecmdname = commandname;
10371        savehandler = exception_handler;
10372        i = setjmp(jmploc.loc);
10373        if (i)
10374                goto cmddone;
10375        exception_handler = &jmploc;
10376        commandname = argv[0];
10377        argptr = argv + 1;
10378        optptr = NULL;                  /* initialize nextopt */
10379        if (cmd == EVALCMD)
10380                status = evalcmd(argc, argv, flags);
10381        else
10382                status = (*cmd->builtin)(argc, argv);
10383        flush_stdout_stderr();
10384        status |= ferror(stdout);
10385        exitstatus = status;
10386 cmddone:
10387        clearerr(stdout);
10388        commandname = savecmdname;
10389        exception_handler = savehandler;
10390
10391        return i;
10392}
10393
10394static int
10395goodname(const char *p)
10396{
10397        return endofname(p)[0] == '\0';
10398}
10399
10400
10401/*
10402 * Search for a command.  This is called before we fork so that the
10403 * location of the command will be available in the parent as well as
10404 * the child.  The check for "goodname" is an overly conservative
10405 * check that the name will not be subject to expansion.
10406 */
10407static void
10408prehash(union node *n)
10409{
10410        struct cmdentry entry;
10411
10412        if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10413                find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
10414}
10415
10416
10417/* ============ Builtin commands
10418 *
10419 * Builtin commands whose functions are closely tied to evaluation
10420 * are implemented here.
10421 */
10422
10423/*
10424 * Handle break and continue commands.  Break, continue, and return are
10425 * all handled by setting the evalskip flag.  The evaluation routines
10426 * above all check this flag, and if it is set they start skipping
10427 * commands rather than executing them.  The variable skipcount is
10428 * the number of loops to break/continue, or the number of function
10429 * levels to return.  (The latter is always 1.)  It should probably
10430 * be an error to break out of more loops than exist, but it isn't
10431 * in the standard shell so we don't make it one here.
10432 */
10433static int FAST_FUNC
10434breakcmd(int argc UNUSED_PARAM, char **argv)
10435{
10436        int n = argv[1] ? number(argv[1]) : 1;
10437
10438        if (n <= 0)
10439                ash_msg_and_raise_error(msg_illnum, argv[1]);
10440        if (n > loopnest)
10441                n = loopnest;
10442        if (n > 0) {
10443                evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
10444                skipcount = n;
10445        }
10446        return 0;
10447}
10448
10449
10450/*
10451 * This implements the input routines used by the parser.
10452 */
10453
10454enum {
10455        INPUT_PUSH_FILE = 1,
10456        INPUT_NOFILE_OK = 2,
10457};
10458
10459static smallint checkkwd;
10460/* values of checkkwd variable */
10461#define CHKALIAS        0x1
10462#define CHKKWD          0x2
10463#define CHKNL           0x4
10464#define CHKEOFMARK      0x8
10465
10466/*
10467 * Push a string back onto the input at this current parsefile level.
10468 * We handle aliases this way.
10469 */
10470#if !ENABLE_ASH_ALIAS
10471#define pushstring(s, ap) pushstring(s)
10472#endif
10473static void
10474pushstring(char *s, struct alias *ap)
10475{
10476        struct strpush *sp;
10477        int len;
10478
10479        len = strlen(s);
10480        INT_OFF;
10481        if (g_parsefile->strpush) {
10482                sp = ckzalloc(sizeof(*sp));
10483                sp->prev = g_parsefile->strpush;
10484        } else {
10485                sp = &(g_parsefile->basestrpush);
10486        }
10487        g_parsefile->strpush = sp;
10488        sp->prev_string = g_parsefile->next_to_pgetc;
10489        sp->prev_left_in_line = g_parsefile->left_in_line;
10490        sp->unget = g_parsefile->unget;
10491        memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
10492#if ENABLE_ASH_ALIAS
10493        sp->ap = ap;
10494        if (ap) {
10495                ap->flag |= ALIASINUSE;
10496                sp->string = s;
10497        }
10498#endif
10499        g_parsefile->next_to_pgetc = s;
10500        g_parsefile->left_in_line = len;
10501        g_parsefile->unget = 0;
10502        INT_ON;
10503}
10504
10505static void
10506popstring(void)
10507{
10508        struct strpush *sp = g_parsefile->strpush;
10509
10510        INT_OFF;
10511#if ENABLE_ASH_ALIAS
10512        if (sp->ap) {
10513                if (g_parsefile->next_to_pgetc[-1] == ' '
10514                 || g_parsefile->next_to_pgetc[-1] == '\t'
10515                ) {
10516                        checkkwd |= CHKALIAS;
10517                }
10518                if (sp->string != sp->ap->val) {
10519                        free(sp->string);
10520                }
10521                sp->ap->flag &= ~ALIASINUSE;
10522                if (sp->ap->flag & ALIASDEAD) {
10523                        unalias(sp->ap->name);
10524                }
10525        }
10526#endif
10527        g_parsefile->next_to_pgetc = sp->prev_string;
10528        g_parsefile->left_in_line = sp->prev_left_in_line;
10529        g_parsefile->unget = sp->unget;
10530        memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
10531        g_parsefile->strpush = sp->prev;
10532        if (sp != &(g_parsefile->basestrpush))
10533                free(sp);
10534        INT_ON;
10535}
10536
10537static int
10538preadfd(void)
10539{
10540        int nr;
10541        char *buf = g_parsefile->buf;
10542
10543        g_parsefile->next_to_pgetc = buf;
10544#if ENABLE_FEATURE_EDITING
10545 retry:
10546        if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10547                nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10548        else {
10549# if ENABLE_ASH_IDLE_TIMEOUT
10550                int timeout = -1;
10551                const char *tmout_var = lookupvar("TMOUT");
10552                if (tmout_var) {
10553                        timeout = atoi(tmout_var) * 1000;
10554                        if (timeout <= 0)
10555                                timeout = -1;
10556                }
10557                line_input_state->timeout = timeout;
10558# endif
10559# if ENABLE_FEATURE_TAB_COMPLETION
10560                line_input_state->path_lookup = pathval();
10561# endif
10562                reinit_unicode_for_ash();
10563                nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10564                if (nr == 0) {
10565                        /* ^C pressed, "convert" to SIGINT */
10566                        write(STDOUT_FILENO, "^C", 2);
10567                        if (trap[SIGINT]) {
10568                                buf[0] = '\n';
10569                                buf[1] = '\0';
10570                                raise(SIGINT);
10571                                return 1;
10572                        }
10573                        exitstatus = 128 + SIGINT;
10574                        bb_putchar('\n');
10575                        goto retry;
10576                }
10577                if (nr < 0) {
10578                        if (errno == 0) {
10579                                /* Ctrl+D pressed */
10580                                nr = 0;
10581                        }
10582# if ENABLE_ASH_IDLE_TIMEOUT
10583                        else if (errno == EAGAIN && timeout > 0) {
10584                                puts("\007timed out waiting for input: auto-logout");
10585                                exitshell();
10586                        }
10587# endif
10588                }
10589        }
10590#else
10591        nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10592#endif
10593
10594#if 0 /* disabled: nonblock_immune_read() handles this problem */
10595        if (nr < 0) {
10596                if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10597                        int flags = fcntl(0, F_GETFL);
10598                        if (flags >= 0 && (flags & O_NONBLOCK)) {
10599                                flags &= ~O_NONBLOCK;
10600                                if (fcntl(0, F_SETFL, flags) >= 0) {
10601                                        out2str("sh: turning off NDELAY mode\n");
10602                                        goto retry;
10603                                }
10604                        }
10605                }
10606        }
10607#endif
10608        return nr;
10609}
10610
10611/*
10612 * Refill the input buffer and return the next input character:
10613 *
10614 * 1) If a string was pushed back on the input, pop it;
10615 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10616 *    or we are reading from a string so we can't refill the buffer,
10617 *    return EOF.
10618 * 3) If there is more stuff in this buffer, use it else call read to fill it.
10619 * 4) Process input up to the next newline, deleting nul characters.
10620 */
10621//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10622#define pgetc_debug(...) ((void)0)
10623static int pgetc(void);
10624static int
10625preadbuffer(void)
10626{
10627        char *q;
10628        int more;
10629
10630        if (g_parsefile->strpush) {
10631#if ENABLE_ASH_ALIAS
10632                if (g_parsefile->left_in_line == -1
10633                 && g_parsefile->strpush->ap
10634                 && g_parsefile->next_to_pgetc[-1] != ' '
10635                 && g_parsefile->next_to_pgetc[-1] != '\t'
10636                ) {
10637                        pgetc_debug("preadbuffer PEOA");
10638                        return PEOA;
10639                }
10640#endif
10641                popstring();
10642                return pgetc();
10643        }
10644        /* on both branches above g_parsefile->left_in_line < 0.
10645         * "pgetc" needs refilling.
10646         */
10647
10648        /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
10649         * pungetc() may increment it a few times.
10650         * Assuming it won't increment it to less than -90.
10651         */
10652        if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
10653                pgetc_debug("preadbuffer PEOF1");
10654                /* even in failure keep left_in_line and next_to_pgetc
10655                 * in lock step, for correct multi-layer pungetc.
10656                 * left_in_line was decremented before preadbuffer(),
10657                 * must inc next_to_pgetc: */
10658                g_parsefile->next_to_pgetc++;
10659                return PEOF;
10660        }
10661
10662        more = g_parsefile->left_in_buffer;
10663        if (more <= 0) {
10664                flush_stdout_stderr();
10665 again:
10666                more = preadfd();
10667                if (more <= 0) {
10668                        /* don't try reading again */
10669                        g_parsefile->left_in_line = -99;
10670                        pgetc_debug("preadbuffer PEOF2");
10671                        g_parsefile->next_to_pgetc++;
10672                        return PEOF;
10673                }
10674        }
10675
10676        /* Find out where's the end of line.
10677         * Set g_parsefile->left_in_line
10678         * and g_parsefile->left_in_buffer acordingly.
10679         * NUL chars are deleted.
10680         */
10681        q = g_parsefile->next_to_pgetc;
10682        for (;;) {
10683                char c;
10684
10685                more--;
10686
10687                c = *q;
10688                if (c == '\0') {
10689                        memmove(q, q + 1, more);
10690                } else {
10691                        q++;
10692                        if (c == '\n') {
10693                                g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10694                                break;
10695                        }
10696                }
10697
10698                if (more <= 0) {
10699                        g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10700                        if (g_parsefile->left_in_line < 0)
10701                                goto again;
10702                        break;
10703                }
10704        }
10705        g_parsefile->left_in_buffer = more;
10706
10707        if (vflag) {
10708                char save = *q;
10709                *q = '\0';
10710                out2str(g_parsefile->next_to_pgetc);
10711                *q = save;
10712        }
10713
10714        pgetc_debug("preadbuffer at %d:%p'%s'",
10715                        g_parsefile->left_in_line,
10716                        g_parsefile->next_to_pgetc,
10717                        g_parsefile->next_to_pgetc);
10718        return (unsigned char)*g_parsefile->next_to_pgetc++;
10719}
10720
10721static void
10722nlprompt(void)
10723{
10724        g_parsefile->linno++;
10725        setprompt_if(doprompt, 2);
10726}
10727static void
10728nlnoprompt(void)
10729{
10730        g_parsefile->linno++;
10731        needprompt = doprompt;
10732}
10733
10734static int
10735pgetc(void)
10736{
10737        int c;
10738
10739        pgetc_debug("pgetc at %d:%p'%s'",
10740                        g_parsefile->left_in_line,
10741                        g_parsefile->next_to_pgetc,
10742                        g_parsefile->next_to_pgetc);
10743        if (g_parsefile->unget)
10744                return g_parsefile->lastc[--g_parsefile->unget];
10745
10746        if (--g_parsefile->left_in_line >= 0)
10747                c = (unsigned char)*g_parsefile->next_to_pgetc++;
10748        else
10749                c = preadbuffer();
10750
10751        g_parsefile->lastc[1] = g_parsefile->lastc[0];
10752        g_parsefile->lastc[0] = c;
10753
10754        return c;
10755}
10756
10757#if ENABLE_ASH_ALIAS
10758static int
10759pgetc_without_PEOA(void)
10760{
10761        int c;
10762        do {
10763                pgetc_debug("pgetc at %d:%p'%s'",
10764                                g_parsefile->left_in_line,
10765                                g_parsefile->next_to_pgetc,
10766                                g_parsefile->next_to_pgetc);
10767                c = pgetc();
10768        } while (c == PEOA);
10769        return c;
10770}
10771#else
10772# define pgetc_without_PEOA() pgetc()
10773#endif
10774
10775/*
10776 * Undo a call to pgetc.  Only two characters may be pushed back.
10777 * PEOF may be pushed back.
10778 */
10779static void
10780pungetc(void)
10781{
10782        g_parsefile->unget++;
10783}
10784
10785/* This one eats backslash+newline */
10786static int
10787pgetc_eatbnl(void)
10788{
10789        int c;
10790
10791        while ((c = pgetc()) == '\\') {
10792                if (pgetc() != '\n') {
10793                        pungetc();
10794                        break;
10795                }
10796
10797                nlprompt();
10798        }
10799
10800        return c;
10801}
10802
10803struct synstack {
10804        smalluint syntax;
10805        uint8_t innerdq   :1;
10806        uint8_t varpushed :1;
10807        uint8_t dblquote  :1;
10808        int varnest;            /* levels of variables expansion */
10809        int dqvarnest;          /* levels of variables expansion within double quotes */
10810        int parenlevel;         /* levels of parens in arithmetic */
10811        struct synstack *prev;
10812        struct synstack *next;
10813};
10814
10815static void
10816synstack_push(struct synstack **stack, struct synstack *next, int syntax)
10817{
10818        memset(next, 0, sizeof(*next));
10819        next->syntax = syntax;
10820        next->next = *stack;
10821        (*stack)->prev = next;
10822        *stack = next;
10823}
10824
10825static ALWAYS_INLINE void
10826synstack_pop(struct synstack **stack)
10827{
10828        *stack = (*stack)->next;
10829}
10830
10831/*
10832 * To handle the "." command, a stack of input files is used.  Pushfile
10833 * adds a new entry to the stack and popfile restores the previous level.
10834 */
10835static void
10836pushfile(void)
10837{
10838        struct parsefile *pf;
10839
10840        pf = ckzalloc(sizeof(*pf));
10841        pf->prev = g_parsefile;
10842        pf->pf_fd = -1;
10843        /*pf->strpush = NULL; - ckzalloc did it */
10844        /*pf->basestrpush.prev = NULL;*/
10845        /*pf->unget = 0;*/
10846        g_parsefile = pf;
10847}
10848
10849static void
10850popfile(void)
10851{
10852        struct parsefile *pf = g_parsefile;
10853
10854        if (pf == &basepf)
10855                return;
10856
10857        INT_OFF;
10858        if (pf->pf_fd >= 0)
10859                close(pf->pf_fd);
10860        free(pf->buf);
10861        while (pf->strpush)
10862                popstring();
10863        g_parsefile = pf->prev;
10864        free(pf);
10865        INT_ON;
10866}
10867
10868static void
10869unwindfiles(struct parsefile *stop)
10870{
10871        while (g_parsefile != stop)
10872                popfile();
10873}
10874
10875/*
10876 * Return to top level.
10877 */
10878static void
10879popallfiles(void)
10880{
10881        unwindfiles(&basepf);
10882}
10883
10884/*
10885 * Close the file(s) that the shell is reading commands from.  Called
10886 * after a fork is done.
10887 */
10888static void
10889closescript(void)
10890{
10891        popallfiles();
10892        if (g_parsefile->pf_fd > 0) {
10893                close(g_parsefile->pf_fd);
10894                g_parsefile->pf_fd = 0;
10895        }
10896}
10897
10898/*
10899 * Like setinputfile, but takes an open file descriptor.  Call this with
10900 * interrupts off.
10901 */
10902static void
10903setinputfd(int fd, int push)
10904{
10905        if (push) {
10906                pushfile();
10907                g_parsefile->buf = NULL;
10908        }
10909        g_parsefile->pf_fd = fd;
10910        if (g_parsefile->buf == NULL)
10911                g_parsefile->buf = ckmalloc(IBUFSIZ);
10912        g_parsefile->left_in_buffer = 0;
10913        g_parsefile->left_in_line = 0;
10914        g_parsefile->linno = 1;
10915}
10916
10917/*
10918 * Set the input to take input from a file.  If push is set, push the
10919 * old input onto the stack first.
10920 */
10921static int
10922setinputfile(const char *fname, int flags)
10923{
10924        int fd;
10925
10926        INT_OFF;
10927        fd = open(fname, O_RDONLY | O_CLOEXEC);
10928        if (fd < 0) {
10929                if (flags & INPUT_NOFILE_OK)
10930                        goto out;
10931                exitstatus = 127;
10932                ash_msg_and_raise_perror("can't open '%s'", fname);
10933        }
10934        if (fd < 10)
10935                fd = savefd(fd);
10936        else if (O_CLOEXEC == 0) /* old libc */
10937                close_on_exec_on(fd);
10938
10939        setinputfd(fd, flags & INPUT_PUSH_FILE);
10940 out:
10941        INT_ON;
10942        return fd;
10943}
10944
10945/*
10946 * Like setinputfile, but takes input from a string.
10947 */
10948static void
10949setinputstring(char *string)
10950{
10951        INT_OFF;
10952        pushfile();
10953        g_parsefile->next_to_pgetc = string;
10954        g_parsefile->left_in_line = strlen(string);
10955        g_parsefile->buf = NULL;
10956        g_parsefile->linno = 1;
10957        INT_ON;
10958}
10959
10960
10961/*
10962 * Routines to check for mail.
10963 */
10964
10965#if ENABLE_ASH_MAIL
10966
10967/* Hash of mtimes of mailboxes */
10968static unsigned mailtime_hash;
10969/* Set if MAIL or MAILPATH is changed. */
10970static smallint mail_var_path_changed;
10971
10972/*
10973 * Print appropriate message(s) if mail has arrived.
10974 * If mail_var_path_changed is set,
10975 * then the value of MAIL has mail_var_path_changed,
10976 * so we just update the values.
10977 */
10978static void
10979chkmail(void)
10980{
10981        const char *mpath;
10982        char *p;
10983        char *q;
10984        unsigned new_hash;
10985        struct stackmark smark;
10986        struct stat statb;
10987
10988        setstackmark(&smark);
10989        mpath = mpathset() ? mpathval() : mailval();
10990        new_hash = 0;
10991        for (;;) {
10992                p = path_advance(&mpath, nullstr);
10993                if (p == NULL)
10994                        break;
10995                if (*p == '\0')
10996                        continue;
10997                for (q = p; *q; q++)
10998                        continue;
10999#if DEBUG
11000                if (q[-1] != '/')
11001                        abort();
11002#endif
11003                q[-1] = '\0';                   /* delete trailing '/' */
11004                if (stat(p, &statb) < 0) {
11005                        continue;
11006                }
11007                /* Very simplistic "hash": just a sum of all mtimes */
11008                new_hash += (unsigned)statb.st_mtime;
11009        }
11010        if (!mail_var_path_changed && mailtime_hash != new_hash) {
11011                if (mailtime_hash != 0)
11012                        out2str("you have mail\n");
11013                mailtime_hash = new_hash;
11014        }
11015        mail_var_path_changed = 0;
11016        popstackmark(&smark);
11017}
11018
11019static void FAST_FUNC
11020changemail(const char *val UNUSED_PARAM)
11021{
11022        mail_var_path_changed = 1;
11023}
11024
11025#endif /* ASH_MAIL */
11026
11027
11028/* ============ ??? */
11029
11030/*
11031 * Set the shell parameters.
11032 */
11033static void
11034setparam(char **argv)
11035{
11036        char **newparam;
11037        char **ap;
11038        int nparam;
11039
11040        for (nparam = 0; argv[nparam]; nparam++)
11041                continue;
11042        ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
11043        while (*argv) {
11044                *ap++ = ckstrdup(*argv++);
11045        }
11046        *ap = NULL;
11047        freeparam(&shellparam);
11048        shellparam.malloced = 1;
11049        shellparam.nparam = nparam;
11050        shellparam.p = newparam;
11051#if ENABLE_ASH_GETOPTS
11052        shellparam.optind = 1;
11053        shellparam.optoff = -1;
11054#endif
11055}
11056
11057/*
11058 * Process shell options.  The global variable argptr contains a pointer
11059 * to the argument list; we advance it past the options.
11060 *
11061 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
11062 * For a non-interactive shell, an error condition encountered
11063 * by a special built-in ... shall cause the shell to write a diagnostic message
11064 * to standard error and exit as shown in the following table:
11065 * Error                                           Special Built-In
11066 * ...
11067 * Utility syntax error (option or operand error)  Shall exit
11068 * ...
11069 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
11070 * we see that bash does not do that (set "finishes" with error code 1 instead,
11071 * and shell continues), and people rely on this behavior!
11072 * Testcase:
11073 * set -o barfoo 2>/dev/null
11074 * echo $?
11075 *
11076 * Oh well. Let's mimic that.
11077 */
11078static int
11079plus_minus_o(char *name, int val)
11080{
11081        int i;
11082
11083        if (name) {
11084                for (i = 0; i < NOPTS; i++) {
11085                        if (strcmp(name, optnames(i)) == 0) {
11086                                optlist[i] = val;
11087                                return 0;
11088                        }
11089                }
11090                ash_msg("illegal option %co %s", val ? '-' : '+', name);
11091                return 1;
11092        }
11093        for (i = 0; i < NOPTS; i++) {
11094                if (optnames(i)[0] == '\0')
11095                        continue;
11096                if (val) {
11097                        out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11098                } else {
11099                        out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11100                }
11101        }
11102        return 0;
11103}
11104static void
11105setoption(int flag, int val)
11106{
11107        int i;
11108
11109        for (i = 0; i < NOPTS; i++) {
11110                if (optletters(i) == flag && optnames(i)[0] != '\0') {
11111                        optlist[i] = val;
11112                        return;
11113                }
11114        }
11115        ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
11116        /* NOTREACHED */
11117}
11118/* If login_sh is not NULL, we are called to parse command line opts,
11119 * not "set -opts"
11120 */
11121static int
11122options(int *login_sh)
11123{
11124        char *p;
11125        int val;
11126        int c;
11127
11128        if (login_sh)
11129                minusc = NULL;
11130        while ((p = *argptr) != NULL) {
11131                c = *p++;
11132                if (c != '-' && c != '+')
11133                        break;
11134                argptr++;
11135                val = 0; /* val = 0 if c == '+' */
11136                if (c == '-') {
11137                        val = 1;
11138                        if (p[0] == '\0' || LONE_DASH(p)) {
11139                                if (!login_sh) {
11140                                        /* "-" means turn off -x and -v */
11141                                        if (p[0] == '\0')
11142                                                xflag = vflag = 0;
11143                                        /* "--" means reset params */
11144                                        else if (*argptr == NULL)
11145                                                setparam(argptr);
11146                                }
11147                                break;    /* "-" or "--" terminates options */
11148                        }
11149                }
11150                /* first char was + or - */
11151                while ((c = *p++) != '\0') {
11152                        if (login_sh) {
11153                                /* bash 3.2 indeed handles -c CMD and +c CMD the same */
11154                                if (c == 'c') {
11155                                        minusc = p; /* command is after shell args */
11156                                        cflag = 1;
11157                                        continue;
11158                                }
11159                                if (c == 's') { /* -s, +s */
11160                                        sflag = 1;
11161                                        continue;
11162                                }
11163                                if (c == 'i') { /* -i, +i */
11164                                        iflag = 1;
11165                                        continue;
11166                                }
11167                                if (c == 'l') {
11168                                        *login_sh = 1; /* -l or +l == --login */
11169                                        continue;
11170                                }
11171                                /* bash does not accept +-login, we also won't */
11172                                if (val && (c == '-')) { /* long options */
11173                                        if (strcmp(p, "login") == 0) {
11174                                                *login_sh = 1;
11175                                        }
11176                                        break;
11177                                }
11178                        }
11179                        if (c == 'o') {
11180                                if (plus_minus_o(*argptr, val)) {
11181                                        /* it already printed err message */
11182                                        return 1; /* error */
11183                                }
11184                                if (*argptr)
11185                                        argptr++;
11186                        } else {
11187                                setoption(c, val);
11188                        }
11189                }
11190        }
11191        return 0;
11192}
11193
11194/*
11195 * The shift builtin command.
11196 */
11197static int FAST_FUNC
11198shiftcmd(int argc UNUSED_PARAM, char **argv)
11199{
11200        int n;
11201        char **ap1, **ap2;
11202
11203        n = 1;
11204        if (argv[1])
11205                n = number(argv[1]);
11206        if (n > shellparam.nparam)
11207                return 1;
11208        INT_OFF;
11209        shellparam.nparam -= n;
11210        for (ap1 = shellparam.p; --n >= 0; ap1++) {
11211                if (shellparam.malloced)
11212                        free(*ap1);
11213        }
11214        ap2 = shellparam.p;
11215        while ((*ap2++ = *ap1++) != NULL)
11216                continue;
11217#if ENABLE_ASH_GETOPTS
11218        shellparam.optind = 1;
11219        shellparam.optoff = -1;
11220#endif
11221        INT_ON;
11222        return 0;
11223}
11224
11225/*
11226 * POSIX requires that 'set' (but not export or readonly) output the
11227 * variables in lexicographic order - by the locale's collating order (sigh).
11228 * Maybe we could keep them in an ordered balanced binary tree
11229 * instead of hashed lists.
11230 * For now just roll 'em through qsort for printing...
11231 */
11232static int
11233showvars(const char *sep_prefix, int on, int off)
11234{
11235        const char *sep;
11236        char **ep, **epend;
11237
11238        ep = listvars(on, off, /*strlist:*/ NULL, &epend);
11239        qsort(ep, epend - ep, sizeof(char *), vpcmp);
11240
11241        sep = *sep_prefix ? " " : sep_prefix;
11242
11243        for (; ep < epend; ep++) {
11244                const char *p;
11245                const char *q;
11246
11247                p = endofname(*ep);
11248/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11249 * makes "export -p" to have output not suitable for "eval":
11250 * import os
11251 * os.environ["test-test"]="test"
11252 * if os.fork() == 0:
11253 *   os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ])  # fixes this
11254 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11255 */
11256                q = nullstr;
11257                if (*p == '=')
11258                        q = single_quote(++p);
11259                out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11260        }
11261        return 0;
11262}
11263
11264/*
11265 * The set command builtin.
11266 */
11267static int FAST_FUNC
11268setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11269{
11270        int retval;
11271
11272        if (!argv[1])
11273                return showvars(nullstr, 0, VUNSET);
11274
11275        INT_OFF;
11276        retval = options(/*login_sh:*/ NULL);
11277        if (retval == 0) { /* if no parse error... */
11278                optschanged();
11279                if (*argptr != NULL) {
11280                        setparam(argptr);
11281                }
11282        }
11283        INT_ON;
11284        return retval;
11285}
11286
11287#if ENABLE_ASH_RANDOM_SUPPORT
11288static void FAST_FUNC
11289change_random(const char *value)
11290{
11291        uint32_t t;
11292
11293        if (value == NULL) {
11294                /* "get", generate */
11295                t = next_random(&random_gen);
11296                /* set without recursion */
11297                setvar(vrandom.var_text, utoa(t), VNOFUNC);
11298                vrandom.flags &= ~VNOFUNC;
11299        } else {
11300                /* set/reset */
11301                t = strtoul(value, NULL, 10);
11302                INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
11303        }
11304}
11305#endif
11306
11307#if BASH_EPOCH_VARS
11308static void FAST_FUNC
11309change_epoch(struct var *vepoch, const char *fmt)
11310{
11311        struct timeval tv;
11312        char buffer[sizeof("%lu.nnnnnn") + sizeof(long)*3];
11313
11314        gettimeofday(&tv, NULL);
11315        sprintf(buffer, fmt, (unsigned long)tv.tv_sec, (unsigned)tv.tv_usec);
11316        setvar(vepoch->var_text, buffer, VNOFUNC);
11317        vepoch->flags &= ~VNOFUNC;
11318}
11319
11320static void FAST_FUNC
11321change_seconds(const char *value UNUSED_PARAM)
11322{
11323        change_epoch(&vepochs, "%lu");
11324}
11325
11326static void FAST_FUNC
11327change_realtime(const char *value UNUSED_PARAM)
11328{
11329        change_epoch(&vepochr, "%lu.%06u");
11330}
11331#endif
11332
11333#if ENABLE_ASH_GETOPTS
11334static int
11335getopts(char *optstr, char *optvar, char **optfirst)
11336{
11337        char *p, *q;
11338        char c = '?';
11339        int done = 0;
11340        char sbuf[2];
11341        char **optnext;
11342        int ind = shellparam.optind;
11343        int off = shellparam.optoff;
11344
11345        sbuf[1] = '\0';
11346
11347        shellparam.optind = -1;
11348        optnext = optfirst + ind - 1;
11349
11350        if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
11351                p = NULL;
11352        else
11353                p = optnext[-1] + off;
11354        if (p == NULL || *p == '\0') {
11355                /* Current word is done, advance */
11356                p = *optnext;
11357                if (p == NULL || *p != '-' || *++p == '\0') {
11358 atend:
11359                        unsetvar("OPTARG");
11360                        p = NULL;
11361                        done = 1;
11362                        goto out;
11363                }
11364                optnext++;
11365                if (LONE_DASH(p))        /* check for "--" */
11366                        goto atend;
11367        }
11368
11369        c = *p++;
11370        for (q = optstr; *q != c;) {
11371                if (*q == '\0') {
11372                        /* OPTERR is a bashism */
11373                        const char *cp = lookupvar("OPTERR");
11374                        if ((cp && LONE_CHAR(cp, '0'))
11375                         || (optstr[0] == ':')
11376                        ) {
11377                                sbuf[0] = c;
11378                                /*sbuf[1] = '\0'; - already is */
11379                                setvar0("OPTARG", sbuf);
11380                        } else {
11381                                fprintf(stderr, "Illegal option -%c\n", c);
11382                                unsetvar("OPTARG");
11383                        }
11384                        c = '?';
11385                        goto out;
11386                }
11387                if (*++q == ':')
11388                        q++;
11389        }
11390
11391        if (*++q == ':') {
11392                if (*p == '\0' && (p = *optnext) == NULL) {
11393                        /* OPTERR is a bashism */
11394                        const char *cp = lookupvar("OPTERR");
11395                        if ((cp && LONE_CHAR(cp, '0'))
11396                         || (optstr[0] == ':')
11397                        ) {
11398                                sbuf[0] = c;
11399                                /*sbuf[1] = '\0'; - already is */
11400                                setvar0("OPTARG", sbuf);
11401                                c = ':';
11402                        } else {
11403                                fprintf(stderr, "No arg for -%c option\n", c);
11404                                unsetvar("OPTARG");
11405                                c = '?';
11406                        }
11407                        goto out;
11408                }
11409
11410                if (p == *optnext)
11411                        optnext++;
11412                setvar0("OPTARG", p);
11413                p = NULL;
11414        } else
11415                setvar0("OPTARG", nullstr);
11416 out:
11417        ind = optnext - optfirst + 1;
11418        setvar("OPTIND", itoa(ind), VNOFUNC);
11419        sbuf[0] = c;
11420        /*sbuf[1] = '\0'; - already is */
11421        setvar0(optvar, sbuf);
11422
11423        shellparam.optoff = p ? p - *(optnext - 1) : -1;
11424        shellparam.optind = ind;
11425
11426        return done;
11427}
11428
11429/*
11430 * The getopts builtin.  Shellparam.optnext points to the next argument
11431 * to be processed.  Shellparam.optptr points to the next character to
11432 * be processed in the current argument.  If shellparam.optnext is NULL,
11433 * then it's the first time getopts has been called.
11434 */
11435static int FAST_FUNC
11436getoptscmd(int argc, char **argv)
11437{
11438        char **optbase;
11439
11440        if (argc < 3)
11441                ash_msg_and_raise_error("usage: getopts optstring var [arg]");
11442        if (argc == 3) {
11443                optbase = shellparam.p;
11444                if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
11445                        shellparam.optind = 1;
11446                        shellparam.optoff = -1;
11447                }
11448        } else {
11449                optbase = &argv[3];
11450                if ((unsigned)shellparam.optind > argc - 2) {
11451                        shellparam.optind = 1;
11452                        shellparam.optoff = -1;
11453                }
11454        }
11455
11456        return getopts(argv[1], argv[2], optbase);
11457}
11458#endif /* ASH_GETOPTS */
11459
11460
11461/* ============ Shell parser */
11462
11463struct heredoc {
11464        struct heredoc *next;   /* next here document in list */
11465        union node *here;       /* redirection node */
11466        char *eofmark;          /* string indicating end of input */
11467        smallint striptabs;     /* if set, strip leading tabs */
11468};
11469
11470static smallint tokpushback;           /* last token pushed back */
11471static smallint quoteflag;             /* set if (part of) last token was quoted */
11472static token_id_t lasttoken;           /* last token read (integer id Txxx) */
11473static struct heredoc *heredoclist;    /* list of here documents to read */
11474static char *wordtext;                 /* text of last word returned by readtoken */
11475static struct nodelist *backquotelist;
11476static union node *redirnode;
11477static struct heredoc *heredoc;
11478
11479static const char *
11480tokname(char *buf, int tok)
11481{
11482        if (tok < TSEMI)
11483                return tokname_array[tok];
11484        sprintf(buf, "\"%s\"", tokname_array[tok]);
11485        return buf;
11486}
11487
11488/* raise_error_unexpected_syntax:
11489 * Called when an unexpected token is read during the parse.  The argument
11490 * is the token that is expected, or -1 if more than one type of token can
11491 * occur at this point.
11492 */
11493static void raise_error_unexpected_syntax(int) NORETURN;
11494static void
11495raise_error_unexpected_syntax(int token)
11496{
11497        char msg[64];
11498        char buf[16];
11499        int l;
11500
11501        l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
11502        if (token >= 0)
11503                sprintf(msg + l, " (expecting %s)", tokname(buf, token));
11504        raise_error_syntax(msg);
11505        /* NOTREACHED */
11506}
11507
11508/* parsing is heavily cross-recursive, need these forward decls */
11509static union node *andor(void);
11510static union node *pipeline(void);
11511static union node *parse_command(void);
11512static void parseheredoc(void);
11513static int peektoken(void);
11514static int readtoken(void);
11515
11516static union node *
11517list(int nlflag)
11518{
11519        union node *n1, *n2, *n3;
11520        int tok;
11521
11522        n1 = NULL;
11523        for (;;) {
11524                switch (peektoken()) {
11525                case TNL:
11526                        if (!(nlflag & 1))
11527                                break;
11528                        parseheredoc();
11529                        return n1;
11530
11531                case TEOF:
11532                        if (!n1 && (nlflag & 1))
11533                                n1 = NODE_EOF;
11534                        parseheredoc();
11535                        return n1;
11536                }
11537
11538                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11539                if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
11540                        return n1;
11541                nlflag |= 2;
11542
11543                n2 = andor();
11544                tok = readtoken();
11545                if (tok == TBACKGND) {
11546                        if (n2->type == NPIPE) {
11547                                n2->npipe.pipe_backgnd = 1;
11548                        } else {
11549                                if (n2->type != NREDIR) {
11550                                        n3 = stzalloc(sizeof(struct nredir));
11551                                        n3->nredir.n = n2;
11552                                        /*n3->nredir.redirect = NULL; - stzalloc did it */
11553                                        n2 = n3;
11554                                }
11555                                n2->type = NBACKGND;
11556                        }
11557                }
11558                if (n1 == NULL) {
11559                        n1 = n2;
11560                } else {
11561                        n3 = stzalloc(sizeof(struct nbinary));
11562                        n3->type = NSEMI;
11563                        n3->nbinary.ch1 = n1;
11564                        n3->nbinary.ch2 = n2;
11565                        n1 = n3;
11566                }
11567                switch (tok) {
11568                case TNL:
11569                case TEOF:
11570                        tokpushback = 1;
11571                        /* fall through */
11572                case TBACKGND:
11573                case TSEMI:
11574                        break;
11575                default:
11576                        if ((nlflag & 1))
11577                                raise_error_unexpected_syntax(-1);
11578                        tokpushback = 1;
11579                        return n1;
11580                }
11581        }
11582}
11583
11584static union node *
11585andor(void)
11586{
11587        union node *n1, *n2, *n3;
11588        int t;
11589
11590        n1 = pipeline();
11591        for (;;) {
11592                t = readtoken();
11593                if (t == TAND) {
11594                        t = NAND;
11595                } else if (t == TOR) {
11596                        t = NOR;
11597                } else {
11598                        tokpushback = 1;
11599                        return n1;
11600                }
11601                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11602                n2 = pipeline();
11603                n3 = stzalloc(sizeof(struct nbinary));
11604                n3->type = t;
11605                n3->nbinary.ch1 = n1;
11606                n3->nbinary.ch2 = n2;
11607                n1 = n3;
11608        }
11609}
11610
11611static union node *
11612pipeline(void)
11613{
11614        union node *n1, *n2, *pipenode;
11615        struct nodelist *lp, *prev;
11616        int negate;
11617
11618        negate = 0;
11619        TRACE(("pipeline: entered\n"));
11620        if (readtoken() == TNOT) {
11621                negate = !negate;
11622                checkkwd = CHKKWD | CHKALIAS;
11623        } else
11624                tokpushback = 1;
11625        n1 = parse_command();
11626        if (readtoken() == TPIPE) {
11627                pipenode = stzalloc(sizeof(struct npipe));
11628                pipenode->type = NPIPE;
11629                /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
11630                lp = stzalloc(sizeof(struct nodelist));
11631                pipenode->npipe.cmdlist = lp;
11632                lp->n = n1;
11633                do {
11634                        prev = lp;
11635                        lp = stzalloc(sizeof(struct nodelist));
11636                        checkkwd = CHKNL | CHKKWD | CHKALIAS;
11637                        lp->n = parse_command();
11638                        prev->next = lp;
11639                } while (readtoken() == TPIPE);
11640                lp->next = NULL;
11641                n1 = pipenode;
11642        }
11643        tokpushback = 1;
11644        if (negate) {
11645                n2 = stzalloc(sizeof(struct nnot));
11646                n2->type = NNOT;
11647                n2->nnot.com = n1;
11648                return n2;
11649        }
11650        return n1;
11651}
11652
11653static union node *
11654makename(void)
11655{
11656        union node *n;
11657
11658        n = stzalloc(sizeof(struct narg));
11659        n->type = NARG;
11660        /*n->narg.next = NULL; - stzalloc did it */
11661        n->narg.text = wordtext;
11662        n->narg.backquote = backquotelist;
11663        return n;
11664}
11665
11666static void
11667fixredir(union node *n, const char *text, int err)
11668{
11669        int fd;
11670
11671        TRACE(("Fix redir %s %d\n", text, err));
11672        if (!err)
11673                n->ndup.vname = NULL;
11674
11675        fd = bb_strtou(text, NULL, 10);
11676        if (!errno && fd >= 0)
11677                n->ndup.dupfd = fd;
11678        else if (LONE_DASH(text))
11679                n->ndup.dupfd = -1;
11680        else {
11681                if (err)
11682                        raise_error_syntax("bad fd number");
11683                n->ndup.vname = makename();
11684        }
11685}
11686
11687static void
11688parsefname(void)
11689{
11690        union node *n = redirnode;
11691
11692        if (n->type == NHERE)
11693                checkkwd = CHKEOFMARK;
11694        if (readtoken() != TWORD)
11695                raise_error_unexpected_syntax(-1);
11696        if (n->type == NHERE) {
11697                struct heredoc *here = heredoc;
11698                struct heredoc *p;
11699
11700                if (quoteflag == 0)
11701                        n->type = NXHERE;
11702                TRACE(("Here document %d\n", n->type));
11703                rmescapes(wordtext, 0, NULL);
11704                here->eofmark = wordtext;
11705                here->next = NULL;
11706                if (heredoclist == NULL)
11707                        heredoclist = here;
11708                else {
11709                        for (p = heredoclist; p->next; p = p->next)
11710                                continue;
11711                        p->next = here;
11712                }
11713        } else if (n->type == NTOFD || n->type == NFROMFD) {
11714                fixredir(n, wordtext, 0);
11715        } else {
11716                n->nfile.fname = makename();
11717        }
11718}
11719
11720static union node *
11721simplecmd(void)
11722{
11723        union node *args, **app;
11724        union node *n = NULL;
11725        union node *vars, **vpp;
11726        union node **rpp, *redir;
11727        int savecheckkwd;
11728        int savelinno;
11729#if BASH_TEST2
11730        smallint double_brackets_flag = 0;
11731#endif
11732        IF_BASH_FUNCTION(smallint function_flag = 0;)
11733
11734        args = NULL;
11735        app = &args;
11736        vars = NULL;
11737        vpp = &vars;
11738        redir = NULL;
11739        rpp = &redir;
11740
11741        savecheckkwd = CHKALIAS;
11742        savelinno = g_parsefile->linno;
11743        for (;;) {
11744                int t;
11745                checkkwd = savecheckkwd;
11746                t = readtoken();
11747                switch (t) {
11748#if BASH_FUNCTION
11749                case TFUNCTION:
11750                        if (peektoken() != TWORD)
11751                                raise_error_unexpected_syntax(TWORD);
11752                        function_flag = 1;
11753                        break;
11754#endif
11755#if BASH_TEST2
11756                case TAND: /* "&&" */
11757                case TOR: /* "||" */
11758                        if (!double_brackets_flag) {
11759                                tokpushback = 1;
11760                                goto out;
11761                        }
11762                        wordtext = (char *) (t == TAND ? "-a" : "-o");
11763#endif
11764                case TWORD:
11765                        n = stzalloc(sizeof(struct narg));
11766                        n->type = NARG;
11767                        /*n->narg.next = NULL; - stzalloc did it */
11768                        n->narg.text = wordtext;
11769#if BASH_TEST2
11770                        if (strcmp("[[", wordtext) == 0)
11771                                double_brackets_flag = 1;
11772                        else if (strcmp("]]", wordtext) == 0)
11773                                double_brackets_flag = 0;
11774#endif
11775                        n->narg.backquote = backquotelist;
11776                        if (savecheckkwd && isassignment(wordtext)) {
11777                                *vpp = n;
11778                                vpp = &n->narg.next;
11779                        } else {
11780                                *app = n;
11781                                app = &n->narg.next;
11782                                savecheckkwd = 0;
11783                        }
11784#if BASH_FUNCTION
11785                        if (function_flag) {
11786                                checkkwd = CHKNL | CHKKWD;
11787                                switch (peektoken()) {
11788                                case TBEGIN:
11789                                case TIF:
11790                                case TCASE:
11791                                case TUNTIL:
11792                                case TWHILE:
11793                                case TFOR:
11794                                        goto do_func;
11795                                case TLP:
11796                                        function_flag = 0;
11797                                        break;
11798# if BASH_TEST2
11799                                case TWORD:
11800                                        if (strcmp("[[", wordtext) == 0)
11801                                                goto do_func;
11802                                        /* fall through */
11803# endif
11804                                default:
11805                                        raise_error_unexpected_syntax(-1);
11806                                }
11807                        }
11808#endif
11809                        break;
11810                case TREDIR:
11811                        *rpp = n = redirnode;
11812                        rpp = &n->nfile.next;
11813                        parsefname();   /* read name of redirection file */
11814                        break;
11815                case TLP:
11816 IF_BASH_FUNCTION(do_func:)
11817                        if (args && app == &args->narg.next
11818                         && !vars && !redir
11819                        ) {
11820                                struct builtincmd *bcmd;
11821                                const char *name;
11822
11823                                /* We have a function */
11824                                if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
11825                                        raise_error_unexpected_syntax(TRP);
11826                                name = n->narg.text;
11827                                if (!goodname(name)
11828                                 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11829                                ) {
11830                                        raise_error_syntax("bad function name");
11831                                }
11832                                n->type = NDEFUN;
11833                                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11834                                n->ndefun.text = n->narg.text;
11835                                n->ndefun.linno = g_parsefile->linno;
11836                                n->ndefun.body = parse_command();
11837                                return n;
11838                        }
11839                        IF_BASH_FUNCTION(function_flag = 0;)
11840                        /* fall through */
11841                default:
11842                        tokpushback = 1;
11843                        goto out;
11844                }
11845        }
11846 out:
11847        *app = NULL;
11848        *vpp = NULL;
11849        *rpp = NULL;
11850        n = stzalloc(sizeof(struct ncmd));
11851        if (NCMD != 0)
11852                n->type = NCMD;
11853        n->ncmd.linno = savelinno;
11854        n->ncmd.args = args;
11855        n->ncmd.assign = vars;
11856        n->ncmd.redirect = redir;
11857        return n;
11858}
11859
11860static union node *
11861parse_command(void)
11862{
11863        union node *n1, *n2;
11864        union node *ap, **app;
11865        union node *cp, **cpp;
11866        union node *redir, **rpp;
11867        union node **rpp2;
11868        int t;
11869        int savelinno;
11870
11871        redir = NULL;
11872        rpp2 = &redir;
11873
11874        savelinno = g_parsefile->linno;
11875
11876        switch (readtoken()) {
11877        default:
11878                raise_error_unexpected_syntax(-1);
11879                /* NOTREACHED */
11880        case TIF:
11881                n1 = stzalloc(sizeof(struct nif));
11882                n1->type = NIF;
11883                n1->nif.test = list(0);
11884                if (readtoken() != TTHEN)
11885                        raise_error_unexpected_syntax(TTHEN);
11886                n1->nif.ifpart = list(0);
11887                n2 = n1;
11888                while (readtoken() == TELIF) {
11889                        n2->nif.elsepart = stzalloc(sizeof(struct nif));
11890                        n2 = n2->nif.elsepart;
11891                        n2->type = NIF;
11892                        n2->nif.test = list(0);
11893                        if (readtoken() != TTHEN)
11894                                raise_error_unexpected_syntax(TTHEN);
11895                        n2->nif.ifpart = list(0);
11896                }
11897                if (lasttoken == TELSE)
11898                        n2->nif.elsepart = list(0);
11899                else {
11900                        n2->nif.elsepart = NULL;
11901                        tokpushback = 1;
11902                }
11903                t = TFI;
11904                break;
11905        case TWHILE:
11906        case TUNTIL: {
11907                int got;
11908                n1 = stzalloc(sizeof(struct nbinary));
11909                n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
11910                n1->nbinary.ch1 = list(0);
11911                got = readtoken();
11912                if (got != TDO) {
11913                        TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
11914                                        got == TWORD ? wordtext : ""));
11915                        raise_error_unexpected_syntax(TDO);
11916                }
11917                n1->nbinary.ch2 = list(0);
11918                t = TDONE;
11919                break;
11920        }
11921        case TFOR:
11922                if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
11923                        raise_error_syntax("bad for loop variable");
11924                n1 = stzalloc(sizeof(struct nfor));
11925                n1->type = NFOR;
11926                n1->nfor.linno = savelinno;
11927                n1->nfor.var = wordtext;
11928                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11929                if (readtoken() == TIN) {
11930                        app = &ap;
11931                        while (readtoken() == TWORD) {
11932                                n2 = stzalloc(sizeof(struct narg));
11933                                n2->type = NARG;
11934                                /*n2->narg.next = NULL; - stzalloc did it */
11935                                n2->narg.text = wordtext;
11936                                n2->narg.backquote = backquotelist;
11937                                *app = n2;
11938                                app = &n2->narg.next;
11939                        }
11940                        *app = NULL;
11941                        n1->nfor.args = ap;
11942                        if (lasttoken != TNL && lasttoken != TSEMI)
11943                                raise_error_unexpected_syntax(-1);
11944                } else {
11945                        n2 = stzalloc(sizeof(struct narg));
11946                        n2->type = NARG;
11947                        /*n2->narg.next = NULL; - stzalloc did it */
11948                        n2->narg.text = (char *)dolatstr;
11949                        /*n2->narg.backquote = NULL;*/
11950                        n1->nfor.args = n2;
11951                        /*
11952                         * Newline or semicolon here is optional (but note
11953                         * that the original Bourne shell only allowed NL).
11954                         */
11955                        if (lasttoken != TSEMI)
11956                                tokpushback = 1;
11957                }
11958                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11959                if (readtoken() != TDO)
11960                        raise_error_unexpected_syntax(TDO);
11961                n1->nfor.body = list(0);
11962                t = TDONE;
11963                break;
11964        case TCASE:
11965                n1 = stzalloc(sizeof(struct ncase));
11966                n1->type = NCASE;
11967                n1->ncase.linno = savelinno;
11968                if (readtoken() != TWORD)
11969                        raise_error_unexpected_syntax(TWORD);
11970                n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
11971                n2->type = NARG;
11972                /*n2->narg.next = NULL; - stzalloc did it */
11973                n2->narg.text = wordtext;
11974                n2->narg.backquote = backquotelist;
11975                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11976                if (readtoken() != TIN)
11977                        raise_error_unexpected_syntax(TIN);
11978                cpp = &n1->ncase.cases;
11979 next_case:
11980                checkkwd = CHKNL | CHKKWD;
11981                t = readtoken();
11982                while (t != TESAC) {
11983                        if (lasttoken == TLP)
11984                                readtoken();
11985                        *cpp = cp = stzalloc(sizeof(struct nclist));
11986                        cp->type = NCLIST;
11987                        app = &cp->nclist.pattern;
11988                        for (;;) {
11989                                *app = ap = stzalloc(sizeof(struct narg));
11990                                ap->type = NARG;
11991                                /*ap->narg.next = NULL; - stzalloc did it */
11992                                ap->narg.text = wordtext;
11993                                ap->narg.backquote = backquotelist;
11994                                if (readtoken() != TPIPE)
11995                                        break;
11996                                app = &ap->narg.next;
11997                                readtoken();
11998                        }
11999                        //ap->narg.next = NULL;
12000                        if (lasttoken != TRP)
12001                                raise_error_unexpected_syntax(TRP);
12002                        cp->nclist.body = list(2);
12003
12004                        cpp = &cp->nclist.next;
12005
12006                        checkkwd = CHKNL | CHKKWD;
12007                        t = readtoken();
12008                        if (t != TESAC) {
12009                                if (t != TENDCASE)
12010                                        raise_error_unexpected_syntax(TENDCASE);
12011                                goto next_case;
12012                        }
12013                }
12014                *cpp = NULL;
12015                goto redir;
12016        case TLP:
12017                n1 = stzalloc(sizeof(struct nredir));
12018                n1->type = NSUBSHELL;
12019                n1->nredir.linno = savelinno;
12020                n1->nredir.n = list(0);
12021                /*n1->nredir.redirect = NULL; - stzalloc did it */
12022                t = TRP;
12023                break;
12024        case TBEGIN:
12025                n1 = list(0);
12026                t = TEND;
12027                break;
12028        IF_BASH_FUNCTION(case TFUNCTION:)
12029        case TWORD:
12030        case TREDIR:
12031                tokpushback = 1;
12032                return simplecmd();
12033        }
12034
12035        if (readtoken() != t)
12036                raise_error_unexpected_syntax(t);
12037
12038 redir:
12039        /* Now check for redirection which may follow command */
12040        checkkwd = CHKKWD | CHKALIAS;
12041        rpp = rpp2;
12042        while (readtoken() == TREDIR) {
12043                *rpp = n2 = redirnode;
12044                rpp = &n2->nfile.next;
12045                parsefname();
12046        }
12047        tokpushback = 1;
12048        *rpp = NULL;
12049        if (redir) {
12050                if (n1->type != NSUBSHELL) {
12051                        n2 = stzalloc(sizeof(struct nredir));
12052                        n2->type = NREDIR;
12053                        n2->nredir.linno = savelinno;
12054                        n2->nredir.n = n1;
12055                        n1 = n2;
12056                }
12057                n1->nredir.redirect = redir;
12058        }
12059        return n1;
12060}
12061
12062#if BASH_DOLLAR_SQUOTE
12063static int
12064decode_dollar_squote(void)
12065{
12066        static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
12067        int c, cnt;
12068        char *p;
12069        char buf[4];
12070
12071        c = pgetc();
12072        p = strchr(C_escapes, c);
12073        if (p) {
12074                buf[0] = c;
12075                p = buf;
12076                cnt = 3;
12077                if ((unsigned char)(c - '0') <= 7) { /* \ooo */
12078                        do {
12079                                c = pgetc();
12080                                *++p = c;
12081                        } while ((unsigned char)(c - '0') <= 7 && --cnt);
12082                        pungetc();
12083                } else if (c == 'x') { /* \xHH */
12084                        do {
12085                                c = pgetc();
12086                                *++p = c;
12087                        } while (isxdigit(c) && --cnt);
12088                        pungetc();
12089                        if (cnt == 3) { /* \x but next char is "bad" */
12090                                c = 'x';
12091                                goto unrecognized;
12092                        }
12093                } else { /* simple seq like \\ or \t */
12094                        p++;
12095                }
12096                *p = '\0';
12097                p = buf;
12098                c = bb_process_escape_sequence((void*)&p);
12099        } else { /* unrecognized "\z": print both chars unless ' or " */
12100                if (c != '\'' && c != '"') {
12101 unrecognized:
12102                        c |= 0x100; /* "please encode \, then me" */
12103                }
12104        }
12105        return c;
12106}
12107#endif
12108
12109/* Used by expandstr to get here-doc like behaviour. */
12110#define FAKEEOFMARK ((char*)(uintptr_t)1)
12111
12112static ALWAYS_INLINE int
12113realeofmark(const char *eofmark)
12114{
12115        return eofmark && eofmark != FAKEEOFMARK;
12116}
12117
12118/*
12119 * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
12120 * is not NULL, read a here document.  In the latter case, eofmark is the
12121 * word which marks the end of the document and striptabs is true if
12122 * leading tabs should be stripped from the document.  The argument c
12123 * is the first character of the input token or document.
12124 *
12125 * Because C does not have internal subroutines, I have simulated them
12126 * using goto's to implement the subroutine linkage.  The following macros
12127 * will run code that appears at the end of readtoken1.
12128 */
12129#define CHECKEND()      {goto checkend; checkend_return:;}
12130#define PARSEREDIR()    {goto parseredir; parseredir_return:;}
12131#define PARSESUB()      {goto parsesub; parsesub_return:;}
12132#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
12133#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
12134#define PARSEARITH()    {goto parsearith; parsearith_return:;}
12135static int
12136readtoken1(int c, int syntax, char *eofmark, int striptabs)
12137{
12138        /* NB: syntax parameter fits into smallint */
12139        /* c parameter is an unsigned char or PEOF or PEOA */
12140        char *out;
12141        size_t len;
12142        struct nodelist *bqlist;
12143        smallint quotef;
12144        smallint oldstyle;
12145        smallint pssyntax;   /* we are expanding a prompt string */
12146        IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
12147        /* syntax stack */
12148        struct synstack synbase = { };
12149        struct synstack *synstack = &synbase;
12150
12151#if ENABLE_ASH_EXPAND_PRMT
12152        pssyntax = (syntax == PSSYNTAX);
12153        if (pssyntax)
12154                syntax = DQSYNTAX;
12155#else
12156        pssyntax = 0; /* constant */
12157#endif
12158        synstack->syntax = syntax;
12159
12160        if (syntax == DQSYNTAX)
12161                synstack->dblquote = 1;
12162        quotef = 0;
12163        bqlist = NULL;
12164
12165        STARTSTACKSTR(out);
12166 loop:
12167        /* For each line, until end of word */
12168        CHECKEND();     /* set c to PEOF if at end of here document */
12169        for (;;) {      /* until end of line or end of word */
12170                CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
12171                switch (SIT(c, synstack->syntax)) {
12172                case CNL:       /* '\n' */
12173                        if (synstack->syntax == BASESYNTAX
12174                         && !synstack->varnest
12175                        ) {
12176                                goto endword;   /* exit outer loop */
12177                        }
12178                        USTPUTC(c, out);
12179                        nlprompt();
12180                        c = pgetc();
12181                        goto loop;              /* continue outer loop */
12182                case CWORD:
12183                        USTPUTC(c, out);
12184                        break;
12185                case CCTL:
12186#if BASH_DOLLAR_SQUOTE
12187                        if (c == '\\' && bash_dollar_squote) {
12188                                c = decode_dollar_squote();
12189                                if (c == '\0') {
12190                                        /* skip $'\000', $'\x00' (like bash) */
12191                                        break;
12192                                }
12193                                if (c & 0x100) {
12194                                        /* Unknown escape. Encode as '\z' */
12195                                        c = (unsigned char)c;
12196                                        if (eofmark == NULL || synstack->dblquote)
12197                                                USTPUTC(CTLESC, out);
12198                                        USTPUTC('\\', out);
12199                                }
12200                        }
12201#endif
12202                        if (!eofmark || synstack->dblquote || synstack->varnest)
12203                                USTPUTC(CTLESC, out);
12204                        USTPUTC(c, out);
12205                        break;
12206                case CBACK:     /* backslash */
12207                        c = pgetc_without_PEOA();
12208                        if (c == PEOF) {
12209                                USTPUTC(CTLESC, out);
12210                                USTPUTC('\\', out);
12211                                pungetc();
12212                        } else if (c == '\n') {
12213                                nlprompt();
12214                        } else {
12215                                if (pssyntax && c == '$') {
12216                                        USTPUTC(CTLESC, out);
12217                                        USTPUTC('\\', out);
12218                                }
12219                                /* Backslash is retained if we are in "str"
12220                                 * and next char isn't dquote-special.
12221                                 */
12222                                if (synstack->dblquote
12223                                 && c != '\\'
12224                                 && c != '`'
12225                                 && c != '$'
12226                                 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12227                                 && (c != '}' || !synstack->varnest)
12228                                ) {
12229                                        USTPUTC(CTLESC, out); /* protect '\' from glob */
12230                                        USTPUTC('\\', out);
12231                                }
12232                                USTPUTC(CTLESC, out);
12233                                USTPUTC(c, out);
12234                                quotef = 1;
12235                        }
12236                        break;
12237                case CSQUOTE:
12238                        synstack->syntax = SQSYNTAX;
12239 quotemark:
12240                        if (eofmark == NULL) {
12241                                USTPUTC(CTLQUOTEMARK, out);
12242                        }
12243                        break;
12244                case CDQUOTE:
12245                        synstack->syntax = DQSYNTAX;
12246                        synstack->dblquote = 1;
12247 toggledq:
12248                        if (synstack->varnest)
12249                                synstack->innerdq ^= 1;
12250                        goto quotemark;
12251                case CENDQUOTE:
12252                        IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
12253                        if (eofmark != NULL && synstack->varnest == 0) {
12254                                USTPUTC(c, out);
12255                                break;
12256                        }
12257
12258                        if (synstack->dqvarnest == 0) {
12259                                synstack->syntax = BASESYNTAX;
12260                                synstack->dblquote = 0;
12261                        }
12262
12263                        quotef = 1;
12264
12265                        if (c == '"')
12266                                goto toggledq;
12267
12268                        goto quotemark;
12269                case CVAR:      /* '$' */
12270                        PARSESUB();             /* parse substitution */
12271                        break;
12272                case CENDVAR:   /* '}' */
12273                        if (!synstack->innerdq && synstack->varnest > 0) {
12274                                if (!--synstack->varnest && synstack->varpushed)
12275                                        synstack_pop(&synstack);
12276                                else if (synstack->dqvarnest > 0)
12277                                        synstack->dqvarnest--;
12278                                c = CTLENDVAR;
12279                        }
12280                        USTPUTC(c, out);
12281                        break;
12282#if ENABLE_FEATURE_SH_MATH
12283                case CLP:       /* '(' in arithmetic */
12284                        synstack->parenlevel++;
12285                        USTPUTC(c, out);
12286                        break;
12287                case CRP:       /* ')' in arithmetic */
12288                        if (synstack->parenlevel > 0) {
12289                                synstack->parenlevel--;
12290                        } else {
12291                                if (pgetc_eatbnl() == ')') {
12292                                        c = CTLENDARI;
12293                                        synstack_pop(&synstack);
12294                                } else {
12295                                        /*
12296                                         * unbalanced parens
12297                                         * (don't 2nd guess - no error)
12298                                         */
12299                                        pungetc();
12300                                }
12301                        }
12302                        USTPUTC(c, out);
12303                        break;
12304#endif
12305                case CBQUOTE:   /* '`' */
12306                        if (checkkwd & CHKEOFMARK) {
12307                                quotef = 1;
12308                                USTPUTC('`', out);
12309                                break;
12310                        }
12311
12312                        PARSEBACKQOLD();
12313                        break;
12314                case CENDFILE:
12315                        goto endword;           /* exit outer loop */
12316                case CIGN:
12317                        break;
12318                default:
12319                        if (synstack->varnest == 0) {
12320#if BASH_REDIR_OUTPUT
12321                                if (c == '&') {
12322//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
12323                                        if (pgetc() == '>')
12324                                                c = 0x100 + '>'; /* flag &> */
12325                                        pungetc();
12326                                }
12327#endif
12328                                goto endword;   /* exit outer loop */
12329                        }
12330                        IF_ASH_ALIAS(if (c != PEOA))
12331                                USTPUTC(c, out);
12332                }
12333                c = pgetc();
12334        } /* for (;;) */
12335 endword:
12336
12337#if ENABLE_FEATURE_SH_MATH
12338        if (synstack->syntax == ARISYNTAX)
12339                raise_error_syntax("missing '))'");
12340#endif
12341        if (synstack->syntax != BASESYNTAX && eofmark == NULL)
12342                raise_error_syntax("unterminated quoted string");
12343        if (synstack->varnest != 0) {
12344                /* { */
12345                raise_error_syntax("missing '}'");
12346        }
12347        USTPUTC('\0', out);
12348        len = out - (char *)stackblock();
12349        out = stackblock();
12350        if (eofmark == NULL) {
12351                if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
12352                 && quotef == 0
12353                ) {
12354                        if (isdigit_str9(out)) {
12355                                PARSEREDIR(); /* passed as params: out, c */
12356                                lasttoken = TREDIR;
12357                                return lasttoken;
12358                        }
12359                        /* else: non-number X seen, interpret it
12360                         * as "NNNX>file" = "NNNX >file" */
12361                }
12362                pungetc();
12363        }
12364        quoteflag = quotef;
12365        backquotelist = bqlist;
12366        grabstackblock(len);
12367        wordtext = out;
12368        lasttoken = TWORD;
12369        return lasttoken;
12370/* end of readtoken routine */
12371
12372/*
12373 * Check to see whether we are at the end of the here document.  When this
12374 * is called, c is set to the first character of the next input line.  If
12375 * we are at the end of the here document, this routine sets the c to PEOF.
12376 */
12377checkend: {
12378        if (realeofmark(eofmark)) {
12379                int markloc;
12380                char *p;
12381
12382#if ENABLE_ASH_ALIAS
12383                if (c == PEOA)
12384                        c = pgetc_without_PEOA();
12385#endif
12386                if (striptabs) {
12387                        while (c == '\t') {
12388                                c = pgetc_without_PEOA();
12389                        }
12390                }
12391
12392                markloc = out - (char *)stackblock();
12393                for (p = eofmark; STPUTC(c, out), *p; p++) {
12394                        if (c != *p)
12395                                goto more_heredoc;
12396
12397                        c = pgetc_without_PEOA();
12398                }
12399
12400                if (c == '\n' || c == PEOF) {
12401                        c = PEOF;
12402                        g_parsefile->linno++;
12403                        needprompt = doprompt;
12404                } else {
12405                        int len_here;
12406
12407 more_heredoc:
12408                        p = (char *)stackblock() + markloc + 1;
12409                        len_here = out - p;
12410
12411                        if (len_here) {
12412                                len_here -= (c >= PEOF);
12413                                c = p[-1];
12414
12415                                if (len_here) {
12416                                        char *str;
12417
12418                                        str = alloca(len_here + 1);
12419                                        *(char *)mempcpy(str, p, len_here) = '\0';
12420
12421                                        pushstring(str, NULL);
12422                                }
12423                        }
12424                }
12425
12426                STADJUST((char *)stackblock() + markloc - out, out);
12427        }
12428        goto checkend_return;
12429}
12430
12431/*
12432 * Parse a redirection operator.  The variable "out" points to a string
12433 * specifying the fd to be redirected.  The variable "c" contains the
12434 * first character of the redirection operator.
12435 */
12436parseredir: {
12437        /* out is already checked to be a valid number or "" */
12438        int fd = (*out == '\0' ? -1 : atoi(out));
12439        union node *np;
12440
12441        np = stzalloc(sizeof(struct nfile));
12442        if (c == '>') {
12443                np->nfile.fd = 1;
12444                c = pgetc_eatbnl();
12445                if (c == '>')
12446                        np->type = NAPPEND;
12447                else if (c == '|')
12448                        np->type = NCLOBBER;
12449                else if (c == '&')
12450                        np->type = NTOFD;
12451                        /* it also can be NTO2 (>&file), but we can't figure it out yet */
12452                else {
12453                        np->type = NTO;
12454                        pungetc();
12455                }
12456        }
12457#if BASH_REDIR_OUTPUT
12458        else if (c == 0x100 + '>') { /* this flags &> redirection */
12459                np->nfile.fd = 1;
12460                pgetc(); /* this is '>', no need to check */
12461                np->type = NTO2;
12462        }
12463#endif
12464        else { /* c == '<' */
12465                /*np->nfile.fd = 0; - stzalloc did it */
12466                c = pgetc_eatbnl();
12467                switch (c) {
12468                case '<':
12469                        if (sizeof(struct nfile) != sizeof(struct nhere)) {
12470                                np = stzalloc(sizeof(struct nhere));
12471                                /*np->nfile.fd = 0; - stzalloc did it */
12472                        }
12473                        np->type = NHERE;
12474                        heredoc = stzalloc(sizeof(struct heredoc));
12475                        heredoc->here = np;
12476                        c = pgetc_eatbnl();
12477                        if (c == '-') {
12478                                heredoc->striptabs = 1;
12479                        } else {
12480                                /*heredoc->striptabs = 0; - stzalloc did it */
12481                                pungetc();
12482                        }
12483                        break;
12484
12485                case '&':
12486                        np->type = NFROMFD;
12487                        break;
12488
12489                case '>':
12490                        np->type = NFROMTO;
12491                        break;
12492
12493                default:
12494                        np->type = NFROM;
12495                        pungetc();
12496                        break;
12497                }
12498        }
12499        if (fd >= 0)
12500                np->nfile.fd = fd;
12501        redirnode = np;
12502        goto parseredir_return;
12503}
12504
12505/*
12506 * Parse a substitution.  At this point, we have read the dollar sign
12507 * and nothing else.
12508 */
12509
12510/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12511 * (assuming ascii char codes, as the original implementation did) */
12512#define is_special(c) \
12513        (((unsigned)(c) - 33 < 32) \
12514                        && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
12515parsesub: {
12516        unsigned char subtype;
12517        int typeloc;
12518
12519        c = pgetc_eatbnl();
12520        if ((checkkwd & CHKEOFMARK)
12521         || c > 255 /* PEOA or PEOF */
12522         || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
12523        ) {
12524#if BASH_DOLLAR_SQUOTE
12525                if (synstack->syntax != DQSYNTAX && c == '\'')
12526                        bash_dollar_squote = 1;
12527                else
12528#endif
12529                        USTPUTC('$', out);
12530                pungetc();
12531        } else if (c == '(') {
12532                /* $(command) or $((arith)) */
12533                if (pgetc_eatbnl() == '(') {
12534#if ENABLE_FEATURE_SH_MATH
12535                        PARSEARITH();
12536#else
12537                        raise_error_syntax("support for $((arith)) is disabled");
12538#endif
12539                } else {
12540                        pungetc();
12541                        PARSEBACKQNEW();
12542                }
12543        } else {
12544                /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
12545                smalluint newsyn = synstack->syntax;
12546
12547                USTPUTC(CTLVAR, out);
12548                typeloc = out - (char *)stackblock();
12549                STADJUST(1, out);
12550                subtype = VSNORMAL;
12551                if (c == '{') {
12552                        c = pgetc_eatbnl();
12553                        subtype = 0;
12554                }
12555 varname:
12556                if (is_name(c)) {
12557                        /* $[{[#]]NAME[}] */
12558                        do {
12559                                STPUTC(c, out);
12560                                c = pgetc_eatbnl();
12561                        } while (is_in_name(c));
12562                } else if (isdigit(c)) {
12563                        /* $[{[#]]NUM[}] */
12564                        do {
12565                                STPUTC(c, out);
12566                                c = pgetc_eatbnl();
12567                        } while (isdigit(c));
12568                } else if (c != '}') {
12569                        /* $[{[#]]<specialchar>[}] */
12570                        int cc = c;
12571
12572                        c = pgetc_eatbnl();
12573                        if (!subtype && cc == '#') {
12574                                subtype = VSLENGTH;
12575                                if (c == '_' || isalnum(c))
12576                                        goto varname;
12577                                cc = c;
12578                                c = pgetc_eatbnl();
12579                                if (cc == '}' || c != '}') {
12580                                        pungetc();
12581                                        subtype = 0;
12582                                        c = cc;
12583                                        cc = '#';
12584                                }
12585                        }
12586
12587                        if (!is_special(cc)) {
12588                                if (subtype == VSLENGTH)
12589                                        subtype = 0;
12590                                goto badsub;
12591                        }
12592
12593                        USTPUTC(cc, out);
12594                } else
12595                        goto badsub;
12596
12597                if (c != '}' && subtype == VSLENGTH) {
12598                        /* ${#VAR didn't end with } */
12599                        goto badsub;
12600                }
12601
12602                if (subtype == 0) {
12603                        static const char types[] ALIGN1 = "}-+?=";
12604                        /* ${VAR...} but not $VAR or ${#VAR} */
12605                        /* c == first char after VAR */
12606                        int cc = c;
12607
12608                        switch (c) {
12609                        case ':':
12610                                c = pgetc_eatbnl();
12611#if BASH_SUBSTR
12612                                /* This check is only needed to not misinterpret
12613                                 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12614                                 * constructs.
12615                                 */
12616                                if (!strchr(types, c)) {
12617                                        subtype = VSSUBSTR;
12618                                        pungetc();
12619                                        break; /* "goto badsub" is bigger (!) */
12620                                }
12621#endif
12622                                subtype = VSNUL;
12623                                /*FALLTHROUGH*/
12624                        default: {
12625                                const char *p = strchr(types, c);
12626                                if (p == NULL)
12627                                        break;
12628                                subtype |= p - types + VSNORMAL;
12629                                break;
12630                        }
12631                        case '%':
12632                        case '#':
12633                                subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12634                                c = pgetc_eatbnl();
12635                                if (c == cc)
12636                                        subtype++;
12637                                else
12638                                        pungetc();
12639
12640                                newsyn = BASESYNTAX;
12641                                break;
12642#if BASH_PATTERN_SUBST
12643                        case '/':
12644                                /* ${v/[/]pattern/repl} */
12645//TODO: encode pattern and repl separately.
12646// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12647// are broken (should print "ONE")
12648                                subtype = VSREPLACE;
12649                                newsyn = BASESYNTAX;
12650                                c = pgetc_eatbnl();
12651                                if (c != '/')
12652                                        goto badsub;
12653                                subtype++; /* VSREPLACEALL */
12654                                break;
12655#endif
12656                        }
12657                } else {
12658 badsub:
12659                        pungetc();
12660                }
12661
12662                if (newsyn == ARISYNTAX)
12663                        newsyn = DQSYNTAX;
12664
12665                if ((newsyn != synstack->syntax || synstack->innerdq)
12666                 && subtype != VSNORMAL
12667                ) {
12668                        synstack_push(&synstack,
12669                                synstack->prev ?: alloca(sizeof(*synstack)),
12670                                newsyn);
12671
12672                        synstack->varpushed = 1;
12673                        synstack->dblquote = newsyn != BASESYNTAX;
12674                }
12675
12676                ((unsigned char *)stackblock())[typeloc] = subtype;
12677                if (subtype != VSNORMAL) {
12678                        synstack->varnest++;
12679                        if (synstack->dblquote)
12680                                synstack->dqvarnest++;
12681                }
12682                STPUTC('=', out);
12683        }
12684        goto parsesub_return;
12685}
12686
12687/*
12688 * Called to parse command substitutions.  Newstyle is set if the command
12689 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12690 * list of commands (passed by reference), and savelen is the number of
12691 * characters on the top of the stack which must be preserved.
12692 */
12693parsebackq: {
12694        struct nodelist **nlpp;
12695        union node *n;
12696        char *str;
12697        size_t savelen;
12698        smallint saveprompt = 0;
12699
12700        str = NULL;
12701        savelen = out - (char *)stackblock();
12702        if (savelen > 0) {
12703                /*
12704                 * FIXME: this can allocate very large block on stack and SEGV.
12705                 * Example:
12706                 * echo "..<100kbytes>..`true` $(true) `true` ..."
12707                 * allocates 100kb for every command subst. With about
12708                 * a hundred command substitutions stack overflows.
12709                 * With larger prepended string, SEGV happens sooner.
12710                 */
12711                str = alloca(savelen);
12712                memcpy(str, stackblock(), savelen);
12713        }
12714
12715        if (oldstyle) {
12716                /* We must read until the closing backquote, giving special
12717                 * treatment to some slashes, and then push the string and
12718                 * reread it as input, interpreting it normally.
12719                 */
12720                char *pout;
12721                size_t psavelen;
12722                char *pstr;
12723
12724                STARTSTACKSTR(pout);
12725                for (;;) {
12726                        int pc;
12727
12728                        setprompt_if(needprompt, 2);
12729                        pc = pgetc_eatbnl();
12730                        switch (pc) {
12731                        case '`':
12732                                goto done;
12733
12734                        case '\\':
12735                                pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
12736                                if (pc != '\\' && pc != '`' && pc != '$'
12737                                 && (!synstack->dblquote || pc != '"')
12738                                ) {
12739                                        STPUTC('\\', pout);
12740                                }
12741                                if (pc <= 255 /* not PEOA or PEOF */) {
12742                                        break;
12743                                }
12744                                /* fall through */
12745
12746                        case PEOF:
12747                        IF_ASH_ALIAS(case PEOA:)
12748                                raise_error_syntax("EOF in backquote substitution");
12749
12750                        case '\n':
12751                                nlnoprompt();
12752                                break;
12753
12754                        default:
12755                                break;
12756                        }
12757                        STPUTC(pc, pout);
12758                }
12759 done:
12760                STPUTC('\0', pout);
12761                psavelen = pout - (char *)stackblock();
12762                if (psavelen > 0) {
12763                        pstr = grabstackstr(pout);
12764                        setinputstring(pstr);
12765                }
12766        }
12767        nlpp = &bqlist;
12768        while (*nlpp)
12769                nlpp = &(*nlpp)->next;
12770        *nlpp = stzalloc(sizeof(**nlpp));
12771        /* (*nlpp)->next = NULL; - stzalloc did it */
12772
12773        if (oldstyle) {
12774                saveprompt = doprompt;
12775                doprompt = 0;
12776        }
12777
12778        n = list(2);
12779
12780        if (oldstyle)
12781                doprompt = saveprompt;
12782        else if (readtoken() != TRP)
12783                raise_error_unexpected_syntax(TRP);
12784
12785        (*nlpp)->n = n;
12786        if (oldstyle) {
12787                /*
12788                 * Start reading from old file again, ignoring any pushed back
12789                 * tokens left from the backquote parsing
12790                 */
12791                popfile();
12792                tokpushback = 0;
12793        }
12794        while (stackblocksize() <= savelen)
12795                growstackblock();
12796        STARTSTACKSTR(out);
12797        if (str) {
12798                memcpy(out, str, savelen);
12799                STADJUST(savelen, out);
12800        }
12801        USTPUTC(CTLBACKQ, out);
12802        if (oldstyle)
12803                goto parsebackq_oldreturn;
12804        goto parsebackq_newreturn;
12805}
12806
12807#if ENABLE_FEATURE_SH_MATH
12808/*
12809 * Parse an arithmetic expansion (indicate start of one and set state)
12810 */
12811parsearith: {
12812
12813        synstack_push(&synstack,
12814                        synstack->prev ?: alloca(sizeof(*synstack)),
12815                        ARISYNTAX);
12816        synstack->dblquote = 1;
12817        USTPUTC(CTLARI, out);
12818        goto parsearith_return;
12819}
12820#endif
12821} /* end of readtoken */
12822
12823/*
12824 * Read the next input token.
12825 * If the token is a word, we set backquotelist to the list of cmds in
12826 *      backquotes.  We set quoteflag to true if any part of the word was
12827 *      quoted.
12828 * If the token is TREDIR, then we set redirnode to a structure containing
12829 *      the redirection.
12830 *
12831 * [Change comment:  here documents and internal procedures]
12832 * [Readtoken shouldn't have any arguments.  Perhaps we should make the
12833 *  word parsing code into a separate routine.  In this case, readtoken
12834 *  doesn't need to have any internal procedures, but parseword does.
12835 *  We could also make parseoperator in essence the main routine, and
12836 *  have parseword (readtoken1?) handle both words and redirection.]
12837 */
12838#define NEW_xxreadtoken
12839#ifdef NEW_xxreadtoken
12840/* singles must be first! */
12841static const char xxreadtoken_chars[7] ALIGN1 = {
12842        '\n', '(', ')', /* singles */
12843        '&', '|', ';',  /* doubles */
12844        0
12845};
12846
12847#define xxreadtoken_singles 3
12848#define xxreadtoken_doubles 3
12849
12850static const char xxreadtoken_tokens[] ALIGN1 = {
12851        TNL, TLP, TRP,          /* only single occurrence allowed */
12852        TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12853        TEOF,                   /* corresponds to trailing nul */
12854        TAND, TOR, TENDCASE     /* if double occurrence */
12855};
12856
12857static int
12858xxreadtoken(void)
12859{
12860        int c;
12861
12862        if (tokpushback) {
12863                tokpushback = 0;
12864                return lasttoken;
12865        }
12866        setprompt_if(needprompt, 2);
12867        for (;;) {                      /* until token or start of word found */
12868                c = pgetc_eatbnl();
12869                if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
12870                        continue;
12871
12872                if (c == '#') {
12873                        while ((c = pgetc()) != '\n' && c != PEOF)
12874                                continue;
12875                        pungetc();
12876                } else if (c == '\\') {
12877                        break; /* return readtoken1(...) */
12878                } else {
12879                        const char *p;
12880
12881                        p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12882                        if (c != PEOF) {
12883                                if (c == '\n') {
12884                                        nlnoprompt();
12885                                }
12886
12887                                p = strchr(xxreadtoken_chars, c);
12888                                if (p == NULL)
12889                                        break; /* return readtoken1(...) */
12890
12891                                if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12892                                        int cc = pgetc_eatbnl();
12893                                        if (cc == c) {    /* double occurrence? */
12894                                                p += xxreadtoken_doubles + 1;
12895                                        } else {
12896                                                pungetc();
12897#if BASH_REDIR_OUTPUT
12898                                                if (c == '&' && cc == '>') /* &> */
12899                                                        break; /* return readtoken1(...) */
12900#endif
12901                                        }
12902                                }
12903                        }
12904                        lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12905                        return lasttoken;
12906                }
12907        } /* for (;;) */
12908
12909        return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
12910}
12911#else /* old xxreadtoken */
12912#define RETURN(token)   return lasttoken = token
12913static int
12914xxreadtoken(void)
12915{
12916        int c;
12917
12918        if (tokpushback) {
12919                tokpushback = 0;
12920                return lasttoken;
12921        }
12922        setprompt_if(needprompt, 2);
12923        for (;;) {      /* until token or start of word found */
12924                c = pgetc_eatbnl();
12925                switch (c) {
12926                case ' ': case '\t':
12927                IF_ASH_ALIAS(case PEOA:)
12928                        continue;
12929                case '#':
12930                        while ((c = pgetc()) != '\n' && c != PEOF)
12931                                continue;
12932                        pungetc();
12933                        continue;
12934                case '\n':
12935                        nlnoprompt();
12936                        RETURN(TNL);
12937                case PEOF:
12938                        RETURN(TEOF);
12939                case '&':
12940                        if (pgetc_eatbnl() == '&')
12941                                RETURN(TAND);
12942                        pungetc();
12943                        RETURN(TBACKGND);
12944                case '|':
12945                        if (pgetc_eatbnl() == '|')
12946                                RETURN(TOR);
12947                        pungetc();
12948                        RETURN(TPIPE);
12949                case ';':
12950                        if (pgetc_eatbnl() == ';')
12951                                RETURN(TENDCASE);
12952                        pungetc();
12953                        RETURN(TSEMI);
12954                case '(':
12955                        RETURN(TLP);
12956                case ')':
12957                        RETURN(TRP);
12958                }
12959                break;
12960        }
12961        return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12962#undef RETURN
12963}
12964#endif /* old xxreadtoken */
12965
12966static int
12967readtoken(void)
12968{
12969        int t;
12970        int kwd = checkkwd;
12971#if DEBUG
12972        smallint alreadyseen = tokpushback;
12973#endif
12974
12975#if ENABLE_ASH_ALIAS
12976 top:
12977#endif
12978
12979        t = xxreadtoken();
12980
12981        /*
12982         * eat newlines
12983         */
12984        if (kwd & CHKNL) {
12985                while (t == TNL) {
12986                        parseheredoc();
12987                        t = xxreadtoken();
12988                }
12989        }
12990
12991        if (t != TWORD || quoteflag) {
12992                goto out;
12993        }
12994
12995        /*
12996         * check for keywords
12997         */
12998        if (kwd & CHKKWD) {
12999                const char *const *pp;
13000
13001                pp = findkwd(wordtext);
13002                if (pp) {
13003                        lasttoken = t = pp - tokname_array;
13004                        TRACE(("keyword '%s' recognized\n", tokname_array[t]));
13005                        goto out;
13006                }
13007        }
13008
13009        if (checkkwd & CHKALIAS) {
13010#if ENABLE_ASH_ALIAS
13011                struct alias *ap;
13012                ap = lookupalias(wordtext, 1);
13013                if (ap != NULL) {
13014                        if (*ap->val) {
13015                                pushstring(ap->val, ap);
13016                        }
13017                        goto top;
13018                }
13019#endif
13020        }
13021 out:
13022        checkkwd = 0;
13023#if DEBUG
13024        if (!alreadyseen)
13025                TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13026        else
13027                TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13028#endif
13029        return t;
13030}
13031
13032static int
13033peektoken(void)
13034{
13035        int t;
13036
13037        t = readtoken();
13038        tokpushback = 1;
13039        return t;
13040}
13041
13042/*
13043 * Read and parse a command.  Returns NODE_EOF on end of file.
13044 * (NULL is a valid parse tree indicating a blank line.)
13045 */
13046static union node *
13047parsecmd(int interact)
13048{
13049        tokpushback = 0;
13050        checkkwd = 0;
13051        heredoclist = 0;
13052        doprompt = interact;
13053        setprompt_if(doprompt, doprompt);
13054        needprompt = 0;
13055        return list(1);
13056}
13057
13058/*
13059 * Input any here documents.
13060 */
13061static void
13062parseheredoc(void)
13063{
13064        struct heredoc *here;
13065        union node *n;
13066
13067        here = heredoclist;
13068        heredoclist = NULL;
13069
13070        while (here) {
13071                tokpushback = 0;
13072                setprompt_if(needprompt, 2);
13073                readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
13074                                here->eofmark, here->striptabs);
13075                n = stzalloc(sizeof(struct narg));
13076                n->narg.type = NARG;
13077                /*n->narg.next = NULL; - stzalloc did it */
13078                n->narg.text = wordtext;
13079                n->narg.backquote = backquotelist;
13080                here->here->nhere.doc = n;
13081                here = here->next;
13082        }
13083}
13084
13085
13086static const char *
13087expandstr(const char *ps, int syntax_type)
13088{
13089        union node n;
13090        int saveprompt;
13091        struct parsefile *file_stop = g_parsefile;
13092        volatile int saveint;
13093        struct jmploc *volatile savehandler = exception_handler;
13094        struct jmploc jmploc;
13095
13096        /* XXX Fix (char *) cast. */
13097        setinputstring((char *)ps);
13098
13099        saveprompt = doprompt;
13100        doprompt = 0;
13101
13102        /* readtoken1() might die horribly.
13103         * Try a prompt with syntactically wrong command:
13104         * PS1='$(date "+%H:%M:%S) > '
13105         */
13106        SAVE_INT(saveint);
13107        if (setjmp(jmploc.loc) == 0) {
13108                exception_handler = &jmploc;
13109                readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
13110        }
13111        exception_handler = savehandler;
13112        RESTORE_INT(saveint);
13113
13114        doprompt = saveprompt;
13115
13116        /* Try: PS1='`xxx(`' */
13117        unwindfiles(file_stop);
13118
13119        n.narg.type = NARG;
13120        n.narg.next = NULL;
13121        n.narg.text = wordtext;
13122        n.narg.backquote = backquotelist;
13123
13124        /* expandarg() might fail too:
13125         * PS1='$((123+))'
13126         */
13127        SAVE_INT(saveint);
13128        if (setjmp(jmploc.loc) == 0) {
13129                exception_handler = &jmploc;
13130                expandarg(&n, NULL, EXP_QUOTED);
13131        } else if (exception_type == EXEXIT) {
13132                exitshell();
13133        }
13134        exception_handler = savehandler;
13135        RESTORE_INT(saveint);
13136
13137        return stackblock();
13138}
13139
13140static inline int
13141parser_eof(void)
13142{
13143        return tokpushback && lasttoken == TEOF;
13144}
13145
13146/*
13147 * Execute a command or commands contained in a string.
13148 */
13149static int
13150evalstring(char *s, int flags)
13151{
13152        struct jmploc *volatile savehandler;
13153        struct jmploc jmploc;
13154        int ex;
13155
13156        union node *n;
13157        struct stackmark smark;
13158        int status;
13159
13160        s = sstrdup(s);
13161        setinputstring(s);
13162        setstackmark(&smark);
13163
13164        status = 0;
13165        /* On exception inside execution loop, we must popfile().
13166         * Try interactively:
13167         *      readonly a=a
13168         *      command eval "a=b"  # throws "is read only" error
13169         * "command BLTIN" is not supposed to abort (even in non-interactive use).
13170         * But if we skip popfile(), we hit EOF in eval's string, and exit.
13171         */
13172        savehandler = exception_handler;
13173        ex = setjmp(jmploc.loc);
13174        if (ex)
13175                goto out;
13176        exception_handler = &jmploc;
13177
13178        while ((n = parsecmd(0)) != NODE_EOF) {
13179                int i;
13180
13181                i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
13182                if (n)
13183                        status = i;
13184                popstackmark(&smark);
13185                if (evalskip)
13186                        break;
13187        }
13188 out:
13189        popstackmark(&smark);
13190        popfile();
13191        stunalloc(s);
13192
13193        exception_handler = savehandler;
13194        if (ex)
13195                longjmp(exception_handler->loc, ex);
13196
13197        return status;
13198}
13199
13200/*
13201 * The eval command.
13202 */
13203static int FAST_FUNC
13204evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
13205{
13206        char *p;
13207        char *concat;
13208
13209        if (argv[1]) {
13210                p = argv[1];
13211                argv += 2;
13212                if (argv[0]) {
13213                        STARTSTACKSTR(concat);
13214                        for (;;) {
13215                                concat = stack_putstr(p, concat);
13216                                p = *argv++;
13217                                if (p == NULL)
13218                                        break;
13219                                STPUTC(' ', concat);
13220                        }
13221                        STPUTC('\0', concat);
13222                        p = grabstackstr(concat);
13223                }
13224                return evalstring(p, flags & EV_TESTED);
13225        }
13226        return 0;
13227}
13228
13229/*
13230 * Read and execute commands.
13231 * "Top" is nonzero for the top level command loop;
13232 * it turns on prompting if the shell is interactive.
13233 */
13234static int
13235cmdloop(int top)
13236{
13237        union node *n;
13238        struct stackmark smark;
13239        int inter;
13240        int status = 0;
13241        int numeof = 0;
13242
13243        TRACE(("cmdloop(%d) called\n", top));
13244        for (;;) {
13245                int skip;
13246
13247                setstackmark(&smark);
13248#if JOBS
13249                if (doing_jobctl)
13250                        showjobs(SHOW_CHANGED|SHOW_STDERR);
13251#endif
13252                inter = 0;
13253                if (iflag && top) {
13254                        inter++;
13255                        chkmail();
13256                }
13257                n = parsecmd(inter);
13258#if DEBUG
13259                if (DEBUG > 2 && debug && (n != NODE_EOF))
13260                        showtree(n);
13261#endif
13262                if (n == NODE_EOF) {
13263                        if (!top || numeof >= 50)
13264                                break;
13265                        if (!stoppedjobs()) {
13266                                if (!Iflag)
13267                                        break;
13268                                out2str("\nUse \"exit\" to leave shell.\n");
13269                        }
13270                        numeof++;
13271                } else if (nflag == 0) {
13272                        int i;
13273
13274                        /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13275                        job_warning >>= 1;
13276                        numeof = 0;
13277                        i = evaltree(n, 0);
13278                        if (n)
13279                                status = i;
13280                }
13281                popstackmark(&smark);
13282                skip = evalskip;
13283
13284                if (skip) {
13285                        evalskip &= ~SKIPFUNC;
13286                        break;
13287                }
13288        }
13289        return status;
13290}
13291
13292/*
13293 * Take commands from a file.  To be compatible we should do a path
13294 * search for the file, which is necessary to find sub-commands.
13295 */
13296static char *
13297find_dot_file(char *name)
13298{
13299        char *fullname;
13300        const char *path = pathval();
13301        struct stat statb;
13302
13303        /* don't try this for absolute or relative paths */
13304        if (strchr(name, '/'))
13305                return name;
13306
13307        while ((fullname = path_advance(&path, name)) != NULL) {
13308                if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
13309                        /*
13310                         * Don't bother freeing here, since it will
13311                         * be freed by the caller.
13312                         */
13313                        return fullname;
13314                }
13315                if (fullname != name)
13316                        stunalloc(fullname);
13317        }
13318        /* not found in PATH */
13319
13320#if ENABLE_ASH_BASH_SOURCE_CURDIR
13321        return name;
13322#else
13323        ash_msg_and_raise_error("%s: not found", name);
13324        /* NOTREACHED */
13325#endif
13326}
13327
13328static int FAST_FUNC
13329dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
13330{
13331        /* "false; . empty_file; echo $?" should print 0, not 1: */
13332        int status = 0;
13333        char *fullname;
13334        char **argv;
13335        char *args_need_save;
13336        volatile struct shparam saveparam;
13337
13338//???
13339//      struct strlist *sp;
13340//      for (sp = cmdenviron; sp; sp = sp->next)
13341//              setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
13342
13343        nextopt(nullstr); /* handle possible "--" */
13344        argv = argptr;
13345
13346        if (!argv[0]) {
13347                /* bash says: "bash: .: filename argument required" */
13348                return 2; /* bash compat */
13349        }
13350
13351        /* This aborts if file isn't found, which is POSIXly correct.
13352         * bash returns exitcode 1 instead.
13353         */
13354        fullname = find_dot_file(argv[0]);
13355        argv++;
13356        args_need_save = argv[0];
13357        if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
13358                int argc;
13359                saveparam = shellparam;
13360                shellparam.malloced = 0;
13361                argc = 1;
13362                while (argv[argc])
13363                        argc++;
13364                shellparam.nparam = argc;
13365                shellparam.p = argv;
13366        };
13367
13368        /* This aborts if file can't be opened, which is POSIXly correct.
13369         * bash returns exitcode 1 instead.
13370         */
13371        setinputfile(fullname, INPUT_PUSH_FILE);
13372        commandname = fullname;
13373        status = cmdloop(0);
13374        popfile();
13375
13376        if (args_need_save) {
13377                freeparam(&shellparam);
13378                shellparam = saveparam;
13379        };
13380
13381        return status;
13382}
13383
13384static int FAST_FUNC
13385exitcmd(int argc UNUSED_PARAM, char **argv)
13386{
13387        if (stoppedjobs())
13388                return 0;
13389        if (argv[1])
13390                exitstatus = number(argv[1]);
13391        raise_exception(EXEXIT);
13392        /* NOTREACHED */
13393}
13394
13395/*
13396 * Read a file containing shell functions.
13397 */
13398static void
13399readcmdfile(char *name)
13400{
13401        setinputfile(name, INPUT_PUSH_FILE);
13402        cmdloop(0);
13403        popfile();
13404}
13405
13406
13407/* ============ find_command inplementation */
13408
13409/*
13410 * Resolve a command name.  If you change this routine, you may have to
13411 * change the shellexec routine as well.
13412 */
13413static void
13414find_command(char *name, struct cmdentry *entry, int act, const char *path)
13415{
13416        struct tblentry *cmdp;
13417        int idx;
13418        int prev;
13419        char *fullname;
13420        struct stat statb;
13421        int e;
13422        int updatetbl;
13423        struct builtincmd *bcmd;
13424
13425        /* If name contains a slash, don't use PATH or hash table */
13426        if (strchr(name, '/') != NULL) {
13427                entry->u.index = -1;
13428                if (act & DO_ABS) {
13429                        while (stat(name, &statb) < 0) {
13430#ifdef SYSV
13431                                if (errno == EINTR)
13432                                        continue;
13433#endif
13434                                entry->cmdtype = CMDUNKNOWN;
13435                                return;
13436                        }
13437                }
13438                entry->cmdtype = CMDNORMAL;
13439                return;
13440        }
13441
13442/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
13443
13444        updatetbl = (path == pathval());
13445        if (!updatetbl) {
13446                act |= DO_ALTPATH;
13447                if (strstr(path, "%builtin") != NULL)
13448                        act |= DO_ALTBLTIN;
13449        }
13450
13451        /* If name is in the table, check answer will be ok */
13452        cmdp = cmdlookup(name, 0);
13453        if (cmdp != NULL) {
13454                int bit;
13455
13456                switch (cmdp->cmdtype) {
13457                default:
13458#if DEBUG
13459                        abort();
13460#endif
13461                case CMDNORMAL:
13462                        bit = DO_ALTPATH;
13463                        break;
13464                case CMDFUNCTION:
13465                        bit = DO_NOFUNC;
13466                        break;
13467                case CMDBUILTIN:
13468                        bit = DO_ALTBLTIN;
13469                        break;
13470                }
13471                if (act & bit) {
13472                        updatetbl = 0;
13473                        cmdp = NULL;
13474                } else if (cmdp->rehash == 0)
13475                        /* if not invalidated by cd, we're done */
13476                        goto success;
13477        }
13478
13479        /* If %builtin not in path, check for builtin next */
13480        bcmd = find_builtin(name);
13481        if (bcmd) {
13482                if (IS_BUILTIN_REGULAR(bcmd))
13483                        goto builtin_success;
13484                if (act & DO_ALTPATH) {
13485                        if (!(act & DO_ALTBLTIN))
13486                                goto builtin_success;
13487                } else if (builtinloc <= 0) {
13488                        goto builtin_success;
13489                }
13490        }
13491
13492#if ENABLE_FEATURE_SH_STANDALONE
13493        {
13494                int applet_no = find_applet_by_name(name);
13495                if (applet_no >= 0) {
13496                        entry->cmdtype = CMDNORMAL;
13497                        entry->u.index = -2 - applet_no;
13498                        return;
13499                }
13500        }
13501#endif
13502
13503        /* We have to search path. */
13504        prev = -1;              /* where to start */
13505        if (cmdp && cmdp->rehash) {     /* doing a rehash */
13506                if (cmdp->cmdtype == CMDBUILTIN)
13507                        prev = builtinloc;
13508                else
13509                        prev = cmdp->param.index;
13510        }
13511
13512        e = ENOENT;
13513        idx = -1;
13514 loop:
13515        while ((fullname = path_advance(&path, name)) != NULL) {
13516                stunalloc(fullname);
13517                /* NB: code below will still use fullname
13518                 * despite it being "unallocated" */
13519                idx++;
13520                if (pathopt) {
13521                        if (prefix(pathopt, "builtin")) {
13522                                if (bcmd)
13523                                        goto builtin_success;
13524                                continue;
13525                        }
13526                        if ((act & DO_NOFUNC)
13527                         || !prefix(pathopt, "func")
13528                        ) {     /* ignore unimplemented options */
13529                                continue;
13530                        }
13531                }
13532                /* if rehash, don't redo absolute path names */
13533                if (fullname[0] == '/' && idx <= prev) {
13534                        if (idx < prev)
13535                                continue;
13536                        TRACE(("searchexec \"%s\": no change\n", name));
13537                        goto success;
13538                }
13539                while (stat(fullname, &statb) < 0) {
13540#ifdef SYSV
13541                        if (errno == EINTR)
13542                                continue;
13543#endif
13544                        if (errno != ENOENT && errno != ENOTDIR)
13545                                e = errno;
13546                        goto loop;
13547                }
13548                e = EACCES;     /* if we fail, this will be the error */
13549                if (!S_ISREG(statb.st_mode))
13550                        continue;
13551                if (pathopt) {          /* this is a %func directory */
13552                        stalloc(strlen(fullname) + 1);
13553                        /* NB: stalloc will return space pointed by fullname
13554                         * (because we don't have any intervening allocations
13555                         * between stunalloc above and this stalloc) */
13556                        readcmdfile(fullname);
13557                        cmdp = cmdlookup(name, 0);
13558                        if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13559                                ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13560                        stunalloc(fullname);
13561                        goto success;
13562                }
13563                TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13564                if (!updatetbl) {
13565                        entry->cmdtype = CMDNORMAL;
13566                        entry->u.index = idx;
13567                        return;
13568                }
13569                INT_OFF;
13570                cmdp = cmdlookup(name, 1);
13571                cmdp->cmdtype = CMDNORMAL;
13572                cmdp->param.index = idx;
13573                INT_ON;
13574                goto success;
13575        }
13576
13577        /* We failed.  If there was an entry for this command, delete it */
13578        if (cmdp && updatetbl)
13579                delete_cmd_entry();
13580        if (act & DO_ERR) {
13581#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13582                struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13583                if (hookp && hookp->cmdtype == CMDFUNCTION) {
13584                        char *argv[3];
13585                        argv[0] = (char*) "command_not_found_handle";
13586                        argv[1] = name;
13587                        argv[2] = NULL;
13588                        evalfun(hookp->param.func, 2, argv, 0);
13589                        entry->cmdtype = CMDUNKNOWN;
13590                        return;
13591                }
13592#endif
13593                ash_msg("%s: %s", name, errmsg(e, "not found"));
13594        }
13595        entry->cmdtype = CMDUNKNOWN;
13596        return;
13597
13598 builtin_success:
13599        if (!updatetbl) {
13600                entry->cmdtype = CMDBUILTIN;
13601                entry->u.cmd = bcmd;
13602                return;
13603        }
13604        INT_OFF;
13605        cmdp = cmdlookup(name, 1);
13606        cmdp->cmdtype = CMDBUILTIN;
13607        cmdp->param.cmd = bcmd;
13608        INT_ON;
13609 success:
13610        cmdp->rehash = 0;
13611        entry->cmdtype = cmdp->cmdtype;
13612        entry->u = cmdp->param;
13613}
13614
13615
13616/*
13617 * The trap builtin.
13618 */
13619static int FAST_FUNC
13620trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13621{
13622        char *action;
13623        char **ap;
13624        int signo, exitcode;
13625
13626        nextopt(nullstr);
13627        ap = argptr;
13628        if (!*ap) {
13629                for (signo = 0; signo < NSIG; signo++) {
13630                        char *tr = trap_ptr[signo];
13631                        if (tr) {
13632                                /* note: bash adds "SIG", but only if invoked
13633                                 * as "bash". If called as "sh", or if set -o posix,
13634                                 * then it prints short signal names.
13635                                 * We are printing short names: */
13636                                out1fmt("trap -- %s %s\n",
13637                                                single_quote(tr),
13638                                                get_signame(signo));
13639                /* trap_ptr != trap only if we are in special-cased `trap` code.
13640                 * In this case, we will exit very soon, no need to free(). */
13641                                /* if (trap_ptr != trap && tp[0]) */
13642                                /*      free(tr); */
13643                        }
13644                }
13645                /*
13646                if (trap_ptr != trap) {
13647                        free(trap_ptr);
13648                        trap_ptr = trap;
13649                }
13650                */
13651                return 0;
13652        }
13653
13654        /* Why the second check?
13655         * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13656         * In this case, NUM is signal no, not an action.
13657         */
13658        action = NULL;
13659        if (ap[1] && !is_number(ap[0]))
13660                action = *ap++;
13661
13662        exitcode = 0;
13663        while (*ap) {
13664                signo = get_signum(*ap);
13665                if (signo < 0) {
13666                        /* Mimic bash message exactly */
13667                        ash_msg("%s: invalid signal specification", *ap);
13668                        exitcode = 1;
13669                        goto next;
13670                }
13671                INT_OFF;
13672                if (action) {
13673                        if (LONE_DASH(action))
13674                                action = NULL;
13675                        else {
13676                                if (action[0]) /* not NULL and not "" and not "-" */
13677                                        may_have_traps = 1;
13678                                action = ckstrdup(action);
13679                        }
13680                }
13681                free(trap[signo]);
13682                trap[signo] = action;
13683                if (signo != 0)
13684                        setsignal(signo);
13685                INT_ON;
13686 next:
13687                ap++;
13688        }
13689        return exitcode;
13690}
13691
13692
13693/* ============ Builtins */
13694
13695#if ENABLE_ASH_HELP
13696static int FAST_FUNC
13697helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13698{
13699        unsigned col;
13700        unsigned i;
13701
13702        out1fmt(
13703                "Built-in commands:\n"
13704                "------------------\n");
13705        for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
13706                col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
13707                                        builtintab[i].name + 1);
13708                if (col > 60) {
13709                        out1fmt("\n");
13710                        col = 0;
13711                }
13712        }
13713# if ENABLE_FEATURE_SH_STANDALONE
13714        {
13715                const char *a = applet_names;
13716                while (*a) {
13717                        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13718                        if (col > 60) {
13719                                out1fmt("\n");
13720                                col = 0;
13721                        }
13722                        while (*a++ != '\0')
13723                                continue;
13724                }
13725        }
13726# endif
13727        newline_and_flush(stdout);
13728        return EXIT_SUCCESS;
13729}
13730#endif
13731
13732#if MAX_HISTORY
13733static int FAST_FUNC
13734historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13735{
13736        if (line_input_state)
13737                show_history(line_input_state);
13738        return EXIT_SUCCESS;
13739}
13740#endif
13741
13742/*
13743 * The export and readonly commands.
13744 */
13745static int FAST_FUNC
13746exportcmd(int argc UNUSED_PARAM, char **argv)
13747{
13748        struct var *vp;
13749        char *name;
13750        const char *p;
13751        char **aptr;
13752        char opt;
13753        int flag;
13754        int flag_off;
13755
13756        /* "readonly" in bash accepts, but ignores -n.
13757         * We do the same: it saves a conditional in nextopt's param.
13758         */
13759        flag_off = 0;
13760        while ((opt = nextopt("np")) != '\0') {
13761                if (opt == 'n')
13762                        flag_off = VEXPORT;
13763        }
13764        flag = VEXPORT;
13765        if (argv[0][0] == 'r') {
13766                flag = VREADONLY;
13767                flag_off = 0; /* readonly ignores -n */
13768        }
13769        flag_off = ~flag_off;
13770
13771        /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
13772        {
13773                aptr = argptr;
13774                name = *aptr;
13775                if (name) {
13776                        do {
13777                                p = strchr(name, '=');
13778                                if (p != NULL) {
13779                                        p++;
13780                                } else {
13781                                        vp = *findvar(hashvar(name), name);
13782                                        if (vp) {
13783                                                vp->flags = ((vp->flags | flag) & flag_off);
13784                                                continue;
13785                                        }
13786                                }
13787                                setvar(name, p, (flag & flag_off));
13788                        } while ((name = *++aptr) != NULL);
13789                        return 0;
13790                }
13791        }
13792
13793        /* No arguments. Show the list of exported or readonly vars.
13794         * -n is ignored.
13795         */
13796        showvars(argv[0], flag, 0);
13797        return 0;
13798}
13799
13800/*
13801 * Delete a function if it exists.
13802 */
13803static void
13804unsetfunc(const char *name)
13805{
13806        struct tblentry *cmdp;
13807
13808        cmdp = cmdlookup(name, 0);
13809        if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
13810                delete_cmd_entry();
13811}
13812
13813/*
13814 * The unset builtin command.  We unset the function before we unset the
13815 * variable to allow a function to be unset when there is a readonly variable
13816 * with the same name.
13817 */
13818static int FAST_FUNC
13819unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13820{
13821        char **ap;
13822        int i;
13823        int flag = 0;
13824
13825        while ((i = nextopt("vf")) != 0) {
13826                flag = i;
13827        }
13828
13829        for (ap = argptr; *ap; ap++) {
13830                if (flag != 'f') {
13831                        unsetvar(*ap);
13832                        continue;
13833                }
13834                if (flag != 'v')
13835                        unsetfunc(*ap);
13836        }
13837        return 0;
13838}
13839
13840static const unsigned char timescmd_str[] ALIGN1 = {
13841        ' ',  offsetof(struct tms, tms_utime),
13842        '\n', offsetof(struct tms, tms_stime),
13843        ' ',  offsetof(struct tms, tms_cutime),
13844        '\n', offsetof(struct tms, tms_cstime),
13845        0
13846};
13847static int FAST_FUNC
13848timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13849{
13850        unsigned clk_tck;
13851        const unsigned char *p;
13852        struct tms buf;
13853
13854        clk_tck = bb_clk_tck();
13855
13856        times(&buf);
13857        p = timescmd_str;
13858        do {
13859                unsigned sec, frac;
13860                unsigned long t;
13861                t = *(clock_t *)(((char *) &buf) + p[1]);
13862                sec = t / clk_tck;
13863                frac = t % clk_tck;
13864                out1fmt("%um%u.%03us%c",
13865                        sec / 60, sec % 60,
13866                        (frac * 1000) / clk_tck,
13867                        p[0]);
13868                p += 2;
13869        } while (*p);
13870
13871        return 0;
13872}
13873
13874#if ENABLE_FEATURE_SH_MATH
13875/*
13876 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
13877 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
13878 *
13879 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13880 */
13881static int FAST_FUNC
13882letcmd(int argc UNUSED_PARAM, char **argv)
13883{
13884        arith_t i;
13885
13886        argv++;
13887        if (!*argv)
13888                ash_msg_and_raise_error("expression expected");
13889        do {
13890                i = ash_arith(*argv);
13891        } while (*++argv);
13892
13893        return !i;
13894}
13895#endif
13896
13897/*
13898 * The read builtin. Options:
13899 *      -r              Do not interpret '\' specially
13900 *      -s              Turn off echo (tty only)
13901 *      -n NCHARS       Read NCHARS max
13902 *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
13903 *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
13904 *      -u FD           Read from given FD instead of fd 0
13905 *      -d DELIM        End on DELIM char, not newline
13906 * This uses unbuffered input, which may be avoidable in some cases.
13907 * TODO: bash also has:
13908 *      -a ARRAY        Read into array[0],[1],etc
13909 *      -e              Use line editing (tty only)
13910 */
13911static int FAST_FUNC
13912readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13913{
13914        struct builtin_read_params params;
13915        const char *r;
13916        int i;
13917
13918        memset(&params, 0, sizeof(params));
13919
13920        while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
13921                switch (i) {
13922                case 'p':
13923                        params.opt_p = optionarg;
13924                        break;
13925                case 'n':
13926                        params.opt_n = optionarg;
13927                        break;
13928                case 's':
13929                        params.read_flags |= BUILTIN_READ_SILENT;
13930                        break;
13931                case 't':
13932                        params.opt_t = optionarg;
13933                        break;
13934                case 'r':
13935                        params.read_flags |= BUILTIN_READ_RAW;
13936                        break;
13937                case 'u':
13938                        params.opt_u = optionarg;
13939                        break;
13940#if BASH_READ_D
13941                case 'd':
13942                        params.opt_d = optionarg;
13943                        break;
13944#endif
13945                default:
13946                        break;
13947                }
13948        }
13949
13950        params.argv = argptr;
13951        params.setvar = setvar0;
13952        params.ifs = bltinlookup("IFS"); /* can be NULL */
13953
13954        /* "read -s" needs to save/restore termios, can't allow ^C
13955         * to jump out of it.
13956         */
13957 again:
13958        INT_OFF;
13959        r = shell_builtin_read(&params);
13960        INT_ON;
13961
13962        if ((uintptr_t)r == 1 && errno == EINTR) {
13963                /* To get SIGCHLD: sleep 1 & read x; echo $x
13964                 * Correct behavior is to not exit "read"
13965                 */
13966                if (pending_sig == 0)
13967                        goto again;
13968        }
13969
13970        if ((uintptr_t)r > 1)
13971                ash_msg_and_raise_error(r);
13972
13973        return (uintptr_t)r;
13974}
13975
13976static int FAST_FUNC
13977umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13978{
13979        static const char permuser[3] ALIGN1 = "ogu";
13980
13981        mode_t mask;
13982        int symbolic_mode = 0;
13983
13984        while (nextopt("S") != '\0') {
13985                symbolic_mode = 1;
13986        }
13987
13988        INT_OFF;
13989        mask = umask(0);
13990        umask(mask);
13991        INT_ON;
13992
13993        if (*argptr == NULL) {
13994                if (symbolic_mode) {
13995                        char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
13996                        char *p = buf;
13997                        int i;
13998
13999                        i = 2;
14000                        for (;;) {
14001                                *p++ = ',';
14002                                *p++ = permuser[i];
14003                                *p++ = '=';
14004                                /* mask is 0..0uuugggooo. i=2 selects uuu bits */
14005                                if (!(mask & 0400)) *p++ = 'r';
14006                                if (!(mask & 0200)) *p++ = 'w';
14007                                if (!(mask & 0100)) *p++ = 'x';
14008                                mask <<= 3;
14009                                if (--i < 0)
14010                                        break;
14011                        }
14012                        *p = '\0';
14013                        puts(buf + 1);
14014                } else {
14015                        out1fmt("%04o\n", mask);
14016                }
14017        } else {
14018                char *modestr = *argptr;
14019                /* numeric umasks are taken as-is */
14020                /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
14021                if (!isdigit(modestr[0]))
14022                        mask ^= 0777;
14023                mask = bb_parse_mode(modestr, mask);
14024                if ((unsigned)mask > 0777) {
14025                        ash_msg_and_raise_error("illegal mode: %s", modestr);
14026                }
14027                if (!isdigit(modestr[0]))
14028                        mask ^= 0777;
14029                umask(mask);
14030        }
14031        return 0;
14032}
14033
14034static int FAST_FUNC
14035ulimitcmd(int argc UNUSED_PARAM, char **argv)
14036{
14037        return shell_builtin_ulimit(argv);
14038}
14039
14040/* ============ main() and helpers */
14041
14042/*
14043 * Called to exit the shell.
14044 */
14045static void
14046exitshell(void)
14047{
14048        struct jmploc loc;
14049        char *p;
14050        int status;
14051
14052#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
14053        if (line_input_state)
14054                save_history(line_input_state);
14055#endif
14056        status = exitstatus;
14057        TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
14058        if (setjmp(loc.loc)) {
14059                if (exception_type == EXEXIT)
14060                        status = exitstatus;
14061                goto out;
14062        }
14063        exception_handler = &loc;
14064        p = trap[0];
14065        if (p) {
14066                trap[0] = NULL;
14067                evalskip = 0;
14068                evalstring(p, 0);
14069                /*free(p); - we'll exit soon */
14070        }
14071 out:
14072        /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14073         * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
14074         */
14075        setjobctl(0);
14076        flush_stdout_stderr();
14077        _exit(status);
14078        /* NOTREACHED */
14079}
14080
14081/* Don't inline: conserve stack of caller from having our locals too */
14082static NOINLINE void
14083init(void)
14084{
14085        /* we will never free this */
14086        basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
14087        basepf.linno = 1;
14088
14089        sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
14090        setsignal(SIGCHLD);
14091
14092        /* bash re-enables SIGHUP which is SIG_IGNed on entry.
14093         * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
14094         */
14095        signal(SIGHUP, SIG_DFL);
14096
14097        {
14098                char **envp;
14099                const char *p;
14100
14101                initvar();
14102                for (envp = environ; envp && *envp; envp++) {
14103/* Used to have
14104 *                      p = endofname(*envp);
14105 *                      if (p != *envp && *p == '=') {
14106 * here to weed out badly-named variables, but this breaks
14107 * scenarios where people do want them passed to children:
14108 * import os
14109 * os.environ["test-test"]="test"
14110 * if os.fork() == 0:
14111 *   os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ])  # fixes this
14112 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])  # breaks this
14113 */
14114                        if (strchr(*envp, '=')) {
14115                                setvareq(*envp, VEXPORT|VTEXTFIXED);
14116                        }
14117                }
14118
14119                setvareq((char*)defifsvar, VTEXTFIXED);
14120                setvareq((char*)defoptindvar, VTEXTFIXED);
14121
14122                setvar0("PPID", utoa(getppid()));
14123#if BASH_SHLVL_VAR
14124                p = lookupvar("SHLVL");
14125                setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
14126#endif
14127#if BASH_HOSTNAME_VAR
14128                if (!lookupvar("HOSTNAME")) {
14129                        struct utsname uts;
14130                        uname(&uts);
14131                        setvar0("HOSTNAME", uts.nodename);
14132                }
14133#endif
14134                p = lookupvar("PWD");
14135                if (p) {
14136                        struct stat st1, st2;
14137                        if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
14138                         || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14139                        ) {
14140                                p = NULL;
14141                        }
14142                }
14143                setpwd(p, 0);
14144        }
14145}
14146
14147
14148//usage:#define ash_trivial_usage
14149//usage:        "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
14150//usage:#define ash_full_usage "\n\n"
14151//usage:        "Unix shell interpreter"
14152
14153/*
14154 * Process the shell command line arguments.
14155 */
14156static int
14157procargs(char **argv)
14158{
14159        int i;
14160        const char *xminusc;
14161        char **xargv;
14162        int login_sh;
14163
14164        xargv = argv;
14165        login_sh = xargv[0] && xargv[0][0] == '-';
14166#if NUM_SCRIPTS > 0
14167        if (minusc)
14168                goto setarg0;
14169#endif
14170        arg0 = xargv[0];
14171        /* if (xargv[0]) - mmm, this is always true! */
14172                xargv++;
14173        argptr = xargv;
14174        for (i = 0; i < NOPTS; i++)
14175                optlist[i] = 2;
14176        if (options(&login_sh)) {
14177                /* it already printed err message */
14178                raise_exception(EXERROR);
14179        }
14180        xargv = argptr;
14181        xminusc = minusc;
14182        if (*xargv == NULL) {
14183                if (xminusc)
14184                        ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14185                sflag = 1;
14186        }
14187        if (iflag == 2 /* no explicit -i given */
14188         && sflag == 1 /* -s given (or implied) */
14189         && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */
14190         && isatty(0) && isatty(1) /* we are on tty */
14191        ) {
14192                iflag = 1;
14193        }
14194        if (mflag == 2)
14195                mflag = iflag;
14196        for (i = 0; i < NOPTS; i++)
14197                if (optlist[i] == 2)
14198                        optlist[i] = 0;
14199#if DEBUG == 2
14200        debug = 1;
14201#endif
14202        /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
14203        if (xminusc) {
14204                minusc = *xargv++;
14205                if (*xargv)
14206                        goto setarg0;
14207        } else if (!sflag) {
14208                setinputfile(*xargv, 0);
14209 setarg0:
14210                arg0 = *xargv++;
14211                commandname = arg0;
14212        }
14213
14214        shellparam.p = xargv;
14215#if ENABLE_ASH_GETOPTS
14216        shellparam.optind = 1;
14217        shellparam.optoff = -1;
14218#endif
14219        /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
14220        while (*xargv) {
14221                shellparam.nparam++;
14222                xargv++;
14223        }
14224        optschanged();
14225
14226        return login_sh;
14227}
14228
14229/*
14230 * Read /etc/profile, ~/.profile, $ENV.
14231 */
14232static void
14233read_profile(const char *name)
14234{
14235        name = expandstr(name, DQSYNTAX);
14236        if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14237                return;
14238        cmdloop(0);
14239        popfile();
14240}
14241
14242/*
14243 * This routine is called when an error or an interrupt occurs in an
14244 * interactive shell and control is returned to the main command loop.
14245 * (In dash, this function is auto-generated by build machinery).
14246 */
14247static void
14248reset(void)
14249{
14250        /* from eval.c: */
14251        evalskip = 0;
14252        loopnest = 0;
14253
14254        /* from expand.c: */
14255        ifsfree();
14256
14257        /* from input.c: */
14258        g_parsefile->left_in_buffer = 0;
14259        g_parsefile->left_in_line = 0;      /* clear input buffer */
14260        popallfiles();
14261
14262        /* from redir.c: */
14263        unwindredir(NULL);
14264
14265        /* from var.c: */
14266        unwindlocalvars(NULL);
14267}
14268
14269#if PROFILE
14270static short profile_buf[16384];
14271extern int etext();
14272#endif
14273
14274/*
14275 * Main routine.  We initialize things, parse the arguments, execute
14276 * profiles if we're a login shell, and then call cmdloop to execute
14277 * commands.  The setjmp call sets up the location to jump to when an
14278 * exception occurs.  When an exception occurs the variable "state"
14279 * is used to figure out how far we had gotten.
14280 */
14281int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14282#if NUM_SCRIPTS > 0
14283int ash_main(int argc, char **argv)
14284#else
14285int ash_main(int argc UNUSED_PARAM, char **argv)
14286#endif
14287/* note: 'argc' is used only if embedded scripts are enabled */
14288{
14289        volatile smallint state;
14290        struct jmploc jmploc;
14291        struct stackmark smark;
14292        int login_sh;
14293
14294        /* Initialize global data */
14295        INIT_G_misc();
14296        INIT_G_memstack();
14297        INIT_G_var();
14298#if ENABLE_ASH_ALIAS
14299        INIT_G_alias();
14300#endif
14301        INIT_G_cmdtable();
14302
14303#if PROFILE
14304        monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14305#endif
14306
14307        state = 0;
14308        if (setjmp(jmploc.loc)) {
14309                smallint e;
14310                smallint s;
14311
14312                reset();
14313
14314                e = exception_type;
14315                s = state;
14316                if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
14317                        exitshell();
14318                }
14319                if (e == EXINT) {
14320                        newline_and_flush(stderr);
14321                }
14322
14323                popstackmark(&smark);
14324                FORCE_INT_ON; /* enable interrupts */
14325                if (s == 1)
14326                        goto state1;
14327                if (s == 2)
14328                        goto state2;
14329                if (s == 3)
14330                        goto state3;
14331                goto state4;
14332        }
14333        exception_handler = &jmploc;
14334        rootpid = getpid();
14335
14336        init();
14337        setstackmark(&smark);
14338
14339#if NUM_SCRIPTS > 0
14340        if (argc < 0)
14341                /* Non-NULL minusc tells procargs that an embedded script is being run */
14342                minusc = get_script_content(-argc - 1);
14343#endif
14344        login_sh = procargs(argv);
14345#if DEBUG
14346        TRACE(("Shell args: "));
14347        trace_puts_args(argv);
14348#endif
14349
14350        if (login_sh) {
14351                const char *hp;
14352
14353                state = 1;
14354                read_profile("/etc/profile");
14355 state1:
14356                state = 2;
14357                hp = lookupvar("HOME");
14358                if (hp)
14359                        read_profile("$HOME/.profile");
14360        }
14361 state2:
14362        state = 3;
14363        if (
14364#ifndef linux
14365         getuid() == geteuid() && getgid() == getegid() &&
14366#endif
14367         iflag
14368        ) {
14369                const char *shinit = lookupvar("ENV");
14370                if (shinit != NULL && *shinit != '\0')
14371                        read_profile(shinit);
14372        }
14373        popstackmark(&smark);
14374 state3:
14375        state = 4;
14376        if (minusc) {
14377                /* evalstring pushes parsefile stack.
14378                 * Ensure we don't falsely claim that 0 (stdin)
14379                 * is one of stacked source fds.
14380                 * Testcase: ash -c 'exec 1>&0' must not complain. */
14381
14382                // if (!sflag) g_parsefile->pf_fd = -1;
14383                // ^^ not necessary since now we special-case fd 0
14384                // in save_fd_on_redirect()
14385
14386                // dash: evalstring(minusc, sflag ? 0 : EV_EXIT);
14387                // The above makes
14388                //  ash -sc 'echo $-'
14389                // continue reading input from stdin after running 'echo'.
14390                // bash does not do this: it prints "hBcs" and exits.
14391                evalstring(minusc, EV_EXIT);
14392        }
14393
14394        if (sflag || minusc == NULL) {
14395#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
14396                if (iflag) {
14397                        const char *hp = lookupvar("HISTFILE");
14398                        if (!hp) {
14399                                hp = lookupvar("HOME");
14400                                if (hp) {
14401                                        INT_OFF;
14402                                        hp = concat_path_file(hp, ".ash_history");
14403                                        setvar0("HISTFILE", hp);
14404                                        free((char*)hp);
14405                                        INT_ON;
14406                                        hp = lookupvar("HISTFILE");
14407                                }
14408                        }
14409                        if (hp)
14410                                line_input_state->hist_file = hp;
14411# if ENABLE_FEATURE_SH_HISTFILESIZE
14412                        hp = lookupvar("HISTFILESIZE");
14413                        line_input_state->max_history = size_from_HISTFILESIZE(hp);
14414# endif
14415                }
14416#endif
14417 state4: /* XXX ??? - why isn't this before the "if" statement */
14418                cmdloop(1);
14419        }
14420#if PROFILE
14421        monitor(0);
14422#endif
14423#ifdef GPROF
14424        {
14425                extern void _mcleanup(void);
14426                _mcleanup();
14427        }
14428#endif
14429        TRACE(("End of main reached\n"));
14430        exitshell();
14431        /* NOTREACHED */
14432}
14433
14434
14435/*-
14436 * Copyright (c) 1989, 1991, 1993, 1994
14437 *      The Regents of the University of California.  All rights reserved.
14438 *
14439 * This code is derived from software contributed to Berkeley by
14440 * Kenneth Almquist.
14441 *
14442 * Redistribution and use in source and binary forms, with or without
14443 * modification, are permitted provided that the following conditions
14444 * are met:
14445 * 1. Redistributions of source code must retain the above copyright
14446 *    notice, this list of conditions and the following disclaimer.
14447 * 2. Redistributions in binary form must reproduce the above copyright
14448 *    notice, this list of conditions and the following disclaimer in the
14449 *    documentation and/or other materials provided with the distribution.
14450 * 3. Neither the name of the University nor the names of its contributors
14451 *    may be used to endorse or promote products derived from this software
14452 *    without specific prior written permission.
14453 *
14454 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
14455 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14456 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14457 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14458 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14459 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14460 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14461 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14462 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14463 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14464 * SUCH DAMAGE.
14465 */
14466