busybox/shell/ash.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * ash shell port for busybox
   4 *
   5 * This code is derived from software contributed to Berkeley by
   6 * Kenneth Almquist.
   7 *
   8 * Original BSD copyright notice is retained at the end of this file.
   9 *
  10 * Copyright (c) 1989, 1991, 1993, 1994
  11 *      The Regents of the University of California.  All rights reserved.
  12 *
  13 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
  14 * was re-ported from NetBSD and debianized.
  15 *
  16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  17 */
  18//config:config SHELL_ASH
  19//config:       bool #hidden option
  20//config:       depends on !NOMMU
  21//config:
  22//config:config ASH
  23//config:       bool "ash (78 kb)"
  24//config:       default y
  25//config:       depends on !NOMMU
  26//config:       select SHELL_ASH
  27//config:       help
  28//config:       The most complete and most pedantically correct shell included with
  29//config:       busybox. This shell is actually a derivative of the Debian 'dash'
  30//config:       shell (by Herbert Xu), which was created by porting the 'ash' shell
  31//config:       (written by Kenneth Almquist) from NetBSD.
  32//config:
  33//config:# ash options
  34//config:# note: Don't remove !NOMMU part in the next line; it would break
  35//config:# menuconfig's indenting.
  36//config:if !NOMMU && (SHELL_ASH || ASH || SH_IS_ASH || BASH_IS_ASH)
  37//config:
  38//config:config ASH_OPTIMIZE_FOR_SIZE
  39//config:       bool "Optimize for size instead of speed"
  40//config:       default y
  41//config:       depends on SHELL_ASH
  42//config:
  43//config:config ASH_INTERNAL_GLOB
  44//config:       bool "Use internal glob() implementation"
  45//config:       default y       # Y is bigger, but because of uclibc glob() bug, let Y be default for now
  46//config:       depends on SHELL_ASH
  47//config:       help
  48//config:       Do not use glob() function from libc, use internal implementation.
  49//config:       Use this if you are getting "glob.h: No such file or directory"
  50//config:       or similar build errors.
  51//config:       Note that as of now (2017-01), uclibc and musl glob() both have bugs
  52//config:       which would break ash if you select N here.
  53//config:
  54//config:config ASH_BASH_COMPAT
  55//config:       bool "bash-compatible extensions"
  56//config:       default y
  57//config:       depends on SHELL_ASH
  58//config:
  59//config:config ASH_BASH_SOURCE_CURDIR
  60//config:       bool "'source' and '.' builtins search current directory after $PATH"
  61//config:       default n   # do not encourage non-standard behavior
  62//config:       depends on ASH_BASH_COMPAT
  63//config:       help
  64//config:       This is not compliant with standards. Avoid if possible.
  65//config:
  66//config:config ASH_BASH_NOT_FOUND_HOOK
  67//config:       bool "command_not_found_handle hook support"
  68//config:       default y
  69//config:       depends on ASH_BASH_COMPAT
  70//config:       help
  71//config:       Enable support for the 'command_not_found_handle' hook function,
  72//config:       from GNU bash, which allows for alternative command not found
  73//config:       handling.
  74//config:
  75//config:config ASH_JOB_CONTROL
  76//config:       bool "Job control"
  77//config:       default y
  78//config:       depends on SHELL_ASH
  79//config:
  80//config:config ASH_ALIAS
  81//config:       bool "Alias support"
  82//config:       default y
  83//config:       depends on SHELL_ASH
  84//config:
  85//config:config ASH_RANDOM_SUPPORT
  86//config:       bool "Pseudorandom generator and $RANDOM variable"
  87//config:       default y
  88//config:       depends on SHELL_ASH
  89//config:       help
  90//config:       Enable pseudorandom generator and dynamic variable "$RANDOM".
  91//config:       Each read of "$RANDOM" will generate a new pseudorandom value.
  92//config:       You can reset the generator by using a specified start value.
  93//config:       After "unset RANDOM" the generator will switch off and this
  94//config:       variable will no longer have special treatment.
  95//config:
  96//config:config ASH_EXPAND_PRMT
  97//config:       bool "Expand prompt string"
  98//config:       default y
  99//config:       depends on SHELL_ASH
 100//config:       help
 101//config:       $PS# may contain volatile content, such as backquote commands.
 102//config:       This option recreates the prompt string from the environment
 103//config:       variable each time it is displayed.
 104//config:
 105//config:config ASH_IDLE_TIMEOUT
 106//config:       bool "Idle timeout variable $TMOUT"
 107//config:       default y
 108//config:       depends on SHELL_ASH
 109//config:       help
 110//config:       Enable bash-like auto-logout after $TMOUT seconds of idle time.
 111//config:
 112//config:config ASH_MAIL
 113//config:       bool "Check for new mail in interactive shell"
 114//config:       default y
 115//config:       depends on SHELL_ASH
 116//config:       help
 117//config:       Enable "check for new mail" function:
 118//config:       if set, $MAIL file and $MAILPATH list of files
 119//config:       are checked for mtime changes, and "you have mail"
 120//config:       message is printed if change is detected.
 121//config:
 122//config:config ASH_ECHO
 123//config:       bool "echo builtin"
 124//config:       default y
 125//config:       depends on SHELL_ASH
 126//config:
 127//config:config ASH_PRINTF
 128//config:       bool "printf builtin"
 129//config:       default y
 130//config:       depends on SHELL_ASH
 131//config:
 132//config:config ASH_TEST
 133//config:       bool "test builtin"
 134//config:       default y
 135//config:       depends on SHELL_ASH
 136//config:
 137//config:config ASH_HELP
 138//config:       bool "help builtin"
 139//config:       default y
 140//config:       depends on SHELL_ASH
 141//config:
 142//config:config ASH_GETOPTS
 143//config:       bool "getopts builtin"
 144//config:       default y
 145//config:       depends on SHELL_ASH
 146//config:
 147//config:config ASH_CMDCMD
 148//config:       bool "command builtin"
 149//config:       default y
 150//config:       depends on SHELL_ASH
 151//config:       help
 152//config:       Enable support for the 'command' builtin, which allows
 153//config:       you to run the specified command or builtin,
 154//config:       even when there is a function with the same name.
 155//config:
 156//config:endif # ash options
 157
 158//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
 159//                      APPLET_ODDNAME:name  main location    suid_type     help
 160//applet:IF_SH_IS_ASH(  APPLET_ODDNAME(sh,   ash, BB_DIR_BIN, BB_SUID_DROP, ash))
 161//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
 162
 163//kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o
 164//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
 165
 166/*
 167 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
 168 * DEBUG=2 to compile in and turn on debugging.
 169 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
 170 * debugging info is written to ./trace, quit signal generates core dump.
 171 */
 172#define DEBUG 0
 173/* Tweak debug output verbosity here */
 174#define DEBUG_TIME 0
 175#define DEBUG_PID 1
 176#define DEBUG_SIG 1
 177#define DEBUG_INTONOFF 0
 178
 179#define PROFILE 0
 180
 181#define JOBS ENABLE_ASH_JOB_CONTROL
 182
 183#include <fnmatch.h>
 184#include <sys/times.h>
 185#include <sys/utsname.h> /* for setting $HOSTNAME */
 186#include "busybox.h" /* for applet_names */
 187#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
 188# include "embedded_scripts.h"
 189#else
 190# define NUM_SCRIPTS 0
 191#endif
 192
 193/* So far, all bash compat is controlled by one config option */
 194/* Separate defines document which part of code implements what */
 195/* function keyword */
 196#define    BASH_FUNCTION        ENABLE_ASH_BASH_COMPAT
 197#define IF_BASH_FUNCTION            IF_ASH_BASH_COMPAT
 198/* &>file */
 199#define    BASH_REDIR_OUTPUT    ENABLE_ASH_BASH_COMPAT
 200#define IF_BASH_REDIR_OUTPUT        IF_ASH_BASH_COMPAT
 201/* $'...' */
 202#define    BASH_DOLLAR_SQUOTE   ENABLE_ASH_BASH_COMPAT
 203#define IF_BASH_DOLLAR_SQUOTE       IF_ASH_BASH_COMPAT
 204#define    BASH_PATTERN_SUBST   ENABLE_ASH_BASH_COMPAT
 205#define IF_BASH_PATTERN_SUBST       IF_ASH_BASH_COMPAT
 206#define    BASH_SUBSTR          ENABLE_ASH_BASH_COMPAT
 207#define IF_BASH_SUBSTR              IF_ASH_BASH_COMPAT
 208/* BASH_TEST2: [[ EXPR ]]
 209 * Status of [[ support:
 210 *   && and || work as they should
 211 *   = is glob match operator, not equality operator: STR = GLOB
 212 *   == same as =
 213 *   =~ is regex match operator: STR =~ REGEX
 214 * TODO:
 215 * singleword+noglob expansion:
 216 *   v='a b'; [[ $v = 'a b' ]]; echo 0:$?
 217 *   [[ /bin/n* ]]; echo 0:$?
 218 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
 219 * ( ) < > should not have special meaning (IOW: should not require quoting)
 220 * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*"
 221 */
 222#define    BASH_TEST2           (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
 223#define    BASH_SOURCE          ENABLE_ASH_BASH_COMPAT
 224#define    BASH_PIPEFAIL        ENABLE_ASH_BASH_COMPAT
 225#define    BASH_HOSTNAME_VAR    ENABLE_ASH_BASH_COMPAT
 226#define    BASH_EPOCH_VARS      ENABLE_ASH_BASH_COMPAT
 227#define    BASH_SHLVL_VAR       ENABLE_ASH_BASH_COMPAT
 228#define    BASH_XTRACEFD        ENABLE_ASH_BASH_COMPAT
 229#define    BASH_READ_D          ENABLE_ASH_BASH_COMPAT
 230#define IF_BASH_READ_D              IF_ASH_BASH_COMPAT
 231#define    BASH_WAIT_N          ENABLE_ASH_BASH_COMPAT
 232/* <(...) and >(...) */
 233#if HAVE_DEV_FD
 234# define    BASH_PROCESS_SUBST   ENABLE_ASH_BASH_COMPAT
 235# define IF_BASH_PROCESS_SUBST       IF_ASH_BASH_COMPAT
 236#else
 237# define    BASH_PROCESS_SUBST 0
 238# define IF_BASH_PROCESS_SUBST(...)
 239#endif
 240
 241#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
 242/* Bionic at least up to version 24 has no glob() */
 243# undef  ENABLE_ASH_INTERNAL_GLOB
 244# define ENABLE_ASH_INTERNAL_GLOB 1
 245#endif
 246
 247#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
 248# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
 249# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
 250# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
 251# error glob() should unbackslash them and match. uClibc does not unbackslash,
 252# error fails to match dirname, subsequently not expanding <pattern> in it.
 253// Testcase:
 254// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
 255// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
 256#endif
 257
 258#if !ENABLE_ASH_INTERNAL_GLOB
 259# include <glob.h>
 260#endif
 261
 262#include "unicode.h"
 263#include "shell_common.h"
 264#if ENABLE_FEATURE_SH_MATH
 265# include "math.h"
 266#else
 267typedef long arith_t;
 268# define ARITH_FMT "%ld"
 269#endif
 270#if ENABLE_ASH_RANDOM_SUPPORT
 271# include "random.h"
 272#else
 273# define CLEAR_RANDOM_T(rnd) ((void)0)
 274#endif
 275
 276#include "NUM_APPLETS.h"
 277#if NUM_APPLETS == 1
 278/* STANDALONE does not make sense, and won't compile */
 279# undef CONFIG_FEATURE_SH_STANDALONE
 280# undef ENABLE_FEATURE_SH_STANDALONE
 281# undef IF_FEATURE_SH_STANDALONE
 282# undef IF_NOT_FEATURE_SH_STANDALONE
 283# define ENABLE_FEATURE_SH_STANDALONE 0
 284# define IF_FEATURE_SH_STANDALONE(...)
 285# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 286#endif
 287
 288#ifndef F_DUPFD_CLOEXEC
 289# define F_DUPFD_CLOEXEC F_DUPFD
 290#endif
 291#ifndef O_CLOEXEC
 292# define O_CLOEXEC 0
 293#endif
 294#ifndef PIPE_BUF
 295# define PIPE_BUF 4096           /* amount of buffering in a pipe */
 296#endif
 297
 298#ifndef unlikely
 299# define unlikely(cond) (cond)
 300#endif
 301
 302#if !BB_MMU
 303# error "Do not even bother, ash will not run on NOMMU machine"
 304#endif
 305
 306/* ============ Hash table sizes. Configurable. */
 307
 308#define VTABSIZE 39
 309#define ATABSIZE 39
 310#define CMDTABLESIZE 31         /* should be prime */
 311
 312
 313/* ============ Shell options */
 314
 315/* If you add/change options hare, update --help text too */
 316static const char *const optletters_optnames[] = {
 317        "e"   "errexit",
 318        "f"   "noglob",
 319/* bash has '-o ignoreeof', but no short synonym -I for it */
 320/* (in bash, set -I disables invisible variables (what's that?)) */
 321        "I"   "ignoreeof",
 322/* The below allowed this invocation:
 323 * ash -c 'set -i; echo $-; sleep 5; echo $-'
 324 * to be ^C-ed and get to interactive ash prompt.
 325 * bash does not support such "set -i".
 326 * In our code, this is denoted by empty long name:
 327 */
 328        "i"   "",
 329/* (removing "i" altogether would remove it from "$-", not good) */
 330        "m"   "monitor",
 331        "n"   "noexec",
 332/* Ditto: bash has no "set -s", "set -c" */
 333        "s"   "",
 334        "c"   "",
 335        "x"   "xtrace",
 336        "v"   "verbose",
 337        "C"   "noclobber",
 338        "a"   "allexport",
 339        "b"   "notify",
 340        "u"   "nounset",
 341        "E"   "errtrace",
 342        "\0"  "vi"
 343#if BASH_PIPEFAIL
 344        ,"\0"  "pipefail"
 345#endif
 346#if DEBUG
 347        ,"\0"  "nolog"
 348        ,"\0"  "debug"
 349#endif
 350};
 351//bash 4.4.23 also has these opts (with these defaults):
 352//braceexpand           on
 353//emacs                 on
 354//errtrace              off
 355//functrace             off
 356//hashall               on
 357//histexpand            off
 358//history               on
 359//interactive-comments  on
 360//keyword               off
 361//onecmd                off
 362//physical              off
 363//posix                 off
 364//privileged            off
 365
 366#define optletters(n)  optletters_optnames[n][0]
 367#define optnames(n)   (optletters_optnames[n] + 1)
 368
 369enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
 370
 371
 372/* ============ Misc data */
 373
 374#define msg_illnum "Illegal number: %s"
 375
 376/*
 377 * We enclose jmp_buf in a structure so that we can declare pointers to
 378 * jump locations.  The global variable handler contains the location to
 379 * jump to when an exception occurs, and the global variable exception_type
 380 * contains a code identifying the exception.  To implement nested
 381 * exception handlers, the user should save the value of handler on entry
 382 * to an inner scope, set handler to point to a jmploc structure for the
 383 * inner scope, and restore handler on exit from the scope.
 384 */
 385struct jmploc {
 386        jmp_buf loc;
 387};
 388
 389struct globals_misc {
 390        uint8_t exitstatus;     /* exit status of last command */
 391        uint8_t back_exitstatus;/* exit status of backquoted command */
 392        smallint job_warning;   /* user was warned about stopped jobs (can be 2, 1 or 0). */
 393        smallint inps4;         /* Prevent PS4 nesting. */
 394        int savestatus;         /* exit status of last command outside traps */
 395        int rootpid;            /* pid of main shell */
 396        /* shell level: 0 for the main shell, 1 for its children, and so on */
 397        int shlvl;
 398#define rootshell (!shlvl)
 399        int errlinno;
 400
 401        char *minusc;  /* argument to -c option */
 402
 403        char *curdir; // = nullstr;     /* current working directory */
 404        char *physdir; // = nullstr;    /* physical working directory */
 405
 406        char *arg0; /* value of $0 */
 407
 408        struct jmploc *exception_handler;
 409
 410        volatile int suppress_int; /* counter */
 411        volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
 412        volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
 413        volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
 414        smallint exception_type; /* kind of exception: */
 415#define EXINT 0         /* SIGINT received */
 416#define EXERROR 1       /* a generic error */
 417#define EXEND 3         /* exit the shell */
 418#define EXEXIT 4        /* exit the shell via exitcmd */
 419
 420        char nullstr[1];        /* zero length string */
 421
 422        char optlist[NOPTS];
 423#define eflag optlist[0]
 424#define fflag optlist[1]
 425#define Iflag optlist[2]
 426#define iflag optlist[3]
 427#define mflag optlist[4]
 428#define nflag optlist[5]
 429#define sflag optlist[6]
 430#define cflag optlist[7]
 431#define xflag optlist[8]
 432#define vflag optlist[9]
 433#define Cflag optlist[10]
 434#define aflag optlist[11]
 435#define bflag optlist[12]
 436#define uflag optlist[13]
 437#define Eflag optlist[14]
 438#define viflag optlist[15]
 439#if BASH_PIPEFAIL
 440# define pipefail optlist[16]
 441#else
 442# define pipefail 0
 443#endif
 444#if DEBUG
 445# define nolog optlist[16 + BASH_PIPEFAIL]
 446# define debug optlist[17 + BASH_PIPEFAIL]
 447#endif
 448
 449        /* trap handler commands */
 450        /*
 451         * Sigmode records the current value of the signal handlers for the various
 452         * modes.  A value of zero means that the current handler is not known.
 453         * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
 454         */
 455        char sigmode[NSIG - 1];
 456#define S_DFL      1            /* default signal handling (SIG_DFL) */
 457#define S_CATCH    2            /* signal is caught */
 458#define S_IGN      3            /* signal is ignored (SIG_IGN) */
 459#define S_HARD_IGN 4            /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
 460
 461        /* indicates specified signal received */
 462        uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
 463        uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
 464        char *trap[NSIG + 1];
 465/* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */
 466#define NTRAP_ERR  NSIG
 467#define NTRAP_LAST NSIG
 468
 469        char **trap_ptr;        /* used only by "trap hack" */
 470
 471        /* Rarely referenced stuff */
 472#if ENABLE_ASH_RANDOM_SUPPORT
 473        random_t random_gen;
 474#endif
 475        pid_t backgndpid;        /* pid of last background process */
 476};
 477extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
 478#define G_misc (*ash_ptr_to_globals_misc)
 479#define exitstatus        (G_misc.exitstatus )
 480#define back_exitstatus   (G_misc.back_exitstatus )
 481#define job_warning       (G_misc.job_warning)
 482#define inps4       (G_misc.inps4      )
 483#define savestatus  (G_misc.savestatus )
 484#define rootpid     (G_misc.rootpid    )
 485#define shlvl       (G_misc.shlvl      )
 486#define errlinno    (G_misc.errlinno   )
 487#define minusc      (G_misc.minusc     )
 488#define curdir      (G_misc.curdir     )
 489#define physdir     (G_misc.physdir    )
 490#define arg0        (G_misc.arg0       )
 491#define exception_handler (G_misc.exception_handler)
 492#define exception_type    (G_misc.exception_type   )
 493#define suppress_int      (G_misc.suppress_int     )
 494#define pending_int       (G_misc.pending_int      )
 495#define got_sigchld       (G_misc.got_sigchld      )
 496#define pending_sig       (G_misc.pending_sig      )
 497#define nullstr     (G_misc.nullstr    )
 498#define optlist     (G_misc.optlist    )
 499#define sigmode     (G_misc.sigmode    )
 500#define gotsig      (G_misc.gotsig     )
 501#define may_have_traps    (G_misc.may_have_traps   )
 502#define trap        (G_misc.trap       )
 503#define trap_ptr    (G_misc.trap_ptr   )
 504#define random_gen  (G_misc.random_gen )
 505#define backgndpid  (G_misc.backgndpid )
 506#define INIT_G_misc() do { \
 507        XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \
 508        savestatus = -1; \
 509        curdir = nullstr; \
 510        physdir = nullstr; \
 511        trap_ptr = trap; \
 512} while (0)
 513
 514
 515/* ============ DEBUG */
 516#if DEBUG
 517static void trace_printf(const char *fmt, ...);
 518static void trace_vprintf(const char *fmt, va_list va);
 519# define TRACE(param)    trace_printf param
 520# define TRACEV(param)   trace_vprintf param
 521# define close(fd) do { \
 522        int dfd = (fd); \
 523        if (close(dfd) < 0) \
 524                bb_error_msg("bug on %d: closing %d(0x%x)", \
 525                        __LINE__, dfd, dfd); \
 526} while (0)
 527#else
 528# define TRACE(param)
 529# define TRACEV(param)
 530#endif
 531
 532
 533/* ============ Utility functions */
 534#define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
 535#define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
 536
 537static int
 538isdigit_str9(const char *str)
 539{
 540        int maxlen = 9 + 1; /* max 9 digits: 999999999 */
 541        while (--maxlen && isdigit(*str))
 542                str++;
 543        return (*str == '\0');
 544}
 545
 546static const char *
 547var_end(const char *var)
 548{
 549        while (*var)
 550                if (*var++ == '=')
 551                        break;
 552        return var;
 553}
 554
 555
 556/* ============ Parser data */
 557
 558/*
 559 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
 560 */
 561struct strlist {
 562        struct strlist *next;
 563        char *text;
 564};
 565
 566struct alias;
 567
 568struct strpush {
 569        struct strpush *prev;   /* preceding string on stack */
 570        char *prev_string;
 571        int prev_left_in_line;
 572#if ENABLE_ASH_ALIAS
 573        struct alias *ap;       /* if push was associated with an alias */
 574#endif
 575        char *string;           /* remember the string since it may change */
 576
 577        /* Delay freeing so we can stop nested aliases. */
 578        struct strpush *spfree;
 579
 580        /* Remember last two characters for pungetc. */
 581        int lastc[2];
 582
 583        /* Number of outstanding calls to pungetc. */
 584        int unget;
 585};
 586
 587/*
 588 * The parsefile structure pointed to by the global variable parsefile
 589 * contains information about the current file being read.
 590 */
 591struct parsefile {
 592        struct parsefile *prev; /* preceding file on stack */
 593        int linno;              /* current line */
 594        int pf_fd;              /* file descriptor (or -1 if string) */
 595        int left_in_line;       /* number of chars left in this line */
 596        int left_in_buffer;     /* number of chars left in this buffer past the line */
 597        char *next_to_pgetc;    /* next char in buffer */
 598        char *buf;              /* input buffer */
 599        struct strpush *strpush; /* for pushing strings at this level */
 600        struct strpush basestrpush; /* so pushing one is fast */
 601
 602        /* Delay freeing so we can stop nested aliases. */
 603        struct strpush *spfree;
 604
 605        /* Remember last two characters for pungetc. */
 606        int lastc[2];
 607
 608        /* Number of outstanding calls to pungetc. */
 609        int unget;
 610};
 611
 612static struct parsefile basepf;        /* top level input file */
 613static struct parsefile *g_parsefile = &basepf;  /* current input file */
 614static char *commandname;              /* currently executing command */
 615
 616
 617/* ============ Interrupts / exceptions */
 618
 619static void exitshell(void) NORETURN;
 620
 621/*
 622 * These macros allow the user to suspend the handling of interrupt signals
 623 * over a period of time.  This is similar to SIGHOLD or to sigblock, but
 624 * much more efficient and portable.  (But hacking the kernel is so much
 625 * more fun than worrying about efficiency and portability. :-))
 626 */
 627#if DEBUG_INTONOFF
 628# define INT_OFF do { \
 629        TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
 630        suppress_int++; \
 631        barrier(); \
 632} while (0)
 633#else
 634# define INT_OFF do { \
 635        suppress_int++; \
 636        barrier(); \
 637} while (0)
 638#endif
 639
 640/*
 641 * Called to raise an exception.  Since C doesn't include exceptions, we
 642 * just do a longjmp to the exception handler.  The type of exception is
 643 * stored in the global variable "exception_type".
 644 */
 645static void raise_exception(int) NORETURN;
 646static void
 647raise_exception(int e)
 648{
 649#if DEBUG
 650        if (exception_handler == NULL)
 651                abort();
 652#endif
 653        INT_OFF;
 654        exception_type = e;
 655        longjmp(exception_handler->loc, 1);
 656}
 657#if DEBUG
 658#define raise_exception(e) do { \
 659        TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
 660        raise_exception(e); \
 661} while (0)
 662#endif
 663
 664/*
 665 * Called when a SIGINT is received.  (If the user specifies
 666 * that SIGINT is to be trapped or ignored using the trap builtin, then
 667 * this routine is not called.)  Suppressint is nonzero when interrupts
 668 * are held using the INT_OFF macro.  (The test for iflag is just
 669 * defensive programming.)
 670 */
 671static void raise_interrupt(void) NORETURN;
 672static void
 673raise_interrupt(void)
 674{
 675        pending_int = 0;
 676        /* Signal is not automatically unmasked after it is raised,
 677         * do it ourself - unmask all signals */
 678        sigprocmask_allsigs(SIG_UNBLOCK);
 679        /* pending_sig = 0; - now done in signal_handler() */
 680
 681        if (!(rootshell && iflag)) {
 682                /* Kill ourself with SIGINT */
 683                signal(SIGINT, SIG_DFL);
 684                raise(SIGINT);
 685        }
 686        /* bash: ^C even on empty command line sets $? */
 687        exitstatus = SIGINT + 128;
 688        raise_exception(EXINT);
 689        /* NOTREACHED */
 690}
 691#if DEBUG
 692#define raise_interrupt() do { \
 693        TRACE(("raising interrupt on line %d\n", __LINE__)); \
 694        raise_interrupt(); \
 695} while (0)
 696#endif
 697
 698static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 699int_on(void)
 700{
 701        barrier();
 702        if (--suppress_int == 0 && pending_int) {
 703                raise_interrupt();
 704        }
 705}
 706#if DEBUG_INTONOFF
 707# define INT_ON do { \
 708        TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
 709        int_on(); \
 710} while (0)
 711#else
 712# define INT_ON int_on()
 713#endif
 714static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 715force_int_on(void)
 716{
 717        barrier();
 718        suppress_int = 0;
 719        if (pending_int)
 720                raise_interrupt();
 721}
 722#define FORCE_INT_ON force_int_on()
 723
 724#define SAVE_INT(v) ((v) = suppress_int)
 725
 726#define RESTORE_INT(v) do { \
 727        barrier(); \
 728        suppress_int = (v); \
 729        if (suppress_int == 0 && pending_int) \
 730                raise_interrupt(); \
 731} while (0)
 732
 733
 734/* ============ Stdout/stderr output */
 735
 736static void
 737outstr(const char *p, FILE *file)
 738{
 739        INT_OFF;
 740        fputs(p, file);
 741        INT_ON;
 742}
 743
 744static void
 745flush_stdout_stderr(void)
 746{
 747        INT_OFF;
 748        fflush_all();
 749        INT_ON;
 750}
 751
 752/* Was called outcslow(c,FILE*), but c was always '\n' */
 753static void
 754newline_and_flush(FILE *dest)
 755{
 756        INT_OFF;
 757        putc('\n', dest);
 758        fflush(dest);
 759        INT_ON;
 760}
 761
 762static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
 763static int
 764out1fmt(const char *fmt, ...)
 765{
 766        va_list ap;
 767        int r;
 768
 769        INT_OFF;
 770        va_start(ap, fmt);
 771        r = vprintf(fmt, ap);
 772        va_end(ap);
 773        INT_ON;
 774        return r;
 775}
 776
 777static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
 778static int
 779fmtstr(char *outbuf, size_t length, const char *fmt, ...)
 780{
 781        va_list ap;
 782        int ret;
 783
 784        INT_OFF;
 785        va_start(ap, fmt);
 786        ret = vsnprintf(outbuf, length, fmt, ap);
 787        va_end(ap);
 788        INT_ON;
 789        return ret > (int)length ? length : ret;
 790}
 791
 792static void
 793out1str(const char *p)
 794{
 795        outstr(p, stdout);
 796}
 797
 798static void
 799out2str(const char *p)
 800{
 801        outstr(p, stderr);
 802        flush_stdout_stderr();
 803}
 804
 805
 806/* ============ Parser structures */
 807
 808/* control characters in argument strings */
 809#define CTL_FIRST CTLESC
 810#define CTLESC       ((unsigned char)'\201')    /* escape next character */
 811#define CTLVAR       ((unsigned char)'\202')    /* variable defn */
 812#define CTLENDVAR    ((unsigned char)'\203')
 813#define CTLBACKQ     ((unsigned char)'\204')
 814#define CTLARI       ((unsigned char)'\206')    /* arithmetic expression */
 815#define CTLENDARI    ((unsigned char)'\207')
 816#define CTLQUOTEMARK ((unsigned char)'\210')
 817#define CTL_LAST CTLQUOTEMARK
 818#if BASH_PROCESS_SUBST
 819# define CTLTOPROC    ((unsigned char)'\211')
 820# define CTLFROMPROC  ((unsigned char)'\212')
 821# undef CTL_LAST
 822# define CTL_LAST CTLFROMPROC
 823#endif
 824
 825/* variable substitution byte (follows CTLVAR) */
 826#define VSTYPE  0x0f            /* type of variable substitution */
 827#define VSNUL   0x10            /* colon--treat the empty string as unset */
 828
 829/* values of VSTYPE field */
 830#define VSNORMAL        0x1     /* normal variable:  $var or ${var} */
 831#define VSMINUS         0x2     /* ${var-text} */
 832#define VSPLUS          0x3     /* ${var+text} */
 833#define VSQUESTION      0x4     /* ${var?message} */
 834#define VSASSIGN        0x5     /* ${var=text} */
 835#define VSTRIMRIGHT     0x6     /* ${var%pattern} */
 836#define VSTRIMRIGHTMAX  0x7     /* ${var%%pattern} */
 837#define VSTRIMLEFT      0x8     /* ${var#pattern} */
 838#define VSTRIMLEFTMAX   0x9     /* ${var##pattern} */
 839#define VSLENGTH        0xa     /* ${#var} */
 840#if BASH_SUBSTR
 841#define VSSUBSTR        0xc     /* ${var:position:length} */
 842#endif
 843#if BASH_PATTERN_SUBST
 844#define VSREPLACE       0xd     /* ${var/pattern/replacement} */
 845#define VSREPLACEALL    0xe     /* ${var//pattern/replacement} */
 846#endif
 847
 848static const char dolatstr[] ALIGN1 = {
 849        CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
 850};
 851#define DOLATSTRLEN 6
 852
 853#define NCMD      0
 854#define NPIPE     1
 855#define NREDIR    2
 856#define NBACKGND  3
 857#define NSUBSHELL 4
 858#define NAND      5
 859#define NOR       6
 860#define NSEMI     7
 861#define NIF       8
 862#define NWHILE    9
 863#define NUNTIL   10
 864#define NFOR     11
 865#define NCASE    12
 866#define NCLIST   13
 867#define NDEFUN   14
 868#define NARG     15
 869#define NTO      16
 870#if BASH_REDIR_OUTPUT
 871#define NTO2     17
 872#endif
 873#define NCLOBBER 18
 874#define NFROM    19
 875#define NFROMTO  20
 876#define NAPPEND  21
 877#define NTOFD    22
 878#define NFROMFD  23
 879#define NHERE    24
 880#define NXHERE   25
 881#define NNOT     26
 882#define N_NUMBER 27
 883
 884union node;
 885
 886struct ncmd {
 887        smallint type; /* Nxxxx */
 888        int linno;
 889        union node *assign;
 890        union node *args;
 891        union node *redirect;
 892};
 893
 894struct npipe {
 895        smallint type;
 896        smallint pipe_backgnd;
 897        struct nodelist *cmdlist;
 898};
 899
 900struct nredir {
 901        smallint type;
 902        int linno;
 903        union node *n;
 904        union node *redirect;
 905};
 906
 907struct nbinary {
 908        smallint type;
 909        union node *ch1;
 910        union node *ch2;
 911};
 912
 913struct nif {
 914        smallint type;
 915        union node *test;
 916        union node *ifpart;
 917        union node *elsepart;
 918};
 919
 920struct nfor {
 921        smallint type;
 922        int linno;
 923        union node *args;
 924        union node *body;
 925        char *var;
 926};
 927
 928struct ncase {
 929        smallint type;
 930        int linno;
 931        union node *expr;
 932        union node *cases;
 933};
 934
 935struct nclist {
 936        smallint type;
 937        union node *next;
 938        union node *pattern;
 939        union node *body;
 940};
 941
 942struct ndefun {
 943        smallint type;
 944        int linno;
 945        char *text;
 946        union node *body;
 947};
 948
 949struct narg {
 950        smallint type;
 951        union node *next;
 952        char *text;
 953        struct nodelist *backquote;
 954};
 955
 956/* nfile and ndup layout must match!
 957 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
 958 * that it is actually NTO2 (>&file), and change its type.
 959 */
 960struct nfile {
 961        smallint type;
 962        union node *next;
 963        int fd;
 964        int _unused_dupfd;
 965        union node *fname;
 966        char *expfname;
 967};
 968
 969struct ndup {
 970        smallint type;
 971        union node *next;
 972        int fd;
 973        int dupfd;
 974        union node *vname;
 975        char *_unused_expfname;
 976};
 977
 978struct nhere {
 979        smallint type;
 980        union node *next;
 981        int fd;
 982        union node *doc;
 983};
 984
 985struct nnot {
 986        smallint type;
 987        union node *com;
 988};
 989
 990union node {
 991        smallint type;
 992        struct ncmd ncmd;
 993        struct npipe npipe;
 994        struct nredir nredir;
 995        struct nbinary nbinary;
 996        struct nif nif;
 997        struct nfor nfor;
 998        struct ncase ncase;
 999        struct nclist nclist;
1000        struct ndefun ndefun;
1001        struct narg narg;
1002        struct nfile nfile;
1003        struct ndup ndup;
1004        struct nhere nhere;
1005        struct nnot nnot;
1006};
1007
1008/*
1009 * NODE_EOF is returned by parsecmd when it encounters an end of file.
1010 * It must be distinct from NULL.
1011 */
1012#define NODE_EOF ((union node *) -1L)
1013
1014struct nodelist {
1015        struct nodelist *next;
1016        union node *n;
1017};
1018
1019struct funcnode {
1020        int count;
1021        union node n;
1022};
1023
1024/*
1025 * Free a parse tree.
1026 */
1027static void
1028freefunc(struct funcnode *f)
1029{
1030        if (f && --f->count < 0)
1031                free(f);
1032}
1033
1034
1035/* ============ Debugging output */
1036
1037#if DEBUG
1038
1039static FILE *tracefile;
1040
1041static void
1042trace_printf(const char *fmt, ...)
1043{
1044        va_list va;
1045
1046        if (debug != 1)
1047                return;
1048        if (DEBUG_TIME)
1049                fprintf(tracefile, "%u ", (int) time(NULL));
1050        if (DEBUG_PID)
1051                fprintf(tracefile, "[%u] ", (int) getpid());
1052        if (DEBUG_SIG)
1053                fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
1054        va_start(va, fmt);
1055        vfprintf(tracefile, fmt, va);
1056        va_end(va);
1057}
1058
1059static void
1060trace_vprintf(const char *fmt, va_list va)
1061{
1062        if (debug != 1)
1063                return;
1064        vfprintf(tracefile, fmt, va);
1065        fprintf(tracefile, "\n");
1066}
1067
1068static void
1069trace_puts(const char *s)
1070{
1071        if (debug != 1)
1072                return;
1073        fputs(s, tracefile);
1074}
1075
1076static void
1077trace_puts_quoted(char *s)
1078{
1079        char *p;
1080        char c;
1081
1082        if (debug != 1)
1083                return;
1084        putc('"', tracefile);
1085        for (p = s; *p; p++) {
1086                switch ((unsigned char)*p) {
1087                case '\n': c = 'n'; goto backslash;
1088                case '\t': c = 't'; goto backslash;
1089                case '\r': c = 'r'; goto backslash;
1090                case '\"': c = '\"'; goto backslash;
1091                case '\\': c = '\\'; goto backslash;
1092                case CTLESC: c = 'e'; goto backslash;
1093                case CTLVAR: c = 'v'; goto backslash;
1094                case CTLBACKQ: c = 'q'; goto backslash;
1095#if BASH_PROCESS_SUBST
1096                case CTLTOPROC: c = 'p'; goto backslash;
1097                case CTLFROMPROC: c = 'P'; goto backslash;
1098#endif
1099 backslash:
1100                        putc('\\', tracefile);
1101                        putc(c, tracefile);
1102                        break;
1103                default:
1104                        if (*p >= ' ' && *p <= '~')
1105                                putc(*p, tracefile);
1106                        else {
1107                                putc('\\', tracefile);
1108                                putc((*p >> 6) & 03, tracefile);
1109                                putc((*p >> 3) & 07, tracefile);
1110                                putc(*p & 07, tracefile);
1111                        }
1112                        break;
1113                }
1114        }
1115        putc('"', tracefile);
1116}
1117
1118static void
1119trace_puts_args(char **ap)
1120{
1121        if (debug != 1)
1122                return;
1123        if (!*ap)
1124                return;
1125        while (1) {
1126                trace_puts_quoted(*ap);
1127                if (!*++ap) {
1128                        putc('\n', tracefile);
1129                        break;
1130                }
1131                putc(' ', tracefile);
1132        }
1133}
1134
1135static void
1136opentrace(void)
1137{
1138        char s[100];
1139#ifdef O_APPEND
1140        int flags;
1141#endif
1142
1143        if (debug != 1) {
1144                if (tracefile)
1145                        fflush(tracefile);
1146                /* leave open because libedit might be using it */
1147                return;
1148        }
1149        strcpy(s, "./trace");
1150        if (tracefile) {
1151                if (!freopen(s, "a", tracefile)) {
1152                        fprintf(stderr, "Can't re-open %s\n", s);
1153                        debug = 0;
1154                        return;
1155                }
1156        } else {
1157                tracefile = fopen(s, "a");
1158                if (tracefile == NULL) {
1159                        fprintf(stderr, "Can't open %s\n", s);
1160                        debug = 0;
1161                        return;
1162                }
1163        }
1164#ifdef O_APPEND
1165        flags = fcntl(fileno(tracefile), F_GETFL);
1166        if (flags >= 0)
1167                fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1168#endif
1169        setlinebuf(tracefile);
1170        fputs("\nTracing started.\n", tracefile);
1171}
1172
1173static void
1174indent(int amount, char *pfx, FILE *fp)
1175{
1176        int i;
1177
1178        for (i = 0; i < amount; i++) {
1179                if (pfx && i == amount - 1)
1180                        fputs(pfx, fp);
1181                putc('\t', fp);
1182        }
1183}
1184
1185/* little circular references here... */
1186static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1187
1188static void
1189sharg(union node *arg, FILE *fp)
1190{
1191        char *p;
1192        struct nodelist *bqlist;
1193        unsigned char subtype;
1194
1195        if (arg->type != NARG) {
1196                out1fmt("<node type %d>\n", arg->type);
1197                abort();
1198        }
1199        bqlist = arg->narg.backquote;
1200        for (p = arg->narg.text; *p; p++) {
1201                switch ((unsigned char)*p) {
1202                case CTLESC:
1203                        p++;
1204                        putc(*p, fp);
1205                        break;
1206                case CTLVAR:
1207                        putc('$', fp);
1208                        putc('{', fp);
1209                        subtype = *++p;
1210                        if (subtype == VSLENGTH)
1211                                putc('#', fp);
1212
1213                        while (*p != '=') {
1214                                putc(*p, fp);
1215                                p++;
1216                        }
1217
1218                        if (subtype & VSNUL)
1219                                putc(':', fp);
1220
1221                        switch (subtype & VSTYPE) {
1222                        case VSNORMAL:
1223                                putc('}', fp);
1224                                break;
1225                        case VSMINUS:
1226                                putc('-', fp);
1227                                break;
1228                        case VSPLUS:
1229                                putc('+', fp);
1230                                break;
1231                        case VSQUESTION:
1232                                putc('?', fp);
1233                                break;
1234                        case VSASSIGN:
1235                                putc('=', fp);
1236                                break;
1237                        case VSTRIMLEFT:
1238                                putc('#', fp);
1239                                break;
1240                        case VSTRIMLEFTMAX:
1241                                putc('#', fp);
1242                                putc('#', fp);
1243                                break;
1244                        case VSTRIMRIGHT:
1245                                putc('%', fp);
1246                                break;
1247                        case VSTRIMRIGHTMAX:
1248                                putc('%', fp);
1249                                putc('%', fp);
1250                                break;
1251                        case VSLENGTH:
1252                                break;
1253                        default:
1254                                out1fmt("<subtype %d>", subtype);
1255                        }
1256                        break;
1257                case CTLENDVAR:
1258                        putc('}', fp);
1259                        break;
1260#if BASH_PROCESS_SUBST
1261                case CTLTOPROC:
1262                        putc('>', fp);
1263                        goto backq;
1264                case CTLFROMPROC:
1265                        putc('<', fp);
1266                        goto backq;
1267#endif
1268                case CTLBACKQ:
1269                        putc('$', fp);
1270 IF_BASH_PROCESS_SUBST(backq:)
1271                        putc('(', fp);
1272                        shtree(bqlist->n, -1, NULL, fp);
1273                        putc(')', fp);
1274                        break;
1275                default:
1276                        putc(*p, fp);
1277                        break;
1278                }
1279        }
1280}
1281
1282static void
1283shcmd(union node *cmd, FILE *fp)
1284{
1285        union node *np;
1286        int first;
1287        const char *s;
1288        int dftfd;
1289
1290        first = 1;
1291        for (np = cmd->ncmd.args; np; np = np->narg.next) {
1292                if (!first)
1293                        putc(' ', fp);
1294                sharg(np, fp);
1295                first = 0;
1296        }
1297        for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1298                if (!first)
1299                        putc(' ', fp);
1300                dftfd = 0;
1301                switch (np->nfile.type) {
1302                case NTO:      s = ">>"+1; dftfd = 1; break;
1303                case NCLOBBER: s = ">|"; dftfd = 1; break;
1304                case NAPPEND:  s = ">>"; dftfd = 1; break;
1305#if BASH_REDIR_OUTPUT
1306                case NTO2:
1307#endif
1308                case NTOFD:    s = ">&"; dftfd = 1; break;
1309                case NFROM:    s = "<"; break;
1310                case NFROMFD:  s = "<&"; break;
1311                case NFROMTO:  s = "<>"; break;
1312                default:       s = "*error*"; break;
1313                }
1314                if (np->nfile.fd != dftfd)
1315                        fprintf(fp, "%d", np->nfile.fd);
1316                fputs(s, fp);
1317                if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1318                        fprintf(fp, "%d", np->ndup.dupfd);
1319                } else {
1320                        sharg(np->nfile.fname, fp);
1321                }
1322                first = 0;
1323        }
1324}
1325
1326static void
1327shtree(union node *n, int ind, char *pfx, FILE *fp)
1328{
1329        struct nodelist *lp;
1330        const char *s;
1331
1332        if (n == NULL)
1333                return;
1334
1335        indent(ind, pfx, fp);
1336
1337        if (n == NODE_EOF) {
1338                fputs("<EOF>", fp);
1339                return;
1340        }
1341
1342        switch (n->type) {
1343        case NSEMI:
1344                s = "; ";
1345                goto binop;
1346        case NAND:
1347                s = " && ";
1348                goto binop;
1349        case NOR:
1350                s = " || ";
1351 binop:
1352                shtree(n->nbinary.ch1, ind, NULL, fp);
1353                /* if (ind < 0) */
1354                        fputs(s, fp);
1355                shtree(n->nbinary.ch2, ind, NULL, fp);
1356                break;
1357        case NCMD:
1358                shcmd(n, fp);
1359                if (ind >= 0)
1360                        putc('\n', fp);
1361                break;
1362        case NPIPE:
1363                for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1364                        shtree(lp->n, 0, NULL, fp);
1365                        if (lp->next)
1366                                fputs(" | ", fp);
1367                }
1368                if (n->npipe.pipe_backgnd)
1369                        fputs(" &", fp);
1370                if (ind >= 0)
1371                        putc('\n', fp);
1372                break;
1373        default:
1374                fprintf(fp, "<node type %d>", n->type);
1375                if (ind >= 0)
1376                        putc('\n', fp);
1377                break;
1378        }
1379}
1380
1381static void
1382showtree(union node *n)
1383{
1384        trace_puts("showtree called\n");
1385        shtree(n, 1, NULL, stderr);
1386}
1387
1388#endif /* DEBUG */
1389
1390
1391/* ============ Message printing */
1392
1393static void
1394ash_vmsg(const char *msg, va_list ap)
1395{
1396        fprintf(stderr, "%s: ", arg0);
1397        if (commandname) {
1398                if (strcmp(arg0, commandname))
1399                        fprintf(stderr, "%s: ", commandname);
1400                if (!iflag || g_parsefile->pf_fd > 0)
1401                        fprintf(stderr, "line %d: ", errlinno);
1402        }
1403        vfprintf(stderr, msg, ap);
1404        newline_and_flush(stderr);
1405}
1406
1407/*
1408 * Exverror is called to raise the error exception.  If the second argument
1409 * is not NULL then error prints an error message using printf style
1410 * formatting.  It then raises the error exception.
1411 */
1412static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1413static void
1414ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1415{
1416#if DEBUG
1417        if (msg) {
1418                TRACE(("ash_vmsg_and_raise(%d):", cond));
1419                TRACEV((msg, ap));
1420        } else
1421                TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1422        if (msg)
1423#endif
1424                ash_vmsg(msg, ap);
1425
1426        flush_stdout_stderr();
1427        raise_exception(cond);
1428        /* NOTREACHED */
1429}
1430
1431static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1432static void
1433ash_msg_and_raise_error(const char *msg, ...)
1434{
1435        va_list ap;
1436
1437        exitstatus = 2;
1438
1439        va_start(ap, msg);
1440        ash_vmsg_and_raise(EXERROR, msg, ap);
1441        /* NOTREACHED */
1442        va_end(ap);
1443}
1444
1445/*
1446 * 'fmt' must be a string literal.
1447 */
1448#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
1449
1450static void raise_error_syntax(const char *) NORETURN;
1451static void
1452raise_error_syntax(const char *msg)
1453{
1454        errlinno = g_parsefile->linno;
1455        ash_msg_and_raise_error("syntax error: %s", msg);
1456        /* NOTREACHED */
1457}
1458
1459static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1460static void
1461ash_msg_and_raise(int cond, const char *msg, ...)
1462{
1463        va_list ap;
1464
1465        va_start(ap, msg);
1466        ash_vmsg_and_raise(cond, msg, ap);
1467        /* NOTREACHED */
1468        va_end(ap);
1469}
1470
1471/*
1472 * error/warning routines for external builtins
1473 */
1474static void
1475ash_msg(const char *fmt, ...)
1476{
1477        va_list ap;
1478
1479        va_start(ap, fmt);
1480        ash_vmsg(fmt, ap);
1481        va_end(ap);
1482}
1483
1484/*
1485 * Return a string describing an error.  The returned string may be a
1486 * pointer to a static buffer that will be overwritten on the next call.
1487 * Action describes the operation that got the error.
1488 */
1489static const char *
1490errmsg(int e, const char *em)
1491{
1492        if (e == ENOENT || e == ENOTDIR) {
1493                return em;
1494        }
1495        return strerror(e);
1496}
1497
1498
1499/* ============ Memory allocation */
1500
1501#if 0
1502/* I consider these wrappers nearly useless:
1503 * ok, they return you to nearest exception handler, but
1504 * how much memory do you leak in the process, making
1505 * memory starvation worse?
1506 */
1507static void *
1508ckrealloc(void * p, size_t nbytes)
1509{
1510        p = realloc(p, nbytes);
1511        if (!p)
1512                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1513        return p;
1514}
1515
1516static void *
1517ckmalloc(size_t nbytes)
1518{
1519        return ckrealloc(NULL, nbytes);
1520}
1521
1522static void *
1523ckzalloc(size_t nbytes)
1524{
1525        return memset(ckmalloc(nbytes), 0, nbytes);
1526}
1527
1528static char *
1529ckstrdup(const char *s)
1530{
1531        char *p = strdup(s);
1532        if (!p)
1533                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1534        return p;
1535}
1536#else
1537/* Using bbox equivalents. They exit if out of memory */
1538# define ckrealloc xrealloc
1539# define ckmalloc  xmalloc
1540# define ckzalloc  xzalloc
1541# define ckstrdup  xstrdup
1542#endif
1543
1544/*
1545 * It appears that grabstackstr() will barf with such alignments
1546 * because stalloc() will return a string allocated in a new stackblock.
1547 */
1548#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1549enum {
1550        /* Most machines require the value returned from malloc to be aligned
1551         * in some way.  The following macro will get this right
1552         * on many machines.  */
1553        SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1554        /* Minimum size of a block */
1555        MINSIZE = SHELL_ALIGN(504),
1556};
1557
1558struct stack_block {
1559        struct stack_block *prev;
1560        char space[MINSIZE];
1561};
1562
1563struct stackmark {
1564        struct stack_block *stackp;
1565        char *stacknxt;
1566        size_t stacknleft;
1567};
1568
1569
1570struct globals_memstack {
1571        struct stack_block *g_stackp; // = &stackbase;
1572        char *g_stacknxt; // = stackbase.space;
1573        char *sstrend; // = stackbase.space + MINSIZE;
1574        size_t g_stacknleft; // = MINSIZE;
1575        struct stack_block stackbase;
1576};
1577extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1578#define G_memstack (*ash_ptr_to_globals_memstack)
1579#define g_stackp     (G_memstack.g_stackp    )
1580#define g_stacknxt   (G_memstack.g_stacknxt  )
1581#define sstrend      (G_memstack.sstrend     )
1582#define g_stacknleft (G_memstack.g_stacknleft)
1583#define stackbase    (G_memstack.stackbase   )
1584#define INIT_G_memstack() do { \
1585        XZALLOC_CONST_PTR(&ash_ptr_to_globals_memstack, sizeof(G_memstack)); \
1586        g_stackp = &stackbase; \
1587        g_stacknxt = stackbase.space; \
1588        g_stacknleft = MINSIZE; \
1589        sstrend = stackbase.space + MINSIZE; \
1590} while (0)
1591
1592
1593#define stackblock()     ((void *)g_stacknxt)
1594#define stackblocksize() g_stacknleft
1595
1596/*
1597 * Parse trees for commands are allocated in lifo order, so we use a stack
1598 * to make this more efficient, and also to avoid all sorts of exception
1599 * handling code to handle interrupts in the middle of a parse.
1600 *
1601 * The size 504 was chosen because the Ultrix malloc handles that size
1602 * well.
1603 */
1604static void *
1605stalloc(size_t nbytes)
1606{
1607        char *p;
1608        size_t aligned;
1609
1610        aligned = SHELL_ALIGN(nbytes);
1611        if (aligned > g_stacknleft) {
1612                size_t len;
1613                size_t blocksize;
1614                struct stack_block *sp;
1615
1616                blocksize = aligned;
1617                if (blocksize < MINSIZE)
1618                        blocksize = MINSIZE;
1619                len = sizeof(struct stack_block) - MINSIZE + blocksize;
1620                if (len < blocksize)
1621                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
1622                INT_OFF;
1623                sp = ckmalloc(len);
1624                sp->prev = g_stackp;
1625                g_stacknxt = sp->space;
1626                g_stacknleft = blocksize;
1627                sstrend = g_stacknxt + blocksize;
1628                g_stackp = sp;
1629                INT_ON;
1630        }
1631        p = g_stacknxt;
1632        g_stacknxt += aligned;
1633        g_stacknleft -= aligned;
1634        return p;
1635}
1636
1637static void *
1638stzalloc(size_t nbytes)
1639{
1640        return memset(stalloc(nbytes), 0, nbytes);
1641}
1642
1643static void
1644stunalloc(void *p)
1645{
1646#if DEBUG
1647        if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1648                write(STDERR_FILENO, "stunalloc\n", 10);
1649                abort();
1650        }
1651#endif
1652        g_stacknleft += g_stacknxt - (char *)p;
1653        g_stacknxt = p;
1654}
1655
1656/*
1657 * Like strdup but works with the ash stack.
1658 */
1659static char *
1660sstrdup(const char *p)
1661{
1662        size_t len = strlen(p) + 1;
1663        return memcpy(stalloc(len), p, len);
1664}
1665
1666static ALWAYS_INLINE void
1667grabstackblock(size_t len)
1668{
1669        stalloc(len);
1670}
1671
1672static void
1673pushstackmark(struct stackmark *mark, size_t len)
1674{
1675        mark->stackp = g_stackp;
1676        mark->stacknxt = g_stacknxt;
1677        mark->stacknleft = g_stacknleft;
1678        grabstackblock(len);
1679}
1680
1681static void
1682setstackmark(struct stackmark *mark)
1683{
1684        pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1685}
1686
1687static void
1688popstackmark(struct stackmark *mark)
1689{
1690        struct stack_block *sp;
1691
1692        if (!mark->stackp)
1693                return;
1694
1695        INT_OFF;
1696        while (g_stackp != mark->stackp) {
1697                sp = g_stackp;
1698                g_stackp = sp->prev;
1699                free(sp);
1700        }
1701        g_stacknxt = mark->stacknxt;
1702        g_stacknleft = mark->stacknleft;
1703        sstrend = mark->stacknxt + mark->stacknleft;
1704        INT_ON;
1705}
1706
1707/*
1708 * When the parser reads in a string, it wants to stick the string on the
1709 * stack and only adjust the stack pointer when it knows how big the
1710 * string is.  Stackblock (defined in stack.h) returns a pointer to a block
1711 * of space on top of the stack and stackblocklen returns the length of
1712 * this block.  Growstackblock will grow this space by at least one byte,
1713 * possibly moving it (like realloc).  Grabstackblock actually allocates the
1714 * part of the block that has been used.
1715 */
1716static void
1717growstackblock(size_t min)
1718{
1719        size_t newlen;
1720
1721        newlen = g_stacknleft * 2;
1722        if (newlen < g_stacknleft)
1723                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1724        min = SHELL_ALIGN(min | 128);
1725        if (newlen < min)
1726                newlen += min;
1727
1728        if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1729                struct stack_block *sp;
1730                struct stack_block *prevstackp;
1731                size_t grosslen;
1732
1733                INT_OFF;
1734                sp = g_stackp;
1735                prevstackp = sp->prev;
1736                grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1737                sp = ckrealloc(sp, grosslen);
1738                sp->prev = prevstackp;
1739                g_stackp = sp;
1740                g_stacknxt = sp->space;
1741                g_stacknleft = newlen;
1742                sstrend = sp->space + newlen;
1743                INT_ON;
1744        } else {
1745                char *oldspace = g_stacknxt;
1746                size_t oldlen = g_stacknleft;
1747                char *p = stalloc(newlen);
1748
1749                /* free the space we just allocated */
1750                g_stacknxt = memcpy(p, oldspace, oldlen);
1751                g_stacknleft += newlen;
1752        }
1753}
1754
1755/*
1756 * The following routines are somewhat easier to use than the above.
1757 * The user declares a variable of type STACKSTR, which may be declared
1758 * to be a register.  The macro STARTSTACKSTR initializes things.  Then
1759 * the user uses the macro STPUTC to add characters to the string.  In
1760 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1761 * grown as necessary.  When the user is done, she can just leave the
1762 * string there and refer to it using stackblock().  Or she can allocate
1763 * the space for it using grabstackstr().  If it is necessary to allow
1764 * someone else to use the stack temporarily and then continue to grow
1765 * the string, the user should use grabstack to allocate the space, and
1766 * then call ungrabstr(p) to return to the previous mode of operation.
1767 *
1768 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1769 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1770 * is space for at least one character.
1771 */
1772static void *
1773growstackstr(void)
1774{
1775        size_t len = stackblocksize();
1776        growstackblock(0);
1777        return (char *)stackblock() + len;
1778}
1779
1780static char *
1781growstackto(size_t len)
1782{
1783        if (stackblocksize() < len)
1784                growstackblock(len);
1785        return stackblock();
1786}
1787
1788/*
1789 * Called from CHECKSTRSPACE.
1790 */
1791static char *
1792makestrspace(size_t newlen, char *p)
1793{
1794        size_t len = p - g_stacknxt;
1795
1796        return growstackto(len + newlen) + len;
1797}
1798
1799static char *
1800stnputs(const char *s, size_t n, char *p)
1801{
1802        p = makestrspace(n, p);
1803        p = (char *)mempcpy(p, s, n);
1804        return p;
1805}
1806
1807static char *
1808stack_putstr(const char *s, char *p)
1809{
1810        return stnputs(s, strlen(s), p);
1811}
1812
1813static char *
1814_STPUTC(int c, char *p)
1815{
1816        if (p == sstrend)
1817                p = growstackstr();
1818        *p++ = c;
1819        return p;
1820}
1821
1822#define STARTSTACKSTR(p)        ((p) = stackblock())
1823#define STPUTC(c, p)            ((p) = _STPUTC((c), (p)))
1824#define CHECKSTRSPACE(n, p) do { \
1825        char *q = (p); \
1826        size_t l = (n); \
1827        size_t m = sstrend - q; \
1828        if (l > m) \
1829                (p) = makestrspace(l, q); \
1830} while (0)
1831#define USTPUTC(c, p)           (*(p)++ = (c))
1832#define STACKSTRNUL(p) do { \
1833        if ((p) == sstrend) \
1834                (p) = growstackstr(); \
1835        *(p) = '\0'; \
1836} while (0)
1837#define STUNPUTC(p)             (--(p))
1838#define STTOPC(p)               ((p)[-1])
1839#define STADJUST(amount, p)     ((p) += (amount))
1840
1841#define grabstackstr(p)         stalloc((char *)(p) - (char *)stackblock())
1842#define ungrabstackstr(s, p)    stunalloc(s)
1843#define stackstrend()           ((void *)sstrend)
1844
1845
1846/* ============ String helpers */
1847
1848/*
1849 * prefix -- see if pfx is a prefix of string.
1850 */
1851static char *
1852prefix(const char *string, const char *pfx)
1853{
1854        while (*pfx) {
1855                if (*pfx++ != *string++)
1856                        return NULL;
1857        }
1858        return (char *) string;
1859}
1860
1861/*
1862 * Check for a valid number.  This should be elsewhere.
1863 */
1864static int
1865is_number(const char *p)
1866{
1867        do {
1868                if (!isdigit(*p))
1869                        return 0;
1870        } while (*++p != '\0');
1871        return 1;
1872}
1873
1874/*
1875 * Convert a string of digits to an integer, printing an error message on
1876 * failure.
1877 */
1878static int
1879number(const char *s)
1880{
1881        if (!is_number(s))
1882                ash_msg_and_raise_error(msg_illnum, s);
1883        return atoi(s);
1884}
1885
1886/*
1887 * Produce a single quoted string suitable as input to the shell.
1888 * The return string is allocated on the stack.
1889 */
1890static char *
1891single_quote(const char *s)
1892{
1893        char *p;
1894
1895        STARTSTACKSTR(p);
1896
1897        do {
1898                char *q;
1899                size_t len;
1900
1901                len = strchrnul(s, '\'') - s;
1902
1903                q = p = makestrspace(len + 3, p);
1904
1905                *q++ = '\'';
1906                q = (char *)mempcpy(q, s, len);
1907                *q++ = '\'';
1908                s += len;
1909
1910                STADJUST(q - p, p);
1911
1912                if (*s != '\'')
1913                        break;
1914                len = 0;
1915                do len++; while (*++s == '\'');
1916
1917                q = p = makestrspace(len + 3, p);
1918
1919                *q++ = '"';
1920                q = (char *)mempcpy(q, s - len, len);
1921                *q++ = '"';
1922
1923                STADJUST(q - p, p);
1924        } while (*s);
1925
1926        USTPUTC('\0', p);
1927
1928        return stackblock();
1929}
1930
1931/*
1932 * Produce a possibly single quoted string suitable as input to the shell.
1933 * If quoting was done, the return string is allocated on the stack,
1934 * otherwise a pointer to the original string is returned.
1935 */
1936static const char *
1937maybe_single_quote(const char *s)
1938{
1939        const char *p = s;
1940
1941        while (*p) {
1942                /* Assuming ACSII */
1943                /* quote ctrl_chars space !"#$%&'()* */
1944                if (*p < '+')
1945                        goto need_quoting;
1946                /* quote ;<=>? */
1947                if (*p >= ';' && *p <= '?')
1948                        goto need_quoting;
1949                /* quote `[\ */
1950                if (*p == '`')
1951                        goto need_quoting;
1952                if (*p == '[')
1953                        goto need_quoting;
1954                if (*p == '\\')
1955                        goto need_quoting;
1956                /* quote {|}~ DEL and high bytes */
1957                if (*p > 'z')
1958                        goto need_quoting;
1959                /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1960                /* TODO: maybe avoid quoting % */
1961                p++;
1962        }
1963        return s;
1964
1965 need_quoting:
1966        return single_quote(s);
1967}
1968
1969
1970/* ============ nextopt */
1971
1972static char **argptr;                  /* argument list for builtin commands */
1973static char *optionarg;                /* set by nextopt (like getopt) */
1974static char *optptr;                   /* used by nextopt */
1975
1976/*
1977 * XXX - should get rid of. Have all builtins use getopt(3).
1978 * The library getopt must have the BSD extension static variable
1979 * "optreset", otherwise it can't be used within the shell safely.
1980 *
1981 * Standard option processing (a la getopt) for builtin routines.
1982 * The only argument that is passed to nextopt is the option string;
1983 * the other arguments are unnecessary. It returns the character,
1984 * or '\0' on end of input.
1985 */
1986static int
1987nextopt(const char *optstring)
1988{
1989        char *p;
1990        const char *q;
1991        char c;
1992
1993        p = optptr;
1994        if (p == NULL || *p == '\0') {
1995                /* We ate entire "-param", take next one */
1996                p = *argptr;
1997                if (p == NULL)
1998                        return '\0';
1999                if (*p != '-')
2000                        return '\0';
2001                if (*++p == '\0') /* just "-" ? */
2002                        return '\0';
2003                argptr++;
2004                if (LONE_DASH(p)) /* "--" ? */
2005                        return '\0';
2006                /* p => next "-param" */
2007        }
2008        /* p => some option char in the middle of a "-param" */
2009        c = *p++;
2010        for (q = optstring; *q != c;) {
2011                if (*q == '\0')
2012                        ash_msg_and_raise_error("illegal option -%c", c);
2013                if (*++q == ':')
2014                        q++;
2015        }
2016        if (*++q == ':') {
2017                if (*p == '\0') {
2018                        p = *argptr++;
2019                        if (p == NULL)
2020                                ash_msg_and_raise_error("no arg for -%c option", c);
2021                }
2022                optionarg = p;
2023                p = NULL;
2024        }
2025        optptr = p;
2026        return c;
2027}
2028
2029
2030/* ============ Shell variables */
2031
2032struct shparam {
2033        int nparam;             /* # of positional parameters (without $0) */
2034#if ENABLE_ASH_GETOPTS
2035        int optind;             /* next parameter to be processed by getopts */
2036        int optoff;             /* used by getopts */
2037#endif
2038        unsigned char malloced; /* if parameter list dynamically allocated */
2039        char **p;               /* parameter list */
2040};
2041
2042/*
2043 * Free the list of positional parameters.
2044 */
2045static void
2046freeparam(volatile struct shparam *param)
2047{
2048        if (param->malloced) {
2049                char **ap, **ap1;
2050                ap = ap1 = param->p;
2051                while (*ap)
2052                        free(*ap++);
2053                free(ap1);
2054        }
2055}
2056
2057#if ENABLE_ASH_GETOPTS
2058static void FAST_FUNC getoptsreset(const char *value);
2059#endif
2060
2061struct var {
2062        struct var *next;               /* next entry in hash list */
2063        int flags;                      /* flags are defined above */
2064        const char *var_text;           /* name=value */
2065        void (*var_func)(const char *) FAST_FUNC; /* function to be called when  */
2066                                        /* the variable gets set/unset */
2067};
2068
2069struct localvar {
2070        struct localvar *next;          /* next local variable in list */
2071        struct var *vp;                 /* the variable that was made local */
2072        int flags;                      /* saved flags */
2073        const char *text;               /* saved text */
2074};
2075
2076/* flags */
2077#define VEXPORT         0x01    /* variable is exported */
2078#define VREADONLY       0x02    /* variable cannot be modified */
2079#define VSTRFIXED       0x04    /* variable struct is statically allocated */
2080#define VTEXTFIXED      0x08    /* text is statically allocated */
2081#define VSTACK          0x10    /* text is allocated on the stack */
2082#define VUNSET          0x20    /* the variable is not set */
2083#define VNOFUNC         0x40    /* don't call the callback function */
2084#define VNOSET          0x80    /* do not set variable - just readonly test */
2085#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
2086#if ENABLE_ASH_RANDOM_SUPPORT
2087# define VDYNAMIC       0x200   /* dynamic variable */
2088#else
2089# define VDYNAMIC       0
2090#endif
2091
2092
2093/* Need to be before varinit_data[] */
2094#if ENABLE_LOCALE_SUPPORT
2095static void FAST_FUNC
2096change_lc_all(const char *value)
2097{
2098        if (value && *value != '\0')
2099                setlocale(LC_ALL, value);
2100}
2101static void FAST_FUNC
2102change_lc_ctype(const char *value)
2103{
2104        if (value && *value != '\0')
2105                setlocale(LC_CTYPE, value);
2106}
2107#endif
2108#if ENABLE_ASH_MAIL
2109static void chkmail(void);
2110static void changemail(const char *var_value) FAST_FUNC;
2111#else
2112# define chkmail()  ((void)0)
2113#endif
2114static void changepath(const char *) FAST_FUNC;
2115#if ENABLE_ASH_RANDOM_SUPPORT
2116static void change_random(const char *) FAST_FUNC;
2117#endif
2118#if BASH_EPOCH_VARS
2119static void change_seconds(const char *) FAST_FUNC;
2120static void change_realtime(const char *) FAST_FUNC;
2121#endif
2122
2123static const struct {
2124        int flags;
2125        const char *var_text;
2126        void (*var_func)(const char *) FAST_FUNC;
2127} varinit_data[] ALIGN_PTR = {
2128        /*
2129         * Note: VEXPORT would not work correctly here for NOFORK applets:
2130         * some environment strings may be constant.
2131         */
2132        { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
2133#if ENABLE_ASH_MAIL
2134        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL"      , changemail      },
2135        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH"  , changemail      },
2136#endif
2137        { VSTRFIXED|VTEXTFIXED       , bb_PATH_root_path, changepath },
2138        { VSTRFIXED|VTEXTFIXED       , "PS1=$ "    , NULL            },
2139        { VSTRFIXED|VTEXTFIXED       , "PS2=> "    , NULL            },
2140        { VSTRFIXED|VTEXTFIXED       , "PS4=+ "    , NULL            },
2141#if ENABLE_ASH_GETOPTS
2142        { VSTRFIXED|VTEXTFIXED       , defoptindvar, getoptsreset    },
2143#endif
2144        { VSTRFIXED|VTEXTFIXED       , NULL /* inited to linenovar */, NULL },
2145        { VSTRFIXED|VTEXTFIXED       , NULL /* inited to funcnamevar */, NULL },
2146#if ENABLE_ASH_RANDOM_SUPPORT
2147        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2148#endif
2149#if BASH_EPOCH_VARS
2150        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHSECONDS", change_seconds },
2151        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHREALTIME", change_realtime },
2152#endif
2153#if ENABLE_LOCALE_SUPPORT
2154        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL"    , change_lc_all   },
2155        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE"  , change_lc_ctype },
2156#endif
2157#if ENABLE_FEATURE_EDITING_SAVEHISTORY
2158        { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE"  , NULL            },
2159#endif
2160};
2161
2162struct redirtab;
2163
2164struct globals_var {
2165        struct shparam shellparam;      /* $@ current positional parameters */
2166        struct redirtab *redirlist;
2167        int preverrout_fd;   /* stderr fd: usually 2, unless redirect moved it */
2168        struct var *vartab[VTABSIZE];
2169        struct var varinit[ARRAY_SIZE(varinit_data)];
2170        int lineno;
2171        char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2172        char funcnamevar[sizeof("FUNCNAME=") + 64];
2173        char *funcname;
2174        unsigned trap_depth;
2175        bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */
2176};
2177extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2178#define G_var (*ash_ptr_to_globals_var)
2179#define shellparam    (G_var.shellparam   )
2180//#define redirlist     (G_var.redirlist    )
2181#define preverrout_fd (G_var.preverrout_fd)
2182#define vartab        (G_var.vartab       )
2183#define varinit       (G_var.varinit      )
2184#define lineno        (G_var.lineno       )
2185#define linenovar     (G_var.linenovar    )
2186#define funcnamevar   (G_var.funcnamevar  )
2187#define funcname      (G_var.funcname     )
2188#define trap_depth    (G_var.trap_depth   )
2189#define in_trap_ERR   (G_var.in_trap_ERR  )
2190#define vifs      varinit[0]
2191#if ENABLE_ASH_MAIL
2192# define vmail    varinit[1]
2193# define vmpath   varinit[2]
2194#endif
2195#define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
2196#define vpath     varinit[VAR_OFFSET1 + 1]
2197#define vps1      varinit[VAR_OFFSET1 + 2]
2198#define vps2      varinit[VAR_OFFSET1 + 3]
2199#define vps4      varinit[VAR_OFFSET1 + 4]
2200#if ENABLE_ASH_GETOPTS
2201# define voptind  varinit[VAR_OFFSET1 + 5]
2202#endif
2203#define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
2204#define vlineno   varinit[VAR_OFFSET2 + 5]
2205#define vfuncname varinit[VAR_OFFSET2 + 6]
2206#if ENABLE_ASH_RANDOM_SUPPORT
2207# define vrandom  varinit[VAR_OFFSET2 + 7]
2208#endif
2209#define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
2210#if BASH_EPOCH_VARS
2211# define vepochs  varinit[VAR_OFFSET3 + 7]
2212# define vepochr  varinit[VAR_OFFSET3 + 8]
2213#endif
2214#define INIT_G_var() do { \
2215        unsigned i; \
2216        XZALLOC_CONST_PTR(&ash_ptr_to_globals_var, sizeof(G_var)); \
2217        for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2218                varinit[i].flags    = varinit_data[i].flags; \
2219                varinit[i].var_text = varinit_data[i].var_text; \
2220                varinit[i].var_func = varinit_data[i].var_func; \
2221        } \
2222        strcpy(linenovar, "LINENO="); \
2223        vlineno.var_text = linenovar; \
2224        strcpy(funcnamevar, "FUNCNAME="); \
2225        vfuncname.var_text = funcnamevar; \
2226} while (0)
2227
2228/*
2229 * The following macros access the values of the above variables.
2230 * They have to skip over the name.  They return the null string
2231 * for unset variables.
2232 */
2233#define ifsval()        (vifs.var_text + 4)
2234#define ifsset()        ((vifs.flags & VUNSET) == 0)
2235#if ENABLE_ASH_MAIL
2236# define mailval()      (vmail.var_text + 5)
2237# define mpathval()     (vmpath.var_text + 9)
2238# define mpathset()     ((vmpath.flags & VUNSET) == 0)
2239#endif
2240#define pathval()       (vpath.var_text + 5)
2241#define ps1val()        (vps1.var_text + 4)
2242#define ps2val()        (vps2.var_text + 4)
2243#define ps4val()        (vps4.var_text + 4)
2244#if ENABLE_ASH_GETOPTS
2245# define optindval()    (voptind.var_text + 7)
2246#endif
2247
2248#if ENABLE_ASH_GETOPTS
2249static void FAST_FUNC
2250getoptsreset(const char *value)
2251{
2252        shellparam.optind = 1;
2253        if (is_number(value))
2254                shellparam.optind = number(value) ?: 1;
2255        shellparam.optoff = -1;
2256}
2257#endif
2258
2259/*
2260 * Compares two strings up to the first = or '\0'.  The first
2261 * string must be terminated by '='; the second may be terminated by
2262 * either '=' or '\0'.
2263 */
2264static int
2265varcmp(const char *p, const char *q)
2266{
2267        int c, d;
2268
2269        while ((c = *p) == (d = *q)) {
2270                if (c == '\0' || c == '=')
2271                        goto out;
2272                p++;
2273                q++;
2274        }
2275        if (c == '=')
2276                c = '\0';
2277        if (d == '=')
2278                d = '\0';
2279 out:
2280        return c - d;
2281}
2282
2283/*
2284 * Find the appropriate entry in the hash table from the name.
2285 */
2286static struct var **
2287hashvar(const char *p)
2288{
2289        unsigned hashval;
2290
2291        hashval = ((unsigned char) *p) << 4;
2292        while (*p && *p != '=')
2293                hashval += (unsigned char) *p++;
2294        return &vartab[hashval % VTABSIZE];
2295}
2296
2297static int
2298vpcmp(const void *a, const void *b)
2299{
2300        return varcmp(*(const char **)a, *(const char **)b);
2301}
2302
2303/*
2304 * This routine initializes the builtin variables.
2305 */
2306static void
2307initvar(void)
2308{
2309        struct var *vp;
2310        struct var *end;
2311        struct var **vpp;
2312
2313        /*
2314         * PS1 depends on uid
2315         */
2316#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2317        vps1.var_text = "PS1=\\w \\$ ";
2318#else
2319        if (!geteuid())
2320                vps1.var_text = "PS1=# ";
2321#endif
2322        vp = varinit;
2323        end = vp + ARRAY_SIZE(varinit);
2324        do {
2325                vpp = hashvar(vp->var_text);
2326                vp->next = *vpp;
2327                *vpp = vp;
2328        } while (++vp < end);
2329}
2330
2331static struct var **
2332findvar(struct var **vpp, const char *name)
2333{
2334        for (; *vpp; vpp = &(*vpp)->next) {
2335                if (varcmp((*vpp)->var_text, name) == 0) {
2336                        break;
2337                }
2338        }
2339        return vpp;
2340}
2341
2342/*
2343 * Find the value of a variable.  Returns NULL if not set.
2344 */
2345static const char* FAST_FUNC
2346lookupvar(const char *name)
2347{
2348        struct var *v;
2349
2350        v = *findvar(hashvar(name), name);
2351        if (v) {
2352#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2353        /*
2354         * Dynamic variables are implemented roughly the same way they are
2355         * in bash. Namely, they're "special" so long as they aren't unset.
2356         * As soon as they're unset, they're no longer dynamic, and dynamic
2357         * lookup will no longer happen at that point. -- PFM.
2358         */
2359                if (v->flags & VDYNAMIC)
2360                        v->var_func(NULL);
2361#endif
2362                if (!(v->flags & VUNSET)) {
2363                        if (v->var_text == linenovar) {
2364                                fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2365                        } else
2366                        if (v->var_text == funcnamevar) {
2367                                safe_strncpy(funcnamevar+9, funcname ? funcname : "", sizeof(funcnamevar)-9);
2368                        }
2369                        return var_end(v->var_text);
2370                }
2371        }
2372        return NULL;
2373}
2374
2375#if ENABLE_UNICODE_SUPPORT
2376static void
2377reinit_unicode_for_ash(void)
2378{
2379        /* Unicode support should be activated even if LANG is set
2380         * _during_ shell execution, not only if it was set when
2381         * shell was started. Therefore, re-check LANG every time:
2382         */
2383        if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2384         || ENABLE_UNICODE_USING_LOCALE
2385        ) {
2386                const char *s = lookupvar("LC_ALL");
2387                if (!s) s = lookupvar("LC_CTYPE");
2388                if (!s) s = lookupvar("LANG");
2389                reinit_unicode(s);
2390        }
2391}
2392#else
2393# define reinit_unicode_for_ash() ((void)0)
2394#endif
2395
2396/*
2397 * Search the environment of a builtin command.
2398 */
2399static ALWAYS_INLINE const char *
2400bltinlookup(const char *name)
2401{
2402        return lookupvar(name);
2403}
2404
2405/*
2406 * Same as setvar except that the variable and value are passed in
2407 * the first argument as name=value.  Since the first argument will
2408 * be actually stored in the table, it should not be a string that
2409 * will go away.
2410 * Called with interrupts off.
2411 */
2412static struct var *
2413setvareq(char *s, int flags)
2414{
2415        struct var *vp, **vpp;
2416
2417        vpp = hashvar(s);
2418        flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2419        vpp = findvar(vpp, s);
2420        vp = *vpp;
2421        if (vp) {
2422                if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2423                        const char *n;
2424
2425                        if (flags & VNOSAVE)
2426                                free(s);
2427                        n = vp->var_text;
2428                        exitstatus = 1;
2429                        ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2430                }
2431
2432                if (flags & VNOSET)
2433                        goto out;
2434
2435                if (vp->var_func && !(flags & VNOFUNC))
2436                        vp->var_func(var_end(s));
2437
2438                if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2439                        free((char*)vp->var_text);
2440
2441                if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2442                        *vpp = vp->next;
2443                        free(vp);
2444 out_free:
2445                        if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2446                                free(s);
2447                        goto out;
2448                }
2449
2450                flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2451#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2452                if (flags & VUNSET)
2453                        flags &= ~VDYNAMIC;
2454#endif
2455        } else {
2456                /* variable s is not found */
2457                if (flags & VNOSET)
2458                        goto out;
2459                if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2460                        goto out_free;
2461                vp = ckzalloc(sizeof(*vp));
2462                vp->next = *vpp;
2463                /*vp->func = NULL; - ckzalloc did it */
2464                *vpp = vp;
2465        }
2466        if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2467                s = ckstrdup(s);
2468        vp->var_text = s;
2469        vp->flags = flags;
2470
2471 out:
2472        return vp;
2473}
2474
2475/*
2476 * Set the value of a variable.  The flags argument is ored with the
2477 * flags of the variable.  If val is NULL, the variable is unset.
2478 */
2479static struct var *
2480setvar(const char *name, const char *val, int flags)
2481{
2482        const char *q;
2483        char *p;
2484        char *nameeq;
2485        size_t namelen;
2486        size_t vallen;
2487        struct var *vp;
2488
2489        q = endofname(name);
2490        p = strchrnul(q, '=');
2491        namelen = p - name;
2492        if (!namelen || p != q)
2493                ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2494        vallen = 0;
2495        if (val == NULL) {
2496                flags |= VUNSET;
2497        } else {
2498                vallen = strlen(val);
2499        }
2500
2501        INT_OFF;
2502        nameeq = ckzalloc(namelen + vallen + 2);
2503        p = mempcpy(nameeq, name, namelen);
2504        if (val) {
2505                *p++ = '=';
2506                memcpy(p, val, vallen);
2507        }
2508        vp = setvareq(nameeq, flags | VNOSAVE);
2509        INT_ON;
2510
2511        return vp;
2512}
2513
2514static void FAST_FUNC
2515setvar0(const char *name, const char *val)
2516{
2517        setvar(name, val, 0);
2518}
2519
2520/*
2521 * Unset the specified variable.
2522 */
2523static void
2524unsetvar(const char *s)
2525{
2526        setvar(s, NULL, 0);
2527}
2528
2529/*
2530 * Generate a list of variables satisfying the given conditions.
2531 */
2532#if !ENABLE_FEATURE_SH_NOFORK
2533# define listvars(on, off, lp, end) listvars(on, off, end)
2534#endif
2535static char **
2536listvars(int on, int off, struct strlist *lp, char ***end)
2537{
2538        struct var **vpp;
2539        struct var *vp;
2540        char **ep;
2541        int mask;
2542
2543        STARTSTACKSTR(ep);
2544        vpp = vartab;
2545        mask = on | off;
2546        do {
2547                for (vp = *vpp; vp; vp = vp->next) {
2548                        if ((vp->flags & mask) == on) {
2549#if ENABLE_FEATURE_SH_NOFORK
2550                                /* If variable with the same name is both
2551                                 * exported and temporarily set for a command:
2552                                 *  export ZVAR=5
2553                                 *  ZVAR=6 printenv
2554                                 * then "ZVAR=6" will be both in vartab and
2555                                 * lp lists. Do not pass it twice to printenv.
2556                                 */
2557                                struct strlist *lp1 = lp;
2558                                while (lp1) {
2559                                        if (strcmp(lp1->text, vp->var_text) == 0)
2560                                                goto skip;
2561                                        lp1 = lp1->next;
2562                                }
2563#endif
2564                                if (ep == stackstrend())
2565                                        ep = growstackstr();
2566                                *ep++ = (char*)vp->var_text;
2567#if ENABLE_FEATURE_SH_NOFORK
2568 skip: ;
2569#endif
2570                        }
2571                }
2572        } while (++vpp < vartab + VTABSIZE);
2573
2574#if ENABLE_FEATURE_SH_NOFORK
2575        while (lp) {
2576                if (ep == stackstrend())
2577                        ep = growstackstr();
2578                *ep++ = lp->text;
2579                lp = lp->next;
2580        }
2581#endif
2582
2583        if (ep == stackstrend())
2584                ep = growstackstr();
2585        if (end)
2586                *end = ep;
2587        *ep++ = NULL;
2588        return grabstackstr(ep);
2589}
2590
2591
2592/* ============ Path search helper */
2593static const char *
2594legal_pathopt(const char *opt, const char *term, int magic)
2595{
2596        switch (magic) {
2597        case 0:
2598                opt = NULL;
2599                break;
2600
2601        case 1:
2602                opt = prefix(opt, "builtin") ?: prefix(opt, "func");
2603                break;
2604
2605        default:
2606                opt += strcspn(opt, term);
2607                break;
2608        }
2609
2610        if (opt && *opt == '%')
2611                opt++;
2612
2613        return opt;
2614}
2615
2616/*
2617 * The variable path (passed by reference) should be set to the start
2618 * of the path before the first call; padvance will update
2619 * this value as it proceeds.  Successive calls to padvance will return
2620 * the possible path expansions in sequence.  If an option (indicated by
2621 * a percent sign) appears in the path entry then the global variable
2622 * pathopt will be set to point to it; otherwise pathopt will be set to
2623 * NULL.
2624 *
2625 * If magic is 0 then pathopt recognition will be disabled.  If magic is
2626 * 1 we shall recognise %builtin/%func.  Otherwise we shall accept any
2627 * pathopt.
2628 */
2629static const char *pathopt;     /* set by padvance */
2630
2631static int
2632padvance_magic(const char **path, const char *name, int magic)
2633{
2634        const char *term = "%:";
2635        const char *lpathopt;
2636        const char *p;
2637        char *q;
2638        const char *start;
2639        size_t qlen;
2640        size_t len;
2641
2642        if (*path == NULL)
2643                return -1;
2644
2645        lpathopt = NULL;
2646        start = *path;
2647
2648        if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) {
2649                lpathopt = start + 1;
2650                start = p;
2651                term = ":";
2652        }
2653
2654        len = strcspn(start, term);
2655        p = start + len;
2656
2657        if (*p == '%') {
2658                size_t extra = strchrnul(p, ':') - p;
2659
2660                if (legal_pathopt(p + 1, term, magic))
2661                        lpathopt = p + 1;
2662                else
2663                        len += extra;
2664
2665                p += extra;
2666        }
2667
2668        pathopt = lpathopt;
2669        *path = *p == ':' ? p + 1 : NULL;
2670
2671        /* "2" is for '/' and '\0' */
2672        qlen = len + strlen(name) + 2;
2673        q = growstackto(qlen);
2674
2675        if (len) {
2676                q = mempcpy(q, start, len);
2677                *q++ = '/';
2678        }
2679        strcpy(q, name);
2680
2681        return qlen;
2682}
2683
2684static int
2685padvance(const char **path, const char *name)
2686{
2687        return padvance_magic(path, name, 1);
2688}
2689
2690
2691/* ============ Prompt */
2692
2693static smallint doprompt;                   /* if set, prompt the user */
2694static smallint needprompt;                 /* true if interactive and at start of line */
2695
2696#if ENABLE_FEATURE_EDITING
2697static line_input_t *line_input_state;
2698static const char *cmdedit_prompt;
2699static void
2700putprompt(const char *s)
2701{
2702        if (ENABLE_ASH_EXPAND_PRMT) {
2703                free((char*)cmdedit_prompt);
2704                cmdedit_prompt = ckstrdup(s);
2705                return;
2706        }
2707        cmdedit_prompt = s;
2708}
2709#else
2710static void
2711putprompt(const char *s)
2712{
2713        out2str(s);
2714}
2715#endif
2716
2717/* expandstr() needs parsing machinery, so it is far away ahead... */
2718static const char *expandstr(const char *ps, int syntax_type);
2719/* Values for syntax param */
2720#define BASESYNTAX 0    /* not in quotes */
2721#define DQSYNTAX   1    /* in double quotes */
2722#define SQSYNTAX   2    /* in single quotes */
2723#define ARISYNTAX  3    /* in arithmetic */
2724#if ENABLE_ASH_EXPAND_PRMT
2725# define PSSYNTAX  4    /* prompt. never passed to SIT() */
2726#endif
2727/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
2728
2729/*
2730 * called by editline -- any expansions to the prompt should be added here.
2731 */
2732static void
2733setprompt_if(smallint do_set, int whichprompt)
2734{
2735        const char *prompt;
2736        IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2737
2738        if (!do_set)
2739                return;
2740
2741        needprompt = 0;
2742
2743        switch (whichprompt) {
2744        case 1:
2745                prompt = ps1val();
2746                break;
2747        case 2:
2748                prompt = ps2val();
2749                break;
2750        default:                        /* 0 */
2751                prompt = nullstr;
2752        }
2753#if ENABLE_ASH_EXPAND_PRMT
2754        pushstackmark(&smark, stackblocksize());
2755        putprompt(expandstr(prompt, PSSYNTAX));
2756        popstackmark(&smark);
2757#else
2758        putprompt(prompt);
2759#endif
2760}
2761
2762
2763/* ============ The cd and pwd commands */
2764
2765#define CD_PHYSICAL 1
2766#define CD_PRINT 2
2767
2768static int
2769cdopt(void)
2770{
2771        int flags = 0;
2772        int i, j;
2773
2774        j = 'L';
2775        while ((i = nextopt("LP")) != '\0') {
2776                if (i != j) {
2777                        flags ^= CD_PHYSICAL;
2778                        j = i;
2779                }
2780        }
2781
2782        return flags;
2783}
2784
2785/*
2786 * Update curdir (the name of the current directory) in response to a
2787 * cd command.
2788 */
2789static const char *
2790updatepwd(const char *dir)
2791{
2792        char *new;
2793        char *p;
2794        char *cdcomppath;
2795        const char *lim;
2796
2797        cdcomppath = sstrdup(dir);
2798        STARTSTACKSTR(new);
2799        if (*dir != '/') {
2800                if (curdir == nullstr)
2801                        return 0;
2802                new = stack_putstr(curdir, new);
2803        }
2804        new = makestrspace(strlen(dir) + 2, new);
2805        lim = (char *)stackblock() + 1;
2806        if (*dir != '/') {
2807                if (new[-1] != '/')
2808                        USTPUTC('/', new);
2809                if (new > lim && *lim == '/')
2810                        lim++;
2811        } else {
2812                USTPUTC('/', new);
2813                cdcomppath++;
2814                if (dir[1] == '/' && dir[2] != '/') {
2815                        USTPUTC('/', new);
2816                        cdcomppath++;
2817                        lim++;
2818                }
2819        }
2820        p = strtok_r(cdcomppath, "/", &cdcomppath);
2821        while (p) {
2822                switch (*p) {
2823                case '.':
2824                        if (p[1] == '.' && p[2] == '\0') {
2825                                while (new > lim) {
2826                                        STUNPUTC(new);
2827                                        if (new[-1] == '/')
2828                                                break;
2829                                }
2830                                break;
2831                        }
2832                        if (p[1] == '\0')
2833                                break;
2834                        /* fall through */
2835                default:
2836                        new = stack_putstr(p, new);
2837                        USTPUTC('/', new);
2838                }
2839                p = strtok_r(NULL, "/", &cdcomppath);
2840        }
2841        if (new > lim)
2842                STUNPUTC(new);
2843        *new = 0;
2844        return stackblock();
2845}
2846
2847/*
2848 * Find out what the current directory is. If we already know the current
2849 * directory, this routine returns immediately.
2850 */
2851static char *
2852getpwd(void)
2853{
2854        char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2855        return dir ? dir : nullstr;
2856}
2857
2858static void
2859setpwd(const char *val, int setold)
2860{
2861        char *oldcur, *dir;
2862
2863        oldcur = dir = curdir;
2864
2865        if (setold) {
2866                setvar("OLDPWD", oldcur, VEXPORT);
2867        }
2868        INT_OFF;
2869        if (physdir != nullstr) {
2870                if (physdir != oldcur)
2871                        free(physdir);
2872                physdir = nullstr;
2873        }
2874        if (oldcur == val || !val) {
2875                char *s = getpwd();
2876                physdir = s;
2877                if (!val)
2878                        dir = s;
2879        } else
2880                dir = ckstrdup(val);
2881        if (oldcur != dir && oldcur != nullstr) {
2882                free(oldcur);
2883        }
2884        curdir = dir;
2885        INT_ON;
2886        setvar("PWD", dir, VEXPORT);
2887}
2888
2889static void hashcd(void);
2890
2891/*
2892 * Actually do the chdir.  We also call hashcd to let other routines
2893 * know that the current directory has changed.
2894 */
2895static int
2896docd(const char *dest, int flags)
2897{
2898        const char *dir = NULL;
2899        int err;
2900
2901        TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2902
2903        INT_OFF;
2904        if (!(flags & CD_PHYSICAL)) {
2905                dir = updatepwd(dest);
2906                if (dir)
2907                        dest = dir;
2908        }
2909        err = chdir(dest);
2910        if (err)
2911                goto out;
2912        setpwd(dir, 1);
2913        hashcd();
2914 out:
2915        INT_ON;
2916        return err;
2917}
2918
2919static int FAST_FUNC
2920cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2921{
2922        const char *dest;
2923        const char *path;
2924        const char *p;
2925        char c;
2926        struct stat statb;
2927        int flags;
2928        int len;
2929
2930        flags = cdopt();
2931        dest = *argptr;
2932        if (!dest)
2933                dest = bltinlookup("HOME");
2934        else if (LONE_DASH(dest)) {
2935                dest = bltinlookup("OLDPWD");
2936                flags |= CD_PRINT;
2937        }
2938        if (!dest)
2939                dest = nullstr;
2940        if (*dest == '/')
2941                goto step6;
2942        if (*dest == '.') {
2943                c = dest[1];
2944 dotdot:
2945                switch (c) {
2946                case '\0':
2947                case '/':
2948                        goto step6;
2949                case '.':
2950                        c = dest[2];
2951                        if (c != '.')
2952                                goto dotdot;
2953                }
2954        }
2955        if (!*dest)
2956                dest = ".";
2957        path = bltinlookup("CDPATH");
2958        while (p = path, (len = padvance(&path, dest)) >= 0) {
2959                c = *p;
2960                p = stalloc(len);
2961
2962                if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2963                        if (c && c != ':')
2964                                flags |= CD_PRINT;
2965 docd:
2966                        if (!docd(p, flags))
2967                                goto out;
2968                        goto err;
2969                }
2970        }
2971
2972 step6:
2973        p = dest;
2974        goto docd;
2975
2976 err:
2977        ash_msg_and_raise_perror("can't cd to %s", dest);
2978        /* NOTREACHED */
2979 out:
2980        if (flags & CD_PRINT)
2981                out1fmt("%s\n", curdir);
2982        return 0;
2983}
2984
2985static int FAST_FUNC
2986pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2987{
2988        int flags;
2989        const char *dir = curdir;
2990
2991        flags = cdopt();
2992        if (flags) {
2993                if (physdir == nullstr)
2994                        setpwd(dir, 0);
2995                dir = physdir;
2996        }
2997        out1fmt("%s\n", dir);
2998        return 0;
2999}
3000
3001
3002/* ============ ... */
3003
3004
3005#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
3006
3007/* Syntax classes */
3008#define CWORD     0             /* character is nothing special */
3009#define CNL       1             /* newline character */
3010#define CBACK     2             /* a backslash character */
3011#define CSQUOTE   3             /* single quote */
3012#define CDQUOTE   4             /* double quote */
3013#define CENDQUOTE 5             /* a terminating quote */
3014#define CBQUOTE   6             /* backwards single quote */
3015#define CVAR      7             /* a dollar sign */
3016#define CENDVAR   8             /* a '}' character */
3017#define CLP       9             /* a left paren in arithmetic */
3018#define CRP      10             /* a right paren in arithmetic */
3019#define CENDFILE 11             /* end of file */
3020#define CCTL     12             /* like CWORD, except it must be escaped */
3021#define CSPCL    13             /* these terminate a word */
3022
3023#define PEOF     256
3024
3025#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
3026
3027#if ENABLE_FEATURE_SH_MATH
3028# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
3029#else
3030# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
3031#endif
3032static const uint16_t S_I_T[] ALIGN2 = {
3033        SIT_ITEM(CSPCL   , CWORD    , CWORD, CWORD  ),    /* 0, ' ' */
3034        SIT_ITEM(CNL     , CNL      , CNL  , CNL    ),    /* 1, \n */
3035        SIT_ITEM(CWORD   , CCTL     , CCTL , CWORD  ),    /* 2, !*-/:=?[]~ */
3036        SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD  ),    /* 3, '"' */
3037        SIT_ITEM(CVAR    , CVAR     , CWORD, CVAR   ),    /* 4, $ */
3038        SIT_ITEM(CSQUOTE , CWORD    , CENDQUOTE, CWORD),  /* 5, "'" */
3039        SIT_ITEM(CSPCL   , CWORD    , CWORD, CLP    ),    /* 6, ( */
3040        SIT_ITEM(CSPCL   , CWORD    , CWORD, CRP    ),    /* 7, ) */
3041        SIT_ITEM(CBACK   , CBACK    , CCTL , CBACK  ),    /* 8, \ */
3042        SIT_ITEM(CBQUOTE , CBQUOTE  , CWORD, CBQUOTE),    /* 9, ` */
3043        SIT_ITEM(CENDVAR , CENDVAR  , CWORD, CENDVAR),    /* 10, } */
3044#if !USE_SIT_FUNCTION
3045        SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 11, PEOF */
3046        SIT_ITEM(CWORD   , CWORD    , CWORD, CWORD  ),    /* 12, 0-9A-Za-z */
3047        SIT_ITEM(CCTL    , CCTL     , CCTL , CCTL   )     /* 13, CTLESC ... */
3048#endif
3049#undef SIT_ITEM
3050};
3051/* Constants below must match table above */
3052enum {
3053        CSPCL_CWORD_CWORD_CWORD            , /*  0 */
3054        CNL_CNL_CNL_CNL                    , /*  1 */
3055        CWORD_CCTL_CCTL_CWORD              , /*  2 */
3056        CDQUOTE_CENDQUOTE_CWORD_CWORD      , /*  3 */
3057        CVAR_CVAR_CWORD_CVAR               , /*  4 */
3058        CSQUOTE_CWORD_CENDQUOTE_CWORD      , /*  5 */
3059        CSPCL_CWORD_CWORD_CLP              , /*  6 */
3060        CSPCL_CWORD_CWORD_CRP              , /*  7 */
3061        CBACK_CBACK_CCTL_CBACK             , /*  8 */
3062        CBQUOTE_CBQUOTE_CWORD_CBQUOTE      , /*  9 */
3063        CENDVAR_CENDVAR_CWORD_CENDVAR      , /* 10 */
3064        CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 11 */
3065        CWORD_CWORD_CWORD_CWORD            , /* 12 */
3066        CCTL_CCTL_CCTL_CCTL                , /* 13 */
3067};
3068
3069/* c in SIT(c, syntax) must be an *unsigned char* or PEOF,
3070 * caller must ensure proper cast on it if c is *char_ptr!
3071 */
3072#if USE_SIT_FUNCTION
3073
3074static int
3075SIT(int c, int syntax)
3076{
3077        /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
3078        static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
3079        /*
3080         * This causes '/' to be prepended with CTLESC in dquoted string,
3081         * making "./file"* treated incorrectly because we feed
3082         * ".\/file*" string to glob(), confusing it (see expandmeta func).
3083         * The "homegrown" glob implementation is okay with that,
3084         * but glibc one isn't. With '/' always treated as CWORD,
3085         * both work fine.
3086         */
3087        static const uint8_t syntax_index_table[] ALIGN1 = {
3088                0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
3089                6, 7, 2, 2,/*2,*/2, 0, 0,       /* "()*-/:;<" */
3090                2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
3091                10, 2                           /* "}~" */
3092        };
3093        const char *s;
3094        int indx;
3095
3096        if (c == PEOF)
3097                return CENDFILE;
3098        /* Cast is purely for paranoia here,
3099         * just in case someone passed signed char to us */
3100        if ((unsigned char)c >= CTL_FIRST
3101         && (unsigned char)c <= CTL_LAST
3102        ) {
3103                return CCTL;
3104        }
3105        s = strchrnul(spec_symbls, c);
3106        if (*s == '\0')
3107                return CWORD;
3108        indx = syntax_index_table[s - spec_symbls];
3109        return (S_I_T[indx] >> (syntax*4)) & 0xf;
3110}
3111
3112#else   /* !USE_SIT_FUNCTION */
3113
3114static const uint8_t syntax_index_table[] ALIGN1 = {
3115        /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
3116        /*   0      */ CWORD_CWORD_CWORD_CWORD,
3117        /*   1      */ CWORD_CWORD_CWORD_CWORD,
3118        /*   2      */ CWORD_CWORD_CWORD_CWORD,
3119        /*   3      */ CWORD_CWORD_CWORD_CWORD,
3120        /*   4      */ CWORD_CWORD_CWORD_CWORD,
3121        /*   5      */ CWORD_CWORD_CWORD_CWORD,
3122        /*   6      */ CWORD_CWORD_CWORD_CWORD,
3123        /*   7      */ CWORD_CWORD_CWORD_CWORD,
3124        /*   8      */ CWORD_CWORD_CWORD_CWORD,
3125        /*   9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3126        /*  10 "\n" */ CNL_CNL_CNL_CNL,
3127        /*  11      */ CWORD_CWORD_CWORD_CWORD,
3128        /*  12      */ CWORD_CWORD_CWORD_CWORD,
3129        /*  13      */ CWORD_CWORD_CWORD_CWORD,
3130        /*  14      */ CWORD_CWORD_CWORD_CWORD,
3131        /*  15      */ CWORD_CWORD_CWORD_CWORD,
3132        /*  16      */ CWORD_CWORD_CWORD_CWORD,
3133        /*  17      */ CWORD_CWORD_CWORD_CWORD,
3134        /*  18      */ CWORD_CWORD_CWORD_CWORD,
3135        /*  19      */ CWORD_CWORD_CWORD_CWORD,
3136        /*  20      */ CWORD_CWORD_CWORD_CWORD,
3137        /*  21      */ CWORD_CWORD_CWORD_CWORD,
3138        /*  22      */ CWORD_CWORD_CWORD_CWORD,
3139        /*  23      */ CWORD_CWORD_CWORD_CWORD,
3140        /*  24      */ CWORD_CWORD_CWORD_CWORD,
3141        /*  25      */ CWORD_CWORD_CWORD_CWORD,
3142        /*  26      */ CWORD_CWORD_CWORD_CWORD,
3143        /*  27      */ CWORD_CWORD_CWORD_CWORD,
3144        /*  28      */ CWORD_CWORD_CWORD_CWORD,
3145        /*  29      */ CWORD_CWORD_CWORD_CWORD,
3146        /*  30      */ CWORD_CWORD_CWORD_CWORD,
3147        /*  31      */ CWORD_CWORD_CWORD_CWORD,
3148        /*  32  " " */ CSPCL_CWORD_CWORD_CWORD,
3149        /*  33  "!" */ CWORD_CCTL_CCTL_CWORD,
3150        /*  34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3151        /*  35  "#" */ CWORD_CWORD_CWORD_CWORD,
3152        /*  36  "$" */ CVAR_CVAR_CWORD_CVAR,
3153        /*  37  "%" */ CWORD_CWORD_CWORD_CWORD,
3154        /*  38  "&" */ CSPCL_CWORD_CWORD_CWORD,
3155        /*  39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3156        /*  40  "(" */ CSPCL_CWORD_CWORD_CLP,
3157        /*  41  ")" */ CSPCL_CWORD_CWORD_CRP,
3158        /*  42  "*" */ CWORD_CCTL_CCTL_CWORD,
3159        /*  43  "+" */ CWORD_CWORD_CWORD_CWORD,
3160        /*  44  "," */ CWORD_CWORD_CWORD_CWORD,
3161        /*  45  "-" */ CWORD_CCTL_CCTL_CWORD,
3162        /*  46  "." */ CWORD_CWORD_CWORD_CWORD,
3163/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3164        /*  47  "/" */ CWORD_CWORD_CWORD_CWORD,
3165        /*  48  "0" */ CWORD_CWORD_CWORD_CWORD,
3166        /*  49  "1" */ CWORD_CWORD_CWORD_CWORD,
3167        /*  50  "2" */ CWORD_CWORD_CWORD_CWORD,
3168        /*  51  "3" */ CWORD_CWORD_CWORD_CWORD,
3169        /*  52  "4" */ CWORD_CWORD_CWORD_CWORD,
3170        /*  53  "5" */ CWORD_CWORD_CWORD_CWORD,
3171        /*  54  "6" */ CWORD_CWORD_CWORD_CWORD,
3172        /*  55  "7" */ CWORD_CWORD_CWORD_CWORD,
3173        /*  56  "8" */ CWORD_CWORD_CWORD_CWORD,
3174        /*  57  "9" */ CWORD_CWORD_CWORD_CWORD,
3175        /*  58  ":" */ CWORD_CCTL_CCTL_CWORD,
3176        /*  59  ";" */ CSPCL_CWORD_CWORD_CWORD,
3177        /*  60  "<" */ CSPCL_CWORD_CWORD_CWORD,
3178        /*  61  "=" */ CWORD_CCTL_CCTL_CWORD,
3179        /*  62  ">" */ CSPCL_CWORD_CWORD_CWORD,
3180        /*  63  "?" */ CWORD_CCTL_CCTL_CWORD,
3181        /*  64  "@" */ CWORD_CWORD_CWORD_CWORD,
3182        /*  65  "A" */ CWORD_CWORD_CWORD_CWORD,
3183        /*  66  "B" */ CWORD_CWORD_CWORD_CWORD,
3184        /*  67  "C" */ CWORD_CWORD_CWORD_CWORD,
3185        /*  68  "D" */ CWORD_CWORD_CWORD_CWORD,
3186        /*  69  "E" */ CWORD_CWORD_CWORD_CWORD,
3187        /*  70  "F" */ CWORD_CWORD_CWORD_CWORD,
3188        /*  71  "G" */ CWORD_CWORD_CWORD_CWORD,
3189        /*  72  "H" */ CWORD_CWORD_CWORD_CWORD,
3190        /*  73  "I" */ CWORD_CWORD_CWORD_CWORD,
3191        /*  74  "J" */ CWORD_CWORD_CWORD_CWORD,
3192        /*  75  "K" */ CWORD_CWORD_CWORD_CWORD,
3193        /*  76  "L" */ CWORD_CWORD_CWORD_CWORD,
3194        /*  77  "M" */ CWORD_CWORD_CWORD_CWORD,
3195        /*  78  "N" */ CWORD_CWORD_CWORD_CWORD,
3196        /*  79  "O" */ CWORD_CWORD_CWORD_CWORD,
3197        /*  80  "P" */ CWORD_CWORD_CWORD_CWORD,
3198        /*  81  "Q" */ CWORD_CWORD_CWORD_CWORD,
3199        /*  82  "R" */ CWORD_CWORD_CWORD_CWORD,
3200        /*  83  "S" */ CWORD_CWORD_CWORD_CWORD,
3201        /*  84  "T" */ CWORD_CWORD_CWORD_CWORD,
3202        /*  85  "U" */ CWORD_CWORD_CWORD_CWORD,
3203        /*  86  "V" */ CWORD_CWORD_CWORD_CWORD,
3204        /*  87  "W" */ CWORD_CWORD_CWORD_CWORD,
3205        /*  88  "X" */ CWORD_CWORD_CWORD_CWORD,
3206        /*  89  "Y" */ CWORD_CWORD_CWORD_CWORD,
3207        /*  90  "Z" */ CWORD_CWORD_CWORD_CWORD,
3208        /*  91  "[" */ CWORD_CCTL_CCTL_CWORD,
3209        /*  92  "\" */ CBACK_CBACK_CCTL_CBACK,
3210        /*  93  "]" */ CWORD_CCTL_CCTL_CWORD,
3211        /*  94  "^" */ CWORD_CWORD_CWORD_CWORD,
3212        /*  95  "_" */ CWORD_CWORD_CWORD_CWORD,
3213        /*  96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3214        /*  97  "a" */ CWORD_CWORD_CWORD_CWORD,
3215        /*  98  "b" */ CWORD_CWORD_CWORD_CWORD,
3216        /*  99  "c" */ CWORD_CWORD_CWORD_CWORD,
3217        /* 100  "d" */ CWORD_CWORD_CWORD_CWORD,
3218        /* 101  "e" */ CWORD_CWORD_CWORD_CWORD,
3219        /* 102  "f" */ CWORD_CWORD_CWORD_CWORD,
3220        /* 103  "g" */ CWORD_CWORD_CWORD_CWORD,
3221        /* 104  "h" */ CWORD_CWORD_CWORD_CWORD,
3222        /* 105  "i" */ CWORD_CWORD_CWORD_CWORD,
3223        /* 106  "j" */ CWORD_CWORD_CWORD_CWORD,
3224        /* 107  "k" */ CWORD_CWORD_CWORD_CWORD,
3225        /* 108  "l" */ CWORD_CWORD_CWORD_CWORD,
3226        /* 109  "m" */ CWORD_CWORD_CWORD_CWORD,
3227        /* 110  "n" */ CWORD_CWORD_CWORD_CWORD,
3228        /* 111  "o" */ CWORD_CWORD_CWORD_CWORD,
3229        /* 112  "p" */ CWORD_CWORD_CWORD_CWORD,
3230        /* 113  "q" */ CWORD_CWORD_CWORD_CWORD,
3231        /* 114  "r" */ CWORD_CWORD_CWORD_CWORD,
3232        /* 115  "s" */ CWORD_CWORD_CWORD_CWORD,
3233        /* 116  "t" */ CWORD_CWORD_CWORD_CWORD,
3234        /* 117  "u" */ CWORD_CWORD_CWORD_CWORD,
3235        /* 118  "v" */ CWORD_CWORD_CWORD_CWORD,
3236        /* 119  "w" */ CWORD_CWORD_CWORD_CWORD,
3237        /* 120  "x" */ CWORD_CWORD_CWORD_CWORD,
3238        /* 121  "y" */ CWORD_CWORD_CWORD_CWORD,
3239        /* 122  "z" */ CWORD_CWORD_CWORD_CWORD,
3240        /* 123  "{" */ CWORD_CWORD_CWORD_CWORD,
3241        /* 124  "|" */ CSPCL_CWORD_CWORD_CWORD,
3242        /* 125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3243        /* 126  "~" */ CWORD_CCTL_CCTL_CWORD,
3244        /* 127  del */ CWORD_CWORD_CWORD_CWORD,
3245        /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3246        /* 129 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
3247        /* 130 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
3248        /* 131 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
3249        /* 132 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
3250        /* 133 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
3251        /* 134 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
3252        /* 135 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
3253        /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3254#if BASH_PROCESS_SUBST
3255        /* 137 CTLTOPROC    */ CCTL_CCTL_CCTL_CCTL,
3256        /* 138 CTLFROMPROC  */ CCTL_CCTL_CCTL_CCTL,
3257#else
3258        /* 137      */ CWORD_CWORD_CWORD_CWORD,
3259        /* 138      */ CWORD_CWORD_CWORD_CWORD,
3260#endif
3261        /* 139      */ CWORD_CWORD_CWORD_CWORD,
3262        /* 140      */ CWORD_CWORD_CWORD_CWORD,
3263        /* 141      */ CWORD_CWORD_CWORD_CWORD,
3264        /* 142      */ CWORD_CWORD_CWORD_CWORD,
3265        /* 143      */ CWORD_CWORD_CWORD_CWORD,
3266        /* 144      */ CWORD_CWORD_CWORD_CWORD,
3267        /* 145      */ CWORD_CWORD_CWORD_CWORD,
3268        /* 146      */ CWORD_CWORD_CWORD_CWORD,
3269        /* 147      */ CWORD_CWORD_CWORD_CWORD,
3270        /* 148      */ CWORD_CWORD_CWORD_CWORD,
3271        /* 149      */ CWORD_CWORD_CWORD_CWORD,
3272        /* 150      */ CWORD_CWORD_CWORD_CWORD,
3273        /* 151      */ CWORD_CWORD_CWORD_CWORD,
3274        /* 152      */ CWORD_CWORD_CWORD_CWORD,
3275        /* 153      */ CWORD_CWORD_CWORD_CWORD,
3276        /* 154      */ CWORD_CWORD_CWORD_CWORD,
3277        /* 155      */ CWORD_CWORD_CWORD_CWORD,
3278        /* 156      */ CWORD_CWORD_CWORD_CWORD,
3279        /* 157      */ CWORD_CWORD_CWORD_CWORD,
3280        /* 158      */ CWORD_CWORD_CWORD_CWORD,
3281        /* 159      */ CWORD_CWORD_CWORD_CWORD,
3282        /* 160      */ CWORD_CWORD_CWORD_CWORD,
3283        /* 161      */ CWORD_CWORD_CWORD_CWORD,
3284        /* 162      */ CWORD_CWORD_CWORD_CWORD,
3285        /* 163      */ CWORD_CWORD_CWORD_CWORD,
3286        /* 164      */ CWORD_CWORD_CWORD_CWORD,
3287        /* 165      */ CWORD_CWORD_CWORD_CWORD,
3288        /* 166      */ CWORD_CWORD_CWORD_CWORD,
3289        /* 167      */ CWORD_CWORD_CWORD_CWORD,
3290        /* 168      */ CWORD_CWORD_CWORD_CWORD,
3291        /* 169      */ CWORD_CWORD_CWORD_CWORD,
3292        /* 170      */ CWORD_CWORD_CWORD_CWORD,
3293        /* 171      */ CWORD_CWORD_CWORD_CWORD,
3294        /* 172      */ CWORD_CWORD_CWORD_CWORD,
3295        /* 173      */ CWORD_CWORD_CWORD_CWORD,
3296        /* 174      */ CWORD_CWORD_CWORD_CWORD,
3297        /* 175      */ CWORD_CWORD_CWORD_CWORD,
3298        /* 176      */ CWORD_CWORD_CWORD_CWORD,
3299        /* 177      */ CWORD_CWORD_CWORD_CWORD,
3300        /* 178      */ CWORD_CWORD_CWORD_CWORD,
3301        /* 179      */ CWORD_CWORD_CWORD_CWORD,
3302        /* 180      */ CWORD_CWORD_CWORD_CWORD,
3303        /* 181      */ CWORD_CWORD_CWORD_CWORD,
3304        /* 182      */ CWORD_CWORD_CWORD_CWORD,
3305        /* 183      */ CWORD_CWORD_CWORD_CWORD,
3306        /* 184      */ CWORD_CWORD_CWORD_CWORD,
3307        /* 185      */ CWORD_CWORD_CWORD_CWORD,
3308        /* 186      */ CWORD_CWORD_CWORD_CWORD,
3309        /* 187      */ CWORD_CWORD_CWORD_CWORD,
3310        /* 188      */ CWORD_CWORD_CWORD_CWORD,
3311        /* 189      */ CWORD_CWORD_CWORD_CWORD,
3312        /* 190      */ CWORD_CWORD_CWORD_CWORD,
3313        /* 191      */ CWORD_CWORD_CWORD_CWORD,
3314        /* 192      */ CWORD_CWORD_CWORD_CWORD,
3315        /* 193      */ CWORD_CWORD_CWORD_CWORD,
3316        /* 194      */ CWORD_CWORD_CWORD_CWORD,
3317        /* 195      */ CWORD_CWORD_CWORD_CWORD,
3318        /* 196      */ CWORD_CWORD_CWORD_CWORD,
3319        /* 197      */ CWORD_CWORD_CWORD_CWORD,
3320        /* 198      */ CWORD_CWORD_CWORD_CWORD,
3321        /* 199      */ CWORD_CWORD_CWORD_CWORD,
3322        /* 200      */ CWORD_CWORD_CWORD_CWORD,
3323        /* 201      */ CWORD_CWORD_CWORD_CWORD,
3324        /* 202      */ CWORD_CWORD_CWORD_CWORD,
3325        /* 203      */ CWORD_CWORD_CWORD_CWORD,
3326        /* 204      */ CWORD_CWORD_CWORD_CWORD,
3327        /* 205      */ CWORD_CWORD_CWORD_CWORD,
3328        /* 206      */ CWORD_CWORD_CWORD_CWORD,
3329        /* 207      */ CWORD_CWORD_CWORD_CWORD,
3330        /* 208      */ CWORD_CWORD_CWORD_CWORD,
3331        /* 209      */ CWORD_CWORD_CWORD_CWORD,
3332        /* 210      */ CWORD_CWORD_CWORD_CWORD,
3333        /* 211      */ CWORD_CWORD_CWORD_CWORD,
3334        /* 212      */ CWORD_CWORD_CWORD_CWORD,
3335        /* 213      */ CWORD_CWORD_CWORD_CWORD,
3336        /* 214      */ CWORD_CWORD_CWORD_CWORD,
3337        /* 215      */ CWORD_CWORD_CWORD_CWORD,
3338        /* 216      */ CWORD_CWORD_CWORD_CWORD,
3339        /* 217      */ CWORD_CWORD_CWORD_CWORD,
3340        /* 218      */ CWORD_CWORD_CWORD_CWORD,
3341        /* 219      */ CWORD_CWORD_CWORD_CWORD,
3342        /* 220      */ CWORD_CWORD_CWORD_CWORD,
3343        /* 221      */ CWORD_CWORD_CWORD_CWORD,
3344        /* 222      */ CWORD_CWORD_CWORD_CWORD,
3345        /* 223      */ CWORD_CWORD_CWORD_CWORD,
3346        /* 224      */ CWORD_CWORD_CWORD_CWORD,
3347        /* 225      */ CWORD_CWORD_CWORD_CWORD,
3348        /* 226      */ CWORD_CWORD_CWORD_CWORD,
3349        /* 227      */ CWORD_CWORD_CWORD_CWORD,
3350        /* 228      */ CWORD_CWORD_CWORD_CWORD,
3351        /* 229      */ CWORD_CWORD_CWORD_CWORD,
3352        /* 230      */ CWORD_CWORD_CWORD_CWORD,
3353        /* 231      */ CWORD_CWORD_CWORD_CWORD,
3354        /* 232      */ CWORD_CWORD_CWORD_CWORD,
3355        /* 233      */ CWORD_CWORD_CWORD_CWORD,
3356        /* 234      */ CWORD_CWORD_CWORD_CWORD,
3357        /* 235      */ CWORD_CWORD_CWORD_CWORD,
3358        /* 236      */ CWORD_CWORD_CWORD_CWORD,
3359        /* 237      */ CWORD_CWORD_CWORD_CWORD,
3360        /* 238      */ CWORD_CWORD_CWORD_CWORD,
3361        /* 239      */ CWORD_CWORD_CWORD_CWORD,
3362        /* 230      */ CWORD_CWORD_CWORD_CWORD,
3363        /* 241      */ CWORD_CWORD_CWORD_CWORD,
3364        /* 242      */ CWORD_CWORD_CWORD_CWORD,
3365        /* 243      */ CWORD_CWORD_CWORD_CWORD,
3366        /* 244      */ CWORD_CWORD_CWORD_CWORD,
3367        /* 245      */ CWORD_CWORD_CWORD_CWORD,
3368        /* 246      */ CWORD_CWORD_CWORD_CWORD,
3369        /* 247      */ CWORD_CWORD_CWORD_CWORD,
3370        /* 248      */ CWORD_CWORD_CWORD_CWORD,
3371        /* 249      */ CWORD_CWORD_CWORD_CWORD,
3372        /* 250      */ CWORD_CWORD_CWORD_CWORD,
3373        /* 251      */ CWORD_CWORD_CWORD_CWORD,
3374        /* 252      */ CWORD_CWORD_CWORD_CWORD,
3375        /* 253      */ CWORD_CWORD_CWORD_CWORD,
3376        /* 254      */ CWORD_CWORD_CWORD_CWORD,
3377        /* 255      */ CWORD_CWORD_CWORD_CWORD,
3378        /* PEOF */     CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3379};
3380
3381#if 1
3382# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3383#else /* debug version, caught one signed char bug */
3384# define SIT(c, syntax) \
3385        ({ \
3386                if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3387                        bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3388                if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3389                        bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3390                ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3391        })
3392#endif
3393
3394#endif  /* !USE_SIT_FUNCTION */
3395
3396
3397/* ============ Alias handling */
3398
3399#if ENABLE_ASH_ALIAS
3400
3401#define ALIASINUSE 1
3402#define ALIASDEAD  2
3403
3404struct alias {
3405        struct alias *next;
3406        char *name;
3407        char *val;
3408        int flag;
3409};
3410
3411
3412static struct alias **atab; // [ATABSIZE];
3413#define INIT_G_alias() do { \
3414        atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3415} while (0)
3416
3417
3418static struct alias **
3419__lookupalias(const char *name)
3420{
3421        unsigned int hashval;
3422        struct alias **app;
3423        const char *p;
3424        unsigned int ch;
3425
3426        p = name;
3427
3428        ch = (unsigned char)*p;
3429        hashval = ch << 4;
3430        while (ch) {
3431                hashval += ch;
3432                ch = (unsigned char)*++p;
3433        }
3434        app = &atab[hashval % ATABSIZE];
3435
3436        for (; *app; app = &(*app)->next) {
3437                if (strcmp(name, (*app)->name) == 0) {
3438                        break;
3439                }
3440        }
3441
3442        return app;
3443}
3444
3445static struct alias *
3446lookupalias(const char *name, int check)
3447{
3448        struct alias *ap = *__lookupalias(name);
3449
3450        if (check && ap && (ap->flag & ALIASINUSE))
3451                return NULL;
3452        return ap;
3453}
3454
3455static struct alias *
3456freealias(struct alias *ap)
3457{
3458        struct alias *next;
3459
3460        if (ap->flag & ALIASINUSE) {
3461                ap->flag |= ALIASDEAD;
3462                return ap;
3463        }
3464
3465        next = ap->next;
3466        free(ap->name);
3467        free(ap->val);
3468        free(ap);
3469        return next;
3470}
3471
3472static void
3473setalias(const char *name, const char *val)
3474{
3475        struct alias *ap, **app;
3476
3477        app = __lookupalias(name);
3478        ap = *app;
3479        INT_OFF;
3480        if (ap) {
3481                if (!(ap->flag & ALIASINUSE)) {
3482                        free(ap->val);
3483                }
3484                ap->val = ckstrdup(val);
3485                ap->flag &= ~ALIASDEAD;
3486        } else {
3487                /* not found */
3488                ap = ckzalloc(sizeof(struct alias));
3489                ap->name = ckstrdup(name);
3490                ap->val = ckstrdup(val);
3491                /*ap->flag = 0; - ckzalloc did it */
3492                /*ap->next = NULL;*/
3493                *app = ap;
3494        }
3495        INT_ON;
3496}
3497
3498static int
3499unalias(const char *name)
3500{
3501        struct alias **app;
3502
3503        app = __lookupalias(name);
3504
3505        if (*app) {
3506                INT_OFF;
3507                *app = freealias(*app);
3508                INT_ON;
3509                return 0;
3510        }
3511
3512        return 1;
3513}
3514
3515static void
3516rmaliases(void)
3517{
3518        struct alias *ap, **app;
3519        int i;
3520
3521        INT_OFF;
3522        for (i = 0; i < ATABSIZE; i++) {
3523                app = &atab[i];
3524                for (ap = *app; ap; ap = *app) {
3525                        *app = freealias(*app);
3526                        if (ap == *app) {
3527                                app = &ap->next;
3528                        }
3529                }
3530        }
3531        INT_ON;
3532}
3533
3534static void
3535printalias(const struct alias *ap)
3536{
3537        out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3538}
3539
3540/*
3541 * TODO - sort output
3542 */
3543static int FAST_FUNC
3544aliascmd(int argc UNUSED_PARAM, char **argv)
3545{
3546        char *n, *v;
3547        int ret = 0;
3548        struct alias *ap;
3549
3550        if (!argv[1]) {
3551                int i;
3552
3553                for (i = 0; i < ATABSIZE; i++) {
3554                        for (ap = atab[i]; ap; ap = ap->next) {
3555                                printalias(ap);
3556                        }
3557                }
3558                return 0;
3559        }
3560        while ((n = *++argv) != NULL) {
3561                v = strchr(n+1, '=');
3562                if (v == NULL) { /* n+1: funny ksh stuff */
3563                        ap = *__lookupalias(n);
3564                        if (ap == NULL) {
3565                                fprintf(stderr, "%s: %s not found\n", "alias", n);
3566                                ret = 1;
3567                        } else
3568                                printalias(ap);
3569                } else {
3570                        *v++ = '\0';
3571                        setalias(n, v);
3572                }
3573        }
3574
3575        return ret;
3576}
3577
3578static int FAST_FUNC
3579unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3580{
3581        int i;
3582
3583        while (nextopt("a") != '\0') {
3584                rmaliases();
3585                return 0;
3586        }
3587        for (i = 0; *argptr; argptr++) {
3588                if (unalias(*argptr)) {
3589                        fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3590                        i = 1;
3591                }
3592        }
3593
3594        return i;
3595}
3596
3597#endif /* ASH_ALIAS */
3598
3599
3600/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
3601#define FORK_FG    0
3602#define FORK_BG    1
3603#define FORK_NOJOB 2
3604
3605/* mode flags for showjob(s) */
3606#define SHOW_ONLY_PGID  0x01    /* show only pgid (jobs -p) */
3607#define SHOW_PIDS       0x02    /* show individual pids, not just one line per job */
3608#define SHOW_CHANGED    0x04    /* only jobs whose state has changed */
3609#define SHOW_STDERR     0x08    /* print to stderr (else stdout) */
3610
3611/*
3612 * A job structure contains information about a job.  A job is either a
3613 * single process or a set of processes contained in a pipeline.  In the
3614 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3615 * array of pids.
3616 */
3617struct procstat {
3618        pid_t   ps_pid;         /* process id */
3619        int     ps_status;      /* last process status from wait() */
3620        char    *ps_cmd;        /* text of command being run */
3621};
3622
3623struct job {
3624        struct procstat ps0;    /* status of process */
3625        struct procstat *ps;    /* status of processes when more than one */
3626#if JOBS
3627        int stopstatus;         /* status of a stopped job */
3628#endif
3629        unsigned nprocs;        /* number of processes */
3630
3631#define JOBRUNNING      0       /* at least one proc running */
3632#define JOBSTOPPED      1       /* all procs are stopped */
3633#define JOBDONE         2       /* all procs are completed */
3634        unsigned
3635                state: 8,
3636#if JOBS
3637                sigint: 1,      /* job was killed by SIGINT */
3638                jobctl: 1,      /* job running under job control */
3639#endif
3640                waited: 1,      /* true if this entry has been waited for */
3641                used: 1,        /* true if this entry is in used */
3642                changed: 1;     /* true if status has changed */
3643        struct job *prev_job;   /* previous job */
3644};
3645
3646static struct job *makejob(/*union node *,*/ int);
3647static int forkshell(struct job *, union node *, int);
3648static int waitforjob(struct job *);
3649
3650#if !JOBS
3651enum { doing_jobctl = 0 };
3652#define setjobctl(on) do {} while (0)
3653#else
3654static smallint doing_jobctl; //references:8
3655static void setjobctl(int);
3656#endif
3657
3658/*
3659 * Ignore a signal.
3660 */
3661static void
3662ignoresig(int signo)
3663{
3664        /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3665        if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3666                /* No, need to do it */
3667                signal(signo, SIG_IGN);
3668        }
3669        sigmode[signo - 1] = S_HARD_IGN;
3670}
3671
3672/*
3673 * Only one usage site - in setsignal()
3674 */
3675static void
3676signal_handler(int signo)
3677{
3678        if (signo == SIGCHLD) {
3679                got_sigchld = 1;
3680                if (!trap[SIGCHLD])
3681                        return;
3682        }
3683
3684        gotsig[signo - 1] = 1;
3685        pending_sig = signo;
3686
3687        if (signo == SIGINT && !trap[SIGINT]) {
3688                if (!suppress_int) {
3689                        pending_sig = 0;
3690                        raise_interrupt(); /* does not return */
3691                }
3692                pending_int = 1;
3693        }
3694}
3695
3696/*
3697 * Set the signal handler for the specified signal.  The routine figures
3698 * out what it should be set to.
3699 */
3700static void
3701setsignal(int signo)
3702{
3703        char *t;
3704        char cur_act, new_act;
3705        struct sigaction act;
3706
3707        t = trap[signo];
3708        new_act = S_DFL;
3709        if (t != NULL) { /* trap for this sig is set */
3710                new_act = S_CATCH;
3711                if (t[0] == '\0') /* trap is "": ignore this sig */
3712                        new_act = S_IGN;
3713        }
3714
3715        if (rootshell && new_act == S_DFL) {
3716                switch (signo) {
3717                case SIGINT:
3718                        if (iflag || minusc || sflag == 0)
3719                                new_act = S_CATCH;
3720                        break;
3721                case SIGQUIT:
3722#if DEBUG
3723                        if (debug)
3724                                break;
3725#endif
3726                        /* man bash:
3727                         * "In all cases, bash ignores SIGQUIT. Non-builtin
3728                         * commands run by bash have signal handlers
3729                         * set to the values inherited by the shell
3730                         * from its parent". */
3731                        new_act = S_IGN;
3732                        break;
3733                case SIGTERM:
3734                        if (iflag)
3735                                new_act = S_IGN;
3736                        break;
3737#if JOBS
3738                case SIGTSTP:
3739                case SIGTTOU:
3740                        if (mflag)
3741                                new_act = S_IGN;
3742                        break;
3743#endif
3744                }
3745        }
3746        /* if !rootshell, we reset SIGQUIT to DFL,
3747         * whereas we have to restore it to what shell got on entry.
3748         * This is handled by the fact that if signal was IGNored on entry,
3749         * then cur_act is S_HARD_IGN and we never change its sigaction
3750         * (see code below).
3751         */
3752
3753        if (signo == SIGCHLD)
3754                new_act = S_CATCH;
3755
3756        t = &sigmode[signo - 1];
3757        cur_act = *t;
3758        if (cur_act == 0) {
3759                /* current setting is not yet known */
3760                if (sigaction(signo, NULL, &act)) {
3761                        /* pretend it worked; maybe we should give a warning,
3762                         * but other shells don't. We don't alter sigmode,
3763                         * so we retry every time.
3764                         * btw, in Linux it never fails. --vda */
3765                        return;
3766                }
3767                if (act.sa_handler == SIG_IGN) {
3768                        cur_act = S_HARD_IGN;
3769                        if (mflag
3770                         && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3771                        ) {
3772                                cur_act = S_IGN;   /* don't hard ignore these */
3773                        }
3774                }
3775                if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3776                        /* installing SIG_DFL over SIG_DFL is a no-op */
3777                        /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3778                        *t = S_DFL;
3779                        return;
3780                }
3781        }
3782        if (cur_act == S_HARD_IGN || cur_act == new_act)
3783                return;
3784
3785        *t = new_act;
3786
3787        act.sa_handler = SIG_DFL;
3788        switch (new_act) {
3789        case S_CATCH:
3790                act.sa_handler = signal_handler;
3791                break;
3792        case S_IGN:
3793                act.sa_handler = SIG_IGN;
3794                break;
3795        }
3796        /* flags and mask matter only if !DFL and !IGN, but we do it
3797         * for all cases for more deterministic behavior:
3798         */
3799        act.sa_flags = 0; //TODO: why not SA_RESTART?
3800        sigfillset(&act.sa_mask);
3801
3802        sigaction_set(signo, &act);
3803}
3804
3805/* mode flags for set_curjob */
3806#define CUR_DELETE 2
3807#define CUR_RUNNING 1
3808#define CUR_STOPPED 0
3809
3810#if JOBS
3811/* pgrp of shell on invocation */
3812static int initialpgrp; //references:2
3813static int ttyfd = -1; //5
3814#endif
3815/* array of jobs */
3816static struct job *jobtab; //5
3817/* size of array */
3818static unsigned njobs; //4
3819/* current job */
3820static struct job *curjob; //lots
3821
3822#if 0
3823/* Bash has a feature: it restores termios after a successful wait for
3824 * a foreground job which had at least one stopped or sigkilled member.
3825 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3826 * properly restoring tty state. Should we do this too?
3827 * A reproducer: ^Z an interactive python:
3828 *
3829 * # python
3830 * Python 2.7.12 (...)
3831 * >>> ^Z
3832 *      { python leaves tty in -icanon -echo state. We do survive that... }
3833 *  [1]+  Stopped                    python
3834 *      { ...however, next program (python #2) does not survive it well: }
3835 * # python
3836 * Python 2.7.12 (...)
3837 * >>> Traceback (most recent call last):
3838 *      { above, I typed "qwerty<CR>", but -echo state is still in effect }
3839 *   File "<stdin>", line 1, in <module>
3840 * NameError: name 'qwerty' is not defined
3841 *
3842 * The implementation below is modeled on bash code and seems to work.
3843 * However, I'm not sure we should do this. For one: what if I'd fg
3844 * the stopped python instead? It'll be confused by "restored" tty state.
3845 */
3846static struct termios shell_tty_info;
3847static void
3848get_tty_state(void)
3849{
3850        if (rootshell && ttyfd >= 0)
3851                tcgetattr(ttyfd, &shell_tty_info);
3852}
3853static void
3854set_tty_state(void)
3855{
3856        /* if (rootshell) - caller ensures this */
3857        if (ttyfd >= 0)
3858                tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3859}
3860static int
3861job_signal_status(struct job *jp)
3862{
3863        int status;
3864        unsigned i;
3865        struct procstat *ps = jp->ps;
3866        for (i = 0; i < jp->nprocs; i++) {
3867                status = ps[i].ps_status;
3868                if (WIFSIGNALED(status) || WIFSTOPPED(status))
3869                        return status;
3870        }
3871        return 0;
3872}
3873static void
3874restore_tty_if_stopped_or_signaled(struct job *jp)
3875{
3876//TODO: check what happens if we come from waitforjob() in expbackq()
3877        if (rootshell) {
3878                int s = job_signal_status(jp);
3879                if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3880                        set_tty_state();
3881        }
3882}
3883#else
3884# define get_tty_state() ((void)0)
3885# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3886#endif
3887
3888static void
3889set_curjob(struct job *jp, unsigned mode)
3890{
3891        struct job *jp1;
3892        struct job **jpp, **curp;
3893
3894        /* first remove from list */
3895        jpp = curp = &curjob;
3896        while (1) {
3897                jp1 = *jpp;
3898                if (jp1 == jp)
3899                        break;
3900                jpp = &jp1->prev_job;
3901        }
3902        *jpp = jp1->prev_job;
3903
3904        /* Then re-insert in correct position */
3905        jpp = curp;
3906        switch (mode) {
3907        default:
3908#if DEBUG
3909                abort();
3910#endif
3911        case CUR_DELETE:
3912                /* job being deleted */
3913                break;
3914        case CUR_RUNNING:
3915                /* newly created job or backgrounded job,
3916                 * put after all stopped jobs.
3917                 */
3918                while (1) {
3919                        jp1 = *jpp;
3920#if JOBS
3921                        if (!jp1 || jp1->state != JOBSTOPPED)
3922#endif
3923                                break;
3924                        jpp = &jp1->prev_job;
3925                }
3926                /* FALLTHROUGH */
3927#if JOBS
3928        case CUR_STOPPED:
3929#endif
3930                /* newly stopped job - becomes curjob */
3931                jp->prev_job = *jpp;
3932                *jpp = jp;
3933                break;
3934        }
3935}
3936
3937#if JOBS || DEBUG
3938static int
3939jobno(const struct job *jp)
3940{
3941        return jp - jobtab + 1;
3942}
3943#endif
3944
3945/*
3946 * Convert a job name to a job structure.
3947 */
3948#if !JOBS
3949#define getjob(name, getctl) getjob(name)
3950#endif
3951static struct job *
3952getjob(const char *name, int getctl)
3953{
3954        struct job *jp;
3955        struct job *found;
3956        const char *err_msg = "%s: no such job";
3957        unsigned num;
3958        int c;
3959        const char *p;
3960        char *(*match)(const char *, const char *);
3961
3962        jp = curjob;
3963        p = name;
3964        if (!p)
3965                goto currentjob;
3966
3967        if (*p != '%')
3968                goto err;
3969
3970        c = *++p;
3971        if (!c)
3972                goto currentjob;
3973
3974        if (!p[1]) {
3975                if (c == '+' || c == '%') {
3976 currentjob:
3977                        err_msg = "No current job";
3978                        goto check;
3979                }
3980                if (c == '-') {
3981                        if (jp)
3982                                jp = jp->prev_job;
3983                        err_msg = "No previous job";
3984 check:
3985                        if (!jp)
3986                                goto err;
3987                        goto gotit;
3988                }
3989        }
3990
3991        if (is_number(p)) {
3992                num = atoi(p);
3993                if (num > 0 && num <= njobs) {
3994                        jp = jobtab + num - 1;
3995                        if (jp->used)
3996                                goto gotit;
3997                        goto err;
3998                }
3999        }
4000
4001        match = prefix;
4002        if (*p == '?') {
4003                match = strstr;
4004                p++;
4005        }
4006
4007        found = NULL;
4008        while (jp) {
4009                if (match(jp->ps[0].ps_cmd, p)) {
4010                        if (found)
4011                                goto err;
4012                        found = jp;
4013                        err_msg = "%s: ambiguous";
4014                }
4015                jp = jp->prev_job;
4016        }
4017        if (!found)
4018                goto err;
4019        jp = found;
4020
4021 gotit:
4022#if JOBS
4023        err_msg = "job %s not created under job control";
4024        if (getctl && jp->jobctl == 0)
4025                goto err;
4026#endif
4027        return jp;
4028 err:
4029        ash_msg_and_raise_error(err_msg, name);
4030}
4031
4032/*
4033 * Mark a job structure as unused.
4034 */
4035static void
4036freejob(struct job *jp)
4037{
4038        struct procstat *ps;
4039        int i;
4040
4041        INT_OFF;
4042        for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
4043                if (ps->ps_cmd != nullstr)
4044                        free(ps->ps_cmd);
4045        }
4046        if (jp->ps != &jp->ps0)
4047                free(jp->ps);
4048        jp->used = 0;
4049        set_curjob(jp, CUR_DELETE);
4050        INT_ON;
4051}
4052
4053#if JOBS
4054static void
4055xtcsetpgrp(int fd, pid_t pgrp)
4056{
4057        if (tcsetpgrp(fd, pgrp))
4058                ash_msg_and_raise_perror("can't set tty process group");
4059}
4060
4061/*
4062 * Turn job control on and off.
4063 *
4064 * Note:  This code assumes that the third arg to ioctl is a character
4065 * pointer, which is true on Berkeley systems but not System V.  Since
4066 * System V doesn't have job control yet, this isn't a problem now.
4067 *
4068 * Called with interrupts off.
4069 */
4070static void
4071setjobctl(int on)
4072{
4073        int fd;
4074        int pgrp;
4075
4076        if (on == doing_jobctl || rootshell == 0)
4077                return;
4078        if (on) {
4079                int ofd;
4080                ofd = fd = open(_PATH_TTY, O_RDWR);
4081                if (fd < 0) {
4082        /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
4083         * That sometimes helps to acquire controlling tty.
4084         * Obviously, a workaround for bugs when someone
4085         * failed to provide a controlling tty to bash! :) */
4086                        fd = 2;
4087                        while (!isatty(fd))
4088                                if (--fd < 0)
4089                                        goto out;
4090                }
4091                /* fd is a tty at this point */
4092                fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
4093                if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
4094                        close(ofd);
4095                if (fd < 0)
4096                        goto out; /* F_DUPFD failed */
4097                if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
4098                        close_on_exec_on(fd);
4099                while (1) { /* while we are in the background */
4100                        pgrp = tcgetpgrp(fd);
4101                        if (pgrp < 0) {
4102 out:
4103                                ash_msg("can't access tty; job control turned off");
4104                                mflag = on = 0;
4105                                goto close;
4106                        }
4107                        if (pgrp == getpgrp())
4108                                break;
4109                        killpg(0, SIGTTIN);
4110                }
4111                initialpgrp = pgrp;
4112
4113                setsignal(SIGTSTP);
4114                setsignal(SIGTTOU);
4115                setsignal(SIGTTIN);
4116                pgrp = rootpid;
4117                setpgid(0, pgrp);
4118                xtcsetpgrp(fd, pgrp);
4119        } else {
4120                /* turning job control off */
4121                fd = ttyfd;
4122                pgrp = initialpgrp;
4123                /* was xtcsetpgrp, but this can make exiting ash
4124                 * loop forever if pty is already deleted */
4125                tcsetpgrp(fd, pgrp);
4126                setpgid(0, pgrp);
4127                setsignal(SIGTSTP);
4128                setsignal(SIGTTOU);
4129                setsignal(SIGTTIN);
4130 close:
4131                if (fd >= 0)
4132                        close(fd);
4133                fd = -1;
4134        }
4135        ttyfd = fd;
4136        doing_jobctl = on;
4137}
4138
4139static int FAST_FUNC
4140killcmd(int argc, char **argv)
4141{
4142        if (argv[1] && strcmp(argv[1], "-l") != 0) {
4143                int i = 1;
4144                do {
4145                        if (argv[i][0] == '%') {
4146                                /*
4147                                 * "kill %N" - job kill
4148                                 * Converting to pgrp / pid kill
4149                                 */
4150                                struct job *jp;
4151                                char *dst;
4152                                int j, n;
4153
4154                                jp = getjob(argv[i], 0);
4155                                /*
4156                                 * In jobs started under job control, we signal
4157                                 * entire process group by kill -PGRP_ID.
4158                                 * This happens, f.e., in interactive shell.
4159                                 *
4160                                 * Otherwise, we signal each child via
4161                                 * kill PID1 PID2 PID3.
4162                                 * Testcases:
4163                                 * sh -c 'sleep 1|sleep 1 & kill %1'
4164                                 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4165                                 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4166                                 */
4167                                n = jp->nprocs; /* can't be 0 (I hope) */
4168                                if (jp->jobctl)
4169                                        n = 1;
4170                                dst = alloca(n * sizeof(int)*4);
4171                                argv[i] = dst;
4172                                for (j = 0; j < n; j++) {
4173                                        struct procstat *ps = &jp->ps[j];
4174                                        /* Skip non-running and not-stopped members
4175                                         * (i.e. dead members) of the job
4176                                         */
4177                                        if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4178                                                continue;
4179                                        /*
4180                                         * kill_main has matching code to expect
4181                                         * leading space. Needed to not confuse
4182                                         * negative pids with "kill -SIGNAL_NO" syntax
4183                                         */
4184                                        dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4185                                }
4186                                *dst = '\0';
4187                        }
4188                } while (argv[++i]);
4189        }
4190        return kill_main(argc, argv);
4191}
4192
4193static void
4194showpipe(struct job *jp /*, FILE *out*/)
4195{
4196        struct procstat *ps;
4197        struct procstat *psend;
4198
4199        psend = jp->ps + jp->nprocs;
4200        for (ps = jp->ps + 1; ps < psend; ps++)
4201                printf(" | %s", ps->ps_cmd);
4202        newline_and_flush(stdout);
4203        flush_stdout_stderr();
4204}
4205
4206
4207static int
4208restartjob(struct job *jp, int mode)
4209{
4210        struct procstat *ps;
4211        int i;
4212        int status;
4213        pid_t pgid;
4214
4215        INT_OFF;
4216        if (jp->state == JOBDONE)
4217                goto out;
4218        jp->state = JOBRUNNING;
4219        pgid = jp->ps[0].ps_pid;
4220        if (mode == FORK_FG) {
4221                get_tty_state();
4222                xtcsetpgrp(ttyfd, pgid);
4223        }
4224        killpg(pgid, SIGCONT);
4225        ps = jp->ps;
4226        i = jp->nprocs;
4227        do {
4228                if (WIFSTOPPED(ps->ps_status)) {
4229                        ps->ps_status = -1;
4230                }
4231                ps++;
4232        } while (--i);
4233 out:
4234        status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4235        INT_ON;
4236        return status;
4237}
4238
4239static int FAST_FUNC
4240fg_bgcmd(int argc UNUSED_PARAM, char **argv)
4241{
4242        struct job *jp;
4243        int mode;
4244        int retval;
4245
4246        mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4247        nextopt(nullstr);
4248        argv = argptr;
4249        do {
4250                jp = getjob(*argv, 1);
4251                if (mode == FORK_BG) {
4252                        set_curjob(jp, CUR_RUNNING);
4253                        printf("[%d] ", jobno(jp));
4254                }
4255                out1str(jp->ps[0].ps_cmd);
4256                showpipe(jp /*, stdout*/);
4257                retval = restartjob(jp, mode);
4258        } while (*argv && *++argv);
4259        return retval;
4260}
4261#endif
4262
4263static int
4264sprint_status48(char *os, int status, int sigonly)
4265{
4266        char *s = os;
4267        int st;
4268
4269        if (!WIFEXITED(status)) {
4270#if JOBS
4271                if (WIFSTOPPED(status))
4272                        st = WSTOPSIG(status);
4273                else
4274#endif
4275                        st = WTERMSIG(status);
4276                if (sigonly) {
4277                        if (st == SIGINT || st == SIGPIPE)
4278                                goto out;
4279#if JOBS
4280                        if (WIFSTOPPED(status))
4281                                goto out;
4282#endif
4283                }
4284                st &= 0x7f;
4285                s = stpncpy(s, strsignal(st), 32);
4286                if (WCOREDUMP(status)) {
4287                        s = stpcpy(s, " (core dumped)");
4288                }
4289        } else if (!sigonly) {
4290                st = WEXITSTATUS(status);
4291                s += fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
4292        }
4293 out:
4294        return s - os;
4295}
4296
4297#define DOWAIT_NONBLOCK 0
4298#define DOWAIT_BLOCK    1
4299#define DOWAIT_BLOCK_OR_SIG 2
4300#if BASH_WAIT_N
4301# define DOWAIT_JOBSTATUS 0x10   /* OR this to get job's exitstatus instead of pid */
4302#endif
4303
4304static int
4305waitproc(int block, int *status)
4306{
4307        sigset_t oldmask;
4308        int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
4309        int err;
4310
4311#if JOBS
4312        if (doing_jobctl)
4313                flags |= WUNTRACED;
4314#endif
4315
4316        do {
4317                got_sigchld = 0;
4318                do
4319                        err = waitpid(-1, status, flags);
4320                while (err < 0 && errno == EINTR);
4321
4322                if (err || (err = -!block))
4323                        break;
4324
4325                sigfillset(&oldmask);
4326                sigprocmask2(SIG_SETMASK, &oldmask); /* mask is updated */
4327                while (!got_sigchld && !pending_sig)
4328                        sigsuspend(&oldmask);
4329                sigprocmask(SIG_SETMASK, &oldmask, NULL);
4330                //simpler, but unsafe: a signal can set pending_sig after check, but before pause():
4331                //while (!got_sigchld && !pending_sig)
4332                //      pause();
4333
4334        } while (got_sigchld);
4335
4336        return err;
4337}
4338
4339static int
4340waitone(int block, struct job *job)
4341{
4342        int pid;
4343        int status;
4344        struct job *jp;
4345        struct job *thisjob = NULL;
4346#if BASH_WAIT_N
4347        bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
4348        block = (block & ~DOWAIT_JOBSTATUS);
4349#endif
4350
4351        TRACE(("dowait(0x%x) called\n", block));
4352
4353        /* It's wrong to call waitpid() outside of INT_OFF region:
4354         * signal can arrive just after syscall return and handler can
4355         * longjmp away, losing stop/exit notification processing.
4356         * Thus, for "jobs" builtin, and for waiting for a fg job,
4357         * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4358         *
4359         * However, for "wait" builtin it is wrong to simply call waitpid()
4360         * in INT_OFF region: "wait" needs to wait for any running job
4361         * to change state, but should exit on any trap too.
4362         * In INT_OFF region, a signal just before syscall entry can set
4363         * pending_sig variables, but we can't check them, and we would
4364         * either enter a sleeping waitpid() (BUG), or need to busy-loop.
4365         *
4366         * Because of this, we run inside INT_OFF, but use a special routine
4367         * which combines waitpid() and sigsuspend().
4368         * This is the reason why we need to have a handler for SIGCHLD:
4369         * SIG_DFL handler does not wake sigsuspend().
4370         */
4371        INT_OFF;
4372        pid = waitproc(block, &status);
4373        TRACE(("wait returns pid %d, status=%d\n", pid, status));
4374        if (pid <= 0)
4375                goto out;
4376
4377        for (jp = curjob; jp; jp = jp->prev_job) {
4378                int jobstate;
4379                struct procstat *ps;
4380                struct procstat *psend;
4381                if (jp->state == JOBDONE)
4382                        continue;
4383                jobstate = JOBDONE;
4384                ps = jp->ps;
4385                psend = ps + jp->nprocs;
4386                do {
4387                        if (ps->ps_pid == pid) {
4388                                TRACE(("Job %d: changing status of proc %d "
4389                                        "from 0x%x to 0x%x\n",
4390                                        jobno(jp), pid, ps->ps_status, status));
4391                                ps->ps_status = status;
4392                                thisjob = jp;
4393                        }
4394                        if (ps->ps_status == -1)
4395                                jobstate = JOBRUNNING;
4396#if JOBS
4397                        if (jobstate == JOBRUNNING)
4398                                continue;
4399                        if (WIFSTOPPED(ps->ps_status)) {
4400                                jp->stopstatus = ps->ps_status;
4401                                jobstate = JOBSTOPPED;
4402                        }
4403#endif
4404                } while (++ps < psend);
4405                if (!thisjob)
4406                        continue;
4407
4408                /* Found the job where one of its processes changed its state.
4409                 * Is there at least one live and running process in this job? */
4410                if (jobstate != JOBRUNNING) {
4411                        /* No. All live processes in the job are stopped
4412                         * (JOBSTOPPED) or there are no live processes (JOBDONE)
4413                         */
4414                        thisjob->changed = 1;
4415                        if (thisjob->state != jobstate) {
4416                                TRACE(("Job %d: changing state from %d to %d\n",
4417                                        jobno(thisjob), thisjob->state, jobstate));
4418                                thisjob->state = jobstate;
4419#if JOBS
4420                                if (jobstate == JOBSTOPPED)
4421                                        set_curjob(thisjob, CUR_STOPPED);
4422#endif
4423                        }
4424                }
4425                goto out;
4426        }
4427        /* The process wasn't found in job list */
4428 out:
4429        INT_ON;
4430
4431#if BASH_WAIT_N
4432        if (want_jobexitstatus) {
4433                pid = -1;
4434                if (thisjob && thisjob->state == JOBDONE)
4435                        pid = thisjob->ps[thisjob->nprocs - 1].ps_status;
4436        }
4437#endif
4438        if (thisjob && thisjob == job) {
4439                char s[48 + 1];
4440                int len;
4441
4442                len = sprint_status48(s, status, 1);
4443                if (len) {
4444                        s[len] = '\n';
4445                        s[len + 1] = '\0';
4446                        out2str(s);
4447                }
4448        }
4449        return pid;
4450}
4451
4452static int
4453dowait(int block, struct job *jp)
4454{
4455        smallint gotchld = *(volatile smallint *)&got_sigchld;
4456        int rpid;
4457        int pid;
4458
4459        if (jp && jp->state != JOBRUNNING)
4460                block = DOWAIT_NONBLOCK;
4461
4462        if (block == DOWAIT_NONBLOCK && !gotchld)
4463                return 1;
4464
4465        rpid = 1;
4466
4467        do {
4468                pid = waitone(block, jp);
4469                rpid &= !!pid;
4470
4471                if (!pid || (jp && jp->state != JOBRUNNING))
4472                        block = DOWAIT_NONBLOCK;
4473        } while (pid >= 0);
4474
4475        return rpid;
4476}
4477
4478#if JOBS
4479static void
4480showjob(struct job *jp, int mode)
4481{
4482        struct procstat *ps;
4483        struct procstat *psend;
4484        int col;
4485        int indent_col;
4486        char s[16 + 16 + 48];
4487        FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4488
4489        ps = jp->ps;
4490
4491        if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4492                /* just output process (group) id of pipeline */
4493                fprintf(out, "%d\n", ps->ps_pid);
4494                return;
4495        }
4496
4497        col = fmtstr(s, 16, "[%d]   ", jobno(jp));
4498        indent_col = col;
4499
4500        if (jp == curjob)
4501                s[col - 3] = '+';
4502        else if (curjob && jp == curjob->prev_job)
4503                s[col - 3] = '-';
4504
4505        if (mode & SHOW_PIDS)
4506                col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4507
4508        psend = ps + jp->nprocs;
4509
4510        if (jp->state == JOBRUNNING) {
4511                strcpy(s + col, "Running");
4512                col += sizeof("Running") - 1;
4513        } else {
4514                int status = psend[-1].ps_status;
4515                if (jp->state == JOBSTOPPED)
4516                        status = jp->stopstatus;
4517                col += sprint_status48(s + col, status, 0);
4518        }
4519        /* By now, "[JOBID]*  [maybe PID] STATUS" is printed */
4520
4521        /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4522         * or prints several "PID             | <cmdN>" lines,
4523         * depending on SHOW_PIDS bit.
4524         * We do not print status of individual processes
4525         * between PID and <cmdN>. bash does it, but not very well:
4526         * first line shows overall job status, not process status,
4527         * making it impossible to know 1st process status.
4528         */
4529        goto start;
4530        do {
4531                /* for each process */
4532                s[0] = '\0';
4533                col = 33;
4534                if (mode & SHOW_PIDS)
4535                        col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4536 start:
4537                fprintf(out, "%s%*c%s%s",
4538                                s,
4539                                33 - col >= 0 ? 33 - col : 0, ' ',
4540                                ps == jp->ps ? "" : "| ",
4541                                ps->ps_cmd
4542                );
4543        } while (++ps != psend);
4544        newline_and_flush(out);
4545
4546        jp->changed = 0;
4547
4548        if (jp->state == JOBDONE) {
4549                TRACE(("showjob: freeing job %d\n", jobno(jp)));
4550                freejob(jp);
4551        }
4552}
4553
4554/*
4555 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
4556 * statuses have changed since the last call to showjobs.
4557 */
4558static void
4559showjobs(int mode)
4560{
4561        struct job *jp;
4562
4563        TRACE(("showjobs(0x%x) called\n", mode));
4564
4565        /* Handle all finished jobs */
4566        dowait(DOWAIT_NONBLOCK, NULL);
4567
4568        for (jp = curjob; jp; jp = jp->prev_job) {
4569                if (!(mode & SHOW_CHANGED) || jp->changed) {
4570                        showjob(jp, mode);
4571                }
4572        }
4573}
4574
4575static int FAST_FUNC
4576jobscmd(int argc UNUSED_PARAM, char **argv)
4577{
4578        int mode, m;
4579
4580        mode = 0;
4581        while ((m = nextopt("lp")) != '\0') {
4582                if (m == 'l')
4583                        mode |= SHOW_PIDS;
4584                else
4585                        mode |= SHOW_ONLY_PGID;
4586        }
4587
4588        argv = argptr;
4589        if (*argv) {
4590                do
4591                        showjob(getjob(*argv, 0), mode);
4592                while (*++argv);
4593        } else {
4594                showjobs(mode);
4595        }
4596
4597        return 0;
4598}
4599#endif /* JOBS */
4600
4601/* Called only on finished or stopped jobs (no members are running) */
4602static int
4603getstatus(struct job *job)
4604{
4605        int status;
4606        int retval;
4607        struct procstat *ps;
4608
4609        /* Fetch last member's status */
4610        ps = job->ps + job->nprocs - 1;
4611        status = ps->ps_status;
4612        if (pipefail) {
4613                /* "set -o pipefail" mode: use last _nonzero_ status */
4614                while (status == 0 && --ps >= job->ps)
4615                        status = ps->ps_status;
4616        }
4617
4618        retval = WEXITSTATUS(status);
4619        if (!WIFEXITED(status)) {
4620#if JOBS
4621                retval = WSTOPSIG(status);
4622                if (!WIFSTOPPED(status))
4623#endif
4624                {
4625                        /* XXX: limits number of signals */
4626                        retval = WTERMSIG(status);
4627#if JOBS
4628                        if (retval == SIGINT)
4629                                job->sigint = 1;
4630#endif
4631                }
4632                retval |= 128;
4633        }
4634        TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4635                jobno(job), job->nprocs, status, retval));
4636        return retval;
4637}
4638
4639static int FAST_FUNC
4640waitcmd(int argc UNUSED_PARAM, char **argv)
4641{
4642        struct job *job;
4643        int retval;
4644        struct job *jp;
4645#if BASH_WAIT_N
4646        int status;
4647        char one = nextopt("n");
4648#else
4649        nextopt(nullstr);
4650#endif
4651        retval = 0;
4652
4653        argv = argptr;
4654        if (!argv[0]) {
4655                /* wait for all jobs / one job if -n */
4656                for (;;) {
4657                        jp = curjob;
4658#if BASH_WAIT_N
4659                        if (one && !jp)
4660                                /* exitcode of "wait -n" with nothing to wait for is 127, not 0 */
4661                                retval = 127;
4662#endif
4663                        while (1) {
4664                                if (!jp) /* no running procs */
4665                                        goto ret;
4666                                if (jp->state == JOBRUNNING)
4667                                        break;
4668                                jp->waited = 1;
4669                                jp = jp->prev_job;
4670                        }
4671        /* man bash:
4672         * "When bash is waiting for an asynchronous command via
4673         * the wait builtin, the reception of a signal for which a trap
4674         * has been set will cause the wait builtin to return immediately
4675         * with an exit status greater than 128, immediately after which
4676         * the trap is executed."
4677         */
4678#if BASH_WAIT_N
4679                        status = dowait(DOWAIT_BLOCK_OR_SIG | DOWAIT_JOBSTATUS, NULL);
4680#else
4681                        dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4682#endif
4683                        /* if child sends us a signal *and immediately exits*,
4684                         * dowait() returns pid > 0. Check this case,
4685                         * not "if (dowait() < 0)"!
4686                         */
4687                        if (pending_sig)
4688                                goto sigout;
4689#if BASH_WAIT_N
4690                        if (one) {
4691                                /* wait -n waits for one _job_, not one _process_.
4692                                 *  date; sleep 3 & sleep 2 | sleep 1 & wait -n; date
4693                                 * should wait for 2 seconds. Not 1 or 3.
4694                                 */
4695                                if (status != -1 && !WIFSTOPPED(status)) {
4696                                        retval = WEXITSTATUS(status);
4697                                        if (WIFSIGNALED(status))
4698                                                retval = 128 | WTERMSIG(status);
4699                                        goto ret;
4700                                }
4701                        }
4702#endif
4703                }
4704        }
4705
4706        retval = 127;
4707        do {
4708                if (**argv != '%') {
4709                        pid_t pid = number(*argv);
4710                        job = curjob;
4711                        while (1) {
4712                                if (!job)
4713                                        goto repeat;
4714                                if (job->ps[job->nprocs - 1].ps_pid == pid)
4715                                        break;
4716                                job = job->prev_job;
4717                        }
4718                } else {
4719                        job = getjob(*argv, 0);
4720                }
4721                /* loop until process terminated or stopped */
4722                dowait(DOWAIT_BLOCK_OR_SIG, job);
4723                if (pending_sig)
4724                        goto sigout;
4725                job->waited = 1;
4726                retval = getstatus(job);
4727 repeat: ;
4728        } while (*++argv);
4729
4730 ret:
4731        return retval;
4732 sigout:
4733        retval = 128 | pending_sig;
4734        return retval;
4735}
4736
4737static struct job *
4738growjobtab(void)
4739{
4740        size_t len;
4741        ptrdiff_t offset;
4742        struct job *jp, *jq;
4743
4744        len = njobs * sizeof(*jp);
4745        jq = jobtab;
4746        jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4747
4748        offset = (char *)jp - (char *)jq;
4749        if (offset) {
4750                /* Relocate pointers */
4751                size_t l = len;
4752
4753                jq = (struct job *)((char *)jq + l);
4754                while (l) {
4755                        l -= sizeof(*jp);
4756                        jq--;
4757#define joff(p) ((struct job *)((char *)(p) + l))
4758#define jmove(p) (p) = (void *)((char *)(p) + offset)
4759                        if (joff(jp)->ps == &jq->ps0)
4760                                jmove(joff(jp)->ps);
4761                        if (joff(jp)->prev_job)
4762                                jmove(joff(jp)->prev_job);
4763                }
4764                if (curjob)
4765                        jmove(curjob);
4766#undef joff
4767#undef jmove
4768        }
4769
4770        njobs += 4;
4771        jobtab = jp;
4772        jp = (struct job *)((char *)jp + len);
4773        jq = jp + 3;
4774        do {
4775                jq->used = 0;
4776        } while (--jq >= jp);
4777        return jp;
4778}
4779
4780/*
4781 * Return a new job structure.
4782 * Called with interrupts off.
4783 */
4784static struct job *
4785makejob(/*union node *node,*/ int nprocs)
4786{
4787        int i;
4788        struct job *jp;
4789
4790        for (i = njobs, jp = jobtab; ; jp++) {
4791                if (--i < 0) {
4792                        jp = growjobtab();
4793                        break;
4794                }
4795                if (jp->used == 0)
4796                        break;
4797                if (jp->state != JOBDONE || !jp->waited)
4798                        continue;
4799#if JOBS
4800                if (doing_jobctl)
4801                        continue;
4802#endif
4803                freejob(jp);
4804                break;
4805        }
4806        memset(jp, 0, sizeof(*jp));
4807#if JOBS
4808        /* jp->jobctl is a bitfield.
4809         * "jp->jobctl |= doing_jobctl" likely to give awful code */
4810        if (doing_jobctl)
4811                jp->jobctl = 1;
4812#endif
4813        jp->prev_job = curjob;
4814        curjob = jp;
4815        jp->used = 1;
4816        jp->ps = &jp->ps0;
4817        if (nprocs > 1) {
4818                jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4819        }
4820        TRACE(("makejob(%d) returns %%%d\n", nprocs,
4821                                jobno(jp)));
4822        return jp;
4823}
4824
4825#if JOBS
4826/*
4827 * Return a string identifying a command (to be printed by the
4828 * jobs command).
4829 */
4830static char *cmdnextc;
4831
4832static void
4833cmdputs(const char *s)
4834{
4835        static const char vstype[VSTYPE + 1][3] ALIGN1 = {
4836                "", "}", "-", "+", "?", "=",
4837                "%", "%%", "#", "##"
4838                IF_BASH_SUBSTR(, ":")
4839                IF_BASH_PATTERN_SUBST(, "/", "//")
4840        };
4841
4842        const char *p, *str;
4843        char cc[2];
4844        char *nextc;
4845        unsigned char c;
4846        unsigned char subtype = 0;
4847        int quoted = 0;
4848
4849        cc[1] = '\0';
4850        nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4851        p = s;
4852        while ((c = *p++) != '\0') {
4853                str = NULL;
4854                switch (c) {
4855                case CTLESC:
4856                        c = *p++;
4857                        break;
4858                case CTLVAR:
4859                        subtype = *p++;
4860                        if ((subtype & VSTYPE) == VSLENGTH)
4861                                str = "${#";
4862                        else
4863                                str = "${";
4864                        goto dostr;
4865                case CTLENDVAR:
4866                        str = "\"}";
4867                        str += !(quoted & 1);
4868                        quoted >>= 1;
4869                        subtype = 0;
4870                        goto dostr;
4871#if BASH_PROCESS_SUBST
4872                case CTLBACKQ:
4873                        c = '$';
4874                        str = "(...)";
4875                        break;
4876                case CTLTOPROC:
4877                        c = '>';
4878                        str = "(...)";
4879                        break;
4880                case CTLFROMPROC:
4881                        c = '<';
4882                        str = "(...)";
4883                        break;
4884#else
4885                case CTLBACKQ:
4886                        str = "$(...)";
4887                        goto dostr;
4888#endif
4889#if ENABLE_FEATURE_SH_MATH
4890                case CTLARI:
4891                        str = "$((";
4892                        goto dostr;
4893                case CTLENDARI:
4894                        str = "))";
4895                        goto dostr;
4896#endif
4897                case CTLQUOTEMARK:
4898                        quoted ^= 1;
4899                        c = '"';
4900                        break;
4901                case '=':
4902                        if (subtype == 0)
4903                                break;
4904                        if ((subtype & VSTYPE) != VSNORMAL)
4905                                quoted <<= 1;
4906                        str = vstype[subtype & VSTYPE];
4907                        if (subtype & VSNUL)
4908                                c = ':';
4909                        else
4910                                goto checkstr;
4911                        break;
4912                case '\'':
4913                case '\\':
4914                case '"':
4915                case '$':
4916                        /* These can only happen inside quotes */
4917                        cc[0] = c;
4918                        str = cc;
4919//FIXME:
4920// $ true $$ &
4921// $ <cr>
4922// [1]+  Done    true ${\$}   <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
4923                        c = '\\';
4924                        break;
4925                default:
4926                        break;
4927                }
4928                USTPUTC(c, nextc);
4929 checkstr:
4930                if (!str)
4931                        continue;
4932 dostr:
4933                while ((c = *str++) != '\0') {
4934                        USTPUTC(c, nextc);
4935                }
4936        } /* while *p++ not NUL */
4937
4938        if (quoted & 1) {
4939                USTPUTC('"', nextc);
4940        }
4941        *nextc = 0;
4942        cmdnextc = nextc;
4943}
4944
4945/* cmdtxt() and cmdlist() call each other */
4946static void cmdtxt(union node *n);
4947
4948static void
4949cmdlist(union node *np, int sep)
4950{
4951        for (; np; np = np->narg.next) {
4952                if (!sep)
4953                        cmdputs(" ");
4954                cmdtxt(np);
4955                if (sep && np->narg.next)
4956                        cmdputs(" ");
4957        }
4958}
4959
4960static void
4961cmdtxt(union node *n)
4962{
4963        union node *np;
4964        struct nodelist *lp;
4965        const char *p;
4966
4967        if (!n)
4968                return;
4969        switch (n->type) {
4970        default:
4971#if DEBUG
4972                abort();
4973#endif
4974        case NPIPE:
4975                lp = n->npipe.cmdlist;
4976                for (;;) {
4977                        cmdtxt(lp->n);
4978                        lp = lp->next;
4979                        if (!lp)
4980                                break;
4981                        cmdputs(" | ");
4982                }
4983                break;
4984        case NSEMI:
4985                p = "; ";
4986                goto binop;
4987        case NAND:
4988                p = " && ";
4989                goto binop;
4990        case NOR:
4991                p = " || ";
4992 binop:
4993                cmdtxt(n->nbinary.ch1);
4994                cmdputs(p);
4995                n = n->nbinary.ch2;
4996                goto donode;
4997        case NREDIR:
4998        case NBACKGND:
4999                n = n->nredir.n;
5000                goto donode;
5001        case NNOT:
5002                cmdputs("!");
5003                n = n->nnot.com;
5004 donode:
5005                cmdtxt(n);
5006                break;
5007        case NIF:
5008                cmdputs("if ");
5009                cmdtxt(n->nif.test);
5010                cmdputs("; then ");
5011                if (n->nif.elsepart) {
5012                        cmdtxt(n->nif.ifpart);
5013                        cmdputs("; else ");
5014                        n = n->nif.elsepart;
5015                } else {
5016                        n = n->nif.ifpart;
5017                }
5018                p = "; fi";
5019                goto dotail;
5020        case NSUBSHELL:
5021                cmdputs("(");
5022                n = n->nredir.n;
5023                p = ")";
5024                goto dotail;
5025        case NWHILE:
5026                p = "while ";
5027                goto until;
5028        case NUNTIL:
5029                p = "until ";
5030 until:
5031                cmdputs(p);
5032                cmdtxt(n->nbinary.ch1);
5033                n = n->nbinary.ch2;
5034                p = "; done";
5035 dodo:
5036                cmdputs("; do ");
5037 dotail:
5038                cmdtxt(n);
5039                goto dotail2;
5040        case NFOR:
5041                cmdputs("for ");
5042                cmdputs(n->nfor.var);
5043                cmdputs(" in ");
5044                cmdlist(n->nfor.args, 1);
5045                n = n->nfor.body;
5046                p = "; done";
5047                goto dodo;
5048        case NDEFUN:
5049                cmdputs(n->ndefun.text);
5050                p = "() { ... }";
5051                goto dotail2;
5052        case NCMD:
5053                cmdlist(n->ncmd.args, 1);
5054                cmdlist(n->ncmd.redirect, 0);
5055                break;
5056        case NARG:
5057                p = n->narg.text;
5058 dotail2:
5059                cmdputs(p);
5060                break;
5061        case NHERE:
5062        case NXHERE:
5063                p = "<<...";
5064                goto dotail2;
5065        case NCASE:
5066                cmdputs("case ");
5067                cmdputs(n->ncase.expr->narg.text);
5068                cmdputs(" in ");
5069                for (np = n->ncase.cases; np; np = np->nclist.next) {
5070                        cmdtxt(np->nclist.pattern);
5071                        cmdputs(") ");
5072                        cmdtxt(np->nclist.body);
5073                        cmdputs(";; ");
5074                }
5075                p = "esac";
5076                goto dotail2;
5077        case NTO:
5078                p = ">";
5079                goto redir;
5080        case NCLOBBER:
5081                p = ">|";
5082                goto redir;
5083        case NAPPEND:
5084                p = ">>";
5085                goto redir;
5086#if BASH_REDIR_OUTPUT
5087        case NTO2:
5088#endif
5089        case NTOFD:
5090                p = ">&";
5091                goto redir;
5092        case NFROM:
5093                p = "<";
5094                goto redir;
5095        case NFROMFD:
5096                p = "<&";
5097                goto redir;
5098        case NFROMTO:
5099                p = "<>";
5100 redir:
5101                cmdputs(utoa(n->nfile.fd));
5102                cmdputs(p);
5103                if (n->type == NTOFD || n->type == NFROMFD) {
5104                        if (n->ndup.dupfd >= 0)
5105                                cmdputs(utoa(n->ndup.dupfd));
5106                        else
5107                                cmdputs("-");
5108                        break;
5109                }
5110                n = n->nfile.fname;
5111                goto donode;
5112        }
5113}
5114
5115static char *
5116commandtext(union node *n)
5117{
5118        char *name;
5119
5120        STARTSTACKSTR(cmdnextc);
5121        cmdtxt(n);
5122        name = stackblock();
5123        TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
5124        return ckstrdup(name);
5125}
5126#endif /* JOBS */
5127
5128/*
5129 * Fork off a subshell.  If we are doing job control, give the subshell its
5130 * own process group.  Jp is a job structure that the job is to be added to.
5131 * N is the command that will be evaluated by the child.  Both jp and n may
5132 * be NULL.  The mode parameter can be one of the following:
5133 *      FORK_FG - Fork off a foreground process.
5134 *      FORK_BG - Fork off a background process.
5135 *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
5136 *                   process group even if job control is on.
5137 *
5138 * When job control is turned off, background processes have their standard
5139 * input redirected to /dev/null (except for the second and later processes
5140 * in a pipeline).
5141 *
5142 * Called with interrupts off.
5143 */
5144/*
5145 * Clear traps on a fork.
5146 */
5147static void
5148clear_traps(void)
5149{
5150        char **tp;
5151
5152        INT_OFF;
5153        for (tp = trap; tp <= &trap[NTRAP_LAST]; tp++) {
5154                if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */
5155                        if (trap_ptr == trap)
5156                                free(*tp);
5157                        /* else: it "belongs" to trap_ptr vector, don't free */
5158                        *tp = NULL;
5159                        if ((tp - trap) != 0 && (tp - trap) < NSIG)
5160                                setsignal(tp - trap);
5161                }
5162        }
5163        may_have_traps = 0;
5164        INT_ON;
5165}
5166
5167/* Lives far away from here, needed for forkchild */
5168static void closescript(void);
5169
5170/* Called after fork(), in child */
5171/* jp and n are NULL when called by openhere() for heredoc support */
5172static NOINLINE void
5173forkchild(struct job *jp, union node *n, int mode)
5174{
5175        int oldlvl;
5176
5177        TRACE(("Child shell %d\n", getpid()));
5178        oldlvl = shlvl;
5179        shlvl++;
5180
5181        /* man bash: "Non-builtin commands run by bash have signal handlers
5182         * set to the values inherited by the shell from its parent".
5183         * Do we do it correctly? */
5184
5185        closescript();
5186
5187        if (mode == FORK_NOJOB          /* is it `xxx` ? */
5188         && n && n->type == NCMD        /* is it single cmd? */
5189        /* && n->ncmd.args->type == NARG - always true? */
5190         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
5191         && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5192        /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5193        ) {
5194                TRACE(("Trap hack\n"));
5195                /* Awful hack for `trap` or $(trap).
5196                 *
5197                 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5198                 * contains an example where "trap" is executed in a subshell:
5199                 *
5200                 * save_traps=$(trap)
5201                 * ...
5202                 * eval "$save_traps"
5203                 *
5204                 * Standard does not say that "trap" in subshell shall print
5205                 * parent shell's traps. It only says that its output
5206                 * must have suitable form, but then, in the above example
5207                 * (which is not supposed to be normative), it implies that.
5208                 *
5209                 * bash (and probably other shell) does implement it
5210                 * (traps are reset to defaults, but "trap" still shows them),
5211                 * but as a result, "trap" logic is hopelessly messed up:
5212                 *
5213                 * # trap
5214                 * trap -- 'echo Ho' SIGWINCH  <--- we have a handler
5215                 * # (trap)        <--- trap is in subshell - no output (correct, traps are reset)
5216                 * # true | trap   <--- trap is in subshell - no output (ditto)
5217                 * # echo `true | trap`    <--- in subshell - output (but traps are reset!)
5218                 * trap -- 'echo Ho' SIGWINCH
5219                 * # echo `(trap)`         <--- in subshell in subshell - output
5220                 * trap -- 'echo Ho' SIGWINCH
5221                 * # echo `true | (trap)`  <--- in subshell in subshell in subshell - output!
5222                 * trap -- 'echo Ho' SIGWINCH
5223                 *
5224                 * The rules when to forget and when to not forget traps
5225                 * get really complex and nonsensical.
5226                 *
5227                 * Our solution: ONLY bare $(trap) or `trap` is special.
5228                 */
5229                /* Save trap handler strings for trap builtin to print */
5230                trap_ptr = xmemdup(trap, sizeof(trap));
5231                /* Fall through into clearing traps */
5232        }
5233        clear_traps();
5234#if JOBS
5235        /* do job control only in root shell */
5236        doing_jobctl = 0;
5237        if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
5238                pid_t pgrp;
5239
5240                if (jp->nprocs == 0)
5241                        pgrp = getpid();
5242                else
5243                        pgrp = jp->ps[0].ps_pid;
5244                /* this can fail because we are doing it in the parent also */
5245                setpgid(0, pgrp);
5246                if (mode == FORK_FG)
5247                        xtcsetpgrp(ttyfd, pgrp);
5248                setsignal(SIGTSTP);
5249                setsignal(SIGTTOU);
5250        } else
5251#endif
5252        if (mode == FORK_BG) {
5253                /* man bash: "When job control is not in effect,
5254                 * asynchronous commands ignore SIGINT and SIGQUIT" */
5255                ignoresig(SIGINT);
5256                ignoresig(SIGQUIT);
5257                if (jp->nprocs == 0) {
5258                        close(0);
5259                        if (open(bb_dev_null, O_RDONLY) != 0)
5260                                ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
5261                }
5262        }
5263        if (oldlvl == 0) {
5264                if (iflag) { /* why if iflag only? */
5265                        setsignal(SIGINT);
5266                        setsignal(SIGTERM);
5267                }
5268                /* man bash:
5269                 * "In all cases, bash ignores SIGQUIT. Non-builtin
5270                 * commands run by bash have signal handlers
5271                 * set to the values inherited by the shell
5272                 * from its parent".
5273                 * Take care of the second rule: */
5274                setsignal(SIGQUIT);
5275        }
5276#if JOBS
5277        if (n && n->type == NCMD
5278         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
5279        ) {
5280                TRACE(("Job hack\n"));
5281                /* "jobs": we do not want to clear job list for it,
5282                 * instead we remove only _its_ own_ job from job list.
5283                 * This makes "jobs .... | cat" more useful.
5284                 */
5285                freejob(curjob);
5286                return;
5287        }
5288#endif
5289        for (jp = curjob; jp; jp = jp->prev_job)
5290                freejob(jp);
5291}
5292
5293/* Called after fork(), in parent */
5294#if !JOBS
5295#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5296#endif
5297static void
5298forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5299{
5300        TRACE(("In parent shell: child = %d\n", pid));
5301        if (!jp) /* jp is NULL when called by openhere() for heredoc support */
5302                return;
5303#if JOBS
5304        if (mode != FORK_NOJOB && jp->jobctl) {
5305                int pgrp;
5306
5307                if (jp->nprocs == 0)
5308                        pgrp = pid;
5309                else
5310                        pgrp = jp->ps[0].ps_pid;
5311                /* This can fail because we are doing it in the child also */
5312                setpgid(pid, pgrp);
5313        }
5314#endif
5315        if (mode == FORK_BG) {
5316                backgndpid = pid;               /* set $! */
5317                set_curjob(jp, CUR_RUNNING);
5318        }
5319        if (jp) {
5320                struct procstat *ps = &jp->ps[jp->nprocs++];
5321                ps->ps_pid = pid;
5322                ps->ps_status = -1;
5323                ps->ps_cmd = nullstr;
5324#if JOBS
5325                if (doing_jobctl && n)
5326                        ps->ps_cmd = commandtext(n);
5327#endif
5328        }
5329}
5330
5331/* jp and n are NULL when called by openhere() for heredoc support */
5332static int
5333forkshell(struct job *jp, union node *n, int mode)
5334{
5335        int pid;
5336
5337        TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5338        pid = fork();
5339        if (pid < 0) {
5340                TRACE(("Fork failed, errno=%d", errno));
5341                if (jp)
5342                        freejob(jp);
5343                ash_msg_and_raise_perror("can't fork");
5344        }
5345        if (pid == 0) {
5346                CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
5347                forkchild(jp, n, mode);
5348        } else {
5349                forkparent(jp, n, mode, pid);
5350        }
5351        return pid;
5352}
5353
5354/*
5355 * Wait for job to finish.
5356 *
5357 * Under job control we have the problem that while a child process
5358 * is running interrupts generated by the user are sent to the child
5359 * but not to the shell.  This means that an infinite loop started by
5360 * an interactive user may be hard to kill.  With job control turned off,
5361 * an interactive user may place an interactive program inside a loop.
5362 * If the interactive program catches interrupts, the user doesn't want
5363 * these interrupts to also abort the loop.  The approach we take here
5364 * is to have the shell ignore interrupt signals while waiting for a
5365 * foreground process to terminate, and then send itself an interrupt
5366 * signal if the child process was terminated by an interrupt signal.
5367 * Unfortunately, some programs want to do a bit of cleanup and then
5368 * exit on interrupt; unless these processes terminate themselves by
5369 * sending a signal to themselves (instead of calling exit) they will
5370 * confuse this approach.
5371 *
5372 * Called with interrupts off.
5373 */
5374static int
5375waitforjob(struct job *jp)
5376{
5377        int st;
5378
5379        TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
5380
5381        /* In non-interactive shells, we _can_ get
5382         * a keyboard signal here and be EINTRed, but we just loop
5383         * inside dowait(), waiting for command to complete.
5384         *
5385         * man bash:
5386         * "If bash is waiting for a command to complete and receives
5387         * a signal for which a trap has been set, the trap
5388         * will not be executed until the command completes."
5389         *
5390         * Reality is that even if trap is not set, bash
5391         * will not act on the signal until command completes.
5392         * Try this. sleep5intoff.c:
5393         * #include <signal.h>
5394         * #include <unistd.h>
5395         * int main() {
5396         *         sigset_t set;
5397         *         sigemptyset(&set);
5398         *         sigaddset(&set, SIGINT);
5399         *         sigaddset(&set, SIGQUIT);
5400         *         sigprocmask(SIG_BLOCK, &set, NULL);
5401         *         sleep(5);
5402         *         return 0;
5403         * }
5404         * $ bash -c './sleep5intoff; echo hi'
5405         * ^C^C^C^C <--- pressing ^C once a second
5406         * $ _
5407         * $ bash -c './sleep5intoff; echo hi'
5408         * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5409         * $ _
5410         */
5411        dowait(jp ? DOWAIT_BLOCK : DOWAIT_NONBLOCK, jp);
5412        if (!jp)
5413                return exitstatus;
5414
5415        st = getstatus(jp);
5416#if JOBS
5417        if (jp->jobctl) {
5418                xtcsetpgrp(ttyfd, rootpid);
5419                restore_tty_if_stopped_or_signaled(jp);
5420
5421                /*
5422                 * This is truly gross.
5423                 * If we're doing job control, then we did a TIOCSPGRP which
5424                 * caused us (the shell) to no longer be in the controlling
5425                 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
5426                 * intuit from the subprocess exit status whether a SIGINT
5427                 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
5428                 */
5429                if (jp->sigint) /* TODO: do the same with all signals */
5430                        raise(SIGINT); /* ... by raise(jp->sig) instead? */
5431        }
5432        if (jp->state == JOBDONE)
5433#endif
5434                freejob(jp);
5435        return st;
5436}
5437
5438/*
5439 * return 1 if there are stopped jobs, otherwise 0
5440 */
5441static int
5442stoppedjobs(void)
5443{
5444        struct job *jp;
5445        int retval;
5446
5447        retval = 0;
5448        if (!iflag || job_warning)
5449                goto out;
5450        jp = curjob;
5451        if (jp && jp->state == JOBSTOPPED) {
5452                out2str("You have stopped jobs.\n");
5453                job_warning = 2;
5454                retval++;
5455        }
5456 out:
5457        return retval;
5458}
5459
5460
5461/*
5462 * Code for dealing with input/output redirection.
5463 */
5464
5465#undef EMPTY
5466#undef CLOSED
5467#define EMPTY -2                /* marks an unused slot in redirtab */
5468#define CLOSED -1               /* marks a slot of previously-closed fd */
5469
5470/*
5471 * Handle here documents.  Normally we fork off a process to write the
5472 * data to a pipe.  If the document is short, we can stuff the data in
5473 * the pipe without forking.
5474 */
5475/* openhere needs this forward reference */
5476static void expandhere(union node *arg);
5477static int
5478openhere(union node *redir)
5479{
5480        char *p;
5481        int pip[2];
5482        size_t len = 0;
5483
5484        if (pipe(pip) < 0)
5485                ash_msg_and_raise_perror("can't create pipe");
5486
5487        p = redir->nhere.doc->narg.text;
5488        if (redir->type == NXHERE) {
5489                expandhere(redir->nhere.doc);
5490                p = stackblock();
5491        }
5492
5493        len = strlen(p);
5494        if (len <= PIPE_BUF) {
5495                xwrite(pip[1], p, len);
5496                goto out;
5497        }
5498
5499        if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5500                /* child */
5501                close(pip[0]);
5502                ignoresig(SIGINT);  //signal(SIGINT, SIG_IGN);
5503                ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5504                ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
5505                ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5506                signal(SIGPIPE, SIG_DFL);
5507                xwrite(pip[1], p, len);
5508                _exit(EXIT_SUCCESS);
5509        }
5510 out:
5511        close(pip[1]);
5512        return pip[0];
5513}
5514
5515static int
5516openredirect(union node *redir)
5517{
5518        struct stat sb;
5519        char *fname;
5520        int f;
5521
5522        switch (redir->nfile.type) {
5523/* Can't happen, our single caller does this itself */
5524//      case NTOFD:
5525//      case NFROMFD:
5526//              return -1;
5527        case NHERE:
5528        case NXHERE:
5529                return openhere(redir);
5530        }
5531
5532        /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5533         * allocated space. Do it only when we know it is safe.
5534         */
5535        fname = redir->nfile.expfname;
5536
5537        switch (redir->nfile.type) {
5538        default:
5539#if DEBUG
5540                abort();
5541#endif
5542        case NFROM:
5543                f = open(fname, O_RDONLY);
5544                if (f < 0)
5545                        goto eopen;
5546                break;
5547        case NFROMTO:
5548                f = open(fname, O_RDWR|O_CREAT, 0666);
5549                if (f < 0)
5550                        goto ecreate;
5551                break;
5552        case NTO:
5553#if BASH_REDIR_OUTPUT
5554        case NTO2:
5555#endif
5556                /* Take care of noclobber mode. */
5557                if (Cflag) {
5558                        if (stat(fname, &sb) < 0) {
5559                                f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5560                                if (f < 0)
5561                                        goto ecreate;
5562                        } else if (!S_ISREG(sb.st_mode)) {
5563                                f = open(fname, O_WRONLY, 0666);
5564                                if (f < 0)
5565                                        goto ecreate;
5566                                if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
5567                                        close(f);
5568                                        errno = EEXIST;
5569                                        goto ecreate;
5570                                }
5571                        } else {
5572                                errno = EEXIST;
5573                                goto ecreate;
5574                        }
5575                        break;
5576                }
5577                /* FALLTHROUGH */
5578        case NCLOBBER:
5579                f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5580                if (f < 0)
5581                        goto ecreate;
5582                break;
5583        case NAPPEND:
5584                f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5585                if (f < 0)
5586                        goto ecreate;
5587                break;
5588        }
5589
5590        return f;
5591 ecreate:
5592        ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5593 eopen:
5594        ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5595}
5596
5597/*
5598 * Copy a file descriptor to be >= 10. Throws exception on error.
5599 */
5600static int
5601savefd(int from)
5602{
5603        int newfd;
5604        int err;
5605
5606        newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
5607        err = newfd < 0 ? errno : 0;
5608        if (err != EBADF) {
5609                if (err)
5610                        ash_msg_and_raise_perror("%d", from);
5611                close(from);
5612                if (F_DUPFD_CLOEXEC == F_DUPFD)
5613                        close_on_exec_on(newfd);
5614        }
5615
5616        return newfd;
5617}
5618static int
5619dup2_or_raise(int from, int to)
5620{
5621        int newfd;
5622
5623        newfd = (from != to) ? dup2(from, to) : to;
5624        if (newfd < 0) {
5625                /* Happens when source fd is not open: try "echo >&99" */
5626                ash_msg_and_raise_perror("%d", from);
5627        }
5628        return newfd;
5629}
5630static int
5631dup_CLOEXEC(int fd, int avoid_fd)
5632{
5633        int newfd;
5634 repeat:
5635        newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5636        if (newfd >= 0) {
5637                if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
5638                        close_on_exec_on(newfd);
5639        } else { /* newfd < 0 */
5640                if (errno == EBUSY)
5641                        goto repeat;
5642                if (errno == EINTR)
5643                        goto repeat;
5644        }
5645        return newfd;
5646}
5647static int
5648xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5649{
5650        int newfd;
5651 repeat:
5652        newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5653        if (newfd < 0) {
5654                if (errno == EBUSY)
5655                        goto repeat;
5656                if (errno == EINTR)
5657                        goto repeat;
5658                /* fd was not open? */
5659                if (errno == EBADF)
5660                        return fd;
5661                ash_msg_and_raise_perror("%d", newfd);
5662        }
5663        if (F_DUPFD_CLOEXEC == F_DUPFD)
5664                close_on_exec_on(newfd);
5665        close(fd);
5666        return newfd;
5667}
5668
5669/* Struct def and variable are moved down to the first usage site */
5670struct squirrel {
5671        int orig_fd;
5672        int moved_to;
5673};
5674struct redirtab {
5675        struct redirtab *next;
5676        int pair_count;
5677        struct squirrel two_fd[];
5678};
5679#define redirlist (G_var.redirlist)
5680
5681static void
5682add_squirrel_closed(struct redirtab *sq, int fd)
5683{
5684        int i;
5685
5686        if (!sq)
5687                return;
5688
5689        for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5690                /* If we collide with an already moved fd... */
5691                if (fd == sq->two_fd[i].orig_fd) {
5692                        /* Examples:
5693                         * "echo 3>FILE 3>&- 3>FILE"
5694                         * "echo 3>&- 3>FILE"
5695                         * No need for last redirect to insert
5696                         * another "need to close 3" indicator.
5697                         */
5698                        TRACE(("redirect_fd %d: already moved or closed\n", fd));
5699                        return;
5700                }
5701        }
5702        TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5703        sq->two_fd[i].orig_fd = fd;
5704        sq->two_fd[i].moved_to = CLOSED;
5705}
5706
5707static int
5708save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5709{
5710        int i, new_fd;
5711
5712        if (avoid_fd < 9) /* the important case here is that it can be -1 */
5713                avoid_fd = 9;
5714
5715#if JOBS
5716        if (fd == ttyfd) {
5717                /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5718                ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5719                TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5720                return 1; /* "we closed fd" */
5721        }
5722#endif
5723        /* Are we called from redirect(0)? E.g. redirect
5724         * in a forked child. No need to save fds,
5725         * we aren't going to use them anymore, ok to trash.
5726         */
5727        if (!sq)
5728                return 0;
5729
5730        /* If this one of script's fds? */
5731        if (fd != 0) {
5732                struct parsefile *pf = g_parsefile;
5733                while (pf) {
5734                        /* We skip fd == 0 case because of the following:
5735                         * $ ash  # running ash interactively
5736                         * $ . ./script.sh
5737                         * and in script.sh: "exec 9>&0".
5738                         * Even though top-level pf_fd _is_ 0,
5739                         * it's still ok to use it: "read" builtin uses it,
5740                         * why should we cripple "exec" builtin?
5741                         */
5742                        if (fd == pf->pf_fd) {
5743                                pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5744                                return 1; /* "we closed fd" */
5745                        }
5746                        pf = pf->prev;
5747                }
5748        }
5749
5750        /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5751
5752        /* First: do we collide with some already moved fds? */
5753        for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5754                /* If we collide with an already moved fd... */
5755                if (fd == sq->two_fd[i].moved_to) {
5756                        new_fd = dup_CLOEXEC(fd, avoid_fd);
5757                        sq->two_fd[i].moved_to = new_fd;
5758                        TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5759                        if (new_fd < 0) /* what? */
5760                                xfunc_die();
5761                        return 0; /* "we did not close fd" */
5762                }
5763                if (fd == sq->two_fd[i].orig_fd) {
5764                        /* Example: echo Hello >/dev/null 1>&2 */
5765                        TRACE(("redirect_fd %d: already moved\n", fd));
5766                        return 0; /* "we did not close fd" */
5767                }
5768        }
5769
5770        /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5771        new_fd = dup_CLOEXEC(fd, avoid_fd);
5772        TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5773        if (new_fd < 0) {
5774                if (errno != EBADF)
5775                        xfunc_die();
5776                /* new_fd = CLOSED; - already is -1 */
5777        }
5778        sq->two_fd[i].moved_to = new_fd;
5779        sq->two_fd[i].orig_fd = fd;
5780
5781        /* if we move stderr, let "set -x" code know */
5782        if (fd == preverrout_fd)
5783                preverrout_fd = new_fd;
5784
5785        return 0; /* "we did not close fd" */
5786}
5787
5788static int
5789internally_opened_fd(int fd, struct redirtab *sq)
5790{
5791        int i;
5792#if JOBS
5793        if (fd == ttyfd)
5794                return 1;
5795#endif
5796        /* If this one of script's fds? */
5797        if (fd != 0) {
5798                struct parsefile *pf = g_parsefile;
5799                while (pf) {
5800                        if (fd == pf->pf_fd)
5801                                return 1;
5802                        pf = pf->prev;
5803                }
5804        }
5805
5806        if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5807                if (fd == sq->two_fd[i].moved_to)
5808                        return 1;
5809        }
5810        return 0;
5811}
5812
5813/*
5814 * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
5815 * old file descriptors are stashed away so that the redirection can be
5816 * undone by calling popredir.
5817 */
5818/* flags passed to redirect */
5819#define REDIR_PUSH    01        /* save previous values of file descriptors */
5820static void
5821redirect(union node *redir, int flags)
5822{
5823        struct redirtab *sv;
5824
5825        if (!redir)
5826                return;
5827
5828        sv = NULL;
5829        INT_OFF;
5830        if (flags & REDIR_PUSH)
5831                sv = redirlist;
5832        do {
5833                int fd;
5834                int newfd;
5835                int close_fd;
5836                int closed;
5837
5838                fd = redir->nfile.fd;
5839                if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5840                        //bb_error_msg("doing %d > %d", fd, newfd);
5841                        newfd = redir->ndup.dupfd;
5842                        close_fd = -1;
5843                } else {
5844                        newfd = openredirect(redir); /* always >= 0 */
5845                        if (fd == newfd) {
5846                                /* open() gave us precisely the fd we wanted.
5847                                 * This means that this fd was not busy
5848                                 * (not opened to anywhere).
5849                                 * Remember to close it on restore:
5850                                 */
5851                                add_squirrel_closed(sv, fd);
5852                                continue;
5853                        }
5854                        close_fd = newfd;
5855                }
5856
5857                if (fd == newfd)
5858                        continue;
5859
5860                /* if "N>FILE": move newfd to fd */
5861                /* if "N>&M": dup newfd to fd */
5862                /* if "N>&-": close fd (newfd is -1) */
5863
5864 IF_BASH_REDIR_OUTPUT(redirect_more:)
5865
5866                closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5867                if (newfd == -1) {
5868                        /* "N>&-" means "close me" */
5869                        if (!closed) {
5870                                /* ^^^ optimization: saving may already
5871                                 * have closed it. If not... */
5872                                close(fd);
5873                        }
5874                } else {
5875                        /* if newfd is a script fd or saved fd, simulate EBADF */
5876                        if (internally_opened_fd(newfd, sv)) {
5877                                errno = EBADF;
5878                                ash_msg_and_raise_perror("%d", newfd);
5879                        }
5880                        dup2_or_raise(newfd, fd);
5881                        if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5882                                close(close_fd);
5883#if BASH_REDIR_OUTPUT
5884                        if (redir->nfile.type == NTO2 && fd == 1) {
5885                                /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5886                                fd = 2;
5887                                newfd = 1;
5888                                close_fd = -1;
5889                                goto redirect_more;
5890                        }
5891#endif
5892                }
5893        } while ((redir = redir->nfile.next) != NULL);
5894        INT_ON;
5895
5896//dash:#define REDIR_SAVEFD2 03        /* set preverrout */
5897#define REDIR_SAVEFD2 0
5898        // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5899        // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5900        // not only for calls with flags containing REDIR_SAVEFD2.
5901        // We do this unconditionally (see save_fd_on_redirect()).
5902        //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5903        //      preverrout_fd = copied_fd2;
5904}
5905
5906static int
5907redirectsafe(union node *redir, int flags)
5908{
5909        int err;
5910        volatile int saveint;
5911        struct jmploc *volatile savehandler = exception_handler;
5912        struct jmploc jmploc;
5913
5914        SAVE_INT(saveint);
5915        /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5916        err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
5917        if (!err) {
5918                exception_handler = &jmploc;
5919                redirect(redir, flags);
5920        }
5921        exception_handler = savehandler;
5922        if (err && exception_type != EXERROR)
5923                longjmp(exception_handler->loc, 1);
5924        RESTORE_INT(saveint);
5925        return err;
5926}
5927
5928#if BASH_PROCESS_SUBST
5929static void
5930pushfd(int fd)
5931{
5932        struct redirtab *sv;
5933
5934        sv = ckzalloc(sizeof(*sv) + sizeof(sv->two_fd[0]));
5935        sv->pair_count = 1;
5936        sv->two_fd[0].orig_fd = fd;
5937        sv->two_fd[0].moved_to = CLOSED;
5938        sv->next = redirlist;
5939        redirlist = sv;
5940}
5941#endif
5942
5943static struct redirtab*
5944pushredir(union node *redir)
5945{
5946        struct redirtab *sv;
5947        int i;
5948
5949        if (!redir)
5950                return redirlist;
5951
5952        i = 0;
5953        do {
5954                i++;
5955#if BASH_REDIR_OUTPUT
5956                if (redir->nfile.type == NTO2)
5957                        i++;
5958#endif
5959                redir = redir->nfile.next;
5960        } while (redir);
5961
5962        sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5963        sv->pair_count = i;
5964        while (--i >= 0)
5965                sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
5966        sv->next = redirlist;
5967        redirlist = sv;
5968        return sv->next;
5969}
5970
5971/*
5972 * Undo the effects of the last redirection.
5973 */
5974static void
5975popredir(int drop)
5976{
5977        struct redirtab *rp;
5978        int i;
5979
5980        if (redirlist == NULL)
5981                return;
5982        INT_OFF;
5983        rp = redirlist;
5984        for (i = 0; i < rp->pair_count; i++) {
5985                int fd = rp->two_fd[i].orig_fd;
5986                int copy = rp->two_fd[i].moved_to;
5987                if (copy == CLOSED) {
5988                        if (!drop)
5989                                close(fd);
5990                        continue;
5991                }
5992                if (copy != EMPTY) {
5993                        if (!drop) {
5994                                /*close(fd);*/
5995                                dup2_or_raise(copy, fd);
5996                        }
5997                        close(copy);
5998                }
5999        }
6000        redirlist = rp->next;
6001        free(rp);
6002        INT_ON;
6003}
6004
6005static void
6006unwindredir(struct redirtab *stop)
6007{
6008        while (redirlist != stop)
6009                popredir(/*drop:*/ 0);
6010}
6011
6012
6013/* ============ Routines to expand arguments to commands
6014 *
6015 * We have to deal with backquotes, shell variables, and file metacharacters.
6016 */
6017
6018#if ENABLE_FEATURE_SH_MATH
6019static arith_t
6020ash_arith(const char *s)
6021{
6022        arith_state_t math_state;
6023        arith_t result;
6024
6025        math_state.lookupvar = lookupvar;
6026        math_state.setvar    = setvar0;
6027        //math_state.endofname = endofname;
6028
6029        INT_OFF;
6030        result = arith(&math_state, s);
6031        if (math_state.errmsg)
6032                ash_msg_and_raise_error(math_state.errmsg);
6033        INT_ON;
6034
6035        return result;
6036}
6037#endif
6038#if BASH_SUBSTR
6039# if ENABLE_FEATURE_SH_MATH
6040static int substr_atoi(const char *s)
6041{
6042        arith_t t = ash_arith(s);
6043        if (sizeof(t) > sizeof(int)) {
6044                /* clamp very large or very large negative nums for ${v:N:M}:
6045                 * else "${v:0:0x100000001}" would work as "${v:0:1}"
6046                 */
6047                if (t > INT_MAX)
6048                        t = INT_MAX;
6049                if (t < INT_MIN)
6050                        t = INT_MIN;
6051        }
6052        return t;
6053}
6054# else
6055#  define substr_atoi(s) number(s)
6056# endif
6057#endif
6058
6059/*
6060 * expandarg flags
6061 */
6062#define EXP_FULL        0x1     /* perform word splitting & file globbing */
6063#define EXP_TILDE       0x2     /* do normal tilde expansion */
6064#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
6065#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
6066/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
6067 * POSIX says for this case:
6068 *  Pathname expansion shall not be performed on the word by a
6069 *  non-interactive shell; an interactive shell may perform it, but shall
6070 *  do so only when the expansion would result in one word.
6071 * Currently, our code complies to the above rule by never globbing
6072 * redirection filenames.
6073 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
6074 * (this means that on a typical Linux distro, bash almost always
6075 * performs globbing, and thus diverges from what we do).
6076 */
6077#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
6078#define EXP_VARTILDE2   0x20    /* expand tildes after colons only */
6079#define EXP_WORD        0x40    /* expand word in parameter expansion */
6080#define EXP_QUOTED      0x100   /* expand word in double quotes */
6081#define EXP_KEEPNUL     0x200   /* do not skip NUL characters */
6082#define EXP_DISCARD     0x400   /* discard result of expansion */
6083
6084/*
6085 * rmescape() flags
6086 */
6087#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
6088#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
6089#define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
6090#define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
6091
6092/* Add CTLESC when necessary. */
6093#define QUOTES_ESC     (EXP_FULL | EXP_CASE)
6094
6095/*
6096 * Structure specifying which parts of the string should be searched
6097 * for IFS characters.
6098 */
6099struct ifsregion {
6100        struct ifsregion *next; /* next region in list */
6101        int begoff;             /* offset of start of region */
6102        int endoff;             /* offset of end of region */
6103        int nulonly;            /* search for nul bytes only */
6104};
6105
6106struct arglist {
6107        struct strlist *list;
6108        struct strlist **lastp;
6109};
6110
6111/* output of current string */
6112static char *expdest;
6113/* list of back quote expressions */
6114static struct nodelist *argbackq;
6115/* first struct in list of ifs regions */
6116static struct ifsregion ifsfirst;
6117/* last struct in list */
6118static struct ifsregion *ifslastp;
6119/* holds expanded arg list */
6120static struct arglist exparg;
6121
6122/*
6123 * Break the argument string into pieces based upon IFS and add the
6124 * strings to the argument list.  The regions of the string to be
6125 * searched for IFS characters have been stored by recordregion.
6126 */
6127static void
6128ifsbreakup(char *string, struct arglist *arglist)
6129{
6130        struct ifsregion *ifsp;
6131        struct strlist *sp;
6132        char *start;
6133        char *p;
6134        char *q;
6135        const char *ifs, *realifs;
6136        int ifsspc;
6137        int nulonly;
6138
6139        start = string;
6140        if (ifslastp != NULL) {
6141                ifsspc = 0;
6142                nulonly = 0;
6143                realifs = ifsset() ? ifsval() : defifs;
6144                ifsp = &ifsfirst;
6145                do {
6146                        int afternul;
6147
6148                        p = string + ifsp->begoff;
6149                        afternul = nulonly;
6150                        nulonly = ifsp->nulonly;
6151                        ifs = nulonly ? nullstr : realifs;
6152                        ifsspc = 0;
6153                        while (p < string + ifsp->endoff) {
6154                                q = p;
6155                                if ((unsigned char)*p == CTLESC)
6156                                        p++;
6157                                if (!strchr(ifs, *p)) {
6158                                        p++;
6159                                        continue;
6160                                }
6161                                if (!(afternul || nulonly))
6162                                        ifsspc = (strchr(defifs, *p) != NULL);
6163                                /* Ignore IFS whitespace at start */
6164                                if (q == start && ifsspc) {
6165                                        p++;
6166                                        start = p;
6167                                        continue;
6168                                }
6169                                *q = '\0';
6170                                sp = stzalloc(sizeof(*sp));
6171                                sp->text = start;
6172                                *arglist->lastp = sp;
6173                                arglist->lastp = &sp->next;
6174                                p++;
6175                                if (!nulonly) {
6176                                        for (;;) {
6177                                                if (p >= string + ifsp->endoff) {
6178                                                        break;
6179                                                }
6180                                                q = p;
6181                                                if ((unsigned char)*p == CTLESC)
6182                                                        p++;
6183                                                if (strchr(ifs, *p) == NULL) {
6184                                                        p = q;
6185                                                        break;
6186                                                }
6187                                                if (strchr(defifs, *p) == NULL) {
6188                                                        if (ifsspc) {
6189                                                                p++;
6190                                                                ifsspc = 0;
6191                                                        } else {
6192                                                                p = q;
6193                                                                break;
6194                                                        }
6195                                                } else
6196                                                        p++;
6197                                        }
6198                                }
6199                                start = p;
6200                        } /* while */
6201                        ifsp = ifsp->next;
6202                } while (ifsp != NULL);
6203                if (nulonly)
6204                        goto add;
6205        }
6206
6207        if (!*start)
6208                return;
6209
6210 add:
6211        sp = stzalloc(sizeof(*sp));
6212        sp->text = start;
6213        *arglist->lastp = sp;
6214        arglist->lastp = &sp->next;
6215}
6216
6217static void
6218ifsfree(void)
6219{
6220        struct ifsregion *p = ifsfirst.next;
6221
6222        if (!p)
6223                goto out;
6224
6225        INT_OFF;
6226        do {
6227                struct ifsregion *ifsp;
6228                ifsp = p->next;
6229                free(p);
6230                p = ifsp;
6231        } while (p);
6232        ifsfirst.next = NULL;
6233        INT_ON;
6234 out:
6235        ifslastp = NULL;
6236}
6237
6238static size_t
6239esclen(const char *start, const char *p)
6240{
6241        size_t esc = 0;
6242
6243        while (p > start && (unsigned char)*--p == CTLESC) {
6244                esc++;
6245        }
6246        return esc;
6247}
6248
6249/*
6250 * Remove any CTLESC characters from a string.
6251 */
6252#if !BASH_PATTERN_SUBST
6253#define rmescapes(str, flag, slash_position) \
6254        rmescapes(str, flag)
6255#endif
6256static char *
6257rmescapes(char *str, int flag, int *slash_position)
6258{
6259        static const char qchars[] ALIGN1 = {
6260                IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
6261
6262        char *p, *q, *r;
6263        unsigned protect_against_glob;
6264        unsigned globbing;
6265
6266        p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
6267        if (!p)
6268                return str;
6269
6270        q = p;
6271        r = str;
6272        if (flag & RMESCAPE_ALLOC) {
6273                size_t len = p - str;
6274                size_t fulllen = len + strlen(p) + 1;
6275
6276                if (flag & RMESCAPE_GROW) {
6277                        int strloc = str - (char *)stackblock();
6278                        r = makestrspace(fulllen, expdest);
6279                        /* p and str may be invalidated by makestrspace */
6280                        str = (char *)stackblock() + strloc;
6281                        p = str + len;
6282                } else if (flag & RMESCAPE_HEAP) {
6283                        r = ckmalloc(fulllen);
6284                } else {
6285                        r = stalloc(fulllen);
6286                }
6287                q = r;
6288                if (len > 0) {
6289                        q = (char *)mempcpy(q, str, len);
6290                }
6291        }
6292
6293        globbing = flag & RMESCAPE_GLOB;
6294        protect_against_glob = globbing;
6295        while (*p) {
6296                if ((unsigned char)*p == CTLQUOTEMARK) {
6297// Note: protect_against_glob only affect whether
6298// CTLESC,<ch> gets converted to <ch> or to \<ch>
6299                        p++;
6300                        protect_against_glob = globbing;
6301                        continue;
6302                }
6303                if (*p == '\\') {
6304                        /* naked back slash */
6305                        protect_against_glob = 0;
6306                        goto copy;
6307                }
6308                if ((unsigned char)*p == CTLESC) {
6309                        p++;
6310#if DEBUG
6311                        if (*p == '\0')
6312                                ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6313#endif
6314                        if (protect_against_glob) {
6315                                /*
6316                                 * We used to trust glob() and fnmatch() to eat
6317                                 * superfluous escapes (\z where z has no
6318                                 * special meaning anyway). But this causes
6319                                 * bugs such as string of one greek letter rho
6320                                 * (unicode-encoded as two bytes "cf,81")
6321                                 * getting encoded as "cf,CTLESC,81"
6322                                 * and here, converted to "cf,\,81" -
6323                                 * which does not go well with some flavors
6324                                 * of fnmatch() in unicode locales
6325                                 * (for example, glibc <= 2.22).
6326                                 *
6327                                 * Lets add "\" only on the chars which need it.
6328                                 * Testcases for less obvious chars are shown.
6329                                 */
6330                                if (*p == '*'
6331                                 || *p == '?'
6332                                 || *p == '['
6333                                 || *p == '\\' /* case '\' in \\    ) echo ok;; *) echo WRONG;; esac */
6334                                 || *p == ']'  /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6335                                 || *p == '-'  /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6336                                 || *p == '!'  /* case '!' in [\!]  ) echo ok;; *) echo WRONG;; esac */
6337                                /* Some libc support [^negate], that's why "^" also needs love */
6338                                 || *p == '^'  /* case '^' in [\^]  ) echo ok;; *) echo WRONG;; esac */
6339                                ) {
6340                                        *q++ = '\\';
6341                                }
6342                        }
6343                }
6344#if BASH_PATTERN_SUBST
6345                else if (slash_position && p == str + *slash_position) {
6346                        /* stop handling globbing */
6347                        globbing = 0;
6348                        *slash_position = q - r;
6349                        slash_position = NULL;
6350                }
6351#endif
6352                protect_against_glob = globbing;
6353 copy:
6354                *q++ = *p++;
6355        }
6356        *q = '\0';
6357        if (flag & RMESCAPE_GROW) {
6358                expdest = r;
6359                STADJUST(q - r + 1, expdest);
6360        }
6361        return r;
6362}
6363#define pmatch(a, b) !fnmatch((a), (b), 0)
6364
6365/*
6366 * Prepare a pattern for a expmeta (internal glob(3)) call.
6367 *
6368 * Returns an stalloced string.
6369 */
6370static char *
6371preglob(const char *pattern, int flag)
6372{
6373        return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
6374}
6375
6376/*
6377 * Put a string on the stack.
6378 */
6379static size_t
6380memtodest(const char *p, size_t len, int flags)
6381{
6382        int syntax = flags & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6383        char *q;
6384        char *s;
6385
6386        if (!len)
6387                return 0;
6388
6389        q = makestrspace(len * 2, expdest);
6390        s = q;
6391
6392        do {
6393                unsigned char c = *p++;
6394                if (c) {
6395                        if (flags & QUOTES_ESC) {
6396                                int n = SIT(c, syntax);
6397                                if (n == CCTL
6398                                 || ((flags & EXP_QUOTED) && n == CBACK)
6399                                ) {
6400                                        USTPUTC(CTLESC, q);
6401                                }
6402                        }
6403                } else if (!(flags & EXP_KEEPNUL))
6404                        continue;
6405                USTPUTC(c, q);
6406        } while (--len);
6407
6408        expdest = q;
6409        return q - s;
6410}
6411
6412static size_t
6413strtodest(const char *p, int flags)
6414{
6415        size_t len = strlen(p);
6416        memtodest(p, len, flags);
6417        return len;
6418}
6419
6420/*
6421 * Our own itoa().
6422 * cvtnum() is used even if math support is off (to prepare $? values and such).
6423 */
6424static int
6425cvtnum(arith_t num, int flags)
6426{
6427        /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
6428        /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
6429        int len = (sizeof(arith_t) >= 4) ? sizeof(arith_t) * 3 : sizeof(arith_t) * 3 + 2;
6430        char buf[len];
6431
6432        len = fmtstr(buf, len, ARITH_FMT, num);
6433        return memtodest(buf, len, flags);
6434}
6435
6436/*
6437 * Record the fact that we have to scan this region of the
6438 * string for IFS characters.
6439 */
6440static void
6441recordregion(int start, int end, int nulonly)
6442{
6443        struct ifsregion *ifsp;
6444
6445        if (ifslastp == NULL) {
6446                ifsp = &ifsfirst;
6447        } else {
6448                INT_OFF;
6449                ifsp = ckzalloc(sizeof(*ifsp));
6450                /*ifsp->next = NULL; - ckzalloc did it */
6451                ifslastp->next = ifsp;
6452                INT_ON;
6453        }
6454        ifslastp = ifsp;
6455        ifslastp->begoff = start;
6456        ifslastp->endoff = end;
6457        ifslastp->nulonly = nulonly;
6458}
6459
6460static void
6461removerecordregions(int endoff)
6462{
6463        if (ifslastp == NULL)
6464                return;
6465
6466        if (ifsfirst.endoff > endoff) {
6467                while (ifsfirst.next) {
6468                        struct ifsregion *ifsp;
6469                        INT_OFF;
6470                        ifsp = ifsfirst.next->next;
6471                        free(ifsfirst.next);
6472                        ifsfirst.next = ifsp;
6473                        INT_ON;
6474                }
6475                if (ifsfirst.begoff > endoff) {
6476                        ifslastp = NULL;
6477                } else {
6478                        ifslastp = &ifsfirst;
6479                        ifsfirst.endoff = endoff;
6480                }
6481                return;
6482        }
6483
6484        ifslastp = &ifsfirst;
6485        while (ifslastp->next && ifslastp->next->begoff < endoff)
6486                ifslastp = ifslastp->next;
6487        while (ifslastp->next) {
6488                struct ifsregion *ifsp;
6489                INT_OFF;
6490                ifsp = ifslastp->next->next;
6491                free(ifslastp->next);
6492                ifslastp->next = ifsp;
6493                INT_ON;
6494        }
6495        if (ifslastp->endoff > endoff)
6496                ifslastp->endoff = endoff;
6497}
6498
6499static char *
6500exptilde(char *startp, int flag)
6501{
6502        unsigned char c;
6503        char *name;
6504        struct passwd *pw;
6505        const char *home;
6506        char *p;
6507
6508        p = startp;
6509        name = p + 1;
6510
6511        while ((c = *++p) != '\0') {
6512                switch (c) {
6513                case CTLESC:
6514                        return startp;
6515                case CTLQUOTEMARK:
6516                        return startp;
6517                case ':':
6518                        if (flag & EXP_VARTILDE)
6519                                goto done;
6520                        break;
6521                case '/':
6522                case CTLENDVAR:
6523                        goto done;
6524                }
6525        }
6526 done:
6527        if (flag & EXP_DISCARD)
6528                goto out;
6529        *p = '\0';
6530        if (*name == '\0') {
6531                home = lookupvar("HOME");
6532        } else {
6533                pw = getpwnam(name);
6534                if (pw == NULL)
6535                        goto lose;
6536                home = pw->pw_dir;
6537        }
6538        *p = c;
6539        if (!home)
6540                goto lose;
6541        strtodest(home, flag | EXP_QUOTED);
6542 out:
6543        return p;
6544 lose:
6545        return startp;
6546}
6547
6548/*
6549 * Execute a command inside back quotes.  If it's a builtin command, we
6550 * want to save its output in a block obtained from malloc.  Otherwise
6551 * we fork off a subprocess and get the output of the command via a pipe.
6552 * Should be called with interrupts off.
6553 */
6554struct backcmd {                /* result of evalbackcmd */
6555        int fd;                 /* file descriptor to read from */
6556        int nleft;              /* number of chars in buffer */
6557        char *buf;              /* buffer */
6558        struct job *jp;         /* job structure for command */
6559};
6560
6561/* These forward decls are needed to use "eval" code for backticks handling: */
6562/* flags in argument to evaltree */
6563#define EV_EXIT    01           /* exit after evaluating tree */
6564#define EV_TESTED  02           /* exit status is checked; ignore -e flag */
6565static int evaltree(union node *, int);
6566
6567/* An evaltree() which is known to never return.
6568 * Used to use an alias:
6569 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6570 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6571 */
6572static ALWAYS_INLINE NORETURN void
6573evaltreenr(union node *n, int flags)
6574{
6575        evaltree(n, flags);
6576        bb_unreachable(abort());
6577        /* NOTREACHED */
6578}
6579
6580static void FAST_FUNC
6581evalbackcmd(union node *n, struct backcmd *result
6582                                IF_BASH_PROCESS_SUBST(, int ctl))
6583{
6584        int pip[2];
6585        struct job *jp;
6586#if BASH_PROCESS_SUBST
6587        /* determine end of pipe used by parent (ip) and child (ic) */
6588        const int ip = (ctl == CTLTOPROC);
6589        const int ic = !(ctl == CTLTOPROC);
6590#else
6591        const int ctl = CTLBACKQ;
6592        const int ip = 0;
6593        const int ic = 1;
6594#endif
6595
6596        result->fd = -1;
6597        result->buf = NULL;
6598        result->nleft = 0;
6599        result->jp = NULL;
6600        if (n == NULL) {
6601                goto out;
6602        }
6603
6604        if (pipe(pip) < 0)
6605                ash_msg_and_raise_perror("can't create pipe");
6606        /* process substitution uses NULL job/node, like openhere() */
6607        jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL;
6608        if (forkshell(jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB) == 0) {
6609                /* child */
6610                FORCE_INT_ON;
6611                close(pip[ip]);
6612                /* ic is index of child end of pipe *and* fd to connect it to */
6613                if (pip[ic] != ic) {
6614                        /*close(ic);*/
6615                        dup2_or_raise(pip[ic], ic);
6616                        close(pip[ic]);
6617                }
6618/* TODO: eflag clearing makes the following not abort:
6619 *  ash -c 'set -e; z=$(false;echo foo); echo $z'
6620 * which is what bash does (unless it is in POSIX mode).
6621 * dash deleted "eflag = 0" line in the commit
6622 *  Date: Mon, 28 Jun 2010 17:11:58 +1000
6623 *  [EVAL] Don't clear eflag in evalbackcmd
6624 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6625 */
6626                eflag = 0;
6627                ifsfree();
6628                evaltreenr(n, EV_EXIT);
6629                /* NOTREACHED */
6630        }
6631        /* parent */
6632#if BASH_PROCESS_SUBST
6633        if (ctl != CTLBACKQ) {
6634                int fd = fcntl(pip[ip], F_DUPFD, 64);
6635                if (fd > 0) {
6636                        close(pip[ip]);
6637                        pip[ip] = fd;
6638                }
6639                pushfd(pip[ip]);
6640        }
6641#endif
6642        close(pip[ic]);
6643        result->fd = pip[ip];
6644        result->jp = jp;
6645
6646 out:
6647        TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6648                result->fd, result->buf, result->nleft, result->jp));
6649}
6650
6651/*
6652 * Expand stuff in backwards quotes.
6653 */
6654static void
6655expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl))
6656{
6657#if !BASH_PROCESS_SUBST
6658        const int ctl = CTLBACKQ;
6659#endif
6660        struct backcmd in;
6661        int i;
6662        char buf[128];
6663        char *p;
6664        char *dest;
6665        int startloc;
6666        struct stackmark smark;
6667
6668        if (flag & EXP_DISCARD)
6669                goto out;
6670
6671        INT_OFF;
6672        startloc = expdest - (char *)stackblock();
6673        pushstackmark(&smark, startloc);
6674        evalbackcmd(cmd, &in IF_BASH_PROCESS_SUBST(, ctl));
6675        popstackmark(&smark);
6676
6677        if (ctl != CTLBACKQ) {
6678                sprintf(buf, DEV_FD_PREFIX"%d", in.fd);
6679                strtodest(buf, BASESYNTAX);
6680                goto done;
6681        }
6682
6683        p = in.buf;
6684        i = in.nleft;
6685        if (i == 0)
6686                goto read;
6687        for (;;) {
6688                memtodest(p, i, flag);
6689 read:
6690                if (in.fd < 0)
6691                        break;
6692                i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6693                TRACE(("expbackq: read returns %d\n", i));
6694                if (i <= 0)
6695                        break;
6696                p = buf;
6697        }
6698
6699        free(in.buf);
6700        if (in.fd >= 0) {
6701                close(in.fd);
6702                back_exitstatus = waitforjob(in.jp);
6703        }
6704 done:
6705        INT_ON;
6706
6707        /* Eat all trailing newlines */
6708        dest = expdest;
6709        for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';)
6710                STUNPUTC(dest);
6711        expdest = dest;
6712
6713        if (!(flag & EXP_QUOTED))
6714                recordregion(startloc, dest - (char *)stackblock(), 0);
6715        TRACE(("evalbackq: size:%d:'%.*s'\n",
6716                (int)((dest - (char *)stackblock()) - startloc),
6717                (int)((dest - (char *)stackblock()) - startloc),
6718                stackblock() + startloc));
6719
6720 out:
6721        argbackq = argbackq->next;
6722}
6723
6724/* expari needs it */
6725static char *argstr(char *p, int flag);
6726
6727#if ENABLE_FEATURE_SH_MATH
6728/*
6729 * Expand arithmetic expression.  Backup to start of expression,
6730 * evaluate, place result in (backed up) result, adjust string position.
6731 */
6732static char *
6733expari(char *start, int flag)
6734{
6735        struct stackmark sm;
6736        int begoff;
6737        int endoff;
6738        int len;
6739        arith_t result;
6740        char *p;
6741
6742        p = stackblock();
6743        begoff = expdest - p;
6744        p = argstr(start, flag & EXP_DISCARD);
6745
6746        if (flag & EXP_DISCARD)
6747                goto out;
6748
6749        start = stackblock();
6750        endoff = expdest - start;
6751        start += begoff;
6752        STADJUST(start - expdest, expdest);
6753
6754        removerecordregions(begoff);
6755
6756        if (flag & QUOTES_ESC)
6757                rmescapes(start, 0, NULL);
6758
6759        pushstackmark(&sm, endoff);
6760        result = ash_arith(start);
6761        popstackmark(&sm);
6762
6763        len = cvtnum(result, flag);
6764
6765        if (!(flag & EXP_QUOTED))
6766                recordregion(begoff, begoff + len, 0);
6767
6768 out:
6769        return p;
6770}
6771#endif
6772
6773/* argstr needs it */
6774static char *evalvar(char *p, int flags);
6775
6776/*
6777 * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
6778 * characters to allow for further processing.  Otherwise treat
6779 * $@ like $* since no splitting will be performed.
6780 */
6781static char *
6782argstr(char *p, int flag)
6783{
6784        static const char spclchars[] ALIGN1 = {
6785                '=',
6786                ':',
6787                CTLQUOTEMARK,
6788                CTLENDVAR,
6789                CTLESC,
6790                CTLVAR,
6791                CTLBACKQ,
6792#if BASH_PROCESS_SUBST
6793                CTLTOPROC,
6794                CTLFROMPROC,
6795#endif
6796#if ENABLE_FEATURE_SH_MATH
6797                CTLARI,
6798                CTLENDARI,
6799#endif
6800                '\0'
6801        };
6802        const char *reject = spclchars;
6803        int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6804        int inquotes;
6805        size_t length;
6806        int startloc;
6807
6808        reject += !!(flag & EXP_VARTILDE2);
6809        reject += flag & EXP_VARTILDE ? 0 : 2;
6810        inquotes = 0;
6811        length = 0;
6812        if (flag & EXP_TILDE) {
6813                flag &= ~EXP_TILDE;
6814 tilde:
6815                if (*p == '~')
6816                        p = exptilde(p, flag);
6817        }
6818 start:
6819        startloc = expdest - (char *)stackblock();
6820        for (;;) {
6821                int end;
6822                unsigned char c;
6823
6824                length += strcspn(p + length, reject);
6825                end = 0;
6826                c = p[length];
6827                if (!(c & 0x80)
6828                 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6829                 || c == CTLENDVAR
6830                ) {
6831                        /*
6832                         * c == '=' || c == ':' || c == '\0' ||
6833                         * c == CTLENDARI || c == CTLENDVAR
6834                         */
6835                        length++;
6836                        /* c == '\0' || c == CTLENDARI || c == CTLENDVAR */
6837                        end = !!((c - 1) & 0x80);
6838                }
6839                if (length > 0 && !(flag & EXP_DISCARD)) {
6840                        int newloc;
6841                        char *q;
6842
6843                        q = stnputs(p, length, expdest);
6844                        q[-1] &= end - 1;
6845                        expdest = q - (flag & EXP_WORD ? end : 0);
6846                        newloc = q - (char *)stackblock() - end;
6847                        if (breakall && !inquotes && newloc > startloc) {
6848                                recordregion(startloc, newloc, 0);
6849                        }
6850                        startloc = newloc;
6851                }
6852                p += length + 1;
6853                length = 0;
6854
6855                if (end)
6856                        break;
6857
6858                switch (c) {
6859                case '=':
6860                        flag |= EXP_VARTILDE2;
6861                        reject++;
6862                        /* fall through */
6863                case ':':
6864                        /*
6865                         * sort of a hack - expand tildes in variable
6866                         * assignments (after the first '=' and after ':'s).
6867                         */
6868                        if (*--p == '~') {
6869                                goto tilde;
6870                        }
6871                        continue;
6872                case CTLQUOTEMARK:
6873                        /* "$@" syntax adherence hack */
6874                        if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6875                                p = evalvar(p + 1, flag | EXP_QUOTED) + 1;
6876                                goto start;
6877                        }
6878                        inquotes ^= EXP_QUOTED;
6879 addquote:
6880                        if (flag & QUOTES_ESC) {
6881                                p--;
6882                                length++;
6883                                startloc++;
6884                        }
6885                        break;
6886                case CTLESC:
6887                        startloc++;
6888                        length++;
6889                        goto addquote;
6890                case CTLVAR:
6891                        TRACE(("argstr: evalvar('%s')\n", p));
6892                        p = evalvar(p, flag | inquotes);
6893                        TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6894                        goto start;
6895#if BASH_PROCESS_SUBST
6896                case CTLTOPROC:
6897                case CTLFROMPROC:
6898#endif
6899                case CTLBACKQ:
6900                        expbackq(argbackq->n, flag | inquotes IF_BASH_PROCESS_SUBST(, c));
6901                        goto start;
6902#if ENABLE_FEATURE_SH_MATH
6903                case CTLARI:
6904                        p = expari(p, flag | inquotes);
6905                        goto start;
6906#endif
6907                }
6908        }
6909        return p - 1;
6910}
6911
6912static char *
6913scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6914                char *pattern, int quotes, int zero)
6915{
6916        char *loc, *loc2;
6917        char c;
6918
6919        loc = startp;
6920        loc2 = rmesc;
6921        do {
6922                int match;
6923                const char *s = loc2;
6924
6925                c = *loc2;
6926                if (zero) {
6927                        *loc2 = '\0';
6928                        s = rmesc;
6929                }
6930                match = pmatch(pattern, s);
6931
6932                *loc2 = c;
6933                if (match)
6934                        return loc;
6935                if (quotes && (unsigned char)*loc == CTLESC)
6936                        loc++;
6937                loc++;
6938                loc2++;
6939        } while (c);
6940        return NULL;
6941}
6942
6943static char *
6944scanright(char *startp, char *rmesc, char *rmescend,
6945                char *pattern, int quotes, int match_at_start)
6946{
6947#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6948        int try2optimize = match_at_start;
6949#endif
6950        int esc = 0;
6951        char *loc;
6952        char *loc2;
6953
6954        /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6955         * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6956         * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6957         * Logic:
6958         * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6959         * and on each iteration they go back two/one char until they reach the beginning.
6960         * We try to match "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6961         * If one of these matches, return pointer past last matched char in startp.
6962         */
6963        /* TODO: document in what other circumstances we are called. */
6964
6965        for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6966                int match;
6967                char c = *loc2;
6968                const char *s = loc2;
6969                if (match_at_start) {
6970                        *loc2 = '\0';
6971                        s = rmesc;
6972                }
6973                match = pmatch(pattern, s);
6974                //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6975                *loc2 = c;
6976                if (match)
6977                        return loc;
6978#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6979                if (try2optimize) {
6980                        /* Maybe we can optimize this:
6981                         * if pattern ends with unescaped *, we can avoid checking
6982                         * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6983                         * it won't match truncated "raw_value_of_" strings too.
6984                         */
6985                        unsigned plen = strlen(pattern);
6986                        /* Does it end with "*"? */
6987                        if (plen != 0 && pattern[--plen] == '*') {
6988                                /* "xxxx*" is not escaped */
6989                                /* "xxx\*" is escaped */
6990                                /* "xx\\*" is not escaped */
6991                                /* "x\\\*" is escaped */
6992                                int slashes = 0;
6993                                while (plen != 0 && pattern[--plen] == '\\')
6994                                        slashes++;
6995                                if (!(slashes & 1))
6996                                        break; /* ends with unescaped "*" */
6997                        }
6998                        try2optimize = 0;
6999                }
7000#endif
7001                loc--;
7002                if (quotes) {
7003                        if (--esc < 0) {
7004                                esc = esclen(startp, loc);
7005                        }
7006                        if (esc % 2) {
7007                                esc--;
7008                                loc--;
7009                        }
7010                }
7011        }
7012        return NULL;
7013}
7014
7015static void varunset(const char *, const char *, const char *, int) NORETURN;
7016static void
7017varunset(const char *end, const char *var, const char *umsg, int varflags)
7018{
7019        const char *msg;
7020        const char *tail;
7021
7022        tail = nullstr;
7023        msg = "parameter not set";
7024        if (umsg) {
7025                if ((unsigned char)*end == CTLENDVAR) {
7026                        if (varflags & VSNUL)
7027                                tail = " or null";
7028                } else {
7029                        msg = umsg;
7030                }
7031        }
7032        ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
7033}
7034
7035static char *
7036subevalvar(char *start, char *str, int strloc,
7037                int startloc, int varflags, int flag)
7038{
7039        int subtype = varflags & VSTYPE;
7040        int quotes = flag & QUOTES_ESC;
7041        char *startp;
7042        char *loc;
7043        char *rmesc, *rmescend;
7044        long amount;
7045        int resetloc;
7046        int argstr_flags;
7047        IF_BASH_PATTERN_SUBST(int workloc;)
7048        IF_BASH_PATTERN_SUBST(int slash_pos;)
7049        IF_BASH_PATTERN_SUBST(char *repl;)
7050        int zero;
7051        char *(*scan)(char*, char*, char*, char*, int, int);
7052        char *p;
7053
7054        //bb_error_msg("subevalvar(start:'%s',str:'%s',strloc:%d,startloc:%d,varflags:%x,quotes:%d)",
7055        //              start, str, strloc, startloc, varflags, quotes);
7056
7057#if BASH_PATTERN_SUBST
7058        /* For "${v/pattern/repl}", we must find the delimiter _before_
7059         * argstr() call expands possible variable references in pattern:
7060         * think about "v=a; a=a/; echo ${v/$a/r}" case.
7061         */
7062        repl = NULL;
7063        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7064                /* Find '/' and replace with NUL */
7065                repl = start;
7066                /* The pattern can't be empty.
7067                 * IOW: if the first char after "${v//" is a slash,
7068                 * it does not terminate the pattern - it's the first char of the pattern:
7069                 *  v=/dev/ram; echo ${v////-}  prints -dev-ram (pattern is "/")
7070                 *  v=/dev/ram; echo ${v///r/-} prints /dev-am  (pattern is "/r")
7071                 */
7072                if (*repl == '/')
7073                        repl++;
7074                for (;;) {
7075                        if (*repl == '\0') {
7076                                repl = NULL;
7077                                break;
7078                        }
7079                        if (*repl == '/') {
7080                                *repl = '\0';
7081                                break;
7082                        }
7083                        /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
7084                        if ((unsigned char)*repl == CTLESC && repl[1])
7085                                repl++;
7086                        repl++;
7087                }
7088        }
7089#endif
7090        argstr_flags = (flag & EXP_DISCARD) | EXP_TILDE;
7091        if (!str
7092#if BASH_SUBSTR
7093         && subtype != VSSUBSTR
7094#endif
7095        ) {
7096                /* EXP_CASE keeps CTLESC's */
7097                argstr_flags |= EXP_CASE;
7098        }
7099        p = argstr(start, argstr_flags);
7100
7101        //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
7102#if BASH_PATTERN_SUBST
7103        slash_pos = -1;
7104        if (repl) {
7105                slash_pos = expdest - ((char *)stackblock() + strloc);
7106                if (!(flag & EXP_DISCARD))
7107                        STPUTC('/', expdest);
7108                //bb_error_msg("repl+1:'%s'", repl + 1);
7109                p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
7110                *repl = '/';
7111        }
7112#endif
7113        if (flag & EXP_DISCARD)
7114                return p;
7115
7116        startp = (char *)stackblock() + startloc;
7117        //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
7118
7119        switch (subtype) {
7120        case VSASSIGN:
7121                setvar0(str, startp);
7122
7123                loc = startp;
7124                goto out;
7125
7126        case VSQUESTION:
7127                varunset(start, str, startp, varflags);
7128                /* NOTREACHED */
7129
7130#if BASH_SUBSTR
7131        case VSSUBSTR: {
7132                int pos, len, orig_len;
7133                char *colon;
7134                char *vstr;
7135
7136                loc = vstr = stackblock() + strloc;
7137
7138                /* Read POS in ${var:POS:LEN} */
7139                colon = strchr(loc, ':');
7140                if (colon) *colon = '\0';
7141                pos = substr_atoi(loc);
7142                if (colon) *colon = ':';
7143
7144                /* Read LEN in ${var:POS:LEN} */
7145                len = vstr - startp - 1;
7146                /* *loc != '\0', guaranteed by parser */
7147                if (quotes) {
7148                        char *ptr;
7149                        /* Adjust the length by the number of escapes */
7150                        for (ptr = startp; ptr < (vstr - 1); ptr++) {
7151                                if ((unsigned char)*ptr == CTLESC) {
7152                                        len--;
7153                                        ptr++;
7154                                }
7155                        }
7156                }
7157                orig_len = len;
7158                if (*loc++ == ':') {
7159                        /* ${var::LEN} */
7160                        len = substr_atoi(loc);
7161                } else {
7162                        /* Skip POS in ${var:POS:LEN} */
7163                        len = orig_len;
7164                        while (*loc && *loc != ':')
7165                                loc++;
7166                        if (*loc++ == ':')
7167                                len = substr_atoi(loc);
7168                }
7169                if (pos < 0) {
7170                        /* ${VAR:$((-n)):l} starts n chars from the end */
7171                        pos = orig_len + pos;
7172                }
7173                if ((unsigned)pos >= orig_len) {
7174                        /* apart from obvious ${VAR:999999:l},
7175                         * covers ${VAR:$((-9999999)):l} - result is ""
7176                         * (bash compat)
7177                         */
7178                        pos = 0;
7179                        len = 0;
7180                }
7181                if (len < 0) {
7182                        /* ${VAR:N:-M} sets LEN to strlen()-M */
7183                        len = (orig_len - pos) + len;
7184                }
7185                if ((unsigned)len > (orig_len - pos))
7186                        len = orig_len - pos;
7187
7188                if (!quotes) {
7189                        loc = mempcpy(startp, startp + pos, len);
7190                } else {
7191                        for (vstr = startp; pos != 0; pos--) {
7192                                if ((unsigned char)*vstr == CTLESC)
7193                                        vstr++;
7194                                vstr++;
7195                        }
7196                        for (loc = startp; len != 0; len--) {
7197                                if ((unsigned char)*vstr == CTLESC)
7198                                        *loc++ = *vstr++;
7199                                *loc++ = *vstr++;
7200                        }
7201                }
7202                *loc = '\0';
7203                goto out;
7204        }
7205#endif /* BASH_SUBSTR */
7206        }
7207
7208        resetloc = expdest - (char *)stackblock();
7209
7210#if BASH_PATTERN_SUBST
7211        repl = NULL;
7212
7213        /* We'll comeback here if we grow the stack while handling
7214         * a VSREPLACE or VSREPLACEALL, since our pointers into the
7215         * stack will need rebasing, and we'll need to remove our work
7216         * areas each time
7217         */
7218 restart:
7219#endif
7220
7221        amount = expdest - ((char *)stackblock() + resetloc);
7222        STADJUST(-amount, expdest);
7223        startp = (char *)stackblock() + startloc;
7224
7225        rmesc = startp;
7226        rmescend = (char *)stackblock() + strloc;
7227        //bb_error_msg("str7:'%s'", rmescend);
7228        if (quotes) {
7229//TODO: how to handle slash_pos here if string changes (shortens?)
7230                rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
7231                if (rmesc != startp) {
7232                        rmescend = expdest;
7233                        startp = (char *)stackblock() + startloc;
7234                }
7235        }
7236        rmescend--;
7237        str = (char *)stackblock() + strloc;
7238        /*
7239         * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7240         * The result is a_\_z_c (not a\_\_z_c)!
7241         *
7242         * The search pattern and replace string treat backslashes differently!
7243         * "&slash_pos" causes rmescapes() to work differently on the pattern
7244         * and string.  It's only used on the first call.
7245         */
7246        //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7247        rmescapes(str, RMESCAPE_GLOB,
7248                repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7249        );
7250
7251#if BASH_PATTERN_SUBST
7252        workloc = expdest - (char *)stackblock();
7253        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7254                size_t no_meta_len, first_escaped;
7255                int len;
7256                char *idx, *end;
7257
7258                if (!repl) {
7259                        //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
7260                        repl = nullstr;
7261                        if (slash_pos >= 0) {
7262                                repl = str + slash_pos;
7263                                *repl++ = '\0';
7264                        }
7265                }
7266                //bb_error_msg("str:'%s' repl:'%s'", str, repl);
7267
7268                /* If there's no pattern to match, return the expansion unmolested */
7269                if (str[0] == '\0')
7270                        goto out1;
7271
7272                first_escaped = (str[0] == '\\' && str[1]);
7273                /* "first_escaped" trick allows to treat e.g. "\*no_glob_chars"
7274                 * as literal too (as it is semi-common, and easy to accomodate
7275                 * by just using str + 1).
7276                 */
7277                no_meta_len = strpbrk(str + first_escaped * 2, "*?[\\") ? 0 : strlen(str);
7278                len = 0;
7279                idx = startp;
7280                end = str - 1;
7281                while (idx <= end) {
7282 try_to_match:
7283                        if (no_meta_len == 0) {
7284                                /* pattern has meta chars, have to glob */
7285                                loc = scanright(idx, rmesc, rmescend, str, quotes, /*match_at_start:*/ 1);
7286                        } else {
7287                                /* Testcase for very slow replace (performs about 22k replaces):
7288                                 * x=::::::::::::::::::::::
7289                                 * x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;echo ${#x}
7290                                 * echo "${x//:/|}"
7291                                 * To test "first_escaped" logic, replace : with *.
7292                                 */
7293                                if (strncmp(rmesc, str + first_escaped, no_meta_len - first_escaped) != 0)
7294                                        goto no_match;
7295                                loc = idx;
7296                                if (!quotes) {
7297                                        loc += no_meta_len - first_escaped;
7298                                } else {
7299                                        size_t n = no_meta_len - first_escaped;
7300                                        do {
7301                                                if ((unsigned char)*loc == CTLESC)
7302                                                        loc++;
7303                                                loc++;
7304                                        } while (--n != 0);
7305                                }
7306                        }
7307                        //bb_error_msg("scanright('%s'):'%s'", str, loc);
7308                        if (!loc) {
7309                                char *restart_detect;
7310 no_match:
7311                                /* No match, advance */
7312                                restart_detect = stackblock();
7313 skip_matching:
7314                                if (idx >= end)
7315                                        break;
7316                                STPUTC(*idx, expdest);
7317                                if (quotes && (unsigned char)*idx == CTLESC) {
7318                                        idx++;
7319                                        len++;
7320                                        STPUTC(*idx, expdest);
7321                                }
7322                                if (stackblock() != restart_detect)
7323                                        goto restart;
7324                                idx++;
7325                                len++;
7326                                rmesc++;
7327                                /* continue; - prone to quadratic behavior, smarter code: */
7328                                if (str[0] == '*') {
7329                                        /* Pattern is "*foo". If "*foo" does not match "long_string",
7330                                         * it would never match "ong_string" etc, no point in trying.
7331                                         */
7332                                        goto skip_matching;
7333                                }
7334                                goto try_to_match;
7335                        }
7336
7337                        if (subtype == VSREPLACEALL) {
7338                                while (idx < loc) {
7339                                        if (quotes && (unsigned char)*idx == CTLESC)
7340                                                idx++;
7341                                        idx++;
7342                                        rmesc++;
7343                                }
7344                        } else {
7345                                idx = loc;
7346                        }
7347
7348                        //bb_error_msg("repl:'%s'", repl);
7349                        for (loc = (char*)repl; *loc; loc++) {
7350                                char *restart_detect = stackblock();
7351                                if (quotes && *loc == '\\') {
7352                                        STPUTC(CTLESC, expdest);
7353                                        len++;
7354                                }
7355                                STPUTC(*loc, expdest);
7356                                if (stackblock() != restart_detect)
7357                                        goto restart;
7358                                len++;
7359                        }
7360
7361                        if (subtype == VSREPLACE) {
7362                                //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
7363                                while (*idx) {
7364                                        char *restart_detect = stackblock();
7365                                        STPUTC(*idx, expdest);
7366                                        if (stackblock() != restart_detect)
7367                                                goto restart;
7368                                        len++;
7369                                        idx++;
7370                                }
7371                                break;
7372                        }
7373                }
7374
7375                /* We've put the replaced text into a buffer at workloc, now
7376                 * move it to the right place and adjust the stack.
7377                 */
7378                STPUTC('\0', expdest);
7379                startp = (char *)stackblock() + startloc;
7380                memmove(startp, (char *)stackblock() + workloc, len + 1);
7381                //bb_error_msg("startp:'%s'", startp);
7382                loc = startp + len;
7383                goto out;
7384        }
7385#endif /* BASH_PATTERN_SUBST */
7386
7387        subtype -= VSTRIMRIGHT;
7388#if DEBUG
7389        if (subtype < 0 || subtype > 7)
7390                abort();
7391#endif
7392        /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
7393        zero = subtype >> 1;
7394        /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7395        scan = (subtype & 1) ^ zero ? scanleft : scanright;
7396
7397        loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7398        if (loc) {
7399                if (zero) {
7400                        memmove(startp, loc, str - loc);
7401                        loc = startp + (str - loc) - 1;
7402                }
7403                *loc = '\0';
7404        } else
7405                loc = str - 1;
7406
7407 out:
7408        amount = loc - expdest;
7409        STADJUST(amount, expdest);
7410#if BASH_PATTERN_SUBST
7411 out1:
7412#endif
7413        /* Remove any recorded regions beyond start of variable */
7414        removerecordregions(startloc);
7415
7416        return p;
7417}
7418
7419/*
7420 * Add the value of a specialized variable to the stack string.
7421 * name parameter (examples):
7422 * ash -c 'echo $1'      name:'1='
7423 * ash -c 'echo $qwe'    name:'qwe='
7424 * ash -c 'echo $$'      name:'$='
7425 * ash -c 'echo ${$}'    name:'$='
7426 * ash -c 'echo ${$##q}' name:'$=q'
7427 * ash -c 'echo ${#$}'   name:'$='
7428 * note: examples with bad shell syntax:
7429 * ash -c 'echo ${#$1}'  name:'$=1'
7430 * ash -c 'echo ${#1#}'  name:'1=#'
7431 */
7432static NOINLINE ssize_t
7433varvalue(char *name, int varflags, int flags, int quoted)
7434{
7435        const char *p;
7436        int num;
7437        int i;
7438        ssize_t len = 0;
7439        int sep;
7440        int subtype = varflags & VSTYPE;
7441        int discard = (subtype == VSPLUS || subtype == VSLENGTH) | (flags & EXP_DISCARD);
7442
7443        if (!subtype) {
7444                if (discard)
7445                        return -1;
7446
7447                raise_error_syntax("bad substitution");
7448        }
7449
7450        flags |= EXP_KEEPNUL;
7451        flags &= discard ? ~QUOTES_ESC : ~0;
7452        sep = (flags & EXP_FULL) << CHAR_BIT;
7453
7454        switch (*name) {
7455        case '$':
7456                num = rootpid;
7457                goto numvar;
7458        case '?':
7459                num = exitstatus;
7460                goto numvar;
7461        case '#':
7462                num = shellparam.nparam;
7463                goto numvar;
7464        case '!':
7465                num = backgndpid;
7466                if (num == 0)
7467                        return -1;
7468 numvar:
7469                len = cvtnum(num, flags);
7470                goto check_1char_name;
7471        case '-':
7472                expdest = makestrspace(NOPTS, expdest);
7473                for (i = NOPTS - 1; i >= 0; i--) {
7474                        if (optlist[i] && optletters(i)) {
7475                                USTPUTC(optletters(i), expdest);
7476                                len++;
7477                        }
7478                }
7479 check_1char_name:
7480#if 0
7481                /* handles cases similar to ${#$1} */
7482                if (name[2] != '\0')
7483                        raise_error_syntax("bad substitution");
7484#endif
7485                break;
7486        case '@':
7487                if (quoted && sep)
7488                        goto param;
7489                /* fall through */
7490        case '*': {
7491                char **ap;
7492                char sepc;
7493                char c;
7494
7495                /* We will set c to 0 or ~0 depending on whether
7496                 * we're doing field splitting.  We won't do field
7497                 * splitting if either we're quoted or sep is zero.
7498                 *
7499                 * Instead of testing (quoted || !sep) the following
7500                 * trick optimises away any branches by using the
7501                 * fact that EXP_QUOTED (which is the only bit that
7502                 * can be set in quoted) is the same as EXP_FULL <<
7503                 * CHAR_BIT (which is the only bit that can be set
7504                 * in sep).
7505                 */
7506#if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7507#error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7508#endif
7509                c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7510                sep &= ~quoted;
7511                sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
7512 param:
7513                sepc = sep;
7514                ap = shellparam.p;
7515                if (!ap)
7516                        return -1;
7517                while ((p = *ap++) != NULL) {
7518                        len += strtodest(p, flags);
7519
7520                        if (*ap && sep) {
7521                                len++;
7522                                memtodest(&sepc, 1, flags);
7523                        }
7524                }
7525                break;
7526        } /* case '*' */
7527        case '0':
7528        case '1':
7529        case '2':
7530        case '3':
7531        case '4':
7532        case '5':
7533        case '6':
7534        case '7':
7535        case '8':
7536        case '9':
7537                num = atoi(name); /* number(name) fails on ${N#str} etc */
7538                if (num < 0 || num > shellparam.nparam)
7539                        return -1;
7540                p = num ? shellparam.p[num - 1] : arg0;
7541                goto value;
7542        default:
7543                /* NB: name has form "VAR=..." */
7544                p = lookupvar(name);
7545 value:
7546                if (!p)
7547                        return -1;
7548
7549                len = strtodest(p, flags);
7550#if ENABLE_UNICODE_SUPPORT
7551                if (subtype == VSLENGTH && len > 0) {
7552                        reinit_unicode_for_ash();
7553                        if (unicode_status == UNICODE_ON) {
7554                                STADJUST(-len, expdest);
7555                                discard = 0;
7556                                len = unicode_strlen(p);
7557                        }
7558                }
7559#endif
7560                break;
7561        }
7562
7563        if (discard)
7564                STADJUST(-len, expdest);
7565
7566        return len;
7567}
7568
7569/*
7570 * Expand a variable, and return a pointer to the next character in the
7571 * input string.
7572 */
7573static char *
7574evalvar(char *p, int flag)
7575{
7576        char varflags;
7577        char subtype;
7578        char *var;
7579        int patloc;
7580        int startloc;
7581        ssize_t varlen;
7582        int discard;
7583        int quoted;
7584
7585        varflags = (unsigned char) *p++;
7586        subtype = varflags & VSTYPE;
7587
7588        quoted = flag & EXP_QUOTED;
7589        var = p;
7590        startloc = expdest - (char *)stackblock();
7591        p = strchr(p, '=') + 1; //TODO: use var_end(p)?
7592
7593 again:
7594        varlen = varvalue(var, varflags, flag, quoted);
7595        if (varflags & VSNUL)
7596                varlen--;
7597
7598        discard = varlen < 0 ? EXP_DISCARD : 0;
7599
7600        switch (subtype) {
7601        case VSPLUS:
7602                discard ^= EXP_DISCARD;
7603                /* fall through */
7604        case 0:
7605        case VSMINUS:
7606                p = argstr(p, flag | EXP_TILDE | EXP_WORD | (discard ^ EXP_DISCARD));
7607                goto record;
7608
7609        case VSASSIGN:
7610        case VSQUESTION:
7611                p = subevalvar(p, var, 0, startloc, varflags,
7612                        (flag & ~QUOTES_ESC) | (discard ^ EXP_DISCARD));
7613
7614                if ((flag | ~discard) & EXP_DISCARD)
7615                        goto record;
7616
7617                varflags &= ~VSNUL;
7618                subtype = VSNORMAL;
7619                goto again;
7620        }
7621
7622        if ((discard & ~flag) && uflag)
7623                varunset(p, var, 0, 0);
7624
7625        if (subtype == VSLENGTH) {
7626                p++;
7627                if (flag & EXP_DISCARD)
7628                        return p;
7629                cvtnum(varlen > 0 ? varlen : 0, flag);
7630                goto really_record;
7631        }
7632
7633        if (subtype == VSNORMAL)
7634                goto record;
7635
7636#if DEBUG
7637        switch (subtype) {
7638        case VSTRIMLEFT:
7639        case VSTRIMLEFTMAX:
7640        case VSTRIMRIGHT:
7641        case VSTRIMRIGHTMAX:
7642#if BASH_SUBSTR
7643        case VSSUBSTR:
7644#endif
7645#if BASH_PATTERN_SUBST
7646        case VSREPLACE:
7647        case VSREPLACEALL:
7648#endif
7649                break;
7650        default:
7651                abort();
7652        }
7653#endif
7654
7655        flag |= discard;
7656        if (!(flag & EXP_DISCARD)) {
7657                /*
7658                 * Terminate the string and start recording the pattern
7659                 * right after it
7660                 */
7661                STPUTC('\0', expdest);
7662        }
7663
7664        patloc = expdest - (char *)stackblock();
7665        p = subevalvar(p, NULL, patloc, startloc, varflags, flag);
7666
7667 record:
7668        if ((flag | discard) & EXP_DISCARD)
7669                return p;
7670
7671 really_record:
7672        if (quoted) {
7673                quoted = *var == '@' && shellparam.nparam;
7674                if (!quoted)
7675                        return p;
7676        }
7677        recordregion(startloc, expdest - (char *)stackblock(), quoted);
7678        return p;
7679}
7680
7681/*
7682 * Add a file name to the list.
7683 */
7684static void
7685addfname(const char *name)
7686{
7687        struct strlist *sp;
7688
7689        sp = stzalloc(sizeof(*sp));
7690        sp->text = sstrdup(name);
7691        *exparg.lastp = sp;
7692        exparg.lastp = &sp->next;
7693}
7694
7695/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7696static int
7697hasmeta(const char *p)
7698{
7699        static const char chars[] ALIGN1 = {
7700                '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7701        };
7702
7703        for (;;) {
7704                p = strpbrk(p, chars);
7705                if (!p)
7706                        break;
7707                switch ((unsigned char)*p) {
7708                case CTLQUOTEMARK:
7709                        for (;;) {
7710                                p++;
7711                                if ((unsigned char)*p == CTLQUOTEMARK)
7712                                        break;
7713                                if ((unsigned char)*p == CTLESC)
7714                                        p++;
7715                                if (*p == '\0') /* huh? */
7716                                        return 0;
7717                        }
7718                        break;
7719                case '\\':
7720                case CTLESC:
7721                        p++;
7722                        if (*p == '\0')
7723                                return 0;
7724                        break;
7725                case '[':
7726                        if (!strchr(p + 1, ']')) {
7727                                /* It's not a properly closed [] pattern,
7728                                 * but other metas may follow. Continue checking.
7729                                 * my[file* _is_ globbed by bash
7730                                 * and matches filenames like "my[file1".
7731                                 */
7732                                break;
7733                        }
7734                        /* fallthrough */
7735                default:
7736                /* case '*': */
7737                /* case '?': */
7738                        return 1;
7739                }
7740                p++;
7741        }
7742
7743        return 0;
7744}
7745
7746/* If we want to use glob() from libc... */
7747#if !ENABLE_ASH_INTERNAL_GLOB
7748
7749/* Add the result of glob() to the list */
7750static void
7751addglob(const glob_t *pglob)
7752{
7753        char **p = pglob->gl_pathv;
7754
7755        do {
7756                addfname(*p);
7757        } while (*++p);
7758}
7759static void
7760expandmeta(struct strlist *str /*, int flag*/)
7761{
7762        /* TODO - EXP_REDIR */
7763
7764        while (str) {
7765                char *p;
7766                glob_t pglob;
7767                int i;
7768
7769                if (fflag)
7770                        goto nometa;
7771
7772                if (!hasmeta(str->text))
7773                        goto nometa;
7774
7775                INT_OFF;
7776                p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7777// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7778// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7779//
7780// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7781// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7782// Which means you need to unescape the string, right? Not so fast:
7783// if there _is_ a file named "file\?" (with backslash), it is returned
7784// as "file\?" too (whichever pattern you used to find it, say, "file*").
7785// You DON'T KNOW by looking at the result whether you need to unescape it.
7786//
7787// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7788// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7789// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7790// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7791//              i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7792//              i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7793                i = glob(p, 0, NULL, &pglob);
7794                //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7795                if (p != str->text)
7796                        free(p);
7797                switch (i) {
7798                case 0:
7799#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7800                        /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7801                        if (!(pglob.gl_flags & GLOB_MAGCHAR))
7802                                goto nometa2;
7803#endif
7804                        addglob(&pglob);
7805                        globfree(&pglob);
7806                        INT_ON;
7807                        break;
7808                case GLOB_NOMATCH:
7809 //nometa2:
7810                        globfree(&pglob);
7811                        INT_ON;
7812 nometa:
7813                        *exparg.lastp = str;
7814                        rmescapes(str->text, 0, NULL);
7815                        exparg.lastp = &str->next;
7816                        break;
7817                default:        /* GLOB_NOSPACE */
7818                        globfree(&pglob);
7819                        INT_ON;
7820                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
7821                }
7822                str = str->next;
7823        }
7824}
7825
7826#else
7827/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7828
7829/*
7830 * Do metacharacter (i.e. *, ?, [...]) expansion.
7831 */
7832typedef struct exp_t {
7833        char *dir;
7834        unsigned dir_max;
7835} exp_t;
7836static void
7837expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7838{
7839#define expdir exp->dir
7840#define expdir_max exp->dir_max
7841        char *enddir = expdir + expdir_len;
7842        char *p;
7843        const char *cp;
7844        char *start;
7845        char *endname;
7846        int metaflag;
7847        struct stat statb;
7848        DIR *dirp;
7849        struct dirent *dp;
7850        int atend;
7851        int matchdot;
7852        int esc;
7853
7854        metaflag = 0;
7855        start = name;
7856        for (p = name; esc = 0, *p; p += esc + 1) {
7857                if (*p == '*' || *p == '?')
7858                        metaflag = 1;
7859                else if (*p == '[') {
7860                        char *q = p + 1;
7861                        if (*q == '!')
7862                                q++;
7863                        for (;;) {
7864                                if (*q == '\\')
7865                                        q++;
7866                                if (*q == '/' || *q == '\0')
7867                                        break;
7868                                if (*++q == ']') {
7869                                        metaflag = 1;
7870                                        break;
7871                                }
7872                        }
7873                } else {
7874                        if (*p == '\\' && p[1])
7875                                esc++;
7876                        if (p[esc] == '/') {
7877                                if (metaflag)
7878                                        break;
7879                                start = p + esc + 1;
7880                        }
7881                }
7882        }
7883        if (metaflag == 0) {    /* we've reached the end of the file name */
7884                if (!expdir_len)
7885                        return;
7886                p = name;
7887                do {
7888                        if (*p == '\\' && p[1])
7889                                p++;
7890                        *enddir++ = *p;
7891                } while (*p++);
7892                if (lstat(expdir, &statb) == 0)
7893                        addfname(expdir);
7894                return;
7895        }
7896        endname = p;
7897        if (name < start) {
7898                p = name;
7899                do {
7900                        if (*p == '\\' && p[1])
7901                                p++;
7902                        *enddir++ = *p++;
7903                } while (p < start);
7904        }
7905        *enddir = '\0';
7906        cp = expdir;
7907        expdir_len = enddir - cp;
7908        if (!expdir_len)
7909                cp = ".";
7910        dirp = opendir(cp);
7911        if (dirp == NULL)
7912                return;
7913        if (*endname == 0) {
7914                atend = 1;
7915        } else {
7916                atend = 0;
7917                *endname = '\0';
7918                endname += esc + 1;
7919        }
7920        name_len -= endname - name;
7921        matchdot = 0;
7922        p = start;
7923        if (*p == '\\')
7924                p++;
7925        if (*p == '.')
7926                matchdot++;
7927        while (!pending_int && (dp = readdir(dirp)) != NULL) {
7928                if (dp->d_name[0] == '.' && !matchdot)
7929                        continue;
7930                if (pmatch(start, dp->d_name)) {
7931                        if (atend) {
7932                                strcpy(enddir, dp->d_name);
7933                                addfname(expdir);
7934                        } else {
7935                                unsigned offset;
7936                                unsigned len;
7937
7938                                p = stpcpy(enddir, dp->d_name);
7939                                *p = '/';
7940
7941                                offset = p - expdir + 1;
7942                                len = offset + name_len + NAME_MAX;
7943                                if (len > expdir_max) {
7944                                        len += PATH_MAX;
7945                                        expdir = ckrealloc(expdir, len);
7946                                        expdir_max = len;
7947                                }
7948
7949                                expmeta(exp, endname, name_len, offset);
7950                                enddir = expdir + expdir_len;
7951                        }
7952                }
7953        }
7954        closedir(dirp);
7955        if (!atend)
7956                endname[-esc - 1] = esc ? '\\' : '/';
7957#undef expdir
7958#undef expdir_max
7959}
7960
7961static struct strlist *
7962msort(struct strlist *list, int len)
7963{
7964        struct strlist *p, *q = NULL;
7965        struct strlist **lpp;
7966        int half;
7967        int n;
7968
7969        if (len <= 1)
7970                return list;
7971        half = len >> 1;
7972        p = list;
7973        for (n = half; --n >= 0;) {
7974                q = p;
7975                p = p->next;
7976        }
7977        q->next = NULL;                 /* terminate first half of list */
7978        q = msort(list, half);          /* sort first half of list */
7979        p = msort(p, len - half);               /* sort second half */
7980        lpp = &list;
7981        for (;;) {
7982#if ENABLE_LOCALE_SUPPORT
7983                if (strcoll(p->text, q->text) < 0)
7984#else
7985                if (strcmp(p->text, q->text) < 0)
7986#endif
7987                                                {
7988                        *lpp = p;
7989                        lpp = &p->next;
7990                        p = *lpp;
7991                        if (p == NULL) {
7992                                *lpp = q;
7993                                break;
7994                        }
7995                } else {
7996                        *lpp = q;
7997                        lpp = &q->next;
7998                        q = *lpp;
7999                        if (q == NULL) {
8000                                *lpp = p;
8001                                break;
8002                        }
8003                }
8004        }
8005        return list;
8006}
8007
8008/*
8009 * Sort the results of file name expansion.  It calculates the number of
8010 * strings to sort and then calls msort (short for merge sort) to do the
8011 * work.
8012 */
8013static struct strlist *
8014expsort(struct strlist *str)
8015{
8016        int len;
8017        struct strlist *sp;
8018
8019        len = 0;
8020        for (sp = str; sp; sp = sp->next)
8021                len++;
8022        return msort(str, len);
8023}
8024
8025static void
8026expandmeta(struct strlist *str /*, int flag*/)
8027{
8028        /* TODO - EXP_REDIR */
8029
8030        while (str) {
8031                exp_t exp;
8032                struct strlist **savelastp;
8033                struct strlist *sp;
8034                char *p;
8035                unsigned len;
8036
8037                if (fflag)
8038                        goto nometa;
8039                if (!hasmeta(str->text))
8040                        goto nometa;
8041                savelastp = exparg.lastp;
8042
8043                INT_OFF;
8044                p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
8045                len = strlen(p);
8046                exp.dir_max = len + PATH_MAX;
8047                exp.dir = ckmalloc(exp.dir_max);
8048
8049                expmeta(&exp, p, len, 0);
8050                free(exp.dir);
8051                if (p != str->text)
8052                        free(p);
8053                INT_ON;
8054                if (exparg.lastp == savelastp) {
8055                        /*
8056                         * no matches
8057                         */
8058 nometa:
8059                        *exparg.lastp = str;
8060                        rmescapes(str->text, 0, NULL);
8061                        exparg.lastp = &str->next;
8062                } else {
8063                        *exparg.lastp = NULL;
8064                        *savelastp = sp = expsort(*savelastp);
8065                        while (sp->next != NULL)
8066                                sp = sp->next;
8067                        exparg.lastp = &sp->next;
8068                }
8069                str = str->next;
8070        }
8071}
8072#endif /* ENABLE_ASH_INTERNAL_GLOB */
8073
8074/*
8075 * Perform variable substitution and command substitution on an argument,
8076 * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
8077 * perform splitting and file name expansion.  When arglist is NULL, perform
8078 * here document expansion.
8079 */
8080static void
8081expandarg(union node *arg, struct arglist *arglist, int flag)
8082{
8083        struct strlist *sp;
8084        char *p;
8085
8086        argbackq = arg->narg.backquote;
8087        STARTSTACKSTR(expdest);
8088        TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
8089        argstr(arg->narg.text, flag);
8090        if (arglist == NULL) {
8091                /* here document expanded */
8092                goto out;
8093        }
8094        p = grabstackstr(expdest);
8095        TRACE(("expandarg: p:'%s'\n", p));
8096        exparg.lastp = &exparg.list;
8097        /*
8098         * TODO - EXP_REDIR
8099         */
8100        if (flag & EXP_FULL) {
8101                ifsbreakup(p, &exparg);
8102                *exparg.lastp = NULL;
8103                exparg.lastp = &exparg.list;
8104                expandmeta(exparg.list /*, flag*/);
8105        } else {
8106                sp = stzalloc(sizeof(*sp));
8107                sp->text = p;
8108                *exparg.lastp = sp;
8109                exparg.lastp = &sp->next;
8110        }
8111        *exparg.lastp = NULL;
8112        if (exparg.list) {
8113                *arglist->lastp = exparg.list;
8114                arglist->lastp = exparg.lastp;
8115        }
8116
8117 out:
8118        ifsfree();
8119}
8120
8121/*
8122 * Expand shell variables and backquotes inside a here document.
8123 */
8124static void
8125expandhere(union node *arg)
8126{
8127        expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
8128}
8129
8130/*
8131 * Returns true if the pattern matches the string.
8132 */
8133static int
8134patmatch(char *pattern, const char *string)
8135{
8136        char *p = preglob(pattern, 0);
8137        int r = pmatch(p, string);
8138        //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
8139        return r;
8140}
8141
8142/*
8143 * See if a pattern matches in a case statement.
8144 */
8145static int
8146casematch(union node *pattern, char *val)
8147{
8148        struct stackmark smark;
8149        int result;
8150
8151        setstackmark(&smark);
8152        argbackq = pattern->narg.backquote;
8153        STARTSTACKSTR(expdest);
8154        argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
8155        ifsfree();
8156        result = patmatch(stackblock(), val);
8157        popstackmark(&smark);
8158        return result;
8159}
8160
8161
8162/* ============ find_command */
8163
8164struct builtincmd {
8165        const char *name;
8166        int (*builtin)(int, char **) FAST_FUNC;
8167        /* unsigned flags; */
8168};
8169#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
8170/* "regular" builtins always take precedence over commands,
8171 * regardless of PATH=....%builtin... position */
8172#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
8173#define IS_BUILTIN_ASSIGN(b)  ((b)->name[0] & 4)
8174
8175struct cmdentry {
8176        smallint cmdtype;       /* CMDxxx */
8177        union param {
8178                int index;
8179                /* index >= 0 for commands without path (slashes) */
8180                /* (TODO: what exactly does the value mean? PATH position?) */
8181                /* index == -1 for commands with slashes */
8182                /* index == (-2 - applet_no) for NOFORK applets */
8183                const struct builtincmd *cmd;
8184                struct funcnode *func;
8185        } u;
8186};
8187/* values of cmdtype */
8188#define CMDUNKNOWN      -1      /* no entry in table for command */
8189#define CMDNORMAL       0       /* command is an executable program */
8190#define CMDFUNCTION     1       /* command is a shell function */
8191#define CMDBUILTIN      2       /* command is a shell builtin */
8192
8193/* action to find_command() */
8194#define DO_ERR          0x01    /* prints errors */
8195#define DO_ABS          0x02    /* checks absolute paths */
8196#define DO_NOFUNC       0x04    /* don't return shell functions, for command */
8197#define DO_ALTPATH      0x08    /* using alternate path */
8198#define DO_REGBLTIN     0x10    /* regular built-ins and functions only */
8199
8200static void find_command(char *, struct cmdentry *, int, const char *);
8201
8202
8203/* ============ Hashing commands */
8204
8205/*
8206 * When commands are first encountered, they are entered in a hash table.
8207 * This ensures that a full path search will not have to be done for them
8208 * on each invocation.
8209 *
8210 * We should investigate converting to a linear search, even though that
8211 * would make the command name "hash" a misnomer.
8212 */
8213
8214struct tblentry {
8215        struct tblentry *next;  /* next entry in hash chain */
8216        union param param;      /* definition of builtin function */
8217        smallint cmdtype;       /* CMDxxx */
8218        char rehash;            /* if set, cd done since entry created */
8219        char cmdname[1];        /* name of command */
8220};
8221
8222static struct tblentry **cmdtable;
8223#define INIT_G_cmdtable() do { \
8224        cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
8225} while (0)
8226
8227static int builtinloc = -1;     /* index in path of %builtin, or -1 */
8228
8229
8230static void
8231tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
8232{
8233#if ENABLE_FEATURE_SH_STANDALONE
8234        if (applet_no >= 0) {
8235                if (APPLET_IS_NOEXEC(applet_no)) {
8236                        clearenv();
8237                        while (*envp)
8238                                putenv(*envp++);
8239                        popredir(/*drop:*/ 1);
8240                        run_noexec_applet_and_exit(applet_no, cmd, argv);
8241                }
8242                /* re-exec ourselves with the new arguments */
8243                execve(bb_busybox_exec_path, argv, envp);
8244                /* If they called chroot or otherwise made the binary no longer
8245                 * executable, fall through */
8246        }
8247#endif
8248
8249 repeat:
8250#ifdef SYSV
8251        do {
8252                execve(cmd, argv, envp);
8253        } while (errno == EINTR);
8254#else
8255        execve(cmd, argv, envp);
8256#endif
8257
8258        if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
8259                /* Run "cmd" as a shell script:
8260                 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8261                 * "If the execve() function fails with ENOEXEC, the shell
8262                 * shall execute a command equivalent to having a shell invoked
8263                 * with the command name as its first operand,
8264                 * with any remaining arguments passed to the new shell"
8265                 *
8266                 * That is, do not use $SHELL, user's shell, or /bin/sh;
8267                 * just call ourselves.
8268                 *
8269                 * Note that bash reads ~80 chars of the file, and if it sees
8270                 * a zero byte before it sees newline, it doesn't try to
8271                 * interpret it, but fails with "cannot execute binary file"
8272                 * message and exit code 126. For one, this prevents attempts
8273                 * to interpret foreign ELF binaries as shell scripts.
8274                 */
8275                argv[0] = (char*) cmd;
8276                cmd = bb_busybox_exec_path;
8277                /* NB: this is only possible because all callers of shellexec()
8278                 * ensure that the argv[-1] slot exists!
8279                 */
8280                argv--;
8281                argv[0] = (char*) "ash";
8282                goto repeat;
8283        }
8284}
8285
8286/*
8287 * Exec a program.  Never returns.  If you change this routine, you may
8288 * have to change the find_command routine as well.
8289 * argv[-1] must exist and be writable! See tryexec() for why.
8290 */
8291static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8292static void shellexec(char *prog, char **argv, const char *path, int idx)
8293{
8294        char *cmdname;
8295        int e;
8296        char **envp;
8297        int exerrno;
8298        int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
8299
8300        envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
8301        if (strchr(prog, '/') != NULL
8302#if ENABLE_FEATURE_SH_STANDALONE
8303         || (applet_no = find_applet_by_name(prog)) >= 0
8304#endif
8305        ) {
8306                tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
8307                if (applet_no >= 0) {
8308                        /* We tried execing ourself, but it didn't work.
8309                         * Maybe /proc/self/exe doesn't exist?
8310                         * Try $PATH search.
8311                         */
8312                        goto try_PATH;
8313                }
8314                e = errno;
8315        } else {
8316 try_PATH:
8317                e = ENOENT;
8318                while (padvance(&path, argv[0]) >= 0) {
8319                        cmdname = stackblock();
8320                        if (--idx < 0 && pathopt == NULL) {
8321                                tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
8322                                if (errno != ENOENT && errno != ENOTDIR)
8323                                        e = errno;
8324                        }
8325                }
8326        }
8327
8328        /* Map to POSIX errors */
8329        switch (e) {
8330        default:
8331                exerrno = 126;
8332                break;
8333        case ELOOP:
8334        case ENAMETOOLONG:
8335        case ENOENT:
8336        case ENOTDIR:
8337                exerrno = 127;
8338                break;
8339        }
8340        exitstatus = exerrno;
8341        TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
8342                prog, e, suppress_int));
8343        ash_msg_and_raise(EXEND, "%s: %s", prog, errmsg(e, "not found"));
8344        /* NOTREACHED */
8345}
8346
8347static void
8348printentry(struct tblentry *cmdp)
8349{
8350        int idx;
8351        const char *path;
8352        char *name;
8353
8354        idx = cmdp->param.index;
8355        path = pathval();
8356        do {
8357                padvance(&path, cmdp->cmdname);
8358        } while (--idx >= 0);
8359        name = stackblock();
8360        out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8361}
8362
8363/*
8364 * Clear out command entries.
8365 */
8366static void
8367clearcmdentry(void)
8368{
8369        struct tblentry **tblp;
8370        struct tblentry **pp;
8371        struct tblentry *cmdp;
8372
8373        INT_OFF;
8374        for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8375                pp = tblp;
8376                while ((cmdp = *pp) != NULL) {
8377                        if (cmdp->cmdtype == CMDNORMAL
8378                         || (cmdp->cmdtype == CMDBUILTIN
8379                            && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8380                            && builtinloc > 0
8381                            )
8382                        ) {
8383                                *pp = cmdp->next;
8384                                free(cmdp);
8385                        } else {
8386                                pp = &cmdp->next;
8387                        }
8388                }
8389        }
8390        INT_ON;
8391}
8392
8393/*
8394 * Locate a command in the command hash table.  If "add" is nonzero,
8395 * add the command to the table if it is not already present.  The
8396 * variable "lastcmdentry" is set to point to the address of the link
8397 * pointing to the entry, so that delete_cmd_entry can delete the
8398 * entry.
8399 *
8400 * Interrupts must be off if called with add != 0.
8401 */
8402static struct tblentry **lastcmdentry;
8403
8404static struct tblentry *
8405cmdlookup(const char *name, int add)
8406{
8407        unsigned int hashval;
8408        const char *p;
8409        struct tblentry *cmdp;
8410        struct tblentry **pp;
8411
8412        p = name;
8413        hashval = (unsigned char)*p << 4;
8414        while (*p)
8415                hashval += (unsigned char)*p++;
8416        hashval &= 0x7FFF;
8417        pp = &cmdtable[hashval % CMDTABLESIZE];
8418        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8419                if (strcmp(cmdp->cmdname, name) == 0)
8420                        break;
8421                pp = &cmdp->next;
8422        }
8423        if (add && cmdp == NULL) {
8424                cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8425                                + strlen(name)
8426                                /* + 1 - already done because
8427                                 * tblentry::cmdname is char[1] */);
8428                /*cmdp->next = NULL; - ckzalloc did it */
8429                cmdp->cmdtype = CMDUNKNOWN;
8430                strcpy(cmdp->cmdname, name);
8431        }
8432        lastcmdentry = pp;
8433        return cmdp;
8434}
8435
8436/*
8437 * Delete the command entry returned on the last lookup.
8438 */
8439static void
8440delete_cmd_entry(void)
8441{
8442        struct tblentry *cmdp;
8443
8444        INT_OFF;
8445        cmdp = *lastcmdentry;
8446        *lastcmdentry = cmdp->next;
8447        if (cmdp->cmdtype == CMDFUNCTION)
8448                freefunc(cmdp->param.func);
8449        free(cmdp);
8450        INT_ON;
8451}
8452
8453/*
8454 * Add a new command entry, replacing any existing command entry for
8455 * the same name - except special builtins.
8456 */
8457static void
8458addcmdentry(char *name, struct cmdentry *entry)
8459{
8460        struct tblentry *cmdp;
8461
8462        cmdp = cmdlookup(name, 1);
8463        if (cmdp->cmdtype == CMDFUNCTION) {
8464                freefunc(cmdp->param.func);
8465        }
8466        cmdp->cmdtype = entry->cmdtype;
8467        cmdp->param = entry->u;
8468        cmdp->rehash = 0;
8469}
8470
8471static int FAST_FUNC
8472hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8473{
8474        struct tblentry **pp;
8475        struct tblentry *cmdp;
8476        int c;
8477        struct cmdentry entry;
8478        char *name;
8479
8480        if (nextopt("r") != '\0') {
8481                clearcmdentry();
8482                return 0;
8483        }
8484
8485        if (*argptr == NULL) {
8486                for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8487                        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8488                                if (cmdp->cmdtype == CMDNORMAL)
8489                                        printentry(cmdp);
8490                        }
8491                }
8492                return 0;
8493        }
8494
8495        c = 0;
8496        while ((name = *argptr) != NULL) {
8497                cmdp = cmdlookup(name, 0);
8498                if (cmdp != NULL
8499                 && (cmdp->cmdtype == CMDNORMAL
8500                    || (cmdp->cmdtype == CMDBUILTIN
8501                        && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8502                        && builtinloc > 0
8503                        )
8504                    )
8505                ) {
8506                        delete_cmd_entry();
8507                }
8508                find_command(name, &entry, DO_ERR, pathval());
8509                if (entry.cmdtype == CMDUNKNOWN)
8510                        c = 1;
8511                argptr++;
8512        }
8513        return c;
8514}
8515
8516/*
8517 * Called when a cd is done.  Marks all commands so the next time they
8518 * are executed they will be rehashed.
8519 */
8520static void
8521hashcd(void)
8522{
8523        struct tblentry **pp;
8524        struct tblentry *cmdp;
8525
8526        for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8527                for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8528                        if (cmdp->cmdtype == CMDNORMAL
8529                         || (cmdp->cmdtype == CMDBUILTIN
8530                             && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8531                             && builtinloc > 0)
8532                        ) {
8533                                cmdp->rehash = 1;
8534                        }
8535                }
8536        }
8537}
8538
8539/*
8540 * Fix command hash table when PATH changed.
8541 * Called before PATH is changed.  The argument is the new value of PATH;
8542 * pathval() still returns the old value at this point.
8543 * Called with interrupts off.
8544 */
8545static void FAST_FUNC
8546changepath(const char *newval)
8547{
8548        const char *new;
8549        int idx;
8550        int bltin;
8551
8552        new = newval;
8553        idx = 0;
8554        bltin = -1;
8555        for (;;) {
8556                if (*new == '%' && prefix(new + 1, "builtin")) {
8557                        bltin = idx;
8558                        break;
8559                }
8560                new = strchr(new, ':');
8561                if (!new)
8562                        break;
8563                idx++;
8564                new++;
8565        }
8566        builtinloc = bltin;
8567        clearcmdentry();
8568}
8569enum {
8570        TEOF,
8571        TNL,
8572        TREDIR,
8573        TWORD,
8574        TSEMI,
8575        TBACKGND,
8576        TAND,
8577        TOR,
8578        TPIPE,
8579        TLP,
8580        TRP,
8581        TENDCASE,
8582        TENDBQUOTE,
8583        TNOT,
8584        TCASE,
8585        TDO,
8586        TDONE,
8587        TELIF,
8588        TELSE,
8589        TESAC,
8590        TFI,
8591        TFOR,
8592#if BASH_FUNCTION
8593        TFUNCTION,
8594#endif
8595        TIF,
8596        TIN,
8597        TTHEN,
8598        TUNTIL,
8599        TWHILE,
8600        TBEGIN,
8601        TEND
8602};
8603typedef smallint token_id_t;
8604
8605/* Nth bit indicates if token marks the end of a list */
8606enum {
8607        tokendlist = 0
8608        /*  0 */ | (1u << TEOF)
8609        /*  1 */ | (0u << TNL)
8610        /*  2 */ | (0u << TREDIR)
8611        /*  3 */ | (0u << TWORD)
8612        /*  4 */ | (0u << TSEMI)
8613        /*  5 */ | (0u << TBACKGND)
8614        /*  6 */ | (0u << TAND)
8615        /*  7 */ | (0u << TOR)
8616        /*  8 */ | (0u << TPIPE)
8617        /*  9 */ | (0u << TLP)
8618        /* 10 */ | (1u << TRP)
8619        /* 11 */ | (1u << TENDCASE)
8620        /* 12 */ | (1u << TENDBQUOTE)
8621        /* 13 */ | (0u << TNOT)
8622        /* 14 */ | (0u << TCASE)
8623        /* 15 */ | (1u << TDO)
8624        /* 16 */ | (1u << TDONE)
8625        /* 17 */ | (1u << TELIF)
8626        /* 18 */ | (1u << TELSE)
8627        /* 19 */ | (1u << TESAC)
8628        /* 20 */ | (1u << TFI)
8629        /* 21 */ | (0u << TFOR)
8630#if BASH_FUNCTION
8631        /* 22 */ | (0u << TFUNCTION)
8632#endif
8633        /* 23 */ | (0u << TIF)
8634        /* 24 */ | (0u << TIN)
8635        /* 25 */ | (1u << TTHEN)
8636        /* 26 */ | (0u << TUNTIL)
8637        /* 27 */ | (0u << TWHILE)
8638        /* 28 */ | (0u << TBEGIN)
8639        /* 29 */ | (1u << TEND)
8640        , /* thus far 29 bits used */
8641};
8642
8643static const char *const tokname_array[] ALIGN_PTR = {
8644        "end of file",
8645        "newline",
8646        "redirection",
8647        "word",
8648        ";",
8649        "&",
8650        "&&",
8651        "||",
8652        "|",
8653        "(",
8654        ")",
8655        ";;",
8656        "`",
8657#define KWDOFFSET 13
8658        /* the following are keywords */
8659        "!",
8660        "case",
8661        "do",
8662        "done",
8663        "elif",
8664        "else",
8665        "esac",
8666        "fi",
8667        "for",
8668#if BASH_FUNCTION
8669        "function",
8670#endif
8671        "if",
8672        "in",
8673        "then",
8674        "until",
8675        "while",
8676        "{",
8677        "}",
8678};
8679
8680/* Wrapper around strcmp for qsort/bsearch/... */
8681static int
8682pstrcmp(const void *a, const void *b)
8683{
8684        return strcmp((char*)a, *(char**)b);
8685}
8686
8687static const char *const *
8688findkwd(const char *s)
8689{
8690        return bsearch(s, tokname_array + KWDOFFSET,
8691                        ARRAY_SIZE(tokname_array) - KWDOFFSET,
8692                        sizeof(tokname_array[0]), pstrcmp);
8693}
8694
8695/*
8696 * Locate and print what a word is...
8697 */
8698static int
8699describe_command(char *command, const char *path, int describe_command_verbose)
8700{
8701        struct cmdentry entry;
8702#if ENABLE_ASH_ALIAS
8703        const struct alias *ap;
8704#endif
8705
8706        path = path ? path : pathval();
8707
8708        if (describe_command_verbose) {
8709                out1str(command);
8710        }
8711
8712        /* First look at the keywords */
8713        if (findkwd(command)) {
8714                out1str(describe_command_verbose ? " is a shell keyword" : command);
8715                goto out;
8716        }
8717
8718#if ENABLE_ASH_ALIAS
8719        /* Then look at the aliases */
8720        ap = lookupalias(command, 0);
8721        if (ap != NULL) {
8722                if (!describe_command_verbose) {
8723                        out1str("alias ");
8724                        printalias(ap);
8725                        return 0;
8726                }
8727                out1fmt(" is an alias for %s", ap->val);
8728                goto out;
8729        }
8730#endif
8731        /* Brute force */
8732        find_command(command, &entry, DO_ABS, path);
8733
8734        switch (entry.cmdtype) {
8735        case CMDNORMAL: {
8736                int j = entry.u.index;
8737                char *p;
8738                if (j < 0) {
8739                        p = command;
8740                } else {
8741                        do {
8742                                padvance(&path, command);
8743                        } while (--j >= 0);
8744                        p = stackblock();
8745                }
8746                if (describe_command_verbose) {
8747                        out1fmt(" is %s", p);
8748                } else {
8749                        out1str(p);
8750                }
8751                break;
8752        }
8753
8754        case CMDFUNCTION:
8755                if (describe_command_verbose) {
8756                        /*out1str(" is a shell function");*/
8757                        out1str(" is a function"); /* bash says this */
8758                } else {
8759                        out1str(command);
8760                }
8761                break;
8762
8763        case CMDBUILTIN:
8764                if (describe_command_verbose) {
8765                        out1fmt(" is a %sshell builtin",
8766                                IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8767                                        "special " : nullstr
8768                        );
8769                } else {
8770                        out1str(command);
8771                }
8772                break;
8773
8774        default:
8775                if (describe_command_verbose) {
8776                        out1str(": not found\n");
8777                }
8778                return 127;
8779        }
8780 out:
8781        out1str("\n");
8782        return 0;
8783}
8784
8785static int FAST_FUNC
8786typecmd(int argc UNUSED_PARAM, char **argv)
8787{
8788        int i = 1;
8789        int err = 0;
8790        int verbose = 1;
8791
8792        /* type -p ... ? (we don't bother checking for 'p') */
8793        if (argv[1] && argv[1][0] == '-') {
8794                i++;
8795                verbose = 0;
8796        }
8797        while (argv[i]) {
8798                err |= describe_command(argv[i++], NULL, verbose);
8799        }
8800        return err;
8801}
8802
8803static struct strlist *
8804fill_arglist(struct arglist *arglist, union node **argpp)
8805{
8806        struct strlist **lastp = arglist->lastp;
8807        union node *argp;
8808
8809        while ((argp = *argpp) != NULL) {
8810                expandarg(argp, arglist, EXP_FULL | EXP_TILDE);
8811                *argpp = argp->narg.next;
8812                if (*lastp)
8813                        break;
8814        }
8815
8816        return *lastp;
8817}
8818
8819#if ENABLE_ASH_CMDCMD
8820/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8821static int
8822parse_command_args(struct arglist *arglist, union node **argpp, const char **path)
8823{
8824        struct strlist *sp = arglist->list;
8825        char *cp, c;
8826
8827        for (;;) {
8828                sp = sp->next ? sp->next : fill_arglist(arglist, argpp);
8829                if (!sp)
8830                        return 0;
8831                cp = sp->text;
8832                if (*cp++ != '-')
8833                        break;
8834                c = *cp++;
8835                if (!c)
8836                        break;
8837                if (c == '-' && !*cp) {
8838                        if (!sp->next && !fill_arglist(arglist, argpp))
8839                                return 0;
8840                        sp = sp->next;
8841                        break;
8842                }
8843                do {
8844                        switch (c) {
8845                        case 'p':
8846                                *path = bb_default_path;
8847                                break;
8848                        default:
8849                                /* run 'typecmd' for other options */
8850                                return 0;
8851                        }
8852                        c = *cp++;
8853                } while (c);
8854        }
8855
8856        arglist->list = sp;
8857        return DO_NOFUNC;
8858}
8859
8860static int FAST_FUNC
8861commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8862{
8863        char *cmd;
8864        int c;
8865        enum {
8866                VERIFY_BRIEF = 1,
8867                VERIFY_VERBOSE = 2,
8868        } verify = 0;
8869        const char *path = NULL;
8870
8871        /* "command [-p] PROG ARGS" (that is, without -V or -v)
8872         * never reaches this function.
8873         */
8874
8875        while ((c = nextopt("pvV")) != '\0')
8876                if (c == 'V')
8877                        verify |= VERIFY_VERBOSE;
8878                else if (c == 'v')
8879                        /*verify |= VERIFY_BRIEF*/;
8880#if DEBUG
8881                else if (c != 'p')
8882                        abort();
8883#endif
8884                else
8885                        path = bb_default_path;
8886
8887        /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8888        cmd = *argptr;
8889        if (/*verify && */ cmd)
8890                return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8891
8892        return 0;
8893}
8894#endif
8895
8896
8897/*static int funcblocksize;     // size of structures in function */
8898/*static int funcstringsize;    // size of strings in node */
8899static void *funcblock;         /* block to allocate function from */
8900static char *funcstring_end;    /* end of block to allocate strings from */
8901
8902static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8903        [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
8904        [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
8905        [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
8906        [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8907        [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8908        [NAND     ] = SHELL_ALIGN(sizeof(struct nbinary)),
8909        [NOR      ] = SHELL_ALIGN(sizeof(struct nbinary)),
8910        [NSEMI    ] = SHELL_ALIGN(sizeof(struct nbinary)),
8911        [NIF      ] = SHELL_ALIGN(sizeof(struct nif)),
8912        [NWHILE   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8913        [NUNTIL   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8914        [NFOR     ] = SHELL_ALIGN(sizeof(struct nfor)),
8915        [NCASE    ] = SHELL_ALIGN(sizeof(struct ncase)),
8916        [NCLIST   ] = SHELL_ALIGN(sizeof(struct nclist)),
8917        [NDEFUN   ] = SHELL_ALIGN(sizeof(struct narg)),
8918        [NARG     ] = SHELL_ALIGN(sizeof(struct narg)),
8919        [NTO      ] = SHELL_ALIGN(sizeof(struct nfile)),
8920#if BASH_REDIR_OUTPUT
8921        [NTO2     ] = SHELL_ALIGN(sizeof(struct nfile)),
8922#endif
8923        [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8924        [NFROM    ] = SHELL_ALIGN(sizeof(struct nfile)),
8925        [NFROMTO  ] = SHELL_ALIGN(sizeof(struct nfile)),
8926        [NAPPEND  ] = SHELL_ALIGN(sizeof(struct nfile)),
8927        [NTOFD    ] = SHELL_ALIGN(sizeof(struct ndup)),
8928        [NFROMFD  ] = SHELL_ALIGN(sizeof(struct ndup)),
8929        [NHERE    ] = SHELL_ALIGN(sizeof(struct nhere)),
8930        [NXHERE   ] = SHELL_ALIGN(sizeof(struct nhere)),
8931        [NNOT     ] = SHELL_ALIGN(sizeof(struct nnot)),
8932};
8933
8934static int calcsize(int funcblocksize, union node *n);
8935
8936static int
8937sizenodelist(int funcblocksize, struct nodelist *lp)
8938{
8939        while (lp) {
8940                funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8941                funcblocksize = calcsize(funcblocksize, lp->n);
8942                lp = lp->next;
8943        }
8944        return funcblocksize;
8945}
8946
8947static int
8948calcsize(int funcblocksize, union node *n)
8949{
8950        if (n == NULL)
8951                return funcblocksize;
8952        funcblocksize += nodesize[n->type];
8953        switch (n->type) {
8954        case NCMD:
8955                funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8956                funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8957                funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8958                break;
8959        case NPIPE:
8960                funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8961                break;
8962        case NREDIR:
8963        case NBACKGND:
8964        case NSUBSHELL:
8965                funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8966                funcblocksize = calcsize(funcblocksize, n->nredir.n);
8967                break;
8968        case NAND:
8969        case NOR:
8970        case NSEMI:
8971        case NWHILE:
8972        case NUNTIL:
8973                funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8974                funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
8975                break;
8976        case NIF:
8977                funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8978                funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8979                funcblocksize = calcsize(funcblocksize, n->nif.test);
8980                break;
8981        case NFOR:
8982                funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
8983                funcblocksize = calcsize(funcblocksize, n->nfor.body);
8984                funcblocksize = calcsize(funcblocksize, n->nfor.args);
8985                break;
8986        case NCASE:
8987                funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8988                funcblocksize = calcsize(funcblocksize, n->ncase.expr);
8989                break;
8990        case NCLIST:
8991                funcblocksize = calcsize(funcblocksize, n->nclist.body);
8992                funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8993                funcblocksize = calcsize(funcblocksize, n->nclist.next);
8994                break;
8995        case NDEFUN:
8996                funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8997                funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8998                break;
8999        case NARG:
9000                funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
9001                funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
9002                funcblocksize = calcsize(funcblocksize, n->narg.next);
9003                break;
9004        case NTO:
9005#if BASH_REDIR_OUTPUT
9006        case NTO2:
9007#endif
9008        case NCLOBBER:
9009        case NFROM:
9010        case NFROMTO:
9011        case NAPPEND:
9012                funcblocksize = calcsize(funcblocksize, n->nfile.fname);
9013                funcblocksize = calcsize(funcblocksize, n->nfile.next);
9014                break;
9015        case NTOFD:
9016        case NFROMFD:
9017                funcblocksize = calcsize(funcblocksize, n->ndup.vname);
9018                funcblocksize = calcsize(funcblocksize, n->ndup.next);
9019        break;
9020        case NHERE:
9021        case NXHERE:
9022                funcblocksize = calcsize(funcblocksize, n->nhere.doc);
9023                funcblocksize = calcsize(funcblocksize, n->nhere.next);
9024                break;
9025        case NNOT:
9026                funcblocksize = calcsize(funcblocksize, n->nnot.com);
9027                break;
9028        };
9029        return funcblocksize;
9030}
9031
9032static char *
9033nodeckstrdup(char *s)
9034{
9035        funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
9036        return strcpy(funcstring_end, s);
9037}
9038
9039static union node *copynode(union node *);
9040
9041static struct nodelist *
9042copynodelist(struct nodelist *lp)
9043{
9044        struct nodelist *start;
9045        struct nodelist **lpp;
9046
9047        lpp = &start;
9048        while (lp) {
9049                *lpp = funcblock;
9050                funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
9051                (*lpp)->n = copynode(lp->n);
9052                lp = lp->next;
9053                lpp = &(*lpp)->next;
9054        }
9055        *lpp = NULL;
9056        return start;
9057}
9058
9059static union node *
9060copynode(union node *n)
9061{
9062        union node *new;
9063
9064        if (n == NULL)
9065                return NULL;
9066        new = funcblock;
9067        funcblock = (char *) funcblock + nodesize[n->type];
9068
9069        switch (n->type) {
9070        case NCMD:
9071                new->ncmd.redirect = copynode(n->ncmd.redirect);
9072                new->ncmd.args = copynode(n->ncmd.args);
9073                new->ncmd.assign = copynode(n->ncmd.assign);
9074                new->ncmd.linno = n->ncmd.linno;
9075                break;
9076        case NPIPE:
9077                new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
9078                new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
9079                break;
9080        case NREDIR:
9081        case NBACKGND:
9082        case NSUBSHELL:
9083                new->nredir.redirect = copynode(n->nredir.redirect);
9084                new->nredir.n = copynode(n->nredir.n);
9085                new->nredir.linno = n->nredir.linno;
9086                break;
9087        case NAND:
9088        case NOR:
9089        case NSEMI:
9090        case NWHILE:
9091        case NUNTIL:
9092                new->nbinary.ch2 = copynode(n->nbinary.ch2);
9093                new->nbinary.ch1 = copynode(n->nbinary.ch1);
9094                break;
9095        case NIF:
9096                new->nif.elsepart = copynode(n->nif.elsepart);
9097                new->nif.ifpart = copynode(n->nif.ifpart);
9098                new->nif.test = copynode(n->nif.test);
9099                break;
9100        case NFOR:
9101                new->nfor.var = nodeckstrdup(n->nfor.var);
9102                new->nfor.body = copynode(n->nfor.body);
9103                new->nfor.args = copynode(n->nfor.args);
9104                new->nfor.linno = n->nfor.linno;
9105                break;
9106        case NCASE:
9107                new->ncase.cases = copynode(n->ncase.cases);
9108                new->ncase.expr = copynode(n->ncase.expr);
9109                new->ncase.linno = n->ncase.linno;
9110                break;
9111        case NCLIST:
9112                new->nclist.body = copynode(n->nclist.body);
9113                new->nclist.pattern = copynode(n->nclist.pattern);
9114                new->nclist.next = copynode(n->nclist.next);
9115                break;
9116        case NDEFUN:
9117                new->ndefun.body = copynode(n->ndefun.body);
9118                new->ndefun.text = nodeckstrdup(n->ndefun.text);
9119                new->ndefun.linno = n->ndefun.linno;
9120                break;
9121        case NARG:
9122                new->narg.backquote = copynodelist(n->narg.backquote);
9123                new->narg.text = nodeckstrdup(n->narg.text);
9124                new->narg.next = copynode(n->narg.next);
9125                break;
9126        case NTO:
9127#if BASH_REDIR_OUTPUT
9128        case NTO2:
9129#endif
9130        case NCLOBBER:
9131        case NFROM:
9132        case NFROMTO:
9133        case NAPPEND:
9134                new->nfile.fname = copynode(n->nfile.fname);
9135                new->nfile.fd = n->nfile.fd;
9136                new->nfile.next = copynode(n->nfile.next);
9137                break;
9138        case NTOFD:
9139        case NFROMFD:
9140                new->ndup.vname = copynode(n->ndup.vname);
9141                new->ndup.dupfd = n->ndup.dupfd;
9142                new->ndup.fd = n->ndup.fd;
9143                new->ndup.next = copynode(n->ndup.next);
9144                break;
9145        case NHERE:
9146        case NXHERE:
9147                new->nhere.doc = copynode(n->nhere.doc);
9148                new->nhere.fd = n->nhere.fd;
9149                new->nhere.next = copynode(n->nhere.next);
9150                break;
9151        case NNOT:
9152                new->nnot.com = copynode(n->nnot.com);
9153                break;
9154        };
9155        new->type = n->type;
9156        return new;
9157}
9158
9159/*
9160 * Make a copy of a parse tree.
9161 */
9162static struct funcnode *
9163copyfunc(union node *n)
9164{
9165        struct funcnode *f;
9166        size_t blocksize;
9167
9168        /*funcstringsize = 0;*/
9169        blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
9170        f = ckzalloc(blocksize /* + funcstringsize */);
9171        funcblock = (char *) f + offsetof(struct funcnode, n);
9172        funcstring_end = (char *) f + blocksize;
9173        copynode(n);
9174        /* f->count = 0; - ckzalloc did it */
9175        return f;
9176}
9177
9178/*
9179 * Define a shell function.
9180 */
9181static void
9182defun(union node *func)
9183{
9184        struct cmdentry entry;
9185
9186        INT_OFF;
9187        entry.cmdtype = CMDFUNCTION;
9188        entry.u.func = copyfunc(func);
9189        addcmdentry(func->ndefun.text, &entry);
9190        INT_ON;
9191}
9192
9193/* Reasons for skipping commands (see comment on breakcmd routine) */
9194#define SKIPBREAK      (1 << 0)
9195#define SKIPCONT       (1 << 1)
9196#define SKIPFUNC       (1 << 2)
9197#define SKIPFUNCDEF    (1 << 3)
9198static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
9199static int skipcount;           /* number of levels to skip */
9200static int loopnest;            /* current loop nesting level */
9201static int funcline;            /* starting line number of current function, or 0 if not in a function */
9202
9203/* Forward decl way out to parsing code - dotrap needs it */
9204static int evalstring(char *s, int flags);
9205
9206/* Called to execute a trap.
9207 * Single callsite - at the end of evaltree().
9208 * If we return non-zero, evaltree raises EXEXIT exception.
9209 *
9210 * Perhaps we should avoid entering new trap handlers
9211 * while we are executing a trap handler. [is it a TODO?]
9212 */
9213static void
9214dotrap(void)
9215{
9216        uint8_t *g;
9217        int sig;
9218        int status, last_status;
9219
9220        if (!pending_sig)
9221                return;
9222
9223        status = savestatus;
9224        last_status = status;
9225        if (status < 0) {
9226                status = exitstatus;
9227                savestatus = status;
9228        }
9229        pending_sig = 0;
9230        barrier();
9231
9232        TRACE(("dotrap entered\n"));
9233        for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
9234                char *p;
9235
9236                if (!*g)
9237                        continue;
9238
9239                if (evalskip) {
9240                        pending_sig = sig;
9241                        break;
9242                }
9243
9244                p = trap[sig];
9245                /* non-trapped SIGINT is handled separately by raise_interrupt,
9246                 * don't upset it by resetting gotsig[SIGINT-1] */
9247                if (sig == SIGINT && !p)
9248                        continue;
9249
9250                TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
9251                *g = 0;
9252                if (!p)
9253                        continue;
9254                trap_depth++;
9255                evalstring(p, 0);
9256                trap_depth--;
9257                if (evalskip != SKIPFUNC)
9258                        exitstatus = status;
9259        }
9260
9261        savestatus = last_status;
9262        TRACE(("dotrap returns\n"));
9263}
9264
9265/* forward declarations - evaluation is fairly recursive business... */
9266static int evalloop(union node *, int);
9267static int evalfor(union node *, int);
9268static int evalcase(union node *, int);
9269static int evalsubshell(union node *, int);
9270static void expredir(union node *);
9271static int evalpipe(union node *, int);
9272static int evalcommand(union node *, int);
9273static int evalbltin(const struct builtincmd *, int, char **, int);
9274static void prehash(union node *);
9275
9276/*
9277 * Evaluate a parse tree.  The value is left in the global variable
9278 * exitstatus.
9279 */
9280static int
9281evaltree(union node *n, int flags)
9282{
9283        int checkexit = 0;
9284        int (*evalfn)(union node *, int);
9285        struct stackmark smark;
9286        int status = 0;
9287
9288        setstackmark(&smark);
9289
9290        if (nflag)
9291                goto out;
9292
9293        if (n == NULL) {
9294                TRACE(("evaltree(NULL) called\n"));
9295                goto out;
9296        }
9297        TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
9298
9299        dotrap();
9300
9301        switch (n->type) {
9302        default:
9303#if DEBUG
9304                out1fmt("Node type = %d\n", n->type);
9305                fflush_all();
9306                break;
9307#endif
9308        case NNOT:
9309                status = !evaltree(n->nnot.com, EV_TESTED);
9310                goto setstatus;
9311        case NREDIR:
9312                errlinno = lineno = n->nredir.linno;
9313                expredir(n->nredir.redirect);
9314                pushredir(n->nredir.redirect);
9315                status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9316                if (!status) {
9317                        status = evaltree(n->nredir.n, flags & EV_TESTED);
9318                }
9319                if (n->nredir.redirect)
9320                        popredir(/*drop:*/ 0);
9321                goto setstatus;
9322        case NCMD:
9323                evalfn = evalcommand;
9324 checkexit:
9325                checkexit = ~flags & EV_TESTED;
9326                goto calleval;
9327        case NFOR:
9328                evalfn = evalfor;
9329                goto calleval;
9330        case NWHILE:
9331        case NUNTIL:
9332                evalfn = evalloop;
9333                goto calleval;
9334        case NSUBSHELL:
9335        case NBACKGND:
9336                evalfn = evalsubshell;
9337                goto checkexit;
9338        case NPIPE:
9339                evalfn = evalpipe;
9340                goto checkexit;
9341        case NCASE:
9342                evalfn = evalcase;
9343                goto calleval;
9344        case NAND:
9345        case NOR:
9346        case NSEMI: {
9347#if NAND + 1 != NOR
9348#error NAND + 1 != NOR
9349#endif
9350#if NOR + 1 != NSEMI
9351#error NOR + 1 != NSEMI
9352#endif
9353                unsigned is_or = n->type - NAND;
9354                status = evaltree(
9355                        n->nbinary.ch1,
9356                        (flags | ((is_or >> 1) - 1)) & EV_TESTED
9357                );
9358                if ((!status) == is_or || evalskip)
9359                        break;
9360                n = n->nbinary.ch2;
9361 evaln:
9362                evalfn = evaltree;
9363 calleval:
9364                status = evalfn(n, flags);
9365                goto setstatus;
9366        }
9367        case NIF:
9368                status = evaltree(n->nif.test, EV_TESTED);
9369                if (evalskip)
9370                        break;
9371                if (!status) {
9372                        n = n->nif.ifpart;
9373                        goto evaln;
9374                } else if (n->nif.elsepart) {
9375                        n = n->nif.elsepart;
9376                        goto evaln;
9377                }
9378                status = 0;
9379                goto setstatus;
9380        case NDEFUN:
9381                defun(n);
9382                /* Not necessary. To test it:
9383                 * "false; f() { qwerty; }; echo $?" should print 0.
9384                 */
9385                /* status = 0; */
9386 setstatus:
9387                exitstatus = status;
9388                break;
9389        }
9390 out:
9391        /* Order of checks below is important:
9392         * signal handlers trigger before exit caused by "set -e".
9393         */
9394        dotrap();
9395
9396        if (checkexit && status) {
9397                if (trap[NTRAP_ERR] && !in_trap_ERR) {
9398                        int err;
9399                        struct jmploc *volatile savehandler = exception_handler;
9400                        struct jmploc jmploc;
9401
9402                        in_trap_ERR = 1;
9403                        trap_depth++;
9404                        err = setjmp(jmploc.loc);
9405                        if (!err) {
9406                                exception_handler = &jmploc;
9407                                savestatus = exitstatus;
9408                                evalstring(trap[NTRAP_ERR], 0);
9409                        }
9410                        trap_depth--;
9411                        in_trap_ERR = 0;
9412
9413                        exception_handler = savehandler;
9414                        if (err && exception_type != EXERROR)
9415                                longjmp(exception_handler->loc, 1);
9416
9417                        exitstatus = savestatus;
9418                }
9419                if (eflag)
9420                        goto exexit;
9421        }
9422        if (flags & EV_EXIT) {
9423 exexit:
9424                raise_exception(EXEND);
9425        }
9426
9427        popstackmark(&smark);
9428        TRACE(("leaving evaltree (no interrupts)\n"));
9429        return exitstatus;
9430}
9431
9432static int
9433skiploop(void)
9434{
9435        int skip = evalskip;
9436
9437        switch (skip) {
9438        case 0:
9439                break;
9440        case SKIPBREAK:
9441        case SKIPCONT:
9442                if (--skipcount <= 0) {
9443                        evalskip = 0;
9444                        break;
9445                }
9446                skip = SKIPBREAK;
9447                break;
9448        }
9449        return skip;
9450}
9451
9452static int
9453evalloop(union node *n, int flags)
9454{
9455        int skip;
9456        int status;
9457
9458        loopnest++;
9459        status = 0;
9460        flags &= EV_TESTED;
9461        do {
9462                int i;
9463
9464                i = evaltree(n->nbinary.ch1, EV_TESTED);
9465                skip = skiploop();
9466                if (skip == SKIPFUNC)
9467                        status = i;
9468                if (skip)
9469                        continue;
9470                if (n->type != NWHILE)
9471                        i = !i;
9472                if (i != 0)
9473                        break;
9474                status = evaltree(n->nbinary.ch2, flags);
9475                skip = skiploop();
9476        } while (!(skip & ~SKIPCONT));
9477        loopnest--;
9478
9479        return status;
9480}
9481
9482static int
9483evalfor(union node *n, int flags)
9484{
9485        struct arglist arglist;
9486        union node *argp;
9487        struct strlist *sp;
9488        int status = 0;
9489
9490        errlinno = lineno = n->ncase.linno;
9491
9492        arglist.list = NULL;
9493        arglist.lastp = &arglist.list;
9494        for (argp = n->nfor.args; argp; argp = argp->narg.next) {
9495                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9496        }
9497        *arglist.lastp = NULL;
9498
9499        loopnest++;
9500        flags &= EV_TESTED;
9501        for (sp = arglist.list; sp; sp = sp->next) {
9502                setvar0(n->nfor.var, sp->text);
9503                status = evaltree(n->nfor.body, flags);
9504                if (skiploop() & ~SKIPCONT)
9505                        break;
9506        }
9507        loopnest--;
9508
9509        return status;
9510}
9511
9512static int
9513evalcase(union node *n, int flags)
9514{
9515        union node *cp;
9516        union node *patp;
9517        struct arglist arglist;
9518        int status = 0;
9519
9520        errlinno = lineno = n->ncase.linno;
9521
9522        arglist.list = NULL;
9523        arglist.lastp = &arglist.list;
9524        expandarg(n->ncase.expr, &arglist, EXP_TILDE);
9525        for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9526                for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
9527                        if (casematch(patp, arglist.list->text)) {
9528                                /* Ensure body is non-empty as otherwise
9529                                 * EV_EXIT may prevent us from setting the
9530                                 * exit status.
9531                                 */
9532                                if (evalskip == 0 && cp->nclist.body) {
9533                                        status = evaltree(cp->nclist.body, flags);
9534                                }
9535                                goto out;
9536                        }
9537                }
9538        }
9539 out:
9540        return status;
9541}
9542
9543/*
9544 * Kick off a subshell to evaluate a tree.
9545 */
9546static int
9547evalsubshell(union node *n, int flags)
9548{
9549        struct job *jp;
9550        int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9551        int status;
9552
9553        errlinno = lineno = n->nredir.linno;
9554
9555        expredir(n->nredir.redirect);
9556        if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9557                goto nofork;
9558        INT_OFF;
9559        if (backgnd == FORK_FG)
9560                get_tty_state();
9561        jp = makejob(/*n,*/ 1);
9562        if (forkshell(jp, n, backgnd) == 0) {
9563                /* child */
9564                INT_ON;
9565                flags |= EV_EXIT;
9566                if (backgnd)
9567                        flags &= ~EV_TESTED;
9568 nofork:
9569                redirect(n->nredir.redirect, 0);
9570                evaltreenr(n->nredir.n, flags);
9571                /* never returns */
9572        }
9573        /* parent */
9574        status = 0;
9575        if (backgnd == FORK_FG)
9576                status = waitforjob(jp);
9577        INT_ON;
9578        return status;
9579}
9580
9581/*
9582 * Compute the names of the files in a redirection list.
9583 */
9584static void fixredir(union node *, const char *, int);
9585static void
9586expredir(union node *n)
9587{
9588        union node *redir;
9589
9590        for (redir = n; redir; redir = redir->nfile.next) {
9591                struct arglist fn;
9592
9593                fn.list = NULL;
9594                fn.lastp = &fn.list;
9595                switch (redir->type) {
9596                case NFROMTO:
9597                case NFROM:
9598                case NTO:
9599#if BASH_REDIR_OUTPUT
9600                case NTO2:
9601#endif
9602                case NCLOBBER:
9603                case NAPPEND:
9604                        expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
9605                        TRACE(("expredir expanded to '%s'\n", fn.list->text));
9606#if BASH_REDIR_OUTPUT
9607 store_expfname:
9608#endif
9609#if 0
9610// By the design of stack allocator, the loop of this kind:
9611//      while true; do while true; do break; done </dev/null; done
9612// will look like a memory leak: ash plans to free expfname's
9613// of "/dev/null" as soon as it finishes running the loop
9614// (in this case, never).
9615// This "fix" is wrong:
9616                        if (redir->nfile.expfname)
9617                                stunalloc(redir->nfile.expfname);
9618// It results in corrupted state of stacked allocations.
9619#endif
9620                        redir->nfile.expfname = fn.list->text;
9621                        break;
9622                case NFROMFD:
9623                case NTOFD: /* >& */
9624                        if (redir->ndup.vname) {
9625                                expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
9626                                if (fn.list == NULL)
9627                                        ash_msg_and_raise_error("redir error");
9628#if BASH_REDIR_OUTPUT
9629                                if (!isdigit_str9(fn.list->text)) {
9630                                        /* >&file, not >&fd */
9631                                        if (redir->nfile.fd != 1) /* 123>&file - BAD */
9632                                                ash_msg_and_raise_error("redir error");
9633                                        redir->type = NTO2;
9634                                        goto store_expfname;
9635                                }
9636#endif
9637                                fixredir(redir, fn.list->text, 1);
9638                        }
9639                        break;
9640                }
9641        }
9642}
9643
9644/*
9645 * Evaluate a pipeline.  All the processes in the pipeline are children
9646 * of the process creating the pipeline.  (This differs from some versions
9647 * of the shell, which make the last process in a pipeline the parent
9648 * of all the rest.)
9649 */
9650static int
9651evalpipe(union node *n, int flags)
9652{
9653        struct job *jp;
9654        struct nodelist *lp;
9655        int pipelen;
9656        int prevfd;
9657        int pip[2];
9658        int status = 0;
9659
9660        TRACE(("evalpipe(0x%lx) called\n", (long)n));
9661        pipelen = 0;
9662        for (lp = n->npipe.cmdlist; lp; lp = lp->next)
9663                pipelen++;
9664        flags |= EV_EXIT;
9665        INT_OFF;
9666        if (n->npipe.pipe_backgnd == 0)
9667                get_tty_state();
9668        jp = makejob(/*n,*/ pipelen);
9669        prevfd = -1;
9670        for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
9671                prehash(lp->n);
9672                pip[1] = -1;
9673                if (lp->next) {
9674                        if (pipe(pip) < 0) {
9675                                close(prevfd);
9676                                ash_msg_and_raise_perror("can't create pipe");
9677                        }
9678                }
9679                if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9680                        /* child */
9681                        INT_ON;
9682                        if (pip[1] >= 0) {
9683                                close(pip[0]);
9684                        }
9685                        if (prevfd > 0) {
9686                                dup2(prevfd, 0);
9687                                close(prevfd);
9688                        }
9689                        if (pip[1] > 1) {
9690                                dup2(pip[1], 1);
9691                                close(pip[1]);
9692                        }
9693                        evaltreenr(lp->n, flags);
9694                        /* never returns */
9695                }
9696                /* parent */
9697                if (prevfd >= 0)
9698                        close(prevfd);
9699                prevfd = pip[0];
9700                /* Don't want to trigger debugging */
9701                if (pip[1] != -1)
9702                        close(pip[1]);
9703        }
9704        if (n->npipe.pipe_backgnd == 0) {
9705                status = waitforjob(jp);
9706                TRACE(("evalpipe:  job done exit status %d\n", status));
9707        }
9708        INT_ON;
9709
9710        return status;
9711}
9712
9713/* setinteractive needs this forward reference */
9714#if EDITING_HAS_get_exe_name
9715static const char *get_builtin_name(int i) FAST_FUNC;
9716#endif
9717
9718/*
9719 * Controls whether the shell is interactive or not.
9720 */
9721static void
9722setinteractive(int on)
9723{
9724        static smallint is_interactive;
9725
9726        if (++on == is_interactive)
9727                return;
9728        is_interactive = on;
9729        setsignal(SIGINT);
9730        setsignal(SIGQUIT);
9731        setsignal(SIGTERM);
9732        if (is_interactive > 1) {
9733#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9734                /* Looks like they want an interactive shell */
9735                static smallint did_banner;
9736
9737                if (!did_banner) {
9738                        /* note: ash and hush share this string */
9739                        out1fmt("\n\n%s %s\n"
9740                                IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9741                                "\n",
9742                                bb_banner,
9743                                "built-in shell (ash)"
9744                        );
9745                        did_banner = 1;
9746                }
9747#endif
9748#if ENABLE_FEATURE_EDITING
9749                if (!line_input_state) {
9750                        line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
9751# if EDITING_HAS_get_exe_name
9752                        line_input_state->get_exe_name = get_builtin_name;
9753# endif
9754                }
9755#endif
9756        }
9757}
9758
9759static void
9760optschanged(void)
9761{
9762#if DEBUG
9763        opentrace();
9764#endif
9765        setinteractive(iflag);
9766        setjobctl(mflag);
9767#if ENABLE_FEATURE_EDITING_VI
9768        if (line_input_state) {
9769                if (viflag)
9770                        line_input_state->flags |= VI_MODE;
9771                else
9772                        line_input_state->flags &= ~VI_MODE;
9773        }
9774#else
9775        viflag = 0; /* forcibly keep the option off */
9776#endif
9777}
9778
9779struct localvar_list {
9780        struct localvar_list *next;
9781        struct localvar *lv;
9782};
9783
9784static struct localvar_list *localvar_stack;
9785
9786/*
9787 * Called after a function returns.
9788 * Interrupts must be off.
9789 */
9790static void
9791poplocalvars(int keep)
9792{
9793        struct localvar_list *ll;
9794        struct localvar *lvp, *next;
9795        struct var *vp;
9796
9797        INT_OFF;
9798        ll = localvar_stack;
9799        localvar_stack = ll->next;
9800
9801        next = ll->lv;
9802        free(ll);
9803
9804        while ((lvp = next) != NULL) {
9805                next = lvp->next;
9806                vp = lvp->vp;
9807                TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9808                if (keep) {
9809                        int bits = VSTRFIXED;
9810
9811                        if (lvp->flags != VUNSET) {
9812                                if (vp->var_text == lvp->text)
9813                                        bits |= VTEXTFIXED;
9814                                else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9815                                        free((char*)lvp->text);
9816                        }
9817
9818                        vp->flags &= ~bits;
9819                        vp->flags |= (lvp->flags & bits);
9820
9821                        if ((vp->flags &
9822                             (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9823                                unsetvar(vp->var_text);
9824                } else if (vp == NULL) {        /* $- saved */
9825                        memcpy(optlist, lvp->text, sizeof(optlist));
9826                        free((char*)lvp->text);
9827                        optschanged();
9828                } else if (lvp->flags == VUNSET) {
9829                        vp->flags &= ~(VSTRFIXED|VREADONLY);
9830                        unsetvar(vp->var_text);
9831                } else {
9832                        if (vp->var_func)
9833                                vp->var_func(var_end(lvp->text));
9834                        if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9835                                free((char*)vp->var_text);
9836                        vp->flags = lvp->flags;
9837                        vp->var_text = lvp->text;
9838                }
9839                free(lvp);
9840        }
9841        INT_ON;
9842}
9843
9844/*
9845 * Create a new localvar environment.
9846 */
9847static struct localvar_list *
9848pushlocalvars(int push)
9849{
9850        struct localvar_list *ll;
9851        struct localvar_list *top;
9852
9853        top = localvar_stack;
9854        if (!push)
9855                goto out;
9856
9857        INT_OFF;
9858        ll = ckzalloc(sizeof(*ll));
9859        /*ll->lv = NULL; - zalloc did it */
9860        ll->next = top;
9861        localvar_stack = ll;
9862        INT_ON;
9863 out:
9864        return top;
9865}
9866
9867static void
9868unwindlocalvars(struct localvar_list *stop)
9869{
9870        while (localvar_stack != stop)
9871                poplocalvars(0);
9872}
9873
9874static int
9875evalfun(struct funcnode *func, int argc, char **argv, int flags)
9876{
9877        volatile struct shparam saveparam;
9878        struct jmploc *volatile savehandler;
9879        struct jmploc jmploc;
9880        int e;
9881        int savelineno;
9882        int savefuncline;
9883        char *savefuncname;
9884        char *savetrap = NULL;
9885
9886        if (!Eflag) {
9887                savetrap = trap[NTRAP_ERR];
9888                trap[NTRAP_ERR] = NULL;
9889        }
9890        savelineno = lineno;
9891        saveparam = shellparam;
9892        savefuncline = funcline;
9893        savefuncname = funcname;
9894        savehandler = exception_handler;
9895        e = setjmp(jmploc.loc);
9896        if (e) {
9897                goto funcdone;
9898        }
9899        INT_OFF;
9900        exception_handler = &jmploc;
9901        shellparam.malloced = 0;
9902        func->count++;
9903        funcname = func->n.ndefun.text;
9904        funcline = func->n.ndefun.linno;
9905        INT_ON;
9906        shellparam.nparam = argc - 1;
9907        shellparam.p = argv + 1;
9908#if ENABLE_ASH_GETOPTS
9909        shellparam.optind = 1;
9910        shellparam.optoff = -1;
9911#endif
9912        evaltree(func->n.ndefun.body, flags & EV_TESTED);
9913 funcdone:
9914        INT_OFF;
9915        funcname = savefuncname;
9916        if (savetrap) {
9917                if (!trap[NTRAP_ERR])
9918                        trap[NTRAP_ERR] = savetrap;
9919                else
9920                        free(savetrap);
9921        }
9922        funcline = savefuncline;
9923        lineno = savelineno;
9924        freefunc(func);
9925        freeparam(&shellparam);
9926        shellparam = saveparam;
9927        exception_handler = savehandler;
9928        INT_ON;
9929        evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
9930        return e;
9931}
9932
9933/*
9934 * Make a variable a local variable.  When a variable is made local, it's
9935 * value and flags are saved in a localvar structure.  The saved values
9936 * will be restored when the shell function returns.  We handle the name
9937 * "-" as a special case: it makes changes to "set +-options" local
9938 * (options will be restored on return from the function).
9939 */
9940static void
9941mklocal(char *name, int flags)
9942{
9943        struct localvar *lvp;
9944        struct var **vpp;
9945        struct var *vp;
9946        char *eq = strchr(name, '=');
9947
9948        INT_OFF;
9949        /* Cater for duplicate "local". Examples:
9950         * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9951         * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9952         */
9953        lvp = localvar_stack->lv;
9954        while (lvp) {
9955                if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9956                        if (eq)
9957                                setvareq(name, 0);
9958                        /* else:
9959                         * it's a duplicate "local VAR" declaration, do nothing
9960                         */
9961                        goto ret;
9962                }
9963                lvp = lvp->next;
9964        }
9965
9966        lvp = ckzalloc(sizeof(*lvp));
9967        if (LONE_DASH(name)) {
9968                char *p;
9969                p = ckmalloc(sizeof(optlist));
9970                lvp->text = memcpy(p, optlist, sizeof(optlist));
9971                vp = NULL;
9972        } else {
9973                vpp = hashvar(name);
9974                vp = *findvar(vpp, name);
9975                if (vp == NULL) {
9976                        /* variable did not exist yet */
9977                        if (eq)
9978                                vp = setvareq(name, VSTRFIXED | flags);
9979                        else
9980                                vp = setvar(name, NULL, VSTRFIXED | flags);
9981                        lvp->flags = VUNSET;
9982                } else {
9983                        lvp->text = vp->var_text;
9984                        lvp->flags = vp->flags;
9985                        /* make sure neither "struct var" nor string gets freed
9986                         * during (un)setting:
9987                         */
9988                        vp->flags |= VSTRFIXED|VTEXTFIXED;
9989                        if (eq)
9990                                setvareq(name, flags);
9991                        else
9992                                /* "local VAR" unsets VAR: */
9993                                setvar0(name, NULL);
9994                }
9995        }
9996        lvp->vp = vp;
9997        lvp->next = localvar_stack->lv;
9998        localvar_stack->lv = lvp;
9999 ret:
10000        INT_ON;
10001}
10002
10003/*
10004 * The "local" command.
10005 */
10006static int FAST_FUNC
10007localcmd(int argc UNUSED_PARAM, char **argv)
10008{
10009        char *name;
10010
10011        if (!localvar_stack)
10012                ash_msg_and_raise_error("not in a function");
10013
10014        argv = argptr;
10015        while ((name = *argv++) != NULL) {
10016                mklocal(name, 0);
10017        }
10018        return 0;
10019}
10020
10021static int FAST_FUNC
10022falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10023{
10024        return 1;
10025}
10026
10027static int FAST_FUNC
10028truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10029{
10030        return 0;
10031}
10032
10033static int FAST_FUNC
10034execcmd(int argc UNUSED_PARAM, char **argv)
10035{
10036        optionarg = NULL;
10037        while (nextopt("a:") != '\0')
10038                /* nextopt() sets optionarg to "-a ARGV0" */;
10039
10040        argv = argptr;
10041        if (argv[0]) {
10042                char *prog;
10043
10044                iflag = 0;              /* exit on error */
10045                mflag = 0;
10046                optschanged();
10047                /* We should set up signals for "exec CMD"
10048                 * the same way as for "CMD" without "exec".
10049                 * But optschanged->setinteractive->setsignal
10050                 * still thought we are a root shell. Therefore, for example,
10051                 * SIGQUIT is still set to IGN. Fix it:
10052                 */
10053                shlvl++;
10054                setsignal(SIGQUIT);
10055                /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
10056                /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
10057                /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
10058
10059                prog = argv[0];
10060                if (optionarg)
10061                        argv[0] = optionarg;
10062                shellexec(prog, argv, pathval(), 0);
10063                /* NOTREACHED */
10064        }
10065        return 0;
10066}
10067
10068/*
10069 * The return command.
10070 */
10071static int FAST_FUNC
10072returncmd(int argc UNUSED_PARAM, char **argv)
10073{
10074        int skip;
10075        int status;
10076
10077        /*
10078         * If called outside a function, do what ksh does;
10079         * skip the rest of the file.
10080         */
10081        if (argv[1]) {
10082                skip = SKIPFUNC;
10083                status = number(argv[1]);
10084        } else {
10085                skip = SKIPFUNCDEF;
10086                status = exitstatus;
10087        }
10088        evalskip = skip;
10089
10090        return status;
10091}
10092
10093/* Forward declarations for builtintab[] */
10094static int breakcmd(int, char **) FAST_FUNC;
10095static int dotcmd(int, char **) FAST_FUNC;
10096static int evalcmd(int, char **, int) FAST_FUNC;
10097static int exitcmd(int, char **) FAST_FUNC;
10098static int exportcmd(int, char **) FAST_FUNC;
10099#if ENABLE_ASH_GETOPTS
10100static int getoptscmd(int, char **) FAST_FUNC;
10101#endif
10102#if ENABLE_ASH_HELP
10103static int helpcmd(int, char **) FAST_FUNC;
10104#endif
10105#if MAX_HISTORY
10106static int historycmd(int, char **) FAST_FUNC;
10107#endif
10108#if ENABLE_FEATURE_SH_MATH
10109static int letcmd(int, char **) FAST_FUNC;
10110#endif
10111static int readcmd(int, char **) FAST_FUNC;
10112static int setcmd(int, char **) FAST_FUNC;
10113static int shiftcmd(int, char **) FAST_FUNC;
10114static int timescmd(int, char **) FAST_FUNC;
10115static int trapcmd(int, char **) FAST_FUNC;
10116static int umaskcmd(int, char **) FAST_FUNC;
10117static int unsetcmd(int, char **) FAST_FUNC;
10118static int ulimitcmd(int, char **) FAST_FUNC;
10119
10120#define BUILTIN_NOSPEC          "0"
10121#define BUILTIN_SPECIAL         "1"
10122#define BUILTIN_REGULAR         "2"
10123#define BUILTIN_SPEC_REG        "3"
10124#define BUILTIN_ASSIGN          "4"
10125#define BUILTIN_SPEC_ASSG       "5"
10126#define BUILTIN_REG_ASSG        "6"
10127#define BUILTIN_SPEC_REG_ASSG   "7"
10128
10129/* Stubs for calling non-FAST_FUNC's */
10130#if ENABLE_ASH_ECHO
10131static int FAST_FUNC echocmd(int argc, char **argv)   { return echo_main(argc, argv); }
10132#endif
10133#if ENABLE_ASH_PRINTF
10134static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
10135#endif
10136#if ENABLE_ASH_TEST || BASH_TEST2
10137static int FAST_FUNC testcmd(int argc, char **argv)   { return test_main(argc, argv); }
10138#endif
10139
10140/* Keep these in proper order since it is searched via bsearch() */
10141static const struct builtincmd builtintab[] = {
10142        { BUILTIN_SPEC_REG      "."       , dotcmd     },
10143        { BUILTIN_SPEC_REG      ":"       , truecmd    },
10144#if ENABLE_ASH_TEST
10145        { BUILTIN_REGULAR       "["       , testcmd    },
10146#endif
10147#if BASH_TEST2
10148        { BUILTIN_REGULAR       "[["      , testcmd    },
10149#endif
10150#if ENABLE_ASH_ALIAS
10151        { BUILTIN_REG_ASSG      "alias"   , aliascmd   },
10152#endif
10153#if JOBS
10154        { BUILTIN_REGULAR       "bg"      , fg_bgcmd   },
10155#endif
10156        { BUILTIN_SPEC_REG      "break"   , breakcmd   },
10157        { BUILTIN_REGULAR       "cd"      , cdcmd      },
10158        { BUILTIN_NOSPEC        "chdir"   , cdcmd      },
10159#if ENABLE_ASH_CMDCMD
10160        { BUILTIN_REGULAR       "command" , commandcmd },
10161#endif
10162        { BUILTIN_SPEC_REG      "continue", breakcmd   },
10163#if ENABLE_ASH_ECHO
10164        { BUILTIN_REGULAR       "echo"    , echocmd    },
10165#endif
10166        { BUILTIN_SPEC_REG      "eval"    , NULL       }, /*evalcmd() has a differing prototype*/
10167        { BUILTIN_SPEC_REG      "exec"    , execcmd    },
10168        { BUILTIN_SPEC_REG      "exit"    , exitcmd    },
10169        { BUILTIN_SPEC_REG_ASSG "export"  , exportcmd  },
10170        { BUILTIN_REGULAR       "false"   , falsecmd   },
10171#if JOBS
10172        { BUILTIN_REGULAR       "fg"      , fg_bgcmd   },
10173#endif
10174#if ENABLE_ASH_GETOPTS
10175        { BUILTIN_REGULAR       "getopts" , getoptscmd },
10176#endif
10177        { BUILTIN_REGULAR       "hash"    , hashcmd    },
10178#if ENABLE_ASH_HELP
10179        { BUILTIN_NOSPEC        "help"    , helpcmd    },
10180#endif
10181#if MAX_HISTORY
10182        { BUILTIN_NOSPEC        "history" , historycmd },
10183#endif
10184#if JOBS
10185        { BUILTIN_REGULAR       "jobs"    , jobscmd    },
10186        { BUILTIN_REGULAR       "kill"    , killcmd    },
10187#endif
10188#if ENABLE_FEATURE_SH_MATH
10189        { BUILTIN_NOSPEC        "let"     , letcmd     },
10190#endif
10191        { BUILTIN_SPEC_REG_ASSG "local"   , localcmd   },
10192#if ENABLE_ASH_PRINTF
10193        { BUILTIN_REGULAR       "printf"  , printfcmd  },
10194#endif
10195        { BUILTIN_REGULAR       "pwd"     , pwdcmd     },
10196        { BUILTIN_REGULAR       "read"    , readcmd    },
10197        { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd  },
10198        { BUILTIN_SPEC_REG      "return"  , returncmd  },
10199        { BUILTIN_SPEC_REG      "set"     , setcmd     },
10200        { BUILTIN_SPEC_REG      "shift"   , shiftcmd   },
10201#if BASH_SOURCE
10202        { BUILTIN_SPEC_REG      "source"  , dotcmd     },
10203#endif
10204#if ENABLE_ASH_TEST
10205        { BUILTIN_REGULAR       "test"    , testcmd    },
10206#endif
10207        { BUILTIN_SPEC_REG      "times"   , timescmd   },
10208        { BUILTIN_SPEC_REG      "trap"    , trapcmd    },
10209        { BUILTIN_REGULAR       "true"    , truecmd    },
10210        { BUILTIN_REGULAR       "type"    , typecmd    },
10211        { BUILTIN_REGULAR       "ulimit"  , ulimitcmd  },
10212        { BUILTIN_REGULAR       "umask"   , umaskcmd   },
10213#if ENABLE_ASH_ALIAS
10214        { BUILTIN_REGULAR       "unalias" , unaliascmd },
10215#endif
10216        { BUILTIN_SPEC_REG      "unset"   , unsetcmd   },
10217        { BUILTIN_REGULAR       "wait"    , waitcmd    },
10218};
10219
10220/* Should match the above table! */
10221#define COMMANDCMD (builtintab + \
10222        /* . : */       2 + \
10223        /* [ */         1 * ENABLE_ASH_TEST + \
10224        /* [[ */        1 * BASH_TEST2 + \
10225        /* alias */     1 * ENABLE_ASH_ALIAS + \
10226        /* bg */        1 * ENABLE_ASH_JOB_CONTROL + \
10227        /* break cd cddir  */   3)
10228#define EVALCMD (COMMANDCMD + \
10229        /* command */   1 * ENABLE_ASH_CMDCMD + \
10230        /* continue */  1 + \
10231        /* echo */      1 * ENABLE_ASH_ECHO + \
10232        0)
10233#define EXECCMD (EVALCMD + \
10234        /* eval */      1)
10235
10236/*
10237 * Search the table of builtin commands.
10238 */
10239static int
10240pstrcmp1(const void *a, const void *b)
10241{
10242        return strcmp((char*)a, *(char**)b + 1);
10243}
10244static struct builtincmd *
10245find_builtin(const char *name)
10246{
10247        struct builtincmd *bp;
10248
10249        bp = bsearch(
10250                name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
10251                pstrcmp1
10252        );
10253        return bp;
10254}
10255
10256#if EDITING_HAS_get_exe_name
10257static const char * FAST_FUNC
10258get_builtin_name(int i)
10259{
10260        return /*i >= 0 &&*/ i < ARRAY_SIZE(builtintab) ? builtintab[i].name + 1 : NULL;
10261}
10262#endif
10263
10264/*
10265 * Execute a simple command.
10266 */
10267static void unwindfiles(struct parsefile *stop);
10268static int
10269isassignment(const char *p)
10270{
10271        const char *q = endofname(p);
10272        if (p == q)
10273                return 0;
10274        return *q == '=';
10275}
10276static int FAST_FUNC
10277bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10278{
10279        /* Preserve exitstatus of a previous possible redirection
10280         * as POSIX mandates */
10281        return back_exitstatus;
10282}
10283static int
10284evalcommand(union node *cmd, int flags)
10285{
10286        static const struct builtincmd null_bltin = {
10287                BUILTIN_REGULAR "", bltincmd
10288        };
10289        struct localvar_list *localvar_stop;
10290        struct parsefile *file_stop;
10291        struct redirtab *redir_stop;
10292        union node *argp;
10293        struct arglist arglist;
10294        struct arglist varlist;
10295        char **argv;
10296        int argc;
10297        struct strlist *osp;
10298        const struct strlist *sp;
10299        struct cmdentry cmdentry;
10300        struct job *jp;
10301        char *lastarg;
10302        const char *path;
10303        int spclbltin;
10304        int cmd_flag;
10305        int status;
10306        char **nargv;
10307        smallint cmd_is_exec;
10308        int vflags;
10309        int vlocal;
10310
10311        errlinno = lineno = cmd->ncmd.linno;
10312
10313        /* First expand the arguments. */
10314        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
10315#if BASH_PROCESS_SUBST
10316        redir_stop = redirlist;
10317#endif
10318        file_stop = g_parsefile;
10319        back_exitstatus = 0;
10320
10321        cmdentry.cmdtype = CMDBUILTIN;
10322        cmdentry.u.cmd = &null_bltin;
10323        varlist.lastp = &varlist.list;
10324        *varlist.lastp = NULL;
10325        arglist.lastp = &arglist.list;
10326        *arglist.lastp = NULL;
10327
10328        cmd_flag = 0;
10329        cmd_is_exec = 0;
10330        spclbltin = -1;
10331        vflags = 0;
10332        vlocal = 0;
10333        path = NULL;
10334
10335        argc = 0;
10336        argp = cmd->ncmd.args;
10337        osp = fill_arglist(&arglist, &argp);
10338        if (osp) {
10339                int pseudovarflag = 0;
10340
10341                for (;;) {
10342                        find_command(arglist.list->text, &cmdentry,
10343                                        cmd_flag | DO_REGBLTIN, pathval());
10344
10345                        vlocal++;
10346
10347                        /* implement bltin and command here */
10348                        if (cmdentry.cmdtype != CMDBUILTIN)
10349                                break;
10350
10351                        pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
10352                        if (spclbltin < 0) {
10353                                spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10354                                vlocal = !spclbltin;
10355                        }
10356                        cmd_is_exec = cmdentry.u.cmd == EXECCMD;
10357#if ENABLE_ASH_CMDCMD
10358                        if (cmdentry.u.cmd != COMMANDCMD)
10359                                break;
10360
10361                        cmd_flag = parse_command_args(&arglist, &argp, &path);
10362                        if (!cmd_flag)
10363#endif
10364                                break;
10365                }
10366
10367                for (; argp; argp = argp->narg.next)
10368                        expandarg(argp, &arglist,
10369                                        pseudovarflag &&
10370                                        isassignment(argp->narg.text) ?
10371                                        EXP_VARTILDE : EXP_FULL | EXP_TILDE);
10372
10373                for (sp = arglist.list; sp; sp = sp->next)
10374                        argc++;
10375
10376                if (cmd_is_exec && argc > 1)
10377                        vflags = VEXPORT;
10378        }
10379
10380        localvar_stop = pushlocalvars(vlocal);
10381
10382        /* Reserve one extra spot at the front for shellexec. */
10383        nargv = stalloc(sizeof(char *) * (argc + 2));
10384        argv = ++nargv;
10385        for (sp = arglist.list; sp; sp = sp->next) {
10386                TRACE(("evalcommand arg: %s\n", sp->text));
10387                *nargv++ = sp->text;
10388        }
10389        *nargv = NULL;
10390
10391        lastarg = NULL;
10392        if (iflag && funcline == 0 && argc > 0)
10393                lastarg = nargv[-1];
10394
10395        expredir(cmd->ncmd.redirect);
10396#if !BASH_PROCESS_SUBST
10397        redir_stop = pushredir(cmd->ncmd.redirect);
10398#else
10399        pushredir(cmd->ncmd.redirect);
10400#endif
10401        preverrout_fd = 2;
10402        if (BASH_XTRACEFD && xflag) {
10403                /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10404                 * we do not emulate this. We only use its value.
10405                 */
10406                const char *xtracefd = lookupvar("BASH_XTRACEFD");
10407                if (xtracefd && is_number(xtracefd))
10408                        preverrout_fd = atoi(xtracefd);
10409
10410        }
10411        status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10412
10413        if (status) {
10414 bail:
10415                exitstatus = status;
10416
10417                /* We have a redirection error. */
10418                if (spclbltin > 0)
10419                        raise_exception(EXERROR);
10420
10421                goto out;
10422        }
10423
10424        for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10425                struct strlist **spp;
10426
10427                spp = varlist.lastp;
10428                expandarg(argp, &varlist, EXP_VARTILDE);
10429
10430                if (vlocal)
10431                        mklocal((*spp)->text, VEXPORT);
10432                else
10433                        setvareq((*spp)->text, vflags);
10434        }
10435
10436        /* Print the command if xflag is set. */
10437        if (xflag && !inps4) {
10438                const char *pfx = "";
10439
10440                inps4 = 1;
10441                fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
10442                inps4 = 0;
10443
10444                sp = varlist.list;
10445                while (sp) {
10446                        char *varval = sp->text;
10447                        char *eq = strchrnul(varval, '=');
10448                        if (*eq)
10449                                eq++;
10450                        fdprintf(preverrout_fd, "%s%.*s%s",
10451                                pfx,
10452                                (int)(eq - varval), varval,
10453                                maybe_single_quote(eq)
10454                        );
10455                        sp = sp->next;
10456                        pfx = " ";
10457                }
10458
10459                sp = arglist.list;
10460                while (sp) {
10461                        fdprintf(preverrout_fd, "%s%s",
10462                                pfx,
10463                                /* always quote if matches reserved word: */
10464                                findkwd(sp->text)
10465                                ? single_quote(sp->text)
10466                                : maybe_single_quote(sp->text)
10467                        );
10468                        sp = sp->next;
10469                        pfx = " ";
10470                }
10471                safe_write(preverrout_fd, "\n", 1);
10472        }
10473
10474        /* Now locate the command. */
10475        if (cmdentry.cmdtype != CMDBUILTIN
10476         || !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
10477        ) {
10478                path = path ? path : pathval();
10479                find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path);
10480        }
10481
10482        jp = NULL;
10483
10484        /* Execute the command. */
10485        switch (cmdentry.cmdtype) {
10486        case CMDUNKNOWN:
10487                status = 127;
10488                flush_stdout_stderr();
10489                goto bail;
10490
10491        default: {
10492
10493#if ENABLE_FEATURE_SH_STANDALONE \
10494 && ENABLE_FEATURE_SH_NOFORK \
10495 && NUM_APPLETS > 1
10496/* (1) BUG: if variables are set, we need to fork, or save/restore them
10497 *     around run_nofork_applet() call.
10498 * (2) Should this check also be done in forkshell()?
10499 *     (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10500 */
10501                /* find_command() encodes applet_no as (-2 - applet_no) */
10502                int applet_no = (- cmdentry.u.index - 2);
10503                if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10504                        char **sv_environ;
10505
10506                        INT_OFF;
10507                        sv_environ = environ;
10508                        environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
10509                        /*
10510                         * Run <applet>_main().
10511                         * Signals (^C) can't interrupt here.
10512                         * Otherwise we can mangle stdio or malloc internal state.
10513                         * This makes applets which can run for a long time
10514                         * and/or wait for user input ineligible for NOFORK:
10515                         * for example, "yes" or "rm" (rm -i waits for input).
10516                         */
10517                        exitstatus = run_nofork_applet(applet_no, argv);
10518                        environ = sv_environ;
10519                        /*
10520                         * Try enabling NOFORK for "yes" applet.
10521                         * ^C _will_ stop it (write returns EINTR),
10522                         * but this causes stdout FILE to be stuck
10523                         * and needing clearerr(). What if other applets
10524                         * also can get EINTRs? Do we need to switch
10525                         * our signals to SA_RESTART?
10526                         */
10527                        /*clearerr(stdout);*/
10528                        INT_ON;
10529                        break;
10530                }
10531#endif
10532                /* Can we avoid forking? For example, very last command
10533                 * in a script or a subshell does not need forking,
10534                 * we can just exec it.
10535                 */
10536                if (!(flags & EV_EXIT) || may_have_traps) {
10537                        /* No, forking off a child is necessary */
10538                        INT_OFF;
10539                        get_tty_state();
10540                        jp = makejob(/*cmd,*/ 1);
10541                        if (forkshell(jp, cmd, FORK_FG) != 0) {
10542                                /* parent */
10543                                break;
10544                        }
10545                        /* child */
10546                        FORCE_INT_ON;
10547                        /* fall through to exec'ing external program */
10548                }
10549                shellexec(argv[0], argv, path, cmdentry.u.index);
10550                /* NOTREACHED */
10551        } /* default */
10552        case CMDBUILTIN:
10553                if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
10554                 && !(exception_type == EXERROR && spclbltin <= 0)
10555                ) {
10556 raise:
10557                        longjmp(exception_handler->loc, 1);
10558                }
10559                break;
10560
10561        case CMDFUNCTION:
10562                if (evalfun(cmdentry.u.func, argc, argv, flags))
10563                        goto raise;
10564                break;
10565        } /* switch */
10566
10567        status = waitforjob(jp);
10568        if (jp)
10569                TRACE(("forked child exited with %d\n", status));
10570        FORCE_INT_ON;
10571
10572 out:
10573        if (cmd->ncmd.redirect)
10574                popredir(/*drop:*/ cmd_is_exec);
10575        unwindredir(redir_stop);
10576        unwindfiles(file_stop);
10577        unwindlocalvars(localvar_stop);
10578        if (lastarg) {
10579                /* dsl: I think this is intended to be used to support
10580                 * '_' in 'vi' command mode during line editing...
10581                 * However I implemented that within libedit itself.
10582                 */
10583                setvar0("_", lastarg);
10584        }
10585
10586        return status;
10587}
10588
10589static int
10590evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
10591{
10592        char *volatile savecmdname;
10593        struct jmploc *volatile savehandler;
10594        struct jmploc jmploc;
10595        int status;
10596        int i;
10597
10598        savecmdname = commandname;
10599        savehandler = exception_handler;
10600        i = setjmp(jmploc.loc);
10601        if (i)
10602                goto cmddone;
10603        exception_handler = &jmploc;
10604        commandname = argv[0];
10605        argptr = argv + 1;
10606        optptr = NULL;                  /* initialize nextopt */
10607        if (cmd == EVALCMD)
10608                status = evalcmd(argc, argv, flags);
10609        else
10610                status = (*cmd->builtin)(argc, argv);
10611        flush_stdout_stderr();
10612        status |= ferror(stdout);
10613        exitstatus = status;
10614 cmddone:
10615        clearerr(stdout);
10616        commandname = savecmdname;
10617        exception_handler = savehandler;
10618
10619        return i;
10620}
10621
10622static int
10623goodname(const char *p)
10624{
10625        return endofname(p)[0] == '\0';
10626}
10627
10628
10629/*
10630 * Search for a command.  This is called before we fork so that the
10631 * location of the command will be available in the parent as well as
10632 * the child.  The check for "goodname" is an overly conservative
10633 * check that the name will not be subject to expansion.
10634 */
10635static void
10636prehash(union node *n)
10637{
10638        struct cmdentry entry;
10639
10640        if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10641                find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
10642}
10643
10644
10645/* ============ Builtin commands
10646 *
10647 * Builtin commands whose functions are closely tied to evaluation
10648 * are implemented here.
10649 */
10650
10651/*
10652 * Handle break and continue commands.  Break, continue, and return are
10653 * all handled by setting the evalskip flag.  The evaluation routines
10654 * above all check this flag, and if it is set they start skipping
10655 * commands rather than executing them.  The variable skipcount is
10656 * the number of loops to break/continue, or the number of function
10657 * levels to return.  (The latter is always 1.)  It should probably
10658 * be an error to break out of more loops than exist, but it isn't
10659 * in the standard shell so we don't make it one here.
10660 */
10661static int FAST_FUNC
10662breakcmd(int argc UNUSED_PARAM, char **argv)
10663{
10664        int n = argv[1] ? number(argv[1]) : 1;
10665
10666        if (n <= 0)
10667                ash_msg_and_raise_error(msg_illnum, argv[1]);
10668        if (n > loopnest)
10669                n = loopnest;
10670        if (n > 0) {
10671                evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
10672                skipcount = n;
10673        }
10674        return 0;
10675}
10676
10677
10678/*
10679 * This implements the input routines used by the parser.
10680 */
10681
10682enum {
10683        INPUT_PUSH_FILE = 1,
10684        INPUT_NOFILE_OK = 2,
10685};
10686
10687static smallint checkkwd;
10688/* values of checkkwd variable */
10689#define CHKALIAS        0x1
10690#define CHKKWD          0x2
10691#define CHKNL           0x4
10692#define CHKEOFMARK      0x8
10693
10694/*
10695 * Push a string back onto the input at this current parsefile level.
10696 * We handle aliases this way.
10697 */
10698#if !ENABLE_ASH_ALIAS
10699#define pushstring(s, ap) pushstring(s)
10700#endif
10701static void
10702pushstring(char *s, struct alias *ap)
10703{
10704        struct strpush *sp;
10705        int len;
10706
10707        len = strlen(s);
10708        INT_OFF;
10709        if (g_parsefile->strpush || g_parsefile->spfree) {
10710                sp = ckzalloc(sizeof(*sp));
10711                sp->prev = g_parsefile->strpush;
10712        } else {
10713                sp = &(g_parsefile->basestrpush);
10714        }
10715        g_parsefile->strpush = sp;
10716        sp->prev_string = g_parsefile->next_to_pgetc;
10717        sp->prev_left_in_line = g_parsefile->left_in_line;
10718        sp->unget = g_parsefile->unget;
10719        sp->spfree = g_parsefile->spfree;
10720        memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
10721#if ENABLE_ASH_ALIAS
10722        sp->ap = ap;
10723        if (ap) {
10724                ap->flag |= ALIASINUSE;
10725                sp->string = s;
10726        }
10727#endif
10728        g_parsefile->next_to_pgetc = s;
10729        g_parsefile->left_in_line = len;
10730        g_parsefile->unget = 0;
10731        g_parsefile->spfree = NULL;
10732        INT_ON;
10733}
10734
10735static void popstring(void)
10736{
10737        struct strpush *sp = g_parsefile->strpush;
10738
10739        INT_OFF;
10740#if ENABLE_ASH_ALIAS
10741        if (sp->ap) {
10742                if (g_parsefile->next_to_pgetc[-1] == ' '
10743                 || g_parsefile->next_to_pgetc[-1] == '\t'
10744                ) {
10745                        checkkwd |= CHKALIAS;
10746                }
10747                if (sp->string != sp->ap->val) {
10748                        free(sp->string);
10749                }
10750        }
10751#endif
10752        g_parsefile->next_to_pgetc = sp->prev_string;
10753        g_parsefile->left_in_line = sp->prev_left_in_line;
10754        g_parsefile->unget = sp->unget;
10755        memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
10756        g_parsefile->strpush = sp->prev;
10757        g_parsefile->spfree = sp;
10758        INT_ON;
10759}
10760
10761static int
10762preadfd(void)
10763{
10764        int nr;
10765        char *buf = g_parsefile->buf;
10766
10767        g_parsefile->next_to_pgetc = buf;
10768#if ENABLE_FEATURE_EDITING
10769 /* retry: */
10770        if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10771                nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10772        else {
10773# if ENABLE_ASH_IDLE_TIMEOUT
10774                int timeout = -1;
10775                const char *tmout_var = lookupvar("TMOUT");
10776                if (tmout_var) {
10777                        timeout = atoi(tmout_var) * 1000;
10778                        if (timeout <= 0)
10779                                timeout = -1;
10780                }
10781                line_input_state->timeout = timeout;
10782# endif
10783# if ENABLE_FEATURE_TAB_COMPLETION
10784                line_input_state->path_lookup = pathval();
10785# endif
10786                reinit_unicode_for_ash();
10787                nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10788                if (nr == 0) {
10789                        /* ^C pressed, "convert" to SIGINT */
10790                        write(STDOUT_FILENO, "^C", 2);
10791                        raise(SIGINT);
10792                        if (trap[SIGINT]) {
10793                                buf[0] = '\n';
10794                                buf[1] = '\0';
10795                                return 1;
10796                        }
10797                        exitstatus = 128 + SIGINT;
10798                        return -1;
10799                }
10800                if (nr < 0) {
10801                        if (errno == 0) {
10802                                /* Ctrl+D pressed */
10803                                nr = 0;
10804                        }
10805# if ENABLE_ASH_IDLE_TIMEOUT
10806                        else if (errno == EAGAIN && timeout > 0) {
10807                                puts("\007timed out waiting for input: auto-logout");
10808                                exitshell();
10809                        }
10810# endif
10811                }
10812        }
10813#else
10814        nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10815#endif
10816
10817#if 0 /* disabled: nonblock_immune_read() handles this problem */
10818        if (nr < 0) {
10819                if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10820                        int flags = fcntl(0, F_GETFL);
10821                        if (flags >= 0 && (flags & O_NONBLOCK)) {
10822                                flags &= ~O_NONBLOCK;
10823                                if (fcntl(0, F_SETFL, flags) >= 0) {
10824                                        out2str("sh: turning off NDELAY mode\n");
10825                                        goto retry;
10826                                }
10827                        }
10828                }
10829        }
10830#endif
10831        return nr;
10832}
10833
10834/*
10835 * Refill the input buffer and return the next input character:
10836 *
10837 * 1) If a string was pushed back on the input, pop it;
10838 * 2) If we are reading from a string we can't refill the buffer, return EOF.
10839 * 3) If there is more stuff in this buffer, use it else call read to fill it.
10840 * 4) Process input up to the next newline, deleting nul characters.
10841 */
10842//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10843#define pgetc_debug(...) ((void)0)
10844static int __pgetc(void);
10845static int
10846preadbuffer(void)
10847{
10848        char *q;
10849        int more;
10850
10851        if (unlikely(g_parsefile->strpush)) {
10852                popstring();
10853                return __pgetc();
10854        }
10855
10856        if (g_parsefile->buf == NULL) {
10857                pgetc_debug("preadbuffer PEOF1");
10858                return PEOF;
10859        }
10860
10861        more = g_parsefile->left_in_buffer;
10862        if (more <= 0) {
10863                flush_stdout_stderr();
10864 again:
10865                more = preadfd();
10866                if (more <= 0) {
10867                        g_parsefile->left_in_buffer = g_parsefile->left_in_line = 0;
10868                        pgetc_debug("preadbuffer PEOF2");
10869                        return PEOF;
10870                }
10871        }
10872
10873        /* Find out where's the end of line.
10874         * Set g_parsefile->left_in_line
10875         * and g_parsefile->left_in_buffer acordingly.
10876         * NUL chars are deleted.
10877         */
10878        q = g_parsefile->next_to_pgetc;
10879        for (;;) {
10880                char c;
10881
10882                more--;
10883
10884                c = *q;
10885                if (c == '\0') {
10886                        memmove(q, q + 1, more);
10887                } else {
10888                        q++;
10889                        if (c == '\n') {
10890                                g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10891                                break;
10892                        }
10893                }
10894
10895                if (more <= 0) {
10896                        g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10897                        if (g_parsefile->left_in_line < 0)
10898                                goto again;
10899                        break;
10900                }
10901        }
10902        g_parsefile->left_in_buffer = more;
10903
10904        if (vflag) {
10905                char save = *q;
10906                *q = '\0';
10907                out2str(g_parsefile->next_to_pgetc);
10908                *q = save;
10909        }
10910
10911        pgetc_debug("preadbuffer at %d:%p'%s'",
10912                        g_parsefile->left_in_line,
10913                        g_parsefile->next_to_pgetc,
10914                        g_parsefile->next_to_pgetc);
10915        return (unsigned char)*g_parsefile->next_to_pgetc++;
10916}
10917
10918static void
10919nlprompt(void)
10920{
10921        if (trap_depth == 0)
10922                g_parsefile->linno++;
10923        setprompt_if(doprompt, 2);
10924}
10925static void
10926nlnoprompt(void)
10927{
10928        if (trap_depth == 0)
10929                g_parsefile->linno++;
10930        needprompt = doprompt;
10931}
10932
10933static void freestrings(struct strpush *sp)
10934{
10935        INT_OFF;
10936        do {
10937                struct strpush *psp;
10938#if ENABLE_ASH_ALIAS
10939                if (sp->ap) {
10940                        sp->ap->flag &= ~ALIASINUSE;
10941                        if (sp->ap->flag & ALIASDEAD) {
10942                                unalias(sp->ap->name);
10943                        }
10944                }
10945#endif
10946                psp = sp;
10947                sp = sp->spfree;
10948
10949                if (psp != &(g_parsefile->basestrpush))
10950                        free(psp);
10951        } while (sp);
10952
10953        g_parsefile->spfree = NULL;
10954        INT_ON;
10955}
10956
10957static int __pgetc(void)
10958{
10959        int c;
10960
10961        pgetc_debug("pgetc at %d:%p'%s'",
10962                        g_parsefile->left_in_line,
10963                        g_parsefile->next_to_pgetc,
10964                        g_parsefile->next_to_pgetc);
10965        if (g_parsefile->unget)
10966                return g_parsefile->lastc[--g_parsefile->unget];
10967
10968        if (--g_parsefile->left_in_line >= 0)
10969                c = (unsigned char)*g_parsefile->next_to_pgetc++;
10970        else
10971                c = preadbuffer();
10972
10973        g_parsefile->lastc[1] = g_parsefile->lastc[0];
10974        g_parsefile->lastc[0] = c;
10975
10976        return c;
10977}
10978
10979/*
10980 * Read a character from the script, returning PEOF on end of file.
10981 * Nul characters in the input are silently discarded.
10982 */
10983static int pgetc(void)
10984{
10985        struct strpush *sp = g_parsefile->spfree;
10986
10987        if (unlikely(sp))
10988                freestrings(sp);
10989
10990        return __pgetc();
10991}
10992
10993/*
10994 * Undo a call to pgetc.  Only two characters may be pushed back.
10995 * PEOF may be pushed back.
10996 */
10997static void
10998pungetc(void)
10999{
11000        g_parsefile->unget++;
11001}
11002
11003/* This one eats backslash+newline */
11004static int
11005pgetc_eatbnl(void)
11006{
11007        int c;
11008
11009        while ((c = pgetc()) == '\\') {
11010                if (pgetc() != '\n') {
11011                        pungetc();
11012                        break;
11013                }
11014
11015                nlprompt();
11016        }
11017
11018        return c;
11019}
11020
11021struct synstack {
11022        smalluint syntax;
11023        uint8_t innerdq   :1;
11024        uint8_t varpushed :1;
11025        uint8_t dblquote  :1;
11026        int varnest;            /* levels of variables expansion */
11027        int dqvarnest;          /* levels of variables expansion within double quotes */
11028        int parenlevel;         /* levels of parens in arithmetic */
11029        struct synstack *prev;
11030        struct synstack *next;
11031};
11032
11033static int
11034pgetc_top(struct synstack *stack)
11035{
11036        return stack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl();
11037}
11038
11039static void
11040synstack_push(struct synstack **stack, struct synstack *next, int syntax)
11041{
11042        memset(next, 0, sizeof(*next));
11043        next->syntax = syntax;
11044        next->next = *stack;
11045        (*stack)->prev = next;
11046        *stack = next;
11047}
11048
11049static ALWAYS_INLINE void
11050synstack_pop(struct synstack **stack)
11051{
11052        *stack = (*stack)->next;
11053}
11054
11055/*
11056 * To handle the "." command, a stack of input files is used.  Pushfile
11057 * adds a new entry to the stack and popfile restores the previous level.
11058 */
11059static void
11060pushfile(void)
11061{
11062        struct parsefile *pf;
11063
11064        pf = ckzalloc(sizeof(*pf));
11065        pf->prev = g_parsefile;
11066        pf->pf_fd = -1;
11067        /*pf->strpush = NULL; - ckzalloc did it */
11068        /*pf->spfree = NULL;*/
11069        /*pf->basestrpush.prev = NULL;*/
11070        /*pf->unget = 0;*/
11071        g_parsefile = pf;
11072}
11073
11074static void
11075popfile(void)
11076{
11077        struct parsefile *pf = g_parsefile;
11078
11079        if (pf == &basepf)
11080                return;
11081
11082        INT_OFF;
11083        if (pf->pf_fd >= 0)
11084                close(pf->pf_fd);
11085        free(pf->buf);
11086        if (g_parsefile->spfree)
11087                freestrings(g_parsefile->spfree);
11088        while (pf->strpush) {
11089                popstring();
11090                freestrings(g_parsefile->spfree);
11091        }
11092        g_parsefile = pf->prev;
11093        free(pf);
11094        INT_ON;
11095}
11096
11097static void
11098unwindfiles(struct parsefile *stop)
11099{
11100        while (g_parsefile != stop)
11101                popfile();
11102}
11103
11104/*
11105 * Return to top level.
11106 */
11107static void
11108popallfiles(void)
11109{
11110        unwindfiles(&basepf);
11111}
11112
11113/*
11114 * Close the file(s) that the shell is reading commands from.  Called
11115 * after a fork is done.
11116 */
11117static void
11118closescript(void)
11119{
11120        popallfiles();
11121        if (g_parsefile->pf_fd > 0) {
11122                close(g_parsefile->pf_fd);
11123                g_parsefile->pf_fd = 0;
11124        }
11125}
11126
11127/*
11128 * Like setinputfile, but takes an open file descriptor.  Call this with
11129 * interrupts off.
11130 */
11131static void
11132setinputfd(int fd, int push)
11133{
11134        if (push) {
11135                pushfile();
11136                g_parsefile->buf = NULL;
11137        }
11138        g_parsefile->pf_fd = fd;
11139        if (g_parsefile->buf == NULL)
11140                g_parsefile->buf = ckmalloc(IBUFSIZ);
11141        g_parsefile->left_in_buffer = 0;
11142        g_parsefile->left_in_line = 0;
11143        g_parsefile->linno = 1;
11144}
11145
11146/*
11147 * Set the input to take input from a file.  If push is set, push the
11148 * old input onto the stack first.
11149 */
11150static int
11151setinputfile(const char *fname, int flags)
11152{
11153        int fd;
11154
11155        INT_OFF;
11156        fd = open(fname, O_RDONLY | O_CLOEXEC);
11157        if (fd < 0) {
11158                if (flags & INPUT_NOFILE_OK)
11159                        goto out;
11160                exitstatus = 127;
11161                ash_msg_and_raise_perror("can't open '%s'", fname);
11162        }
11163        if (fd < 10)
11164                fd = savefd(fd);
11165        else if (O_CLOEXEC == 0) /* old libc */
11166                close_on_exec_on(fd);
11167
11168        setinputfd(fd, flags & INPUT_PUSH_FILE);
11169 out:
11170        INT_ON;
11171        return fd;
11172}
11173
11174/*
11175 * Like setinputfile, but takes input from a string.
11176 */
11177static void
11178setinputstring(char *string)
11179{
11180        INT_OFF;
11181        pushfile();
11182        g_parsefile->next_to_pgetc = string;
11183        g_parsefile->left_in_line = strlen(string);
11184        g_parsefile->buf = NULL;
11185        g_parsefile->linno = lineno;
11186        INT_ON;
11187}
11188
11189
11190/*
11191 * Routines to check for mail.
11192 */
11193
11194#if ENABLE_ASH_MAIL
11195
11196/* Hash of mtimes of mailboxes */
11197static unsigned mailtime_hash;
11198/* Set if MAIL or MAILPATH is changed. */
11199static smallint mail_var_path_changed;
11200
11201/*
11202 * Print appropriate message(s) if mail has arrived.
11203 * If mail_var_path_changed is set,
11204 * then the value of MAIL has mail_var_path_changed,
11205 * so we just update the values.
11206 */
11207static void
11208chkmail(void)
11209{
11210        const char *mpath;
11211        char *p;
11212        char *q;
11213        unsigned new_hash;
11214        struct stackmark smark;
11215        struct stat statb;
11216
11217        setstackmark(&smark);
11218        mpath = mpathset() ? mpathval() : mailval();
11219        new_hash = 0;
11220        for (;;) {
11221                int len;
11222
11223                len = padvance_magic(&mpath, nullstr, 2);
11224                if (!len)
11225                        break;
11226                p = stackblock();
11227                        break;
11228                if (*p == '\0')
11229                        continue;
11230                for (q = p; *q; q++)
11231                        continue;
11232#if DEBUG
11233                if (q[-1] != '/')
11234                        abort();
11235#endif
11236                q[-1] = '\0';                   /* delete trailing '/' */
11237                if (stat(p, &statb) < 0) {
11238                        continue;
11239                }
11240                /* Very simplistic "hash": just a sum of all mtimes */
11241                new_hash += (unsigned)statb.st_mtime;
11242        }
11243        if (!mail_var_path_changed && mailtime_hash != new_hash) {
11244                if (mailtime_hash != 0)
11245                        out2str("you have mail\n");
11246                mailtime_hash = new_hash;
11247        }
11248        mail_var_path_changed = 0;
11249        popstackmark(&smark);
11250}
11251
11252static void FAST_FUNC
11253changemail(const char *val UNUSED_PARAM)
11254{
11255        mail_var_path_changed = 1;
11256}
11257
11258#endif /* ASH_MAIL */
11259
11260
11261/* ============ ??? */
11262
11263/*
11264 * Set the shell parameters.
11265 */
11266static void
11267setparam(char **argv)
11268{
11269        char **newparam;
11270        char **ap;
11271        int nparam;
11272
11273        for (nparam = 0; argv[nparam]; nparam++)
11274                continue;
11275        ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
11276        while (*argv) {
11277                *ap++ = ckstrdup(*argv++);
11278        }
11279        *ap = NULL;
11280        freeparam(&shellparam);
11281        shellparam.malloced = 1;
11282        shellparam.nparam = nparam;
11283        shellparam.p = newparam;
11284#if ENABLE_ASH_GETOPTS
11285        shellparam.optind = 1;
11286        shellparam.optoff = -1;
11287#endif
11288}
11289
11290/*
11291 * Process shell options.  The global variable argptr contains a pointer
11292 * to the argument list; we advance it past the options.
11293 *
11294 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
11295 * For a non-interactive shell, an error condition encountered
11296 * by a special built-in ... shall cause the shell to write a diagnostic message
11297 * to standard error and exit as shown in the following table:
11298 * Error                                           Special Built-In
11299 * ...
11300 * Utility syntax error (option or operand error)  Shall exit
11301 * ...
11302 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
11303 * we see that bash does not do that (set "finishes" with error code 1 instead,
11304 * and shell continues), and people rely on this behavior!
11305 * Testcase:
11306 * set -o barfoo 2>/dev/null
11307 * echo $?
11308 *
11309 * Oh well. Let's mimic that.
11310 */
11311static int
11312plus_minus_o(char *name, int val)
11313{
11314        int i;
11315
11316        if (name) {
11317                for (i = 0; i < NOPTS; i++) {
11318                        if (strcmp(name, optnames(i)) == 0) {
11319                                optlist[i] = val;
11320                                return 0;
11321                        }
11322                }
11323                ash_msg("illegal option %co %s", val ? '-' : '+', name);
11324                return 1;
11325        }
11326        for (i = 0; i < NOPTS; i++) {
11327                if (optnames(i)[0] == '\0')
11328                        continue;
11329                if (val) {
11330                        out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11331                } else {
11332                        out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11333                }
11334        }
11335        return 0;
11336}
11337static void
11338setoption(int flag, int val)
11339{
11340        int i;
11341
11342        for (i = 0; i < NOPTS; i++) {
11343                if (optletters(i) == flag && optnames(i)[0] != '\0') {
11344                        optlist[i] = val;
11345                        return;
11346                }
11347        }
11348        ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
11349        /* NOTREACHED */
11350}
11351/* If login_sh is not NULL, we are called to parse command line opts,
11352 * not "set -opts"
11353 */
11354static int
11355options(int *login_sh)
11356{
11357        char *p;
11358        int val;
11359        int c;
11360
11361        if (login_sh)
11362                minusc = NULL;
11363        while ((p = *argptr) != NULL) {
11364                c = *p++;
11365                if (c != '-' && c != '+')
11366                        break;
11367                argptr++;
11368                val = 0; /* val = 0 if c == '+' */
11369                if (c == '-') {
11370                        val = 1;
11371                        if (p[0] == '\0' || LONE_DASH(p)) {
11372                                if (!login_sh) {
11373                                        /* "-" means turn off -x and -v */
11374                                        if (p[0] == '\0')
11375                                                xflag = vflag = 0;
11376                                        /* "--" means reset params */
11377                                        else if (*argptr == NULL)
11378                                                setparam(argptr);
11379                                }
11380                                break;    /* "-" or "--" terminates options */
11381                        }
11382                }
11383                /* first char was + or - */
11384                while ((c = *p++) != '\0') {
11385                        if (login_sh) {
11386                                /* bash 3.2 indeed handles -c CMD and +c CMD the same */
11387                                if (c == 'c') {
11388                                        minusc = p; /* command is after shell args */
11389                                        cflag = 1;
11390                                        continue;
11391                                }
11392                                if (c == 's') { /* -s, +s */
11393                                        sflag = 1;
11394                                        continue;
11395                                }
11396                                if (c == 'i') { /* -i, +i */
11397                                        iflag = 1;
11398                                        continue;
11399                                }
11400                                if (c == 'l') {
11401                                        *login_sh = 1; /* -l or +l == --login */
11402                                        continue;
11403                                }
11404                                /* bash does not accept +-login, we also won't */
11405                                if (val && (c == '-')) { /* long options */
11406                                        if (strcmp(p, "login") == 0) {
11407                                                *login_sh = 1;
11408                                        }
11409                                        break;
11410                                }
11411                        }
11412                        if (c == 'o') {
11413                                if (plus_minus_o(*argptr, val)) {
11414                                        /* it already printed err message */
11415                                        return 1; /* error */
11416                                }
11417                                if (*argptr)
11418                                        argptr++;
11419                        } else {
11420                                setoption(c, val);
11421                        }
11422                }
11423        }
11424        return 0;
11425}
11426
11427/*
11428 * The shift builtin command.
11429 */
11430static int FAST_FUNC
11431shiftcmd(int argc UNUSED_PARAM, char **argv)
11432{
11433        int n;
11434        char **ap1, **ap2;
11435
11436        n = 1;
11437        if (argv[1])
11438                n = number(argv[1]);
11439        if (n > shellparam.nparam)
11440                return 1;
11441        INT_OFF;
11442        shellparam.nparam -= n;
11443        for (ap1 = shellparam.p; --n >= 0; ap1++) {
11444                if (shellparam.malloced)
11445                        free(*ap1);
11446        }
11447        ap2 = shellparam.p;
11448        while ((*ap2++ = *ap1++) != NULL)
11449                continue;
11450#if ENABLE_ASH_GETOPTS
11451        shellparam.optind = 1;
11452        shellparam.optoff = -1;
11453#endif
11454        INT_ON;
11455        return 0;
11456}
11457
11458/*
11459 * POSIX requires that 'set' (but not export or readonly) output the
11460 * variables in lexicographic order - by the locale's collating order (sigh).
11461 * Maybe we could keep them in an ordered balanced binary tree
11462 * instead of hashed lists.
11463 * For now just roll 'em through qsort for printing...
11464 */
11465static int
11466showvars(const char *sep_prefix, int on, int off)
11467{
11468        const char *sep;
11469        char **ep, **epend;
11470
11471        ep = listvars(on, off, /*strlist:*/ NULL, &epend);
11472        qsort(ep, epend - ep, sizeof(char *), vpcmp);
11473
11474        sep = *sep_prefix ? " " : sep_prefix;
11475
11476        for (; ep < epend; ep++) {
11477                const char *p;
11478                const char *q;
11479
11480                p = endofname(*ep);
11481/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11482 * makes "export -p" to have output not suitable for "eval":
11483 * import os
11484 * os.environ["test-test"]="test"
11485 * if os.fork() == 0:
11486 *   os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ])  # fixes this
11487 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11488 */
11489                q = nullstr;
11490                if (*p == '=')
11491                        q = single_quote(++p);
11492                out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11493        }
11494        return 0;
11495}
11496
11497/*
11498 * The set command builtin.
11499 */
11500static int FAST_FUNC
11501setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11502{
11503        int retval;
11504
11505        if (!argv[1])
11506                return showvars(nullstr, 0, VUNSET);
11507
11508        INT_OFF;
11509        retval = options(/*login_sh:*/ NULL);
11510        if (retval == 0) { /* if no parse error... */
11511                optschanged();
11512                if (*argptr != NULL) {
11513                        setparam(argptr);
11514                }
11515        }
11516        INT_ON;
11517        return retval;
11518}
11519
11520#if ENABLE_ASH_RANDOM_SUPPORT
11521static void FAST_FUNC
11522change_random(const char *value)
11523{
11524        uint32_t t;
11525
11526        if (value == NULL) {
11527                /* "get", generate */
11528                t = next_random(&random_gen);
11529                /* set without recursion */
11530                setvar(vrandom.var_text, utoa(t), VNOFUNC);
11531                vrandom.flags &= ~VNOFUNC;
11532        } else {
11533                /* set/reset */
11534                t = strtoul(value, NULL, 10);
11535                INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
11536        }
11537}
11538#endif
11539
11540#if BASH_EPOCH_VARS
11541static void FAST_FUNC
11542change_epoch(struct var *vepoch, const char *fmt)
11543{
11544        struct timeval tv;
11545        char buffer[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
11546
11547        xgettimeofday(&tv);
11548        sprintf(buffer, fmt, (unsigned long long)tv.tv_sec, (unsigned)tv.tv_usec);
11549        setvar(vepoch->var_text, buffer, VNOFUNC);
11550        vepoch->flags &= ~VNOFUNC;
11551}
11552
11553static void FAST_FUNC
11554change_seconds(const char *value UNUSED_PARAM)
11555{
11556        change_epoch(&vepochs, "%llu");
11557}
11558
11559static void FAST_FUNC
11560change_realtime(const char *value UNUSED_PARAM)
11561{
11562        change_epoch(&vepochr, "%llu.%06u");
11563}
11564#endif
11565
11566#if ENABLE_ASH_GETOPTS
11567static int
11568getopts(char *optstr, char *optvar, char **optfirst)
11569{
11570        char *p, *q;
11571        char c = '?';
11572        int done = 0;
11573        char sbuf[2];
11574        char **optnext;
11575        int ind = shellparam.optind;
11576        int off = shellparam.optoff;
11577
11578        sbuf[1] = '\0';
11579
11580        shellparam.optind = -1;
11581        optnext = optfirst + ind - 1;
11582
11583        if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
11584                p = NULL;
11585        else
11586                p = optnext[-1] + off;
11587        if (p == NULL || *p == '\0') {
11588                /* Current word is done, advance */
11589                p = *optnext;
11590                if (p == NULL || *p != '-' || *++p == '\0') {
11591 atend:
11592                        unsetvar("OPTARG");
11593                        p = NULL;
11594                        done = 1;
11595                        goto out;
11596                }
11597                optnext++;
11598                if (LONE_DASH(p))        /* check for "--" */
11599                        goto atend;
11600        }
11601
11602        c = *p++;
11603        for (q = optstr; *q != c;) {
11604                if (*q == '\0') {
11605                        /* OPTERR is a bashism */
11606                        const char *cp = lookupvar("OPTERR");
11607                        if ((cp && LONE_CHAR(cp, '0'))
11608                         || (optstr[0] == ':')
11609                        ) {
11610                                sbuf[0] = c;
11611                                /*sbuf[1] = '\0'; - already is */
11612                                setvar0("OPTARG", sbuf);
11613                        } else {
11614                                fprintf(stderr, "Illegal option -%c\n", c);
11615                                unsetvar("OPTARG");
11616                        }
11617                        c = '?';
11618                        goto out;
11619                }
11620                if (*++q == ':')
11621                        q++;
11622        }
11623
11624        if (*++q == ':') {
11625                if (*p == '\0' && (p = *optnext) == NULL) {
11626                        /* OPTERR is a bashism */
11627                        const char *cp = lookupvar("OPTERR");
11628                        if ((cp && LONE_CHAR(cp, '0'))
11629                         || (optstr[0] == ':')
11630                        ) {
11631                                sbuf[0] = c;
11632                                /*sbuf[1] = '\0'; - already is */
11633                                setvar0("OPTARG", sbuf);
11634                                c = ':';
11635                        } else {
11636                                fprintf(stderr, "No arg for -%c option\n", c);
11637                                unsetvar("OPTARG");
11638                                c = '?';
11639                        }
11640                        goto out;
11641                }
11642
11643                if (p == *optnext)
11644                        optnext++;
11645                setvar0("OPTARG", p);
11646                p = NULL;
11647        } else
11648                setvar0("OPTARG", nullstr);
11649 out:
11650        ind = optnext - optfirst + 1;
11651        setvar("OPTIND", itoa(ind), VNOFUNC);
11652        sbuf[0] = c;
11653        /*sbuf[1] = '\0'; - already is */
11654        setvar0(optvar, sbuf);
11655
11656        shellparam.optoff = p ? p - *(optnext - 1) : -1;
11657        shellparam.optind = ind;
11658
11659        return done;
11660}
11661
11662/*
11663 * The getopts builtin.  Shellparam.optnext points to the next argument
11664 * to be processed.  Shellparam.optptr points to the next character to
11665 * be processed in the current argument.  If shellparam.optnext is NULL,
11666 * then it's the first time getopts has been called.
11667 */
11668static int FAST_FUNC
11669getoptscmd(int argc, char **argv)
11670{
11671        char **optbase;
11672
11673        if (argc < 3)
11674                ash_msg_and_raise_error("usage: getopts optstring var [arg]");
11675        if (argc == 3) {
11676                optbase = shellparam.p;
11677                if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
11678                        shellparam.optind = 1;
11679                        shellparam.optoff = -1;
11680                }
11681        } else {
11682                optbase = &argv[3];
11683                if ((unsigned)shellparam.optind > argc - 2) {
11684                        shellparam.optind = 1;
11685                        shellparam.optoff = -1;
11686                }
11687        }
11688
11689        return getopts(argv[1], argv[2], optbase);
11690}
11691#endif /* ASH_GETOPTS */
11692
11693
11694/* ============ Shell parser */
11695
11696struct heredoc {
11697        struct heredoc *next;   /* next here document in list */
11698        union node *here;       /* redirection node */
11699        char *eofmark;          /* string indicating end of input */
11700        smallint striptabs;     /* if set, strip leading tabs */
11701};
11702
11703static smallint tokpushback;           /* last token pushed back */
11704static smallint quoteflag;             /* set if (part of) last token was quoted */
11705static token_id_t lasttoken;           /* last token read (integer id Txxx) */
11706static struct heredoc *heredoclist;    /* list of here documents to read */
11707static char *wordtext;                 /* text of last word returned by readtoken */
11708static struct nodelist *backquotelist;
11709static union node *redirnode;
11710static struct heredoc *heredoc;
11711
11712static const char *
11713tokname(char *buf, int tok)
11714{
11715        if (tok < TSEMI)
11716                return tokname_array[tok];
11717        sprintf(buf, "\"%s\"", tokname_array[tok]);
11718        return buf;
11719}
11720
11721/* raise_error_unexpected_syntax:
11722 * Called when an unexpected token is read during the parse.  The argument
11723 * is the token that is expected, or -1 if more than one type of token can
11724 * occur at this point.
11725 */
11726static void raise_error_unexpected_syntax(int) NORETURN;
11727static void
11728raise_error_unexpected_syntax(int token)
11729{
11730        char msg[64];
11731        char buf[16];
11732        int l;
11733
11734        l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
11735        if (token >= 0)
11736                sprintf(msg + l, " (expecting %s)", tokname(buf, token));
11737        raise_error_syntax(msg);
11738        /* NOTREACHED */
11739}
11740
11741/* parsing is heavily cross-recursive, need these forward decls */
11742static union node *andor(void);
11743static union node *pipeline(void);
11744static union node *parse_command(void);
11745static void parseheredoc(void);
11746static int readtoken(void);
11747
11748static union node *
11749list(int nlflag)
11750{
11751        int chknl = nlflag & 1 ? 0 : CHKNL;
11752        union node *n1, *n2, *n3;
11753        int tok;
11754
11755        n1 = NULL;
11756        for (;;) {
11757                checkkwd = chknl | CHKKWD | CHKALIAS;
11758                tok = readtoken();
11759                switch (tok) {
11760                case TNL:
11761                        parseheredoc();
11762                        return n1;
11763
11764                case TEOF:
11765                        if (!n1 && !chknl)
11766                                n1 = NODE_EOF;
11767 out_eof:
11768                        parseheredoc();
11769                        tokpushback++;
11770                        lasttoken = TEOF;
11771                        return n1;
11772                }
11773
11774                tokpushback++;
11775                if (nlflag == 2 && ((1 << tok) & tokendlist))
11776                        return n1;
11777                nlflag |= 2;
11778
11779                n2 = andor();
11780                tok = readtoken();
11781                if (tok == TBACKGND) {
11782                        if (n2->type == NPIPE) {
11783                                n2->npipe.pipe_backgnd = 1;
11784                        } else {
11785                                if (n2->type != NREDIR) {
11786                                        n3 = stzalloc(sizeof(struct nredir));
11787                                        n3->nredir.n = n2;
11788                                        /*n3->nredir.redirect = NULL; - stzalloc did it */
11789                                        n2 = n3;
11790                                }
11791                                n2->type = NBACKGND;
11792                        }
11793                }
11794                if (n1 == NULL) {
11795                        n1 = n2;
11796                } else {
11797                        n3 = stzalloc(sizeof(struct nbinary));
11798                        n3->type = NSEMI;
11799                        n3->nbinary.ch1 = n1;
11800                        n3->nbinary.ch2 = n2;
11801                        n1 = n3;
11802                }
11803                switch (tok) {
11804                case TEOF:
11805                        goto out_eof;
11806                case TNL:
11807                        tokpushback = 1;
11808                        /* fall through */
11809                case TBACKGND:
11810                case TSEMI:
11811                        break;
11812                default:
11813                        if (!chknl)
11814                                raise_error_unexpected_syntax(-1);
11815                        tokpushback = 1;
11816                        return n1;
11817                }
11818        }
11819}
11820
11821static union node *
11822andor(void)
11823{
11824        union node *n1, *n2, *n3;
11825        int t;
11826
11827        n1 = pipeline();
11828        for (;;) {
11829                t = readtoken();
11830                if (t == TAND) {
11831                        t = NAND;
11832                } else if (t == TOR) {
11833                        t = NOR;
11834                } else {
11835                        tokpushback = 1;
11836                        return n1;
11837                }
11838                checkkwd = CHKNL | CHKKWD | CHKALIAS;
11839                n2 = pipeline();
11840                n3 = stzalloc(sizeof(struct nbinary));
11841                n3->type = t;
11842                n3->nbinary.ch1 = n1;
11843                n3->nbinary.ch2 = n2;
11844                n1 = n3;
11845        }
11846}
11847
11848static union node *
11849pipeline(void)
11850{
11851        union node *n1, *n2, *pipenode;
11852        struct nodelist *lp, *prev;
11853        int negate;
11854
11855        negate = 0;
11856        TRACE(("pipeline: entered\n"));
11857        if (readtoken() == TNOT) {
11858                negate = !negate;
11859                checkkwd = CHKKWD | CHKALIAS;
11860        } else
11861                tokpushback = 1;
11862        n1 = parse_command();
11863        if (readtoken() == TPIPE) {
11864                pipenode = stzalloc(sizeof(struct npipe));
11865                pipenode->type = NPIPE;
11866                /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
11867                lp = stzalloc(sizeof(struct nodelist));
11868                pipenode->npipe.cmdlist = lp;
11869                lp->n = n1;
11870                do {
11871                        prev = lp;
11872                        lp = stzalloc(sizeof(struct nodelist));
11873                        checkkwd = CHKNL | CHKKWD | CHKALIAS;
11874                        lp->n = parse_command();
11875                        prev->next = lp;
11876                } while (readtoken() == TPIPE);
11877                lp->next = NULL;
11878                n1 = pipenode;
11879        }
11880        tokpushback = 1;
11881        if (negate) {
11882                n2 = stzalloc(sizeof(struct nnot));
11883                n2->type = NNOT;
11884                n2->nnot.com = n1;
11885                return n2;
11886        }
11887        return n1;
11888}
11889
11890static union node *
11891makename(void)
11892{
11893        union node *n;
11894
11895        n = stzalloc(sizeof(struct narg));
11896        n->type = NARG;
11897        /*n->narg.next = NULL; - stzalloc did it */
11898        n->narg.text = wordtext;
11899        n->narg.backquote = backquotelist;
11900        return n;
11901}
11902
11903static void
11904fixredir(union node *n, const char *text, int err)
11905{
11906        int fd;
11907
11908        TRACE(("Fix redir %s %d\n", text, err));
11909        if (!err)
11910                n->ndup.vname = NULL;
11911
11912        fd = bb_strtou(text, NULL, 10);
11913        if (!errno && fd >= 0)
11914                n->ndup.dupfd = fd;
11915        else if (LONE_DASH(text))
11916                n->ndup.dupfd = -1;
11917        else {
11918                if (err)
11919                        raise_error_syntax("bad fd number");
11920                n->ndup.vname = makename();
11921        }
11922}
11923
11924static void
11925parsefname(void)
11926{
11927        union node *n = redirnode;
11928
11929        if (n->type == NHERE)
11930                checkkwd = CHKEOFMARK;
11931        if (readtoken() != TWORD)
11932                raise_error_unexpected_syntax(-1);
11933        if (n->type == NHERE) {
11934                struct heredoc *here = heredoc;
11935                struct heredoc *p;
11936
11937                if (quoteflag == 0)
11938                        n->type = NXHERE;
11939                TRACE(("Here document %d\n", n->type));
11940                rmescapes(wordtext, 0, NULL);
11941                here->eofmark = wordtext;
11942                here->next = NULL;
11943                if (heredoclist == NULL)
11944                        heredoclist = here;
11945                else {
11946                        for (p = heredoclist; p->next; p = p->next)
11947                                continue;
11948                        p->next = here;
11949                }
11950        } else if (n->type == NTOFD || n->type == NFROMFD) {
11951                fixredir(n, wordtext, 0);
11952        } else {
11953                n->nfile.fname = makename();
11954        }
11955}
11956
11957static union node *
11958simplecmd(void)
11959{
11960        union node *args, **app;
11961        union node *n = NULL;
11962        union node *vars, **vpp;
11963        union node **rpp, *redir;
11964        int savecheckkwd;
11965        int savelinno;
11966#if BASH_TEST2
11967        smallint double_brackets_flag = 0;
11968#endif
11969        IF_BASH_FUNCTION(smallint function_flag = 0;)
11970
11971        args = NULL;
11972        app = &args;
11973        vars = NULL;
11974        vpp = &vars;
11975        redir = NULL;
11976        rpp = &redir;
11977
11978        savecheckkwd = CHKALIAS;
11979        savelinno = g_parsefile->linno;
11980        for (;;) {
11981                int t;
11982                checkkwd = savecheckkwd;
11983                t = readtoken();
11984                switch (t) {
11985#if BASH_FUNCTION
11986                case TFUNCTION:
11987                        if (readtoken() != TWORD)
11988                                raise_error_unexpected_syntax(TWORD);
11989                        tokpushback = 1;
11990                        function_flag = 1;
11991                        break;
11992#endif
11993#if BASH_TEST2
11994                case TAND: /* "&&" */
11995                case TOR: /* "||" */
11996                        if (!double_brackets_flag) {
11997                                tokpushback = 1;
11998                                goto out;
11999                        }
12000                        /* pass "&&" or "||" to [[ ]] as literal args */
12001                        wordtext = (char *) (t == TAND ? "&&" : "||");
12002#endif
12003                case TWORD:
12004                        n = stzalloc(sizeof(struct narg));
12005                        n->type = NARG;
12006                        /*n->narg.next = NULL; - stzalloc did it */
12007                        n->narg.text = wordtext;
12008#if BASH_TEST2
12009                        if (strcmp("[[", wordtext) == 0)
12010                                double_brackets_flag = 1;
12011                        else if (strcmp("]]", wordtext) == 0)
12012                                double_brackets_flag = 0;
12013#endif
12014                        n->narg.backquote = backquotelist;
12015                        if (savecheckkwd && isassignment(wordtext)) {
12016                                *vpp = n;
12017                                vpp = &n->narg.next;
12018                        } else {
12019                                *app = n;
12020                                app = &n->narg.next;
12021                                savecheckkwd = 0;
12022                        }
12023#if BASH_FUNCTION
12024                        if (function_flag) {
12025                                checkkwd = CHKNL | CHKKWD;
12026                                t = readtoken();
12027                                tokpushback = 1;
12028                                switch (t) {
12029                                case TBEGIN:
12030                                case TIF:
12031                                case TCASE:
12032                                case TUNTIL:
12033                                case TWHILE:
12034                                case TFOR:
12035                                        goto do_func;
12036                                case TLP:
12037                                        function_flag = 0;
12038                                        break;
12039# if BASH_TEST2
12040                                case TWORD:
12041                                        if (strcmp("[[", wordtext) == 0)
12042                                                goto do_func;
12043                                        /* fall through */
12044# endif
12045                                default:
12046                                        raise_error_unexpected_syntax(-1);
12047                                }
12048                        }
12049#endif
12050                        break;
12051                case TREDIR:
12052                        *rpp = n = redirnode;
12053                        rpp = &n->nfile.next;
12054                        parsefname();   /* read name of redirection file */
12055                        break;
12056                case TLP:
12057 IF_BASH_FUNCTION(do_func:)
12058                        if (args && app == &args->narg.next
12059                         && !vars && !redir
12060                        ) {
12061                                struct builtincmd *bcmd;
12062                                const char *name;
12063
12064                                /* We have a function */
12065                                if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
12066                                        raise_error_unexpected_syntax(TRP);
12067                                name = n->narg.text;
12068                                if (!goodname(name)
12069                                 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
12070                                ) {
12071                                        raise_error_syntax("bad function name");
12072                                }
12073                                n->type = NDEFUN;
12074                                checkkwd = CHKNL | CHKKWD | CHKALIAS;
12075                                n->ndefun.text = n->narg.text;
12076                                n->ndefun.linno = g_parsefile->linno;
12077                                n->ndefun.body = parse_command();
12078                                return n;
12079                        }
12080                        IF_BASH_FUNCTION(function_flag = 0;)
12081                        /* fall through */
12082                default:
12083                        tokpushback = 1;
12084                        goto out;
12085                }
12086        }
12087 out:
12088        *app = NULL;
12089        *vpp = NULL;
12090        *rpp = NULL;
12091        n = stzalloc(sizeof(struct ncmd));
12092        if (NCMD != 0)
12093                n->type = NCMD;
12094        n->ncmd.linno = savelinno;
12095        n->ncmd.args = args;
12096        n->ncmd.assign = vars;
12097        n->ncmd.redirect = redir;
12098        return n;
12099}
12100
12101static union node *
12102parse_command(void)
12103{
12104        union node *n1, *n2;
12105        union node *ap, **app;
12106        union node *cp, **cpp;
12107        union node *redir, **rpp;
12108        union node **rpp2;
12109        int t;
12110        int savelinno;
12111
12112        redir = NULL;
12113        rpp2 = &redir;
12114
12115        savelinno = g_parsefile->linno;
12116
12117        switch (readtoken()) {
12118        default:
12119                raise_error_unexpected_syntax(-1);
12120                /* NOTREACHED */
12121        case TIF:
12122                n1 = stzalloc(sizeof(struct nif));
12123                n1->type = NIF;
12124                n1->nif.test = list(0);
12125                if (readtoken() != TTHEN)
12126                        raise_error_unexpected_syntax(TTHEN);
12127                n1->nif.ifpart = list(0);
12128                n2 = n1;
12129                while (readtoken() == TELIF) {
12130                        n2->nif.elsepart = stzalloc(sizeof(struct nif));
12131                        n2 = n2->nif.elsepart;
12132                        n2->type = NIF;
12133                        n2->nif.test = list(0);
12134                        if (readtoken() != TTHEN)
12135                                raise_error_unexpected_syntax(TTHEN);
12136                        n2->nif.ifpart = list(0);
12137                }
12138                if (lasttoken == TELSE)
12139                        n2->nif.elsepart = list(0);
12140                else {
12141                        n2->nif.elsepart = NULL;
12142                        tokpushback = 1;
12143                }
12144                t = TFI;
12145                break;
12146        case TWHILE:
12147        case TUNTIL: {
12148                int got;
12149                n1 = stzalloc(sizeof(struct nbinary));
12150                n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
12151                n1->nbinary.ch1 = list(0);
12152                got = readtoken();
12153                if (got != TDO) {
12154                        TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
12155                                        got == TWORD ? wordtext : ""));
12156                        raise_error_unexpected_syntax(TDO);
12157                }
12158                n1->nbinary.ch2 = list(0);
12159                t = TDONE;
12160                break;
12161        }
12162        case TFOR:
12163                if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
12164                        raise_error_syntax("bad for loop variable");
12165                n1 = stzalloc(sizeof(struct nfor));
12166                n1->type = NFOR;
12167                n1->nfor.linno = savelinno;
12168                n1->nfor.var = wordtext;
12169                checkkwd = CHKNL | CHKKWD | CHKALIAS;
12170                if (readtoken() == TIN) {
12171                        app = &ap;
12172                        while (readtoken() == TWORD) {
12173                                n2 = stzalloc(sizeof(struct narg));
12174                                n2->type = NARG;
12175                                /*n2->narg.next = NULL; - stzalloc did it */
12176                                n2->narg.text = wordtext;
12177                                n2->narg.backquote = backquotelist;
12178                                *app = n2;
12179                                app = &n2->narg.next;
12180                        }
12181                        *app = NULL;
12182                        n1->nfor.args = ap;
12183                        if (lasttoken != TNL && lasttoken != TSEMI)
12184                                raise_error_unexpected_syntax(-1);
12185                } else {
12186                        n2 = stzalloc(sizeof(struct narg));
12187                        n2->type = NARG;
12188                        /*n2->narg.next = NULL; - stzalloc did it */
12189                        n2->narg.text = (char *)dolatstr;
12190                        /*n2->narg.backquote = NULL;*/
12191                        n1->nfor.args = n2;
12192                        /*
12193                         * Newline or semicolon here is optional (but note
12194                         * that the original Bourne shell only allowed NL).
12195                         */
12196                        if (lasttoken != TSEMI)
12197                                tokpushback = 1;
12198                }
12199                checkkwd = CHKNL | CHKKWD | CHKALIAS;
12200                if (readtoken() != TDO)
12201                        raise_error_unexpected_syntax(TDO);
12202                n1->nfor.body = list(0);
12203                t = TDONE;
12204                break;
12205        case TCASE:
12206                n1 = stzalloc(sizeof(struct ncase));
12207                n1->type = NCASE;
12208                n1->ncase.linno = savelinno;
12209                if (readtoken() != TWORD)
12210                        raise_error_unexpected_syntax(TWORD);
12211                n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
12212                n2->type = NARG;
12213                /*n2->narg.next = NULL; - stzalloc did it */
12214                n2->narg.text = wordtext;
12215                n2->narg.backquote = backquotelist;
12216                checkkwd = CHKNL | CHKKWD | CHKALIAS;
12217                if (readtoken() != TIN)
12218                        raise_error_unexpected_syntax(TIN);
12219                cpp = &n1->ncase.cases;
12220 next_case:
12221                checkkwd = CHKNL | CHKKWD;
12222                t = readtoken();
12223                while (t != TESAC) {
12224                        if (lasttoken == TLP)
12225                                readtoken();
12226                        *cpp = cp = stzalloc(sizeof(struct nclist));
12227                        cp->type = NCLIST;
12228                        app = &cp->nclist.pattern;
12229                        for (;;) {
12230                                *app = ap = stzalloc(sizeof(struct narg));
12231                                ap->type = NARG;
12232                                /*ap->narg.next = NULL; - stzalloc did it */
12233                                ap->narg.text = wordtext;
12234                                ap->narg.backquote = backquotelist;
12235                                if (readtoken() != TPIPE)
12236                                        break;
12237                                app = &ap->narg.next;
12238                                readtoken();
12239                        }
12240                        //ap->narg.next = NULL;
12241                        if (lasttoken != TRP)
12242                                raise_error_unexpected_syntax(TRP);
12243                        cp->nclist.body = list(2);
12244
12245                        cpp = &cp->nclist.next;
12246
12247                        checkkwd = CHKNL | CHKKWD;
12248                        t = readtoken();
12249                        if (t != TESAC) {
12250                                if (t != TENDCASE)
12251                                        raise_error_unexpected_syntax(TENDCASE);
12252                                goto next_case;
12253                        }
12254                }
12255                *cpp = NULL;
12256                goto redir;
12257        case TLP:
12258                n1 = stzalloc(sizeof(struct nredir));
12259                n1->type = NSUBSHELL;
12260                n1->nredir.linno = savelinno;
12261                n1->nredir.n = list(0);
12262                /*n1->nredir.redirect = NULL; - stzalloc did it */
12263                t = TRP;
12264                break;
12265        case TBEGIN:
12266                n1 = list(0);
12267                t = TEND;
12268                break;
12269        IF_BASH_FUNCTION(case TFUNCTION:)
12270        case TWORD:
12271        case TREDIR:
12272                tokpushback = 1;
12273                return simplecmd();
12274        }
12275
12276        if (readtoken() != t)
12277                raise_error_unexpected_syntax(t);
12278
12279 redir:
12280        /* Now check for redirection which may follow command */
12281        checkkwd = CHKKWD | CHKALIAS;
12282        rpp = rpp2;
12283        while (readtoken() == TREDIR) {
12284                *rpp = n2 = redirnode;
12285                rpp = &n2->nfile.next;
12286                parsefname();
12287        }
12288        tokpushback = 1;
12289        *rpp = NULL;
12290        if (redir) {
12291                if (n1->type != NSUBSHELL) {
12292                        n2 = stzalloc(sizeof(struct nredir));
12293                        n2->type = NREDIR;
12294                        n2->nredir.linno = savelinno;
12295                        n2->nredir.n = n1;
12296                        n1 = n2;
12297                }
12298                n1->nredir.redirect = redir;
12299        }
12300        return n1;
12301}
12302
12303#if BASH_DOLLAR_SQUOTE
12304static int
12305decode_dollar_squote(void)
12306{
12307        static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
12308        int c, cnt;
12309        char *p;
12310        char buf[4];
12311
12312        c = pgetc();
12313        p = strchr(C_escapes, c);
12314        if (p) {
12315                buf[0] = c;
12316                p = buf;
12317                cnt = 3;
12318                if ((unsigned char)(c - '0') <= 7) { /* \ooo */
12319                        do {
12320                                c = pgetc();
12321                                *++p = c;
12322                        } while ((unsigned char)(c - '0') <= 7 && --cnt);
12323                        pungetc();
12324                } else if (c == 'x') { /* \xHH */
12325                        do {
12326                                c = pgetc();
12327                                *++p = c;
12328                        } while (isxdigit(c) && --cnt);
12329                        pungetc();
12330                        if (cnt == 3) { /* \x but next char is "bad" */
12331                                c = 'x';
12332                                goto unrecognized;
12333                        }
12334                } else { /* simple seq like \\ or \t */
12335                        p++;
12336                }
12337                *p = '\0';
12338                p = buf;
12339                c = bb_process_escape_sequence((void*)&p);
12340        } else { /* unrecognized "\z": print both chars unless ' or " */
12341                if (c != '\'' && c != '"') {
12342 unrecognized:
12343                        c |= 0x100; /* "please encode \, then me" */
12344                }
12345        }
12346        return c;
12347}
12348#endif
12349
12350/* Used by expandstr to get here-doc like behaviour. */
12351#define FAKEEOFMARK ((char*)(uintptr_t)1)
12352
12353static ALWAYS_INLINE int
12354realeofmark(const char *eofmark)
12355{
12356        return eofmark && eofmark != FAKEEOFMARK;
12357}
12358
12359/*
12360 * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
12361 * is not NULL, read a here document.  In the latter case, eofmark is the
12362 * word which marks the end of the document and striptabs is true if
12363 * leading tabs should be stripped from the document.  The argument c
12364 * is the first character of the input token or document.
12365 *
12366 * Because C does not have internal subroutines, I have simulated them
12367 * using goto's to implement the subroutine linkage.  The following macros
12368 * will run code that appears at the end of readtoken1.
12369 */
12370#define CHECKEND()      {goto checkend; checkend_return:;}
12371#define PARSEREDIR()    {goto parseredir; parseredir_return:;}
12372#define PARSESUB()      {goto parsesub; parsesub_return:;}
12373#define PARSEBACKQOLD() {style = OLD; goto parsebackq; parsebackq_oldreturn:;}
12374#define PARSEBACKQNEW() {style = NEW; goto parsebackq; parsebackq_newreturn:;}
12375#define PARSEPROCSUB()  {style = PSUB; goto parsebackq; parsebackq_psreturn:;}
12376#define PARSEARITH()    {goto parsearith; parsearith_return:;}
12377static int
12378readtoken1(int c, int syntax, char *eofmark, int striptabs)
12379{
12380        /* NB: syntax parameter fits into smallint */
12381        /* c parameter is an unsigned char or PEOF */
12382        char *out;
12383        size_t len;
12384        struct nodelist *bqlist;
12385        smallint quotef;
12386        smallint style;
12387        enum { OLD, NEW, PSUB };
12388#define oldstyle (style == OLD)
12389        smallint pssyntax;   /* we are expanding a prompt string */
12390        IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
12391        /* syntax stack */
12392        struct synstack synbase = { };
12393        struct synstack *synstack = &synbase;
12394
12395#if ENABLE_ASH_EXPAND_PRMT
12396        pssyntax = (syntax == PSSYNTAX);
12397        if (pssyntax)
12398                syntax = DQSYNTAX;
12399#else
12400        pssyntax = 0; /* constant */
12401#endif
12402        synstack->syntax = syntax;
12403
12404        if (syntax == DQSYNTAX)
12405                synstack->dblquote = 1;
12406        quotef = 0;
12407        bqlist = NULL;
12408
12409        STARTSTACKSTR(out);
12410 loop:
12411        /* For each line, until end of word */
12412        CHECKEND();     /* set c to PEOF if at end of here document */
12413        for (;;) {      /* until end of line or end of word */
12414                CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
12415                switch (SIT(c, synstack->syntax)) {
12416                case CNL:       /* '\n' */
12417                        if (synstack->syntax == BASESYNTAX
12418                         && !synstack->varnest
12419                        ) {
12420                                goto endword;   /* exit outer loop */
12421                        }
12422                        USTPUTC(c, out);
12423                        nlprompt();
12424                        c = pgetc_top(synstack);
12425                        goto loop;              /* continue outer loop */
12426                case CWORD:
12427                        USTPUTC(c, out);
12428                        break;
12429                case CCTL:
12430#if BASH_DOLLAR_SQUOTE
12431                        if (c == '\\' && bash_dollar_squote) {
12432                                c = decode_dollar_squote();
12433                                if (c == '\0') {
12434                                        /* skip $'\000', $'\x00' (like bash) */
12435                                        break;
12436                                }
12437                                if (c & 0x100) {
12438                                        /* Unknown escape. Encode as '\z' */
12439                                        c = (unsigned char)c;
12440                                        if (eofmark == NULL || synstack->dblquote)
12441                                                USTPUTC(CTLESC, out);
12442                                        USTPUTC('\\', out);
12443                                }
12444                        }
12445#endif
12446                        if (!eofmark || synstack->dblquote || synstack->varnest)
12447                                USTPUTC(CTLESC, out);
12448                        USTPUTC(c, out);
12449                        break;
12450                case CBACK:     /* backslash */
12451                        c = pgetc();
12452                        if (c == PEOF) {
12453                                USTPUTC(CTLESC, out);
12454                                USTPUTC('\\', out);
12455                                pungetc();
12456                        } else {
12457                                if (pssyntax && c == '$') {
12458                                        USTPUTC(CTLESC, out);
12459                                        USTPUTC('\\', out);
12460                                }
12461                                /* Backslash is retained if we are in "str"
12462                                 * and next char isn't dquote-special.
12463                                 */
12464                                if (synstack->dblquote
12465                                 && c != '\\'
12466                                 && c != '`'
12467                                 && c != '$'
12468                                 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12469                                 && (c != '}' || !synstack->varnest)
12470                                ) {
12471                                        USTPUTC(CTLESC, out); /* protect '\' from glob */
12472                                        USTPUTC('\\', out);
12473                                }
12474                                USTPUTC(CTLESC, out);
12475                                USTPUTC(c, out);
12476                                quotef = 1;
12477                        }
12478                        break;
12479                case CSQUOTE:
12480                        synstack->syntax = SQSYNTAX;
12481 quotemark:
12482                        if (eofmark == NULL) {
12483                                USTPUTC(CTLQUOTEMARK, out);
12484                        }
12485                        break;
12486                case CDQUOTE:
12487                        synstack->syntax = DQSYNTAX;
12488                        synstack->dblquote = 1;
12489 toggledq:
12490                        if (synstack->varnest)
12491                                synstack->innerdq ^= 1;
12492                        goto quotemark;
12493                case CENDQUOTE:
12494                        IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
12495                        if (eofmark != NULL && synstack->varnest == 0) {
12496                                USTPUTC(c, out);
12497                                break;
12498                        }
12499
12500                        if (synstack->dqvarnest == 0) {
12501                                synstack->syntax = BASESYNTAX;
12502                                synstack->dblquote = 0;
12503                        }
12504
12505                        quotef = 1;
12506
12507                        if (c == '"')
12508                                goto toggledq;
12509
12510                        goto quotemark;
12511                case CVAR:      /* '$' */
12512                        PARSESUB();             /* parse substitution */
12513                        break;
12514                case CENDVAR:   /* '}' */
12515                        if (!synstack->innerdq && synstack->varnest > 0) {
12516                                if (!--synstack->varnest && synstack->varpushed)
12517                                        synstack_pop(&synstack);
12518                                else if (synstack->dqvarnest > 0)
12519                                        synstack->dqvarnest--;
12520                                c = CTLENDVAR;
12521                        }
12522                        USTPUTC(c, out);
12523                        break;
12524#if ENABLE_FEATURE_SH_MATH
12525                case CLP:       /* '(' in arithmetic */
12526                        synstack->parenlevel++;
12527                        USTPUTC(c, out);
12528                        break;
12529                case CRP:       /* ')' in arithmetic */
12530                        if (synstack->parenlevel > 0) {
12531                                synstack->parenlevel--;
12532                        } else {
12533                                if (pgetc_eatbnl() == ')') {
12534                                        c = CTLENDARI;
12535                                        synstack_pop(&synstack);
12536                                } else {
12537                                        /*
12538                                         * unbalanced parens
12539                                         * (don't 2nd guess - no error)
12540                                         */
12541                                        pungetc();
12542                                }
12543                        }
12544                        USTPUTC(c, out);
12545                        break;
12546#endif
12547                case CBQUOTE:   /* '`' */
12548                        if (checkkwd & CHKEOFMARK) {
12549                                quotef = 1;
12550                                USTPUTC('`', out);
12551                                break;
12552                        }
12553
12554                        PARSEBACKQOLD();
12555                        break;
12556                case CENDFILE:
12557                        goto endword;           /* exit outer loop */
12558                default:
12559                        if (synstack->varnest == 0) {
12560#if BASH_REDIR_OUTPUT
12561                                if (c == '&') {
12562//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
12563                                        if (pgetc() == '>')
12564                                                c = 0x100 + '>'; /* flag &> */
12565                                        pungetc();
12566                                }
12567#endif
12568#if BASH_PROCESS_SUBST
12569                                if (c == '<' || c == '>') {
12570                                        if (pgetc() == '(') {
12571                                                PARSEPROCSUB();
12572                                                break;
12573                                        }
12574                                        pungetc();
12575                                }
12576#endif
12577                                goto endword;   /* exit outer loop */
12578                        }
12579                        USTPUTC(c, out);
12580                }
12581                c = pgetc_top(synstack);
12582        } /* for (;;) */
12583 endword:
12584
12585#if ENABLE_FEATURE_SH_MATH
12586        if (synstack->syntax == ARISYNTAX)
12587                raise_error_syntax("missing '))'");
12588#endif
12589        if (synstack->syntax != BASESYNTAX && eofmark == NULL)
12590                raise_error_syntax("unterminated quoted string");
12591        if (synstack->varnest != 0) {
12592                /* { */
12593                raise_error_syntax("missing '}'");
12594        }
12595        USTPUTC('\0', out);
12596        len = out - (char *)stackblock();
12597        out = stackblock();
12598        if (eofmark == NULL) {
12599                if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
12600                 && quotef == 0
12601                ) {
12602                        if (isdigit_str9(out)) {
12603                                PARSEREDIR(); /* passed as params: out, c */
12604                                lasttoken = TREDIR;
12605                                return lasttoken;
12606                        }
12607                        /* else: non-number X seen, interpret it
12608                         * as "NNNX>file" = "NNNX >file" */
12609                }
12610                pungetc();
12611        }
12612        quoteflag = quotef;
12613        backquotelist = bqlist;
12614        grabstackblock(len);
12615        wordtext = out;
12616        lasttoken = TWORD;
12617        return lasttoken;
12618/* end of readtoken routine */
12619
12620/*
12621 * Check to see whether we are at the end of the here document.  When this
12622 * is called, c is set to the first character of the next input line.  If
12623 * we are at the end of the here document, this routine sets the c to PEOF.
12624 */
12625checkend: {
12626        if (realeofmark(eofmark)) {
12627                int markloc;
12628                char *p;
12629
12630                if (striptabs) {
12631                        while (c == '\t')
12632                                c = pgetc();
12633                }
12634
12635                markloc = out - (char *)stackblock();
12636                for (p = eofmark; STPUTC(c, out), *p; p++) {
12637                        if (c != *p)
12638                                goto more_heredoc;
12639                        /* FIXME: fails for backslash-newlined terminator:
12640                         * cat <<EOF
12641                         * ...
12642                         * EO\
12643                         * F
12644                         * (see heredoc_bkslash_newline2.tests)
12645                         */
12646                        c = pgetc();
12647                }
12648
12649                if (c == '\n' || c == PEOF) {
12650                        c = PEOF;
12651                        if (trap_depth == 0)
12652                                g_parsefile->linno++;
12653                        needprompt = doprompt;
12654                } else {
12655                        int len_here;
12656
12657 more_heredoc:
12658                        p = (char *)stackblock() + markloc + 1;
12659                        len_here = out - p;
12660
12661                        if (len_here) {
12662                                len_here -= (c >= PEOF);
12663                                c = p[-1];
12664
12665                                if (len_here) {
12666                                        char *str;
12667
12668                                        str = alloca(len_here + 1);
12669                                        *(char *)mempcpy(str, p, len_here) = '\0';
12670
12671                                        pushstring(str, NULL);
12672                                }
12673                        }
12674                }
12675
12676                STADJUST((char *)stackblock() + markloc - out, out);
12677        }
12678        goto checkend_return;
12679}
12680
12681/*
12682 * Parse a redirection operator.  The variable "out" points to a string
12683 * specifying the fd to be redirected.  The variable "c" contains the
12684 * first character of the redirection operator.
12685 */
12686parseredir: {
12687        /* out is already checked to be a valid number or "" */
12688        int fd = (*out == '\0' ? -1 : atoi(out));
12689        union node *np;
12690
12691        np = stzalloc(sizeof(struct nfile));
12692        if (c == '>') {
12693                np->nfile.fd = 1;
12694                c = pgetc_eatbnl();
12695                if (c == '>')
12696                        np->type = NAPPEND;
12697                else if (c == '|')
12698                        np->type = NCLOBBER;
12699                else if (c == '&')
12700                        np->type = NTOFD;
12701                        /* it also can be NTO2 (>&file), but we can't figure it out yet */
12702                else {
12703                        np->type = NTO;
12704                        pungetc();
12705                }
12706        }
12707#if BASH_REDIR_OUTPUT
12708        else if (c == 0x100 + '>') { /* this flags &> redirection */
12709                np->nfile.fd = 1;
12710                pgetc(); /* this is '>', no need to check */
12711                np->type = NTO2;
12712        }
12713#endif
12714        else { /* c == '<' */
12715                /*np->nfile.fd = 0; - stzalloc did it */
12716                c = pgetc_eatbnl();
12717                switch (c) {
12718                case '<':
12719                        if (sizeof(struct nfile) != sizeof(struct nhere)) {
12720                                np = stzalloc(sizeof(struct nhere));
12721                                /*np->nfile.fd = 0; - stzalloc did it */
12722                        }
12723                        np->type = NHERE;
12724                        heredoc = stzalloc(sizeof(struct heredoc));
12725                        heredoc->here = np;
12726                        c = pgetc_eatbnl();
12727                        if (c == '-') {
12728                                heredoc->striptabs = 1;
12729                        } else {
12730                                /*heredoc->striptabs = 0; - stzalloc did it */
12731                                pungetc();
12732                        }
12733                        break;
12734
12735                case '&':
12736                        np->type = NFROMFD;
12737                        break;
12738
12739                case '>':
12740                        np->type = NFROMTO;
12741                        break;
12742
12743                default:
12744                        np->type = NFROM;
12745                        pungetc();
12746                        break;
12747                }
12748        }
12749        if (fd >= 0)
12750                np->nfile.fd = fd;
12751        redirnode = np;
12752        goto parseredir_return;
12753}
12754
12755/*
12756 * Parse a substitution.  At this point, we have read the dollar sign
12757 * and nothing else.
12758 */
12759
12760/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12761 * (assuming ascii char codes, as the original implementation did) */
12762#define is_special(c) \
12763        (((unsigned)(c) - 33 < 32) \
12764                        && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
12765parsesub: {
12766        unsigned char subtype;
12767        int typeloc;
12768
12769        c = pgetc_eatbnl();
12770        if ((checkkwd & CHKEOFMARK)
12771         || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
12772        ) {
12773#if BASH_DOLLAR_SQUOTE
12774                if (synstack->syntax != DQSYNTAX && c == '\'')
12775                        bash_dollar_squote = 1;
12776                else
12777#endif
12778                        USTPUTC('$', out);
12779                pungetc();
12780        } else if (c == '(') {
12781                /* $(command) or $((arith)) */
12782                if (pgetc_eatbnl() == '(') {
12783#if ENABLE_FEATURE_SH_MATH
12784                        PARSEARITH();
12785#else
12786                        raise_error_syntax("support for $((arith)) is disabled");
12787#endif
12788                } else {
12789                        pungetc();
12790                        PARSEBACKQNEW();
12791                }
12792        } else {
12793                /* $VAR, $<specialchar>, ${...}, or PEOF */
12794                smalluint newsyn = synstack->syntax;
12795
12796                USTPUTC(CTLVAR, out);
12797                typeloc = out - (char *)stackblock();
12798                STADJUST(1, out);
12799                subtype = VSNORMAL;
12800                if (c == '{') {
12801                        c = pgetc_eatbnl();
12802                        subtype = 0;
12803                }
12804 varname:
12805                if (is_name(c)) {
12806                        /* $[{[#]]NAME[}] */
12807                        do {
12808                                STPUTC(c, out);
12809                                c = pgetc_eatbnl();
12810                        } while (is_in_name(c));
12811                } else if (isdigit(c)) {
12812                        /* $[{[#]]NUM[}] */
12813                        do {
12814                                STPUTC(c, out);
12815                                c = pgetc_eatbnl();
12816                        } while ((subtype == 0 || subtype == VSLENGTH) && isdigit(c));
12817                } else if (c != '}') {
12818                        /* $[{[#]]<specialchar>[}] */
12819                        int cc = c;
12820
12821                        c = pgetc_eatbnl();
12822                        if (!subtype && cc == '#') {
12823                                subtype = VSLENGTH;
12824                                if (c == '_' || isalnum(c))
12825                                        goto varname;
12826                                cc = c;
12827                                c = pgetc_eatbnl();
12828                                if (cc == '}' || c != '}') {
12829                                        pungetc();
12830                                        subtype = 0;
12831                                        c = cc;
12832                                        cc = '#';
12833                                }
12834                        }
12835
12836                        if (!is_special(cc)) {
12837                                if (subtype == VSLENGTH)
12838                                        subtype = 0;
12839                                goto badsub;
12840                        }
12841
12842                        USTPUTC(cc, out);
12843                } else
12844                        goto badsub;
12845
12846                if (subtype == 0) {
12847                        static const char types[] ALIGN1 = "}-+?=";
12848                        /* ${VAR...} but not $VAR or ${#VAR} */
12849                        /* c == first char after VAR */
12850                        int cc = c;
12851
12852                        switch (c) {
12853                        case ':':
12854                                c = pgetc_eatbnl();
12855#if BASH_SUBSTR
12856                                /* This check is only needed to not misinterpret
12857                                 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12858                                 * constructs.
12859                                 */
12860                                if (!strchr(types, c)) {
12861                                        subtype = VSSUBSTR;
12862                                        pungetc();
12863                                        break; /* "goto badsub" is bigger (!) */
12864                                }
12865#endif
12866                                subtype = VSNUL;
12867                                /*FALLTHROUGH*/
12868                        default: {
12869                                const char *p = strchr(types, c);
12870                                if (p == NULL)
12871                                        break;
12872                                subtype |= p - types + VSNORMAL;
12873                                break;
12874                        }
12875                        case '%':
12876                        case '#':
12877                                subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12878                                c = pgetc_eatbnl();
12879                                if (c == cc)
12880                                        subtype++;
12881                                else
12882                                        pungetc();
12883
12884                                newsyn = BASESYNTAX;
12885                                break;
12886#if BASH_PATTERN_SUBST
12887                        case '/':
12888                                /* ${v/[/]pattern/repl} */
12889//TODO: encode pattern and repl separately.
12890// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12891// are broken (should print "ONE")
12892                                subtype = VSREPLACE;
12893                                newsyn = BASESYNTAX;
12894                                c = pgetc_eatbnl();
12895                                if (c != '/')
12896                                        goto badsub;
12897                                subtype++; /* VSREPLACEALL */
12898                                break;
12899#endif
12900                        }
12901                } else {
12902                        if (subtype == VSLENGTH && c != '}')
12903                                subtype = 0;
12904 badsub:
12905                        pungetc();
12906                }
12907
12908                if (newsyn == ARISYNTAX)
12909                        newsyn = DQSYNTAX;
12910
12911                if ((newsyn != synstack->syntax || synstack->innerdq)
12912                 && subtype != VSNORMAL
12913                ) {
12914                        synstack_push(&synstack,
12915                                synstack->prev ?: alloca(sizeof(*synstack)),
12916                                newsyn);
12917
12918                        synstack->varpushed = 1;
12919                        synstack->dblquote = newsyn != BASESYNTAX;
12920                }
12921
12922                ((unsigned char *)stackblock())[typeloc] = subtype;
12923                if (subtype != VSNORMAL) {
12924                        synstack->varnest++;
12925                        if (synstack->dblquote)
12926                                synstack->dqvarnest++;
12927                }
12928                STPUTC('=', out);
12929        }
12930        goto parsesub_return;
12931}
12932
12933/*
12934 * Called to parse command substitutions.  Newstyle is set if the command
12935 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12936 * list of commands (passed by reference), and savelen is the number of
12937 * characters on the top of the stack which must be preserved.
12938 */
12939parsebackq: {
12940        struct nodelist **nlpp;
12941        union node *n;
12942        char *str;
12943        size_t savelen;
12944        struct heredoc *saveheredoclist;
12945        smallint saveprompt = 0;
12946
12947        str = NULL;
12948        savelen = out - (char *)stackblock();
12949        if (savelen > 0) {
12950                /*
12951                 * FIXME: this can allocate very large block on stack and SEGV.
12952                 * Example:
12953                 * echo "..<100kbytes>..`true` $(true) `true` ..."
12954                 * allocates 100kb for every command subst. With about
12955                 * a hundred command substitutions stack overflows.
12956                 * With larger prepended string, SEGV happens sooner.
12957                 */
12958                str = alloca(savelen);
12959                memcpy(str, stackblock(), savelen);
12960        }
12961
12962        if (oldstyle) {
12963                /* We must read until the closing backquote, giving special
12964                 * treatment to some slashes, and then push the string and
12965                 * reread it as input, interpreting it normally.
12966                 */
12967                char *pout;
12968                size_t psavelen;
12969                char *pstr;
12970
12971                STARTSTACKSTR(pout);
12972                for (;;) {
12973                        int pc;
12974
12975                        setprompt_if(needprompt, 2);
12976                        pc = pgetc_eatbnl();
12977                        switch (pc) {
12978                        case '`':
12979                                goto done;
12980
12981                        case '\\':
12982                                pc = pgetc(); /* not pgetc_eatbnl! */
12983                                if (pc != '\\' && pc != '`' && pc != '$'
12984                                 && (!synstack->dblquote || pc != '"')
12985                                ) {
12986                                        STPUTC('\\', pout);
12987                                }
12988                                break;
12989
12990                        case PEOF:
12991                                raise_error_syntax("EOF in backquote substitution");
12992
12993                        case '\n':
12994                                nlnoprompt();
12995                                break;
12996
12997                        default:
12998                                break;
12999                        }
13000                        STPUTC(pc, pout);
13001                }
13002 done:
13003                STPUTC('\0', pout);
13004                psavelen = pout - (char *)stackblock();
13005                if (psavelen > 0) {
13006                        pstr = grabstackstr(pout);
13007                        setinputstring(pstr);
13008                }
13009        }
13010        nlpp = &bqlist;
13011        while (*nlpp)
13012                nlpp = &(*nlpp)->next;
13013        *nlpp = stzalloc(sizeof(**nlpp));
13014        /* (*nlpp)->next = NULL; - stzalloc did it */
13015
13016        saveheredoclist = heredoclist;
13017        heredoclist = NULL;
13018
13019        if (oldstyle) {
13020                saveprompt = doprompt;
13021                doprompt = 0;
13022        }
13023
13024        n = list(2);
13025
13026        if (oldstyle)
13027                doprompt = saveprompt;
13028        else {
13029                if (readtoken() != TRP)
13030                        raise_error_unexpected_syntax(TRP);
13031                setinputstring(nullstr);
13032        }
13033
13034        parseheredoc();
13035        heredoclist = saveheredoclist;
13036
13037        (*nlpp)->n = n;
13038        /* Start reading from old file again. */
13039        popfile();
13040        /* Ignore any pushed back tokens left from the backquote parsing. */
13041        if (oldstyle)
13042                tokpushback = 0;
13043        out = growstackto(savelen + 1);
13044        if (str) {
13045                memcpy(out, str, savelen);
13046                STADJUST(savelen, out);
13047        }
13048#if BASH_PROCESS_SUBST
13049        if (style == PSUB)
13050                USTPUTC(c == '<' ? CTLFROMPROC : CTLTOPROC, out);
13051        else
13052#endif
13053                USTPUTC(CTLBACKQ, out);
13054        if (oldstyle)
13055                goto parsebackq_oldreturn;
13056#if BASH_PROCESS_SUBST
13057        else if (style == PSUB)
13058                goto parsebackq_psreturn;
13059#endif
13060        goto parsebackq_newreturn;
13061}
13062
13063#if ENABLE_FEATURE_SH_MATH
13064/*
13065 * Parse an arithmetic expansion (indicate start of one and set state)
13066 */
13067parsearith: {
13068
13069        synstack_push(&synstack,
13070                        synstack->prev ?: alloca(sizeof(*synstack)),
13071                        ARISYNTAX);
13072        synstack->dblquote = 1;
13073        USTPUTC(CTLARI, out);
13074        goto parsearith_return;
13075}
13076#endif
13077} /* end of readtoken */
13078
13079/*
13080 * Read the next input token.
13081 * If the token is a word, we set backquotelist to the list of cmds in
13082 *      backquotes.  We set quoteflag to true if any part of the word was
13083 *      quoted.
13084 * If the token is TREDIR, then we set redirnode to a structure containing
13085 *      the redirection.
13086 *
13087 * [Change comment:  here documents and internal procedures]
13088 * [Readtoken shouldn't have any arguments.  Perhaps we should make the
13089 *  word parsing code into a separate routine.  In this case, readtoken
13090 *  doesn't need to have any internal procedures, but parseword does.
13091 *  We could also make parseoperator in essence the main routine, and
13092 *  have parseword (readtoken1?) handle both words and redirection.]
13093 */
13094#define NEW_xxreadtoken
13095#ifdef NEW_xxreadtoken
13096/* singles must be first! */
13097static const char xxreadtoken_chars[7] ALIGN1 = {
13098        '\n', '(', ')', /* singles */
13099        '&', '|', ';',  /* doubles */
13100        0
13101};
13102
13103#define xxreadtoken_singles 3
13104#define xxreadtoken_doubles 3
13105
13106static const char xxreadtoken_tokens[] ALIGN1 = {
13107        TNL, TLP, TRP,          /* only single occurrence allowed */
13108        TBACKGND, TPIPE, TSEMI, /* if single occurrence */
13109        TEOF,                   /* corresponds to trailing nul */
13110        TAND, TOR, TENDCASE     /* if double occurrence */
13111};
13112
13113static int
13114xxreadtoken(void)
13115{
13116        int c;
13117
13118        if (tokpushback) {
13119                tokpushback = 0;
13120                return lasttoken;
13121        }
13122        setprompt_if(needprompt, 2);
13123        for (;;) {                      /* until token or start of word found */
13124                c = pgetc_eatbnl();
13125                if (c == ' ' || c == '\t')
13126                        continue;
13127
13128                if (c == '#') {
13129                        while ((c = pgetc()) != '\n' && c != PEOF)
13130                                continue;
13131                        pungetc();
13132                } else if (c == '\\') {
13133                        break; /* return readtoken1(...) */
13134                } else {
13135                        const char *p;
13136
13137                        p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
13138                        if (c != PEOF) {
13139                                if (c == '\n') {
13140                                        nlnoprompt();
13141                                }
13142
13143                                p = strchr(xxreadtoken_chars, c);
13144                                if (p == NULL)
13145                                        break; /* return readtoken1(...) */
13146
13147                                if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
13148                                        int cc = pgetc_eatbnl();
13149                                        if (cc == c) {    /* double occurrence? */
13150                                                p += xxreadtoken_doubles + 1;
13151                                        } else {
13152                                                pungetc();
13153#if BASH_REDIR_OUTPUT
13154                                                if (c == '&' && cc == '>') /* &> */
13155                                                        break; /* return readtoken1(...) */
13156#endif
13157                                        }
13158                                }
13159                        }
13160                        lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
13161                        return lasttoken;
13162                }
13163        } /* for (;;) */
13164
13165        return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
13166}
13167#else /* old xxreadtoken */
13168#define RETURN(token)   return lasttoken = token
13169static int
13170xxreadtoken(void)
13171{
13172        int c;
13173
13174        if (tokpushback) {
13175                tokpushback = 0;
13176                return lasttoken;
13177        }
13178        setprompt_if(needprompt, 2);
13179        for (;;) {      /* until token or start of word found */
13180                c = pgetc_eatbnl();
13181                switch (c) {
13182                case ' ': case '\t':
13183                        continue;
13184                case '#':
13185                        while ((c = pgetc()) != '\n' && c != PEOF)
13186                                continue;
13187                        pungetc();
13188                        continue;
13189                case '\n':
13190                        nlnoprompt();
13191                        RETURN(TNL);
13192                case PEOF:
13193                        RETURN(TEOF);
13194                case '&':
13195                        if (pgetc_eatbnl() == '&')
13196                                RETURN(TAND);
13197                        pungetc();
13198                        RETURN(TBACKGND);
13199                case '|':
13200                        if (pgetc_eatbnl() == '|')
13201                                RETURN(TOR);
13202                        pungetc();
13203                        RETURN(TPIPE);
13204                case ';':
13205                        if (pgetc_eatbnl() == ';')
13206                                RETURN(TENDCASE);
13207                        pungetc();
13208                        RETURN(TSEMI);
13209                case '(':
13210                        RETURN(TLP);
13211                case ')':
13212                        RETURN(TRP);
13213                }
13214                break;
13215        }
13216        return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
13217#undef RETURN
13218}
13219#endif /* old xxreadtoken */
13220
13221static int
13222readtoken(void)
13223{
13224        int t;
13225        int kwd = checkkwd;
13226#if DEBUG
13227        smallint alreadyseen = tokpushback;
13228#endif
13229
13230#if ENABLE_ASH_ALIAS
13231 top:
13232#endif
13233
13234        t = xxreadtoken();
13235
13236        /*
13237         * eat newlines
13238         */
13239        if (kwd & CHKNL) {
13240                while (t == TNL) {
13241                        parseheredoc();
13242                        checkkwd = 0;
13243                        t = xxreadtoken();
13244                }
13245        }
13246
13247        kwd |= checkkwd;
13248        checkkwd = 0;
13249
13250        if (t != TWORD || quoteflag) {
13251                goto out;
13252        }
13253
13254        /*
13255         * check for keywords
13256         */
13257        if (kwd & CHKKWD) {
13258                const char *const *pp;
13259
13260                pp = findkwd(wordtext);
13261                if (pp) {
13262                        lasttoken = t = pp - tokname_array;
13263                        TRACE(("keyword '%s' recognized\n", tokname_array[t]));
13264                        goto out;
13265                }
13266        }
13267
13268        if (kwd & CHKALIAS) {
13269#if ENABLE_ASH_ALIAS
13270                struct alias *ap;
13271                ap = lookupalias(wordtext, 1);
13272                if (ap != NULL) {
13273                        if (*ap->val) {
13274                                pushstring(ap->val, ap);
13275                        }
13276                        goto top;
13277                }
13278#endif
13279        }
13280 out:
13281#if DEBUG
13282        if (!alreadyseen)
13283                TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13284        else
13285                TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13286#endif
13287        return t;
13288}
13289
13290/*
13291 * Read and parse a command.  Returns NODE_EOF on end of file.
13292 * (NULL is a valid parse tree indicating a blank line.)
13293 */
13294static union node *
13295parsecmd(int interact)
13296{
13297        tokpushback = 0;
13298        checkkwd = 0;
13299        heredoclist = 0;
13300        doprompt = interact;
13301        setprompt_if(doprompt, doprompt);
13302        needprompt = 0;
13303        return list(1);
13304}
13305
13306/*
13307 * Input any here documents.
13308 */
13309static void
13310parseheredoc(void)
13311{
13312        struct heredoc *here;
13313        union node *n;
13314
13315        here = heredoclist;
13316        heredoclist = NULL;
13317
13318        while (here) {
13319                tokpushback = 0;
13320                setprompt_if(needprompt, 2);
13321                if (here->here->type == NHERE)
13322                        readtoken1(pgetc(), SQSYNTAX, here->eofmark, here->striptabs);
13323                else
13324                        readtoken1(pgetc_eatbnl(), DQSYNTAX, here->eofmark, here->striptabs);
13325                n = stzalloc(sizeof(struct narg));
13326                n->narg.type = NARG;
13327                /*n->narg.next = NULL; - stzalloc did it */
13328                n->narg.text = wordtext;
13329                n->narg.backquote = backquotelist;
13330                here->here->nhere.doc = n;
13331                here = here->next;
13332        }
13333}
13334
13335
13336static const char *
13337expandstr(const char *ps, int syntax_type)
13338{
13339        struct parsefile *file_stop;
13340        struct jmploc *volatile savehandler;
13341        struct heredoc *saveheredoclist;
13342        const char *result;
13343        int saveprompt;
13344        struct jmploc jmploc;
13345        union node n;
13346        int err;
13347
13348        file_stop = g_parsefile;
13349
13350        /* XXX Fix (char *) cast. */
13351        setinputstring((char *)ps);
13352
13353        saveheredoclist = heredoclist;
13354        heredoclist = NULL;
13355        saveprompt = doprompt;
13356        doprompt = 0;
13357        result = ps;
13358        savehandler = exception_handler;
13359        err = setjmp(jmploc.loc);
13360        if (err)
13361                goto out;
13362
13363        /* readtoken1() might die horribly.
13364         * Try a prompt with syntactically wrong command:
13365         * PS1='$(date "+%H:%M:%S) > '
13366         */
13367        exception_handler = &jmploc;
13368        readtoken1(pgetc_eatbnl(), syntax_type, FAKEEOFMARK, 0);
13369
13370        n.narg.type = NARG;
13371        n.narg.next = NULL;
13372        n.narg.text = wordtext;
13373        n.narg.backquote = backquotelist;
13374
13375        /* expandarg() might fail too:
13376         * PS1='$((123+))'
13377         */
13378        expandarg(&n, NULL, EXP_QUOTED);
13379        result = stackblock();
13380
13381out:
13382        exception_handler = savehandler;
13383        if (err && exception_type != EXERROR)
13384                longjmp(exception_handler->loc, 1);
13385
13386        doprompt = saveprompt;
13387        /* Try: PS1='`xxx(`' */
13388        unwindfiles(file_stop);
13389        heredoclist = saveheredoclist;
13390
13391        return result;
13392}
13393
13394static inline int
13395parser_eof(void)
13396{
13397        return tokpushback && lasttoken == TEOF;
13398}
13399
13400/*
13401 * Execute a command or commands contained in a string.
13402 */
13403static int
13404evalstring(char *s, int flags)
13405{
13406        struct jmploc *volatile savehandler;
13407        struct jmploc jmploc;
13408        int ex;
13409
13410        union node *n;
13411        struct stackmark smark;
13412        int status;
13413
13414        s = sstrdup(s);
13415        setinputstring(s);
13416        setstackmark(&smark);
13417
13418        status = 0;
13419        /* On exception inside execution loop, we must popfile().
13420         * Try interactively:
13421         *      readonly a=a
13422         *      command eval "a=b"  # throws "is read only" error
13423         * "command BLTIN" is not supposed to abort (even in non-interactive use).
13424         * But if we skip popfile(), we hit EOF in eval's string, and exit.
13425         */
13426        savehandler = exception_handler;
13427        ex = setjmp(jmploc.loc);
13428        if (ex)
13429                goto out;
13430        exception_handler = &jmploc;
13431
13432        while ((n = parsecmd(0)) != NODE_EOF) {
13433                int i;
13434
13435                i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
13436                if (n)
13437                        status = i;
13438                popstackmark(&smark);
13439                if (evalskip)
13440                        break;
13441        }
13442 out:
13443        popstackmark(&smark);
13444        popfile();
13445        stunalloc(s);
13446
13447        exception_handler = savehandler;
13448        if (ex)
13449                longjmp(exception_handler->loc, ex);
13450
13451        return status;
13452}
13453
13454/*
13455 * The eval command.
13456 */
13457static int FAST_FUNC
13458evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
13459{
13460        char *p;
13461        char *concat;
13462
13463        if (argv[1]) {
13464                p = argv[1];
13465                argv += 2;
13466                if (argv[0]) {
13467                        STARTSTACKSTR(concat);
13468                        for (;;) {
13469                                concat = stack_putstr(p, concat);
13470                                p = *argv++;
13471                                if (p == NULL)
13472                                        break;
13473                                STPUTC(' ', concat);
13474                        }
13475                        STPUTC('\0', concat);
13476                        p = grabstackstr(concat);
13477                }
13478                return evalstring(p, flags & EV_TESTED);
13479        }
13480        return 0;
13481}
13482
13483/*
13484 * Read and execute commands.
13485 * "Top" is nonzero for the top level command loop;
13486 * it turns on prompting if the shell is interactive.
13487 */
13488static int
13489cmdloop(int top)
13490{
13491        union node *n;
13492        struct stackmark smark;
13493        int inter;
13494        int status = 0;
13495        int numeof = 0;
13496
13497        TRACE(("cmdloop(%d) called\n", top));
13498        for (;;) {
13499                int skip;
13500
13501                setstackmark(&smark);
13502#if JOBS
13503                if (doing_jobctl)
13504                        showjobs(SHOW_CHANGED|SHOW_STDERR);
13505#endif
13506                inter = 0;
13507                if (iflag && top) {
13508                        inter++;
13509                        chkmail();
13510                }
13511                n = parsecmd(inter);
13512#if DEBUG
13513                if (DEBUG > 2 && debug && (n != NODE_EOF))
13514                        showtree(n);
13515#endif
13516                if (n == NODE_EOF) {
13517                        if (!top || numeof >= 50)
13518                                break;
13519                        if (!stoppedjobs()) {
13520                                if (!iflag)
13521                                        break;
13522                                if (!Iflag) {
13523                                        newline_and_flush(stderr);
13524                                        break;
13525                                }
13526                                /* "set -o ignoreeof" active, do not exit command loop on ^D */
13527                                out2str("\nUse \"exit\" to leave shell.\n");
13528                        }
13529                        numeof++;
13530                } else {
13531                        int i;
13532
13533                        /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13534                        job_warning >>= 1;
13535                        numeof = 0;
13536                        i = evaltree(n, 0);
13537                        if (n)
13538                                status = i;
13539                }
13540                popstackmark(&smark);
13541                skip = evalskip;
13542
13543                if (skip) {
13544                        evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
13545                        break;
13546                }
13547        }
13548        return status;
13549}
13550
13551/*
13552 * Take commands from a file.  To be compatible we should do a path
13553 * search for the file, which is necessary to find sub-commands.
13554 */
13555static char *
13556find_dot_file(char *basename)
13557{
13558        char *fullname;
13559        const char *path = pathval();
13560        struct stat statb;
13561        int len;
13562
13563        /* don't try this for absolute or relative paths */
13564        if (strchr(basename, '/'))
13565                return basename;
13566
13567        while ((len = padvance(&path, basename)) >= 0) {
13568                fullname = stackblock();
13569                if ((!pathopt || *pathopt == 'f')
13570                 && !stat(fullname, &statb) && S_ISREG(statb.st_mode)
13571                ) {
13572                        /* This will be freed by the caller. */
13573                        return stalloc(len);
13574                }
13575        }
13576        /* not found in PATH */
13577
13578#if ENABLE_ASH_BASH_SOURCE_CURDIR
13579        return basename;
13580#else
13581        ash_msg_and_raise_error("%s: not found", basename);
13582        /* NOTREACHED */
13583#endif
13584}
13585
13586static int FAST_FUNC
13587dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
13588{
13589        /* "false; . empty_file; echo $?" should print 0, not 1: */
13590        int status = 0;
13591        char *fullname;
13592        char **argv;
13593        char *args_need_save;
13594        volatile struct shparam saveparam;
13595
13596//???
13597//      struct strlist *sp;
13598//      for (sp = cmdenviron; sp; sp = sp->next)
13599//              setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
13600
13601        nextopt(nullstr); /* handle possible "--" */
13602        argv = argptr;
13603
13604        if (!argv[0]) {
13605                /* bash says: "bash: .: filename argument required" */
13606                return 2; /* bash compat */
13607        }
13608
13609        /* This aborts if file isn't found, which is POSIXly correct.
13610         * bash returns exitcode 1 instead.
13611         */
13612        fullname = find_dot_file(argv[0]);
13613        argv++;
13614        args_need_save = argv[0];
13615        if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
13616                int argc;
13617                saveparam = shellparam;
13618                shellparam.malloced = 0;
13619                argc = 1;
13620                while (argv[argc])
13621                        argc++;
13622                shellparam.nparam = argc;
13623                shellparam.p = argv;
13624        };
13625
13626        /* This aborts if file can't be opened, which is POSIXly correct.
13627         * bash returns exitcode 1 instead.
13628         */
13629        setinputfile(fullname, INPUT_PUSH_FILE);
13630        commandname = fullname;
13631        status = cmdloop(0);
13632        popfile();
13633
13634        if (args_need_save) {
13635                freeparam(&shellparam);
13636                shellparam = saveparam;
13637        };
13638
13639        return status;
13640}
13641
13642static int FAST_FUNC
13643exitcmd(int argc UNUSED_PARAM, char **argv)
13644{
13645        if (stoppedjobs())
13646                return 0;
13647
13648        if (argv[1])
13649                savestatus = number(argv[1]);
13650
13651//TODO: this script
13652// trap 'echo trap:$FUNCNAME' EXIT
13653// f() { exit; }
13654// f
13655//prints "trap:f" in bash. We can call exitshell() here to achieve this.
13656//For now, keeping dash code:
13657        raise_exception(EXEXIT);
13658        /* NOTREACHED */
13659}
13660
13661/*
13662 * Read a file containing shell functions.
13663 */
13664static void
13665readcmdfile(char *name)
13666{
13667        setinputfile(name, INPUT_PUSH_FILE);
13668        cmdloop(0);
13669        popfile();
13670}
13671
13672
13673/* ============ find_command inplementation */
13674
13675/*
13676 * Resolve a command name.  If you change this routine, you may have to
13677 * change the shellexec routine as well.
13678 */
13679static void
13680find_command(char *name, struct cmdentry *entry, int act, const char *path)
13681{
13682        struct tblentry *cmdp;
13683        int idx;
13684        int prev;
13685        char *fullname;
13686        struct stat statb;
13687        int e;
13688        int updatetbl;
13689        struct builtincmd *bcmd;
13690        int len;
13691
13692        /* If name contains a slash, don't use PATH or hash table */
13693        if (strchr(name, '/') != NULL) {
13694                entry->u.index = -1;
13695                if (act & DO_ABS) {
13696                        while (stat(name, &statb) < 0) {
13697#ifdef SYSV
13698                                if (errno == EINTR)
13699                                        continue;
13700#endif
13701                                entry->cmdtype = CMDUNKNOWN;
13702                                return;
13703                        }
13704                }
13705                entry->cmdtype = CMDNORMAL;
13706                return;
13707        }
13708
13709/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
13710
13711        updatetbl = (path == pathval());
13712        if (!updatetbl)
13713                act |= DO_ALTPATH;
13714
13715        /* If name is in the table, check answer will be ok */
13716        cmdp = cmdlookup(name, 0);
13717        if (cmdp != NULL) {
13718                int bit;
13719
13720                switch (cmdp->cmdtype) {
13721                default:
13722#if DEBUG
13723                        abort();
13724#endif
13725                case CMDNORMAL:
13726                        bit = DO_ALTPATH | DO_REGBLTIN;
13727                        break;
13728                case CMDFUNCTION:
13729                        bit = DO_NOFUNC;
13730                        break;
13731                case CMDBUILTIN:
13732                        bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
13733                        break;
13734                }
13735                if (act & bit) {
13736                        if (act & bit & DO_REGBLTIN)
13737                                goto fail;
13738
13739                        updatetbl = 0;
13740                        cmdp = NULL;
13741                } else if (cmdp->rehash == 0)
13742                        /* if not invalidated by cd, we're done */
13743                        goto success;
13744        }
13745
13746        /* If %builtin not in path, check for builtin next */
13747        bcmd = find_builtin(name);
13748        if (bcmd) {
13749                if (IS_BUILTIN_REGULAR(bcmd))
13750                        goto builtin_success;
13751                if (act & DO_ALTPATH)
13752                        goto builtin_success;
13753                if (builtinloc <= 0)
13754                        goto builtin_success;
13755        }
13756
13757        if (act & DO_REGBLTIN)
13758                goto fail;
13759
13760#if ENABLE_FEATURE_SH_STANDALONE
13761        {
13762                int applet_no = find_applet_by_name(name);
13763                if (applet_no >= 0) {
13764                        entry->cmdtype = CMDNORMAL;
13765                        entry->u.index = -2 - applet_no;
13766                        return;
13767                }
13768        }
13769#endif
13770
13771        /* We have to search path. */
13772        prev = -1;              /* where to start */
13773        if (cmdp && cmdp->rehash) {     /* doing a rehash */
13774                if (cmdp->cmdtype == CMDBUILTIN)
13775                        prev = builtinloc;
13776                else
13777                        prev = cmdp->param.index;
13778        }
13779
13780        e = ENOENT;
13781        idx = -1;
13782 loop:
13783        while ((len = padvance(&path, name)) >= 0) {
13784                const char *lpathopt = pathopt;
13785
13786                fullname = stackblock();
13787                idx++;
13788                if (lpathopt) {
13789                        if (*lpathopt == 'b') {
13790                                if (bcmd)
13791                                        goto builtin_success;
13792                                continue;
13793                        } else if (!(act & DO_NOFUNC)) {
13794                                /* handled below */
13795                        } else {
13796                                /* ignore unimplemented options */
13797                                continue;
13798                        }
13799                }
13800                /* if rehash, don't redo absolute path names */
13801                if (fullname[0] == '/' && idx <= prev) {
13802                        if (idx < prev)
13803                                continue;
13804                        TRACE(("searchexec \"%s\": no change\n", name));
13805                        goto success;
13806                }
13807                while (stat(fullname, &statb) < 0) {
13808#ifdef SYSV
13809                        if (errno == EINTR)
13810                                continue;
13811#endif
13812                        if (errno != ENOENT && errno != ENOTDIR)
13813                                e = errno;
13814                        goto loop;
13815                }
13816                e = EACCES;     /* if we fail, this will be the error */
13817                if (!S_ISREG(statb.st_mode))
13818                        continue;
13819                if (lpathopt) {          /* this is a %func directory */
13820                        stalloc(len);
13821                        /* NB: stalloc will return space pointed by fullname
13822                         * (because we don't have any intervening allocations
13823                         * between stunalloc above and this stalloc) */
13824                        readcmdfile(fullname);
13825                        cmdp = cmdlookup(name, 0);
13826                        if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13827                                ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13828                        stunalloc(fullname);
13829                        goto success;
13830                }
13831                TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13832                if (!updatetbl) {
13833                        entry->cmdtype = CMDNORMAL;
13834                        entry->u.index = idx;
13835                        return;
13836                }
13837                INT_OFF;
13838                cmdp = cmdlookup(name, 1);
13839                cmdp->cmdtype = CMDNORMAL;
13840                cmdp->param.index = idx;
13841                INT_ON;
13842                goto success;
13843        }
13844
13845        /* We failed.  If there was an entry for this command, delete it */
13846        if (cmdp && updatetbl)
13847                delete_cmd_entry();
13848        if (act & DO_ERR) {
13849#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13850                struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13851                if (hookp && hookp->cmdtype == CMDFUNCTION) {
13852                        char *argv[3];
13853                        argv[0] = (char*) "command_not_found_handle";
13854                        argv[1] = name;
13855                        argv[2] = NULL;
13856                        evalfun(hookp->param.func, 2, argv, 0);
13857                        entry->cmdtype = CMDUNKNOWN;
13858                        return;
13859                }
13860#endif
13861                ash_msg("%s: %s", name, errmsg(e, "not found"));
13862        }
13863 fail:
13864        entry->cmdtype = CMDUNKNOWN;
13865        return;
13866
13867 builtin_success:
13868        if (!updatetbl) {
13869                entry->cmdtype = CMDBUILTIN;
13870                entry->u.cmd = bcmd;
13871                return;
13872        }
13873        INT_OFF;
13874        cmdp = cmdlookup(name, 1);
13875        cmdp->cmdtype = CMDBUILTIN;
13876        cmdp->param.cmd = bcmd;
13877        INT_ON;
13878 success:
13879        cmdp->rehash = 0;
13880        entry->cmdtype = cmdp->cmdtype;
13881        entry->u = cmdp->param;
13882}
13883
13884
13885/*
13886 * The trap builtin.
13887 */
13888static int FAST_FUNC
13889trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13890{
13891        char *action;
13892        char **ap;
13893        int signo, exitcode;
13894
13895        nextopt(nullstr);
13896        ap = argptr;
13897        if (!*ap) {
13898                for (signo = 0; signo <= NTRAP_LAST; signo++) {
13899                        char *tr = trap_ptr[signo];
13900                        if (tr) {
13901                                /* note: bash adds "SIG", but only if invoked
13902                                 * as "bash". If called as "sh", or if set -o posix,
13903                                 * then it prints short signal names.
13904                                 * We are printing short names: */
13905                                out1fmt("trap -- %s %s\n",
13906                                                single_quote(tr),
13907                                                (signo == NTRAP_ERR) ? "ERR" : get_signame(signo));
13908                /* trap_ptr != trap only if we are in special-cased `trap` code.
13909                 * In this case, we will exit very soon, no need to free(). */
13910                                /* if (trap_ptr != trap && tp[0]) */
13911                                /*      free(tr); */
13912                        }
13913                }
13914                /*
13915                if (trap_ptr != trap) {
13916                        free(trap_ptr);
13917                        trap_ptr = trap;
13918                }
13919                */
13920                return 0;
13921        }
13922
13923        /* Why the second check?
13924         * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13925         * In this case, NUM is signal no, not an action.
13926         */
13927        action = NULL;
13928        if (ap[1] && !is_number(ap[0]))
13929                action = *ap++;
13930
13931        exitcode = 0;
13932        while (*ap) {
13933                signo = strcmp(*ap, "ERR") == 0 ? NTRAP_ERR : get_signum(*ap);
13934                if (signo < 0) {
13935                        /* Mimic bash message exactly */
13936                        ash_msg("%s: invalid signal specification", *ap);
13937                        exitcode = 1;
13938                        goto next;
13939                }
13940                INT_OFF;
13941                if (action) {
13942                        if (LONE_DASH(action))
13943                                action = NULL;
13944                        else {
13945                                if (action[0]) /* not NULL and not "" and not "-" */
13946                                        may_have_traps = 1;
13947                                action = ckstrdup(action);
13948                        }
13949                }
13950                free(trap[signo]);
13951                trap[signo] = action;
13952                if (signo != 0 && signo < NSIG)
13953                        setsignal(signo);
13954                INT_ON;
13955 next:
13956                ap++;
13957        }
13958        return exitcode;
13959}
13960
13961
13962/* ============ Builtins */
13963
13964#if ENABLE_ASH_HELP
13965static int FAST_FUNC
13966helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13967{
13968        unsigned col;
13969        unsigned i;
13970
13971        out1fmt(
13972                "Built-in commands:\n"
13973                "------------------\n");
13974        for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
13975                col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
13976                                        builtintab[i].name + 1);
13977                if (col > 60) {
13978                        out1fmt("\n");
13979                        col = 0;
13980                }
13981        }
13982# if ENABLE_FEATURE_SH_STANDALONE
13983        {
13984                const char *a = applet_names;
13985                while (*a) {
13986                        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13987                        if (col > 60) {
13988                                out1fmt("\n");
13989                                col = 0;
13990                        }
13991                        while (*a++ != '\0')
13992                                continue;
13993                }
13994        }
13995# endif
13996        newline_and_flush(stdout);
13997        return EXIT_SUCCESS;
13998}
13999#endif
14000
14001#if MAX_HISTORY
14002static int FAST_FUNC
14003historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14004{
14005        show_history(line_input_state);
14006        return EXIT_SUCCESS;
14007}
14008#endif
14009
14010/*
14011 * The export and readonly commands.
14012 */
14013static int FAST_FUNC
14014exportcmd(int argc UNUSED_PARAM, char **argv)
14015{
14016        struct var *vp;
14017        char *name;
14018        const char *p;
14019        char **aptr;
14020        char opt;
14021        int flag;
14022        int flag_off;
14023
14024        /* "readonly" in bash accepts, but ignores -n.
14025         * We do the same: it saves a conditional in nextopt's param.
14026         */
14027        flag_off = 0;
14028        while ((opt = nextopt("np")) != '\0') {
14029                if (opt == 'n')
14030                        flag_off = VEXPORT;
14031        }
14032        flag = VEXPORT;
14033        if (argv[0][0] == 'r') {
14034                flag = VREADONLY;
14035                flag_off = 0; /* readonly ignores -n */
14036        }
14037        flag_off = ~flag_off;
14038
14039        /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
14040        {
14041                aptr = argptr;
14042                name = *aptr;
14043                if (name) {
14044                        do {
14045                                p = strchr(name, '=');
14046                                if (p != NULL) {
14047                                        p++;
14048                                } else {
14049                                        vp = *findvar(hashvar(name), name);
14050                                        if (vp) {
14051                                                vp->flags = ((vp->flags | flag) & flag_off);
14052                                                continue;
14053                                        }
14054                                }
14055                                setvar(name, p, (flag & flag_off));
14056                        } while ((name = *++aptr) != NULL);
14057                        return 0;
14058                }
14059        }
14060
14061        /* No arguments. Show the list of exported or readonly vars.
14062         * -n is ignored.
14063         */
14064        showvars(argv[0], flag, 0);
14065        return 0;
14066}
14067
14068/*
14069 * Delete a function if it exists.
14070 */
14071static void
14072unsetfunc(const char *name)
14073{
14074        struct tblentry *cmdp;
14075
14076        cmdp = cmdlookup(name, 0);
14077        if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
14078                delete_cmd_entry();
14079}
14080
14081/*
14082 * The unset builtin command.  We unset the function before we unset the
14083 * variable to allow a function to be unset when there is a readonly variable
14084 * with the same name.
14085 */
14086static int FAST_FUNC
14087unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14088{
14089        char **ap;
14090        int i;
14091        int flag = 0;
14092
14093        while ((i = nextopt("vf")) != 0) {
14094                flag = i;
14095        }
14096
14097        for (ap = argptr; *ap; ap++) {
14098                if (flag != 'f') {
14099                        unsetvar(*ap);
14100                        continue;
14101                }
14102                if (flag != 'v')
14103                        unsetfunc(*ap);
14104        }
14105        return 0;
14106}
14107
14108static const unsigned char timescmd_str[] ALIGN1 = {
14109        ' ',  offsetof(struct tms, tms_utime),
14110        '\n', offsetof(struct tms, tms_stime),
14111        ' ',  offsetof(struct tms, tms_cutime),
14112        '\n', offsetof(struct tms, tms_cstime),
14113        0
14114};
14115static int FAST_FUNC
14116timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14117{
14118        unsigned clk_tck;
14119        const unsigned char *p;
14120        struct tms buf;
14121
14122        clk_tck = bb_clk_tck();
14123
14124        times(&buf);
14125        p = timescmd_str;
14126        do {
14127                unsigned sec, frac;
14128                unsigned long t;
14129                t = *(clock_t *)(((char *) &buf) + p[1]);
14130                sec = t / clk_tck;
14131                frac = t % clk_tck;
14132                out1fmt("%um%u.%03us%c",
14133                        sec / 60, sec % 60,
14134                        (frac * 1000) / clk_tck,
14135                        p[0]);
14136                p += 2;
14137        } while (*p);
14138
14139        return 0;
14140}
14141
14142#if ENABLE_FEATURE_SH_MATH
14143/*
14144 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
14145 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
14146 *
14147 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
14148 */
14149static int FAST_FUNC
14150letcmd(int argc UNUSED_PARAM, char **argv)
14151{
14152        arith_t i;
14153
14154        argv++;
14155        if (!*argv)
14156                ash_msg_and_raise_error("expression expected");
14157        do {
14158                i = ash_arith(*argv);
14159        } while (*++argv);
14160
14161        return !i;
14162}
14163#endif
14164
14165/*
14166 * The read builtin. Options:
14167 *      -r              Do not interpret '\' specially
14168 *      -s              Turn off echo (tty only)
14169 *      -n NCHARS       Read NCHARS max
14170 *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
14171 *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
14172 *      -u FD           Read from given FD instead of fd 0
14173 *      -d DELIM        End on DELIM char, not newline
14174 * This uses unbuffered input, which may be avoidable in some cases.
14175 * TODO: bash also has:
14176 *      -a ARRAY        Read into array[0],[1],etc
14177 *      -e              Use line editing (tty only)
14178 */
14179static int FAST_FUNC
14180readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14181{
14182        struct builtin_read_params params;
14183        const char *r;
14184        int i;
14185
14186        memset(&params, 0, sizeof(params));
14187
14188        while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
14189                switch (i) {
14190                case 'p':
14191                        params.opt_p = optionarg;
14192                        break;
14193                case 'n':
14194                        params.opt_n = optionarg;
14195                        break;
14196                case 's':
14197                        params.read_flags |= BUILTIN_READ_SILENT;
14198                        break;
14199                case 't':
14200                        params.opt_t = optionarg;
14201                        break;
14202                case 'r':
14203                        params.read_flags |= BUILTIN_READ_RAW;
14204                        break;
14205                case 'u':
14206                        params.opt_u = optionarg;
14207                        break;
14208#if BASH_READ_D
14209                case 'd':
14210                        params.opt_d = optionarg;
14211                        break;
14212#endif
14213                default:
14214                        break;
14215                }
14216        }
14217
14218        if (!ENABLE_ASH_BASH_COMPAT && !argptr) {
14219                bb_simple_error_msg("read: need variable name");
14220                return 1;
14221        }
14222        params.argv = argptr;
14223        params.setvar = setvar0;
14224        params.ifs = bltinlookup("IFS"); /* can be NULL */
14225
14226        /* "read -s" needs to save/restore termios, can't allow ^C
14227         * to jump out of it.
14228         */
14229 again:
14230        INT_OFF;
14231        r = shell_builtin_read(&params);
14232        INT_ON;
14233
14234        if ((uintptr_t)r == 1 && errno == EINTR) {
14235                /* To get SIGCHLD: sleep 1 & read x; echo $x
14236                 * Correct behavior is to not exit "read"
14237                 */
14238                if (pending_sig == 0)
14239                        goto again;
14240        }
14241
14242        if ((uintptr_t)r > 1)
14243                ash_msg_and_raise_error(r);
14244
14245        return (uintptr_t)r;
14246}
14247
14248static int FAST_FUNC
14249umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14250{
14251        static const char permuser[3] ALIGN1 = "ogu";
14252
14253        mode_t mask;
14254        int symbolic_mode = 0;
14255
14256        while (nextopt("S") != '\0') {
14257                symbolic_mode = 1;
14258        }
14259
14260        INT_OFF;
14261        mask = umask(0);
14262        umask(mask);
14263        INT_ON;
14264
14265        if (*argptr == NULL) {
14266                if (symbolic_mode) {
14267                        char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
14268                        char *p = buf;
14269                        int i;
14270
14271                        i = 2;
14272                        for (;;) {
14273                                *p++ = ',';
14274                                *p++ = permuser[i];
14275                                *p++ = '=';
14276                                /* mask is 0..0uuugggooo. i=2 selects uuu bits */
14277                                if (!(mask & 0400)) *p++ = 'r';
14278                                if (!(mask & 0200)) *p++ = 'w';
14279                                if (!(mask & 0100)) *p++ = 'x';
14280                                mask <<= 3;
14281                                if (--i < 0)
14282                                        break;
14283                        }
14284                        *p = '\0';
14285                        puts(buf + 1);
14286                } else {
14287                        out1fmt("%04o\n", mask);
14288                }
14289        } else {
14290                char *modestr = *argptr;
14291                /* numeric umasks are taken as-is */
14292                /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
14293                if (!isdigit(modestr[0]))
14294                        mask ^= 0777;
14295                mask = bb_parse_mode(modestr, mask);
14296                if ((unsigned)mask > 0777) {
14297                        ash_msg_and_raise_error("illegal mode: %s", modestr);
14298                }
14299                if (!isdigit(modestr[0]))
14300                        mask ^= 0777;
14301                umask(mask);
14302        }
14303        return 0;
14304}
14305
14306static int FAST_FUNC
14307ulimitcmd(int argc UNUSED_PARAM, char **argv)
14308{
14309        return shell_builtin_ulimit(argv);
14310}
14311
14312/* ============ main() and helpers */
14313
14314/*
14315 * This routine is called when an error or an interrupt occurs in an
14316 * interactive shell and control is returned to the main command loop
14317 * but prior to exitshell.
14318 */
14319static void
14320exitreset(void)
14321{
14322        /* from eval.c: */
14323        if (savestatus >= 0) {
14324                if (exception_type == EXEXIT || evalskip == SKIPFUNCDEF)
14325                        exitstatus = savestatus;
14326                savestatus = -1;
14327        }
14328        evalskip = 0;
14329        loopnest = 0;
14330        inps4 = 0;
14331
14332        /* from expand.c: */
14333        ifsfree();
14334
14335        /* from redir.c: */
14336        unwindredir(NULL);
14337}
14338
14339/*
14340 * This routine is called when an error or an interrupt occurs in an
14341 * interactive shell and control is returned to the main command loop.
14342 * (In dash, this function is auto-generated by build machinery).
14343 */
14344static void
14345reset(void)
14346{
14347        /* from input.c: */
14348        g_parsefile->left_in_buffer = 0;
14349        g_parsefile->left_in_line = 0;      /* clear input buffer */
14350        g_parsefile->unget = 0;
14351        popallfiles();
14352
14353        /* from var.c: */
14354        unwindlocalvars(NULL);
14355}
14356
14357/*
14358 * Called to exit the shell.
14359 */
14360static void
14361exitshell(void)
14362{
14363        struct jmploc loc;
14364        char *p;
14365
14366#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
14367        save_history(line_input_state); /* may be NULL */
14368#endif
14369        savestatus = exitstatus;
14370        TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
14371        if (setjmp(loc.loc))
14372                goto out;
14373        exception_handler = &loc;
14374        p = trap[0];
14375        if (p) {
14376                trap[0] = NULL;
14377                evalskip = 0;
14378                trap_depth++;
14379                evalstring(p, 0);
14380                trap_depth--;
14381                evalskip = SKIPFUNCDEF;
14382                /*free(p); - we'll exit soon */
14383        }
14384 out:
14385        exitreset();
14386        /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14387         * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
14388         */
14389        setjobctl(0);
14390        flush_stdout_stderr();
14391        _exit(exitstatus);
14392        /* NOTREACHED */
14393}
14394
14395/* Don't inline: conserve stack of caller from having our locals too */
14396static NOINLINE void
14397init(void)
14398{
14399        /* we will never free this */
14400        basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
14401        basepf.linno = 1;
14402
14403        sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
14404        setsignal(SIGCHLD);
14405
14406        {
14407                char **envp;
14408                const char *p;
14409
14410                initvar();
14411                for (envp = environ; envp && *envp; envp++) {
14412/* Used to have
14413 *                      p = endofname(*envp);
14414 *                      if (p != *envp && *p == '=') {
14415 * here to weed out badly-named variables, but this breaks
14416 * scenarios where people do want them passed to children:
14417 * import os
14418 * os.environ["test-test"]="test"
14419 * if os.fork() == 0:
14420 *   os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ])  # fixes this
14421 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])  # breaks this
14422 */
14423                        if (strchr(*envp, '=')) {
14424                                setvareq(*envp, VEXPORT|VTEXTFIXED);
14425                        }
14426                }
14427
14428                setvareq((char*)defifsvar, VTEXTFIXED);
14429                setvareq((char*)defoptindvar, VTEXTFIXED);
14430
14431                setvar0("PPID", utoa(getppid()));
14432#if BASH_SHLVL_VAR
14433                p = lookupvar("SHLVL");
14434                setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
14435#endif
14436#if BASH_HOSTNAME_VAR
14437                if (!lookupvar("HOSTNAME")) {
14438                        struct utsname uts;
14439                        uname(&uts);
14440                        setvar0("HOSTNAME", uts.nodename);
14441                }
14442#endif
14443                p = lookupvar("PWD");
14444                if (p) {
14445                        struct stat st1, st2;
14446                        if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
14447                         || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14448                        ) {
14449                                p = NULL;
14450                        }
14451                }
14452                setpwd(p, 0);
14453        }
14454}
14455
14456
14457//usage:#define ash_trivial_usage
14458//usage:        "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]"
14459////////        comes from ^^^^^^^^^^optletters
14460//usage:#define ash_full_usage "\n\n"
14461//usage:        "Unix shell interpreter"
14462
14463/*
14464 * Process the shell command line arguments.
14465 */
14466static int
14467procargs(char **argv)
14468{
14469        int i;
14470        const char *xminusc;
14471        char **xargv;
14472        int login_sh;
14473
14474        xargv = argv;
14475        login_sh = xargv[0] && xargv[0][0] == '-';
14476#if NUM_SCRIPTS > 0
14477        if (minusc)
14478                goto setarg0;
14479#endif
14480        arg0 = xargv[0];
14481        /* if (xargv[0]) - mmm, this is always true! */
14482                xargv++;
14483        argptr = xargv;
14484        for (i = 0; i < NOPTS; i++)
14485                optlist[i] = 2;
14486        if (options(&login_sh)) {
14487                /* it already printed err message */
14488                raise_exception(EXERROR);
14489        }
14490        xargv = argptr;
14491        xminusc = minusc;
14492        if (*xargv == NULL) {
14493                if (xminusc)
14494                        ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14495                sflag = 1;
14496        }
14497        if (iflag == 2 /* no explicit -i given */
14498         && sflag == 1 /* -s given (or implied) */
14499         && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */
14500         && isatty(0) && isatty(1) /* we are on tty */
14501        ) {
14502                iflag = 1;
14503        }
14504        if (mflag == 2)
14505                mflag = iflag;
14506        /* Unset options which weren't explicitly set or unset */
14507        for (i = 0; i < NOPTS; i++)
14508                optlist[i] &= 1; /* same effect as "if (optlist[i] == 2) optlist[i] = 0;" */
14509#if DEBUG == 2
14510        debug = 1;
14511#endif
14512        /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
14513        if (xminusc) {
14514                minusc = *xargv++;
14515                if (*xargv)
14516                        goto setarg0;
14517        } else if (!sflag) {
14518                setinputfile(*xargv, 0);
14519 setarg0:
14520                arg0 = *xargv++;
14521                commandname = arg0;
14522        }
14523
14524        shellparam.p = xargv;
14525#if ENABLE_ASH_GETOPTS
14526        shellparam.optind = 1;
14527        shellparam.optoff = -1;
14528#endif
14529        /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
14530        while (*xargv) {
14531                shellparam.nparam++;
14532                xargv++;
14533        }
14534
14535        /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
14536         * Try:
14537         * trap '' hup; bash; echo RET  # type "kill -hup $$", see SIGHUP having effect
14538         * trap '' hup; bash -c 'kill -hup $$; echo ALIVE'  # here SIGHUP is SIG_IGNed
14539         * NB: must do it before setting up signals (in optschanged())
14540         * and reading .profile etc (after we return from here):
14541         */
14542        if (iflag)
14543                signal(SIGHUP, SIG_DFL);
14544
14545        optschanged();
14546
14547        return login_sh;
14548}
14549
14550/*
14551 * Read /etc/profile, ~/.profile, $ENV.
14552 */
14553static void
14554read_profile(const char *name)
14555{
14556        name = expandstr(name, DQSYNTAX);
14557        if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14558                return;
14559        cmdloop(0);
14560        popfile();
14561}
14562
14563#if PROFILE
14564static short profile_buf[16384];
14565extern int etext();
14566#endif
14567
14568/*
14569 * Main routine.  We initialize things, parse the arguments, execute
14570 * profiles if we're a login shell, and then call cmdloop to execute
14571 * commands.  The setjmp call sets up the location to jump to when an
14572 * exception occurs.  When an exception occurs the variable "state"
14573 * is used to figure out how far we had gotten.
14574 */
14575int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14576#if NUM_SCRIPTS > 0
14577int ash_main(int argc, char **argv)
14578#else
14579int ash_main(int argc UNUSED_PARAM, char **argv)
14580#endif
14581/* note: 'argc' is used only if embedded scripts are enabled */
14582{
14583        volatile smallint state;
14584        struct jmploc jmploc;
14585        struct stackmark smark;
14586        int login_sh;
14587
14588        /* Initialize global data */
14589        INIT_G_misc();
14590        INIT_G_memstack();
14591        INIT_G_var();
14592#if ENABLE_ASH_ALIAS
14593        INIT_G_alias();
14594#endif
14595        INIT_G_cmdtable();
14596
14597#if PROFILE
14598        monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14599#endif
14600
14601        state = 0;
14602        if (setjmp(jmploc.loc)) {
14603                smallint e;
14604                smallint s;
14605
14606                exitreset();
14607
14608                e = exception_type;
14609                s = state;
14610                if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
14611                        exitshell();
14612                }
14613
14614                reset();
14615
14616                if (e == EXINT) {
14617                        newline_and_flush(stderr);
14618                }
14619
14620                popstackmark(&smark);
14621                FORCE_INT_ON; /* enable interrupts */
14622                if (s == 1)
14623                        goto state1;
14624                if (s == 2)
14625                        goto state2;
14626                if (s == 3)
14627                        goto state3;
14628                goto state4;
14629        }
14630        exception_handler = &jmploc;
14631        rootpid = getpid();
14632
14633        init();
14634        setstackmark(&smark);
14635
14636#if NUM_SCRIPTS > 0
14637        if (argc < 0)
14638                /* Non-NULL minusc tells procargs that an embedded script is being run */
14639                minusc = get_script_content(-argc - 1);
14640#endif
14641        login_sh = procargs(argv);
14642#if DEBUG
14643        TRACE(("Shell args: "));
14644        trace_puts_args(argv);
14645#endif
14646
14647        if (login_sh) {
14648                const char *hp;
14649
14650                state = 1;
14651                read_profile("/etc/profile");
14652 state1:
14653                state = 2;
14654                hp = lookupvar("HOME");
14655                if (hp)
14656                        read_profile("$HOME/.profile");
14657        }
14658 state2:
14659        state = 3;
14660        if (iflag
14661#ifndef linux
14662         && getuid() == geteuid() && getgid() == getegid()
14663#endif
14664        ) {
14665                const char *shinit = lookupvar("ENV");
14666                if (shinit != NULL && *shinit != '\0')
14667                        read_profile(shinit);
14668        }
14669        popstackmark(&smark);
14670 state3:
14671        state = 4;
14672        if (minusc) {
14673                /* evalstring pushes parsefile stack.
14674                 * Ensure we don't falsely claim that 0 (stdin)
14675                 * is one of stacked source fds.
14676                 * Testcase: ash -c 'exec 1>&0' must not complain. */
14677
14678                // if (!sflag) g_parsefile->pf_fd = -1;
14679                // ^^ not necessary since now we special-case fd 0
14680                // in save_fd_on_redirect()
14681
14682                lineno = 0; // bash compat
14683                // dash: evalstring(minusc, sflag ? 0 : EV_EXIT);
14684                // The above makes
14685                //  ash -sc 'echo $-'
14686                // continue reading input from stdin after running 'echo'.
14687                // bash does not do this: it prints "hBcs" and exits.
14688                evalstring(minusc, EV_EXIT);
14689        }
14690
14691        if (sflag || minusc == NULL) {
14692#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
14693                if (line_input_state) {
14694                        const char *hp = lookupvar("HISTFILE");
14695                        if (!hp) {
14696                                hp = lookupvar("HOME");
14697                                if (hp) {
14698                                        INT_OFF;
14699                                        hp = concat_path_file(hp, ".ash_history");
14700                                        setvar0("HISTFILE", hp);
14701                                        free((char*)hp);
14702                                        INT_ON;
14703                                        hp = lookupvar("HISTFILE");
14704                                }
14705                        }
14706                        if (hp)
14707                                line_input_state->hist_file = xstrdup(hp);
14708# if ENABLE_FEATURE_SH_HISTFILESIZE
14709                        hp = lookupvar("HISTFILESIZE");
14710                        line_input_state->max_history = size_from_HISTFILESIZE(hp);
14711# endif
14712                }
14713#endif
14714 state4: /* XXX ??? - why isn't this before the "if" statement */
14715                cmdloop(1);
14716        }
14717#if PROFILE
14718        monitor(0);
14719#endif
14720#ifdef GPROF
14721        {
14722                extern void _mcleanup(void);
14723                _mcleanup();
14724        }
14725#endif
14726        TRACE(("End of main reached\n"));
14727        exitshell();
14728        /* NOTREACHED */
14729}
14730
14731
14732/*-
14733 * Copyright (c) 1989, 1991, 1993, 1994
14734 *      The Regents of the University of California.  All rights reserved.
14735 *
14736 * This code is derived from software contributed to Berkeley by
14737 * Kenneth Almquist.
14738 *
14739 * Redistribution and use in source and binary forms, with or without
14740 * modification, are permitted provided that the following conditions
14741 * are met:
14742 * 1. Redistributions of source code must retain the above copyright
14743 *    notice, this list of conditions and the following disclaimer.
14744 * 2. Redistributions in binary form must reproduce the above copyright
14745 *    notice, this list of conditions and the following disclaimer in the
14746 *    documentation and/or other materials provided with the distribution.
14747 * 3. Neither the name of the University nor the names of its contributors
14748 *    may be used to endorse or promote products derived from this software
14749 *    without specific prior written permission.
14750 *
14751 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
14752 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14753 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14754 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14755 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14756 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14757 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14758 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14759 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14760 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14761 * SUCH DAMAGE.
14762 */
14763