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 the GPL v2 or later, see the file LICENSE in this tarball.
  17 */
  18
  19/*
  20 * The following should be set to reflect the type of system you have:
  21 *      JOBS -> 1 if you have Berkeley job control, 0 otherwise.
  22 *      define SYSV if you are running under System V.
  23 *      define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
  24 *      define DEBUG=2 to compile in and turn on debugging.
  25 *
  26 * When debugging is on, debugging info will be written to ./trace and
  27 * a quit signal will generate a core dump.
  28 */
  29#define DEBUG 0
  30/* Tweak debug output verbosity here */
  31#define DEBUG_TIME 0
  32#define DEBUG_PID 1
  33#define DEBUG_SIG 1
  34
  35#define PROFILE 0
  36
  37#define JOBS ENABLE_ASH_JOB_CONTROL
  38
  39#include "busybox.h" /* for applet_names */
  40#include <paths.h>
  41#include <setjmp.h>
  42#include <fnmatch.h>
  43#include <sys/times.h>
  44
  45#include "shell_common.h"
  46#include "math.h"
  47#if ENABLE_ASH_RANDOM_SUPPORT
  48# include "random.h"
  49#else
  50# define CLEAR_RANDOM_T(rnd) ((void)0)
  51#endif
  52
  53#include "NUM_APPLETS.h"
  54#if NUM_APPLETS == 1
  55/* STANDALONE does not make sense, and won't compile */
  56# undef CONFIG_FEATURE_SH_STANDALONE
  57# undef ENABLE_FEATURE_SH_STANDALONE
  58# undef IF_FEATURE_SH_STANDALONE
  59# undef IF_NOT_FEATURE_SH_STANDALONE
  60# define ENABLE_FEATURE_SH_STANDALONE 0
  61# define IF_FEATURE_SH_STANDALONE(...)
  62# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
  63#endif
  64
  65#ifndef PIPE_BUF
  66# define PIPE_BUF 4096           /* amount of buffering in a pipe */
  67#endif
  68
  69#if !BB_MMU
  70# error "Do not even bother, ash will not run on NOMMU machine"
  71#endif
  72
  73
  74/* ============ Hash table sizes. Configurable. */
  75
  76#define VTABSIZE 39
  77#define ATABSIZE 39
  78#define CMDTABLESIZE 31         /* should be prime */
  79
  80
  81/* ============ Shell options */
  82
  83static const char *const optletters_optnames[] = {
  84        "e"   "errexit",
  85        "f"   "noglob",
  86        "I"   "ignoreeof",
  87        "i"   "interactive",
  88        "m"   "monitor",
  89        "n"   "noexec",
  90        "s"   "stdin",
  91        "x"   "xtrace",
  92        "v"   "verbose",
  93        "C"   "noclobber",
  94        "a"   "allexport",
  95        "b"   "notify",
  96        "u"   "nounset",
  97        "\0"  "vi"
  98#if ENABLE_ASH_BASH_COMPAT
  99        ,"\0"  "pipefail"
 100#endif
 101#if DEBUG
 102        ,"\0"  "nolog"
 103        ,"\0"  "debug"
 104#endif
 105};
 106
 107#define optletters(n)  optletters_optnames[n][0]
 108#define optnames(n)   (optletters_optnames[n] + 1)
 109
 110enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
 111
 112
 113/* ============ Misc data */
 114
 115#define msg_illnum "Illegal number: %s"
 116
 117/*
 118 * We enclose jmp_buf in a structure so that we can declare pointers to
 119 * jump locations.  The global variable handler contains the location to
 120 * jump to when an exception occurs, and the global variable exception_type
 121 * contains a code identifying the exception.  To implement nested
 122 * exception handlers, the user should save the value of handler on entry
 123 * to an inner scope, set handler to point to a jmploc structure for the
 124 * inner scope, and restore handler on exit from the scope.
 125 */
 126struct jmploc {
 127        jmp_buf loc;
 128};
 129
 130struct globals_misc {
 131        /* pid of main shell */
 132        int rootpid;
 133        /* shell level: 0 for the main shell, 1 for its children, and so on */
 134        int shlvl;
 135#define rootshell (!shlvl)
 136        char *minusc;  /* argument to -c option */
 137
 138        char *curdir; // = nullstr;     /* current working directory */
 139        char *physdir; // = nullstr;    /* physical working directory */
 140
 141        char *arg0; /* value of $0 */
 142
 143        struct jmploc *exception_handler;
 144
 145        volatile int suppress_int; /* counter */
 146        volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
 147        /* last pending signal */
 148        volatile /*sig_atomic_t*/ smallint pending_sig;
 149        smallint exception_type; /* kind of exception (0..5) */
 150        /* exceptions */
 151#define EXINT 0         /* SIGINT received */
 152#define EXERROR 1       /* a generic error */
 153#define EXSHELLPROC 2   /* execute a shell procedure */
 154#define EXEXEC 3        /* command execution failed */
 155#define EXEXIT 4        /* exit the shell */
 156#define EXSIG 5         /* trapped signal in wait(1) */
 157
 158        smallint isloginsh;
 159        char nullstr[1];        /* zero length string */
 160
 161        char optlist[NOPTS];
 162#define eflag optlist[0]
 163#define fflag optlist[1]
 164#define Iflag optlist[2]
 165#define iflag optlist[3]
 166#define mflag optlist[4]
 167#define nflag optlist[5]
 168#define sflag optlist[6]
 169#define xflag optlist[7]
 170#define vflag optlist[8]
 171#define Cflag optlist[9]
 172#define aflag optlist[10]
 173#define bflag optlist[11]
 174#define uflag optlist[12]
 175#define viflag optlist[13]
 176#if ENABLE_ASH_BASH_COMPAT
 177# define pipefail optlist[14]
 178#else
 179# define pipefail 0
 180#endif
 181#if DEBUG
 182# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
 183# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
 184#endif
 185
 186        /* trap handler commands */
 187        /*
 188         * Sigmode records the current value of the signal handlers for the various
 189         * modes.  A value of zero means that the current handler is not known.
 190         * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
 191         */
 192        char sigmode[NSIG - 1];
 193#define S_DFL      1            /* default signal handling (SIG_DFL) */
 194#define S_CATCH    2            /* signal is caught */
 195#define S_IGN      3            /* signal is ignored (SIG_IGN) */
 196#define S_HARD_IGN 4            /* signal is ignored permenantly */
 197
 198        /* indicates specified signal received */
 199        uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
 200        uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
 201        char *trap[NSIG];
 202        char **trap_ptr;        /* used only by "trap hack" */
 203
 204        /* Rarely referenced stuff */
 205#if ENABLE_ASH_RANDOM_SUPPORT
 206        random_t random_gen;
 207#endif
 208        pid_t backgndpid;        /* pid of last background process */
 209        smallint job_warning;    /* user was warned about stopped jobs (can be 2, 1 or 0). */
 210};
 211extern struct globals_misc *const ash_ptr_to_globals_misc;
 212#define G_misc (*ash_ptr_to_globals_misc)
 213#define rootpid     (G_misc.rootpid    )
 214#define shlvl       (G_misc.shlvl      )
 215#define minusc      (G_misc.minusc     )
 216#define curdir      (G_misc.curdir     )
 217#define physdir     (G_misc.physdir    )
 218#define arg0        (G_misc.arg0       )
 219#define exception_handler (G_misc.exception_handler)
 220#define exception_type    (G_misc.exception_type   )
 221#define suppress_int      (G_misc.suppress_int     )
 222#define pending_int       (G_misc.pending_int      )
 223#define pending_sig       (G_misc.pending_sig      )
 224#define isloginsh   (G_misc.isloginsh  )
 225#define nullstr     (G_misc.nullstr    )
 226#define optlist     (G_misc.optlist    )
 227#define sigmode     (G_misc.sigmode    )
 228#define gotsig      (G_misc.gotsig     )
 229#define may_have_traps    (G_misc.may_have_traps   )
 230#define trap        (G_misc.trap       )
 231#define trap_ptr    (G_misc.trap_ptr   )
 232#define random_gen  (G_misc.random_gen )
 233#define backgndpid  (G_misc.backgndpid )
 234#define job_warning (G_misc.job_warning)
 235#define INIT_G_misc() do { \
 236        (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
 237        barrier(); \
 238        curdir = nullstr; \
 239        physdir = nullstr; \
 240        trap_ptr = trap; \
 241} while (0)
 242
 243
 244/* ============ DEBUG */
 245#if DEBUG
 246static void trace_printf(const char *fmt, ...);
 247static void trace_vprintf(const char *fmt, va_list va);
 248# define TRACE(param)    trace_printf param
 249# define TRACEV(param)   trace_vprintf param
 250# define close(fd) do { \
 251        int dfd = (fd); \
 252        if (close(dfd) < 0) \
 253                bb_error_msg("bug on %d: closing %d(0x%x)", \
 254                        __LINE__, dfd, dfd); \
 255} while (0)
 256#else
 257# define TRACE(param)
 258# define TRACEV(param)
 259#endif
 260
 261
 262/* ============ Utility functions */
 263#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
 264
 265static int isdigit_str9(const char *str)
 266{
 267        int maxlen = 9 + 1; /* max 9 digits: 999999999 */
 268        while (--maxlen && isdigit(*str))
 269                str++;
 270        return (*str == '\0');
 271}
 272
 273static const char *var_end(const char *var)
 274{
 275        while (*var)
 276                if (*var++ == '=')
 277                        break;
 278        return var;
 279}
 280
 281
 282/* ============ Interrupts / exceptions */
 283/*
 284 * These macros allow the user to suspend the handling of interrupt signals
 285 * over a period of time.  This is similar to SIGHOLD or to sigblock, but
 286 * much more efficient and portable.  (But hacking the kernel is so much
 287 * more fun than worrying about efficiency and portability. :-))
 288 */
 289#define INT_OFF do { \
 290        suppress_int++; \
 291        xbarrier(); \
 292} while (0)
 293
 294/*
 295 * Called to raise an exception.  Since C doesn't include exceptions, we
 296 * just do a longjmp to the exception handler.  The type of exception is
 297 * stored in the global variable "exception_type".
 298 */
 299static void raise_exception(int) NORETURN;
 300static void
 301raise_exception(int e)
 302{
 303#if DEBUG
 304        if (exception_handler == NULL)
 305                abort();
 306#endif
 307        INT_OFF;
 308        exception_type = e;
 309        longjmp(exception_handler->loc, 1);
 310}
 311#if DEBUG
 312#define raise_exception(e) do { \
 313        TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
 314        raise_exception(e); \
 315} while (0)
 316#endif
 317
 318/*
 319 * Called from trap.c when a SIGINT is received.  (If the user specifies
 320 * that SIGINT is to be trapped or ignored using the trap builtin, then
 321 * this routine is not called.)  Suppressint is nonzero when interrupts
 322 * are held using the INT_OFF macro.  (The test for iflag is just
 323 * defensive programming.)
 324 */
 325static void raise_interrupt(void) NORETURN;
 326static void
 327raise_interrupt(void)
 328{
 329        int ex_type;
 330
 331        pending_int = 0;
 332        /* Signal is not automatically unmasked after it is raised,
 333         * do it ourself - unmask all signals */
 334        sigprocmask_allsigs(SIG_UNBLOCK);
 335        /* pending_sig = 0; - now done in signal_handler() */
 336
 337        ex_type = EXSIG;
 338        if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
 339                if (!(rootshell && iflag)) {
 340                        /* Kill ourself with SIGINT */
 341                        signal(SIGINT, SIG_DFL);
 342                        raise(SIGINT);
 343                }
 344                ex_type = EXINT;
 345        }
 346        raise_exception(ex_type);
 347        /* NOTREACHED */
 348}
 349#if DEBUG
 350#define raise_interrupt() do { \
 351        TRACE(("raising interrupt on line %d\n", __LINE__)); \
 352        raise_interrupt(); \
 353} while (0)
 354#endif
 355
 356static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 357int_on(void)
 358{
 359        xbarrier();
 360        if (--suppress_int == 0 && pending_int) {
 361                raise_interrupt();
 362        }
 363}
 364#define INT_ON int_on()
 365static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 366force_int_on(void)
 367{
 368        xbarrier();
 369        suppress_int = 0;
 370        if (pending_int)
 371                raise_interrupt();
 372}
 373#define FORCE_INT_ON force_int_on()
 374
 375#define SAVE_INT(v) ((v) = suppress_int)
 376
 377#define RESTORE_INT(v) do { \
 378        xbarrier(); \
 379        suppress_int = (v); \
 380        if (suppress_int == 0 && pending_int) \
 381                raise_interrupt(); \
 382} while (0)
 383
 384
 385/* ============ Stdout/stderr output */
 386
 387static void
 388outstr(const char *p, FILE *file)
 389{
 390        INT_OFF;
 391        fputs(p, file);
 392        INT_ON;
 393}
 394
 395static void
 396flush_stdout_stderr(void)
 397{
 398        INT_OFF;
 399        fflush_all();
 400        INT_ON;
 401}
 402
 403static void
 404outcslow(int c, FILE *dest)
 405{
 406        INT_OFF;
 407        putc(c, dest);
 408        fflush(dest);
 409        INT_ON;
 410}
 411
 412static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
 413static int
 414out1fmt(const char *fmt, ...)
 415{
 416        va_list ap;
 417        int r;
 418
 419        INT_OFF;
 420        va_start(ap, fmt);
 421        r = vprintf(fmt, ap);
 422        va_end(ap);
 423        INT_ON;
 424        return r;
 425}
 426
 427static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
 428static int
 429fmtstr(char *outbuf, size_t length, const char *fmt, ...)
 430{
 431        va_list ap;
 432        int ret;
 433
 434        va_start(ap, fmt);
 435        INT_OFF;
 436        ret = vsnprintf(outbuf, length, fmt, ap);
 437        va_end(ap);
 438        INT_ON;
 439        return ret;
 440}
 441
 442static void
 443out1str(const char *p)
 444{
 445        outstr(p, stdout);
 446}
 447
 448static void
 449out2str(const char *p)
 450{
 451        outstr(p, stderr);
 452        flush_stdout_stderr();
 453}
 454
 455
 456/* ============ Parser structures */
 457
 458/* control characters in argument strings */
 459#define CTL_FIRST CTLESC
 460#define CTLESC       ((unsigned char)'\201')    /* escape next character */
 461#define CTLVAR       ((unsigned char)'\202')    /* variable defn */
 462#define CTLENDVAR    ((unsigned char)'\203')
 463#define CTLBACKQ     ((unsigned char)'\204')
 464#define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */
 465/*      CTLBACKQ | CTLQUOTE == '\205' */
 466#define CTLARI       ((unsigned char)'\206')    /* arithmetic expression */
 467#define CTLENDARI    ((unsigned char)'\207')
 468#define CTLQUOTEMARK ((unsigned char)'\210')
 469#define CTL_LAST CTLQUOTEMARK
 470
 471/* variable substitution byte (follows CTLVAR) */
 472#define VSTYPE  0x0f            /* type of variable substitution */
 473#define VSNUL   0x10            /* colon--treat the empty string as unset */
 474#define VSQUOTE 0x80            /* inside double quotes--suppress splitting */
 475
 476/* values of VSTYPE field */
 477#define VSNORMAL        0x1     /* normal variable:  $var or ${var} */
 478#define VSMINUS         0x2     /* ${var-text} */
 479#define VSPLUS          0x3     /* ${var+text} */
 480#define VSQUESTION      0x4     /* ${var?message} */
 481#define VSASSIGN        0x5     /* ${var=text} */
 482#define VSTRIMRIGHT     0x6     /* ${var%pattern} */
 483#define VSTRIMRIGHTMAX  0x7     /* ${var%%pattern} */
 484#define VSTRIMLEFT      0x8     /* ${var#pattern} */
 485#define VSTRIMLEFTMAX   0x9     /* ${var##pattern} */
 486#define VSLENGTH        0xa     /* ${#var} */
 487#if ENABLE_ASH_BASH_COMPAT
 488#define VSSUBSTR        0xc     /* ${var:position:length} */
 489#define VSREPLACE       0xd     /* ${var/pattern/replacement} */
 490#define VSREPLACEALL    0xe     /* ${var//pattern/replacement} */
 491#endif
 492
 493static const char dolatstr[] ALIGN1 = {
 494        CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
 495};
 496
 497#define NCMD      0
 498#define NPIPE     1
 499#define NREDIR    2
 500#define NBACKGND  3
 501#define NSUBSHELL 4
 502#define NAND      5
 503#define NOR       6
 504#define NSEMI     7
 505#define NIF       8
 506#define NWHILE    9
 507#define NUNTIL   10
 508#define NFOR     11
 509#define NCASE    12
 510#define NCLIST   13
 511#define NDEFUN   14
 512#define NARG     15
 513#define NTO      16
 514#if ENABLE_ASH_BASH_COMPAT
 515#define NTO2     17
 516#endif
 517#define NCLOBBER 18
 518#define NFROM    19
 519#define NFROMTO  20
 520#define NAPPEND  21
 521#define NTOFD    22
 522#define NFROMFD  23
 523#define NHERE    24
 524#define NXHERE   25
 525#define NNOT     26
 526#define N_NUMBER 27
 527
 528union node;
 529
 530struct ncmd {
 531        smallint type; /* Nxxxx */
 532        union node *assign;
 533        union node *args;
 534        union node *redirect;
 535};
 536
 537struct npipe {
 538        smallint type;
 539        smallint pipe_backgnd;
 540        struct nodelist *cmdlist;
 541};
 542
 543struct nredir {
 544        smallint type;
 545        union node *n;
 546        union node *redirect;
 547};
 548
 549struct nbinary {
 550        smallint type;
 551        union node *ch1;
 552        union node *ch2;
 553};
 554
 555struct nif {
 556        smallint type;
 557        union node *test;
 558        union node *ifpart;
 559        union node *elsepart;
 560};
 561
 562struct nfor {
 563        smallint type;
 564        union node *args;
 565        union node *body;
 566        char *var;
 567};
 568
 569struct ncase {
 570        smallint type;
 571        union node *expr;
 572        union node *cases;
 573};
 574
 575struct nclist {
 576        smallint type;
 577        union node *next;
 578        union node *pattern;
 579        union node *body;
 580};
 581
 582struct narg {
 583        smallint type;
 584        union node *next;
 585        char *text;
 586        struct nodelist *backquote;
 587};
 588
 589/* nfile and ndup layout must match!
 590 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
 591 * that it is actually NTO2 (>&file), and change its type.
 592 */
 593struct nfile {
 594        smallint type;
 595        union node *next;
 596        int fd;
 597        int _unused_dupfd;
 598        union node *fname;
 599        char *expfname;
 600};
 601
 602struct ndup {
 603        smallint type;
 604        union node *next;
 605        int fd;
 606        int dupfd;
 607        union node *vname;
 608        char *_unused_expfname;
 609};
 610
 611struct nhere {
 612        smallint type;
 613        union node *next;
 614        int fd;
 615        union node *doc;
 616};
 617
 618struct nnot {
 619        smallint type;
 620        union node *com;
 621};
 622
 623union node {
 624        smallint type;
 625        struct ncmd ncmd;
 626        struct npipe npipe;
 627        struct nredir nredir;
 628        struct nbinary nbinary;
 629        struct nif nif;
 630        struct nfor nfor;
 631        struct ncase ncase;
 632        struct nclist nclist;
 633        struct narg narg;
 634        struct nfile nfile;
 635        struct ndup ndup;
 636        struct nhere nhere;
 637        struct nnot nnot;
 638};
 639
 640/*
 641 * NODE_EOF is returned by parsecmd when it encounters an end of file.
 642 * It must be distinct from NULL.
 643 */
 644#define NODE_EOF ((union node *) -1L)
 645
 646struct nodelist {
 647        struct nodelist *next;
 648        union node *n;
 649};
 650
 651struct funcnode {
 652        int count;
 653        union node n;
 654};
 655
 656/*
 657 * Free a parse tree.
 658 */
 659static void
 660freefunc(struct funcnode *f)
 661{
 662        if (f && --f->count < 0)
 663                free(f);
 664}
 665
 666
 667/* ============ Debugging output */
 668
 669#if DEBUG
 670
 671static FILE *tracefile;
 672
 673static void
 674trace_printf(const char *fmt, ...)
 675{
 676        va_list va;
 677
 678        if (debug != 1)
 679                return;
 680        if (DEBUG_TIME)
 681                fprintf(tracefile, "%u ", (int) time(NULL));
 682        if (DEBUG_PID)
 683                fprintf(tracefile, "[%u] ", (int) getpid());
 684        if (DEBUG_SIG)
 685                fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
 686        va_start(va, fmt);
 687        vfprintf(tracefile, fmt, va);
 688        va_end(va);
 689}
 690
 691static void
 692trace_vprintf(const char *fmt, va_list va)
 693{
 694        if (debug != 1)
 695                return;
 696        if (DEBUG_TIME)
 697                fprintf(tracefile, "%u ", (int) time(NULL));
 698        if (DEBUG_PID)
 699                fprintf(tracefile, "[%u] ", (int) getpid());
 700        if (DEBUG_SIG)
 701                fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
 702        vfprintf(tracefile, fmt, va);
 703}
 704
 705static void
 706trace_puts(const char *s)
 707{
 708        if (debug != 1)
 709                return;
 710        fputs(s, tracefile);
 711}
 712
 713static void
 714trace_puts_quoted(char *s)
 715{
 716        char *p;
 717        char c;
 718
 719        if (debug != 1)
 720                return;
 721        putc('"', tracefile);
 722        for (p = s; *p; p++) {
 723                switch ((unsigned char)*p) {
 724                case '\n': c = 'n'; goto backslash;
 725                case '\t': c = 't'; goto backslash;
 726                case '\r': c = 'r'; goto backslash;
 727                case '\"': c = '\"'; goto backslash;
 728                case '\\': c = '\\'; goto backslash;
 729                case CTLESC: c = 'e'; goto backslash;
 730                case CTLVAR: c = 'v'; goto backslash;
 731                case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
 732                case CTLBACKQ: c = 'q'; goto backslash;
 733                case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
 734 backslash:
 735                        putc('\\', tracefile);
 736                        putc(c, tracefile);
 737                        break;
 738                default:
 739                        if (*p >= ' ' && *p <= '~')
 740                                putc(*p, tracefile);
 741                        else {
 742                                putc('\\', tracefile);
 743                                putc((*p >> 6) & 03, tracefile);
 744                                putc((*p >> 3) & 07, tracefile);
 745                                putc(*p & 07, tracefile);
 746                        }
 747                        break;
 748                }
 749        }
 750        putc('"', tracefile);
 751}
 752
 753static void
 754trace_puts_args(char **ap)
 755{
 756        if (debug != 1)
 757                return;
 758        if (!*ap)
 759                return;
 760        while (1) {
 761                trace_puts_quoted(*ap);
 762                if (!*++ap) {
 763                        putc('\n', tracefile);
 764                        break;
 765                }
 766                putc(' ', tracefile);
 767        }
 768}
 769
 770static void
 771opentrace(void)
 772{
 773        char s[100];
 774#ifdef O_APPEND
 775        int flags;
 776#endif
 777
 778        if (debug != 1) {
 779                if (tracefile)
 780                        fflush(tracefile);
 781                /* leave open because libedit might be using it */
 782                return;
 783        }
 784        strcpy(s, "./trace");
 785        if (tracefile) {
 786                if (!freopen(s, "a", tracefile)) {
 787                        fprintf(stderr, "Can't re-open %s\n", s);
 788                        debug = 0;
 789                        return;
 790                }
 791        } else {
 792                tracefile = fopen(s, "a");
 793                if (tracefile == NULL) {
 794                        fprintf(stderr, "Can't open %s\n", s);
 795                        debug = 0;
 796                        return;
 797                }
 798        }
 799#ifdef O_APPEND
 800        flags = fcntl(fileno(tracefile), F_GETFL);
 801        if (flags >= 0)
 802                fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
 803#endif
 804        setlinebuf(tracefile);
 805        fputs("\nTracing started.\n", tracefile);
 806}
 807
 808static void
 809indent(int amount, char *pfx, FILE *fp)
 810{
 811        int i;
 812
 813        for (i = 0; i < amount; i++) {
 814                if (pfx && i == amount - 1)
 815                        fputs(pfx, fp);
 816                putc('\t', fp);
 817        }
 818}
 819
 820/* little circular references here... */
 821static void shtree(union node *n, int ind, char *pfx, FILE *fp);
 822
 823static void
 824sharg(union node *arg, FILE *fp)
 825{
 826        char *p;
 827        struct nodelist *bqlist;
 828        unsigned char subtype;
 829
 830        if (arg->type != NARG) {
 831                out1fmt("<node type %d>\n", arg->type);
 832                abort();
 833        }
 834        bqlist = arg->narg.backquote;
 835        for (p = arg->narg.text; *p; p++) {
 836                switch ((unsigned char)*p) {
 837                case CTLESC:
 838                        putc(*++p, fp);
 839                        break;
 840                case CTLVAR:
 841                        putc('$', fp);
 842                        putc('{', fp);
 843                        subtype = *++p;
 844                        if (subtype == VSLENGTH)
 845                                putc('#', fp);
 846
 847                        while (*p != '=')
 848                                putc(*p++, fp);
 849
 850                        if (subtype & VSNUL)
 851                                putc(':', fp);
 852
 853                        switch (subtype & VSTYPE) {
 854                        case VSNORMAL:
 855                                putc('}', fp);
 856                                break;
 857                        case VSMINUS:
 858                                putc('-', fp);
 859                                break;
 860                        case VSPLUS:
 861                                putc('+', fp);
 862                                break;
 863                        case VSQUESTION:
 864                                putc('?', fp);
 865                                break;
 866                        case VSASSIGN:
 867                                putc('=', fp);
 868                                break;
 869                        case VSTRIMLEFT:
 870                                putc('#', fp);
 871                                break;
 872                        case VSTRIMLEFTMAX:
 873                                putc('#', fp);
 874                                putc('#', fp);
 875                                break;
 876                        case VSTRIMRIGHT:
 877                                putc('%', fp);
 878                                break;
 879                        case VSTRIMRIGHTMAX:
 880                                putc('%', fp);
 881                                putc('%', fp);
 882                                break;
 883                        case VSLENGTH:
 884                                break;
 885                        default:
 886                                out1fmt("<subtype %d>", subtype);
 887                        }
 888                        break;
 889                case CTLENDVAR:
 890                        putc('}', fp);
 891                        break;
 892                case CTLBACKQ:
 893                case CTLBACKQ|CTLQUOTE:
 894                        putc('$', fp);
 895                        putc('(', fp);
 896                        shtree(bqlist->n, -1, NULL, fp);
 897                        putc(')', fp);
 898                        break;
 899                default:
 900                        putc(*p, fp);
 901                        break;
 902                }
 903        }
 904}
 905
 906static void
 907shcmd(union node *cmd, FILE *fp)
 908{
 909        union node *np;
 910        int first;
 911        const char *s;
 912        int dftfd;
 913
 914        first = 1;
 915        for (np = cmd->ncmd.args; np; np = np->narg.next) {
 916                if (!first)
 917                        putc(' ', fp);
 918                sharg(np, fp);
 919                first = 0;
 920        }
 921        for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
 922                if (!first)
 923                        putc(' ', fp);
 924                dftfd = 0;
 925                switch (np->nfile.type) {
 926                case NTO:      s = ">>"+1; dftfd = 1; break;
 927                case NCLOBBER: s = ">|"; dftfd = 1; break;
 928                case NAPPEND:  s = ">>"; dftfd = 1; break;
 929#if ENABLE_ASH_BASH_COMPAT
 930                case NTO2:
 931#endif
 932                case NTOFD:    s = ">&"; dftfd = 1; break;
 933                case NFROM:    s = "<"; break;
 934                case NFROMFD:  s = "<&"; break;
 935                case NFROMTO:  s = "<>"; break;
 936                default:       s = "*error*"; break;
 937                }
 938                if (np->nfile.fd != dftfd)
 939                        fprintf(fp, "%d", np->nfile.fd);
 940                fputs(s, fp);
 941                if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
 942                        fprintf(fp, "%d", np->ndup.dupfd);
 943                } else {
 944                        sharg(np->nfile.fname, fp);
 945                }
 946                first = 0;
 947        }
 948}
 949
 950static void
 951shtree(union node *n, int ind, char *pfx, FILE *fp)
 952{
 953        struct nodelist *lp;
 954        const char *s;
 955
 956        if (n == NULL)
 957                return;
 958
 959        indent(ind, pfx, fp);
 960
 961        if (n == NODE_EOF) {
 962                fputs("<EOF>", fp);
 963                return;
 964        }
 965
 966        switch (n->type) {
 967        case NSEMI:
 968                s = "; ";
 969                goto binop;
 970        case NAND:
 971                s = " && ";
 972                goto binop;
 973        case NOR:
 974                s = " || ";
 975 binop:
 976                shtree(n->nbinary.ch1, ind, NULL, fp);
 977                /* if (ind < 0) */
 978                        fputs(s, fp);
 979                shtree(n->nbinary.ch2, ind, NULL, fp);
 980                break;
 981        case NCMD:
 982                shcmd(n, fp);
 983                if (ind >= 0)
 984                        putc('\n', fp);
 985                break;
 986        case NPIPE:
 987                for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
 988                        shtree(lp->n, 0, NULL, fp);
 989                        if (lp->next)
 990                                fputs(" | ", fp);
 991                }
 992                if (n->npipe.pipe_backgnd)
 993                        fputs(" &", fp);
 994                if (ind >= 0)
 995                        putc('\n', fp);
 996                break;
 997        default:
 998                fprintf(fp, "<node type %d>", n->type);
 999                if (ind >= 0)
1000                        putc('\n', fp);
1001                break;
1002        }
1003}
1004
1005static void
1006showtree(union node *n)
1007{
1008        trace_puts("showtree called\n");
1009        shtree(n, 1, NULL, stderr);
1010}
1011
1012#endif /* DEBUG */
1013
1014
1015/* ============ Parser data */
1016
1017/*
1018 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1019 */
1020struct strlist {
1021        struct strlist *next;
1022        char *text;
1023};
1024
1025struct alias;
1026
1027struct strpush {
1028        struct strpush *prev;   /* preceding string on stack */
1029        char *prev_string;
1030        int prev_left_in_line;
1031#if ENABLE_ASH_ALIAS
1032        struct alias *ap;       /* if push was associated with an alias */
1033#endif
1034        char *string;           /* remember the string since it may change */
1035};
1036
1037struct parsefile {
1038        struct parsefile *prev; /* preceding file on stack */
1039        int linno;              /* current line */
1040        int pf_fd;              /* file descriptor (or -1 if string) */
1041        int left_in_line;       /* number of chars left in this line */
1042        int left_in_buffer;     /* number of chars left in this buffer past the line */
1043        char *next_to_pgetc;    /* next char in buffer */
1044        char *buf;              /* input buffer */
1045        struct strpush *strpush; /* for pushing strings at this level */
1046        struct strpush basestrpush; /* so pushing one is fast */
1047};
1048
1049static struct parsefile basepf;        /* top level input file */
1050static struct parsefile *g_parsefile = &basepf;  /* current input file */
1051static int startlinno;                 /* line # where last token started */
1052static char *commandname;              /* currently executing command */
1053static struct strlist *cmdenviron;     /* environment for builtin command */
1054static uint8_t exitstatus;             /* exit status of last command */
1055
1056
1057/* ============ Message printing */
1058
1059static void
1060ash_vmsg(const char *msg, va_list ap)
1061{
1062        fprintf(stderr, "%s: ", arg0);
1063        if (commandname) {
1064                if (strcmp(arg0, commandname))
1065                        fprintf(stderr, "%s: ", commandname);
1066                if (!iflag || g_parsefile->pf_fd > 0)
1067                        fprintf(stderr, "line %d: ", startlinno);
1068        }
1069        vfprintf(stderr, msg, ap);
1070        outcslow('\n', stderr);
1071}
1072
1073/*
1074 * Exverror is called to raise the error exception.  If the second argument
1075 * is not NULL then error prints an error message using printf style
1076 * formatting.  It then raises the error exception.
1077 */
1078static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1079static void
1080ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1081{
1082#if DEBUG
1083        if (msg) {
1084                TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1085                TRACEV((msg, ap));
1086                TRACE(("\") pid=%d\n", getpid()));
1087        } else
1088                TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1089        if (msg)
1090#endif
1091                ash_vmsg(msg, ap);
1092
1093        flush_stdout_stderr();
1094        raise_exception(cond);
1095        /* NOTREACHED */
1096}
1097
1098static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1099static void
1100ash_msg_and_raise_error(const char *msg, ...)
1101{
1102        va_list ap;
1103
1104        va_start(ap, msg);
1105        ash_vmsg_and_raise(EXERROR, msg, ap);
1106        /* NOTREACHED */
1107        va_end(ap);
1108}
1109
1110static void raise_error_syntax(const char *) NORETURN;
1111static void
1112raise_error_syntax(const char *msg)
1113{
1114        ash_msg_and_raise_error("syntax error: %s", msg);
1115        /* NOTREACHED */
1116}
1117
1118static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1119static void
1120ash_msg_and_raise(int cond, const char *msg, ...)
1121{
1122        va_list ap;
1123
1124        va_start(ap, msg);
1125        ash_vmsg_and_raise(cond, msg, ap);
1126        /* NOTREACHED */
1127        va_end(ap);
1128}
1129
1130/*
1131 * error/warning routines for external builtins
1132 */
1133static void
1134ash_msg(const char *fmt, ...)
1135{
1136        va_list ap;
1137
1138        va_start(ap, fmt);
1139        ash_vmsg(fmt, ap);
1140        va_end(ap);
1141}
1142
1143/*
1144 * Return a string describing an error.  The returned string may be a
1145 * pointer to a static buffer that will be overwritten on the next call.
1146 * Action describes the operation that got the error.
1147 */
1148static const char *
1149errmsg(int e, const char *em)
1150{
1151        if (e == ENOENT || e == ENOTDIR) {
1152                return em;
1153        }
1154        return strerror(e);
1155}
1156
1157
1158/* ============ Memory allocation */
1159
1160#if 0
1161/* I consider these wrappers nearly useless:
1162 * ok, they return you to nearest exception handler, but
1163 * how much memory do you leak in the process, making
1164 * memory starvation worse?
1165 */
1166static void *
1167ckrealloc(void * p, size_t nbytes)
1168{
1169        p = realloc(p, nbytes);
1170        if (!p)
1171                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1172        return p;
1173}
1174
1175static void *
1176ckmalloc(size_t nbytes)
1177{
1178        return ckrealloc(NULL, nbytes);
1179}
1180
1181static void *
1182ckzalloc(size_t nbytes)
1183{
1184        return memset(ckmalloc(nbytes), 0, nbytes);
1185}
1186
1187static char *
1188ckstrdup(const char *s)
1189{
1190        char *p = strdup(s);
1191        if (!p)
1192                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1193        return p;
1194}
1195#else
1196/* Using bbox equivalents. They exit if out of memory */
1197# define ckrealloc xrealloc
1198# define ckmalloc  xmalloc
1199# define ckzalloc  xzalloc
1200# define ckstrdup  xstrdup
1201#endif
1202
1203/*
1204 * It appears that grabstackstr() will barf with such alignments
1205 * because stalloc() will return a string allocated in a new stackblock.
1206 */
1207#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1208enum {
1209        /* Most machines require the value returned from malloc to be aligned
1210         * in some way.  The following macro will get this right
1211         * on many machines.  */
1212        SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1213        /* Minimum size of a block */
1214        MINSIZE = SHELL_ALIGN(504),
1215};
1216
1217struct stack_block {
1218        struct stack_block *prev;
1219        char space[MINSIZE];
1220};
1221
1222struct stackmark {
1223        struct stack_block *stackp;
1224        char *stacknxt;
1225        size_t stacknleft;
1226        struct stackmark *marknext;
1227};
1228
1229
1230struct globals_memstack {
1231        struct stack_block *g_stackp; // = &stackbase;
1232        struct stackmark *markp;
1233        char *g_stacknxt; // = stackbase.space;
1234        char *sstrend; // = stackbase.space + MINSIZE;
1235        size_t g_stacknleft; // = MINSIZE;
1236        int    herefd; // = -1;
1237        struct stack_block stackbase;
1238};
1239extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1240#define G_memstack (*ash_ptr_to_globals_memstack)
1241#define g_stackp     (G_memstack.g_stackp    )
1242#define markp        (G_memstack.markp       )
1243#define g_stacknxt   (G_memstack.g_stacknxt  )
1244#define sstrend      (G_memstack.sstrend     )
1245#define g_stacknleft (G_memstack.g_stacknleft)
1246#define herefd       (G_memstack.herefd      )
1247#define stackbase    (G_memstack.stackbase   )
1248#define INIT_G_memstack() do { \
1249        (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1250        barrier(); \
1251        g_stackp = &stackbase; \
1252        g_stacknxt = stackbase.space; \
1253        g_stacknleft = MINSIZE; \
1254        sstrend = stackbase.space + MINSIZE; \
1255        herefd = -1; \
1256} while (0)
1257
1258
1259#define stackblock()     ((void *)g_stacknxt)
1260#define stackblocksize() g_stacknleft
1261
1262/*
1263 * Parse trees for commands are allocated in lifo order, so we use a stack
1264 * to make this more efficient, and also to avoid all sorts of exception
1265 * handling code to handle interrupts in the middle of a parse.
1266 *
1267 * The size 504 was chosen because the Ultrix malloc handles that size
1268 * well.
1269 */
1270static void *
1271stalloc(size_t nbytes)
1272{
1273        char *p;
1274        size_t aligned;
1275
1276        aligned = SHELL_ALIGN(nbytes);
1277        if (aligned > g_stacknleft) {
1278                size_t len;
1279                size_t blocksize;
1280                struct stack_block *sp;
1281
1282                blocksize = aligned;
1283                if (blocksize < MINSIZE)
1284                        blocksize = MINSIZE;
1285                len = sizeof(struct stack_block) - MINSIZE + blocksize;
1286                if (len < blocksize)
1287                        ash_msg_and_raise_error(bb_msg_memory_exhausted);
1288                INT_OFF;
1289                sp = ckmalloc(len);
1290                sp->prev = g_stackp;
1291                g_stacknxt = sp->space;
1292                g_stacknleft = blocksize;
1293                sstrend = g_stacknxt + blocksize;
1294                g_stackp = sp;
1295                INT_ON;
1296        }
1297        p = g_stacknxt;
1298        g_stacknxt += aligned;
1299        g_stacknleft -= aligned;
1300        return p;
1301}
1302
1303static void *
1304stzalloc(size_t nbytes)
1305{
1306        return memset(stalloc(nbytes), 0, nbytes);
1307}
1308
1309static void
1310stunalloc(void *p)
1311{
1312#if DEBUG
1313        if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1314                write(STDERR_FILENO, "stunalloc\n", 10);
1315                abort();
1316        }
1317#endif
1318        g_stacknleft += g_stacknxt - (char *)p;
1319        g_stacknxt = p;
1320}
1321
1322/*
1323 * Like strdup but works with the ash stack.
1324 */
1325static char *
1326ststrdup(const char *p)
1327{
1328        size_t len = strlen(p) + 1;
1329        return memcpy(stalloc(len), p, len);
1330}
1331
1332static void
1333setstackmark(struct stackmark *mark)
1334{
1335        mark->stackp = g_stackp;
1336        mark->stacknxt = g_stacknxt;
1337        mark->stacknleft = g_stacknleft;
1338        mark->marknext = markp;
1339        markp = mark;
1340}
1341
1342static void
1343popstackmark(struct stackmark *mark)
1344{
1345        struct stack_block *sp;
1346
1347        if (!mark->stackp)
1348                return;
1349
1350        INT_OFF;
1351        markp = mark->marknext;
1352        while (g_stackp != mark->stackp) {
1353                sp = g_stackp;
1354                g_stackp = sp->prev;
1355                free(sp);
1356        }
1357        g_stacknxt = mark->stacknxt;
1358        g_stacknleft = mark->stacknleft;
1359        sstrend = mark->stacknxt + mark->stacknleft;
1360        INT_ON;
1361}
1362
1363/*
1364 * When the parser reads in a string, it wants to stick the string on the
1365 * stack and only adjust the stack pointer when it knows how big the
1366 * string is.  Stackblock (defined in stack.h) returns a pointer to a block
1367 * of space on top of the stack and stackblocklen returns the length of
1368 * this block.  Growstackblock will grow this space by at least one byte,
1369 * possibly moving it (like realloc).  Grabstackblock actually allocates the
1370 * part of the block that has been used.
1371 */
1372static void
1373growstackblock(void)
1374{
1375        size_t newlen;
1376
1377        newlen = g_stacknleft * 2;
1378        if (newlen < g_stacknleft)
1379                ash_msg_and_raise_error(bb_msg_memory_exhausted);
1380        if (newlen < 128)
1381                newlen += 128;
1382
1383        if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1384                struct stack_block *oldstackp;
1385                struct stackmark *xmark;
1386                struct stack_block *sp;
1387                struct stack_block *prevstackp;
1388                size_t grosslen;
1389
1390                INT_OFF;
1391                oldstackp = g_stackp;
1392                sp = g_stackp;
1393                prevstackp = sp->prev;
1394                grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1395                sp = ckrealloc(sp, grosslen);
1396                sp->prev = prevstackp;
1397                g_stackp = sp;
1398                g_stacknxt = sp->space;
1399                g_stacknleft = newlen;
1400                sstrend = sp->space + newlen;
1401
1402                /*
1403                 * Stack marks pointing to the start of the old block
1404                 * must be relocated to point to the new block
1405                 */
1406                xmark = markp;
1407                while (xmark != NULL && xmark->stackp == oldstackp) {
1408                        xmark->stackp = g_stackp;
1409                        xmark->stacknxt = g_stacknxt;
1410                        xmark->stacknleft = g_stacknleft;
1411                        xmark = xmark->marknext;
1412                }
1413                INT_ON;
1414        } else {
1415                char *oldspace = g_stacknxt;
1416                size_t oldlen = g_stacknleft;
1417                char *p = stalloc(newlen);
1418
1419                /* free the space we just allocated */
1420                g_stacknxt = memcpy(p, oldspace, oldlen);
1421                g_stacknleft += newlen;
1422        }
1423}
1424
1425static void
1426grabstackblock(size_t len)
1427{
1428        len = SHELL_ALIGN(len);
1429        g_stacknxt += len;
1430        g_stacknleft -= len;
1431}
1432
1433/*
1434 * The following routines are somewhat easier to use than the above.
1435 * The user declares a variable of type STACKSTR, which may be declared
1436 * to be a register.  The macro STARTSTACKSTR initializes things.  Then
1437 * the user uses the macro STPUTC to add characters to the string.  In
1438 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1439 * grown as necessary.  When the user is done, she can just leave the
1440 * string there and refer to it using stackblock().  Or she can allocate
1441 * the space for it using grabstackstr().  If it is necessary to allow
1442 * someone else to use the stack temporarily and then continue to grow
1443 * the string, the user should use grabstack to allocate the space, and
1444 * then call ungrabstr(p) to return to the previous mode of operation.
1445 *
1446 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1447 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1448 * is space for at least one character.
1449 */
1450static void *
1451growstackstr(void)
1452{
1453        size_t len = stackblocksize();
1454        if (herefd >= 0 && len >= 1024) {
1455                full_write(herefd, stackblock(), len);
1456                return stackblock();
1457        }
1458        growstackblock();
1459        return (char *)stackblock() + len;
1460}
1461
1462/*
1463 * Called from CHECKSTRSPACE.
1464 */
1465static char *
1466makestrspace(size_t newlen, char *p)
1467{
1468        size_t len = p - g_stacknxt;
1469        size_t size = stackblocksize();
1470
1471        for (;;) {
1472                size_t nleft;
1473
1474                size = stackblocksize();
1475                nleft = size - len;
1476                if (nleft >= newlen)
1477                        break;
1478                growstackblock();
1479        }
1480        return (char *)stackblock() + len;
1481}
1482
1483static char *
1484stack_nputstr(const char *s, size_t n, char *p)
1485{
1486        p = makestrspace(n, p);
1487        p = (char *)memcpy(p, s, n) + n;
1488        return p;
1489}
1490
1491static char *
1492stack_putstr(const char *s, char *p)
1493{
1494        return stack_nputstr(s, strlen(s), p);
1495}
1496
1497static char *
1498_STPUTC(int c, char *p)
1499{
1500        if (p == sstrend)
1501                p = growstackstr();
1502        *p++ = c;
1503        return p;
1504}
1505
1506#define STARTSTACKSTR(p)        ((p) = stackblock())
1507#define STPUTC(c, p)            ((p) = _STPUTC((c), (p)))
1508#define CHECKSTRSPACE(n, p) do { \
1509        char *q = (p); \
1510        size_t l = (n); \
1511        size_t m = sstrend - q; \
1512        if (l > m) \
1513                (p) = makestrspace(l, q); \
1514} while (0)
1515#define USTPUTC(c, p)           (*(p)++ = (c))
1516#define STACKSTRNUL(p) do { \
1517        if ((p) == sstrend) \
1518                (p) = growstackstr(); \
1519        *(p) = '\0'; \
1520} while (0)
1521#define STUNPUTC(p)             (--(p))
1522#define STTOPC(p)               ((p)[-1])
1523#define STADJUST(amount, p)     ((p) += (amount))
1524
1525#define grabstackstr(p)         stalloc((char *)(p) - (char *)stackblock())
1526#define ungrabstackstr(s, p)    stunalloc(s)
1527#define stackstrend()           ((void *)sstrend)
1528
1529
1530/* ============ String helpers */
1531
1532/*
1533 * prefix -- see if pfx is a prefix of string.
1534 */
1535static char *
1536prefix(const char *string, const char *pfx)
1537{
1538        while (*pfx) {
1539                if (*pfx++ != *string++)
1540                        return NULL;
1541        }
1542        return (char *) string;
1543}
1544
1545/*
1546 * Check for a valid number.  This should be elsewhere.
1547 */
1548static int
1549is_number(const char *p)
1550{
1551        do {
1552                if (!isdigit(*p))
1553                        return 0;
1554        } while (*++p != '\0');
1555        return 1;
1556}
1557
1558/*
1559 * Convert a string of digits to an integer, printing an error message on
1560 * failure.
1561 */
1562static int
1563number(const char *s)
1564{
1565        if (!is_number(s))
1566                ash_msg_and_raise_error(msg_illnum, s);
1567        return atoi(s);
1568}
1569
1570/*
1571 * Produce a possibly single quoted string suitable as input to the shell.
1572 * The return string is allocated on the stack.
1573 */
1574static char *
1575single_quote(const char *s)
1576{
1577        char *p;
1578
1579        STARTSTACKSTR(p);
1580
1581        do {
1582                char *q;
1583                size_t len;
1584
1585                len = strchrnul(s, '\'') - s;
1586
1587                q = p = makestrspace(len + 3, p);
1588
1589                *q++ = '\'';
1590                q = (char *)memcpy(q, s, len) + len;
1591                *q++ = '\'';
1592                s += len;
1593
1594                STADJUST(q - p, p);
1595
1596                if (*s != '\'')
1597                        break;
1598                len = 0;
1599                do len++; while (*++s == '\'');
1600
1601                q = p = makestrspace(len + 3, p);
1602
1603                *q++ = '"';
1604                q = (char *)memcpy(q, s - len, len) + len;
1605                *q++ = '"';
1606
1607                STADJUST(q - p, p);
1608        } while (*s);
1609
1610        USTPUTC('\0', p);
1611
1612        return stackblock();
1613}
1614
1615
1616/* ============ nextopt */
1617
1618static char **argptr;                  /* argument list for builtin commands */
1619static char *optionarg;                /* set by nextopt (like getopt) */
1620static char *optptr;                   /* used by nextopt */
1621
1622/*
1623 * XXX - should get rid of. Have all builtins use getopt(3).
1624 * The library getopt must have the BSD extension static variable
1625 * "optreset", otherwise it can't be used within the shell safely.
1626 *
1627 * Standard option processing (a la getopt) for builtin routines.
1628 * The only argument that is passed to nextopt is the option string;
1629 * the other arguments are unnecessary. It returns the character,
1630 * or '\0' on end of input.
1631 */
1632static int
1633nextopt(const char *optstring)
1634{
1635        char *p;
1636        const char *q;
1637        char c;
1638
1639        p = optptr;
1640        if (p == NULL || *p == '\0') {
1641                /* We ate entire "-param", take next one */
1642                p = *argptr;
1643                if (p == NULL)
1644                        return '\0';
1645                if (*p != '-')
1646                        return '\0';
1647                if (*++p == '\0') /* just "-" ? */
1648                        return '\0';
1649                argptr++;
1650                if (LONE_DASH(p)) /* "--" ? */
1651                        return '\0';
1652                /* p => next "-param" */
1653        }
1654        /* p => some option char in the middle of a "-param" */
1655        c = *p++;
1656        for (q = optstring; *q != c;) {
1657                if (*q == '\0')
1658                        ash_msg_and_raise_error("illegal option -%c", c);
1659                if (*++q == ':')
1660                        q++;
1661        }
1662        if (*++q == ':') {
1663                if (*p == '\0') {
1664                        p = *argptr++;
1665                        if (p == NULL)
1666                                ash_msg_and_raise_error("no arg for -%c option", c);
1667                }
1668                optionarg = p;
1669                p = NULL;
1670        }
1671        optptr = p;
1672        return c;
1673}
1674
1675
1676/* ============ Shell variables */
1677
1678/*
1679 * The parsefile structure pointed to by the global variable parsefile
1680 * contains information about the current file being read.
1681 */
1682struct shparam {
1683        int nparam;             /* # of positional parameters (without $0) */
1684#if ENABLE_ASH_GETOPTS
1685        int optind;             /* next parameter to be processed by getopts */
1686        int optoff;             /* used by getopts */
1687#endif
1688        unsigned char malloced; /* if parameter list dynamically allocated */
1689        char **p;               /* parameter list */
1690};
1691
1692/*
1693 * Free the list of positional parameters.
1694 */
1695static void
1696freeparam(volatile struct shparam *param)
1697{
1698        if (param->malloced) {
1699                char **ap, **ap1;
1700                ap = ap1 = param->p;
1701                while (*ap)
1702                        free(*ap++);
1703                free(ap1);
1704        }
1705}
1706
1707#if ENABLE_ASH_GETOPTS
1708static void FAST_FUNC getoptsreset(const char *value);
1709#endif
1710
1711struct var {
1712        struct var *next;               /* next entry in hash list */
1713        int flags;                      /* flags are defined above */
1714        const char *var_text;           /* name=value */
1715        void (*var_func)(const char *) FAST_FUNC; /* function to be called when  */
1716                                        /* the variable gets set/unset */
1717};
1718
1719struct localvar {
1720        struct localvar *next;          /* next local variable in list */
1721        struct var *vp;                 /* the variable that was made local */
1722        int flags;                      /* saved flags */
1723        const char *text;               /* saved text */
1724};
1725
1726/* flags */
1727#define VEXPORT         0x01    /* variable is exported */
1728#define VREADONLY       0x02    /* variable cannot be modified */
1729#define VSTRFIXED       0x04    /* variable struct is statically allocated */
1730#define VTEXTFIXED      0x08    /* text is statically allocated */
1731#define VSTACK          0x10    /* text is allocated on the stack */
1732#define VUNSET          0x20    /* the variable is not set */
1733#define VNOFUNC         0x40    /* don't call the callback function */
1734#define VNOSET          0x80    /* do not set variable - just readonly test */
1735#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
1736#if ENABLE_ASH_RANDOM_SUPPORT
1737# define VDYNAMIC       0x200   /* dynamic variable */
1738#else
1739# define VDYNAMIC       0
1740#endif
1741
1742
1743/* Need to be before varinit_data[] */
1744#if ENABLE_LOCALE_SUPPORT
1745static void FAST_FUNC
1746change_lc_all(const char *value)
1747{
1748        if (value && *value != '\0')
1749                setlocale(LC_ALL, value);
1750}
1751static void FAST_FUNC
1752change_lc_ctype(const char *value)
1753{
1754        if (value && *value != '\0')
1755                setlocale(LC_CTYPE, value);
1756}
1757#endif
1758#if ENABLE_ASH_MAIL
1759static void chkmail(void);
1760static void changemail(const char *) FAST_FUNC;
1761#endif
1762static void changepath(const char *) FAST_FUNC;
1763#if ENABLE_ASH_RANDOM_SUPPORT
1764static void change_random(const char *) FAST_FUNC;
1765#endif
1766
1767static const struct {
1768        int flags;
1769        const char *var_text;
1770        void (*var_func)(const char *) FAST_FUNC;
1771} varinit_data[] = {
1772        { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
1773#if ENABLE_ASH_MAIL
1774        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL"      , changemail      },
1775        { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH"  , changemail      },
1776#endif
1777        { VSTRFIXED|VTEXTFIXED       , bb_PATH_root_path, changepath },
1778        { VSTRFIXED|VTEXTFIXED       , "PS1=$ "    , NULL            },
1779        { VSTRFIXED|VTEXTFIXED       , "PS2=> "    , NULL            },
1780        { VSTRFIXED|VTEXTFIXED       , "PS4=+ "    , NULL            },
1781#if ENABLE_ASH_GETOPTS
1782        { VSTRFIXED|VTEXTFIXED       , "OPTIND=1"  , getoptsreset    },
1783#endif
1784#if ENABLE_ASH_RANDOM_SUPPORT
1785        { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
1786#endif
1787#if ENABLE_LOCALE_SUPPORT
1788        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL"    , change_lc_all   },
1789        { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE"  , change_lc_ctype },
1790#endif
1791#if ENABLE_FEATURE_EDITING_SAVEHISTORY
1792        { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE"  , NULL            },
1793#endif
1794};
1795
1796struct redirtab;
1797
1798struct globals_var {
1799        struct shparam shellparam;      /* $@ current positional parameters */
1800        struct redirtab *redirlist;
1801        int g_nullredirs;
1802        int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
1803        struct var *vartab[VTABSIZE];
1804        struct var varinit[ARRAY_SIZE(varinit_data)];
1805};
1806extern struct globals_var *const ash_ptr_to_globals_var;
1807#define G_var (*ash_ptr_to_globals_var)
1808#define shellparam    (G_var.shellparam   )
1809//#define redirlist     (G_var.redirlist    )
1810#define g_nullredirs  (G_var.g_nullredirs )
1811#define preverrout_fd (G_var.preverrout_fd)
1812#define vartab        (G_var.vartab       )
1813#define varinit       (G_var.varinit      )
1814#define INIT_G_var() do { \
1815        unsigned i; \
1816        (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1817        barrier(); \
1818        for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1819                varinit[i].flags    = varinit_data[i].flags; \
1820                varinit[i].var_text = varinit_data[i].var_text; \
1821                varinit[i].var_func = varinit_data[i].var_func; \
1822        } \
1823} while (0)
1824
1825#define vifs      varinit[0]
1826#if ENABLE_ASH_MAIL
1827# define vmail    (&vifs)[1]
1828# define vmpath   (&vmail)[1]
1829# define vpath    (&vmpath)[1]
1830#else
1831# define vpath    (&vifs)[1]
1832#endif
1833#define vps1      (&vpath)[1]
1834#define vps2      (&vps1)[1]
1835#define vps4      (&vps2)[1]
1836#if ENABLE_ASH_GETOPTS
1837# define voptind  (&vps4)[1]
1838# if ENABLE_ASH_RANDOM_SUPPORT
1839#  define vrandom (&voptind)[1]
1840# endif
1841#else
1842# if ENABLE_ASH_RANDOM_SUPPORT
1843#  define vrandom (&vps4)[1]
1844# endif
1845#endif
1846
1847/*
1848 * The following macros access the values of the above variables.
1849 * They have to skip over the name.  They return the null string
1850 * for unset variables.
1851 */
1852#define ifsval()        (vifs.var_text + 4)
1853#define ifsset()        ((vifs.flags & VUNSET) == 0)
1854#if ENABLE_ASH_MAIL
1855# define mailval()      (vmail.var_text + 5)
1856# define mpathval()     (vmpath.var_text + 9)
1857# define mpathset()     ((vmpath.flags & VUNSET) == 0)
1858#endif
1859#define pathval()       (vpath.var_text + 5)
1860#define ps1val()        (vps1.var_text + 4)
1861#define ps2val()        (vps2.var_text + 4)
1862#define ps4val()        (vps4.var_text + 4)
1863#if ENABLE_ASH_GETOPTS
1864# define optindval()    (voptind.var_text + 7)
1865#endif
1866
1867
1868#define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
1869#define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
1870
1871#if ENABLE_ASH_GETOPTS
1872static void FAST_FUNC
1873getoptsreset(const char *value)
1874{
1875        shellparam.optind = number(value);
1876        shellparam.optoff = -1;
1877}
1878#endif
1879
1880/*
1881 * Return of a legal variable name (a letter or underscore followed by zero or
1882 * more letters, underscores, and digits).
1883 */
1884static char* FAST_FUNC
1885endofname(const char *name)
1886{
1887        char *p;
1888
1889        p = (char *) name;
1890        if (!is_name(*p))
1891                return p;
1892        while (*++p) {
1893                if (!is_in_name(*p))
1894                        break;
1895        }
1896        return p;
1897}
1898
1899/*
1900 * Compares two strings up to the first = or '\0'.  The first
1901 * string must be terminated by '='; the second may be terminated by
1902 * either '=' or '\0'.
1903 */
1904static int
1905varcmp(const char *p, const char *q)
1906{
1907        int c, d;
1908
1909        while ((c = *p) == (d = *q)) {
1910                if (!c || c == '=')
1911                        goto out;
1912                p++;
1913                q++;
1914        }
1915        if (c == '=')
1916                c = '\0';
1917        if (d == '=')
1918                d = '\0';
1919 out:
1920        return c - d;
1921}
1922
1923/*
1924 * Find the appropriate entry in the hash table from the name.
1925 */
1926static struct var **
1927hashvar(const char *p)
1928{
1929        unsigned hashval;
1930
1931        hashval = ((unsigned char) *p) << 4;
1932        while (*p && *p != '=')
1933                hashval += (unsigned char) *p++;
1934        return &vartab[hashval % VTABSIZE];
1935}
1936
1937static int
1938vpcmp(const void *a, const void *b)
1939{
1940        return varcmp(*(const char **)a, *(const char **)b);
1941}
1942
1943/*
1944 * This routine initializes the builtin variables.
1945 */
1946static void
1947initvar(void)
1948{
1949        struct var *vp;
1950        struct var *end;
1951        struct var **vpp;
1952
1953        /*
1954         * PS1 depends on uid
1955         */
1956#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1957        vps1.var_text = "PS1=\\w \\$ ";
1958#else
1959        if (!geteuid())
1960                vps1.var_text = "PS1=# ";
1961#endif
1962        vp = varinit;
1963        end = vp + ARRAY_SIZE(varinit);
1964        do {
1965                vpp = hashvar(vp->var_text);
1966                vp->next = *vpp;
1967                *vpp = vp;
1968        } while (++vp < end);
1969}
1970
1971static struct var **
1972findvar(struct var **vpp, const char *name)
1973{
1974        for (; *vpp; vpp = &(*vpp)->next) {
1975                if (varcmp((*vpp)->var_text, name) == 0) {
1976                        break;
1977                }
1978        }
1979        return vpp;
1980}
1981
1982/*
1983 * Find the value of a variable.  Returns NULL if not set.
1984 */
1985static const char* FAST_FUNC
1986lookupvar(const char *name)
1987{
1988        struct var *v;
1989
1990        v = *findvar(hashvar(name), name);
1991        if (v) {
1992#if ENABLE_ASH_RANDOM_SUPPORT
1993        /*
1994         * Dynamic variables are implemented roughly the same way they are
1995         * in bash. Namely, they're "special" so long as they aren't unset.
1996         * As soon as they're unset, they're no longer dynamic, and dynamic
1997         * lookup will no longer happen at that point. -- PFM.
1998         */
1999                if (v->flags & VDYNAMIC)
2000                        v->var_func(NULL);
2001#endif
2002                if (!(v->flags & VUNSET))
2003                        return var_end(v->var_text);
2004        }
2005        return NULL;
2006}
2007
2008/*
2009 * Search the environment of a builtin command.
2010 */
2011static const char *
2012bltinlookup(const char *name)
2013{
2014        struct strlist *sp;
2015
2016        for (sp = cmdenviron; sp; sp = sp->next) {
2017                if (varcmp(sp->text, name) == 0)
2018                        return var_end(sp->text);
2019        }
2020        return lookupvar(name);
2021}
2022
2023/*
2024 * Same as setvar except that the variable and value are passed in
2025 * the first argument as name=value.  Since the first argument will
2026 * be actually stored in the table, it should not be a string that
2027 * will go away.
2028 * Called with interrupts off.
2029 */
2030static void
2031setvareq(char *s, int flags)
2032{
2033        struct var *vp, **vpp;
2034
2035        vpp = hashvar(s);
2036        flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2037        vp = *findvar(vpp, s);
2038        if (vp) {
2039                if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2040                        const char *n;
2041
2042                        if (flags & VNOSAVE)
2043                                free(s);
2044                        n = vp->var_text;
2045                        ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2046                }
2047
2048                if (flags & VNOSET)
2049                        return;
2050
2051                if (vp->var_func && !(flags & VNOFUNC))
2052                        vp->var_func(var_end(s));
2053
2054                if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2055                        free((char*)vp->var_text);
2056
2057                flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2058        } else {
2059                /* variable s is not found */
2060                if (flags & VNOSET)
2061                        return;
2062                vp = ckzalloc(sizeof(*vp));
2063                vp->next = *vpp;
2064                /*vp->func = NULL; - ckzalloc did it */
2065                *vpp = vp;
2066        }
2067        if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2068                s = ckstrdup(s);
2069        vp->var_text = s;
2070        vp->flags = flags;
2071}
2072
2073/*
2074 * Set the value of a variable.  The flags argument is ored with the
2075 * flags of the variable.  If val is NULL, the variable is unset.
2076 */
2077static void
2078setvar(const char *name, const char *val, int flags)
2079{
2080        char *p, *q;
2081        size_t namelen;
2082        char *nameeq;
2083        size_t vallen;
2084
2085        q = endofname(name);
2086        p = strchrnul(q, '=');
2087        namelen = p - name;
2088        if (!namelen || p != q)
2089                ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2090        vallen = 0;
2091        if (val == NULL) {
2092                flags |= VUNSET;
2093        } else {
2094                vallen = strlen(val);
2095        }
2096        INT_OFF;
2097        nameeq = ckmalloc(namelen + vallen + 2);
2098        p = (char *)memcpy(nameeq, name, namelen) + namelen;
2099        if (val) {
2100                *p++ = '=';
2101                p = (char *)memcpy(p, val, vallen) + vallen;
2102        }
2103        *p = '\0';
2104        setvareq(nameeq, flags | VNOSAVE);
2105        INT_ON;
2106}
2107
2108static void FAST_FUNC
2109setvar2(const char *name, const char *val)
2110{
2111        setvar(name, val, 0);
2112}
2113
2114#if ENABLE_ASH_GETOPTS
2115/*
2116 * Safe version of setvar, returns 1 on success 0 on failure.
2117 */
2118static int
2119setvarsafe(const char *name, const char *val, int flags)
2120{
2121        int err;
2122        volatile int saveint;
2123        struct jmploc *volatile savehandler = exception_handler;
2124        struct jmploc jmploc;
2125
2126        SAVE_INT(saveint);
2127        if (setjmp(jmploc.loc))
2128                err = 1;
2129        else {
2130                exception_handler = &jmploc;
2131                setvar(name, val, flags);
2132                err = 0;
2133        }
2134        exception_handler = savehandler;
2135        RESTORE_INT(saveint);
2136        return err;
2137}
2138#endif
2139
2140/*
2141 * Unset the specified variable.
2142 */
2143static int
2144unsetvar(const char *s)
2145{
2146        struct var **vpp;
2147        struct var *vp;
2148        int retval;
2149
2150        vpp = findvar(hashvar(s), s);
2151        vp = *vpp;
2152        retval = 2;
2153        if (vp) {
2154                int flags = vp->flags;
2155
2156                retval = 1;
2157                if (flags & VREADONLY)
2158                        goto out;
2159#if ENABLE_ASH_RANDOM_SUPPORT
2160                vp->flags &= ~VDYNAMIC;
2161#endif
2162                if (flags & VUNSET)
2163                        goto ok;
2164                if ((flags & VSTRFIXED) == 0) {
2165                        INT_OFF;
2166                        if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2167                                free((char*)vp->var_text);
2168                        *vpp = vp->next;
2169                        free(vp);
2170                        INT_ON;
2171                } else {
2172                        setvar(s, 0, 0);
2173                        vp->flags &= ~VEXPORT;
2174                }
2175 ok:
2176                retval = 0;
2177        }
2178 out:
2179        return retval;
2180}
2181
2182/*
2183 * Process a linked list of variable assignments.
2184 */
2185static void
2186listsetvar(struct strlist *list_set_var, int flags)
2187{
2188        struct strlist *lp = list_set_var;
2189
2190        if (!lp)
2191                return;
2192        INT_OFF;
2193        do {
2194                setvareq(lp->text, flags);
2195                lp = lp->next;
2196        } while (lp);
2197        INT_ON;
2198}
2199
2200/*
2201 * Generate a list of variables satisfying the given conditions.
2202 */
2203static char **
2204listvars(int on, int off, char ***end)
2205{
2206        struct var **vpp;
2207        struct var *vp;
2208        char **ep;
2209        int mask;
2210
2211        STARTSTACKSTR(ep);
2212        vpp = vartab;
2213        mask = on | off;
2214        do {
2215                for (vp = *vpp; vp; vp = vp->next) {
2216                        if ((vp->flags & mask) == on) {
2217                                if (ep == stackstrend())
2218                                        ep = growstackstr();
2219                                *ep++ = (char*)vp->var_text;
2220                        }
2221                }
2222        } while (++vpp < vartab + VTABSIZE);
2223        if (ep == stackstrend())
2224                ep = growstackstr();
2225        if (end)
2226                *end = ep;
2227        *ep++ = NULL;
2228        return grabstackstr(ep);
2229}
2230
2231
2232/* ============ Path search helper
2233 *
2234 * The variable path (passed by reference) should be set to the start
2235 * of the path before the first call; path_advance will update
2236 * this value as it proceeds.  Successive calls to path_advance will return
2237 * the possible path expansions in sequence.  If an option (indicated by
2238 * a percent sign) appears in the path entry then the global variable
2239 * pathopt will be set to point to it; otherwise pathopt will be set to
2240 * NULL.
2241 */
2242static const char *pathopt;     /* set by path_advance */
2243
2244static char *
2245path_advance(const char **path, const char *name)
2246{
2247        const char *p;
2248        char *q;
2249        const char *start;
2250        size_t len;
2251
2252        if (*path == NULL)
2253                return NULL;
2254        start = *path;
2255        for (p = start; *p && *p != ':' && *p != '%'; p++)
2256                continue;
2257        len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
2258        while (stackblocksize() < len)
2259                growstackblock();
2260        q = stackblock();
2261        if (p != start) {
2262                memcpy(q, start, p - start);
2263                q += p - start;
2264                *q++ = '/';
2265        }
2266        strcpy(q, name);
2267        pathopt = NULL;
2268        if (*p == '%') {
2269                pathopt = ++p;
2270                while (*p && *p != ':')
2271                        p++;
2272        }
2273        if (*p == ':')
2274                *path = p + 1;
2275        else
2276                *path = NULL;
2277        return stalloc(len);
2278}
2279
2280
2281/* ============ Prompt */
2282
2283static smallint doprompt;                   /* if set, prompt the user */
2284static smallint needprompt;                 /* true if interactive and at start of line */
2285
2286#if ENABLE_FEATURE_EDITING
2287static line_input_t *line_input_state;
2288static const char *cmdedit_prompt;
2289static void
2290putprompt(const char *s)
2291{
2292        if (ENABLE_ASH_EXPAND_PRMT) {
2293                free((char*)cmdedit_prompt);
2294                cmdedit_prompt = ckstrdup(s);
2295                return;
2296        }
2297        cmdedit_prompt = s;
2298}
2299#else
2300static void
2301putprompt(const char *s)
2302{
2303        out2str(s);
2304}
2305#endif
2306
2307#if ENABLE_ASH_EXPAND_PRMT
2308/* expandstr() needs parsing machinery, so it is far away ahead... */
2309static const char *expandstr(const char *ps);
2310#else
2311#define expandstr(s) s
2312#endif
2313
2314static void
2315setprompt(int whichprompt)
2316{
2317        const char *prompt;
2318#if ENABLE_ASH_EXPAND_PRMT
2319        struct stackmark smark;
2320#endif
2321
2322        needprompt = 0;
2323
2324        switch (whichprompt) {
2325        case 1:
2326                prompt = ps1val();
2327                break;
2328        case 2:
2329                prompt = ps2val();
2330                break;
2331        default:                        /* 0 */
2332                prompt = nullstr;
2333        }
2334#if ENABLE_ASH_EXPAND_PRMT
2335        setstackmark(&smark);
2336        stalloc(stackblocksize());
2337#endif
2338        putprompt(expandstr(prompt));
2339#if ENABLE_ASH_EXPAND_PRMT
2340        popstackmark(&smark);
2341#endif
2342}
2343
2344
2345/* ============ The cd and pwd commands */
2346
2347#define CD_PHYSICAL 1
2348#define CD_PRINT 2
2349
2350static int
2351cdopt(void)
2352{
2353        int flags = 0;
2354        int i, j;
2355
2356        j = 'L';
2357        while ((i = nextopt("LP")) != '\0') {
2358                if (i != j) {
2359                        flags ^= CD_PHYSICAL;
2360                        j = i;
2361                }
2362        }
2363
2364        return flags;
2365}
2366
2367/*
2368 * Update curdir (the name of the current directory) in response to a
2369 * cd command.
2370 */
2371static const char *
2372updatepwd(const char *dir)
2373{
2374        char *new;
2375        char *p;
2376        char *cdcomppath;
2377        const char *lim;
2378
2379        cdcomppath = ststrdup(dir);
2380        STARTSTACKSTR(new);
2381        if (*dir != '/') {
2382                if (curdir == nullstr)
2383                        return 0;
2384                new = stack_putstr(curdir, new);
2385        }
2386        new = makestrspace(strlen(dir) + 2, new);
2387        lim = (char *)stackblock() + 1;
2388        if (*dir != '/') {
2389                if (new[-1] != '/')
2390                        USTPUTC('/', new);
2391                if (new > lim && *lim == '/')
2392                        lim++;
2393        } else {
2394                USTPUTC('/', new);
2395                cdcomppath++;
2396                if (dir[1] == '/' && dir[2] != '/') {
2397                        USTPUTC('/', new);
2398                        cdcomppath++;
2399                        lim++;
2400                }
2401        }
2402        p = strtok(cdcomppath, "/");
2403        while (p) {
2404                switch (*p) {
2405                case '.':
2406                        if (p[1] == '.' && p[2] == '\0') {
2407                                while (new > lim) {
2408                                        STUNPUTC(new);
2409                                        if (new[-1] == '/')
2410                                                break;
2411                                }
2412                                break;
2413                        }
2414                        if (p[1] == '\0')
2415                                break;
2416                        /* fall through */
2417                default:
2418                        new = stack_putstr(p, new);
2419                        USTPUTC('/', new);
2420                }
2421                p = strtok(0, "/");
2422        }
2423        if (new > lim)
2424                STUNPUTC(new);
2425        *new = 0;
2426        return stackblock();
2427}
2428
2429/*
2430 * Find out what the current directory is. If we already know the current
2431 * directory, this routine returns immediately.
2432 */
2433static char *
2434getpwd(void)
2435{
2436        char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2437        return dir ? dir : nullstr;
2438}
2439
2440static void
2441setpwd(const char *val, int setold)
2442{
2443        char *oldcur, *dir;
2444
2445        oldcur = dir = curdir;
2446
2447        if (setold) {
2448                setvar("OLDPWD", oldcur, VEXPORT);
2449        }
2450        INT_OFF;
2451        if (physdir != nullstr) {
2452                if (physdir != oldcur)
2453                        free(physdir);
2454                physdir = nullstr;
2455        }
2456        if (oldcur == val || !val) {
2457                char *s = getpwd();
2458                physdir = s;
2459                if (!val)
2460                        dir = s;
2461        } else
2462                dir = ckstrdup(val);
2463        if (oldcur != dir && oldcur != nullstr) {
2464                free(oldcur);
2465        }
2466        curdir = dir;
2467        INT_ON;
2468        setvar("PWD", dir, VEXPORT);
2469}
2470
2471static void hashcd(void);
2472
2473/*
2474 * Actually do the chdir.  We also call hashcd to let the routines in exec.c
2475 * know that the current directory has changed.
2476 */
2477static int
2478docd(const char *dest, int flags)
2479{
2480        const char *dir = NULL;
2481        int err;
2482
2483        TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2484
2485        INT_OFF;
2486        if (!(flags & CD_PHYSICAL)) {
2487                dir = updatepwd(dest);
2488                if (dir)
2489                        dest = dir;
2490        }
2491        err = chdir(dest);
2492        if (err)
2493                goto out;
2494        setpwd(dir, 1);
2495        hashcd();
2496 out:
2497        INT_ON;
2498        return err;
2499}
2500
2501static int FAST_FUNC
2502cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2503{
2504        const char *dest;
2505        const char *path;
2506        const char *p;
2507        char c;
2508        struct stat statb;
2509        int flags;
2510
2511        flags = cdopt();
2512        dest = *argptr;
2513        if (!dest)
2514                dest = bltinlookup("HOME");
2515        else if (LONE_DASH(dest)) {
2516                dest = bltinlookup("OLDPWD");
2517                flags |= CD_PRINT;
2518        }
2519        if (!dest)
2520                dest = nullstr;
2521        if (*dest == '/')
2522                goto step7;
2523        if (*dest == '.') {
2524                c = dest[1];
2525 dotdot:
2526                switch (c) {
2527                case '\0':
2528                case '/':
2529                        goto step6;
2530                case '.':
2531                        c = dest[2];
2532                        if (c != '.')
2533                                goto dotdot;
2534                }
2535        }
2536        if (!*dest)
2537                dest = ".";
2538        path = bltinlookup("CDPATH");
2539        if (!path) {
2540 step6:
2541 step7:
2542                p = dest;
2543                goto docd;
2544        }
2545        do {
2546                c = *path;
2547                p = path_advance(&path, dest);
2548                if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2549                        if (c && c != ':')
2550                                flags |= CD_PRINT;
2551 docd:
2552                        if (!docd(p, flags))
2553                                goto out;
2554                        break;
2555                }
2556        } while (path);
2557        ash_msg_and_raise_error("can't cd to %s", dest);
2558        /* NOTREACHED */
2559 out:
2560        if (flags & CD_PRINT)
2561                out1fmt("%s\n", curdir);
2562        return 0;
2563}
2564
2565static int FAST_FUNC
2566pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2567{
2568        int flags;
2569        const char *dir = curdir;
2570
2571        flags = cdopt();
2572        if (flags) {
2573                if (physdir == nullstr)
2574                        setpwd(dir, 0);
2575                dir = physdir;
2576        }
2577        out1fmt("%s\n", dir);
2578        return 0;
2579}
2580
2581
2582/* ============ ... */
2583
2584
2585#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2586
2587/* Syntax classes */
2588#define CWORD     0             /* character is nothing special */
2589#define CNL       1             /* newline character */
2590#define CBACK     2             /* a backslash character */
2591#define CSQUOTE   3             /* single quote */
2592#define CDQUOTE   4             /* double quote */
2593#define CENDQUOTE 5             /* a terminating quote */
2594#define CBQUOTE   6             /* backwards single quote */
2595#define CVAR      7             /* a dollar sign */
2596#define CENDVAR   8             /* a '}' character */
2597#define CLP       9             /* a left paren in arithmetic */
2598#define CRP      10             /* a right paren in arithmetic */
2599#define CENDFILE 11             /* end of file */
2600#define CCTL     12             /* like CWORD, except it must be escaped */
2601#define CSPCL    13             /* these terminate a word */
2602#define CIGN     14             /* character should be ignored */
2603
2604#define PEOF     256
2605#if ENABLE_ASH_ALIAS
2606# define PEOA    257
2607#endif
2608
2609#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2610
2611#if ENABLE_SH_MATH_SUPPORT
2612# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2613#else
2614# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2615#endif
2616static const uint16_t S_I_T[] = {
2617#if ENABLE_ASH_ALIAS
2618        SIT_ITEM(CSPCL   , CIGN     , CIGN , CIGN   ),    /* 0, PEOA */
2619#endif
2620        SIT_ITEM(CSPCL   , CWORD    , CWORD, CWORD  ),    /* 1, ' ' */
2621        SIT_ITEM(CNL     , CNL      , CNL  , CNL    ),    /* 2, \n */
2622        SIT_ITEM(CWORD   , CCTL     , CCTL , CWORD  ),    /* 3, !*-/:=?[]~ */
2623        SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD  ),    /* 4, '"' */
2624        SIT_ITEM(CVAR    , CVAR     , CWORD, CVAR   ),    /* 5, $ */
2625        SIT_ITEM(CSQUOTE , CWORD    , CENDQUOTE, CWORD),  /* 6, "'" */
2626        SIT_ITEM(CSPCL   , CWORD    , CWORD, CLP    ),    /* 7, ( */
2627        SIT_ITEM(CSPCL   , CWORD    , CWORD, CRP    ),    /* 8, ) */
2628        SIT_ITEM(CBACK   , CBACK    , CCTL , CBACK  ),    /* 9, \ */
2629        SIT_ITEM(CBQUOTE , CBQUOTE  , CWORD, CBQUOTE),    /* 10, ` */
2630        SIT_ITEM(CENDVAR , CENDVAR  , CWORD, CENDVAR),    /* 11, } */
2631#if !USE_SIT_FUNCTION
2632        SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2633        SIT_ITEM(CWORD   , CWORD    , CWORD, CWORD  ),    /* 13, 0-9A-Za-z */
2634        SIT_ITEM(CCTL    , CCTL     , CCTL , CCTL   )     /* 14, CTLESC ... */
2635#endif
2636#undef SIT_ITEM
2637};
2638/* Constants below must match table above */
2639enum {
2640#if ENABLE_ASH_ALIAS
2641        CSPCL_CIGN_CIGN_CIGN               , /*  0 */
2642#endif
2643        CSPCL_CWORD_CWORD_CWORD            , /*  1 */
2644        CNL_CNL_CNL_CNL                    , /*  2 */
2645        CWORD_CCTL_CCTL_CWORD              , /*  3 */
2646        CDQUOTE_CENDQUOTE_CWORD_CWORD      , /*  4 */
2647        CVAR_CVAR_CWORD_CVAR               , /*  5 */
2648        CSQUOTE_CWORD_CENDQUOTE_CWORD      , /*  6 */
2649        CSPCL_CWORD_CWORD_CLP              , /*  7 */
2650        CSPCL_CWORD_CWORD_CRP              , /*  8 */
2651        CBACK_CBACK_CCTL_CBACK             , /*  9 */
2652        CBQUOTE_CBQUOTE_CWORD_CBQUOTE      , /* 10 */
2653        CENDVAR_CENDVAR_CWORD_CENDVAR      , /* 11 */
2654        CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2655        CWORD_CWORD_CWORD_CWORD            , /* 13 */
2656        CCTL_CCTL_CCTL_CCTL                , /* 14 */
2657};
2658
2659/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2660 * caller must ensure proper cast on it if c is *char_ptr!
2661 */
2662/* Values for syntax param */
2663#define BASESYNTAX 0    /* not in quotes */
2664#define DQSYNTAX   1    /* in double quotes */
2665#define SQSYNTAX   2    /* in single quotes */
2666#define ARISYNTAX  3    /* in arithmetic */
2667#define PSSYNTAX   4    /* prompt. never passed to SIT() */
2668
2669#if USE_SIT_FUNCTION
2670
2671static int
2672SIT(int c, int syntax)
2673{
2674        static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2675# if ENABLE_ASH_ALIAS
2676        static const uint8_t syntax_index_table[] ALIGN1 = {
2677                1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
2678                7, 8, 3, 3, 3, 3, 1, 1,         /* "()*-/:;<" */
2679                3, 1, 3, 3, 9, 3, 10, 1,        /* "=>?[\\]`|" */
2680                11, 3                           /* "}~" */
2681        };
2682# else
2683        static const uint8_t syntax_index_table[] ALIGN1 = {
2684                0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
2685                6, 7, 2, 2, 2, 2, 0, 0,         /* "()*-/:;<" */
2686                2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
2687                10, 2                           /* "}~" */
2688        };
2689# endif
2690        const char *s;
2691        int indx;
2692
2693        if (c == PEOF)
2694                return CENDFILE;
2695# if ENABLE_ASH_ALIAS
2696        if (c == PEOA)
2697                indx = 0;
2698        else
2699# endif
2700        {
2701                /* Cast is purely for paranoia here,
2702                 * just in case someone passed signed char to us */
2703                if ((unsigned char)c >= CTL_FIRST
2704                 && (unsigned char)c <= CTL_LAST
2705                ) {
2706                        return CCTL;
2707                }
2708                s = strchrnul(spec_symbls, c);
2709                if (*s == '\0')
2710                        return CWORD;
2711                indx = syntax_index_table[s - spec_symbls];
2712        }
2713        return (S_I_T[indx] >> (syntax*4)) & 0xf;
2714}
2715
2716#else   /* !USE_SIT_FUNCTION */
2717
2718static const uint8_t syntax_index_table[] = {
2719        /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2720        /*   0      */ CWORD_CWORD_CWORD_CWORD,
2721        /*   1      */ CWORD_CWORD_CWORD_CWORD,
2722        /*   2      */ CWORD_CWORD_CWORD_CWORD,
2723        /*   3      */ CWORD_CWORD_CWORD_CWORD,
2724        /*   4      */ CWORD_CWORD_CWORD_CWORD,
2725        /*   5      */ CWORD_CWORD_CWORD_CWORD,
2726        /*   6      */ CWORD_CWORD_CWORD_CWORD,
2727        /*   7      */ CWORD_CWORD_CWORD_CWORD,
2728        /*   8      */ CWORD_CWORD_CWORD_CWORD,
2729        /*   9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2730        /*  10 "\n" */ CNL_CNL_CNL_CNL,
2731        /*  11      */ CWORD_CWORD_CWORD_CWORD,
2732        /*  12      */ CWORD_CWORD_CWORD_CWORD,
2733        /*  13      */ CWORD_CWORD_CWORD_CWORD,
2734        /*  14      */ CWORD_CWORD_CWORD_CWORD,
2735        /*  15      */ CWORD_CWORD_CWORD_CWORD,
2736        /*  16      */ CWORD_CWORD_CWORD_CWORD,
2737        /*  17      */ CWORD_CWORD_CWORD_CWORD,
2738        /*  18      */ CWORD_CWORD_CWORD_CWORD,
2739        /*  19      */ CWORD_CWORD_CWORD_CWORD,
2740        /*  20      */ CWORD_CWORD_CWORD_CWORD,
2741        /*  21      */ CWORD_CWORD_CWORD_CWORD,
2742        /*  22      */ CWORD_CWORD_CWORD_CWORD,
2743        /*  23      */ CWORD_CWORD_CWORD_CWORD,
2744        /*  24      */ CWORD_CWORD_CWORD_CWORD,
2745        /*  25      */ CWORD_CWORD_CWORD_CWORD,
2746        /*  26      */ CWORD_CWORD_CWORD_CWORD,
2747        /*  27      */ CWORD_CWORD_CWORD_CWORD,
2748        /*  28      */ CWORD_CWORD_CWORD_CWORD,
2749        /*  29      */ CWORD_CWORD_CWORD_CWORD,
2750        /*  30      */ CWORD_CWORD_CWORD_CWORD,
2751        /*  31      */ CWORD_CWORD_CWORD_CWORD,
2752        /*  32  " " */ CSPCL_CWORD_CWORD_CWORD,
2753        /*  33  "!" */ CWORD_CCTL_CCTL_CWORD,
2754        /*  34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2755        /*  35  "#" */ CWORD_CWORD_CWORD_CWORD,
2756        /*  36  "$" */ CVAR_CVAR_CWORD_CVAR,
2757        /*  37  "%" */ CWORD_CWORD_CWORD_CWORD,
2758        /*  38  "&" */ CSPCL_CWORD_CWORD_CWORD,
2759        /*  39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2760        /*  40  "(" */ CSPCL_CWORD_CWORD_CLP,
2761        /*  41  ")" */ CSPCL_CWORD_CWORD_CRP,
2762        /*  42  "*" */ CWORD_CCTL_CCTL_CWORD,
2763        /*  43  "+" */ CWORD_CWORD_CWORD_CWORD,
2764        /*  44  "," */ CWORD_CWORD_CWORD_CWORD,
2765        /*  45  "-" */ CWORD_CCTL_CCTL_CWORD,
2766        /*  46  "." */ CWORD_CWORD_CWORD_CWORD,
2767        /*  47  "/" */ CWORD_CCTL_CCTL_CWORD,
2768        /*  48  "0" */ CWORD_CWORD_CWORD_CWORD,
2769        /*  49  "1" */ CWORD_CWORD_CWORD_CWORD,
2770        /*  50  "2" */ CWORD_CWORD_CWORD_CWORD,
2771        /*  51  "3" */ CWORD_CWORD_CWORD_CWORD,
2772        /*  52  "4" */ CWORD_CWORD_CWORD_CWORD,
2773        /*  53  "5" */ CWORD_CWORD_CWORD_CWORD,
2774        /*  54  "6" */ CWORD_CWORD_CWORD_CWORD,
2775        /*  55  "7" */ CWORD_CWORD_CWORD_CWORD,
2776        /*  56  "8" */ CWORD_CWORD_CWORD_CWORD,
2777        /*  57  "9" */ CWORD_CWORD_CWORD_CWORD,
2778        /*  58  ":" */ CWORD_CCTL_CCTL_CWORD,
2779        /*  59  ";" */ CSPCL_CWORD_CWORD_CWORD,
2780        /*  60  "<" */ CSPCL_CWORD_CWORD_CWORD,
2781        /*  61  "=" */ CWORD_CCTL_CCTL_CWORD,
2782        /*  62  ">" */ CSPCL_CWORD_CWORD_CWORD,
2783        /*  63  "?" */ CWORD_CCTL_CCTL_CWORD,
2784        /*  64  "@" */ CWORD_CWORD_CWORD_CWORD,
2785        /*  65  "A" */ CWORD_CWORD_CWORD_CWORD,
2786        /*  66  "B" */ CWORD_CWORD_CWORD_CWORD,
2787        /*  67  "C" */ CWORD_CWORD_CWORD_CWORD,
2788        /*  68  "D" */ CWORD_CWORD_CWORD_CWORD,
2789        /*  69  "E" */ CWORD_CWORD_CWORD_CWORD,
2790        /*  70  "F" */ CWORD_CWORD_CWORD_CWORD,
2791        /*  71  "G" */ CWORD_CWORD_CWORD_CWORD,
2792        /*  72  "H" */ CWORD_CWORD_CWORD_CWORD,
2793        /*  73  "I" */ CWORD_CWORD_CWORD_CWORD,
2794        /*  74  "J" */ CWORD_CWORD_CWORD_CWORD,
2795        /*  75  "K" */ CWORD_CWORD_CWORD_CWORD,
2796        /*  76  "L" */ CWORD_CWORD_CWORD_CWORD,
2797        /*  77  "M" */ CWORD_CWORD_CWORD_CWORD,
2798        /*  78  "N" */ CWORD_CWORD_CWORD_CWORD,
2799        /*  79  "O" */ CWORD_CWORD_CWORD_CWORD,
2800        /*  80  "P" */ CWORD_CWORD_CWORD_CWORD,
2801        /*  81  "Q" */ CWORD_CWORD_CWORD_CWORD,
2802        /*  82  "R" */ CWORD_CWORD_CWORD_CWORD,
2803        /*  83  "S" */ CWORD_CWORD_CWORD_CWORD,
2804        /*  84  "T" */ CWORD_CWORD_CWORD_CWORD,
2805        /*  85  "U" */ CWORD_CWORD_CWORD_CWORD,
2806        /*  86  "V" */ CWORD_CWORD_CWORD_CWORD,
2807        /*  87  "W" */ CWORD_CWORD_CWORD_CWORD,
2808        /*  88  "X" */ CWORD_CWORD_CWORD_CWORD,
2809        /*  89  "Y" */ CWORD_CWORD_CWORD_CWORD,
2810        /*  90  "Z" */ CWORD_CWORD_CWORD_CWORD,
2811        /*  91  "[" */ CWORD_CCTL_CCTL_CWORD,
2812        /*  92  "\" */ CBACK_CBACK_CCTL_CBACK,
2813        /*  93  "]" */ CWORD_CCTL_CCTL_CWORD,
2814        /*  94  "^" */ CWORD_CWORD_CWORD_CWORD,
2815        /*  95  "_" */ CWORD_CWORD_CWORD_CWORD,
2816        /*  96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2817        /*  97  "a" */ CWORD_CWORD_CWORD_CWORD,
2818        /*  98  "b" */ CWORD_CWORD_CWORD_CWORD,
2819        /*  99  "c" */ CWORD_CWORD_CWORD_CWORD,
2820        /* 100  "d" */ CWORD_CWORD_CWORD_CWORD,
2821        /* 101  "e" */ CWORD_CWORD_CWORD_CWORD,
2822        /* 102  "f" */ CWORD_CWORD_CWORD_CWORD,
2823        /* 103  "g" */ CWORD_CWORD_CWORD_CWORD,
2824        /* 104  "h" */ CWORD_CWORD_CWORD_CWORD,
2825        /* 105  "i" */ CWORD_CWORD_CWORD_CWORD,
2826        /* 106  "j" */ CWORD_CWORD_CWORD_CWORD,
2827        /* 107  "k" */ CWORD_CWORD_CWORD_CWORD,
2828        /* 108  "l" */ CWORD_CWORD_CWORD_CWORD,
2829        /* 109  "m" */ CWORD_CWORD_CWORD_CWORD,
2830        /* 110  "n" */ CWORD_CWORD_CWORD_CWORD,
2831        /* 111  "o" */ CWORD_CWORD_CWORD_CWORD,
2832        /* 112  "p" */ CWORD_CWORD_CWORD_CWORD,
2833        /* 113  "q" */ CWORD_CWORD_CWORD_CWORD,
2834        /* 114  "r" */ CWORD_CWORD_CWORD_CWORD,
2835        /* 115  "s" */ CWORD_CWORD_CWORD_CWORD,
2836        /* 116  "t" */ CWORD_CWORD_CWORD_CWORD,
2837        /* 117  "u" */ CWORD_CWORD_CWORD_CWORD,
2838        /* 118  "v" */ CWORD_CWORD_CWORD_CWORD,
2839        /* 119  "w" */ CWORD_CWORD_CWORD_CWORD,
2840        /* 120  "x" */ CWORD_CWORD_CWORD_CWORD,
2841        /* 121  "y" */ CWORD_CWORD_CWORD_CWORD,
2842        /* 122  "z" */ CWORD_CWORD_CWORD_CWORD,
2843        /* 123  "{" */ CWORD_CWORD_CWORD_CWORD,
2844        /* 124  "|" */ CSPCL_CWORD_CWORD_CWORD,
2845        /* 125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2846        /* 126  "~" */ CWORD_CCTL_CCTL_CWORD,
2847        /* 127  del */ CWORD_CWORD_CWORD_CWORD,
2848        /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2849        /* 129 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
2850        /* 130 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
2851        /* 131 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
2852        /* 132 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
2853        /* 133 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
2854        /* 134 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
2855        /* 135 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
2856        /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2857        /* 137      */ CWORD_CWORD_CWORD_CWORD,
2858        /* 138      */ CWORD_CWORD_CWORD_CWORD,
2859        /* 139      */ CWORD_CWORD_CWORD_CWORD,
2860        /* 140      */ CWORD_CWORD_CWORD_CWORD,
2861        /* 141      */ CWORD_CWORD_CWORD_CWORD,
2862        /* 142      */ CWORD_CWORD_CWORD_CWORD,
2863        /* 143      */ CWORD_CWORD_CWORD_CWORD,
2864        /* 144      */ CWORD_CWORD_CWORD_CWORD,
2865        /* 145      */ CWORD_CWORD_CWORD_CWORD,
2866        /* 146      */ CWORD_CWORD_CWORD_CWORD,
2867        /* 147      */ CWORD_CWORD_CWORD_CWORD,
2868        /* 148      */ CWORD_CWORD_CWORD_CWORD,
2869        /* 149      */ CWORD_CWORD_CWORD_CWORD,
2870        /* 150      */ CWORD_CWORD_CWORD_CWORD,
2871        /* 151      */ CWORD_CWORD_CWORD_CWORD,
2872        /* 152      */ CWORD_CWORD_CWORD_CWORD,
2873        /* 153      */ CWORD_CWORD_CWORD_CWORD,
2874        /* 154      */ CWORD_CWORD_CWORD_CWORD,
2875        /* 155      */ CWORD_CWORD_CWORD_CWORD,
2876        /* 156      */ CWORD_CWORD_CWORD_CWORD,
2877        /* 157      */ CWORD_CWORD_CWORD_CWORD,
2878        /* 158      */ CWORD_CWORD_CWORD_CWORD,
2879        /* 159      */ CWORD_CWORD_CWORD_CWORD,
2880        /* 160      */ CWORD_CWORD_CWORD_CWORD,
2881        /* 161      */ CWORD_CWORD_CWORD_CWORD,
2882        /* 162      */ CWORD_CWORD_CWORD_CWORD,
2883        /* 163      */ CWORD_CWORD_CWORD_CWORD,
2884        /* 164      */ CWORD_CWORD_CWORD_CWORD,
2885        /* 165      */ CWORD_CWORD_CWORD_CWORD,
2886        /* 166      */ CWORD_CWORD_CWORD_CWORD,
2887        /* 167      */ CWORD_CWORD_CWORD_CWORD,
2888        /* 168      */ CWORD_CWORD_CWORD_CWORD,
2889        /* 169      */ CWORD_CWORD_CWORD_CWORD,
2890        /* 170      */ CWORD_CWORD_CWORD_CWORD,
2891        /* 171      */ CWORD_CWORD_CWORD_CWORD,
2892        /* 172      */ CWORD_CWORD_CWORD_CWORD,
2893        /* 173      */ CWORD_CWORD_CWORD_CWORD,
2894        /* 174      */ CWORD_CWORD_CWORD_CWORD,
2895        /* 175      */ CWORD_CWORD_CWORD_CWORD,
2896        /* 176      */ CWORD_CWORD_CWORD_CWORD,
2897        /* 177      */ CWORD_CWORD_CWORD_CWORD,
2898        /* 178      */ CWORD_CWORD_CWORD_CWORD,
2899        /* 179      */ CWORD_CWORD_CWORD_CWORD,
2900        /* 180      */ CWORD_CWORD_CWORD_CWORD,
2901        /* 181      */ CWORD_CWORD_CWORD_CWORD,
2902        /* 182      */ CWORD_CWORD_CWORD_CWORD,
2903        /* 183      */ CWORD_CWORD_CWORD_CWORD,
2904        /* 184      */ CWORD_CWORD_CWORD_CWORD,
2905        /* 185      */ CWORD_CWORD_CWORD_CWORD,
2906        /* 186      */ CWORD_CWORD_CWORD_CWORD,
2907        /* 187      */ CWORD_CWORD_CWORD_CWORD,
2908        /* 188      */ CWORD_CWORD_CWORD_CWORD,
2909        /* 189      */ CWORD_CWORD_CWORD_CWORD,
2910        /* 190      */ CWORD_CWORD_CWORD_CWORD,
2911        /* 191      */ CWORD_CWORD_CWORD_CWORD,
2912        /* 192      */ CWORD_CWORD_CWORD_CWORD,
2913        /* 193      */ CWORD_CWORD_CWORD_CWORD,
2914        /* 194      */ CWORD_CWORD_CWORD_CWORD,
2915        /* 195      */ CWORD_CWORD_CWORD_CWORD,
2916        /* 196      */ CWORD_CWORD_CWORD_CWORD,
2917        /* 197      */ CWORD_CWORD_CWORD_CWORD,
2918        /* 198      */ CWORD_CWORD_CWORD_CWORD,
2919        /* 199      */ CWORD_CWORD_CWORD_CWORD,
2920        /* 200      */ CWORD_CWORD_CWORD_CWORD,
2921        /* 201      */ CWORD_CWORD_CWORD_CWORD,
2922        /* 202      */ CWORD_CWORD_CWORD_CWORD,
2923        /* 203      */ CWORD_CWORD_CWORD_CWORD,
2924        /* 204      */ CWORD_CWORD_CWORD_CWORD,
2925        /* 205      */ CWORD_CWORD_CWORD_CWORD,
2926        /* 206      */ CWORD_CWORD_CWORD_CWORD,
2927        /* 207      */ CWORD_CWORD_CWORD_CWORD,
2928        /* 208      */ CWORD_CWORD_CWORD_CWORD,
2929        /* 209      */ CWORD_CWORD_CWORD_CWORD,
2930        /* 210      */ CWORD_CWORD_CWORD_CWORD,
2931        /* 211      */ CWORD_CWORD_CWORD_CWORD,
2932        /* 212      */ CWORD_CWORD_CWORD_CWORD,
2933        /* 213      */ CWORD_CWORD_CWORD_CWORD,
2934        /* 214      */ CWORD_CWORD_CWORD_CWORD,
2935        /* 215      */ CWORD_CWORD_CWORD_CWORD,
2936        /* 216      */ CWORD_CWORD_CWORD_CWORD,
2937        /* 217      */ CWORD_CWORD_CWORD_CWORD,
2938        /* 218      */ CWORD_CWORD_CWORD_CWORD,
2939        /* 219      */ CWORD_CWORD_CWORD_CWORD,
2940        /* 220      */ CWORD_CWORD_CWORD_CWORD,
2941        /* 221      */ CWORD_CWORD_CWORD_CWORD,
2942        /* 222      */ CWORD_CWORD_CWORD_CWORD,
2943        /* 223      */ CWORD_CWORD_CWORD_CWORD,
2944        /* 224      */ CWORD_CWORD_CWORD_CWORD,
2945        /* 225      */ CWORD_CWORD_CWORD_CWORD,
2946        /* 226      */ CWORD_CWORD_CWORD_CWORD,
2947        /* 227      */ CWORD_CWORD_CWORD_CWORD,
2948        /* 228      */ CWORD_CWORD_CWORD_CWORD,
2949        /* 229      */ CWORD_CWORD_CWORD_CWORD,
2950        /* 230      */ CWORD_CWORD_CWORD_CWORD,
2951        /* 231      */ CWORD_CWORD_CWORD_CWORD,
2952        /* 232      */ CWORD_CWORD_CWORD_CWORD,
2953        /* 233      */ CWORD_CWORD_CWORD_CWORD,
2954        /* 234      */ CWORD_CWORD_CWORD_CWORD,
2955        /* 235      */ CWORD_CWORD_CWORD_CWORD,
2956        /* 236      */ CWORD_CWORD_CWORD_CWORD,
2957        /* 237      */ CWORD_CWORD_CWORD_CWORD,
2958        /* 238      */ CWORD_CWORD_CWORD_CWORD,
2959        /* 239      */ CWORD_CWORD_CWORD_CWORD,
2960        /* 230      */ CWORD_CWORD_CWORD_CWORD,
2961        /* 241      */ CWORD_CWORD_CWORD_CWORD,
2962        /* 242      */ CWORD_CWORD_CWORD_CWORD,
2963        /* 243      */ CWORD_CWORD_CWORD_CWORD,
2964        /* 244      */ CWORD_CWORD_CWORD_CWORD,
2965        /* 245      */ CWORD_CWORD_CWORD_CWORD,
2966        /* 246      */ CWORD_CWORD_CWORD_CWORD,
2967        /* 247      */ CWORD_CWORD_CWORD_CWORD,
2968        /* 248      */ CWORD_CWORD_CWORD_CWORD,
2969        /* 249      */ CWORD_CWORD_CWORD_CWORD,
2970        /* 250      */ CWORD_CWORD_CWORD_CWORD,
2971        /* 251      */ CWORD_CWORD_CWORD_CWORD,
2972        /* 252      */ CWORD_CWORD_CWORD_CWORD,
2973        /* 253      */ CWORD_CWORD_CWORD_CWORD,
2974        /* 254      */ CWORD_CWORD_CWORD_CWORD,
2975        /* 255      */ CWORD_CWORD_CWORD_CWORD,
2976        /* PEOF */     CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2977# if ENABLE_ASH_ALIAS
2978        /* PEOA */     CSPCL_CIGN_CIGN_CIGN,
2979# endif
2980};
2981
2982# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
2983
2984#endif  /* !USE_SIT_FUNCTION */
2985
2986
2987/* ============ Alias handling */
2988
2989#if ENABLE_ASH_ALIAS
2990
2991#define ALIASINUSE 1
2992#define ALIASDEAD  2
2993
2994struct alias {
2995        struct alias *next;
2996        char *name;
2997        char *val;
2998        int flag;
2999};
3000
3001
3002static struct alias **atab; // [ATABSIZE];
3003#define INIT_G_alias() do { \
3004        atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3005} while (0)
3006
3007
3008static struct alias **
3009__lookupalias(const char *name) {
3010        unsigned int hashval;
3011        struct alias **app;
3012        const char *p;
3013        unsigned int ch;
3014
3015        p = name;
3016
3017        ch = (unsigned char)*p;
3018        hashval = ch << 4;
3019        while (ch) {
3020                hashval += ch;
3021                ch = (unsigned char)*++p;
3022        }
3023        app = &atab[hashval % ATABSIZE];
3024
3025        for (; *app; app = &(*app)->next) {
3026                if (strcmp(name, (*app)->name) == 0) {
3027                        break;
3028                }
3029        }
3030
3031        return app;
3032}
3033
3034static struct alias *
3035lookupalias(const char *name, int check)
3036{
3037        struct alias *ap = *__lookupalias(name);
3038
3039        if (check && ap && (ap->flag & ALIASINUSE))
3040                return NULL;
3041        return ap;
3042}
3043
3044static struct alias *
3045freealias(struct alias *ap)
3046{
3047        struct alias *next;
3048
3049        if (ap->flag & ALIASINUSE) {
3050                ap->flag |= ALIASDEAD;
3051                return ap;
3052        }
3053
3054        next = ap->next;
3055        free(ap->name);
3056        free(ap->val);
3057        free(ap);
3058        return next;
3059}
3060
3061static void
3062setalias(const char *name, const char *val)
3063{
3064        struct alias *ap, **app;
3065
3066        app = __lookupalias(name);
3067        ap = *app;
3068        INT_OFF;
3069        if (ap) {
3070                if (!(ap->flag & ALIASINUSE)) {
3071                        free(ap->val);
3072                }
3073                ap->val = ckstrdup(val);
3074                ap->flag &= ~ALIASDEAD;
3075        } else {
3076                /* not found */
3077                ap = ckzalloc(sizeof(struct alias));
3078                ap->name = ckstrdup(name);
3079                ap->val = ckstrdup(val);
3080                /*ap->flag = 0; - ckzalloc did it */
3081                /*ap->next = NULL;*/
3082                *app = ap;
3083        }
3084        INT_ON;
3085}
3086
3087static int
3088unalias(const char *name)
3089{
3090        struct alias **app;
3091
3092        app = __lookupalias(name);
3093
3094        if (*app) {
3095                INT_OFF;
3096                *app = freealias(*app);
3097                INT_ON;
3098                return 0;
3099        }
3100
3101        return 1;
3102}
3103
3104static void
3105rmaliases(void)
3106{
3107        struct alias *ap, **app;
3108        int i;
3109
3110        INT_OFF;
3111        for (i = 0; i < ATABSIZE; i++) {
3112                app = &atab[i];
3113                for (ap = *app; ap; ap = *app) {
3114                        *app = freealias(*app);
3115                        if (ap == *app) {
3116                                app = &ap->next;
3117                        }
3118                }
3119        }
3120        INT_ON;
3121}
3122
3123static void
3124printalias(const struct alias *ap)
3125{
3126        out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3127}
3128
3129/*
3130 * TODO - sort output
3131 */
3132static int FAST_FUNC
3133aliascmd(int argc UNUSED_PARAM, char **argv)
3134{
3135        char *n, *v;
3136        int ret = 0;
3137        struct alias *ap;
3138
3139        if (!argv[1]) {
3140                int i;
3141
3142                for (i = 0; i < ATABSIZE; i++) {
3143                        for (ap = atab[i]; ap; ap = ap->next) {
3144                                printalias(ap);
3145                        }
3146                }
3147                return 0;
3148        }
3149        while ((n = *++argv) != NULL) {
3150                v = strchr(n+1, '=');
3151                if (v == NULL) { /* n+1: funny ksh stuff */
3152                        ap = *__lookupalias(n);
3153                        if (ap == NULL) {
3154                                fprintf(stderr, "%s: %s not found\n", "alias", n);
3155                                ret = 1;
3156                        } else
3157                                printalias(ap);
3158                } else {
3159                        *v++ = '\0';
3160                        setalias(n, v);
3161                }
3162        }
3163
3164        return ret;
3165}
3166
3167static int FAST_FUNC
3168unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3169{
3170        int i;
3171
3172        while ((i = nextopt("a")) != '\0') {
3173                if (i == 'a') {
3174                        rmaliases();
3175                        return 0;
3176                }
3177        }
3178        for (i = 0; *argptr; argptr++) {
3179                if (unalias(*argptr)) {
3180                        fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3181                        i = 1;
3182                }
3183        }
3184
3185        return i;
3186}
3187
3188#endif /* ASH_ALIAS */
3189
3190
3191/* ============ jobs.c */
3192
3193/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
3194#define FORK_FG    0
3195#define FORK_BG    1
3196#define FORK_NOJOB 2
3197
3198/* mode flags for showjob(s) */
3199#define SHOW_ONLY_PGID  0x01    /* show only pgid (jobs -p) */
3200#define SHOW_PIDS       0x02    /* show individual pids, not just one line per job */
3201#define SHOW_CHANGED    0x04    /* only jobs whose state has changed */
3202
3203/*
3204 * A job structure contains information about a job.  A job is either a
3205 * single process or a set of processes contained in a pipeline.  In the
3206 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3207 * array of pids.
3208 */
3209struct procstat {
3210        pid_t   ps_pid;         /* process id */
3211        int     ps_status;      /* last process status from wait() */
3212        char    *ps_cmd;        /* text of command being run */
3213};
3214
3215struct job {
3216        struct procstat ps0;    /* status of process */
3217        struct procstat *ps;    /* status or processes when more than one */
3218#if JOBS
3219        int stopstatus;         /* status of a stopped job */
3220#endif
3221        uint32_t
3222                nprocs: 16,     /* number of processes */
3223                state: 8,
3224#define JOBRUNNING      0       /* at least one proc running */
3225#define JOBSTOPPED      1       /* all procs are stopped */
3226#define JOBDONE         2       /* all procs are completed */
3227#if JOBS
3228                sigint: 1,      /* job was killed by SIGINT */
3229                jobctl: 1,      /* job running under job control */
3230#endif
3231                waited: 1,      /* true if this entry has been waited for */
3232                used: 1,        /* true if this entry is in used */
3233                changed: 1;     /* true if status has changed */
3234        struct job *prev_job;   /* previous job */
3235};
3236
3237static struct job *makejob(/*union node *,*/ int);
3238static int forkshell(struct job *, union node *, int);
3239static int waitforjob(struct job *);
3240
3241#if !JOBS
3242enum { doing_jobctl = 0 };
3243#define setjobctl(on) do {} while (0)
3244#else
3245static smallint doing_jobctl; //references:8
3246static void setjobctl(int);
3247#endif
3248
3249/*
3250 * Ignore a signal.
3251 */
3252static void
3253ignoresig(int signo)
3254{
3255        /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3256        if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3257                /* No, need to do it */
3258                signal(signo, SIG_IGN);
3259        }
3260        sigmode[signo - 1] = S_HARD_IGN;
3261}
3262
3263/*
3264 * Only one usage site - in setsignal()
3265 */
3266static void
3267signal_handler(int signo)
3268{
3269        gotsig[signo - 1] = 1;
3270
3271        if (signo == SIGINT && !trap[SIGINT]) {
3272                if (!suppress_int) {
3273                        pending_sig = 0;
3274                        raise_interrupt(); /* does not return */
3275                }
3276                pending_int = 1;
3277        } else {
3278                pending_sig = signo;
3279        }
3280}
3281
3282/*
3283 * Set the signal handler for the specified signal.  The routine figures
3284 * out what it should be set to.
3285 */
3286static void
3287setsignal(int signo)
3288{
3289        char *t;
3290        char cur_act, new_act;
3291        struct sigaction act;
3292
3293        t = trap[signo];
3294        new_act = S_DFL;
3295        if (t != NULL) { /* trap for this sig is set */
3296                new_act = S_CATCH;
3297                if (t[0] == '\0') /* trap is "": ignore this sig */
3298                        new_act = S_IGN;
3299        }
3300
3301        if (rootshell && new_act == S_DFL) {
3302                switch (signo) {
3303                case SIGINT:
3304                        if (iflag || minusc || sflag == 0)
3305                                new_act = S_CATCH;
3306                        break;
3307                case SIGQUIT:
3308#if DEBUG
3309                        if (debug)
3310                                break;
3311#endif
3312                        /* man bash:
3313                         * "In all cases, bash ignores SIGQUIT. Non-builtin
3314                         * commands run by bash have signal handlers
3315                         * set to the values inherited by the shell
3316                         * from its parent". */
3317                        new_act = S_IGN;
3318                        break;
3319                case SIGTERM:
3320                        if (iflag)
3321                                new_act = S_IGN;
3322                        break;
3323#if JOBS
3324                case SIGTSTP:
3325                case SIGTTOU:
3326                        if (mflag)
3327                                new_act = S_IGN;
3328                        break;
3329#endif
3330                }
3331        }
3332//TODO: if !rootshell, we reset SIGQUIT to DFL,
3333//whereas we have to restore it to what shell got on entry
3334//from the parent. See comment above
3335
3336        t = &sigmode[signo - 1];
3337        cur_act = *t;
3338        if (cur_act == 0) {
3339                /* current setting is not yet known */
3340                if (sigaction(signo, NULL, &act)) {
3341                        /* pretend it worked; maybe we should give a warning,
3342                         * but other shells don't. We don't alter sigmode,
3343                         * so we retry every time.
3344                         * btw, in Linux it never fails. --vda */
3345                        return;
3346                }
3347                if (act.sa_handler == SIG_IGN) {
3348                        cur_act = S_HARD_IGN;
3349                        if (mflag
3350                         && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3351                        ) {
3352                                cur_act = S_IGN;   /* don't hard ignore these */
3353                        }
3354                }
3355        }
3356        if (cur_act == S_HARD_IGN || cur_act == new_act)
3357                return;
3358
3359        act.sa_handler = SIG_DFL;
3360        switch (new_act) {
3361        case S_CATCH:
3362                act.sa_handler = signal_handler;
3363                act.sa_flags = 0; /* matters only if !DFL and !IGN */
3364                sigfillset(&act.sa_mask); /* ditto */
3365                break;
3366        case S_IGN:
3367                act.sa_handler = SIG_IGN;
3368                break;
3369        }
3370        sigaction_set(signo, &act);
3371
3372        *t = new_act;
3373}
3374
3375/* mode flags for set_curjob */
3376#define CUR_DELETE 2
3377#define CUR_RUNNING 1
3378#define CUR_STOPPED 0
3379
3380/* mode flags for dowait */
3381#define DOWAIT_NONBLOCK WNOHANG
3382#define DOWAIT_BLOCK    0
3383
3384#if JOBS
3385/* pgrp of shell on invocation */
3386static int initialpgrp; //references:2
3387static int ttyfd = -1; //5
3388#endif
3389/* array of jobs */
3390static struct job *jobtab; //5
3391/* size of array */
3392static unsigned njobs; //4
3393/* current job */
3394static struct job *curjob; //lots
3395/* number of presumed living untracked jobs */
3396static int jobless; //4
3397
3398static void
3399set_curjob(struct job *jp, unsigned mode)
3400{
3401        struct job *jp1;
3402        struct job **jpp, **curp;
3403
3404        /* first remove from list */
3405        jpp = curp = &curjob;
3406        do {
3407                jp1 = *jpp;
3408                if (jp1 == jp)
3409                        break;
3410                jpp = &jp1->prev_job;
3411        } while (1);
3412        *jpp = jp1->prev_job;
3413
3414        /* Then re-insert in correct position */
3415        jpp = curp;
3416        switch (mode) {
3417        default:
3418#if DEBUG
3419                abort();
3420#endif
3421        case CUR_DELETE:
3422                /* job being deleted */
3423                break;
3424        case CUR_RUNNING:
3425                /* newly created job or backgrounded job,
3426                   put after all stopped jobs. */
3427                do {
3428                        jp1 = *jpp;
3429#if JOBS
3430                        if (!jp1 || jp1->state != JOBSTOPPED)
3431#endif
3432                                break;
3433                        jpp = &jp1->prev_job;
3434                } while (1);
3435                /* FALLTHROUGH */
3436#if JOBS
3437        case CUR_STOPPED:
3438#endif
3439                /* newly stopped job - becomes curjob */
3440                jp->prev_job = *jpp;
3441                *jpp = jp;
3442                break;
3443        }
3444}
3445
3446#if JOBS || DEBUG
3447static int
3448jobno(const struct job *jp)
3449{
3450        return jp - jobtab + 1;
3451}
3452#endif
3453
3454/*
3455 * Convert a job name to a job structure.
3456 */
3457#if !JOBS
3458#define getjob(name, getctl) getjob(name)
3459#endif
3460static struct job *
3461getjob(const char *name, int getctl)
3462{
3463        struct job *jp;
3464        struct job *found;
3465        const char *err_msg = "%s: no such job";
3466        unsigned num;
3467        int c;
3468        const char *p;
3469        char *(*match)(const char *, const char *);
3470
3471        jp = curjob;
3472        p = name;
3473        if (!p)
3474                goto currentjob;
3475
3476        if (*p != '%')
3477                goto err;
3478
3479        c = *++p;
3480        if (!c)
3481                goto currentjob;
3482
3483        if (!p[1]) {
3484                if (c == '+' || c == '%') {
3485 currentjob:
3486                        err_msg = "No current job";
3487                        goto check;
3488                }
3489                if (c == '-') {
3490                        if (jp)
3491                                jp = jp->prev_job;
3492                        err_msg = "No previous job";
3493 check:
3494                        if (!jp)
3495                                goto err;
3496                        goto gotit;
3497                }
3498        }
3499
3500        if (is_number(p)) {
3501                num = atoi(p);
3502                if (num < njobs) {
3503                        jp = jobtab + num - 1;
3504                        if (jp->used)
3505                                goto gotit;
3506                        goto err;
3507                }
3508        }
3509
3510        match = prefix;
3511        if (*p == '?') {
3512                match = strstr;
3513                p++;
3514        }
3515
3516        found = NULL;
3517        while (jp) {
3518                if (match(jp->ps[0].ps_cmd, p)) {
3519                        if (found)
3520                                goto err;
3521                        found = jp;
3522                        err_msg = "%s: ambiguous";
3523                }
3524                jp = jp->prev_job;
3525        }
3526        if (!found)
3527                goto err;
3528        jp = found;
3529
3530 gotit:
3531#if JOBS
3532        err_msg = "job %s not created under job control";
3533        if (getctl && jp->jobctl == 0)
3534                goto err;
3535#endif
3536        return jp;
3537 err:
3538        ash_msg_and_raise_error(err_msg, name);
3539}
3540
3541/*
3542 * Mark a job structure as unused.
3543 */
3544static void
3545freejob(struct job *jp)
3546{
3547        struct procstat *ps;
3548        int i;
3549
3550        INT_OFF;
3551        for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3552                if (ps->ps_cmd != nullstr)
3553                        free(ps->ps_cmd);
3554        }
3555        if (jp->ps != &jp->ps0)
3556                free(jp->ps);
3557        jp->used = 0;
3558        set_curjob(jp, CUR_DELETE);
3559        INT_ON;
3560}
3561
3562#if JOBS
3563static void
3564xtcsetpgrp(int fd, pid_t pgrp)
3565{
3566        if (tcsetpgrp(fd, pgrp))
3567                ash_msg_and_raise_error("can't set tty process group (%m)");
3568}
3569
3570/*
3571 * Turn job control on and off.
3572 *
3573 * Note:  This code assumes that the third arg to ioctl is a character
3574 * pointer, which is true on Berkeley systems but not System V.  Since
3575 * System V doesn't have job control yet, this isn't a problem now.
3576 *
3577 * Called with interrupts off.
3578 */
3579static void
3580setjobctl(int on)
3581{
3582        int fd;
3583        int pgrp;
3584
3585        if (on == doing_jobctl || rootshell == 0)
3586                return;
3587        if (on) {
3588                int ofd;
3589                ofd = fd = open(_PATH_TTY, O_RDWR);
3590                if (fd < 0) {
3591        /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3592         * That sometimes helps to acquire controlling tty.
3593         * Obviously, a workaround for bugs when someone
3594         * failed to provide a controlling tty to bash! :) */
3595                        fd = 2;
3596                        while (!isatty(fd))
3597                                if (--fd < 0)
3598                                        goto out;
3599                }
3600                fd = fcntl(fd, F_DUPFD, 10);
3601                if (ofd >= 0)
3602                        close(ofd);
3603                if (fd < 0)
3604                        goto out;
3605                /* fd is a tty at this point */
3606                close_on_exec_on(fd);
3607                do { /* while we are in the background */
3608                        pgrp = tcgetpgrp(fd);
3609                        if (pgrp < 0) {
3610 out:
3611                                ash_msg("can't access tty; job control turned off");
3612                                mflag = on = 0;
3613                                goto close;
3614                        }
3615                        if (pgrp == getpgrp())
3616                                break;
3617                        killpg(0, SIGTTIN);
3618                } while (1);
3619                initialpgrp = pgrp;
3620
3621                setsignal(SIGTSTP);
3622                setsignal(SIGTTOU);
3623                setsignal(SIGTTIN);
3624                pgrp = rootpid;
3625                setpgid(0, pgrp);
3626                xtcsetpgrp(fd, pgrp);
3627        } else {
3628                /* turning job control off */
3629                fd = ttyfd;
3630                pgrp = initialpgrp;
3631                /* was xtcsetpgrp, but this can make exiting ash
3632                 * loop forever if pty is already deleted */
3633                tcsetpgrp(fd, pgrp);
3634                setpgid(0, pgrp);
3635                setsignal(SIGTSTP);
3636                setsignal(SIGTTOU);
3637                setsignal(SIGTTIN);
3638 close:
3639                if (fd >= 0)
3640                        close(fd);
3641                fd = -1;
3642        }
3643        ttyfd = fd;
3644        doing_jobctl = on;
3645}
3646
3647static int FAST_FUNC
3648killcmd(int argc, char **argv)
3649{
3650        int i = 1;
3651        if (argv[1] && strcmp(argv[1], "-l") != 0) {
3652                do {
3653                        if (argv[i][0] == '%') {
3654                                struct job *jp = getjob(argv[i], 0);
3655                                unsigned pid = jp->ps[0].ps_pid;
3656                                /* Enough space for ' -NNN<nul>' */
3657                                argv[i] = alloca(sizeof(int)*3 + 3);
3658                                /* kill_main has matching code to expect
3659                                 * leading space. Needed to not confuse
3660                                 * negative pids with "kill -SIGNAL_NO" syntax */
3661                                sprintf(argv[i], " -%u", pid);
3662                        }
3663                } while (argv[++i]);
3664        }
3665        return kill_main(argc, argv);
3666}
3667
3668static void
3669showpipe(struct job *jp /*, FILE *out*/)
3670{
3671        struct procstat *ps;
3672        struct procstat *psend;
3673
3674        psend = jp->ps + jp->nprocs;
3675        for (ps = jp->ps + 1; ps < psend; ps++)
3676                printf(" | %s", ps->ps_cmd);
3677        outcslow('\n', stdout);
3678        flush_stdout_stderr();
3679}
3680
3681
3682static int
3683restartjob(struct job *jp, int mode)
3684{
3685        struct procstat *ps;
3686        int i;
3687        int status;
3688        pid_t pgid;
3689
3690        INT_OFF;
3691        if (jp->state == JOBDONE)
3692                goto out;
3693        jp->state = JOBRUNNING;
3694        pgid = jp->ps[0].ps_pid;
3695        if (mode == FORK_FG)
3696                xtcsetpgrp(ttyfd, pgid);
3697        killpg(pgid, SIGCONT);
3698        ps = jp->ps;
3699        i = jp->nprocs;
3700        do {
3701                if (WIFSTOPPED(ps->ps_status)) {
3702                        ps->ps_status = -1;
3703                }
3704                ps++;
3705        } while (--i);
3706 out:
3707        status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3708        INT_ON;
3709        return status;
3710}
3711
3712static int FAST_FUNC
3713fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3714{
3715        struct job *jp;
3716        int mode;
3717        int retval;
3718
3719        mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3720        nextopt(nullstr);
3721        argv = argptr;
3722        do {
3723                jp = getjob(*argv, 1);
3724                if (mode == FORK_BG) {
3725                        set_curjob(jp, CUR_RUNNING);
3726                        printf("[%d] ", jobno(jp));
3727                }
3728                out1str(jp->ps[0].ps_cmd);
3729                showpipe(jp /*, stdout*/);
3730                retval = restartjob(jp, mode);
3731        } while (*argv && *++argv);
3732        return retval;
3733}
3734#endif
3735
3736static int
3737sprint_status(char *s, int status, int sigonly)
3738{
3739        int col;
3740        int st;
3741
3742        col = 0;
3743        if (!WIFEXITED(status)) {
3744#if JOBS
3745                if (WIFSTOPPED(status))
3746                        st = WSTOPSIG(status);
3747                else
3748#endif
3749                        st = WTERMSIG(status);
3750                if (sigonly) {
3751                        if (st == SIGINT || st == SIGPIPE)
3752                                goto out;
3753#if JOBS
3754                        if (WIFSTOPPED(status))
3755                                goto out;
3756#endif
3757                }
3758                st &= 0x7f;
3759                col = fmtstr(s, 32, strsignal(st));
3760                if (WCOREDUMP(status)) {
3761                        col += fmtstr(s + col, 16, " (core dumped)");
3762                }
3763        } else if (!sigonly) {
3764                st = WEXITSTATUS(status);
3765                if (st)
3766                        col = fmtstr(s, 16, "Done(%d)", st);
3767                else
3768                        col = fmtstr(s, 16, "Done");
3769        }
3770 out:
3771        return col;
3772}
3773
3774static int
3775dowait(int wait_flags, struct job *job)
3776{
3777        int pid;
3778        int status;
3779        struct job *jp;
3780        struct job *thisjob;
3781        int state;
3782
3783        TRACE(("dowait(0x%x) called\n", wait_flags));
3784
3785        /* Do a wait system call. If job control is compiled in, we accept
3786         * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3787         * NB: _not_ safe_waitpid, we need to detect EINTR */
3788        if (doing_jobctl)
3789                wait_flags |= WUNTRACED;
3790        pid = waitpid(-1, &status, wait_flags);
3791        TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3792                                pid, status, errno, strerror(errno)));
3793        if (pid <= 0)
3794                return pid;
3795
3796        INT_OFF;
3797        thisjob = NULL;
3798        for (jp = curjob; jp; jp = jp->prev_job) {
3799                struct procstat *ps;
3800                struct procstat *psend;
3801                if (jp->state == JOBDONE)
3802                        continue;
3803                state = JOBDONE;
3804                ps = jp->ps;
3805                psend = ps + jp->nprocs;
3806                do {
3807                        if (ps->ps_pid == pid) {
3808                                TRACE(("Job %d: changing status of proc %d "
3809                                        "from 0x%x to 0x%x\n",
3810                                        jobno(jp), pid, ps->ps_status, status));
3811                                ps->ps_status = status;
3812                                thisjob = jp;
3813                        }
3814                        if (ps->ps_status == -1)
3815                                state = JOBRUNNING;
3816#if JOBS
3817                        if (state == JOBRUNNING)
3818                                continue;
3819                        if (WIFSTOPPED(ps->ps_status)) {
3820                                jp->stopstatus = ps->ps_status;
3821                                state = JOBSTOPPED;
3822                        }
3823#endif
3824                } while (++ps < psend);
3825                if (thisjob)
3826                        goto gotjob;
3827        }
3828#if JOBS
3829        if (!WIFSTOPPED(status))
3830#endif
3831                jobless--;
3832        goto out;
3833
3834 gotjob:
3835        if (state != JOBRUNNING) {
3836                thisjob->changed = 1;
3837
3838                if (thisjob->state != state) {
3839                        TRACE(("Job %d: changing state from %d to %d\n",
3840                                jobno(thisjob), thisjob->state, state));
3841                        thisjob->state = state;
3842#if JOBS
3843                        if (state == JOBSTOPPED) {
3844                                set_curjob(thisjob, CUR_STOPPED);
3845                        }
3846#endif
3847                }
3848        }
3849
3850 out:
3851        INT_ON;
3852
3853        if (thisjob && thisjob == job) {
3854                char s[48 + 1];
3855                int len;
3856
3857                len = sprint_status(s, status, 1);
3858                if (len) {
3859                        s[len] = '\n';
3860                        s[len + 1] = '\0';
3861                        out2str(s);
3862                }
3863        }
3864        return pid;
3865}
3866
3867static int
3868blocking_wait_with_raise_on_sig(void)
3869{
3870        pid_t pid = dowait(DOWAIT_BLOCK, NULL);
3871        if (pid <= 0 && pending_sig)
3872                raise_exception(EXSIG);
3873        return pid;
3874}
3875
3876#if JOBS
3877static void
3878showjob(FILE *out, struct job *jp, int mode)
3879{
3880        struct procstat *ps;
3881        struct procstat *psend;
3882        int col;
3883        int indent_col;
3884        char s[80];
3885
3886        ps = jp->ps;
3887
3888        if (mode & SHOW_ONLY_PGID) { /* jobs -p */
3889                /* just output process (group) id of pipeline */
3890                fprintf(out, "%d\n", ps->ps_pid);
3891                return;
3892        }
3893
3894        col = fmtstr(s, 16, "[%d]   ", jobno(jp));
3895        indent_col = col;
3896
3897        if (jp == curjob)
3898                s[col - 3] = '+';
3899        else if (curjob && jp == curjob->prev_job)
3900                s[col - 3] = '-';
3901
3902        if (mode & SHOW_PIDS)
3903                col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
3904
3905        psend = ps + jp->nprocs;
3906
3907        if (jp->state == JOBRUNNING) {
3908                strcpy(s + col, "Running");
3909                col += sizeof("Running") - 1;
3910        } else {
3911                int status = psend[-1].ps_status;
3912                if (jp->state == JOBSTOPPED)
3913                        status = jp->stopstatus;
3914                col += sprint_status(s + col, status, 0);
3915        }
3916        /* By now, "[JOBID]*  [maybe PID] STATUS" is printed */
3917
3918        /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
3919         * or prints several "PID             | <cmdN>" lines,
3920         * depending on SHOW_PIDS bit.
3921         * We do not print status of individual processes
3922         * between PID and <cmdN>. bash does it, but not very well:
3923         * first line shows overall job status, not process status,
3924         * making it impossible to know 1st process status.
3925         */
3926        goto start;
3927        do {
3928                /* for each process */
3929                s[0] = '\0';
3930                col = 33;
3931                if (mode & SHOW_PIDS)
3932                        col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
3933 start:
3934                fprintf(out, "%s%*c%s%s",
3935                                s,
3936                                33 - col >= 0 ? 33 - col : 0, ' ',
3937                                ps == jp->ps ? "" : "| ",
3938                                ps->ps_cmd
3939                );
3940        } while (++ps != psend);
3941        outcslow('\n', out);
3942
3943        jp->changed = 0;
3944
3945        if (jp->state == JOBDONE) {
3946                TRACE(("showjob: freeing job %d\n", jobno(jp)));
3947                freejob(jp);
3948        }
3949}
3950
3951/*
3952 * Print a list of jobs.  If "change" is nonzero, only print jobs whose
3953 * statuses have changed since the last call to showjobs.
3954 */
3955static void
3956showjobs(FILE *out, int mode)
3957{
3958        struct job *jp;
3959
3960        TRACE(("showjobs(0x%x) called\n", mode));
3961
3962        /* Handle all finished jobs */
3963        while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3964                continue;
3965
3966        for (jp = curjob; jp; jp = jp->prev_job) {
3967                if (!(mode & SHOW_CHANGED) || jp->changed) {
3968                        showjob(out, jp, mode);
3969                }
3970        }
3971}
3972
3973static int FAST_FUNC
3974jobscmd(int argc UNUSED_PARAM, char **argv)
3975{
3976        int mode, m;
3977
3978        mode = 0;
3979        while ((m = nextopt("lp")) != '\0') {
3980                if (m == 'l')
3981                        mode |= SHOW_PIDS;
3982                else
3983                        mode |= SHOW_ONLY_PGID;
3984        }
3985
3986        argv = argptr;
3987        if (*argv) {
3988                do
3989                        showjob(stdout, getjob(*argv, 0), mode);
3990                while (*++argv);
3991        } else {
3992                showjobs(stdout, mode);
3993        }
3994
3995        return 0;
3996}
3997#endif /* JOBS */
3998
3999/* Called only on finished or stopped jobs (no members are running) */
4000static int
4001getstatus(struct job *job)
4002{
4003        int status;
4004        int retval;
4005        struct procstat *ps;
4006
4007        /* Fetch last member's status */
4008        ps = job->ps + job->nprocs - 1;
4009        status = ps->ps_status;
4010        if (pipefail) {
4011                /* "set -o pipefail" mode: use last _nonzero_ status */
4012                while (status == 0 && --ps >= job->ps)
4013                        status = ps->ps_status;
4014        }
4015
4016        retval = WEXITSTATUS(status);
4017        if (!WIFEXITED(status)) {
4018#if JOBS
4019                retval = WSTOPSIG(status);
4020                if (!WIFSTOPPED(status))
4021#endif
4022                {
4023                        /* XXX: limits number of signals */
4024                        retval = WTERMSIG(status);
4025#if JOBS
4026                        if (retval == SIGINT)
4027                                job->sigint = 1;
4028#endif
4029                }
4030                retval += 128;
4031        }
4032        TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4033                jobno(job), job->nprocs, status, retval));
4034        return retval;
4035}
4036
4037static int FAST_FUNC
4038waitcmd(int argc UNUSED_PARAM, char **argv)
4039{
4040        struct job *job;
4041        int retval;
4042        struct job *jp;
4043
4044        if (pending_sig)
4045                raise_exception(EXSIG);
4046
4047        nextopt(nullstr);
4048        retval = 0;
4049
4050        argv = argptr;
4051        if (!*argv) {
4052                /* wait for all jobs */
4053                for (;;) {
4054                        jp = curjob;
4055                        while (1) {
4056                                if (!jp) /* no running procs */
4057                                        goto ret;
4058                                if (jp->state == JOBRUNNING)
4059                                        break;
4060                                jp->waited = 1;
4061                                jp = jp->prev_job;
4062                        }
4063                        blocking_wait_with_raise_on_sig();
4064        /* man bash:
4065         * "When bash is waiting for an asynchronous command via
4066         * the wait builtin, the reception of a signal for which a trap
4067         * has been set will cause the wait builtin to return immediately
4068         * with an exit status greater than 128, immediately after which
4069         * the trap is executed."
4070         *
4071         * blocking_wait_with_raise_on_sig raises signal handlers
4072         * if it gets no pid (pid < 0). However,
4073         * if child sends us a signal *and immediately exits*,
4074         * blocking_wait_with_raise_on_sig gets pid > 0
4075         * and does not handle pending_sig. Check this case: */
4076                        if (pending_sig)
4077                                raise_exception(EXSIG);
4078                }
4079        }
4080
4081        retval = 127;
4082        do {
4083                if (**argv != '%') {
4084                        pid_t pid = number(*argv);
4085                        job = curjob;
4086                        while (1) {
4087                                if (!job)
4088                                        goto repeat;
4089                                if (job->ps[job->nprocs - 1].ps_pid == pid)
4090                                        break;
4091                                job = job->prev_job;
4092                        }
4093                } else
4094                        job = getjob(*argv, 0);
4095                /* loop until process terminated or stopped */
4096                while (job->state == JOBRUNNING)
4097                        blocking_wait_with_raise_on_sig();
4098                job->waited = 1;
4099                retval = getstatus(job);
4100 repeat: ;
4101        } while (*++argv);
4102
4103 ret:
4104        return retval;
4105}
4106
4107static struct job *
4108growjobtab(void)
4109{
4110        size_t len;
4111        ptrdiff_t offset;
4112        struct job *jp, *jq;
4113
4114        len = njobs * sizeof(*jp);
4115        jq = jobtab;
4116        jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4117
4118        offset = (char *)jp - (char *)jq;
4119        if (offset) {
4120                /* Relocate pointers */
4121                size_t l = len;
4122
4123                jq = (struct job *)((char *)jq + l);
4124                while (l) {
4125                        l -= sizeof(*jp);
4126                        jq--;
4127#define joff(p) ((struct job *)((char *)(p) + l))
4128#define jmove(p) (p) = (void *)((char *)(p) + offset)
4129                        if (joff(jp)->ps == &jq->ps0)
4130                                jmove(joff(jp)->ps);
4131                        if (joff(jp)->prev_job)
4132                                jmove(joff(jp)->prev_job);
4133                }
4134                if (curjob)
4135                        jmove(curjob);
4136#undef joff
4137#undef jmove
4138        }
4139
4140        njobs += 4;
4141        jobtab = jp;
4142        jp = (struct job *)((char *)jp + len);
4143        jq = jp + 3;
4144        do {
4145                jq->used = 0;
4146        } while (--jq >= jp);
4147        return jp;
4148}
4149
4150/*
4151 * Return a new job structure.
4152 * Called with interrupts off.
4153 */
4154static struct job *
4155makejob(/*union node *node,*/ int nprocs)
4156{
4157        int i;
4158        struct job *jp;
4159
4160        for (i = njobs, jp = jobtab; ; jp++) {
4161                if (--i < 0) {
4162                        jp = growjobtab();
4163                        break;
4164                }
4165                if (jp->used == 0)
4166                        break;
4167                if (jp->state != JOBDONE || !jp->waited)
4168                        continue;
4169#if JOBS
4170                if (doing_jobctl)
4171                        continue;
4172#endif
4173                freejob(jp);
4174                break;
4175        }
4176        memset(jp, 0, sizeof(*jp));
4177#if JOBS
4178        /* jp->jobctl is a bitfield.
4179         * "jp->jobctl |= jobctl" likely to give awful code */
4180        if (doing_jobctl)
4181                jp->jobctl = 1;
4182#endif
4183        jp->prev_job = curjob;
4184        curjob = jp;
4185        jp->used = 1;
4186        jp->ps = &jp->ps0;
4187        if (nprocs > 1) {
4188                jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4189        }
4190        TRACE(("makejob(%d) returns %%%d\n", nprocs,
4191                                jobno(jp)));
4192        return jp;
4193}
4194
4195#if JOBS
4196/*
4197 * Return a string identifying a command (to be printed by the
4198 * jobs command).
4199 */
4200static char *cmdnextc;
4201
4202static void
4203cmdputs(const char *s)
4204{
4205        static const char vstype[VSTYPE + 1][3] = {
4206                "", "}", "-", "+", "?", "=",
4207                "%", "%%", "#", "##"
4208                IF_ASH_BASH_COMPAT(, ":", "/", "//")
4209        };
4210
4211        const char *p, *str;
4212        char cc[2];
4213        char *nextc;
4214        unsigned char c;
4215        unsigned char subtype = 0;
4216        int quoted = 0;
4217
4218        cc[1] = '\0';
4219        nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4220        p = s;
4221        while ((c = *p++) != '\0') {
4222                str = NULL;
4223                switch (c) {
4224                case CTLESC:
4225                        c = *p++;
4226                        break;
4227                case CTLVAR:
4228                        subtype = *p++;
4229                        if ((subtype & VSTYPE) == VSLENGTH)
4230                                str = "${#";
4231                        else
4232                                str = "${";
4233                        if (!(subtype & VSQUOTE) == !(quoted & 1))
4234                                goto dostr;
4235                        quoted ^= 1;
4236                        c = '"';
4237                        break;
4238                case CTLENDVAR:
4239                        str = "\"}" + !(quoted & 1);
4240                        quoted >>= 1;
4241                        subtype = 0;
4242                        goto dostr;
4243                case CTLBACKQ:
4244                        str = "$(...)";
4245                        goto dostr;
4246                case CTLBACKQ+CTLQUOTE:
4247                        str = "\"$(...)\"";
4248                        goto dostr;
4249#if ENABLE_SH_MATH_SUPPORT
4250                case CTLARI:
4251                        str = "$((";
4252                        goto dostr;
4253                case CTLENDARI:
4254                        str = "))";
4255                        goto dostr;
4256#endif
4257                case CTLQUOTEMARK:
4258                        quoted ^= 1;
4259                        c = '"';
4260                        break;
4261                case '=':
4262                        if (subtype == 0)
4263                                break;
4264                        if ((subtype & VSTYPE) != VSNORMAL)
4265                                quoted <<= 1;
4266                        str = vstype[subtype & VSTYPE];
4267                        if (subtype & VSNUL)
4268                                c = ':';
4269                        else
4270                                goto checkstr;
4271                        break;
4272                case '\'':
4273                case '\\':
4274                case '"':
4275                case '$':
4276                        /* These can only happen inside quotes */
4277                        cc[0] = c;
4278                        str = cc;
4279                        c = '\\';
4280                        break;
4281                default:
4282                        break;
4283                }
4284                USTPUTC(c, nextc);
4285 checkstr:
4286                if (!str)
4287                        continue;
4288 dostr:
4289                while ((c = *str++) != '\0') {
4290                        USTPUTC(c, nextc);
4291                }
4292        } /* while *p++ not NUL */
4293
4294        if (quoted & 1) {
4295                USTPUTC('"', nextc);
4296        }
4297        *nextc = 0;
4298        cmdnextc = nextc;
4299}
4300
4301/* cmdtxt() and cmdlist() call each other */
4302static void cmdtxt(union node *n);
4303
4304static void
4305cmdlist(union node *np, int sep)
4306{
4307        for (; np; np = np->narg.next) {
4308                if (!sep)
4309                        cmdputs(" ");
4310                cmdtxt(np);
4311                if (sep && np->narg.next)
4312                        cmdputs(" ");
4313        }
4314}
4315
4316static void
4317cmdtxt(union node *n)
4318{
4319        union node *np;
4320        struct nodelist *lp;
4321        const char *p;
4322
4323        if (!n)
4324                return;
4325        switch (n->type) {
4326        default:
4327#if DEBUG
4328                abort();
4329#endif
4330        case NPIPE:
4331                lp = n->npipe.cmdlist;
4332                for (;;) {
4333                        cmdtxt(lp->n);
4334                        lp = lp->next;
4335                        if (!lp)
4336                                break;
4337                        cmdputs(" | ");
4338                }
4339                break;
4340        case NSEMI:
4341                p = "; ";
4342                goto binop;
4343        case NAND:
4344                p = " && ";
4345                goto binop;
4346        case NOR:
4347                p = " || ";
4348 binop:
4349                cmdtxt(n->nbinary.ch1);
4350                cmdputs(p);
4351                n = n->nbinary.ch2;
4352                goto donode;
4353        case NREDIR:
4354        case NBACKGND:
4355                n = n->nredir.n;
4356                goto donode;
4357        case NNOT:
4358                cmdputs("!");
4359                n = n->nnot.com;
4360 donode:
4361                cmdtxt(n);
4362                break;
4363        case NIF:
4364                cmdputs("if ");
4365                cmdtxt(n->nif.test);
4366                cmdputs("; then ");
4367                if (n->nif.elsepart) {
4368                        cmdtxt(n->nif.ifpart);
4369                        cmdputs("; else ");
4370                        n = n->nif.elsepart;
4371                } else {
4372                        n = n->nif.ifpart;
4373                }
4374                p = "; fi";
4375                goto dotail;
4376        case NSUBSHELL:
4377                cmdputs("(");
4378                n = n->nredir.n;
4379                p = ")";
4380                goto dotail;
4381        case NWHILE:
4382                p = "while ";
4383                goto until;
4384        case NUNTIL:
4385                p = "until ";
4386 until:
4387                cmdputs(p);
4388                cmdtxt(n->nbinary.ch1);
4389                n = n->nbinary.ch2;
4390                p = "; done";
4391 dodo:
4392                cmdputs("; do ");
4393 dotail:
4394                cmdtxt(n);
4395                goto dotail2;
4396        case NFOR:
4397                cmdputs("for ");
4398                cmdputs(n->nfor.var);
4399                cmdputs(" in ");
4400                cmdlist(n->nfor.args, 1);
4401                n = n->nfor.body;
4402                p = "; done";
4403                goto dodo;
4404        case NDEFUN:
4405                cmdputs(n->narg.text);
4406                p = "() { ... }";
4407                goto dotail2;
4408        case NCMD:
4409                cmdlist(n->ncmd.args, 1);
4410                cmdlist(n->ncmd.redirect, 0);
4411                break;
4412        case NARG:
4413                p = n->narg.text;
4414 dotail2:
4415                cmdputs(p);
4416                break;
4417        case NHERE:
4418        case NXHERE:
4419                p = "<<...";
4420                goto dotail2;
4421        case NCASE:
4422                cmdputs("case ");
4423                cmdputs(n->ncase.expr->narg.text);
4424                cmdputs(" in ");
4425                for (np = n->ncase.cases; np; np = np->nclist.next) {
4426                        cmdtxt(np->nclist.pattern);
4427                        cmdputs(") ");
4428                        cmdtxt(np->nclist.body);
4429                        cmdputs(";; ");
4430                }
4431                p = "esac";
4432                goto dotail2;
4433        case NTO:
4434                p = ">";
4435                goto redir;
4436        case NCLOBBER:
4437                p = ">|";
4438                goto redir;
4439        case NAPPEND:
4440                p = ">>";
4441                goto redir;
4442#if ENABLE_ASH_BASH_COMPAT
4443        case NTO2:
4444#endif
4445        case NTOFD:
4446                p = ">&";
4447                goto redir;
4448        case NFROM:
4449                p = "<";
4450                goto redir;
4451        case NFROMFD:
4452                p = "<&";
4453                goto redir;
4454        case NFROMTO:
4455                p = "<>";
4456 redir:
4457                cmdputs(utoa(n->nfile.fd));
4458                cmdputs(p);
4459                if (n->type == NTOFD || n->type == NFROMFD) {
4460                        cmdputs(utoa(n->ndup.dupfd));
4461                        break;
4462                }
4463                n = n->nfile.fname;
4464                goto donode;
4465        }
4466}
4467
4468static char *
4469commandtext(union node *n)
4470{
4471        char *name;
4472
4473        STARTSTACKSTR(cmdnextc);
4474        cmdtxt(n);
4475        name = stackblock();
4476        TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4477                        name, cmdnextc, cmdnextc));
4478        return ckstrdup(name);
4479}
4480#endif /* JOBS */
4481
4482/*
4483 * Fork off a subshell.  If we are doing job control, give the subshell its
4484 * own process group.  Jp is a job structure that the job is to be added to.
4485 * N is the command that will be evaluated by the child.  Both jp and n may
4486 * be NULL.  The mode parameter can be one of the following:
4487 *      FORK_FG - Fork off a foreground process.
4488 *      FORK_BG - Fork off a background process.
4489 *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
4490 *                   process group even if job control is on.
4491 *
4492 * When job control is turned off, background processes have their standard
4493 * input redirected to /dev/null (except for the second and later processes
4494 * in a pipeline).
4495 *
4496 * Called with interrupts off.
4497 */
4498/*
4499 * Clear traps on a fork.
4500 */
4501static void
4502clear_traps(void)
4503{
4504        char **tp;
4505
4506        for (tp = trap; tp < &trap[NSIG]; tp++) {
4507                if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */
4508                        INT_OFF;
4509                        if (trap_ptr == trap)
4510                                free(*tp);
4511                        /* else: it "belongs" to trap_ptr vector, don't free */
4512                        *tp = NULL;
4513                        if ((tp - trap) != 0)
4514                                setsignal(tp - trap);
4515                        INT_ON;
4516                }
4517        }
4518}
4519
4520/* Lives far away from here, needed for forkchild */
4521static void closescript(void);
4522
4523/* Called after fork(), in child */
4524static NOINLINE void
4525forkchild(struct job *jp, union node *n, int mode)
4526{
4527        int oldlvl;
4528
4529        TRACE(("Child shell %d\n", getpid()));
4530        oldlvl = shlvl;
4531        shlvl++;
4532
4533        /* man bash: "Non-builtin commands run by bash have signal handlers
4534         * set to the values inherited by the shell from its parent".
4535         * Do we do it correctly? */
4536
4537        closescript();
4538
4539        if (mode == FORK_NOJOB          /* is it `xxx` ? */
4540         && n && n->type == NCMD        /* is it single cmd? */
4541        /* && n->ncmd.args->type == NARG - always true? */
4542         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
4543         && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4544        /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4545        ) {
4546                TRACE(("Trap hack\n"));
4547                /* Awful hack for `trap` or $(trap).
4548                 *
4549                 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4550                 * contains an example where "trap" is executed in a subshell:
4551                 *
4552                 * save_traps=$(trap)
4553                 * ...
4554                 * eval "$save_traps"
4555                 *
4556                 * Standard does not say that "trap" in subshell shall print
4557                 * parent shell's traps. It only says that its output
4558                 * must have suitable form, but then, in the above example
4559                 * (which is not supposed to be normative), it implies that.
4560                 *
4561                 * bash (and probably other shell) does implement it
4562                 * (traps are reset to defaults, but "trap" still shows them),
4563                 * but as a result, "trap" logic is hopelessly messed up:
4564                 *
4565                 * # trap
4566                 * trap -- 'echo Ho' SIGWINCH  <--- we have a handler
4567                 * # (trap)        <--- trap is in subshell - no output (correct, traps are reset)
4568                 * # true | trap   <--- trap is in subshell - no output (ditto)
4569                 * # echo `true | trap`    <--- in subshell - output (but traps are reset!)
4570                 * trap -- 'echo Ho' SIGWINCH
4571                 * # echo `(trap)`         <--- in subshell in subshell - output
4572                 * trap -- 'echo Ho' SIGWINCH
4573                 * # echo `true | (trap)`  <--- in subshell in subshell in subshell - output!
4574                 * trap -- 'echo Ho' SIGWINCH
4575                 *
4576                 * The rules when to forget and when to not forget traps
4577                 * get really complex and nonsensical.
4578                 *
4579                 * Our solution: ONLY bare $(trap) or `trap` is special.
4580                 */
4581                /* Save trap handler strings for trap builtin to print */
4582                trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
4583                /* Fall through into clearing traps */
4584        }
4585        clear_traps();
4586#if JOBS
4587        /* do job control only in root shell */
4588        doing_jobctl = 0;
4589        if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4590                pid_t pgrp;
4591
4592                if (jp->nprocs == 0)
4593                        pgrp = getpid();
4594                else
4595                        pgrp = jp->ps[0].ps_pid;
4596                /* this can fail because we are doing it in the parent also */
4597                setpgid(0, pgrp);
4598                if (mode == FORK_FG)
4599                        xtcsetpgrp(ttyfd, pgrp);
4600                setsignal(SIGTSTP);
4601                setsignal(SIGTTOU);
4602        } else
4603#endif
4604        if (mode == FORK_BG) {
4605                /* man bash: "When job control is not in effect,
4606                 * asynchronous commands ignore SIGINT and SIGQUIT" */
4607                ignoresig(SIGINT);
4608                ignoresig(SIGQUIT);
4609                if (jp->nprocs == 0) {
4610                        close(0);
4611                        if (open(bb_dev_null, O_RDONLY) != 0)
4612                                ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4613                }
4614        }
4615        if (!oldlvl) {
4616                if (iflag) { /* why if iflag only? */
4617                        setsignal(SIGINT);
4618                        setsignal(SIGTERM);
4619                }
4620                /* man bash:
4621                 * "In all cases, bash ignores SIGQUIT. Non-builtin
4622                 * commands run by bash have signal handlers
4623                 * set to the values inherited by the shell
4624                 * from its parent".
4625                 * Take care of the second rule: */
4626                setsignal(SIGQUIT);
4627        }
4628#if JOBS
4629        if (n && n->type == NCMD
4630         && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
4631        ) {
4632                TRACE(("Job hack\n"));
4633                /* "jobs": we do not want to clear job list for it,
4634                 * instead we remove only _its_ own_ job from job list.
4635                 * This makes "jobs .... | cat" more useful.
4636                 */
4637                freejob(curjob);
4638                return;
4639        }
4640#endif
4641        for (jp = curjob; jp; jp = jp->prev_job)
4642                freejob(jp);
4643        jobless = 0;
4644}
4645
4646/* Called after fork(), in parent */
4647#if !JOBS
4648#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4649#endif
4650static void
4651forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4652{
4653        TRACE(("In parent shell: child = %d\n", pid));
4654        if (!jp) {
4655                while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4656                        continue;
4657                jobless++;
4658                return;
4659        }
4660#if JOBS
4661        if (mode != FORK_NOJOB && jp->jobctl) {
4662                int pgrp;
4663
4664                if (jp->nprocs == 0)
4665                        pgrp = pid;
4666                else
4667                        pgrp = jp->ps[0].ps_pid;
4668                /* This can fail because we are doing it in the child also */
4669                setpgid(pid, pgrp);
4670        }
4671#endif
4672        if (mode == FORK_BG) {
4673                backgndpid = pid;               /* set $! */
4674                set_curjob(jp, CUR_RUNNING);
4675        }
4676        if (jp) {
4677                struct procstat *ps = &jp->ps[jp->nprocs++];
4678                ps->ps_pid = pid;
4679                ps->ps_status = -1;
4680                ps->ps_cmd = nullstr;
4681#if JOBS
4682                if (doing_jobctl && n)
4683                        ps->ps_cmd = commandtext(n);
4684#endif
4685        }
4686}
4687
4688static int
4689forkshell(struct job *jp, union node *n, int mode)
4690{
4691        int pid;
4692
4693        TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4694        pid = fork();
4695        if (pid < 0) {
4696                TRACE(("Fork failed, errno=%d", errno));
4697                if (jp)
4698                        freejob(jp);
4699                ash_msg_and_raise_error("can't fork");
4700        }
4701        if (pid == 0) {
4702                CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
4703                forkchild(jp, n, mode);
4704        } else {
4705                forkparent(jp, n, mode, pid);
4706        }
4707        return pid;
4708}
4709
4710/*
4711 * Wait for job to finish.
4712 *
4713 * Under job control we have the problem that while a child process
4714 * is running interrupts generated by the user are sent to the child
4715 * but not to the shell.  This means that an infinite loop started by
4716 * an interactive user may be hard to kill.  With job control turned off,
4717 * an interactive user may place an interactive program inside a loop.
4718 * If the interactive program catches interrupts, the user doesn't want
4719 * these interrupts to also abort the loop.  The approach we take here
4720 * is to have the shell ignore interrupt signals while waiting for a
4721 * foreground process to terminate, and then send itself an interrupt
4722 * signal if the child process was terminated by an interrupt signal.
4723 * Unfortunately, some programs want to do a bit of cleanup and then
4724 * exit on interrupt; unless these processes terminate themselves by
4725 * sending a signal to themselves (instead of calling exit) they will
4726 * confuse this approach.
4727 *
4728 * Called with interrupts off.
4729 */
4730static int
4731waitforjob(struct job *jp)
4732{
4733        int st;
4734
4735        TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4736
4737        INT_OFF;
4738        while (jp->state == JOBRUNNING) {
4739                /* In non-interactive shells, we _can_ get
4740                 * a keyboard signal here and be EINTRed,
4741                 * but we just loop back, waiting for command to complete.
4742                 *
4743                 * man bash:
4744                 * "If bash is waiting for a command to complete and receives
4745                 * a signal for which a trap has been set, the trap
4746                 * will not be executed until the command completes."
4747                 *
4748                 * Reality is that even if trap is not set, bash
4749                 * will not act on the signal until command completes.
4750                 * Try this. sleep5intoff.c:
4751                 * #include <signal.h>
4752                 * #include <unistd.h>
4753                 * int main() {
4754                 *         sigset_t set;
4755                 *         sigemptyset(&set);
4756                 *         sigaddset(&set, SIGINT);
4757                 *         sigaddset(&set, SIGQUIT);
4758                 *         sigprocmask(SIG_BLOCK, &set, NULL);
4759                 *         sleep(5);
4760                 *         return 0;
4761                 * }
4762                 * $ bash -c './sleep5intoff; echo hi'
4763                 * ^C^C^C^C <--- pressing ^C once a second
4764                 * $ _
4765                 * $ bash -c './sleep5intoff; echo hi'
4766                 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4767                 * $ _
4768                 */
4769                dowait(DOWAIT_BLOCK, jp);
4770        }
4771        INT_ON;
4772
4773        st = getstatus(jp);
4774#if JOBS
4775        if (jp->jobctl) {
4776                xtcsetpgrp(ttyfd, rootpid);
4777                /*
4778                 * This is truly gross.
4779                 * If we're doing job control, then we did a TIOCSPGRP which
4780                 * caused us (the shell) to no longer be in the controlling
4781                 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
4782                 * intuit from the subprocess exit status whether a SIGINT
4783                 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
4784                 */
4785                if (jp->sigint) /* TODO: do the same with all signals */
4786                        raise(SIGINT); /* ... by raise(jp->sig) instead? */
4787        }
4788        if (jp->state == JOBDONE)
4789#endif
4790                freejob(jp);
4791        return st;
4792}
4793
4794/*
4795 * return 1 if there are stopped jobs, otherwise 0
4796 */
4797static int
4798stoppedjobs(void)
4799{
4800        struct job *jp;
4801        int retval;
4802
4803        retval = 0;
4804        if (job_warning)
4805                goto out;
4806        jp = curjob;
4807        if (jp && jp->state == JOBSTOPPED) {
4808                out2str("You have stopped jobs.\n");
4809                job_warning = 2;
4810                retval++;
4811        }
4812 out:
4813        return retval;
4814}
4815
4816
4817/* ============ redir.c
4818 *
4819 * Code for dealing with input/output redirection.
4820 */
4821
4822#define EMPTY -2                /* marks an unused slot in redirtab */
4823#define CLOSED -3               /* marks a slot of previously-closed fd */
4824
4825/*
4826 * Open a file in noclobber mode.
4827 * The code was copied from bash.
4828 */
4829static int
4830noclobberopen(const char *fname)
4831{
4832        int r, fd;
4833        struct stat finfo, finfo2;
4834
4835        /*
4836         * If the file exists and is a regular file, return an error
4837         * immediately.
4838         */
4839        r = stat(fname, &finfo);
4840        if (r == 0 && S_ISREG(finfo.st_mode)) {
4841                errno = EEXIST;
4842                return -1;
4843        }
4844
4845        /*
4846         * If the file was not present (r != 0), make sure we open it
4847         * exclusively so that if it is created before we open it, our open
4848         * will fail.  Make sure that we do not truncate an existing file.
4849         * Note that we don't turn on O_EXCL unless the stat failed -- if the
4850         * file was not a regular file, we leave O_EXCL off.
4851         */
4852        if (r != 0)
4853                return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4854        fd = open(fname, O_WRONLY|O_CREAT, 0666);
4855
4856        /* If the open failed, return the file descriptor right away. */
4857        if (fd < 0)
4858                return fd;
4859
4860        /*
4861         * OK, the open succeeded, but the file may have been changed from a
4862         * non-regular file to a regular file between the stat and the open.
4863         * We are assuming that the O_EXCL open handles the case where FILENAME
4864         * did not exist and is symlinked to an existing file between the stat
4865         * and open.
4866         */
4867
4868        /*
4869         * If we can open it and fstat the file descriptor, and neither check
4870         * revealed that it was a regular file, and the file has not been
4871         * replaced, return the file descriptor.
4872         */
4873        if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4874         && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4875                return fd;
4876
4877        /* The file has been replaced.  badness. */
4878        close(fd);
4879        errno = EEXIST;
4880        return -1;
4881}
4882
4883/*
4884 * Handle here documents.  Normally we fork off a process to write the
4885 * data to a pipe.  If the document is short, we can stuff the data in
4886 * the pipe without forking.
4887 */
4888/* openhere needs this forward reference */
4889static void expandhere(union node *arg, int fd);
4890static int
4891openhere(union node *redir)
4892{
4893        int pip[2];
4894        size_t len = 0;
4895
4896        if (pipe(pip) < 0)
4897                ash_msg_and_raise_error("pipe call failed");
4898        if (redir->type == NHERE) {
4899                len = strlen(redir->nhere.doc->narg.text);
4900                if (len <= PIPE_BUF) {
4901                        full_write(pip[1], redir->nhere.doc->narg.text, len);
4902                        goto out;
4903                }
4904        }
4905        if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4906                /* child */
4907                close(pip[0]);
4908                ignoresig(SIGINT);  //signal(SIGINT, SIG_IGN);
4909                ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
4910                ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
4911                ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
4912                signal(SIGPIPE, SIG_DFL);
4913                if (redir->type == NHERE)
4914                        full_write(pip[1], redir->nhere.doc->narg.text, len);
4915                else /* NXHERE */
4916                        expandhere(redir->nhere.doc, pip[1]);
4917                _exit(EXIT_SUCCESS);
4918        }
4919 out:
4920        close(pip[1]);
4921        return pip[0];
4922}
4923
4924static int
4925openredirect(union node *redir)
4926{
4927        char *fname;
4928        int f;
4929
4930        switch (redir->nfile.type) {
4931        case NFROM:
4932                fname = redir->nfile.expfname;
4933                f = open(fname, O_RDONLY);
4934                if (f < 0)
4935                        goto eopen;
4936                break;
4937        case NFROMTO:
4938                fname = redir->nfile.expfname;
4939                f = open(fname, O_RDWR|O_CREAT, 0666);
4940                if (f < 0)
4941                        goto ecreate;
4942                break;
4943        case NTO:
4944#if ENABLE_ASH_BASH_COMPAT
4945        case NTO2:
4946#endif
4947                /* Take care of noclobber mode. */
4948                if (Cflag) {
4949                        fname = redir->nfile.expfname;
4950                        f = noclobberopen(fname);
4951                        if (f < 0)
4952                                goto ecreate;
4953                        break;
4954                }
4955                /* FALLTHROUGH */
4956        case NCLOBBER:
4957                fname = redir->nfile.expfname;
4958                f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4959                if (f < 0)
4960                        goto ecreate;
4961                break;
4962        case NAPPEND:
4963                fname = redir->nfile.expfname;
4964                f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4965                if (f < 0)
4966                        goto ecreate;
4967                break;
4968        default:
4969#if DEBUG
4970                abort();
4971#endif
4972                /* Fall through to eliminate warning. */
4973/* Our single caller does this itself */
4974//      case NTOFD:
4975//      case NFROMFD:
4976//              f = -1;
4977//              break;
4978        case NHERE:
4979        case NXHERE:
4980                f = openhere(redir);
4981                break;
4982        }
4983
4984        return f;
4985 ecreate:
4986        ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4987 eopen:
4988        ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
4989}
4990
4991/*
4992 * Copy a file descriptor to be >= to.  Returns -1
4993 * if the source file descriptor is closed, EMPTY if there are no unused
4994 * file descriptors left.
4995 */
4996/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
4997 * old code was doing close(to) prior to copyfd() to achieve the same */
4998enum {
4999        COPYFD_EXACT   = (int)~(INT_MAX),
5000        COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5001};
5002static int
5003copyfd(int from, int to)
5004{
5005        int newfd;
5006
5007        if (to & COPYFD_EXACT) {
5008                to &= ~COPYFD_EXACT;
5009                /*if (from != to)*/
5010                        newfd = dup2(from, to);
5011        } else {
5012                newfd = fcntl(from, F_DUPFD, to);
5013        }
5014        if (newfd < 0) {
5015                if (errno == EMFILE)
5016                        return EMPTY;
5017                /* Happens when source fd is not open: try "echo >&99" */
5018                ash_msg_and_raise_error("%d: %m", from);
5019        }
5020        return newfd;
5021}
5022
5023/* Struct def and variable are moved down to the first usage site */
5024struct two_fd_t {
5025        int orig, copy;
5026};
5027struct redirtab {
5028        struct redirtab *next;
5029        int nullredirs;
5030        int pair_count;
5031        struct two_fd_t two_fd[];
5032};
5033#define redirlist (G_var.redirlist)
5034
5035static int need_to_remember(struct redirtab *rp, int fd)
5036{
5037        int i;
5038
5039        if (!rp) /* remembering was not requested */
5040                return 0;
5041
5042        for (i = 0; i < rp->pair_count; i++) {
5043                if (rp->two_fd[i].orig == fd) {
5044                        /* already remembered */
5045                        return 0;
5046                }
5047        }
5048        return 1;
5049}
5050
5051/* "hidden" fd is a fd used to read scripts, or a copy of such */
5052static int is_hidden_fd(struct redirtab *rp, int fd)
5053{
5054        int i;
5055        struct parsefile *pf;
5056
5057        if (fd == -1)
5058                return 0;
5059        /* Check open scripts' fds */
5060        pf = g_parsefile;
5061        while (pf) {
5062                /* We skip pf_fd == 0 case because of the following case:
5063                 * $ ash  # running ash interactively
5064                 * $ . ./script.sh
5065                 * and in script.sh: "exec 9>&0".
5066                 * Even though top-level pf_fd _is_ 0,
5067                 * it's still ok to use it: "read" builtin uses it,
5068                 * why should we cripple "exec" builtin?
5069                 */
5070                if (pf->pf_fd > 0 && fd == pf->pf_fd) {
5071                        return 1;
5072                }
5073                pf = pf->prev;
5074        }
5075
5076        if (!rp)
5077                return 0;
5078        /* Check saved fds of redirects */
5079        fd |= COPYFD_RESTORE;
5080        for (i = 0; i < rp->pair_count; i++) {
5081                if (rp->two_fd[i].copy == fd) {
5082                        return 1;
5083                }
5084        }
5085        return 0;
5086}
5087
5088/*
5089 * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
5090 * old file descriptors are stashed away so that the redirection can be
5091 * undone by calling popredir.
5092 */
5093/* flags passed to redirect */
5094#define REDIR_PUSH    01        /* save previous values of file descriptors */
5095#define REDIR_SAVEFD2 03        /* set preverrout */
5096static void
5097redirect(union node *redir, int flags)
5098{
5099        struct redirtab *sv;
5100        int sv_pos;
5101        int i;
5102        int fd;
5103        int newfd;
5104        int copied_fd2 = -1;
5105
5106        g_nullredirs++;
5107        if (!redir) {
5108                return;
5109        }
5110
5111        sv = NULL;
5112        sv_pos = 0;
5113        INT_OFF;
5114        if (flags & REDIR_PUSH) {
5115                union node *tmp = redir;
5116                do {
5117                        sv_pos++;
5118#if ENABLE_ASH_BASH_COMPAT
5119                        if (tmp->nfile.type == NTO2)
5120                                sv_pos++;
5121#endif
5122                        tmp = tmp->nfile.next;
5123                } while (tmp);
5124                sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
5125                sv->next = redirlist;
5126                sv->pair_count = sv_pos;
5127                redirlist = sv;
5128                sv->nullredirs = g_nullredirs - 1;
5129                g_nullredirs = 0;
5130                while (sv_pos > 0) {
5131                        sv_pos--;
5132                        sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5133                }
5134        }
5135
5136        do {
5137                int right_fd = -1;
5138                fd = redir->nfile.fd;
5139                if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5140                        right_fd = redir->ndup.dupfd;
5141                        //bb_error_msg("doing %d > %d", fd, right_fd);
5142                        /* redirect from/to same file descriptor? */
5143                        if (right_fd == fd)
5144                                continue;
5145                        /* "echo >&10" and 10 is a fd opened to a sh script? */
5146                        if (is_hidden_fd(sv, right_fd)) {
5147                                errno = EBADF; /* as if it is closed */
5148                                ash_msg_and_raise_error("%d: %m", right_fd);
5149                        }
5150                        newfd = -1;
5151                } else {
5152                        newfd = openredirect(redir); /* always >= 0 */
5153                        if (fd == newfd) {
5154                                /* Descriptor wasn't open before redirect.
5155                                 * Mark it for close in the future */
5156                                if (need_to_remember(sv, fd)) {
5157                                        goto remember_to_close;
5158                                }
5159                                continue;
5160                        }
5161                }
5162#if ENABLE_ASH_BASH_COMPAT
5163 redirect_more:
5164#endif
5165                if (need_to_remember(sv, fd)) {
5166                        /* Copy old descriptor */
5167                        /* Careful to not accidentally "save"
5168                         * to the same fd as right side fd in N>&M */
5169                        int minfd = right_fd < 10 ? 10 : right_fd + 1;
5170                        i = fcntl(fd, F_DUPFD, minfd);
5171/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5172 * are closed in popredir() in the child, preventing them from leaking
5173 * into child. (popredir() also cleans up the mess in case of failures)
5174 */
5175                        if (i == -1) {
5176                                i = errno;
5177                                if (i != EBADF) {
5178                                        /* Strange error (e.g. "too many files" EMFILE?) */
5179                                        if (newfd >= 0)
5180                                                close(newfd);
5181                                        errno = i;
5182                                        ash_msg_and_raise_error("%d: %m", fd);
5183                                        /* NOTREACHED */
5184                                }
5185                                /* EBADF: it is not open - good, remember to close it */
5186 remember_to_close:
5187                                i = CLOSED;
5188                        } else { /* fd is open, save its copy */
5189                                /* "exec fd>&-" should not close fds
5190                                 * which point to script file(s).
5191                                 * Force them to be restored afterwards */
5192                                if (is_hidden_fd(sv, fd))
5193                                        i |= COPYFD_RESTORE;
5194                        }
5195                        if (fd == 2)
5196                                copied_fd2 = i;
5197                        sv->two_fd[sv_pos].orig = fd;
5198                        sv->two_fd[sv_pos].copy = i;
5199                        sv_pos++;
5200                }
5201                if (newfd < 0) {
5202                        /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5203                        if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5204                                /* Don't want to trigger debugging */
5205                                if (fd != -1)
5206                                        close(fd);
5207                        } else {
5208                                copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5209                        }
5210                } else if (fd != newfd) { /* move newfd to fd */
5211                        copyfd(newfd, fd | COPYFD_EXACT);
5212#if ENABLE_ASH_BASH_COMPAT
5213                        if (!(redir->nfile.type == NTO2 && fd == 2))
5214#endif
5215                                close(newfd);
5216                }
5217#if ENABLE_ASH_BASH_COMPAT
5218                if (redir->nfile.type == NTO2 && fd == 1) {
5219                        /* We already redirected it to fd 1, now copy it to 2 */
5220                        newfd = 1;
5221                        fd = 2;
5222                        goto redirect_more;
5223                }
5224#endif
5225        } while ((redir = redir->nfile.next) != NULL);
5226
5227        INT_ON;
5228        if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5229                preverrout_fd = copied_fd2;
5230}
5231
5232/*
5233 * Undo the effects of the last redirection.
5234 */
5235static void
5236popredir(int drop, int restore)
5237{
5238        struct redirtab *rp;
5239        int i;
5240
5241        if (--g_nullredirs >= 0)
5242                return;
5243        INT_OFF;
5244        rp = redirlist;
5245        for (i = 0; i < rp->pair_count; i++) {
5246                int fd = rp->two_fd[i].orig;
5247                int copy = rp->two_fd[i].copy;
5248                if (copy == CLOSED) {
5249                        if (!drop)
5250                                close(fd);
5251                        continue;
5252                }
5253                if (copy != EMPTY) {
5254                        if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5255                                copy &= ~COPYFD_RESTORE;
5256                                /*close(fd);*/
5257                                copyfd(copy, fd | COPYFD_EXACT);
5258                        }
5259                        close(copy & ~COPYFD_RESTORE);
5260                }
5261        }
5262        redirlist = rp->next;
5263        g_nullredirs = rp->nullredirs;
5264        free(rp);
5265        INT_ON;
5266}
5267
5268/*
5269 * Undo all redirections.  Called on error or interrupt.
5270 */
5271
5272/*
5273 * Discard all saved file descriptors.
5274 */
5275static void
5276clearredir(int drop)
5277{
5278        for (;;) {
5279                g_nullredirs = 0;
5280                if (!redirlist)
5281                        break;
5282                popredir(drop, /*restore:*/ 0);
5283        }
5284}
5285
5286static int
5287redirectsafe(union node *redir, int flags)
5288{
5289        int err;
5290        volatile int saveint;
5291        struct jmploc *volatile savehandler = exception_handler;
5292        struct jmploc jmploc;
5293
5294        SAVE_INT(saveint);
5295        /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5296        err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5297        if (!err) {
5298                exception_handler = &jmploc;
5299                redirect(redir, flags);
5300        }
5301        exception_handler = savehandler;
5302        if (err && exception_type != EXERROR)
5303                longjmp(exception_handler->loc, 1);
5304        RESTORE_INT(saveint);
5305        return err;
5306}
5307
5308
5309/* ============ Routines to expand arguments to commands
5310 *
5311 * We have to deal with backquotes, shell variables, and file metacharacters.
5312 */
5313
5314#if ENABLE_SH_MATH_SUPPORT
5315static arith_t
5316ash_arith(const char *s)
5317{
5318        arith_eval_hooks_t math_hooks;
5319        arith_t result;
5320        int errcode = 0;
5321
5322        math_hooks.lookupvar = lookupvar;
5323        math_hooks.setvar    = setvar2;
5324        math_hooks.endofname = endofname;
5325
5326        INT_OFF;
5327        result = arith(s, &errcode, &math_hooks);
5328        if (errcode < 0) {
5329                if (errcode == -3)
5330                        ash_msg_and_raise_error("exponent less than 0");
5331                if (errcode == -2)
5332                        ash_msg_and_raise_error("divide by zero");
5333                if (errcode == -5)
5334                        ash_msg_and_raise_error("expression recursion loop detected");
5335                raise_error_syntax(s);
5336        }
5337        INT_ON;
5338
5339        return result;
5340}
5341#endif
5342
5343/*
5344 * expandarg flags
5345 */
5346#define EXP_FULL        0x1     /* perform word splitting & file globbing */
5347#define EXP_TILDE       0x2     /* do normal tilde expansion */
5348#define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
5349#define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
5350#define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
5351#define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
5352#define EXP_VARTILDE2   0x40    /* expand tildes after colons only */
5353#define EXP_WORD        0x80    /* expand word in parameter expansion */
5354#define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
5355/*
5356 * rmescape() flags
5357 */
5358#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
5359#define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
5360#define RMESCAPE_QUOTED 0x4     /* Remove CTLESC unless in quotes */
5361#define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
5362#define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
5363
5364/*
5365 * Structure specifying which parts of the string should be searched
5366 * for IFS characters.
5367 */
5368struct ifsregion {
5369        struct ifsregion *next; /* next region in list */
5370        int begoff;             /* offset of start of region */
5371        int endoff;             /* offset of end of region */
5372        int nulonly;            /* search for nul bytes only */
5373};
5374
5375struct arglist {
5376        struct strlist *list;
5377        struct strlist **lastp;
5378};
5379
5380/* output of current string */
5381static char *expdest;
5382/* list of back quote expressions */
5383static struct nodelist *argbackq;
5384/* first struct in list of ifs regions */
5385static struct ifsregion ifsfirst;
5386/* last struct in list */
5387static struct ifsregion *ifslastp;
5388/* holds expanded arg list */
5389static struct arglist exparg;
5390
5391/*
5392 * Our own itoa().
5393 */
5394static int
5395cvtnum(arith_t num)
5396{
5397        int len;
5398
5399        expdest = makestrspace(32, expdest);
5400        len = fmtstr(expdest, 32, arith_t_fmt, num);
5401        STADJUST(len, expdest);
5402        return len;
5403}
5404
5405static size_t
5406esclen(const char *start, const char *p)
5407{
5408        size_t esc = 0;
5409
5410        while (p > start && (unsigned char)*--p == CTLESC) {
5411                esc++;
5412        }
5413        return esc;
5414}
5415
5416/*
5417 * Remove any CTLESC characters from a string.
5418 */
5419static char *
5420rmescapes(char *str, int flag)
5421{
5422        static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5423
5424        char *p, *q, *r;
5425        unsigned inquotes;
5426        unsigned protect_against_glob;
5427        unsigned globbing;
5428
5429        p = strpbrk(str, qchars);
5430        if (!p)
5431                return str;
5432
5433        q = p;
5434        r = str;
5435        if (flag & RMESCAPE_ALLOC) {
5436                size_t len = p - str;
5437                size_t fulllen = len + strlen(p) + 1;
5438
5439                if (flag & RMESCAPE_GROW) {
5440                        int strloc = str - (char *)stackblock();
5441                        r = makestrspace(fulllen, expdest);
5442                        /* p and str may be invalidated by makestrspace */
5443                        str = (char *)stackblock() + strloc;
5444                        p = str + len;
5445                } else if (flag & RMESCAPE_HEAP) {
5446                        r = ckmalloc(fulllen);
5447                } else {
5448                        r = stalloc(fulllen);
5449                }
5450                q = r;
5451                if (len > 0) {
5452                        q = (char *)memcpy(q, str, len) + len;
5453                }
5454        }
5455
5456        inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5457        globbing = flag & RMESCAPE_GLOB;
5458        protect_against_glob = globbing;
5459        while (*p) {
5460                if ((unsigned char)*p == CTLQUOTEMARK) {
5461// TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
5462// (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
5463// Note: both inquotes and protect_against_glob only affect whether
5464// CTLESC,<ch> gets converted to <ch> or to \<ch>
5465                        inquotes = ~inquotes;
5466                        p++;
5467                        protect_against_glob = globbing;
5468                        continue;
5469                }
5470                if (*p == '\\') {
5471                        /* naked back slash */
5472                        protect_against_glob = 0;
5473                        goto copy;
5474                }
5475                if ((unsigned char)*p == CTLESC) {
5476                        p++;
5477                        if (protect_against_glob && inquotes && *p != '/') {
5478                                *q++ = '\\';
5479                        }
5480                }
5481                protect_against_glob = globbing;
5482 copy:
5483                *q++ = *p++;
5484        }
5485        *q = '\0';
5486        if (flag & RMESCAPE_GROW) {
5487                expdest = r;
5488                STADJUST(q - r + 1, expdest);
5489        }
5490        return r;
5491}
5492#define pmatch(a, b) !fnmatch((a), (b), 0)
5493
5494/*
5495 * Prepare a pattern for a expmeta (internal glob(3)) call.
5496 *
5497 * Returns an stalloced string.
5498 */
5499static char *
5500preglob(const char *pattern, int quoted, int flag)
5501{
5502        flag |= RMESCAPE_GLOB;
5503        if (quoted) {
5504                flag |= RMESCAPE_QUOTED;
5505        }
5506        return rmescapes((char *)pattern, flag);
5507}
5508
5509/*
5510 * Put a string on the stack.
5511 */
5512static void
5513memtodest(const char *p, size_t len, int syntax, int quotes)
5514{
5515        char *q = expdest;
5516
5517        q = makestrspace(quotes ? len * 2 : len, q);
5518
5519        while (len--) {
5520                unsigned char c = *p++;
5521                if (c == '\0')
5522                        continue;
5523                if (quotes) {
5524                        int n = SIT(c, syntax);
5525                        if (n == CCTL || n == CBACK)
5526                                USTPUTC(CTLESC, q);
5527                }
5528                USTPUTC(c, q);
5529        }
5530
5531        expdest = q;
5532}
5533
5534static void
5535strtodest(const char *p, int syntax, int quotes)
5536{
5537        memtodest(p, strlen(p), syntax, quotes);
5538}
5539
5540/*
5541 * Record the fact that we have to scan this region of the
5542 * string for IFS characters.
5543 */
5544static void
5545recordregion(int start, int end, int nulonly)
5546{
5547        struct ifsregion *ifsp;
5548
5549        if (ifslastp == NULL) {
5550                ifsp = &ifsfirst;
5551        } else {
5552                INT_OFF;
5553                ifsp = ckzalloc(sizeof(*ifsp));
5554                /*ifsp->next = NULL; - ckzalloc did it */
5555                ifslastp->next = ifsp;
5556                INT_ON;
5557        }
5558        ifslastp = ifsp;
5559        ifslastp->begoff = start;
5560        ifslastp->endoff = end;
5561        ifslastp->nulonly = nulonly;
5562}
5563
5564static void
5565removerecordregions(int endoff)
5566{
5567        if (ifslastp == NULL)
5568                return;
5569
5570        if (ifsfirst.endoff > endoff) {
5571                while (ifsfirst.next != NULL) {
5572                        struct ifsregion *ifsp;
5573                        INT_OFF;
5574                        ifsp = ifsfirst.next->next;
5575                        free(ifsfirst.next);
5576                        ifsfirst.next = ifsp;
5577                        INT_ON;
5578                }
5579                if (ifsfirst.begoff > endoff)
5580                        ifslastp = NULL;
5581                else {
5582                        ifslastp = &ifsfirst;
5583                        ifsfirst.endoff = endoff;
5584                }
5585                return;
5586        }
5587
5588        ifslastp = &ifsfirst;
5589        while (ifslastp->next && ifslastp->next->begoff < endoff)
5590                ifslastp=ifslastp->next;
5591        while (ifslastp->next != NULL) {
5592                struct ifsregion *ifsp;
5593                INT_OFF;
5594                ifsp = ifslastp->next->next;
5595                free(ifslastp->next);
5596                ifslastp->next = ifsp;
5597                INT_ON;
5598        }
5599        if (ifslastp->endoff > endoff)
5600                ifslastp->endoff = endoff;
5601}
5602
5603static char *
5604exptilde(char *startp, char *p, int flags)
5605{
5606        unsigned char c;
5607        char *name;
5608        struct passwd *pw;
5609        const char *home;
5610        int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
5611        int startloc;
5612
5613        name = p + 1;
5614
5615        while ((c = *++p) != '\0') {
5616                switch (c) {
5617                case CTLESC:
5618                        return startp;
5619                case CTLQUOTEMARK:
5620                        return startp;
5621                case ':':
5622                        if (flags & EXP_VARTILDE)
5623                                goto done;
5624                        break;
5625                case '/':
5626                case CTLENDVAR:
5627                        goto done;
5628                }
5629        }
5630 done:
5631        *p = '\0';
5632        if (*name == '\0') {
5633                home = lookupvar("HOME");
5634        } else {
5635                pw = getpwnam(name);
5636                if (pw == NULL)
5637                        goto lose;
5638                home = pw->pw_dir;
5639        }
5640        if (!home || !*home)
5641                goto lose;
5642        *p = c;
5643        startloc = expdest - (char *)stackblock();
5644        strtodest(home, SQSYNTAX, quotes);
5645        recordregion(startloc, expdest - (char *)stackblock(), 0);
5646        return p;
5647 lose:
5648        *p = c;
5649        return startp;
5650}
5651
5652/*
5653 * Execute a command inside back quotes.  If it's a builtin command, we
5654 * want to save its output in a block obtained from malloc.  Otherwise
5655 * we fork off a subprocess and get the output of the command via a pipe.
5656 * Should be called with interrupts off.
5657 */
5658struct backcmd {                /* result of evalbackcmd */
5659        int fd;                 /* file descriptor to read from */
5660        int nleft;              /* number of chars in buffer */
5661        char *buf;              /* buffer */
5662        struct job *jp;         /* job structure for command */
5663};
5664
5665/* These forward decls are needed to use "eval" code for backticks handling: */
5666static uint8_t back_exitstatus; /* exit status of backquoted command */
5667#define EV_EXIT 01              /* exit after evaluating tree */
5668static void evaltree(union node *, int);
5669
5670static void FAST_FUNC
5671evalbackcmd(union node *n, struct backcmd *result)
5672{
5673        int saveherefd;
5674
5675        result->fd = -1;
5676        result->buf = NULL;
5677        result->nleft = 0;
5678        result->jp = NULL;
5679        if (n == NULL)
5680                goto out;
5681
5682        saveherefd = herefd;
5683        herefd = -1;
5684
5685        {
5686                int pip[2];
5687                struct job *jp;
5688
5689                if (pipe(pip) < 0)
5690                        ash_msg_and_raise_error("pipe call failed");
5691                jp = makejob(/*n,*/ 1);
5692                if (forkshell(jp, n, FORK_NOJOB) == 0) {
5693                        FORCE_INT_ON;
5694                        close(pip[0]);
5695                        if (pip[1] != 1) {
5696                                /*close(1);*/
5697                                copyfd(pip[1], 1 | COPYFD_EXACT);
5698                                close(pip[1]);
5699                        }
5700                        eflag = 0;
5701                        evaltree(n, EV_EXIT); /* actually evaltreenr... */
5702                        /* NOTREACHED */
5703                }
5704                close(pip[1]);
5705                result->fd = pip[0];
5706                result->jp = jp;
5707        }
5708        herefd = saveherefd;
5709 out:
5710        TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5711                result->fd, result->buf, result->nleft, result->jp));
5712}
5713
5714/*
5715 * Expand stuff in backwards quotes.
5716 */
5717static void
5718expbackq(union node *cmd, int quoted, int quotes)
5719{
5720        struct backcmd in;
5721        int i;
5722        char buf[128];
5723        char *p;
5724        char *dest;
5725        int startloc;
5726        int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5727        struct stackmark smark;
5728
5729        INT_OFF;
5730        setstackmark(&smark);
5731        dest = expdest;
5732        startloc = dest - (char *)stackblock();
5733        grabstackstr(dest);
5734        evalbackcmd(cmd, &in);
5735        popstackmark(&smark);
5736
5737        p = in.buf;
5738        i = in.nleft;
5739        if (i == 0)
5740                goto read;
5741        for (;;) {
5742                memtodest(p, i, syntax, quotes);
5743 read:
5744                if (in.fd < 0)
5745                        break;
5746                i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5747                TRACE(("expbackq: read returns %d\n", i));
5748                if (i <= 0)
5749                        break;
5750                p = buf;
5751        }
5752
5753        free(in.buf);
5754        if (in.fd >= 0) {
5755                close(in.fd);
5756                back_exitstatus = waitforjob(in.jp);
5757        }
5758        INT_ON;
5759
5760        /* Eat all trailing newlines */
5761        dest = expdest;
5762        for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5763                STUNPUTC(dest);
5764        expdest = dest;
5765
5766        if (quoted == 0)
5767                recordregion(startloc, dest - (char *)stackblock(), 0);
5768        TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5769                (dest - (char *)stackblock()) - startloc,
5770                (dest - (char *)stackblock()) - startloc,
5771                stackblock() + startloc));
5772}
5773
5774#if ENABLE_SH_MATH_SUPPORT
5775/*
5776 * Expand arithmetic expression.  Backup to start of expression,
5777 * evaluate, place result in (backed up) result, adjust string position.
5778 */
5779static void
5780expari(int quotes)
5781{
5782        char *p, *start;
5783        int begoff;
5784        int flag;
5785        int len;
5786
5787        /* ifsfree(); */
5788
5789        /*
5790         * This routine is slightly over-complicated for
5791         * efficiency.  Next we scan backwards looking for the
5792         * start of arithmetic.
5793         */
5794        start = stackblock();
5795        p = expdest - 1;
5796        *p = '\0';
5797        p--;
5798        do {
5799                int esc;
5800
5801                while ((unsigned char)*p != CTLARI) {
5802                        p--;
5803#if DEBUG
5804                        if (p < start) {
5805                                ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5806                        }
5807#endif
5808                }
5809
5810                esc = esclen(start, p);
5811                if (!(esc % 2)) {
5812                        break;
5813                }
5814
5815                p -= esc + 1;
5816        } while (1);
5817
5818        begoff = p - start;
5819
5820        removerecordregions(begoff);
5821
5822        flag = p[1];
5823
5824        expdest = p;
5825
5826        if (quotes)
5827                rmescapes(p + 2, 0);
5828
5829        len = cvtnum(ash_arith(p + 2));
5830
5831        if (flag != '"')
5832                recordregion(begoff, begoff + len, 0);
5833}
5834#endif
5835
5836/* argstr needs it */
5837static char *evalvar(char *p, int flags, struct strlist *var_str_list);
5838
5839/*
5840 * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
5841 * characters to allow for further processing.  Otherwise treat
5842 * $@ like $* since no splitting will be performed.
5843 *
5844 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5845 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5846 * for correct expansion of "B=$A" word.
5847 */
5848static void
5849argstr(char *p, int flags, struct strlist *var_str_list)
5850{
5851        static const char spclchars[] ALIGN1 = {
5852                '=',
5853                ':',
5854                CTLQUOTEMARK,
5855                CTLENDVAR,
5856                CTLESC,
5857                CTLVAR,
5858                CTLBACKQ,
5859                CTLBACKQ | CTLQUOTE,
5860#if ENABLE_SH_MATH_SUPPORT
5861                CTLENDARI,
5862#endif
5863                '\0'
5864        };
5865        const char *reject = spclchars;
5866        int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
5867        int breakall = flags & EXP_WORD;
5868        int inquotes;
5869        size_t length;
5870        int startloc;
5871
5872        if (!(flags & EXP_VARTILDE)) {
5873                reject += 2;
5874        } else if (flags & EXP_VARTILDE2) {
5875                reject++;
5876        }
5877        inquotes = 0;
5878        length = 0;
5879        if (flags & EXP_TILDE) {
5880                char *q;
5881
5882                flags &= ~EXP_TILDE;
5883 tilde:
5884                q = p;
5885                if (*q == CTLESC && (flags & EXP_QWORD))
5886                        q++;
5887                if (*q == '~')
5888                        p = exptilde(p, q, flags);
5889        }
5890 start:
5891        startloc = expdest - (char *)stackblock();
5892        for (;;) {
5893                unsigned char c;
5894
5895                length += strcspn(p + length, reject);
5896                c = p[length];
5897                if (c) {
5898                        if (!(c & 0x80)
5899#if ENABLE_SH_MATH_SUPPORT
5900                         || c == CTLENDARI
5901#endif
5902                        ) {
5903                                /* c == '=' || c == ':' || c == CTLENDARI */
5904                                length++;
5905                        }
5906                }
5907                if (length > 0) {
5908                        int newloc;
5909                        expdest = stack_nputstr(p, length, expdest);
5910                        newloc = expdest - (char *)stackblock();
5911                        if (breakall && !inquotes && newloc > startloc) {
5912                                recordregion(startloc, newloc, 0);
5913                        }
5914                        startloc = newloc;
5915                }
5916                p += length + 1;
5917                length = 0;
5918
5919                switch (c) {
5920                case '\0':
5921                        goto breakloop;
5922                case '=':
5923                        if (flags & EXP_VARTILDE2) {
5924                                p--;
5925                                continue;
5926                        }
5927                        flags |= EXP_VARTILDE2;
5928                        reject++;
5929                        /* fall through */
5930                case ':':
5931                        /*
5932                         * sort of a hack - expand tildes in variable
5933                         * assignments (after the first '=' and after ':'s).
5934                         */
5935                        if (*--p == '~') {
5936                                goto tilde;
5937                        }
5938                        continue;
5939                }
5940
5941                switch (c) {
5942                case CTLENDVAR: /* ??? */
5943                        goto breakloop;
5944                case CTLQUOTEMARK:
5945                        /* "$@" syntax adherence hack */
5946                        if (!inquotes
5947                         && memcmp(p, dolatstr, 4) == 0
5948                         && (  p[4] == CTLQUOTEMARK
5949                            || (p[4] == CTLENDVAR && p[5] == CTLQUOTEMARK)
5950                            )
5951                        ) {
5952                                p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
5953                                goto start;
5954                        }
5955                        inquotes = !inquotes;
5956 addquote:
5957                        if (quotes) {
5958                                p--;
5959                                length++;
5960                                startloc++;
5961                        }
5962                        break;
5963                case CTLESC:
5964                        startloc++;
5965                        length++;
5966                        goto addquote;
5967                case CTLVAR:
5968                        p = evalvar(p, flags, var_str_list);
5969                        goto start;
5970                case CTLBACKQ:
5971                        c = '\0';
5972                case CTLBACKQ|CTLQUOTE:
5973                        expbackq(argbackq->n, c, quotes);
5974                        argbackq = argbackq->next;
5975                        goto start;
5976#if ENABLE_SH_MATH_SUPPORT
5977                case CTLENDARI:
5978                        p--;
5979                        expari(quotes);
5980                        goto start;
5981#endif
5982                }
5983        }
5984 breakloop:
5985        ;
5986}
5987
5988static char *
5989scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes,
5990        int zero)
5991{
5992// This commented out code was added by James Simmons <jsimmons@infradead.org>
5993// as part of a larger change when he added support for ${var/a/b}.
5994// However, it broke # and % operators:
5995//
5996//var=ababcdcd
5997//                 ok       bad
5998//echo ${var#ab}   abcdcd   abcdcd
5999//echo ${var##ab}  abcdcd   abcdcd
6000//echo ${var#a*b}  abcdcd   ababcdcd  (!)
6001//echo ${var##a*b} cdcd     cdcd
6002//echo ${var#?}    babcdcd  ababcdcd  (!)
6003//echo ${var##?}   babcdcd  babcdcd
6004//echo ${var#*}    ababcdcd babcdcd   (!)
6005//echo ${var##*}
6006//echo ${var%cd}   ababcd   ababcd
6007//echo ${var%%cd}  ababcd   abab      (!)
6008//echo ${var%c*d}  ababcd   ababcd
6009//echo ${var%%c*d} abab     ababcdcd  (!)
6010//echo ${var%?}    ababcdc  ababcdc
6011//echo ${var%%?}   ababcdc  ababcdcd  (!)
6012//echo ${var%*}    ababcdcd ababcdcd
6013//echo ${var%%*}
6014//
6015// Commenting it back out helped. Remove it completely if it really
6016// is not needed.
6017
6018        char *loc, *loc2; //, *full;
6019        char c;
6020
6021        loc = startp;
6022        loc2 = rmesc;
6023        do {
6024                int match; // = strlen(str);
6025                const char *s = loc2;
6026
6027                c = *loc2;
6028                if (zero) {
6029                        *loc2 = '\0';
6030                        s = rmesc;
6031                }
6032                match = pmatch(str, s); // this line was deleted
6033
6034//              // chop off end if its '*'
6035//              full = strrchr(str, '*');
6036//              if (full && full != str)
6037//                      match--;
6038//
6039//              // If str starts with '*' replace with s.
6040//              if ((*str == '*') && strlen(s) >= match) {
6041//                      full = xstrdup(s);
6042//                      strncpy(full+strlen(s)-match+1, str+1, match-1);
6043//              } else
6044//                      full = xstrndup(str, match);
6045//              match = strncmp(s, full, strlen(full));
6046//              free(full);
6047//
6048                *loc2 = c;
6049                if (match) // if (!match)
6050                        return loc;
6051                if (quotes && (unsigned char)*loc == CTLESC)
6052                        loc++;
6053                loc++;
6054                loc2++;
6055        } while (c);
6056        return 0;
6057}
6058
6059static char *
6060scanright(char *startp, char *rmesc, char *rmescend, char *pattern, int quotes, int match_at_start)
6061{
6062#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6063        int try2optimize = match_at_start;
6064#endif
6065        int esc = 0;
6066        char *loc;
6067        char *loc2;
6068
6069        /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6070         * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6071         * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6072         * Logic:
6073         * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6074         * and on each iteration they go back two/one char until they reach the beginning.
6075         * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6076         */
6077        /* TODO: document in what other circumstances we are called. */
6078
6079        for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6080                int match;
6081                char c = *loc2;
6082                const char *s = loc2;
6083                if (match_at_start) {
6084                        *loc2 = '\0';
6085                        s = rmesc;
6086                }
6087                match = pmatch(pattern, s);
6088                //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6089                *loc2 = c;
6090                if (match)
6091                        return loc;
6092#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6093                if (try2optimize) {
6094                        /* Maybe we can optimize this:
6095                         * if pattern ends with unescaped *, we can avoid checking
6096                         * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6097                         * it wont match truncated "raw_value_of_" strings too.
6098                         */
6099                        unsigned plen = strlen(pattern);
6100                        /* Does it end with "*"? */
6101                        if (plen != 0 && pattern[--plen] == '*') {
6102                                /* "xxxx*" is not escaped */
6103                                /* "xxx\*" is escaped */
6104                                /* "xx\\*" is not escaped */
6105                                /* "x\\\*" is escaped */
6106                                int slashes = 0;
6107                                while (plen != 0 && pattern[--plen] == '\\')
6108                                        slashes++;
6109                                if (!(slashes & 1))
6110                                        break; /* ends with unescaped "*" */
6111                        }
6112                        try2optimize = 0;
6113                }
6114#endif
6115                loc--;
6116                if (quotes) {
6117                        if (--esc < 0) {
6118                                esc = esclen(startp, loc);
6119                        }
6120                        if (esc % 2) {
6121                                esc--;
6122                                loc--;
6123                        }
6124                }
6125        }
6126        return 0;
6127}
6128
6129static void varunset(const char *, const char *, const char *, int) NORETURN;
6130static void
6131varunset(const char *end, const char *var, const char *umsg, int varflags)
6132{
6133        const char *msg;
6134        const char *tail;
6135
6136        tail = nullstr;
6137        msg = "parameter not set";
6138        if (umsg) {
6139                if ((unsigned char)*end == CTLENDVAR) {
6140                        if (varflags & VSNUL)
6141                                tail = " or null";
6142                } else {
6143                        msg = umsg;
6144                }
6145        }
6146        ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
6147}
6148
6149#if ENABLE_ASH_BASH_COMPAT
6150static char *
6151parse_sub_pattern(char *arg, int inquotes)
6152{
6153        char *idx, *repl = NULL;
6154        unsigned char c;
6155
6156        idx = arg;
6157        while (1) {
6158                c = *arg;
6159                if (!c)
6160                        break;
6161                if (c == '/') {
6162                        /* Only the first '/' seen is our separator */
6163                        if (!repl) {
6164                                repl = idx + 1;
6165                                c = '\0';
6166                        }
6167                }
6168                *idx++ = c;
6169                if (!inquotes && c == '\\' && arg[1] == '\\')
6170                        arg++; /* skip both \\, not just first one */
6171                arg++;
6172        }
6173        *idx = c; /* NUL */
6174
6175        return repl;
6176}
6177#endif /* ENABLE_ASH_BASH_COMPAT */
6178
6179static const char *
6180subevalvar(char *p, char *str, int strloc, int subtype,
6181                int startloc, int varflags, int quotes, struct strlist *var_str_list)
6182{
6183        struct nodelist *saveargbackq = argbackq;
6184        char *startp;
6185        char *loc;
6186        char *rmesc, *rmescend;
6187        IF_ASH_BASH_COMPAT(const char *repl = NULL;)
6188        IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6189        int saveherefd = herefd;
6190        int amount, workloc, resetloc;
6191        int zero;
6192        char *(*scan)(char*, char*, char*, char*, int, int);
6193
6194        herefd = -1;
6195        argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6196                        var_str_list);
6197        STPUTC('\0', expdest);
6198        herefd = saveherefd;
6199        argbackq = saveargbackq;
6200        startp = (char *)stackblock() + startloc;
6201
6202        switch (subtype) {
6203        case VSASSIGN:
6204                setvar(str, startp, 0);
6205                amount = startp - expdest;
6206                STADJUST(amount, expdest);
6207                return startp;
6208
6209#if ENABLE_ASH_BASH_COMPAT
6210        case VSSUBSTR:
6211                loc = str = stackblock() + strloc;
6212                /* Read POS in ${var:POS:LEN} */
6213                pos = atoi(loc); /* number(loc) errors out on "1:4" */
6214                len = str - startp - 1;
6215
6216                /* *loc != '\0', guaranteed by parser */
6217                if (quotes) {
6218                        char *ptr;
6219
6220                        /* Adjust the length by the number of escapes */
6221                        for (ptr = startp; ptr < (str - 1); ptr++) {
6222                                if ((unsigned char)*ptr == CTLESC) {
6223                                        len--;
6224                                        ptr++;
6225                                }
6226                        }
6227                }
6228                orig_len = len;
6229
6230                if (*loc++ == ':') {
6231                        /* ${var::LEN} */
6232                        len = number(loc);
6233                } else {
6234                        /* Skip POS in ${var:POS:LEN} */
6235                        len = orig_len;
6236                        while (*loc && *loc != ':') {
6237                                /* TODO?
6238                                 * bash complains on: var=qwe; echo ${var:1a:123}
6239                                if (!isdigit(*loc))
6240                                        ash_msg_and_raise_error(msg_illnum, str);
6241                                 */
6242                                loc++;
6243                        }
6244                        if (*loc++ == ':') {
6245                                len = number(loc);
6246                        }
6247                }
6248                if (pos >= orig_len) {
6249                        pos = 0;
6250                        len = 0;
6251                }
6252                if (len > (orig_len - pos))
6253                        len = orig_len - pos;
6254
6255                for (str = startp; pos; str++, pos--) {
6256                        if (quotes && (unsigned char)*str == CTLESC)
6257                                str++;
6258                }
6259                for (loc = startp; len; len--) {
6260                        if (quotes && (unsigned char)*str == CTLESC)
6261                                *loc++ = *str++;
6262                        *loc++ = *str++;
6263                }
6264                *loc = '\0';
6265                amount = loc - expdest;
6266                STADJUST(amount, expdest);
6267                return loc;
6268#endif
6269
6270        case VSQUESTION:
6271                varunset(p, str, startp, varflags);
6272                /* NOTREACHED */
6273        }
6274        resetloc = expdest - (char *)stackblock();
6275
6276        /* We'll comeback here if we grow the stack while handling
6277         * a VSREPLACE or VSREPLACEALL, since our pointers into the
6278         * stack will need rebasing, and we'll need to remove our work
6279         * areas each time
6280         */
6281 IF_ASH_BASH_COMPAT(restart:)
6282
6283        amount = expdest - ((char *)stackblock() + resetloc);
6284        STADJUST(-amount, expdest);
6285        startp = (char *)stackblock() + startloc;
6286
6287        rmesc = startp;
6288        rmescend = (char *)stackblock() + strloc;
6289        if (quotes) {
6290                rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6291                if (rmesc != startp) {
6292                        rmescend = expdest;
6293                        startp = (char *)stackblock() + startloc;
6294                }
6295        }
6296        rmescend--;
6297        str = (char *)stackblock() + strloc;
6298        preglob(str, varflags & VSQUOTE, 0);
6299        workloc = expdest - (char *)stackblock();
6300
6301#if ENABLE_ASH_BASH_COMPAT
6302        if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6303                char *idx, *end;
6304
6305                if (!repl) {
6306                        repl = parse_sub_pattern(str, varflags & VSQUOTE);
6307                        if (!repl)
6308                                repl = nullstr;
6309                }
6310
6311                /* If there's no pattern to match, return the expansion unmolested */
6312                if (str[0] == '\0')
6313                        return 0;
6314
6315                len = 0;
6316                idx = startp;
6317                end = str - 1;
6318                while (idx < end) {
6319 try_to_match:
6320                        loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6321                        if (!loc) {
6322                                /* No match, advance */
6323                                char *restart_detect = stackblock();
6324 skip_matching:
6325                                STPUTC(*idx, expdest);
6326                                if (quotes && (unsigned char)*idx == CTLESC) {
6327                                        idx++;
6328                                        len++;
6329                                        STPUTC(*idx, expdest);
6330                                }
6331                                if (stackblock() != restart_detect)
6332                                        goto restart;
6333                                idx++;
6334                                len++;
6335                                rmesc++;
6336                                /* continue; - prone to quadratic behavior, smarter code: */
6337                                if (idx >= end)
6338                                        break;
6339                                if (str[0] == '*') {
6340                                        /* Pattern is "*foo". If "*foo" does not match "long_string",
6341                                         * it would never match "ong_string" etc, no point in trying.
6342                                         */
6343                                        goto skip_matching;
6344                                }
6345                                goto try_to_match;
6346                        }
6347
6348                        if (subtype == VSREPLACEALL) {
6349                                while (idx < loc) {
6350                                        if (quotes && (unsigned char)*idx == CTLESC)
6351                                                idx++;
6352                                        idx++;
6353                                        rmesc++;
6354                                }
6355                        } else {
6356                                idx = loc;
6357                        }
6358
6359                        for (loc = (char*)repl; *loc; loc++) {
6360                                char *restart_detect = stackblock();
6361                                if (quotes && *loc == '\\') {
6362                                        STPUTC(CTLESC, expdest);
6363                                        len++;
6364                                }
6365                                STPUTC(*loc, expdest);
6366                                if (stackblock() != restart_detect)
6367                                        goto restart;
6368                                len++;
6369                        }
6370
6371                        if (subtype == VSREPLACE) {
6372                                while (*idx) {
6373                                        char *restart_detect = stackblock();
6374                                        if (quotes && *idx == '\\') {
6375                                                STPUTC(CTLESC, expdest);
6376                                                len++;
6377                                        }
6378                                        STPUTC(*idx, expdest);
6379                                        if (stackblock() != restart_detect)
6380                                                goto restart;
6381                                        len++;
6382                                        idx++;
6383                                }
6384                                break;
6385                        }
6386                }
6387
6388                /* We've put the replaced text into a buffer at workloc, now
6389                 * move it to the right place and adjust the stack.
6390                 */
6391                STPUTC('\0', expdest);
6392                startp = (char *)stackblock() + startloc;
6393                memmove(startp, (char *)stackblock() + workloc, len + 1);
6394                amount = expdest - (startp + len);
6395                STADJUST(-amount, expdest);
6396                return startp;
6397        }
6398#endif /* ENABLE_ASH_BASH_COMPAT */
6399
6400        subtype -= VSTRIMRIGHT;
6401#if DEBUG
6402        if (subtype < 0 || subtype > 7)
6403                abort();
6404#endif
6405        /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
6406        zero = subtype >> 1;
6407        /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6408        scan = (subtype & 1) ^ zero ? scanleft : scanright;
6409
6410        loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6411        if (loc) {
6412                if (zero) {
6413                        memmove(startp, loc, str - loc);
6414                        loc = startp + (str - loc) - 1;
6415                }
6416                *loc = '\0';
6417                amount = loc - expdest;
6418                STADJUST(amount, expdest);
6419        }
6420        return loc;
6421}
6422
6423/*
6424 * Add the value of a specialized variable to the stack string.
6425 * name parameter (examples):
6426 * ash -c 'echo $1'      name:'1='
6427 * ash -c 'echo $qwe'    name:'qwe='
6428 * ash -c 'echo $$'      name:'$='
6429 * ash -c 'echo ${$}'    name:'$='
6430 * ash -c 'echo ${$##q}' name:'$=q'
6431 * ash -c 'echo ${#$}'   name:'$='
6432 * note: examples with bad shell syntax:
6433 * ash -c 'echo ${#$1}'  name:'$=1'
6434 * ash -c 'echo ${#1#}'  name:'1=#'
6435 */
6436static NOINLINE ssize_t
6437varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6438{
6439        const char *p;
6440        int num;
6441        int i;
6442        int sepq = 0;
6443        ssize_t len = 0;
6444        int subtype = varflags & VSTYPE;
6445        int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
6446        int quoted = varflags & VSQUOTE;
6447        int syntax = quoted ? DQSYNTAX : BASESYNTAX;
6448
6449        switch (*name) {
6450        case '$':
6451                num = rootpid;
6452                goto numvar;
6453        case '?':
6454                num = exitstatus;
6455                goto numvar;
6456        case '#':
6457                num = shellparam.nparam;
6458                goto numvar;
6459        case '!':
6460                num = backgndpid;
6461                if (num == 0)
6462                        return -1;
6463 numvar:
6464                len = cvtnum(num);
6465                goto check_1char_name;
6466        case '-':
6467                expdest = makestrspace(NOPTS, expdest);
6468                for (i = NOPTS - 1; i >= 0; i--) {
6469                        if (optlist[i]) {
6470                                USTPUTC(optletters(i), expdest);
6471                                len++;
6472                        }
6473                }
6474 check_1char_name:
6475#if 0
6476                /* handles cases similar to ${#$1} */
6477                if (name[2] != '\0')
6478                        raise_error_syntax("bad substitution");
6479#endif
6480                break;
6481        case '@': {
6482                char **ap;
6483                int sep;
6484
6485                if (quoted && (flags & EXP_FULL)) {
6486                        /* note: this is not meant as PEOF value */
6487                        sep = 1 << CHAR_BIT;
6488                        goto param;
6489                }
6490                /* fall through */
6491        case '*':
6492                sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
6493                i = SIT(sep, syntax);
6494                if (quotes && (i == CCTL || i == CBACK))
6495                        sepq = 1;
6496 param:
6497                ap = shellparam.p;
6498                if (!ap)
6499                        return -1;
6500                while ((p = *ap++) != NULL) {
6501                        size_t partlen;
6502
6503                        partlen = strlen(p);
6504                        len += partlen;
6505
6506                        if (!(subtype == VSPLUS || subtype == VSLENGTH))
6507                                memtodest(p, partlen, syntax, quotes);
6508
6509                        if (*ap && sep) {
6510                                char *q;
6511
6512                                len++;
6513                                if (subtype == VSPLUS || subtype == VSLENGTH) {
6514                                        continue;
6515                                }
6516                                q = expdest;
6517                                if (sepq)
6518                                        STPUTC(CTLESC, q);
6519                                /* note: may put NUL despite sep != 0
6520                                 * (see sep = 1 << CHAR_BIT above) */
6521                                STPUTC(sep, q);
6522                                expdest = q;
6523                        }
6524                }
6525                return len;
6526        } /* case '@' and '*' */
6527        case '0':
6528        case '1':
6529        case '2':
6530        case '3':
6531        case '4':
6532        case '5':
6533        case '6':
6534        case '7':
6535        case '8':
6536        case '9':
6537                num = atoi(name); /* number(name) fails on ${N#str} etc */
6538                if (num < 0 || num > shellparam.nparam)
6539                        return -1;
6540                p = num ? shellparam.p[num - 1] : arg0;
6541                goto value;
6542        default:
6543                /* NB: name has form "VAR=..." */
6544
6545                /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6546                 * which should be considered before we check variables. */
6547                if (var_str_list) {
6548                        unsigned name_len = (strchrnul(name, '=') - name) + 1;
6549                        p = NULL;
6550                        do {
6551                                char *str, *eq;
6552                                str = var_str_list->text;
6553                                eq = strchr(str, '=');
6554                                if (!eq) /* stop at first non-assignment */
6555                                        break;
6556                                eq++;
6557                                if (name_len == (unsigned)(eq - str)
6558                                 && strncmp(str, name, name_len) == 0
6559                                ) {
6560                                        p = eq;
6561                                        /* goto value; - WRONG! */
6562                                        /* think "A=1 A=2 B=$A" */
6563                                }
6564                                var_str_list = var_str_list->next;
6565                        } while (var_str_list);
6566                        if (p)
6567                                goto value;
6568                }
6569                p = lookupvar(name);
6570 value:
6571                if (!p)
6572                        return -1;
6573
6574                len = strlen(p);
6575                if (!(subtype == VSPLUS || subtype == VSLENGTH))
6576                        memtodest(p, len, syntax, quotes);
6577                return len;
6578        }
6579
6580        if (subtype == VSPLUS || subtype == VSLENGTH)
6581                STADJUST(-len, expdest);
6582        return len;
6583}
6584
6585/*
6586 * Expand a variable, and return a pointer to the next character in the
6587 * input string.
6588 */
6589static char *
6590evalvar(char *p, int flags, struct strlist *var_str_list)
6591{
6592        char varflags;
6593        char subtype;
6594        char quoted;
6595        char easy;
6596        char *var;
6597        int patloc;
6598        int startloc;
6599        ssize_t varlen;
6600
6601        varflags = (unsigned char) *p++;
6602        subtype = varflags & VSTYPE;
6603        quoted = varflags & VSQUOTE;
6604        var = p;
6605        easy = (!quoted || (*var == '@' && shellparam.nparam));
6606        startloc = expdest - (char *)stackblock();
6607        p = strchr(p, '=') + 1; //TODO: use var_end(p)?
6608
6609 again:
6610        varlen = varvalue(var, varflags, flags, var_str_list);
6611        if (varflags & VSNUL)
6612                varlen--;
6613
6614        if (subtype == VSPLUS) {
6615                varlen = -1 - varlen;
6616                goto vsplus;
6617        }
6618
6619        if (subtype == VSMINUS) {
6620 vsplus:
6621                if (varlen < 0) {
6622                        argstr(
6623                                p, flags | EXP_TILDE |
6624                                        (quoted ? EXP_QWORD : EXP_WORD),
6625                                var_str_list
6626                        );
6627                        goto end;
6628                }
6629                if (easy)
6630                        goto record;
6631                goto end;
6632        }
6633
6634        if (subtype == VSASSIGN || subtype == VSQUESTION) {
6635                if (varlen < 0) {
6636                        if (subevalvar(p, var, /* strloc: */ 0,
6637                                        subtype, startloc, varflags,
6638                                        /* quotes: */ 0,
6639                                        var_str_list)
6640                        ) {
6641                                varflags &= ~VSNUL;
6642                                /*
6643                                 * Remove any recorded regions beyond
6644                                 * start of variable
6645                                 */
6646                                removerecordregions(startloc);
6647                                goto again;
6648                        }
6649                        goto end;
6650                }
6651                if (easy)
6652                        goto record;
6653                goto end;
6654        }
6655
6656        if (varlen < 0 && uflag)
6657                varunset(p, var, 0, 0);
6658
6659        if (subtype == VSLENGTH) {
6660                cvtnum(varlen > 0 ? varlen : 0);
6661                goto record;
6662        }
6663
6664        if (subtype == VSNORMAL) {
6665                if (easy)
6666                        goto record;
6667                goto end;
6668        }
6669
6670#if DEBUG
6671        switch (subtype) {
6672        case VSTRIMLEFT:
6673        case VSTRIMLEFTMAX:
6674        case VSTRIMRIGHT:
6675        case VSTRIMRIGHTMAX:
6676#if ENABLE_ASH_BASH_COMPAT
6677        case VSSUBSTR:
6678        case VSREPLACE:
6679        case VSREPLACEALL:
6680#endif
6681                break;
6682        default:
6683                abort();
6684        }
6685#endif
6686
6687        if (varlen >= 0) {
6688                /*
6689                 * Terminate the string and start recording the pattern
6690                 * right after it
6691                 */
6692                STPUTC('\0', expdest);
6693                patloc = expdest - (char *)stackblock();
6694                if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype,
6695                                startloc, varflags,
6696//TODO: | EXP_REDIR too? All other such places do it too
6697                                /* quotes: */ flags & (EXP_FULL | EXP_CASE),
6698                                var_str_list)
6699                ) {
6700                        int amount = expdest - (
6701                                (char *)stackblock() + patloc - 1
6702                        );
6703                        STADJUST(-amount, expdest);
6704                }
6705                /* Remove any recorded regions beyond start of variable */
6706                removerecordregions(startloc);
6707 record:
6708                recordregion(startloc, expdest - (char *)stackblock(), quoted);
6709        }
6710
6711 end:
6712        if (subtype != VSNORMAL) {      /* skip to end of alternative */
6713                int nesting = 1;
6714                for (;;) {
6715                        unsigned char c = *p++;
6716                        if (c == CTLESC)
6717                                p++;
6718                        else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6719                                if (varlen >= 0)
6720                                        argbackq = argbackq->next;
6721                        } else if (c == CTLVAR) {
6722                                if ((*p++ & VSTYPE) != VSNORMAL)
6723                                        nesting++;
6724                        } else if (c == CTLENDVAR) {
6725                                if (--nesting == 0)
6726                                        break;
6727                        }
6728                }
6729        }
6730        return p;
6731}
6732
6733/*
6734 * Break the argument string into pieces based upon IFS and add the
6735 * strings to the argument list.  The regions of the string to be
6736 * searched for IFS characters have been stored by recordregion.
6737 */
6738static void
6739ifsbreakup(char *string, struct arglist *arglist)
6740{
6741        struct ifsregion *ifsp;
6742        struct strlist *sp;
6743        char *start;
6744        char *p;
6745        char *q;
6746        const char *ifs, *realifs;
6747        int ifsspc;
6748        int nulonly;
6749
6750        start = string;
6751        if (ifslastp != NULL) {
6752                ifsspc = 0;
6753                nulonly = 0;
6754                realifs = ifsset() ? ifsval() : defifs;
6755                ifsp = &ifsfirst;
6756                do {
6757                        p = string + ifsp->begoff;
6758                        nulonly = ifsp->nulonly;
6759                        ifs = nulonly ? nullstr : realifs;
6760                        ifsspc = 0;
6761                        while (p < string + ifsp->endoff) {
6762                                q = p;
6763                                if ((unsigned char)*p == CTLESC)
6764                                        p++;
6765                                if (!strchr(ifs, *p)) {
6766                                        p++;
6767                                        continue;
6768                                }
6769                                if (!nulonly)
6770                                        ifsspc = (strchr(defifs, *p) != NULL);
6771                                /* Ignore IFS whitespace at start */
6772                                if (q == start && ifsspc) {
6773                                        p++;
6774                                        start = p;
6775                                        continue;
6776                                }
6777                                *q = '\0';
6778                                sp = stzalloc(sizeof(*sp));
6779                                sp->text = start;
6780                                *arglist->lastp = sp;
6781                                arglist->lastp = &sp->next;
6782                                p++;
6783                                if (!nulonly) {
6784                                        for (;;) {
6785                                                if (p >= string + ifsp->endoff) {
6786                                                        break;
6787                                                }
6788                                                q = p;
6789                                                if ((unsigned char)*p == CTLESC)
6790                                                        p++;
6791                                                if (strchr(ifs, *p) == NULL) {
6792                                                        p = q;
6793                                                        break;
6794                                                }
6795                                                if (strchr(defifs, *p) == NULL) {
6796                                                        if (ifsspc) {
6797                                                                p++;
6798                                                                ifsspc = 0;
6799                                                        } else {
6800                                                                p = q;
6801                                                                break;
6802                                                        }
6803                                                } else
6804                                                        p++;
6805                                        }
6806                                }
6807                                start = p;
6808                        } /* while */
6809                        ifsp = ifsp->next;
6810                } while (ifsp != NULL);
6811                if (nulonly)
6812                        goto add;
6813        }
6814
6815        if (!*start)
6816                return;
6817
6818 add:
6819        sp = stzalloc(sizeof(*sp));
6820        sp->text = start;
6821        *arglist->lastp = sp;
6822        arglist->lastp = &sp->next;
6823}
6824
6825static void
6826ifsfree(void)
6827{
6828        struct ifsregion *p;
6829
6830        INT_OFF;
6831        p = ifsfirst.next;
6832        do {
6833                struct ifsregion *ifsp;
6834                ifsp = p->next;
6835                free(p);
6836                p = ifsp;
6837        } while (p);
6838        ifslastp = NULL;
6839        ifsfirst.next = NULL;
6840        INT_ON;
6841}
6842
6843/*
6844 * Add a file name to the list.
6845 */
6846static void
6847addfname(const char *name)
6848{
6849        struct strlist *sp;
6850
6851        sp = stzalloc(sizeof(*sp));
6852        sp->text = ststrdup(name);
6853        *exparg.lastp = sp;
6854        exparg.lastp = &sp->next;
6855}
6856
6857/*
6858 * Do metacharacter (i.e. *, ?, [...]) expansion.
6859 */
6860static void
6861expmeta(char *expdir, char *enddir, char *name)
6862{
6863        char *p;
6864        const char *cp;
6865        char *start;
6866        char *endname;
6867        int metaflag;
6868        struct stat statb;
6869        DIR *dirp;
6870        struct dirent *dp;
6871        int atend;
6872        int matchdot;
6873
6874        metaflag = 0;
6875        start = name;
6876        for (p = name; *p; p++) {
6877                if (*p == '*' || *p == '?')
6878                        metaflag = 1;
6879                else if (*p == '[') {
6880                        char *q = p + 1;
6881                        if (*q == '!')
6882                                q++;
6883                        for (;;) {
6884                                if (*q == '\\')
6885                                        q++;
6886                                if (*q == '/' || *q == '\0')
6887                                        break;
6888                                if (*++q == ']') {
6889                                        metaflag = 1;
6890                                        break;
6891                                }
6892                        }
6893                } else if (*p == '\\')
6894                        p++;
6895                else if (*p == '/') {
6896                        if (metaflag)
6897                                goto out;
6898                        start = p + 1;
6899                }
6900        }
6901 out:
6902        if (metaflag == 0) {    /* we've reached the end of the file name */
6903                if (enddir != expdir)
6904                        metaflag++;
6905                p = name;
6906                do {
6907                        if (*p == '\\')
6908                                p++;
6909                        *enddir++ = *p;
6910                } while (*p++);
6911                if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6912                        addfname(expdir);
6913                return;
6914        }
6915        endname = p;
6916        if (name < start) {
6917                p = name;
6918                do {
6919                        if (*p == '\\')
6920                                p++;
6921                        *enddir++ = *p++;
6922                } while (p < start);
6923        }
6924        if (enddir == expdir) {
6925                cp = ".";
6926        } else if (enddir == expdir + 1 && *expdir == '/') {
6927                cp = "/";
6928        } else {
6929                cp = expdir;
6930                enddir[-1] = '\0';
6931        }
6932        dirp = opendir(cp);
6933        if (dirp == NULL)
6934                return;
6935        if (enddir != expdir)
6936                enddir[-1] = '/';
6937        if (*endname == 0) {
6938                atend = 1;
6939        } else {
6940                atend = 0;
6941                *endname++ = '\0';
6942        }
6943        matchdot = 0;
6944        p = start;
6945        if (*p == '\\')
6946                p++;
6947        if (*p == '.')
6948                matchdot++;
6949        while (!pending_int && (dp = readdir(dirp)) != NULL) {
6950                if (dp->d_name[0] == '.' && !matchdot)
6951                        continue;
6952                if (pmatch(start, dp->d_name)) {
6953                        if (atend) {
6954                                strcpy(enddir, dp->d_name);
6955                                addfname(expdir);
6956                        } else {
6957                                for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6958                                        continue;
6959                                p[-1] = '/';
6960                                expmeta(expdir, p, endname);
6961                        }
6962                }
6963        }
6964        closedir(dirp);
6965        if (!atend)
6966                endname[-1] = '/';
6967}
6968
6969static struct strlist *
6970msort(struct strlist *list, int len)
6971{
6972        struct strlist *p, *q = NULL;
6973        struct strlist **lpp;
6974        int half;
6975        int n;
6976
6977        if (len <= 1)
6978                return list;
6979        half = len >> 1;
6980        p = list;
6981        for (n = half; --n >= 0;) {
6982                q = p;
6983                p = p->next;
6984        }
6985        q->next = NULL;                 /* terminate first half of list */
6986        q = msort(list, half);          /* sort first half of list */
6987        p = msort(p, len - half);               /* sort second half */
6988        lpp = &list;
6989        for (;;) {
6990#if ENABLE_LOCALE_SUPPORT
6991                if (strcoll(p->text, q->text) < 0)
6992#else
6993                if (strcmp(p->text, q->text) < 0)
6994#endif
6995                                                {
6996                        *lpp = p;
6997                        lpp = &p->next;
6998                        p = *lpp;
6999                        if (p == NULL) {
7000                                *lpp = q;
7001                                break;
7002                        }
7003                } else {
7004                        *lpp = q;
7005                        lpp = &q->next;
7006                        q = *lpp;
7007                        if (q == NULL) {
7008                                *lpp = p;
7009                                break;
7010                        }
7011                }
7012        }
7013        return list;
7014}
7015
7016/*
7017 * Sort the results of file name expansion.  It calculates the number of
7018 * strings to sort and then calls msort (short for merge sort) to do the
7019 * work.
7020 */
7021static struct strlist *
7022expsort(struct strlist *str)
7023{
7024        int len;
7025        struct strlist *sp;
7026
7027        len = 0;
7028        for (sp = str; sp; sp = sp->next)
7029                len++;
7030        return msort(str, len);
7031}
7032
7033static void
7034expandmeta(struct strlist *str /*, int flag*/)
7035{
7036        static const char metachars[] ALIGN1 = {
7037                '*', '?', '[', 0
7038        };
7039        /* TODO - EXP_REDIR */
7040
7041        while (str) {
7042                char *expdir;
7043                struct strlist **savelastp;
7044                struct strlist *sp;
7045                char *p;
7046
7047                if (fflag)
7048                        goto nometa;
7049                if (!strpbrk(str->text, metachars))
7050                        goto nometa;
7051                savelastp = exparg.lastp;
7052
7053                INT_OFF;
7054                p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7055                {
7056                        int i = strlen(str->text);
7057                        expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7058                }
7059                expmeta(expdir, expdir, p);
7060                free(expdir);
7061                if (p != str->text)
7062                        free(p);
7063                INT_ON;
7064                if (exparg.lastp == savelastp) {
7065                        /*
7066                         * no matches
7067                         */
7068 nometa:
7069                        *exparg.lastp = str;
7070                        rmescapes(str->text, 0);
7071                        exparg.lastp = &str->next;
7072                } else {
7073                        *exparg.lastp = NULL;
7074                        *savelastp = sp = expsort(*savelastp);
7075                        while (sp->next != NULL)
7076                                sp = sp->next;
7077                        exparg.lastp = &sp->next;
7078                }
7079                str = str->next;
7080        }
7081}
7082
7083/*
7084 * Perform variable substitution and command substitution on an argument,
7085 * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
7086 * perform splitting and file name expansion.  When arglist is NULL, perform
7087 * here document expansion.
7088 */
7089static void
7090expandarg(union node *arg, struct arglist *arglist, int flag)
7091{
7092        struct strlist *sp;
7093        char *p;
7094
7095        argbackq = arg->narg.backquote;
7096        STARTSTACKSTR(expdest);
7097        ifsfirst.next = NULL;
7098        ifslastp = NULL;
7099        argstr(arg->narg.text, flag,
7100                        /* var_str_list: */ arglist ? arglist->list : NULL);
7101        p = _STPUTC('\0', expdest);
7102        expdest = p - 1;
7103        if (arglist == NULL) {
7104                return;                 /* here document expanded */
7105        }
7106        p = grabstackstr(p);
7107        exparg.lastp = &exparg.list;
7108        /*
7109         * TODO - EXP_REDIR
7110         */
7111        if (flag & EXP_FULL) {
7112                ifsbreakup(p, &exparg);
7113                *exparg.lastp = NULL;
7114                exparg.lastp = &exparg.list;
7115                expandmeta(exparg.list /*, flag*/);
7116        } else {
7117                if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
7118                        rmescapes(p, 0);
7119                sp = stzalloc(sizeof(*sp));
7120                sp->text = p;
7121                *exparg.lastp = sp;
7122                exparg.lastp = &sp->next;
7123        }
7124        if (ifsfirst.next)
7125                ifsfree();
7126        *exparg.lastp = NULL;
7127        if (exparg.list) {
7128                *arglist->lastp = exparg.list;
7129                arglist->lastp = exparg.lastp;
7130        }
7131}
7132
7133/*
7134 * Expand shell variables and backquotes inside a here document.
7135 */
7136static void
7137expandhere(union node *arg, int fd)
7138{
7139        herefd = fd;
7140        expandarg(arg, (struct arglist *)NULL, 0);
7141        full_write(fd, stackblock(), expdest - (char *)stackblock());
7142}
7143
7144/*
7145 * Returns true if the pattern matches the string.
7146 */
7147static int
7148patmatch(char *pattern, const char *string)
7149{
7150        return pmatch(preglob(pattern, 0, 0), string);
7151}
7152
7153/*
7154 * See if a pattern matches in a case statement.
7155 */
7156static int
7157casematch(union node *pattern, char *val)
7158{
7159        struct stackmark smark;
7160        int result;
7161
7162        setstackmark(&smark);
7163        argbackq = pattern->narg.backquote;
7164        STARTSTACKSTR(expdest);
7165        ifslastp = NULL;
7166        argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7167                        /* var_str_list: */ NULL);
7168        STACKSTRNUL(expdest);
7169        result = patmatch(stackblock(), val);
7170        popstackmark(&smark);
7171        return result;
7172}
7173
7174
7175/* ============ find_command */
7176
7177struct builtincmd {
7178        const char *name;
7179        int (*builtin)(int, char **) FAST_FUNC;
7180        /* unsigned flags; */
7181};
7182#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7183/* "regular" builtins always take precedence over commands,
7184 * regardless of PATH=....%builtin... position */
7185#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7186#define IS_BUILTIN_ASSIGN(b)  ((b)->name[0] & 4)
7187
7188struct cmdentry {
7189        smallint cmdtype;       /* CMDxxx */
7190        union param {
7191                int index;
7192                /* index >= 0 for commands without path (slashes) */
7193                /* (TODO: what exactly does the value mean? PATH position?) */
7194                /* index == -1 for commands with slashes */
7195                /* index == (-2 - applet_no) for NOFORK applets */
7196                const struct builtincmd *cmd;
7197                struct funcnode *func;
7198        } u;
7199};
7200/* values of cmdtype */
7201#define CMDUNKNOWN      -1      /* no entry in table for command */
7202#define CMDNORMAL       0       /* command is an executable program */
7203#define CMDFUNCTION     1       /* command is a shell function */
7204#define CMDBUILTIN      2       /* command is a shell builtin */
7205
7206/* action to find_command() */
7207#define DO_ERR          0x01    /* prints errors */
7208#define DO_ABS          0x02    /* checks absolute paths */
7209#define DO_NOFUNC       0x04    /* don't return shell functions, for command */
7210#define DO_ALTPATH      0x08    /* using alternate path */
7211#define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
7212
7213static void find_command(char *, struct cmdentry *, int, const char *);
7214
7215
7216/* ============ Hashing commands */
7217
7218/*
7219 * When commands are first encountered, they are entered in a hash table.
7220 * This ensures that a full path search will not have to be done for them
7221 * on each invocation.
7222 *
7223 * We should investigate converting to a linear search, even though that
7224 * would make the command name "hash" a misnomer.
7225 */
7226
7227struct tblentry {
7228        struct tblentry *next;  /* next entry in hash chain */
7229        union param param;      /* definition of builtin function */
7230        smallint cmdtype;       /* CMDxxx */
7231        char rehash;            /* if set, cd done since entry created */
7232        char cmdname[1];        /* name of command */
7233};
7234
7235static struct tblentry **cmdtable;
7236#define INIT_G_cmdtable() do { \
7237        cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7238} while (0)
7239
7240static int builtinloc = -1;     /* index in path of %builtin, or -1 */
7241
7242
7243static void
7244tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7245{
7246        int repeated = 0;
7247
7248#if ENABLE_FEATURE_SH_STANDALONE
7249        if (applet_no >= 0) {
7250                if (APPLET_IS_NOEXEC(applet_no)) {
7251                        clearenv();
7252                        while (*envp)
7253                                putenv(*envp++);
7254                        run_applet_no_and_exit(applet_no, argv);
7255                }
7256                /* re-exec ourselves with the new arguments */
7257                execve(bb_busybox_exec_path, argv, envp);
7258                /* If they called chroot or otherwise made the binary no longer
7259                 * executable, fall through */
7260        }
7261#endif
7262
7263 repeat:
7264#ifdef SYSV
7265        do {
7266                execve(cmd, argv, envp);
7267        } while (errno == EINTR);
7268#else
7269        execve(cmd, argv, envp);
7270#endif
7271        if (repeated) {
7272                free(argv);
7273                return;
7274        }
7275        if (errno == ENOEXEC) {
7276                char **ap;
7277                char **new;
7278
7279                for (ap = argv; *ap; ap++)
7280                        continue;
7281                ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
7282                ap[1] = cmd;
7283                ap[0] = cmd = (char *)DEFAULT_SHELL;
7284                ap += 2;
7285                argv++;
7286                while ((*ap++ = *argv++) != NULL)
7287                        continue;
7288                argv = new;
7289                repeated++;
7290                goto repeat;
7291        }
7292}
7293
7294/*
7295 * Exec a program.  Never returns.  If you change this routine, you may
7296 * have to change the find_command routine as well.
7297 */
7298static void shellexec(char **, const char *, int) NORETURN;
7299static void
7300shellexec(char **argv, const char *path, int idx)
7301{
7302        char *cmdname;
7303        int e;
7304        char **envp;
7305        int exerrno;
7306#if ENABLE_FEATURE_SH_STANDALONE
7307        int applet_no = -1;
7308#endif
7309
7310        clearredir(/*drop:*/ 1);
7311        envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7312        if (strchr(argv[0], '/') != NULL
7313#if ENABLE_FEATURE_SH_STANDALONE
7314         || (applet_no = find_applet_by_name(argv[0])) >= 0
7315#endif
7316        ) {
7317                tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7318                e = errno;
7319        } else {
7320                e = ENOENT;
7321                while ((cmdname = path_advance(&path, argv[0])) != NULL) {
7322                        if (--idx < 0 && pathopt == NULL) {
7323                                tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7324                                if (errno != ENOENT && errno != ENOTDIR)
7325                                        e = errno;
7326                        }
7327                        stunalloc(cmdname);
7328                }
7329        }
7330
7331        /* Map to POSIX errors */
7332        switch (e) {
7333        case EACCES:
7334                exerrno = 126;
7335                break;
7336        case ENOENT:
7337                exerrno = 127;
7338                break;
7339        default:
7340                exerrno = 2;
7341                break;
7342        }
7343        exitstatus = exerrno;
7344        TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7345                argv[0], e, suppress_int));
7346        ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7347        /* NOTREACHED */
7348}
7349
7350static void
7351printentry(struct tblentry *cmdp)
7352{
7353        int idx;
7354        const char *path;
7355        char *name;
7356
7357        idx = cmdp->param.index;
7358        path = pathval();
7359        do {
7360                name = path_advance(&path, cmdp->cmdname);
7361                stunalloc(name);
7362        } while (--idx >= 0);
7363        out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7364}
7365
7366/*
7367 * Clear out command entries.  The argument specifies the first entry in
7368 * PATH which has changed.
7369 */
7370static void
7371clearcmdentry(int firstchange)
7372{
7373        struct tblentry **tblp;
7374        struct tblentry **pp;
7375        struct tblentry *cmdp;
7376
7377        INT_OFF;
7378        for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7379                pp = tblp;
7380                while ((cmdp = *pp) != NULL) {
7381                        if ((cmdp->cmdtype == CMDNORMAL &&
7382                             cmdp->param.index >= firstchange)
7383                         || (cmdp->cmdtype == CMDBUILTIN &&
7384                             builtinloc >= firstchange)
7385                        ) {
7386                                *pp = cmdp->next;
7387                                free(cmdp);
7388                        } else {
7389                                pp = &cmdp->next;
7390                        }
7391                }
7392        }
7393        INT_ON;
7394}
7395
7396/*
7397 * Locate a command in the command hash table.  If "add" is nonzero,
7398 * add the command to the table if it is not already present.  The
7399 * variable "lastcmdentry" is set to point to the address of the link
7400 * pointing to the entry, so that delete_cmd_entry can delete the
7401 * entry.
7402 *
7403 * Interrupts must be off if called with add != 0.
7404 */
7405static struct tblentry **lastcmdentry;
7406
7407static struct tblentry *
7408cmdlookup(const char *name, int add)
7409{
7410        unsigned int hashval;
7411        const char *p;
7412        struct tblentry *cmdp;
7413        struct tblentry **pp;
7414
7415        p = name;
7416        hashval = (unsigned char)*p << 4;
7417        while (*p)
7418                hashval += (unsigned char)*p++;
7419        hashval &= 0x7FFF;
7420        pp = &cmdtable[hashval % CMDTABLESIZE];
7421        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7422                if (strcmp(cmdp->cmdname, name) == 0)
7423                        break;
7424                pp = &cmdp->next;
7425        }
7426        if (add && cmdp == NULL) {
7427                cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7428                                + strlen(name)
7429                                /* + 1 - already done because
7430                                 * tblentry::cmdname is char[1] */);
7431                /*cmdp->next = NULL; - ckzalloc did it */
7432                cmdp->cmdtype = CMDUNKNOWN;
7433                strcpy(cmdp->cmdname, name);
7434        }
7435        lastcmdentry = pp;
7436        return cmdp;
7437}
7438
7439/*
7440 * Delete the command entry returned on the last lookup.
7441 */
7442static void
7443delete_cmd_entry(void)
7444{
7445        struct tblentry *cmdp;
7446
7447        INT_OFF;
7448        cmdp = *lastcmdentry;
7449        *lastcmdentry = cmdp->next;
7450        if (cmdp->cmdtype == CMDFUNCTION)
7451                freefunc(cmdp->param.func);
7452        free(cmdp);
7453        INT_ON;
7454}
7455
7456/*
7457 * Add a new command entry, replacing any existing command entry for
7458 * the same name - except special builtins.
7459 */
7460static void
7461addcmdentry(char *name, struct cmdentry *entry)
7462{
7463        struct tblentry *cmdp;
7464
7465        cmdp = cmdlookup(name, 1);
7466        if (cmdp->cmdtype == CMDFUNCTION) {
7467                freefunc(cmdp->param.func);
7468        }
7469        cmdp->cmdtype = entry->cmdtype;
7470        cmdp->param = entry->u;
7471        cmdp->rehash = 0;
7472}
7473
7474static int FAST_FUNC
7475hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7476{
7477        struct tblentry **pp;
7478        struct tblentry *cmdp;
7479        int c;
7480        struct cmdentry entry;
7481        char *name;
7482
7483        if (nextopt("r") != '\0') {
7484                clearcmdentry(0);
7485                return 0;
7486        }
7487
7488        if (*argptr == NULL) {
7489                for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7490                        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7491                                if (cmdp->cmdtype == CMDNORMAL)
7492                                        printentry(cmdp);
7493                        }
7494                }
7495                return 0;
7496        }
7497
7498        c = 0;
7499        while ((name = *argptr) != NULL) {
7500                cmdp = cmdlookup(name, 0);
7501                if (cmdp != NULL
7502                 && (cmdp->cmdtype == CMDNORMAL
7503                     || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7504                ) {
7505                        delete_cmd_entry();
7506                }
7507                find_command(name, &entry, DO_ERR, pathval());
7508                if (entry.cmdtype == CMDUNKNOWN)
7509                        c = 1;
7510                argptr++;
7511        }
7512        return c;
7513}
7514
7515/*
7516 * Called when a cd is done.  Marks all commands so the next time they
7517 * are executed they will be rehashed.
7518 */
7519static void
7520hashcd(void)
7521{
7522        struct tblentry **pp;
7523        struct tblentry *cmdp;
7524
7525        for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7526                for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7527                        if (cmdp->cmdtype == CMDNORMAL
7528                         || (cmdp->cmdtype == CMDBUILTIN
7529                             && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7530                             && builtinloc > 0)
7531                        ) {
7532                                cmdp->rehash = 1;
7533                        }
7534                }
7535        }
7536}
7537
7538/*
7539 * Fix command hash table when PATH changed.
7540 * Called before PATH is changed.  The argument is the new value of PATH;
7541 * pathval() still returns the old value at this point.
7542 * Called with interrupts off.
7543 */
7544static void FAST_FUNC
7545changepath(const char *new)
7546{
7547        const char *old;
7548        int firstchange;
7549        int idx;
7550        int idx_bltin;
7551
7552        old = pathval();
7553        firstchange = 9999;     /* assume no change */
7554        idx = 0;
7555        idx_bltin = -1;
7556        for (;;) {
7557                if (*old != *new) {
7558                        firstchange = idx;
7559                        if ((*old == '\0' && *new == ':')
7560                         || (*old == ':' && *new == '\0')
7561                        ) {
7562                                firstchange++;
7563                        }
7564                        old = new;      /* ignore subsequent differences */
7565                }
7566                if (*new == '\0')
7567                        break;
7568                if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7569                        idx_bltin = idx;
7570                if (*new == ':')
7571                        idx++;
7572                new++;
7573                old++;
7574        }
7575        if (builtinloc < 0 && idx_bltin >= 0)
7576                builtinloc = idx_bltin;             /* zap builtins */
7577        if (builtinloc >= 0 && idx_bltin < 0)
7578                firstchange = 0;
7579        clearcmdentry(firstchange);
7580        builtinloc = idx_bltin;
7581}
7582
7583#define TEOF 0
7584#define TNL 1
7585#define TREDIR 2
7586#define TWORD 3
7587#define TSEMI 4
7588#define TBACKGND 5
7589#define TAND 6
7590#define TOR 7
7591#define TPIPE 8
7592#define TLP 9
7593#define TRP 10
7594#define TENDCASE 11
7595#define TENDBQUOTE 12
7596#define TNOT 13
7597#define TCASE 14
7598#define TDO 15
7599#define TDONE 16
7600#define TELIF 17
7601#define TELSE 18
7602#define TESAC 19
7603#define TFI 20
7604#define TFOR 21
7605#define TIF 22
7606#define TIN 23
7607#define TTHEN 24
7608#define TUNTIL 25
7609#define TWHILE 26
7610#define TBEGIN 27
7611#define TEND 28
7612typedef smallint token_id_t;
7613
7614/* first char is indicating which tokens mark the end of a list */
7615static const char *const tokname_array[] = {
7616        "\1end of file",
7617        "\0newline",
7618        "\0redirection",
7619        "\0word",
7620        "\0;",
7621        "\0&",
7622        "\0&&",
7623        "\0||",
7624        "\0|",
7625        "\0(",
7626        "\1)",
7627        "\1;;",
7628        "\1`",
7629#define KWDOFFSET 13
7630        /* the following are keywords */
7631        "\0!",
7632        "\0case",
7633        "\1do",
7634        "\1done",
7635        "\1elif",
7636        "\1else",
7637        "\1esac",
7638        "\1fi",
7639        "\0for",
7640        "\0if",
7641        "\0in",
7642        "\1then",
7643        "\0until",
7644        "\0while",
7645        "\0{",
7646        "\1}",
7647};
7648
7649/* Wrapper around strcmp for qsort/bsearch/... */
7650static int
7651pstrcmp(const void *a, const void *b)
7652{
7653        return strcmp((char*) a, (*(char**) b) + 1);
7654}
7655
7656static const char *const *
7657findkwd(const char *s)
7658{
7659        return bsearch(s, tokname_array + KWDOFFSET,
7660                        ARRAY_SIZE(tokname_array) - KWDOFFSET,
7661                        sizeof(tokname_array[0]), pstrcmp);
7662}
7663
7664/*
7665 * Locate and print what a word is...
7666 */
7667static int
7668describe_command(char *command, int describe_command_verbose)
7669{
7670        struct cmdentry entry;
7671        struct tblentry *cmdp;
7672#if ENABLE_ASH_ALIAS
7673        const struct alias *ap;
7674#endif
7675        const char *path = pathval();
7676
7677        if (describe_command_verbose) {
7678                out1str(command);
7679        }
7680
7681        /* First look at the keywords */
7682        if (findkwd(command)) {
7683                out1str(describe_command_verbose ? " is a shell keyword" : command);
7684                goto out;
7685        }
7686
7687#if ENABLE_ASH_ALIAS
7688        /* Then look at the aliases */
7689        ap = lookupalias(command, 0);
7690        if (ap != NULL) {
7691                if (!describe_command_verbose) {
7692                        out1str("alias ");
7693                        printalias(ap);
7694                        return 0;
7695                }
7696                out1fmt(" is an alias for %s", ap->val);
7697                goto out;
7698        }
7699#endif
7700        /* Then check if it is a tracked alias */
7701        cmdp = cmdlookup(command, 0);
7702        if (cmdp != NULL) {
7703                entry.cmdtype = cmdp->cmdtype;
7704                entry.u = cmdp->param;
7705        } else {
7706                /* Finally use brute force */
7707                find_command(command, &entry, DO_ABS, path);
7708        }
7709
7710        switch (entry.cmdtype) {
7711        case CMDNORMAL: {
7712                int j = entry.u.index;
7713                char *p;
7714                if (j < 0) {
7715                        p = command;
7716                } else {
7717                        do {
7718                                p = path_advance(&path, command);
7719                                stunalloc(p);
7720                        } while (--j >= 0);
7721                }
7722                if (describe_command_verbose) {
7723                        out1fmt(" is%s %s",
7724                                (cmdp ? " a tracked alias for" : nullstr), p
7725                        );
7726                } else {
7727                        out1str(p);
7728                }
7729                break;
7730        }
7731
7732        case CMDFUNCTION:
7733                if (describe_command_verbose) {
7734                        out1str(" is a shell function");
7735                } else {
7736                        out1str(command);
7737                }
7738                break;
7739
7740        case CMDBUILTIN:
7741                if (describe_command_verbose) {
7742                        out1fmt(" is a %sshell builtin",
7743                                IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7744                                        "special " : nullstr
7745                        );
7746                } else {
7747                        out1str(command);
7748                }
7749                break;
7750
7751        default:
7752                if (describe_command_verbose) {
7753                        out1str(": not found\n");
7754                }
7755                return 127;
7756        }
7757 out:
7758        out1str("\n");
7759        return 0;
7760}
7761
7762static int FAST_FUNC
7763typecmd(int argc UNUSED_PARAM, char **argv)
7764{
7765        int i = 1;
7766        int err = 0;
7767        int verbose = 1;
7768
7769        /* type -p ... ? (we don't bother checking for 'p') */
7770        if (argv[1] && argv[1][0] == '-') {
7771                i++;
7772                verbose = 0;
7773        }
7774        while (argv[i]) {
7775                err |= describe_command(argv[i++], verbose);
7776        }
7777        return err;
7778}
7779
7780#if ENABLE_ASH_CMDCMD
7781static int FAST_FUNC
7782commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7783{
7784        int c;
7785        enum {
7786                VERIFY_BRIEF = 1,
7787                VERIFY_VERBOSE = 2,
7788        } verify = 0;
7789
7790        while ((c = nextopt("pvV")) != '\0')
7791                if (c == 'V')
7792                        verify |= VERIFY_VERBOSE;
7793                else if (c == 'v')
7794                        verify |= VERIFY_BRIEF;
7795#if DEBUG
7796                else if (c != 'p')
7797                        abort();
7798#endif
7799        /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7800        if (verify && (*argptr != NULL)) {
7801                return describe_command(*argptr, verify - VERIFY_BRIEF);
7802        }
7803
7804        return 0;
7805}
7806#endif
7807
7808
7809/* ============ eval.c */
7810
7811static int funcblocksize;       /* size of structures in function */
7812static int funcstringsize;      /* size of strings in node */
7813static void *funcblock;         /* block to allocate function from */
7814static char *funcstring;        /* block to allocate strings from */
7815
7816/* flags in argument to evaltree */
7817#define EV_EXIT    01           /* exit after evaluating tree */
7818#define EV_TESTED  02           /* exit status is checked; ignore -e flag */
7819#define EV_BACKCMD 04           /* command executing within back quotes */
7820
7821static const uint8_t nodesize[N_NUMBER] = {
7822        [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
7823        [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
7824        [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
7825        [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7826        [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7827        [NAND     ] = SHELL_ALIGN(sizeof(struct nbinary)),
7828        [NOR      ] = SHELL_ALIGN(sizeof(struct nbinary)),
7829        [NSEMI    ] = SHELL_ALIGN(sizeof(struct nbinary)),
7830        [NIF      ] = SHELL_ALIGN(sizeof(struct nif)),
7831        [NWHILE   ] = SHELL_ALIGN(sizeof(struct nbinary)),
7832        [NUNTIL   ] = SHELL_ALIGN(sizeof(struct nbinary)),
7833        [NFOR     ] = SHELL_ALIGN(sizeof(struct nfor)),
7834        [NCASE    ] = SHELL_ALIGN(sizeof(struct ncase)),
7835        [NCLIST   ] = SHELL_ALIGN(sizeof(struct nclist)),
7836        [NDEFUN   ] = SHELL_ALIGN(sizeof(struct narg)),
7837        [NARG     ] = SHELL_ALIGN(sizeof(struct narg)),
7838        [NTO      ] = SHELL_ALIGN(sizeof(struct nfile)),
7839#if ENABLE_ASH_BASH_COMPAT
7840        [NTO2     ] = SHELL_ALIGN(sizeof(struct nfile)),
7841#endif
7842        [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
7843        [NFROM    ] = SHELL_ALIGN(sizeof(struct nfile)),
7844        [NFROMTO  ] = SHELL_ALIGN(sizeof(struct nfile)),
7845        [NAPPEND  ] = SHELL_ALIGN(sizeof(struct nfile)),
7846        [NTOFD    ] = SHELL_ALIGN(sizeof(struct ndup)),
7847        [NFROMFD  ] = SHELL_ALIGN(sizeof(struct ndup)),
7848        [NHERE    ] = SHELL_ALIGN(sizeof(struct nhere)),
7849        [NXHERE   ] = SHELL_ALIGN(sizeof(struct nhere)),
7850        [NNOT     ] = SHELL_ALIGN(sizeof(struct nnot)),
7851};
7852
7853static void calcsize(union node *n);
7854
7855static void
7856sizenodelist(struct nodelist *lp)
7857{
7858        while (lp) {
7859                funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7860                calcsize(lp->n);
7861                lp = lp->next;
7862        }
7863}
7864
7865static void
7866calcsize(union node *n)
7867{
7868        if (n == NULL)
7869                return;
7870        funcblocksize += nodesize[n->type];
7871        switch (n->type) {
7872        case NCMD:
7873                calcsize(n->ncmd.redirect);
7874                calcsize(n->ncmd.args);
7875                calcsize(n->ncmd.assign);
7876                break;
7877        case NPIPE:
7878                sizenodelist(n->npipe.cmdlist);
7879                break;
7880        case NREDIR:
7881        case NBACKGND:
7882        case NSUBSHELL:
7883                calcsize(n->nredir.redirect);
7884                calcsize(n->nredir.n);
7885                break;
7886        case NAND:
7887        case NOR:
7888        case NSEMI:
7889        case NWHILE:
7890        case NUNTIL:
7891                calcsize(n->nbinary.ch2);
7892                calcsize(n->nbinary.ch1);
7893                break;
7894        case NIF:
7895                calcsize(n->nif.elsepart);
7896                calcsize(n->nif.ifpart);
7897                calcsize(n->nif.test);
7898                break;
7899        case NFOR:
7900                funcstringsize += strlen(n->nfor.var) + 1;
7901                calcsize(n->nfor.body);
7902                calcsize(n->nfor.args);
7903                break;
7904        case NCASE:
7905                calcsize(n->ncase.cases);
7906                calcsize(n->ncase.expr);
7907                break;
7908        case NCLIST:
7909                calcsize(n->nclist.body);
7910                calcsize(n->nclist.pattern);
7911                calcsize(n->nclist.next);
7912                break;
7913        case NDEFUN:
7914        case NARG:
7915                sizenodelist(n->narg.backquote);
7916                funcstringsize += strlen(n->narg.text) + 1;
7917                calcsize(n->narg.next);
7918                break;
7919        case NTO:
7920#if ENABLE_ASH_BASH_COMPAT
7921        case NTO2:
7922#endif
7923        case NCLOBBER:
7924        case NFROM:
7925        case NFROMTO:
7926        case NAPPEND:
7927                calcsize(n->nfile.fname);
7928                calcsize(n->nfile.next);
7929                break;
7930        case NTOFD:
7931        case NFROMFD:
7932                calcsize(n->ndup.vname);
7933                calcsize(n->ndup.next);
7934        break;
7935        case NHERE:
7936        case NXHERE:
7937                calcsize(n->nhere.doc);
7938                calcsize(n->nhere.next);
7939                break;
7940        case NNOT:
7941                calcsize(n->nnot.com);
7942                break;
7943        };
7944}
7945
7946static char *
7947nodeckstrdup(char *s)
7948{
7949        char *rtn = funcstring;
7950
7951        strcpy(funcstring, s);
7952        funcstring += strlen(s) + 1;
7953        return rtn;
7954}
7955
7956static union node *copynode(union node *);
7957
7958static struct nodelist *
7959copynodelist(struct nodelist *lp)
7960{
7961        struct nodelist *start;
7962        struct nodelist **lpp;
7963
7964        lpp = &start;
7965        while (lp) {
7966                *lpp = funcblock;
7967                funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7968                (*lpp)->n = copynode(lp->n);
7969                lp = lp->next;
7970                lpp = &(*lpp)->next;
7971        }
7972        *lpp = NULL;
7973        return start;
7974}
7975
7976static union node *
7977copynode(union node *n)
7978{
7979        union node *new;
7980
7981        if (n == NULL)
7982                return NULL;
7983        new = funcblock;
7984        funcblock = (char *) funcblock + nodesize[n->type];
7985
7986        switch (n->type) {
7987        case NCMD:
7988                new->ncmd.redirect = copynode(n->ncmd.redirect);
7989                new->ncmd.args = copynode(n->ncmd.args);
7990                new->ncmd.assign = copynode(n->ncmd.assign);
7991                break;
7992        case NPIPE:
7993                new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7994                new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
7995                break;
7996        case NREDIR:
7997        case NBACKGND:
7998        case NSUBSHELL:
7999                new->nredir.redirect = copynode(n->nredir.redirect);
8000                new->nredir.n = copynode(n->nredir.n);
8001                break;
8002        case NAND:
8003        case NOR:
8004        case NSEMI:
8005        case NWHILE:
8006        case NUNTIL:
8007                new->nbinary.ch2 = copynode(n->nbinary.ch2);
8008                new->nbinary.ch1 = copynode(n->nbinary.ch1);
8009                break;
8010        case NIF:
8011                new->nif.elsepart = copynode(n->nif.elsepart);
8012                new->nif.ifpart = copynode(n->nif.ifpart);
8013                new->nif.test = copynode(n->nif.test);
8014                break;
8015        case NFOR:
8016                new->nfor.var = nodeckstrdup(n->nfor.var);
8017                new->nfor.body = copynode(n->nfor.body);
8018                new->nfor.args = copynode(n->nfor.args);
8019                break;
8020        case NCASE:
8021                new->ncase.cases = copynode(n->ncase.cases);
8022                new->ncase.expr = copynode(n->ncase.expr);
8023                break;
8024        case NCLIST:
8025                new->nclist.body = copynode(n->nclist.body);
8026                new->nclist.pattern = copynode(n->nclist.pattern);
8027                new->nclist.next = copynode(n->nclist.next);
8028                break;
8029        case NDEFUN:
8030        case NARG:
8031                new->narg.backquote = copynodelist(n->narg.backquote);
8032                new->narg.text = nodeckstrdup(n->narg.text);
8033                new->narg.next = copynode(n->narg.next);
8034                break;
8035        case NTO:
8036#if ENABLE_ASH_BASH_COMPAT
8037        case NTO2:
8038#endif
8039        case NCLOBBER:
8040        case NFROM:
8041        case NFROMTO:
8042        case NAPPEND:
8043                new->nfile.fname = copynode(n->nfile.fname);
8044                new->nfile.fd = n->nfile.fd;
8045                new->nfile.next = copynode(n->nfile.next);
8046                break;
8047        case NTOFD:
8048        case NFROMFD:
8049                new->ndup.vname = copynode(n->ndup.vname);
8050                new->ndup.dupfd = n->ndup.dupfd;
8051                new->ndup.fd = n->ndup.fd;
8052                new->ndup.next = copynode(n->ndup.next);
8053                break;
8054        case NHERE:
8055        case NXHERE:
8056                new->nhere.doc = copynode(n->nhere.doc);
8057                new->nhere.fd = n->nhere.fd;
8058                new->nhere.next = copynode(n->nhere.next);
8059                break;
8060        case NNOT:
8061                new->nnot.com = copynode(n->nnot.com);
8062                break;
8063        };
8064        new->type = n->type;
8065        return new;
8066}
8067
8068/*
8069 * Make a copy of a parse tree.
8070 */
8071static struct funcnode *
8072copyfunc(union node *n)
8073{
8074        struct funcnode *f;
8075        size_t blocksize;
8076
8077        funcblocksize = offsetof(struct funcnode, n);
8078        funcstringsize = 0;
8079        calcsize(n);
8080        blocksize = funcblocksize;
8081        f = ckmalloc(blocksize + funcstringsize);
8082        funcblock = (char *) f + offsetof(struct funcnode, n);
8083        funcstring = (char *) f + blocksize;
8084        copynode(n);
8085        f->count = 0;
8086        return f;
8087}
8088
8089/*
8090 * Define a shell function.
8091 */
8092static void
8093defun(char *name, union node *func)
8094{
8095        struct cmdentry entry;
8096
8097        INT_OFF;
8098        entry.cmdtype = CMDFUNCTION;
8099        entry.u.func = copyfunc(func);
8100        addcmdentry(name, &entry);
8101        INT_ON;
8102}
8103
8104/* Reasons for skipping commands (see comment on breakcmd routine) */
8105#define SKIPBREAK      (1 << 0)
8106#define SKIPCONT       (1 << 1)
8107#define SKIPFUNC       (1 << 2)
8108#define SKIPFILE       (1 << 3)
8109#define SKIPEVAL       (1 << 4)
8110static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
8111static int skipcount;           /* number of levels to skip */
8112static int funcnest;            /* depth of function calls */
8113static int loopnest;            /* current loop nesting level */
8114
8115/* Forward decl way out to parsing code - dotrap needs it */
8116static int evalstring(char *s, int mask);
8117
8118/* Called to execute a trap.
8119 * Single callsite - at the end of evaltree().
8120 * If we return non-zero, exaltree raises EXEXIT exception.
8121 *
8122 * Perhaps we should avoid entering new trap handlers
8123 * while we are executing a trap handler. [is it a TODO?]
8124 */
8125static int
8126dotrap(void)
8127{
8128        uint8_t *g;
8129        int sig;
8130        uint8_t savestatus;
8131
8132        savestatus = exitstatus;
8133        pending_sig = 0;
8134        xbarrier();
8135
8136        TRACE(("dotrap entered\n"));
8137        for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8138                int want_exexit;
8139                char *t;
8140
8141                if (*g == 0)
8142                        continue;
8143                t = trap[sig];
8144                /* non-trapped SIGINT is handled separately by raise_interrupt,
8145                 * don't upset it by resetting gotsig[SIGINT-1] */
8146                if (sig == SIGINT && !t)
8147                        continue;
8148
8149                TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
8150                *g = 0;
8151                if (!t)
8152                        continue;
8153                want_exexit = evalstring(t, SKIPEVAL);
8154                exitstatus = savestatus;
8155                if (want_exexit) {
8156                        TRACE(("dotrap returns %d\n", want_exexit));
8157                        return want_exexit;
8158                }
8159        }
8160
8161        TRACE(("dotrap returns 0\n"));
8162        return 0;
8163}
8164
8165/* forward declarations - evaluation is fairly recursive business... */
8166static void evalloop(union node *, int);
8167static void evalfor(union node *, int);
8168static void evalcase(union node *, int);
8169static void evalsubshell(union node *, int);
8170static void expredir(union node *);
8171static void evalpipe(union node *, int);
8172static void evalcommand(union node *, int);
8173static int evalbltin(const struct builtincmd *, int, char **);
8174static void prehash(union node *);
8175
8176/*
8177 * Evaluate a parse tree.  The value is left in the global variable
8178 * exitstatus.
8179 */
8180static void
8181evaltree(union node *n, int flags)
8182{
8183        struct jmploc *volatile savehandler = exception_handler;
8184        struct jmploc jmploc;
8185        int checkexit = 0;
8186        void (*evalfn)(union node *, int);
8187        int status;
8188        int int_level;
8189
8190        SAVE_INT(int_level);
8191
8192        if (n == NULL) {
8193                TRACE(("evaltree(NULL) called\n"));
8194                goto out1;
8195        }
8196        TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8197
8198        exception_handler = &jmploc;
8199        {
8200                int err = setjmp(jmploc.loc);
8201                if (err) {
8202                        /* if it was a signal, check for trap handlers */
8203                        if (exception_type == EXSIG) {
8204                                TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8205                                                exception_type, err));
8206                                goto out;
8207                        }
8208                        /* continue on the way out */
8209                        TRACE(("exception %d in evaltree, propagating err=%d\n",
8210                                        exception_type, err));
8211                        exception_handler = savehandler;
8212                        longjmp(exception_handler->loc, err);
8213                }
8214        }
8215
8216        switch (n->type) {
8217        default:
8218#if DEBUG
8219                out1fmt("Node type = %d\n", n->type);
8220                fflush_all();
8221                break;
8222#endif
8223        case NNOT:
8224                evaltree(n->nnot.com, EV_TESTED);
8225                status = !exitstatus;
8226                goto setstatus;
8227        case NREDIR:
8228                expredir(n->nredir.redirect);
8229                status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8230                if (!status) {
8231                        evaltree(n->nredir.n, flags & EV_TESTED);
8232                        status = exitstatus;
8233                }
8234                popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8235                goto setstatus;
8236        case NCMD:
8237                evalfn = evalcommand;
8238 checkexit:
8239                if (eflag && !(flags & EV_TESTED))
8240                        checkexit = ~0;
8241                goto calleval;
8242        case NFOR:
8243                evalfn = evalfor;
8244                goto calleval;
8245        case NWHILE:
8246        case NUNTIL:
8247                evalfn = evalloop;
8248                goto calleval;
8249        case NSUBSHELL:
8250        case NBACKGND:
8251                evalfn = evalsubshell;
8252                goto calleval;
8253        case NPIPE:
8254                evalfn = evalpipe;
8255                goto checkexit;
8256        case NCASE:
8257                evalfn = evalcase;
8258                goto calleval;
8259        case NAND:
8260        case NOR:
8261        case NSEMI: {
8262
8263#if NAND + 1 != NOR
8264#error NAND + 1 != NOR
8265#endif
8266#if NOR + 1 != NSEMI
8267#error NOR + 1 != NSEMI
8268#endif
8269                unsigned is_or = n->type - NAND;
8270                evaltree(
8271                        n->nbinary.ch1,
8272                        (flags | ((is_or >> 1) - 1)) & EV_TESTED
8273                );
8274                if (!exitstatus == is_or)
8275                        break;
8276                if (!evalskip) {
8277                        n = n->nbinary.ch2;
8278 evaln:
8279                        evalfn = evaltree;
8280 calleval:
8281                        evalfn(n, flags);
8282                        break;
8283                }
8284                break;
8285        }
8286        case NIF:
8287                evaltree(n->nif.test, EV_TESTED);
8288                if (evalskip)
8289                        break;
8290                if (exitstatus == 0) {
8291                        n = n->nif.ifpart;
8292                        goto evaln;
8293                }
8294                if (n->nif.elsepart) {
8295                        n = n->nif.elsepart;
8296                        goto evaln;
8297                }
8298                goto success;
8299        case NDEFUN:
8300                defun(n->narg.text, n->narg.next);
8301 success:
8302                status = 0;
8303 setstatus:
8304                exitstatus = status;
8305                break;
8306        }
8307
8308 out:
8309        exception_handler = savehandler;
8310 out1:
8311        if (checkexit & exitstatus)
8312                evalskip |= SKIPEVAL;
8313        else if (pending_sig && dotrap())
8314                goto exexit;
8315
8316        if (flags & EV_EXIT) {
8317 exexit:
8318                raise_exception(EXEXIT);
8319        }
8320
8321        RESTORE_INT(int_level);
8322        TRACE(("leaving evaltree (no interrupts)\n"));
8323}
8324
8325#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8326static
8327#endif
8328void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8329
8330static void
8331evalloop(union node *n, int flags)
8332{
8333        int status;
8334
8335        loopnest++;
8336        status = 0;
8337        flags &= EV_TESTED;
8338        for (;;) {
8339                int i;
8340
8341                evaltree(n->nbinary.ch1, EV_TESTED);
8342                if (evalskip) {
8343 skipping:
8344                        if (evalskip == SKIPCONT && --skipcount <= 0) {
8345                                evalskip = 0;
8346                                continue;
8347                        }
8348                        if (evalskip == SKIPBREAK && --skipcount <= 0)
8349                                evalskip = 0;
8350                        break;
8351                }
8352                i = exitstatus;
8353                if (n->type != NWHILE)
8354                        i = !i;
8355                if (i != 0)
8356                        break;
8357                evaltree(n->nbinary.ch2, flags);
8358                status = exitstatus;
8359                if (evalskip)
8360                        goto skipping;
8361        }
8362        loopnest--;
8363        exitstatus = status;
8364}
8365
8366static void
8367evalfor(union node *n, int flags)
8368{
8369        struct arglist arglist;
8370        union node *argp;
8371        struct strlist *sp;
8372        struct stackmark smark;
8373
8374        setstackmark(&smark);
8375        arglist.list = NULL;
8376        arglist.lastp = &arglist.list;
8377        for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8378                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8379                /* XXX */
8380                if (evalskip)
8381                        goto out;
8382        }
8383        *arglist.lastp = NULL;
8384
8385        exitstatus = 0;
8386        loopnest++;
8387        flags &= EV_TESTED;
8388        for (sp = arglist.list; sp; sp = sp->next) {
8389                setvar(n->nfor.var, sp->text, 0);
8390                evaltree(n->nfor.body, flags);
8391                if (evalskip) {
8392                        if (evalskip == SKIPCONT && --skipcount <= 0) {
8393                                evalskip = 0;
8394                                continue;
8395                        }
8396                        if (evalskip == SKIPBREAK && --skipcount <= 0)
8397                                evalskip = 0;
8398                        break;
8399                }
8400        }
8401        loopnest--;
8402 out:
8403        popstackmark(&smark);
8404}
8405
8406static void
8407evalcase(union node *n, int flags)
8408{
8409        union node *cp;
8410        union node *patp;
8411        struct arglist arglist;
8412        struct stackmark smark;
8413
8414        setstackmark(&smark);
8415        arglist.list = NULL;
8416        arglist.lastp = &arglist.list;
8417        expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8418        exitstatus = 0;
8419        for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8420                for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8421                        if (casematch(patp, arglist.list->text)) {
8422                                if (evalskip == 0) {
8423                                        evaltree(cp->nclist.body, flags);
8424                                }
8425                                goto out;
8426                        }
8427                }
8428        }
8429 out:
8430        popstackmark(&smark);
8431}
8432
8433/*
8434 * Kick off a subshell to evaluate a tree.
8435 */
8436static void
8437evalsubshell(union node *n, int flags)
8438{
8439        struct job *jp;
8440        int backgnd = (n->type == NBACKGND);
8441        int status;
8442
8443        expredir(n->nredir.redirect);
8444        if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
8445                goto nofork;
8446        INT_OFF;
8447        jp = makejob(/*n,*/ 1);
8448        if (forkshell(jp, n, backgnd) == 0) {
8449                /* child */
8450                INT_ON;
8451                flags |= EV_EXIT;
8452                if (backgnd)
8453                        flags &= ~EV_TESTED;
8454 nofork:
8455                redirect(n->nredir.redirect, 0);
8456                evaltreenr(n->nredir.n, flags);
8457                /* never returns */
8458        }
8459        status = 0;
8460        if (!backgnd)
8461                status = waitforjob(jp);
8462        exitstatus = status;
8463        INT_ON;
8464}
8465
8466/*
8467 * Compute the names of the files in a redirection list.
8468 */
8469static void fixredir(union node *, const char *, int);
8470static void
8471expredir(union node *n)
8472{
8473        union node *redir;
8474
8475        for (redir = n; redir; redir = redir->nfile.next) {
8476                struct arglist fn;
8477
8478                fn.list = NULL;
8479                fn.lastp = &fn.list;
8480                switch (redir->type) {
8481                case NFROMTO:
8482                case NFROM:
8483                case NTO:
8484#if ENABLE_ASH_BASH_COMPAT
8485                case NTO2:
8486#endif
8487                case NCLOBBER:
8488                case NAPPEND:
8489                        expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8490#if ENABLE_ASH_BASH_COMPAT
8491 store_expfname:
8492#endif
8493                        redir->nfile.expfname = fn.list->text;
8494                        break;
8495                case NFROMFD:
8496                case NTOFD: /* >& */
8497                        if (redir->ndup.vname) {
8498                                expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8499                                if (fn.list == NULL)
8500                                        ash_msg_and_raise_error("redir error");
8501#if ENABLE_ASH_BASH_COMPAT
8502//FIXME: we used expandarg with different args!
8503                                if (!isdigit_str9(fn.list->text)) {
8504                                        /* >&file, not >&fd */
8505                                        if (redir->nfile.fd != 1) /* 123>&file - BAD */
8506                                                ash_msg_and_raise_error("redir error");
8507                                        redir->type = NTO2;
8508                                        goto store_expfname;
8509                                }
8510#endif
8511                                fixredir(redir, fn.list->text, 1);
8512                        }
8513                        break;
8514                }
8515        }
8516}
8517
8518/*
8519 * Evaluate a pipeline.  All the processes in the pipeline are children
8520 * of the process creating the pipeline.  (This differs from some versions
8521 * of the shell, which make the last process in a pipeline the parent
8522 * of all the rest.)
8523 */
8524static void
8525evalpipe(union node *n, int flags)
8526{
8527        struct job *jp;
8528        struct nodelist *lp;
8529        int pipelen;
8530        int prevfd;
8531        int pip[2];
8532
8533        TRACE(("evalpipe(0x%lx) called\n", (long)n));
8534        pipelen = 0;
8535        for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8536                pipelen++;
8537        flags |= EV_EXIT;
8538        INT_OFF;
8539        jp = makejob(/*n,*/ pipelen);
8540        prevfd = -1;
8541        for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8542                prehash(lp->n);
8543                pip[1] = -1;
8544                if (lp->next) {
8545                        if (pipe(pip) < 0) {
8546                                close(prevfd);
8547                                ash_msg_and_raise_error("pipe call failed");
8548                        }
8549                }
8550                if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8551                        INT_ON;
8552                        if (pip[1] >= 0) {
8553                                close(pip[0]);
8554                        }
8555                        if (prevfd > 0) {
8556                                dup2(prevfd, 0);
8557                                close(prevfd);
8558                        }
8559                        if (pip[1] > 1) {
8560                                dup2(pip[1], 1);
8561                                close(pip[1]);
8562                        }
8563                        evaltreenr(lp->n, flags);
8564                        /* never returns */
8565                }
8566                if (prevfd >= 0)
8567                        close(prevfd);
8568                prevfd = pip[0];
8569                /* Don't want to trigger debugging */
8570                if (pip[1] != -1)
8571                        close(pip[1]);
8572        }
8573        if (n->npipe.pipe_backgnd == 0) {
8574                exitstatus = waitforjob(jp);
8575                TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
8576        }
8577        INT_ON;
8578}
8579
8580/*
8581 * Controls whether the shell is interactive or not.
8582 */
8583static void
8584setinteractive(int on)
8585{
8586        static smallint is_interactive;
8587
8588        if (++on == is_interactive)
8589                return;
8590        is_interactive = on;
8591        setsignal(SIGINT);
8592        setsignal(SIGQUIT);
8593        setsignal(SIGTERM);
8594#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8595        if (is_interactive > 1) {
8596                /* Looks like they want an interactive shell */
8597                static smallint did_banner;
8598
8599                if (!did_banner) {
8600                        /* note: ash and hush share this string */
8601                        out1fmt("\n\n%s %s\n"
8602                                "Enter 'help' for a list of built-in commands."
8603                                "\n\n",
8604                                bb_banner,
8605                                "built-in shell (ash)"
8606                        );
8607                        did_banner = 1;
8608                }
8609        }
8610#endif
8611}
8612
8613static void
8614optschanged(void)
8615{
8616#if DEBUG
8617        opentrace();
8618#endif
8619        setinteractive(iflag);
8620        setjobctl(mflag);
8621#if ENABLE_FEATURE_EDITING_VI
8622        if (viflag)
8623                line_input_state->flags |= VI_MODE;
8624        else
8625                line_input_state->flags &= ~VI_MODE;
8626#else
8627        viflag = 0; /* forcibly keep the option off */
8628#endif
8629}
8630
8631static struct localvar *localvars;
8632
8633/*
8634 * Called after a function returns.
8635 * Interrupts must be off.
8636 */
8637static void
8638poplocalvars(void)
8639{
8640        struct localvar *lvp;
8641        struct var *vp;
8642
8643        while ((lvp = localvars) != NULL) {
8644                localvars = lvp->next;
8645                vp = lvp->vp;
8646                TRACE(("poplocalvar %s\n", vp ? vp->text : "-"));
8647                if (vp == NULL) {       /* $- saved */
8648                        memcpy(optlist, lvp->text, sizeof(optlist));
8649                        free((char*)lvp->text);
8650                        optschanged();
8651                } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8652                        unsetvar(vp->var_text);
8653                } else {
8654                        if (vp->var_func)
8655                                vp->var_func(var_end(lvp->text));
8656                        if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8657                                free((char*)vp->var_text);
8658                        vp->flags = lvp->flags;
8659                        vp->var_text = lvp->text;
8660                }
8661                free(lvp);
8662        }
8663}
8664
8665static int
8666evalfun(struct funcnode *func, int argc, char **argv, int flags)
8667{
8668        volatile struct shparam saveparam;
8669        struct localvar *volatile savelocalvars;
8670        struct jmploc *volatile savehandler;
8671        struct jmploc jmploc;
8672        int e;
8673
8674        saveparam = shellparam;
8675        savelocalvars = localvars;
8676        e = setjmp(jmploc.loc);
8677        if (e) {
8678                goto funcdone;
8679        }
8680        INT_OFF;
8681        savehandler = exception_handler;
8682        exception_handler = &jmploc;
8683        localvars = NULL;
8684        shellparam.malloced = 0;
8685        func->count++;
8686        funcnest++;
8687        INT_ON;
8688        shellparam.nparam = argc - 1;
8689        shellparam.p = argv + 1;
8690#if ENABLE_ASH_GETOPTS
8691        shellparam.optind = 1;
8692        shellparam.optoff = -1;
8693#endif
8694        evaltree(&func->n, flags & EV_TESTED);
8695 funcdone:
8696        INT_OFF;
8697        funcnest--;
8698        freefunc(func);
8699        poplocalvars();
8700        localvars = savelocalvars;
8701        freeparam(&shellparam);
8702        shellparam = saveparam;
8703        exception_handler = savehandler;
8704        INT_ON;
8705        evalskip &= ~SKIPFUNC;
8706        return e;
8707}
8708
8709#if ENABLE_ASH_CMDCMD
8710static char **
8711parse_command_args(char **argv, const char **path)
8712{
8713        char *cp, c;
8714
8715        for (;;) {
8716                cp = *++argv;
8717                if (!cp)
8718                        return 0;
8719                if (*cp++ != '-')
8720                        break;
8721                c = *cp++;
8722                if (!c)
8723                        break;
8724                if (c == '-' && !*cp) {
8725                        argv++;
8726                        break;
8727                }
8728                do {
8729                        switch (c) {
8730                        case 'p':
8731                                *path = bb_default_path;
8732                                break;
8733                        default:
8734                                /* run 'typecmd' for other options */
8735                                return 0;
8736                        }
8737                        c = *cp++;
8738                } while (c);
8739        }
8740        return argv;
8741}
8742#endif
8743
8744/*
8745 * Make a variable a local variable.  When a variable is made local, it's
8746 * value and flags are saved in a localvar structure.  The saved values
8747 * will be restored when the shell function returns.  We handle the name
8748 * "-" as a special case.
8749 */
8750static void
8751mklocal(char *name)
8752{
8753        struct localvar *lvp;
8754        struct var **vpp;
8755        struct var *vp;
8756
8757        INT_OFF;
8758        lvp = ckzalloc(sizeof(struct localvar));
8759        if (LONE_DASH(name)) {
8760                char *p;
8761                p = ckmalloc(sizeof(optlist));
8762                lvp->text = memcpy(p, optlist, sizeof(optlist));
8763                vp = NULL;
8764        } else {
8765                char *eq;
8766
8767                vpp = hashvar(name);
8768                vp = *findvar(vpp, name);
8769                eq = strchr(name, '=');
8770                if (vp == NULL) {
8771                        if (eq)
8772                                setvareq(name, VSTRFIXED);
8773                        else
8774                                setvar(name, NULL, VSTRFIXED);
8775                        vp = *vpp;      /* the new variable */
8776                        lvp->flags = VUNSET;
8777                } else {
8778                        lvp->text = vp->var_text;
8779                        lvp->flags = vp->flags;
8780                        vp->flags |= VSTRFIXED|VTEXTFIXED;
8781                        if (eq)
8782                                setvareq(name, 0);
8783                }
8784        }
8785        lvp->vp = vp;
8786        lvp->next = localvars;
8787        localvars = lvp;
8788        INT_ON;
8789}
8790
8791/*
8792 * The "local" command.
8793 */
8794static int FAST_FUNC
8795localcmd(int argc UNUSED_PARAM, char **argv)
8796{
8797        char *name;
8798
8799        argv = argptr;
8800        while ((name = *argv++) != NULL) {
8801                mklocal(name);
8802        }
8803        return 0;
8804}
8805
8806static int FAST_FUNC
8807falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8808{
8809        return 1;
8810}
8811
8812static int FAST_FUNC
8813truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8814{
8815        return 0;
8816}
8817
8818static int FAST_FUNC
8819execcmd(int argc UNUSED_PARAM, char **argv)
8820{
8821        if (argv[1]) {
8822                iflag = 0;              /* exit on error */
8823                mflag = 0;
8824                optschanged();
8825                shellexec(argv + 1, pathval(), 0);
8826        }
8827        return 0;
8828}
8829
8830/*
8831 * The return command.
8832 */
8833static int FAST_FUNC
8834returncmd(int argc UNUSED_PARAM, char **argv)
8835{
8836        /*
8837         * If called outside a function, do what ksh does;
8838         * skip the rest of the file.
8839         */
8840        evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8841        return argv[1] ? number(argv[1]) : exitstatus;
8842}
8843
8844/* Forward declarations for builtintab[] */
8845static int breakcmd(int, char **) FAST_FUNC;
8846static int dotcmd(int, char **) FAST_FUNC;
8847static int evalcmd(int, char **) FAST_FUNC;
8848static int exitcmd(int, char **) FAST_FUNC;
8849static int exportcmd(int, char **) FAST_FUNC;
8850#if ENABLE_ASH_GETOPTS
8851static int getoptscmd(int, char **) FAST_FUNC;
8852#endif
8853#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8854static int helpcmd(int, char **) FAST_FUNC;
8855#endif
8856#if ENABLE_SH_MATH_SUPPORT
8857static int letcmd(int, char **) FAST_FUNC;
8858#endif
8859static int readcmd(int, char **) FAST_FUNC;
8860static int setcmd(int, char **) FAST_FUNC;
8861static int shiftcmd(int, char **) FAST_FUNC;
8862static int timescmd(int, char **) FAST_FUNC;
8863static int trapcmd(int, char **) FAST_FUNC;
8864static int umaskcmd(int, char **) FAST_FUNC;
8865static int unsetcmd(int, char **) FAST_FUNC;
8866static int ulimitcmd(int, char **) FAST_FUNC;
8867
8868#define BUILTIN_NOSPEC          "0"
8869#define BUILTIN_SPECIAL         "1"
8870#define BUILTIN_REGULAR         "2"
8871#define BUILTIN_SPEC_REG        "3"
8872#define BUILTIN_ASSIGN          "4"
8873#define BUILTIN_SPEC_ASSG       "5"
8874#define BUILTIN_REG_ASSG        "6"
8875#define BUILTIN_SPEC_REG_ASSG   "7"
8876
8877/* Stubs for calling non-FAST_FUNC's */
8878#if ENABLE_ASH_BUILTIN_ECHO
8879static int FAST_FUNC echocmd(int argc, char **argv)   { return echo_main(argc, argv); }
8880#endif
8881#if ENABLE_ASH_BUILTIN_PRINTF
8882static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
8883#endif
8884#if ENABLE_ASH_BUILTIN_TEST
8885static int FAST_FUNC testcmd(int argc, char **argv)   { return test_main(argc, argv); }
8886#endif
8887
8888/* Keep these in proper order since it is searched via bsearch() */
8889static const struct builtincmd builtintab[] = {
8890        { BUILTIN_SPEC_REG      "."       , dotcmd     },
8891        { BUILTIN_SPEC_REG      ":"       , truecmd    },
8892#if ENABLE_ASH_BUILTIN_TEST
8893        { BUILTIN_REGULAR       "["       , testcmd    },
8894#if ENABLE_ASH_BASH_COMPAT
8895        { BUILTIN_REGULAR       "[["      , testcmd    },
8896#endif
8897#endif
8898#if ENABLE_ASH_ALIAS
8899        { BUILTIN_REG_ASSG      "alias"   , aliascmd   },
8900#endif
8901#if JOBS
8902        { BUILTIN_REGULAR       "bg"      , fg_bgcmd   },
8903#endif
8904        { BUILTIN_SPEC_REG      "break"   , breakcmd   },
8905        { BUILTIN_REGULAR       "cd"      , cdcmd      },
8906        { BUILTIN_NOSPEC        "chdir"   , cdcmd      },
8907#if ENABLE_ASH_CMDCMD
8908        { BUILTIN_REGULAR       "command" , commandcmd },
8909#endif
8910        { BUILTIN_SPEC_REG      "continue", breakcmd   },
8911#if ENABLE_ASH_BUILTIN_ECHO
8912        { BUILTIN_REGULAR       "echo"    , echocmd    },
8913#endif
8914        { BUILTIN_SPEC_REG      "eval"    , evalcmd    },
8915        { BUILTIN_SPEC_REG      "exec"    , execcmd    },
8916        { BUILTIN_SPEC_REG      "exit"    , exitcmd    },
8917        { BUILTIN_SPEC_REG_ASSG "export"  , exportcmd  },
8918        { BUILTIN_REGULAR       "false"   , falsecmd   },
8919#if JOBS
8920        { BUILTIN_REGULAR       "fg"      , fg_bgcmd   },
8921#endif
8922#if ENABLE_ASH_GETOPTS
8923        { BUILTIN_REGULAR       "getopts" , getoptscmd },
8924#endif
8925        { BUILTIN_NOSPEC        "hash"    , hashcmd    },
8926#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8927        { BUILTIN_NOSPEC        "help"    , helpcmd    },
8928#endif
8929#if JOBS
8930        { BUILTIN_REGULAR       "jobs"    , jobscmd    },
8931        { BUILTIN_REGULAR       "kill"    , killcmd    },
8932#endif
8933#if ENABLE_SH_MATH_SUPPORT
8934        { BUILTIN_NOSPEC        "let"     , letcmd     },
8935#endif
8936        { BUILTIN_ASSIGN        "local"   , localcmd   },
8937#if ENABLE_ASH_BUILTIN_PRINTF
8938        { BUILTIN_REGULAR       "printf"  , printfcmd  },
8939#endif
8940        { BUILTIN_NOSPEC        "pwd"     , pwdcmd     },
8941        { BUILTIN_REGULAR       "read"    , readcmd    },
8942        { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd  },
8943        { BUILTIN_SPEC_REG      "return"  , returncmd  },
8944        { BUILTIN_SPEC_REG      "set"     , setcmd     },
8945        { BUILTIN_SPEC_REG      "shift"   , shiftcmd   },
8946#if ENABLE_ASH_BASH_COMPAT
8947        { BUILTIN_SPEC_REG      "source"  , dotcmd     },
8948#endif
8949#if ENABLE_ASH_BUILTIN_TEST
8950        { BUILTIN_REGULAR       "test"    , testcmd    },
8951#endif
8952        { BUILTIN_SPEC_REG      "times"   , timescmd   },
8953        { BUILTIN_SPEC_REG      "trap"    , trapcmd    },
8954        { BUILTIN_REGULAR       "true"    , truecmd    },
8955        { BUILTIN_NOSPEC        "type"    , typecmd    },
8956        { BUILTIN_NOSPEC        "ulimit"  , ulimitcmd  },
8957        { BUILTIN_REGULAR       "umask"   , umaskcmd   },
8958#if ENABLE_ASH_ALIAS
8959        { BUILTIN_REGULAR       "unalias" , unaliascmd },
8960#endif
8961        { BUILTIN_SPEC_REG      "unset"   , unsetcmd   },
8962        { BUILTIN_REGULAR       "wait"    , waitcmd    },
8963};
8964
8965/* Should match the above table! */
8966#define COMMANDCMD (builtintab + \
8967        2 + \
8968        1 * ENABLE_ASH_BUILTIN_TEST + \
8969        1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8970        1 * ENABLE_ASH_ALIAS + \
8971        1 * ENABLE_ASH_JOB_CONTROL + \
8972        3)
8973#define EXECCMD (builtintab + \
8974        2 + \
8975        1 * ENABLE_ASH_BUILTIN_TEST + \
8976        1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8977        1 * ENABLE_ASH_ALIAS + \
8978        1 * ENABLE_ASH_JOB_CONTROL + \
8979        3 + \
8980        1 * ENABLE_ASH_CMDCMD + \
8981        1 + \
8982        ENABLE_ASH_BUILTIN_ECHO + \
8983        1)
8984
8985/*
8986 * Search the table of builtin commands.
8987 */
8988static struct builtincmd *
8989find_builtin(const char *name)
8990{
8991        struct builtincmd *bp;
8992
8993        bp = bsearch(
8994                name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8995                pstrcmp
8996        );
8997        return bp;
8998}
8999
9000/*
9001 * Execute a simple command.
9002 */
9003static int
9004isassignment(const char *p)
9005{
9006        const char *q = endofname(p);
9007        if (p == q)
9008                return 0;
9009        return *q == '=';
9010}
9011static int FAST_FUNC
9012bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9013{
9014        /* Preserve exitstatus of a previous possible redirection
9015         * as POSIX mandates */
9016        return back_exitstatus;
9017}
9018static void
9019evalcommand(union node *cmd, int flags)
9020{
9021        static const struct builtincmd null_bltin = {
9022                "\0\0", bltincmd /* why three NULs? */
9023        };
9024        struct stackmark smark;
9025        union node *argp;
9026        struct arglist arglist;
9027        struct arglist varlist;
9028        char **argv;
9029        int argc;
9030        const struct strlist *sp;
9031        struct cmdentry cmdentry;
9032        struct job *jp;
9033        char *lastarg;
9034        const char *path;
9035        int spclbltin;
9036        int status;
9037        char **nargv;
9038        struct builtincmd *bcmd;
9039        smallint cmd_is_exec;
9040        smallint pseudovarflag = 0;
9041
9042        /* First expand the arguments. */
9043        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9044        setstackmark(&smark);
9045        back_exitstatus = 0;
9046
9047        cmdentry.cmdtype = CMDBUILTIN;
9048        cmdentry.u.cmd = &null_bltin;
9049        varlist.lastp = &varlist.list;
9050        *varlist.lastp = NULL;
9051        arglist.lastp = &arglist.list;
9052        *arglist.lastp = NULL;
9053
9054        argc = 0;
9055        if (cmd->ncmd.args) {
9056                bcmd = find_builtin(cmd->ncmd.args->narg.text);
9057                pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9058        }
9059
9060        for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9061                struct strlist **spp;
9062
9063                spp = arglist.lastp;
9064                if (pseudovarflag && isassignment(argp->narg.text))
9065                        expandarg(argp, &arglist, EXP_VARTILDE);
9066                else
9067                        expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9068
9069                for (sp = *spp; sp; sp = sp->next)
9070                        argc++;
9071        }
9072
9073        argv = nargv = stalloc(sizeof(char *) * (argc + 1));
9074        for (sp = arglist.list; sp; sp = sp->next) {
9075                TRACE(("evalcommand arg: %s\n", sp->text));
9076                *nargv++ = sp->text;
9077        }
9078        *nargv = NULL;
9079
9080        lastarg = NULL;
9081        if (iflag && funcnest == 0 && argc > 0)
9082                lastarg = nargv[-1];
9083
9084        preverrout_fd = 2;
9085        expredir(cmd->ncmd.redirect);
9086        status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
9087
9088        path = vpath.var_text;
9089        for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9090                struct strlist **spp;
9091                char *p;
9092
9093                spp = varlist.lastp;
9094                expandarg(argp, &varlist, EXP_VARTILDE);
9095
9096                /*
9097                 * Modify the command lookup path, if a PATH= assignment
9098                 * is present
9099                 */
9100                p = (*spp)->text;
9101                if (varcmp(p, path) == 0)
9102                        path = p;
9103        }
9104
9105        /* Print the command if xflag is set. */
9106        if (xflag) {
9107                int n;
9108                const char *p = " %s" + 1;
9109
9110                fdprintf(preverrout_fd, p, expandstr(ps4val()));
9111                sp = varlist.list;
9112                for (n = 0; n < 2; n++) {
9113                        while (sp) {
9114                                fdprintf(preverrout_fd, p, sp->text);
9115                                sp = sp->next;
9116                                p = " %s";
9117                        }
9118                        sp = arglist.list;
9119                }
9120                safe_write(preverrout_fd, "\n", 1);
9121        }
9122
9123        cmd_is_exec = 0;
9124        spclbltin = -1;
9125
9126        /* Now locate the command. */
9127        if (argc) {
9128                const char *oldpath;
9129                int cmd_flag = DO_ERR;
9130
9131                path += 5;
9132                oldpath = path;
9133                for (;;) {
9134                        find_command(argv[0], &cmdentry, cmd_flag, path);
9135                        if (cmdentry.cmdtype == CMDUNKNOWN) {
9136                                flush_stdout_stderr();
9137                                status = 127;
9138                                goto bail;
9139                        }
9140
9141                        /* implement bltin and command here */
9142                        if (cmdentry.cmdtype != CMDBUILTIN)
9143                                break;
9144                        if (spclbltin < 0)
9145                                spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9146                        if (cmdentry.u.cmd == EXECCMD)
9147                                cmd_is_exec = 1;
9148#if ENABLE_ASH_CMDCMD
9149                        if (cmdentry.u.cmd == COMMANDCMD) {
9150                                path = oldpath;
9151                                nargv = parse_command_args(argv, &path);
9152                                if (!nargv)
9153                                        break;
9154                                argc -= nargv - argv;
9155                                argv = nargv;
9156                                cmd_flag |= DO_NOFUNC;
9157                        } else
9158#endif
9159                                break;
9160                }
9161        }
9162
9163        if (status) {
9164                /* We have a redirection error. */
9165                if (spclbltin > 0)
9166                        raise_exception(EXERROR);
9167 bail:
9168                exitstatus = status;
9169                goto out;
9170        }
9171
9172        /* Execute the command. */
9173        switch (cmdentry.cmdtype) {
9174        default: {
9175
9176#if ENABLE_FEATURE_SH_NOFORK
9177/* (1) BUG: if variables are set, we need to fork, or save/restore them
9178 *     around run_nofork_applet() call.
9179 * (2) Should this check also be done in forkshell()?
9180 *     (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9181 */
9182                /* find_command() encodes applet_no as (-2 - applet_no) */
9183                int applet_no = (- cmdentry.u.index - 2);
9184                if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
9185                        listsetvar(varlist.list, VEXPORT|VSTACK);
9186                        /* run <applet>_main() */
9187                        exitstatus = run_nofork_applet(applet_no, argv);
9188                        break;
9189                }
9190#endif
9191                /* Can we avoid forking off? For example, very last command
9192                 * in a script or a subshell does not need forking,
9193                 * we can just exec it.
9194                 */
9195                if (!(flags & EV_EXIT) || may_have_traps) {
9196                        /* No, forking off a child is necessary */
9197                        INT_OFF;
9198                        jp = makejob(/*cmd,*/ 1);
9199                        if (forkshell(jp, cmd, FORK_FG) != 0) {
9200                                /* parent */
9201                                exitstatus = waitforjob(jp);
9202                                INT_ON;
9203                                TRACE(("forked child exited with %d\n", exitstatus));
9204                                break;
9205                        }
9206                        /* child */
9207                        FORCE_INT_ON;
9208                        /* fall through to exec'ing external program */
9209                }
9210                listsetvar(varlist.list, VEXPORT|VSTACK);
9211                shellexec(argv, path, cmdentry.u.index);
9212                /* NOTREACHED */
9213        } /* default */
9214        case CMDBUILTIN:
9215                cmdenviron = varlist.list;
9216                if (cmdenviron) {
9217                        struct strlist *list = cmdenviron;
9218                        int i = VNOSET;
9219                        if (spclbltin > 0 || argc == 0) {
9220                                i = 0;
9221                                if (cmd_is_exec && argc > 1)
9222                                        i = VEXPORT;
9223                        }
9224                        listsetvar(list, i);
9225                }
9226                /* Tight loop with builtins only:
9227                 * "while kill -0 $child; do true; done"
9228                 * will never exit even if $child died, unless we do this
9229                 * to reap the zombie and make kill detect that it's gone: */
9230                dowait(DOWAIT_NONBLOCK, NULL);
9231
9232                if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9233                        int exit_status;
9234                        int i = exception_type;
9235                        if (i == EXEXIT)
9236                                goto raise;
9237                        exit_status = 2;
9238                        if (i == EXINT)
9239                                exit_status = 128 + SIGINT;
9240                        if (i == EXSIG)
9241                                exit_status = 128 + pending_sig;
9242                        exitstatus = exit_status;
9243                        if (i == EXINT || spclbltin > 0) {
9244 raise:
9245                                longjmp(exception_handler->loc, 1);
9246                        }
9247                        FORCE_INT_ON;
9248                }
9249                break;
9250
9251        case CMDFUNCTION:
9252                listsetvar(varlist.list, 0);
9253                /* See above for the rationale */
9254                dowait(DOWAIT_NONBLOCK, NULL);
9255                if (evalfun(cmdentry.u.func, argc, argv, flags))
9256                        goto raise;
9257                break;
9258
9259        } /* switch */
9260
9261 out:
9262        popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9263        if (lastarg) {
9264                /* dsl: I think this is intended to be used to support
9265                 * '_' in 'vi' command mode during line editing...
9266                 * However I implemented that within libedit itself.
9267                 */
9268                setvar("_", lastarg, 0);
9269        }
9270        popstackmark(&smark);
9271}
9272
9273static int
9274evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9275{
9276        char *volatile savecmdname;
9277        struct jmploc *volatile savehandler;
9278        struct jmploc jmploc;
9279        int i;
9280
9281        savecmdname = commandname;
9282        i = setjmp(jmploc.loc);
9283        if (i)
9284                goto cmddone;
9285        savehandler = exception_handler;
9286        exception_handler = &jmploc;
9287        commandname = argv[0];
9288        argptr = argv + 1;
9289        optptr = NULL;                  /* initialize nextopt */
9290        exitstatus = (*cmd->builtin)(argc, argv);
9291        flush_stdout_stderr();
9292 cmddone:
9293        exitstatus |= ferror(stdout);
9294        clearerr(stdout);
9295        commandname = savecmdname;
9296        exception_handler = savehandler;
9297
9298        return i;
9299}
9300
9301static int
9302goodname(const char *p)
9303{
9304        return !*endofname(p);
9305}
9306
9307
9308/*
9309 * Search for a command.  This is called before we fork so that the
9310 * location of the command will be available in the parent as well as
9311 * the child.  The check for "goodname" is an overly conservative
9312 * check that the name will not be subject to expansion.
9313 */
9314static void
9315prehash(union node *n)
9316{
9317        struct cmdentry entry;
9318
9319        if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9320                find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9321}
9322
9323
9324/* ============ Builtin commands
9325 *
9326 * Builtin commands whose functions are closely tied to evaluation
9327 * are implemented here.
9328 */
9329
9330/*
9331 * Handle break and continue commands.  Break, continue, and return are
9332 * all handled by setting the evalskip flag.  The evaluation routines
9333 * above all check this flag, and if it is set they start skipping
9334 * commands rather than executing them.  The variable skipcount is
9335 * the number of loops to break/continue, or the number of function
9336 * levels to return.  (The latter is always 1.)  It should probably
9337 * be an error to break out of more loops than exist, but it isn't
9338 * in the standard shell so we don't make it one here.
9339 */
9340static int FAST_FUNC
9341breakcmd(int argc UNUSED_PARAM, char **argv)
9342{
9343        int n = argv[1] ? number(argv[1]) : 1;
9344
9345        if (n <= 0)
9346                ash_msg_and_raise_error(msg_illnum, argv[1]);
9347        if (n > loopnest)
9348                n = loopnest;
9349        if (n > 0) {
9350                evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9351                skipcount = n;
9352        }
9353        return 0;
9354}
9355
9356
9357/* ============ input.c
9358 *
9359 * This implements the input routines used by the parser.
9360 */
9361
9362enum {
9363        INPUT_PUSH_FILE = 1,
9364        INPUT_NOFILE_OK = 2,
9365};
9366
9367static smallint checkkwd;
9368/* values of checkkwd variable */
9369#define CHKALIAS        0x1
9370#define CHKKWD          0x2
9371#define CHKNL           0x4
9372
9373/*
9374 * Push a string back onto the input at this current parsefile level.
9375 * We handle aliases this way.
9376 */
9377#if !ENABLE_ASH_ALIAS
9378#define pushstring(s, ap) pushstring(s)
9379#endif
9380static void
9381pushstring(char *s, struct alias *ap)
9382{
9383        struct strpush *sp;
9384        int len;
9385
9386        len = strlen(s);
9387        INT_OFF;
9388        if (g_parsefile->strpush) {
9389                sp = ckzalloc(sizeof(*sp));
9390                sp->prev = g_parsefile->strpush;
9391        } else {
9392                sp = &(g_parsefile->basestrpush);
9393        }
9394        g_parsefile->strpush = sp;
9395        sp->prev_string = g_parsefile->next_to_pgetc;
9396        sp->prev_left_in_line = g_parsefile->left_in_line;
9397#if ENABLE_ASH_ALIAS
9398        sp->ap = ap;
9399        if (ap) {
9400                ap->flag |= ALIASINUSE;
9401                sp->string = s;
9402        }
9403#endif
9404        g_parsefile->next_to_pgetc = s;
9405        g_parsefile->left_in_line = len;
9406        INT_ON;
9407}
9408
9409static void
9410popstring(void)
9411{
9412        struct strpush *sp = g_parsefile->strpush;
9413
9414        INT_OFF;
9415#if ENABLE_ASH_ALIAS
9416        if (sp->ap) {
9417                if (g_parsefile->next_to_pgetc[-1] == ' '
9418                 || g_parsefile->next_to_pgetc[-1] == '\t'
9419                ) {
9420                        checkkwd |= CHKALIAS;
9421                }
9422                if (sp->string != sp->ap->val) {
9423                        free(sp->string);
9424                }
9425                sp->ap->flag &= ~ALIASINUSE;
9426                if (sp->ap->flag & ALIASDEAD) {
9427                        unalias(sp->ap->name);
9428                }
9429        }
9430#endif
9431        g_parsefile->next_to_pgetc = sp->prev_string;
9432        g_parsefile->left_in_line = sp->prev_left_in_line;
9433        g_parsefile->strpush = sp->prev;
9434        if (sp != &(g_parsefile->basestrpush))
9435                free(sp);
9436        INT_ON;
9437}
9438
9439//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9440//it peeks whether it is &>, and then pushes back both chars.
9441//This function needs to save last *next_to_pgetc to buf[0]
9442//to make two pungetc() reliable. Currently,
9443// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
9444static int
9445preadfd(void)
9446{
9447        int nr;
9448        char *buf = g_parsefile->buf;
9449
9450        g_parsefile->next_to_pgetc = buf;
9451#if ENABLE_FEATURE_EDITING
9452 retry:
9453        if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
9454                nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9455        else {
9456#if ENABLE_FEATURE_TAB_COMPLETION
9457                line_input_state->path_lookup = pathval();
9458#endif
9459                nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state);
9460                if (nr == 0) {
9461                        /* Ctrl+C pressed */
9462                        if (trap[SIGINT]) {
9463                                buf[0] = '\n';
9464                                buf[1] = '\0';
9465                                raise(SIGINT);
9466                                return 1;
9467                        }
9468                        goto retry;
9469                }
9470                if (nr < 0 && errno == 0) {
9471                        /* Ctrl+D pressed */
9472                        nr = 0;
9473                }
9474        }
9475#else
9476        nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9477#endif
9478
9479#if 0
9480/* nonblock_safe_read() handles this problem */
9481        if (nr < 0) {
9482                if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9483                        int flags = fcntl(0, F_GETFL);
9484                        if (flags >= 0 && (flags & O_NONBLOCK)) {
9485                                flags &= ~O_NONBLOCK;
9486                                if (fcntl(0, F_SETFL, flags) >= 0) {
9487                                        out2str("sh: turning off NDELAY mode\n");
9488                                        goto retry;
9489                                }
9490                        }
9491                }
9492        }
9493#endif
9494        return nr;
9495}
9496
9497/*
9498 * Refill the input buffer and return the next input character:
9499 *
9500 * 1) If a string was pushed back on the input, pop it;
9501 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9502 *    or we are reading from a string so we can't refill the buffer,
9503 *    return EOF.
9504 * 3) If there is more stuff in this buffer, use it else call read to fill it.
9505 * 4) Process input up to the next newline, deleting nul characters.
9506 */
9507//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9508#define pgetc_debug(...) ((void)0)
9509static int
9510preadbuffer(void)
9511{
9512        char *q;
9513        int more;
9514
9515        while (g_parsefile->strpush) {
9516#if ENABLE_ASH_ALIAS
9517                if (g_parsefile->left_in_line == -1
9518                 && g_parsefile->strpush->ap
9519                 && g_parsefile->next_to_pgetc[-1] != ' '
9520                 && g_parsefile->next_to_pgetc[-1] != '\t'
9521                ) {
9522                        pgetc_debug("preadbuffer PEOA");
9523                        return PEOA;
9524                }
9525#endif
9526                popstring();
9527                /* try "pgetc" now: */
9528                pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9529                                g_parsefile->left_in_line,
9530                                g_parsefile->next_to_pgetc,
9531                                g_parsefile->next_to_pgetc);
9532                if (--g_parsefile->left_in_line >= 0)
9533                        return (unsigned char)(*g_parsefile->next_to_pgetc++);
9534        }
9535        /* on both branches above g_parsefile->left_in_line < 0.
9536         * "pgetc" needs refilling.
9537         */
9538
9539        /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9540         * pungetc() may increment it a few times.
9541         * Assuming it won't increment it to less than -90.
9542         */
9543        if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9544                pgetc_debug("preadbuffer PEOF1");
9545                /* even in failure keep left_in_line and next_to_pgetc
9546                 * in lock step, for correct multi-layer pungetc.
9547                 * left_in_line was decremented before preadbuffer(),
9548                 * must inc next_to_pgetc: */
9549                g_parsefile->next_to_pgetc++;
9550                return PEOF;
9551        }
9552
9553        more = g_parsefile->left_in_buffer;
9554        if (more <= 0) {
9555                flush_stdout_stderr();
9556 again:
9557                more = preadfd();
9558                if (more <= 0) {
9559                        /* don't try reading again */
9560                        g_parsefile->left_in_line = -99;
9561                        pgetc_debug("preadbuffer PEOF2");
9562                        g_parsefile->next_to_pgetc++;
9563                        return PEOF;
9564                }
9565        }
9566
9567        /* Find out where's the end of line.
9568         * Set g_parsefile->left_in_line
9569         * and g_parsefile->left_in_buffer acordingly.
9570         * NUL chars are deleted.
9571         */
9572        q = g_parsefile->next_to_pgetc;
9573        for (;;) {
9574                char c;
9575
9576                more--;
9577
9578                c = *q;
9579                if (c == '\0') {
9580                        memmove(q, q + 1, more);
9581                } else {
9582                        q++;
9583                        if (c == '\n') {
9584                                g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9585                                break;
9586                        }
9587                }
9588
9589                if (more <= 0) {
9590                        g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9591                        if (g_parsefile->left_in_line < 0)
9592                                goto again;
9593                        break;
9594                }
9595        }
9596        g_parsefile->left_in_buffer = more;
9597
9598        if (vflag) {
9599                char save = *q;
9600                *q = '\0';
9601                out2str(g_parsefile->next_to_pgetc);
9602                *q = save;
9603        }
9604
9605        pgetc_debug("preadbuffer at %d:%p'%s'",
9606                        g_parsefile->left_in_line,
9607                        g_parsefile->next_to_pgetc,
9608                        g_parsefile->next_to_pgetc);
9609        return (unsigned char)*g_parsefile->next_to_pgetc++;
9610}
9611
9612#define pgetc_as_macro() \
9613        (--g_parsefile->left_in_line >= 0 \
9614        ? (unsigned char)*g_parsefile->next_to_pgetc++ \
9615        : preadbuffer() \
9616        )
9617
9618static int
9619pgetc(void)
9620{
9621        pgetc_debug("pgetc_fast at %d:%p'%s'",
9622                        g_parsefile->left_in_line,
9623                        g_parsefile->next_to_pgetc,
9624                        g_parsefile->next_to_pgetc);
9625        return pgetc_as_macro();
9626}
9627
9628#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9629# define pgetc_fast() pgetc()
9630#else
9631# define pgetc_fast() pgetc_as_macro()
9632#endif
9633
9634#if ENABLE_ASH_ALIAS
9635static int
9636pgetc_without_PEOA(void)
9637{
9638        int c;
9639        do {
9640                pgetc_debug("pgetc_fast at %d:%p'%s'",
9641                                g_parsefile->left_in_line,
9642                                g_parsefile->next_to_pgetc,
9643                                g_parsefile->next_to_pgetc);
9644                c = pgetc_fast();
9645        } while (c == PEOA);
9646        return c;
9647}
9648#else
9649# define pgetc_without_PEOA() pgetc()
9650#endif
9651
9652/*
9653 * Read a line from the script.
9654 */
9655static char *
9656pfgets(char *line, int len)
9657{
9658        char *p = line;
9659        int nleft = len;
9660        int c;
9661
9662        while (--nleft > 0) {
9663                c = pgetc_without_PEOA();
9664                if (c == PEOF) {
9665                        if (p == line)
9666                                return NULL;
9667                        break;
9668                }
9669                *p++ = c;
9670                if (c == '\n')
9671                        break;
9672        }
9673        *p = '\0';
9674        return line;
9675}
9676
9677/*
9678 * Undo the last call to pgetc.  Only one character may be pushed back.
9679 * PEOF may be pushed back.
9680 */
9681static void
9682pungetc(void)
9683{
9684        g_parsefile->left_in_line++;
9685        g_parsefile->next_to_pgetc--;
9686        pgetc_debug("pushed back to %d:%p'%s'",
9687                        g_parsefile->left_in_line,
9688                        g_parsefile->next_to_pgetc,
9689                        g_parsefile->next_to_pgetc);
9690}
9691
9692/*
9693 * To handle the "." command, a stack of input files is used.  Pushfile
9694 * adds a new entry to the stack and popfile restores the previous level.
9695 */
9696static void
9697pushfile(void)
9698{
9699        struct parsefile *pf;
9700
9701        pf = ckzalloc(sizeof(*pf));
9702        pf->prev = g_parsefile;
9703        pf->pf_fd = -1;
9704        /*pf->strpush = NULL; - ckzalloc did it */
9705        /*pf->basestrpush.prev = NULL;*/
9706        g_parsefile = pf;
9707}
9708
9709static void
9710popfile(void)
9711{
9712        struct parsefile *pf = g_parsefile;
9713
9714        INT_OFF;
9715        if (pf->pf_fd >= 0)
9716                close(pf->pf_fd);
9717        free(pf->buf);
9718        while (pf->strpush)
9719                popstring();
9720        g_parsefile = pf->prev;
9721        free(pf);
9722        INT_ON;
9723}
9724
9725/*
9726 * Return to top level.
9727 */
9728static void
9729popallfiles(void)
9730{
9731        while (g_parsefile != &basepf)
9732                popfile();
9733}
9734
9735/*
9736 * Close the file(s) that the shell is reading commands from.  Called
9737 * after a fork is done.
9738 */
9739static void
9740closescript(void)
9741{
9742        popallfiles();
9743        if (g_parsefile->pf_fd > 0) {
9744                close(g_parsefile->pf_fd);
9745                g_parsefile->pf_fd = 0;
9746        }
9747}
9748
9749/*
9750 * Like setinputfile, but takes an open file descriptor.  Call this with
9751 * interrupts off.
9752 */
9753static void
9754setinputfd(int fd, int push)
9755{
9756        close_on_exec_on(fd);
9757        if (push) {
9758                pushfile();
9759                g_parsefile->buf = NULL;
9760        }
9761        g_parsefile->pf_fd = fd;
9762        if (g_parsefile->buf == NULL)
9763                g_parsefile->buf = ckmalloc(IBUFSIZ);
9764        g_parsefile->left_in_buffer = 0;
9765        g_parsefile->left_in_line = 0;
9766        g_parsefile->linno = 1;
9767}
9768
9769/*
9770 * Set the input to take input from a file.  If push is set, push the
9771 * old input onto the stack first.
9772 */
9773static int
9774setinputfile(const char *fname, int flags)
9775{
9776        int fd;
9777        int fd2;
9778
9779        INT_OFF;
9780        fd = open(fname, O_RDONLY);
9781        if (fd < 0) {
9782                if (flags & INPUT_NOFILE_OK)
9783                        goto out;
9784                ash_msg_and_raise_error("can't open '%s'", fname);
9785        }
9786        if (fd < 10) {
9787                fd2 = copyfd(fd, 10);
9788                close(fd);
9789                if (fd2 < 0)
9790                        ash_msg_and_raise_error("out of file descriptors");
9791                fd = fd2;
9792        }
9793        setinputfd(fd, flags & INPUT_PUSH_FILE);
9794 out:
9795        INT_ON;
9796        return fd;
9797}
9798
9799/*
9800 * Like setinputfile, but takes input from a string.
9801 */
9802static void
9803setinputstring(char *string)
9804{
9805        INT_OFF;
9806        pushfile();
9807        g_parsefile->next_to_pgetc = string;
9808        g_parsefile->left_in_line = strlen(string);
9809        g_parsefile->buf = NULL;
9810        g_parsefile->linno = 1;
9811        INT_ON;
9812}
9813
9814
9815/* ============ mail.c
9816 *
9817 * Routines to check for mail.
9818 */
9819
9820#if ENABLE_ASH_MAIL
9821
9822#define MAXMBOXES 10
9823
9824/* times of mailboxes */
9825static time_t mailtime[MAXMBOXES];
9826/* Set if MAIL or MAILPATH is changed. */
9827static smallint mail_var_path_changed;
9828
9829/*
9830 * Print appropriate message(s) if mail has arrived.
9831 * If mail_var_path_changed is set,
9832 * then the value of MAIL has mail_var_path_changed,
9833 * so we just update the values.
9834 */
9835static void
9836chkmail(void)
9837{
9838        const char *mpath;
9839        char *p;
9840        char *q;
9841        time_t *mtp;
9842        struct stackmark smark;
9843        struct stat statb;
9844
9845        setstackmark(&smark);
9846        mpath = mpathset() ? mpathval() : mailval();
9847        for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9848                p = path_advance(&mpath, nullstr);
9849                if (p == NULL)
9850                        break;
9851                if (*p == '\0')
9852                        continue;
9853                for (q = p; *q; q++)
9854                        continue;
9855#if DEBUG
9856                if (q[-1] != '/')
9857                        abort();
9858#endif
9859                q[-1] = '\0';                   /* delete trailing '/' */
9860                if (stat(p, &statb) < 0) {
9861                        *mtp = 0;
9862                        continue;
9863                }
9864                if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9865                        fprintf(
9866                                stderr, "%s\n",
9867                                pathopt ? pathopt : "you have mail"
9868                        );
9869                }
9870                *mtp = statb.st_mtime;
9871        }
9872        mail_var_path_changed = 0;
9873        popstackmark(&smark);
9874}
9875
9876static void FAST_FUNC
9877changemail(const char *val UNUSED_PARAM)
9878{
9879        mail_var_path_changed = 1;
9880}
9881
9882#endif /* ASH_MAIL */
9883
9884
9885/* ============ ??? */
9886
9887/*
9888 * Set the shell parameters.
9889 */
9890static void
9891setparam(char **argv)
9892{
9893        char **newparam;
9894        char **ap;
9895        int nparam;
9896
9897        for (nparam = 0; argv[nparam]; nparam++)
9898                continue;
9899        ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9900        while (*argv) {
9901                *ap++ = ckstrdup(*argv++);
9902        }
9903        *ap = NULL;
9904        freeparam(&shellparam);
9905        shellparam.malloced = 1;
9906        shellparam.nparam = nparam;
9907        shellparam.p = newparam;
9908#if ENABLE_ASH_GETOPTS
9909        shellparam.optind = 1;
9910        shellparam.optoff = -1;
9911#endif
9912}
9913
9914/*
9915 * Process shell options.  The global variable argptr contains a pointer
9916 * to the argument list; we advance it past the options.
9917 *
9918 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9919 * For a non-interactive shell, an error condition encountered
9920 * by a special built-in ... shall cause the shell to write a diagnostic message
9921 * to standard error and exit as shown in the following table:
9922 * Error                                           Special Built-In
9923 * ...
9924 * Utility syntax error (option or operand error)  Shall exit
9925 * ...
9926 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9927 * we see that bash does not do that (set "finishes" with error code 1 instead,
9928 * and shell continues), and people rely on this behavior!
9929 * Testcase:
9930 * set -o barfoo 2>/dev/null
9931 * echo $?
9932 *
9933 * Oh well. Let's mimic that.
9934 */
9935static int
9936plus_minus_o(char *name, int val)
9937{
9938        int i;
9939
9940        if (name) {
9941                for (i = 0; i < NOPTS; i++) {
9942                        if (strcmp(name, optnames(i)) == 0) {
9943                                optlist[i] = val;
9944                                return 0;
9945                        }
9946                }
9947                ash_msg("illegal option %co %s", val ? '-' : '+', name);
9948                return 1;
9949        }
9950        for (i = 0; i < NOPTS; i++) {
9951                if (val) {
9952                        out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9953                } else {
9954                        out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9955                }
9956        }
9957        return 0;
9958}
9959static void
9960setoption(int flag, int val)
9961{
9962        int i;
9963
9964        for (i = 0; i < NOPTS; i++) {
9965                if (optletters(i) == flag) {
9966                        optlist[i] = val;
9967                        return;
9968                }
9969        }
9970        ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9971        /* NOTREACHED */
9972}
9973static int
9974options(int cmdline)
9975{
9976        char *p;
9977        int val;
9978        int c;
9979
9980        if (cmdline)
9981                minusc = NULL;
9982        while ((p = *argptr) != NULL) {
9983                c = *p++;
9984                if (c != '-' && c != '+')
9985                        break;
9986                argptr++;
9987                val = 0; /* val = 0 if c == '+' */
9988                if (c == '-') {
9989                        val = 1;
9990                        if (p[0] == '\0' || LONE_DASH(p)) {
9991                                if (!cmdline) {
9992                                        /* "-" means turn off -x and -v */
9993                                        if (p[0] == '\0')
9994                                                xflag = vflag = 0;
9995                                        /* "--" means reset params */
9996                                        else if (*argptr == NULL)
9997                                                setparam(argptr);
9998                                }
9999                                break;    /* "-" or  "--" terminates options */
10000                        }
10001                }
10002                /* first char was + or - */
10003                while ((c = *p++) != '\0') {
10004                        /* bash 3.2 indeed handles -c CMD and +c CMD the same */
10005                        if (c == 'c' && cmdline) {
10006                                minusc = p;     /* command is after shell args */
10007                        } else if (c == 'o') {
10008                                if (plus_minus_o(*argptr, val)) {
10009                                        /* it already printed err message */
10010                                        return 1; /* error */
10011                                }
10012                                if (*argptr)
10013                                        argptr++;
10014                        } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10015                                isloginsh = 1;
10016                        /* bash does not accept +-login, we also won't */
10017                        } else if (cmdline && val && (c == '-')) { /* long options */
10018                                if (strcmp(p, "login") == 0)
10019                                        isloginsh = 1;
10020                                break;
10021                        } else {
10022                                setoption(c, val);
10023                        }
10024                }
10025        }
10026        return 0;
10027}
10028
10029/*
10030 * The shift builtin command.
10031 */
10032static int FAST_FUNC
10033shiftcmd(int argc UNUSED_PARAM, char **argv)
10034{
10035        int n;
10036        char **ap1, **ap2;
10037
10038        n = 1;
10039        if (argv[1])
10040                n = number(argv[1]);
10041        if (n > shellparam.nparam)
10042                n = 0; /* bash compat, was = shellparam.nparam; */
10043        INT_OFF;
10044        shellparam.nparam -= n;
10045        for (ap1 = shellparam.p; --n >= 0; ap1++) {
10046                if (shellparam.malloced)
10047                        free(*ap1);
10048        }
10049        ap2 = shellparam.p;
10050        while ((*ap2++ = *ap1++) != NULL)
10051                continue;
10052#if ENABLE_ASH_GETOPTS
10053        shellparam.optind = 1;
10054        shellparam.optoff = -1;
10055#endif
10056        INT_ON;
10057        return 0;
10058}
10059
10060/*
10061 * POSIX requires that 'set' (but not export or readonly) output the
10062 * variables in lexicographic order - by the locale's collating order (sigh).
10063 * Maybe we could keep them in an ordered balanced binary tree
10064 * instead of hashed lists.
10065 * For now just roll 'em through qsort for printing...
10066 */
10067static int
10068showvars(const char *sep_prefix, int on, int off)
10069{
10070        const char *sep;
10071        char **ep, **epend;
10072
10073        ep = listvars(on, off, &epend);
10074        qsort(ep, epend - ep, sizeof(char *), vpcmp);
10075
10076        sep = *sep_prefix ? " " : sep_prefix;
10077
10078        for (; ep < epend; ep++) {
10079                const char *p;
10080                const char *q;
10081
10082                p = strchrnul(*ep, '=');
10083                q = nullstr;
10084                if (*p)
10085                        q = single_quote(++p);
10086                out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10087        }
10088        return 0;
10089}
10090
10091/*
10092 * The set command builtin.
10093 */
10094static int FAST_FUNC
10095setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10096{
10097        int retval;
10098
10099        if (!argv[1])
10100                return showvars(nullstr, 0, VUNSET);
10101        INT_OFF;
10102        retval = 1;
10103        if (!options(0)) { /* if no parse error... */
10104                retval = 0;
10105                optschanged();
10106                if (*argptr != NULL) {
10107                        setparam(argptr);
10108                }
10109        }
10110        INT_ON;
10111        return retval;
10112}
10113
10114#if ENABLE_ASH_RANDOM_SUPPORT
10115static void FAST_FUNC
10116change_random(const char *value)
10117{
10118        uint32_t t;
10119
10120        if (value == NULL) {
10121                /* "get", generate */
10122                t = next_random(&random_gen);
10123                /* set without recursion */
10124                setvar(vrandom.var_text, utoa(t), VNOFUNC);
10125                vrandom.flags &= ~VNOFUNC;
10126        } else {
10127                /* set/reset */
10128                t = strtoul(value, NULL, 10);
10129                INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
10130        }
10131}
10132#endif
10133
10134#if ENABLE_ASH_GETOPTS
10135static int
10136getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
10137{
10138        char *p, *q;
10139        char c = '?';
10140        int done = 0;
10141        int err = 0;
10142        char s[12];
10143        char **optnext;
10144
10145        if (*param_optind < 1)
10146                return 1;
10147        optnext = optfirst + *param_optind - 1;
10148
10149        if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
10150                p = NULL;
10151        else
10152                p = optnext[-1] + *optoff;
10153        if (p == NULL || *p == '\0') {
10154                /* Current word is done, advance */
10155                p = *optnext;
10156                if (p == NULL || *p != '-' || *++p == '\0') {
10157 atend:
10158                        p = NULL;
10159                        done = 1;
10160                        goto out;
10161                }
10162                optnext++;
10163                if (LONE_DASH(p))        /* check for "--" */
10164                        goto atend;
10165        }
10166
10167        c = *p++;
10168        for (q = optstr; *q != c;) {
10169                if (*q == '\0') {
10170                        if (optstr[0] == ':') {
10171                                s[0] = c;
10172                                s[1] = '\0';
10173                                err |= setvarsafe("OPTARG", s, 0);
10174                        } else {
10175                                fprintf(stderr, "Illegal option -%c\n", c);
10176                                unsetvar("OPTARG");
10177                        }
10178                        c = '?';
10179                        goto out;
10180                }
10181                if (*++q == ':')
10182                        q++;
10183        }
10184
10185        if (*++q == ':') {
10186                if (*p == '\0' && (p = *optnext) == NULL) {
10187                        if (optstr[0] == ':') {
10188                                s[0] = c;
10189                                s[1] = '\0';
10190                                err |= setvarsafe("OPTARG", s, 0);
10191                                c = ':';
10192                        } else {
10193                                fprintf(stderr, "No arg for -%c option\n", c);
10194                                unsetvar("OPTARG");
10195                                c = '?';
10196                        }
10197                        goto out;
10198                }
10199
10200                if (p == *optnext)
10201                        optnext++;
10202                err |= setvarsafe("OPTARG", p, 0);
10203                p = NULL;
10204        } else
10205                err |= setvarsafe("OPTARG", nullstr, 0);
10206 out:
10207        *optoff = p ? p - *(optnext - 1) : -1;
10208        *param_optind = optnext - optfirst + 1;
10209        fmtstr(s, sizeof(s), "%d", *param_optind);
10210        err |= setvarsafe("OPTIND", s, VNOFUNC);
10211        s[0] = c;
10212        s[1] = '\0';
10213        err |= setvarsafe(optvar, s, 0);
10214        if (err) {
10215                *param_optind = 1;
10216                *optoff = -1;
10217                flush_stdout_stderr();
10218                raise_exception(EXERROR);
10219        }
10220        return done;
10221}
10222
10223/*
10224 * The getopts builtin.  Shellparam.optnext points to the next argument
10225 * to be processed.  Shellparam.optptr points to the next character to
10226 * be processed in the current argument.  If shellparam.optnext is NULL,
10227 * then it's the first time getopts has been called.
10228 */
10229static int FAST_FUNC
10230getoptscmd(int argc, char **argv)
10231{
10232        char **optbase;
10233
10234        if (argc < 3)
10235                ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10236        if (argc == 3) {
10237                optbase = shellparam.p;
10238                if (shellparam.optind > shellparam.nparam + 1) {
10239                        shellparam.optind = 1;
10240                        shellparam.optoff = -1;
10241                }
10242        } else {
10243                optbase = &argv[3];
10244                if (shellparam.optind > argc - 2) {
10245                        shellparam.optind = 1;
10246                        shellparam.optoff = -1;
10247                }
10248        }
10249
10250        return getopts(argv[1], argv[2], optbase, &shellparam.optind,
10251                        &shellparam.optoff);
10252}
10253#endif /* ASH_GETOPTS */
10254
10255
10256/* ============ Shell parser */
10257
10258struct heredoc {
10259        struct heredoc *next;   /* next here document in list */
10260        union node *here;       /* redirection node */
10261        char *eofmark;          /* string indicating end of input */
10262        smallint striptabs;     /* if set, strip leading tabs */
10263};
10264
10265static smallint tokpushback;           /* last token pushed back */
10266static smallint parsebackquote;        /* nonzero if we are inside backquotes */
10267static smallint quoteflag;             /* set if (part of) last token was quoted */
10268static token_id_t lasttoken;           /* last token read (integer id Txxx) */
10269static struct heredoc *heredoclist;    /* list of here documents to read */
10270static char *wordtext;                 /* text of last word returned by readtoken */
10271static struct nodelist *backquotelist;
10272static union node *redirnode;
10273static struct heredoc *heredoc;
10274
10275static const char *
10276tokname(char *buf, int tok)
10277{
10278        if (tok < TSEMI)
10279                return tokname_array[tok] + 1;
10280        sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10281        return buf;
10282}
10283
10284/* raise_error_unexpected_syntax:
10285 * Called when an unexpected token is read during the parse.  The argument
10286 * is the token that is expected, or -1 if more than one type of token can
10287 * occur at this point.
10288 */
10289static void raise_error_unexpected_syntax(int) NORETURN;
10290static void
10291raise_error_unexpected_syntax(int token)
10292{
10293        char msg[64];
10294        char buf[16];
10295        int l;
10296
10297        l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
10298        if (token >= 0)
10299                sprintf(msg + l, " (expecting %s)", tokname(buf, token));
10300        raise_error_syntax(msg);
10301        /* NOTREACHED */
10302}
10303
10304#define EOFMARKLEN 79
10305
10306/* parsing is heavily cross-recursive, need these forward decls */
10307static union node *andor(void);
10308static union node *pipeline(void);
10309static union node *parse_command(void);
10310static void parseheredoc(void);
10311static char peektoken(void);
10312static int readtoken(void);
10313
10314static union node *
10315list(int nlflag)
10316{
10317        union node *n1, *n2, *n3;
10318        int tok;
10319
10320        checkkwd = CHKNL | CHKKWD | CHKALIAS;
10321        if (nlflag == 2 && peektoken())
10322                return NULL;
10323        n1 = NULL;
10324        for (;;) {
10325                n2 = andor();
10326                tok = readtoken();
10327                if (tok == TBACKGND) {
10328                        if (n2->type == NPIPE) {
10329                                n2->npipe.pipe_backgnd = 1;
10330                        } else {
10331                                if (n2->type != NREDIR) {
10332                                        n3 = stzalloc(sizeof(struct nredir));
10333                                        n3->nredir.n = n2;
10334                                        /*n3->nredir.redirect = NULL; - stzalloc did it */
10335                                        n2 = n3;
10336                                }
10337                                n2->type = NBACKGND;
10338                        }
10339                }
10340                if (n1 == NULL) {
10341                        n1 = n2;
10342                } else {
10343                        n3 = stzalloc(sizeof(struct nbinary));
10344                        n3->type = NSEMI;
10345                        n3->nbinary.ch1 = n1;
10346                        n3->nbinary.ch2 = n2;
10347                        n1 = n3;
10348                }
10349                switch (tok) {
10350                case TBACKGND:
10351                case TSEMI:
10352                        tok = readtoken();
10353                        /* fall through */
10354                case TNL:
10355                        if (tok == TNL) {
10356                                parseheredoc();
10357                                if (nlflag == 1)
10358                                        return n1;
10359                        } else {
10360                                tokpushback = 1;
10361                        }
10362                        checkkwd = CHKNL | CHKKWD | CHKALIAS;
10363                        if (peektoken())
10364                                return n1;
10365                        break;
10366                case TEOF:
10367                        if (heredoclist)
10368                                parseheredoc();
10369                        else
10370                                pungetc();              /* push back EOF on input */
10371                        return n1;
10372                default:
10373                        if (nlflag == 1)
10374                                raise_error_unexpected_syntax(-1);
10375                        tokpushback = 1;
10376                        return n1;
10377                }
10378        }
10379}
10380
10381static union node *
10382andor(void)
10383{
10384        union node *n1, *n2, *n3;
10385        int t;
10386
10387        n1 = pipeline();
10388        for (;;) {
10389                t = readtoken();
10390                if (t == TAND) {
10391                        t = NAND;
10392                } else if (t == TOR) {
10393                        t = NOR;
10394                } else {
10395                        tokpushback = 1;
10396                        return n1;
10397                }
10398                checkkwd = CHKNL | CHKKWD | CHKALIAS;
10399                n2 = pipeline();
10400                n3 = stzalloc(sizeof(struct nbinary));
10401                n3->type = t;
10402                n3->nbinary.ch1 = n1;
10403                n3->nbinary.ch2 = n2;
10404                n1 = n3;
10405        }
10406}
10407
10408static union node *
10409pipeline(void)
10410{
10411        union node *n1, *n2, *pipenode;
10412        struct nodelist *lp, *prev;
10413        int negate;
10414
10415        negate = 0;
10416        TRACE(("pipeline: entered\n"));
10417        if (readtoken() == TNOT) {
10418                negate = !negate;
10419                checkkwd = CHKKWD | CHKALIAS;
10420        } else
10421                tokpushback = 1;
10422        n1 = parse_command();
10423        if (readtoken() == TPIPE) {
10424                pipenode = stzalloc(sizeof(struct npipe));
10425                pipenode->type = NPIPE;
10426                /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10427                lp = stzalloc(sizeof(struct nodelist));
10428                pipenode->npipe.cmdlist = lp;
10429                lp->n = n1;
10430                do {
10431                        prev = lp;
10432                        lp = stzalloc(sizeof(struct nodelist));
10433                        checkkwd = CHKNL | CHKKWD | CHKALIAS;
10434                        lp->n = parse_command();
10435                        prev->next = lp;
10436                } while (readtoken() == TPIPE);
10437                lp->next = NULL;
10438                n1 = pipenode;
10439        }
10440        tokpushback = 1;
10441        if (negate) {
10442                n2 = stzalloc(sizeof(struct nnot));
10443                n2->type = NNOT;
10444                n2->nnot.com = n1;
10445                return n2;
10446        }
10447        return n1;
10448}
10449
10450static union node *
10451makename(void)
10452{
10453        union node *n;
10454
10455        n = stzalloc(sizeof(struct narg));
10456        n->type = NARG;
10457        /*n->narg.next = NULL; - stzalloc did it */
10458        n->narg.text = wordtext;
10459        n->narg.backquote = backquotelist;
10460        return n;
10461}
10462
10463static void
10464fixredir(union node *n, const char *text, int err)
10465{
10466        int fd;
10467
10468        TRACE(("Fix redir %s %d\n", text, err));
10469        if (!err)
10470                n->ndup.vname = NULL;
10471
10472        fd = bb_strtou(text, NULL, 10);
10473        if (!errno && fd >= 0)
10474                n->ndup.dupfd = fd;
10475        else if (LONE_DASH(text))
10476                n->ndup.dupfd = -1;
10477        else {
10478                if (err)
10479                        raise_error_syntax("bad fd number");
10480                n->ndup.vname = makename();
10481        }
10482}
10483
10484/*
10485 * Returns true if the text contains nothing to expand (no dollar signs
10486 * or backquotes).
10487 */
10488static int
10489noexpand(const char *text)
10490{
10491        unsigned char c;
10492
10493        while ((c = *text++) != '\0') {
10494                if (c == CTLQUOTEMARK)
10495                        continue;
10496                if (c == CTLESC)
10497                        text++;
10498                else if (SIT(c, BASESYNTAX) == CCTL)
10499                        return 0;
10500        }
10501        return 1;
10502}
10503
10504static void
10505parsefname(void)
10506{
10507        union node *n = redirnode;
10508
10509        if (readtoken() != TWORD)
10510                raise_error_unexpected_syntax(-1);
10511        if (n->type == NHERE) {
10512                struct heredoc *here = heredoc;
10513                struct heredoc *p;
10514                int i;
10515
10516                if (quoteflag == 0)
10517                        n->type = NXHERE;
10518                TRACE(("Here document %d\n", n->type));
10519                if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10520                        raise_error_syntax("illegal eof marker for << redirection");
10521                rmescapes(wordtext, 0);
10522                here->eofmark = wordtext;
10523                here->next = NULL;
10524                if (heredoclist == NULL)
10525                        heredoclist = here;
10526                else {
10527                        for (p = heredoclist; p->next; p = p->next)
10528                                continue;
10529                        p->next = here;
10530                }
10531        } else if (n->type == NTOFD || n->type == NFROMFD) {
10532                fixredir(n, wordtext, 0);
10533        } else {
10534                n->nfile.fname = makename();
10535        }
10536}
10537
10538static union node *
10539simplecmd(void)
10540{
10541        union node *args, **app;
10542        union node *n = NULL;
10543        union node *vars, **vpp;
10544        union node **rpp, *redir;
10545        int savecheckkwd;
10546#if ENABLE_ASH_BASH_COMPAT
10547        smallint double_brackets_flag = 0;
10548#endif
10549
10550        args = NULL;
10551        app = &args;
10552        vars = NULL;
10553        vpp = &vars;
10554        redir = NULL;
10555        rpp = &redir;
10556
10557        savecheckkwd = CHKALIAS;
10558        for (;;) {
10559                int t;
10560                checkkwd = savecheckkwd;
10561                t = readtoken();
10562                switch (t) {
10563#if ENABLE_ASH_BASH_COMPAT
10564                case TAND: /* "&&" */
10565                case TOR: /* "||" */
10566                        if (!double_brackets_flag) {
10567                                tokpushback = 1;
10568                                goto out;
10569                        }
10570                        wordtext = (char *) (t == TAND ? "-a" : "-o");
10571#endif
10572                case TWORD:
10573                        n = stzalloc(sizeof(struct narg));
10574                        n->type = NARG;
10575                        /*n->narg.next = NULL; - stzalloc did it */
10576                        n->narg.text = wordtext;
10577#if ENABLE_ASH_BASH_COMPAT
10578                        if (strcmp("[[", wordtext) == 0)
10579                                double_brackets_flag = 1;
10580                        else if (strcmp("]]", wordtext) == 0)
10581                                double_brackets_flag = 0;
10582#endif
10583                        n->narg.backquote = backquotelist;
10584                        if (savecheckkwd && isassignment(wordtext)) {
10585                                *vpp = n;
10586                                vpp = &n->narg.next;
10587                        } else {
10588                                *app = n;
10589                                app = &n->narg.next;
10590                                savecheckkwd = 0;
10591                        }
10592                        break;
10593                case TREDIR:
10594                        *rpp = n = redirnode;
10595                        rpp = &n->nfile.next;
10596                        parsefname();   /* read name of redirection file */
10597                        break;
10598                case TLP:
10599                        if (args && app == &args->narg.next
10600                         && !vars && !redir
10601                        ) {
10602                                struct builtincmd *bcmd;
10603                                const char *name;
10604
10605                                /* We have a function */
10606                                if (readtoken() != TRP)
10607                                        raise_error_unexpected_syntax(TRP);
10608                                name = n->narg.text;
10609                                if (!goodname(name)
10610                                 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10611                                ) {
10612                                        raise_error_syntax("bad function name");
10613                                }
10614                                n->type = NDEFUN;
10615                                checkkwd = CHKNL | CHKKWD | CHKALIAS;
10616                                n->narg.next = parse_command();
10617                                return n;
10618                        }
10619                        /* fall through */
10620                default:
10621                        tokpushback = 1;
10622                        goto out;
10623                }
10624        }
10625 out:
10626        *app = NULL;
10627        *vpp = NULL;
10628        *rpp = NULL;
10629        n = stzalloc(sizeof(struct ncmd));
10630        n->type = NCMD;
10631        n->ncmd.args = args;
10632        n->ncmd.assign = vars;
10633        n->ncmd.redirect = redir;
10634        return n;
10635}
10636
10637static union node *
10638parse_command(void)
10639{
10640        union node *n1, *n2;
10641        union node *ap, **app;
10642        union node *cp, **cpp;
10643        union node *redir, **rpp;
10644        union node **rpp2;
10645        int t;
10646
10647        redir = NULL;
10648        rpp2 = &redir;
10649
10650        switch (readtoken()) {
10651        default:
10652                raise_error_unexpected_syntax(-1);
10653                /* NOTREACHED */
10654        case TIF:
10655                n1 = stzalloc(sizeof(struct nif));
10656                n1->type = NIF;
10657                n1->nif.test = list(0);
10658                if (readtoken() != TTHEN)
10659                        raise_error_unexpected_syntax(TTHEN);
10660                n1->nif.ifpart = list(0);
10661                n2 = n1;
10662                while (readtoken() == TELIF) {
10663                        n2->nif.elsepart = stzalloc(sizeof(struct nif));
10664                        n2 = n2->nif.elsepart;
10665                        n2->type = NIF;
10666                        n2->nif.test = list(0);
10667                        if (readtoken() != TTHEN)
10668                                raise_error_unexpected_syntax(TTHEN);
10669                        n2->nif.ifpart = list(0);
10670                }
10671                if (lasttoken == TELSE)
10672                        n2->nif.elsepart = list(0);
10673                else {
10674                        n2->nif.elsepart = NULL;
10675                        tokpushback = 1;
10676                }
10677                t = TFI;
10678                break;
10679        case TWHILE:
10680        case TUNTIL: {
10681                int got;
10682                n1 = stzalloc(sizeof(struct nbinary));
10683                n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10684                n1->nbinary.ch1 = list(0);
10685                got = readtoken();
10686                if (got != TDO) {
10687                        TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
10688                                        got == TWORD ? wordtext : ""));
10689                        raise_error_unexpected_syntax(TDO);
10690                }
10691                n1->nbinary.ch2 = list(0);
10692                t = TDONE;
10693                break;
10694        }
10695        case TFOR:
10696                if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10697                        raise_error_syntax("bad for loop variable");
10698                n1 = stzalloc(sizeof(struct nfor));
10699                n1->type = NFOR;
10700                n1->nfor.var = wordtext;
10701                checkkwd = CHKKWD | CHKALIAS;
10702                if (readtoken() == TIN) {
10703                        app = &ap;
10704                        while (readtoken() == TWORD) {
10705                                n2 = stzalloc(sizeof(struct narg));
10706                                n2->type = NARG;
10707                                /*n2->narg.next = NULL; - stzalloc did it */
10708                                n2->narg.text = wordtext;
10709                                n2->narg.backquote = backquotelist;
10710                                *app = n2;
10711                                app = &n2->narg.next;
10712                        }
10713                        *app = NULL;
10714                        n1->nfor.args = ap;
10715                        if (lasttoken != TNL && lasttoken != TSEMI)
10716                                raise_error_unexpected_syntax(-1);
10717                } else {
10718                        n2 = stzalloc(sizeof(struct narg));
10719                        n2->type = NARG;
10720                        /*n2->narg.next = NULL; - stzalloc did it */
10721                        n2->narg.text = (char *)dolatstr;
10722                        /*n2->narg.backquote = NULL;*/
10723                        n1->nfor.args = n2;
10724                        /*
10725                         * Newline or semicolon here is optional (but note
10726                         * that the original Bourne shell only allowed NL).
10727                         */
10728                        if (lasttoken != TNL && lasttoken != TSEMI)
10729                                tokpushback = 1;
10730                }
10731                checkkwd = CHKNL | CHKKWD | CHKALIAS;
10732                if (readtoken() != TDO)
10733                        raise_error_unexpected_syntax(TDO);
10734                n1->nfor.body = list(0);
10735                t = TDONE;
10736                break;
10737        case TCASE:
10738                n1 = stzalloc(sizeof(struct ncase));
10739                n1->type = NCASE;
10740                if (readtoken() != TWORD)
10741                        raise_error_unexpected_syntax(TWORD);
10742                n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10743                n2->type = NARG;
10744                /*n2->narg.next = NULL; - stzalloc did it */
10745                n2->narg.text = wordtext;
10746                n2->narg.backquote = backquotelist;
10747                do {
10748                        checkkwd = CHKKWD | CHKALIAS;
10749                } while (readtoken() == TNL);
10750                if (lasttoken != TIN)
10751                        raise_error_unexpected_syntax(TIN);
10752                cpp = &n1->ncase.cases;
10753 next_case:
10754                checkkwd = CHKNL | CHKKWD;
10755                t = readtoken();
10756                while (t != TESAC) {
10757                        if (lasttoken == TLP)
10758                                readtoken();
10759                        *cpp = cp = stzalloc(sizeof(struct nclist));
10760                        cp->type = NCLIST;
10761                        app = &cp->nclist.pattern;
10762                        for (;;) {
10763                                *app = ap = stzalloc(sizeof(struct narg));
10764                                ap->type = NARG;
10765                                /*ap->narg.next = NULL; - stzalloc did it */
10766                                ap->narg.text = wordtext;
10767                                ap->narg.backquote = backquotelist;
10768                                if (readtoken() != TPIPE)
10769                                        break;
10770                                app = &ap->narg.next;
10771                                readtoken();
10772                        }
10773                        //ap->narg.next = NULL;
10774                        if (lasttoken != TRP)
10775                                raise_error_unexpected_syntax(TRP);
10776                        cp->nclist.body = list(2);
10777
10778                        cpp = &cp->nclist.next;
10779
10780                        checkkwd = CHKNL | CHKKWD;
10781                        t = readtoken();
10782                        if (t != TESAC) {
10783                                if (t != TENDCASE)
10784                                        raise_error_unexpected_syntax(TENDCASE);
10785                                goto next_case;
10786                        }
10787                }
10788                *cpp = NULL;
10789                goto redir;
10790        case TLP:
10791                n1 = stzalloc(sizeof(struct nredir));
10792                n1->type = NSUBSHELL;
10793                n1->nredir.n = list(0);
10794                /*n1->nredir.redirect = NULL; - stzalloc did it */
10795                t = TRP;
10796                break;
10797        case TBEGIN:
10798                n1 = list(0);
10799                t = TEND;
10800                break;
10801        case TWORD:
10802        case TREDIR:
10803                tokpushback = 1;
10804                return simplecmd();
10805        }
10806
10807        if (readtoken() != t)
10808                raise_error_unexpected_syntax(t);
10809
10810 redir:
10811        /* Now check for redirection which may follow command */
10812        checkkwd = CHKKWD | CHKALIAS;
10813        rpp = rpp2;
10814        while (readtoken() == TREDIR) {
10815                *rpp = n2 = redirnode;
10816                rpp = &n2->nfile.next;
10817                parsefname();
10818        }
10819        tokpushback = 1;
10820        *rpp = NULL;
10821        if (redir) {
10822                if (n1->type != NSUBSHELL) {
10823                        n2 = stzalloc(sizeof(struct nredir));
10824                        n2->type = NREDIR;
10825                        n2->nredir.n = n1;
10826                        n1 = n2;
10827                }
10828                n1->nredir.redirect = redir;
10829        }
10830        return n1;
10831}
10832
10833#if ENABLE_ASH_BASH_COMPAT
10834static int decode_dollar_squote(void)
10835{
10836        static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10837        int c, cnt;
10838        char *p;
10839        char buf[4];
10840
10841        c = pgetc();
10842        p = strchr(C_escapes, c);
10843        if (p) {
10844                buf[0] = c;
10845                p = buf;
10846                cnt = 3;
10847                if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10848                        do {
10849                                c = pgetc();
10850                                *++p = c;
10851                        } while ((unsigned char)(c - '0') <= 7 && --cnt);
10852                        pungetc();
10853                } else if (c == 'x') { /* \xHH */
10854                        do {
10855                                c = pgetc();
10856                                *++p = c;
10857                        } while (isxdigit(c) && --cnt);
10858                        pungetc();
10859                        if (cnt == 3) { /* \x but next char is "bad" */
10860                                c = 'x';
10861                                goto unrecognized;
10862                        }
10863                } else { /* simple seq like \\ or \t */
10864                        p++;
10865                }
10866                *p = '\0';
10867                p = buf;
10868                c = bb_process_escape_sequence((void*)&p);
10869        } else { /* unrecognized "\z": print both chars unless ' or " */
10870                if (c != '\'' && c != '"') {
10871 unrecognized:
10872                        c |= 0x100; /* "please encode \, then me" */
10873                }
10874        }
10875        return c;
10876}
10877#endif
10878
10879/*
10880 * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10881 * is not NULL, read a here document.  In the latter case, eofmark is the
10882 * word which marks the end of the document and striptabs is true if
10883 * leading tabs should be stripped from the document.  The argument c
10884 * is the first character of the input token or document.
10885 *
10886 * Because C does not have internal subroutines, I have simulated them
10887 * using goto's to implement the subroutine linkage.  The following macros
10888 * will run code that appears at the end of readtoken1.
10889 */
10890#define CHECKEND()      {goto checkend; checkend_return:;}
10891#define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10892#define PARSESUB()      {goto parsesub; parsesub_return:;}
10893#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10894#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10895#define PARSEARITH()    {goto parsearith; parsearith_return:;}
10896static int
10897readtoken1(int c, int syntax, char *eofmark, int striptabs)
10898{
10899        /* NB: syntax parameter fits into smallint */
10900        /* c parameter is an unsigned char or PEOF or PEOA */
10901        char *out;
10902        int len;
10903        char line[EOFMARKLEN + 1];
10904        struct nodelist *bqlist;
10905        smallint quotef;
10906        smallint dblquote;
10907        smallint oldstyle;
10908        smallint prevsyntax; /* syntax before arithmetic */
10909#if ENABLE_ASH_EXPAND_PRMT
10910        smallint pssyntax;   /* we are expanding a prompt string */
10911#endif
10912        int varnest;         /* levels of variables expansion */
10913        int arinest;         /* levels of arithmetic expansion */
10914        int parenlevel;      /* levels of parens in arithmetic */
10915        int dqvarnest;       /* levels of variables expansion within double quotes */
10916
10917        IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10918
10919#if __GNUC__
10920        /* Avoid longjmp clobbering */
10921        (void) &out;
10922        (void) &quotef;
10923        (void) &dblquote;
10924        (void) &varnest;
10925        (void) &arinest;
10926        (void) &parenlevel;
10927        (void) &dqvarnest;
10928        (void) &oldstyle;
10929        (void) &prevsyntax;
10930        (void) &syntax;
10931#endif
10932        startlinno = g_parsefile->linno;
10933        bqlist = NULL;
10934        quotef = 0;
10935        oldstyle = 0;
10936        prevsyntax = 0;
10937#if ENABLE_ASH_EXPAND_PRMT
10938        pssyntax = (syntax == PSSYNTAX);
10939        if (pssyntax)
10940                syntax = DQSYNTAX;
10941#endif
10942        dblquote = (syntax == DQSYNTAX);
10943        varnest = 0;
10944        arinest = 0;
10945        parenlevel = 0;
10946        dqvarnest = 0;
10947
10948        STARTSTACKSTR(out);
10949 loop:
10950        /* For each line, until end of word */
10951        {
10952                CHECKEND();     /* set c to PEOF if at end of here document */
10953                for (;;) {      /* until end of line or end of word */
10954                        CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
10955                        switch (SIT(c, syntax)) {
10956                        case CNL:       /* '\n' */
10957                                if (syntax == BASESYNTAX)
10958                                        goto endword;   /* exit outer loop */
10959                                USTPUTC(c, out);
10960                                g_parsefile->linno++;
10961                                if (doprompt)
10962                                        setprompt(2);
10963                                c = pgetc();
10964                                goto loop;              /* continue outer loop */
10965                        case CWORD:
10966                                USTPUTC(c, out);
10967                                break;
10968                        case CCTL:
10969                                if (eofmark == NULL || dblquote)
10970                                        USTPUTC(CTLESC, out);
10971#if ENABLE_ASH_BASH_COMPAT
10972                                if (c == '\\' && bash_dollar_squote) {
10973                                        c = decode_dollar_squote();
10974                                        if (c & 0x100) {
10975                                                USTPUTC('\\', out);
10976                                                c = (unsigned char)c;
10977                                        }
10978                                }
10979#endif
10980                                USTPUTC(c, out);
10981                                break;
10982                        case CBACK:     /* backslash */
10983                                c = pgetc_without_PEOA();
10984                                if (c == PEOF) {
10985                                        USTPUTC(CTLESC, out);
10986                                        USTPUTC('\\', out);
10987                                        pungetc();
10988                                } else if (c == '\n') {
10989                                        if (doprompt)
10990                                                setprompt(2);
10991                                } else {
10992#if ENABLE_ASH_EXPAND_PRMT
10993                                        if (c == '$' && pssyntax) {
10994                                                USTPUTC(CTLESC, out);
10995                                                USTPUTC('\\', out);
10996                                        }
10997#endif
10998                                        if (dblquote && c != '\\'
10999                                         && c != '`' && c != '$'
11000                                         && (c != '"' || eofmark != NULL)
11001                                        ) {
11002                                                USTPUTC(CTLESC, out);
11003                                                USTPUTC('\\', out);
11004                                        }
11005                                        if (SIT(c, SQSYNTAX) == CCTL)
11006                                                USTPUTC(CTLESC, out);
11007                                        USTPUTC(c, out);
11008                                        quotef = 1;
11009                                }
11010                                break;
11011                        case CSQUOTE:
11012                                syntax = SQSYNTAX;
11013 quotemark:
11014                                if (eofmark == NULL) {
11015                                        USTPUTC(CTLQUOTEMARK, out);
11016                                }
11017                                break;
11018                        case CDQUOTE:
11019                                syntax = DQSYNTAX;
11020                                dblquote = 1;
11021                                goto quotemark;
11022                        case CENDQUOTE:
11023                                IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11024                                if (eofmark != NULL && arinest == 0
11025                                 && varnest == 0
11026                                ) {
11027                                        USTPUTC(c, out);
11028                                } else {
11029                                        if (dqvarnest == 0) {
11030                                                syntax = BASESYNTAX;
11031                                                dblquote = 0;
11032                                        }
11033                                        quotef = 1;
11034                                        goto quotemark;
11035                                }
11036                                break;
11037                        case CVAR:      /* '$' */
11038                                PARSESUB();             /* parse substitution */
11039                                break;
11040                        case CENDVAR:   /* '}' */
11041                                if (varnest > 0) {
11042                                        varnest--;
11043                                        if (dqvarnest > 0) {
11044                                                dqvarnest--;
11045                                        }
11046                                        USTPUTC(CTLENDVAR, out);
11047                                } else {
11048                                        USTPUTC(c, out);
11049                                }
11050                                break;
11051#if ENABLE_SH_MATH_SUPPORT
11052                        case CLP:       /* '(' in arithmetic */
11053                                parenlevel++;
11054                                USTPUTC(c, out);
11055                                break;
11056                        case CRP:       /* ')' in arithmetic */
11057                                if (parenlevel > 0) {
11058                                        USTPUTC(c, out);
11059                                        --parenlevel;
11060                                } else {
11061                                        if (pgetc() == ')') {
11062                                                if (--arinest == 0) {
11063                                                        USTPUTC(CTLENDARI, out);
11064                                                        syntax = prevsyntax;
11065                                                        dblquote = (syntax == DQSYNTAX);
11066                                                } else
11067                                                        USTPUTC(')', out);
11068                                        } else {
11069                                                /*
11070                                                 * unbalanced parens
11071                                                 *  (don't 2nd guess - no error)
11072                                                 */
11073                                                pungetc();
11074                                                USTPUTC(')', out);
11075                                        }
11076                                }
11077                                break;
11078#endif
11079                        case CBQUOTE:   /* '`' */
11080                                PARSEBACKQOLD();
11081                                break;
11082                        case CENDFILE:
11083                                goto endword;           /* exit outer loop */
11084                        case CIGN:
11085                                break;
11086                        default:
11087                                if (varnest == 0) {
11088#if ENABLE_ASH_BASH_COMPAT
11089                                        if (c == '&') {
11090                                                if (pgetc() == '>')
11091                                                        c = 0x100 + '>'; /* flag &> */
11092                                                pungetc();
11093                                        }
11094#endif
11095                                        goto endword;   /* exit outer loop */
11096                                }
11097                                IF_ASH_ALIAS(if (c != PEOA))
11098                                        USTPUTC(c, out);
11099
11100                        }
11101                        c = pgetc_fast();
11102                } /* for (;;) */
11103        }
11104 endword:
11105#if ENABLE_SH_MATH_SUPPORT
11106        if (syntax == ARISYNTAX)
11107                raise_error_syntax("missing '))'");
11108#endif
11109        if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
11110                raise_error_syntax("unterminated quoted string");
11111        if (varnest != 0) {
11112                startlinno = g_parsefile->linno;
11113                /* { */
11114                raise_error_syntax("missing '}'");
11115        }
11116        USTPUTC('\0', out);
11117        len = out - (char *)stackblock();
11118        out = stackblock();
11119        if (eofmark == NULL) {
11120                if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
11121                 && quotef == 0
11122                ) {
11123                        if (isdigit_str9(out)) {
11124                                PARSEREDIR(); /* passed as params: out, c */
11125                                lasttoken = TREDIR;
11126                                return lasttoken;
11127                        }
11128                        /* else: non-number X seen, interpret it
11129                         * as "NNNX>file" = "NNNX >file" */
11130                }
11131                pungetc();
11132        }
11133        quoteflag = quotef;
11134        backquotelist = bqlist;
11135        grabstackblock(len);
11136        wordtext = out;
11137        lasttoken = TWORD;
11138        return lasttoken;
11139/* end of readtoken routine */
11140
11141/*
11142 * Check to see whether we are at the end of the here document.  When this
11143 * is called, c is set to the first character of the next input line.  If
11144 * we are at the end of the here document, this routine sets the c to PEOF.
11145 */
11146checkend: {
11147        if (eofmark) {
11148#if ENABLE_ASH_ALIAS
11149                if (c == PEOA)
11150                        c = pgetc_without_PEOA();
11151#endif
11152                if (striptabs) {
11153                        while (c == '\t') {
11154                                c = pgetc_without_PEOA();
11155                        }
11156                }
11157                if (c == *eofmark) {
11158                        if (pfgets(line, sizeof(line)) != NULL) {
11159                                char *p, *q;
11160
11161                                p = line;
11162                                for (q = eofmark + 1; *q && *p == *q; p++, q++)
11163                                        continue;
11164                                if (*p == '\n' && *q == '\0') {
11165                                        c = PEOF;
11166                                        g_parsefile->linno++;
11167                                        needprompt = doprompt;
11168                                } else {
11169                                        pushstring(line, NULL);
11170                                }
11171                        }
11172                }
11173        }
11174        goto checkend_return;
11175}
11176
11177/*
11178 * Parse a redirection operator.  The variable "out" points to a string
11179 * specifying the fd to be redirected.  The variable "c" contains the
11180 * first character of the redirection operator.
11181 */
11182parseredir: {
11183        /* out is already checked to be a valid number or "" */
11184        int fd = (*out == '\0' ? -1 : atoi(out));
11185        union node *np;
11186
11187        np = stzalloc(sizeof(struct nfile));
11188        if (c == '>') {
11189                np->nfile.fd = 1;
11190                c = pgetc();
11191                if (c == '>')
11192                        np->type = NAPPEND;
11193                else if (c == '|')
11194                        np->type = NCLOBBER;
11195                else if (c == '&')
11196                        np->type = NTOFD;
11197                        /* it also can be NTO2 (>&file), but we can't figure it out yet */
11198                else {
11199                        np->type = NTO;
11200                        pungetc();
11201                }
11202        }
11203#if ENABLE_ASH_BASH_COMPAT
11204        else if (c == 0x100 + '>') { /* this flags &> redirection */
11205                np->nfile.fd = 1;
11206                pgetc(); /* this is '>', no need to check */
11207                np->type = NTO2;
11208        }
11209#endif
11210        else { /* c == '<' */
11211                /*np->nfile.fd = 0; - stzalloc did it */
11212                c = pgetc();
11213                switch (c) {
11214                case '<':
11215                        if (sizeof(struct nfile) != sizeof(struct nhere)) {
11216                                np = stzalloc(sizeof(struct nhere));
11217                                /*np->nfile.fd = 0; - stzalloc did it */
11218                        }
11219                        np->type = NHERE;
11220                        heredoc = stzalloc(sizeof(struct heredoc));
11221                        heredoc->here = np;
11222                        c = pgetc();
11223                        if (c == '-') {
11224                                heredoc->striptabs = 1;
11225                        } else {
11226                                /*heredoc->striptabs = 0; - stzalloc did it */
11227                                pungetc();
11228                        }
11229                        break;
11230
11231                case '&':
11232                        np->type = NFROMFD;
11233                        break;
11234
11235                case '>':
11236                        np->type = NFROMTO;
11237                        break;
11238
11239                default:
11240                        np->type = NFROM;
11241                        pungetc();
11242                        break;
11243                }
11244        }
11245        if (fd >= 0)
11246                np->nfile.fd = fd;
11247        redirnode = np;
11248        goto parseredir_return;
11249}
11250
11251/*
11252 * Parse a substitution.  At this point, we have read the dollar sign
11253 * and nothing else.
11254 */
11255
11256/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11257 * (assuming ascii char codes, as the original implementation did) */
11258#define is_special(c) \
11259        (((unsigned)(c) - 33 < 32) \
11260                        && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11261parsesub: {
11262        unsigned char subtype;
11263        int typeloc;
11264        int flags;
11265        char *p;
11266        static const char types[] ALIGN1 = "}-+?=";
11267
11268        c = pgetc();
11269        if (c > 255 /* PEOA or PEOF */
11270         || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11271        ) {
11272#if ENABLE_ASH_BASH_COMPAT
11273                if (c == '\'')
11274                        bash_dollar_squote = 1;
11275                else
11276#endif
11277                        USTPUTC('$', out);
11278                pungetc();
11279        } else if (c == '(') {  /* $(command) or $((arith)) */
11280                if (pgetc() == '(') {
11281#if ENABLE_SH_MATH_SUPPORT
11282                        PARSEARITH();
11283#else
11284                        raise_error_syntax("you disabled math support for $((arith)) syntax");
11285#endif
11286                } else {
11287                        pungetc();
11288                        PARSEBACKQNEW();
11289                }
11290        } else {
11291                USTPUTC(CTLVAR, out);
11292                typeloc = out - (char *)stackblock();
11293                USTPUTC(VSNORMAL, out);
11294                subtype = VSNORMAL;
11295                if (c == '{') {
11296                        c = pgetc();
11297                        if (c == '#') {
11298                                c = pgetc();
11299                                if (c == '}')
11300                                        c = '#';
11301                                else
11302                                        subtype = VSLENGTH;
11303                        } else
11304                                subtype = 0;
11305                }
11306                if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
11307                        do {
11308                                STPUTC(c, out);
11309                                c = pgetc();
11310                        } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
11311                } else if (isdigit(c)) {
11312                        do {
11313                                STPUTC(c, out);
11314                                c = pgetc();
11315                        } while (isdigit(c));
11316                } else if (is_special(c)) {
11317                        USTPUTC(c, out);
11318                        c = pgetc();
11319                } else {
11320 badsub:
11321                        raise_error_syntax("bad substitution");
11322                }
11323                if (c != '}' && subtype == VSLENGTH)
11324                        goto badsub;
11325
11326                STPUTC('=', out);
11327                flags = 0;
11328                if (subtype == 0) {
11329                        switch (c) {
11330                        case ':':
11331                                c = pgetc();
11332#if ENABLE_ASH_BASH_COMPAT
11333                                if (c == ':' || c == '$' || isdigit(c)) {
11334                                        pungetc();
11335                                        subtype = VSSUBSTR;
11336                                        break;
11337                                }
11338#endif
11339                                flags = VSNUL;
11340                                /*FALLTHROUGH*/
11341                        default:
11342                                p = strchr(types, c);
11343                                if (p == NULL)
11344                                        goto badsub;
11345                                subtype = p - types + VSNORMAL;
11346                                break;
11347                        case '%':
11348                        case '#': {
11349                                int cc = c;
11350                                subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
11351                                c = pgetc();
11352                                if (c == cc)
11353                                        subtype++;
11354                                else
11355                                        pungetc();
11356                                break;
11357                        }
11358#if ENABLE_ASH_BASH_COMPAT
11359                        case '/':
11360                                subtype = VSREPLACE;
11361                                c = pgetc();
11362                                if (c == '/')
11363                                        subtype++; /* VSREPLACEALL */
11364                                else
11365                                        pungetc();
11366                                break;
11367#endif
11368                        }
11369                } else {
11370                        pungetc();
11371                }
11372                if (dblquote || arinest)
11373                        flags |= VSQUOTE;
11374                ((unsigned char *)stackblock())[typeloc] = subtype | flags;
11375                if (subtype != VSNORMAL) {
11376                        varnest++;
11377                        if (dblquote || arinest) {
11378                                dqvarnest++;
11379                        }
11380                }
11381        }
11382        goto parsesub_return;
11383}
11384
11385/*
11386 * Called to parse command substitutions.  Newstyle is set if the command
11387 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11388 * list of commands (passed by reference), and savelen is the number of
11389 * characters on the top of the stack which must be preserved.
11390 */
11391parsebackq: {
11392        struct nodelist **nlpp;
11393        smallint savepbq;
11394        union node *n;
11395        char *volatile str;
11396        struct jmploc jmploc;
11397        struct jmploc *volatile savehandler;
11398        size_t savelen;
11399        smallint saveprompt = 0;
11400
11401#ifdef __GNUC__
11402        (void) &saveprompt;
11403#endif
11404        savepbq = parsebackquote;
11405        if (setjmp(jmploc.loc)) {
11406                free(str);
11407                parsebackquote = 0;
11408                exception_handler = savehandler;
11409                longjmp(exception_handler->loc, 1);
11410        }
11411        INT_OFF;
11412        str = NULL;
11413        savelen = out - (char *)stackblock();
11414        if (savelen > 0) {
11415                str = ckmalloc(savelen);
11416                memcpy(str, stackblock(), savelen);
11417        }
11418        savehandler = exception_handler;
11419        exception_handler = &jmploc;
11420        INT_ON;
11421        if (oldstyle) {
11422                /* We must read until the closing backquote, giving special
11423                   treatment to some slashes, and then push the string and
11424                   reread it as input, interpreting it normally.  */
11425                char *pout;
11426                int pc;
11427                size_t psavelen;
11428                char *pstr;
11429
11430
11431                STARTSTACKSTR(pout);
11432                for (;;) {
11433                        if (needprompt) {
11434                                setprompt(2);
11435                        }
11436                        pc = pgetc();
11437                        switch (pc) {
11438                        case '`':
11439                                goto done;
11440
11441                        case '\\':
11442                                pc = pgetc();
11443                                if (pc == '\n') {
11444                                        g_parsefile->linno++;
11445                                        if (doprompt)
11446                                                setprompt(2);
11447                                        /*
11448                                         * If eating a newline, avoid putting
11449                                         * the newline into the new character
11450                                         * stream (via the STPUTC after the
11451                                         * switch).
11452                                         */
11453                                        continue;
11454                                }
11455                                if (pc != '\\' && pc != '`' && pc != '$'
11456                                 && (!dblquote || pc != '"')
11457                                ) {
11458                                        STPUTC('\\', pout);
11459                                }
11460                                if (pc <= 255 /* not PEOA or PEOF */) {
11461                                        break;
11462                                }
11463                                /* fall through */
11464
11465                        case PEOF:
11466                        IF_ASH_ALIAS(case PEOA:)
11467                                startlinno = g_parsefile->linno;
11468                                raise_error_syntax("EOF in backquote substitution");
11469
11470                        case '\n':
11471                                g_parsefile->linno++;
11472                                needprompt = doprompt;
11473                                break;
11474
11475                        default:
11476                                break;
11477                        }
11478                        STPUTC(pc, pout);
11479                }
11480 done:
11481                STPUTC('\0', pout);
11482                psavelen = pout - (char *)stackblock();
11483                if (psavelen > 0) {
11484                        pstr = grabstackstr(pout);
11485                        setinputstring(pstr);
11486                }
11487        }
11488        nlpp = &bqlist;
11489        while (*nlpp)
11490                nlpp = &(*nlpp)->next;
11491        *nlpp = stzalloc(sizeof(**nlpp));
11492        /* (*nlpp)->next = NULL; - stzalloc did it */
11493        parsebackquote = oldstyle;
11494
11495        if (oldstyle) {
11496                saveprompt = doprompt;
11497                doprompt = 0;
11498        }
11499
11500        n = list(2);
11501
11502        if (oldstyle)
11503                doprompt = saveprompt;
11504        else if (readtoken() != TRP)
11505                raise_error_unexpected_syntax(TRP);
11506
11507        (*nlpp)->n = n;
11508        if (oldstyle) {
11509                /*
11510                 * Start reading from old file again, ignoring any pushed back
11511                 * tokens left from the backquote parsing
11512                 */
11513                popfile();
11514                tokpushback = 0;
11515        }
11516        while (stackblocksize() <= savelen)
11517                growstackblock();
11518        STARTSTACKSTR(out);
11519        if (str) {
11520                memcpy(out, str, savelen);
11521                STADJUST(savelen, out);
11522                INT_OFF;
11523                free(str);
11524                str = NULL;
11525                INT_ON;
11526        }
11527        parsebackquote = savepbq;
11528        exception_handler = savehandler;
11529        if (arinest || dblquote)
11530                USTPUTC(CTLBACKQ | CTLQUOTE, out);
11531        else
11532                USTPUTC(CTLBACKQ, out);
11533        if (oldstyle)
11534                goto parsebackq_oldreturn;
11535        goto parsebackq_newreturn;
11536}
11537
11538#if ENABLE_SH_MATH_SUPPORT
11539/*
11540 * Parse an arithmetic expansion (indicate start of one and set state)
11541 */
11542parsearith: {
11543        if (++arinest == 1) {
11544                prevsyntax = syntax;
11545                syntax = ARISYNTAX;
11546                USTPUTC(CTLARI, out);
11547                if (dblquote)
11548                        USTPUTC('"', out);
11549                else
11550                        USTPUTC(' ', out);
11551        } else {
11552                /*
11553                 * we collapse embedded arithmetic expansion to
11554                 * parenthesis, which should be equivalent
11555                 */
11556                USTPUTC('(', out);
11557        }
11558        goto parsearith_return;
11559}
11560#endif
11561
11562} /* end of readtoken */
11563
11564/*
11565 * Read the next input token.
11566 * If the token is a word, we set backquotelist to the list of cmds in
11567 *      backquotes.  We set quoteflag to true if any part of the word was
11568 *      quoted.
11569 * If the token is TREDIR, then we set redirnode to a structure containing
11570 *      the redirection.
11571 * In all cases, the variable startlinno is set to the number of the line
11572 *      on which the token starts.
11573 *
11574 * [Change comment:  here documents and internal procedures]
11575 * [Readtoken shouldn't have any arguments.  Perhaps we should make the
11576 *  word parsing code into a separate routine.  In this case, readtoken
11577 *  doesn't need to have any internal procedures, but parseword does.
11578 *  We could also make parseoperator in essence the main routine, and
11579 *  have parseword (readtoken1?) handle both words and redirection.]
11580 */
11581#define NEW_xxreadtoken
11582#ifdef NEW_xxreadtoken
11583/* singles must be first! */
11584static const char xxreadtoken_chars[7] ALIGN1 = {
11585        '\n', '(', ')', /* singles */
11586        '&', '|', ';',  /* doubles */
11587        0
11588};
11589
11590#define xxreadtoken_singles 3
11591#define xxreadtoken_doubles 3
11592
11593static const char xxreadtoken_tokens[] ALIGN1 = {
11594        TNL, TLP, TRP,          /* only single occurrence allowed */
11595        TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11596        TEOF,                   /* corresponds to trailing nul */
11597        TAND, TOR, TENDCASE     /* if double occurrence */
11598};
11599
11600static int
11601xxreadtoken(void)
11602{
11603        int c;
11604
11605        if (tokpushback) {
11606                tokpushback = 0;
11607                return lasttoken;
11608        }
11609        if (needprompt) {
11610                setprompt(2);
11611        }
11612        startlinno = g_parsefile->linno;
11613        for (;;) {                      /* until token or start of word found */
11614                c = pgetc_fast();
11615                if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
11616                        continue;
11617
11618                if (c == '#') {
11619                        while ((c = pgetc()) != '\n' && c != PEOF)
11620                                continue;
11621                        pungetc();
11622                } else if (c == '\\') {
11623                        if (pgetc() != '\n') {
11624                                pungetc();
11625                                break; /* return readtoken1(...) */
11626                        }
11627                        startlinno = ++g_parsefile->linno;
11628                        if (doprompt)
11629                                setprompt(2);
11630                } else {
11631                        const char *p;
11632
11633                        p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11634                        if (c != PEOF) {
11635                                if (c == '\n') {
11636                                        g_parsefile->linno++;
11637                                        needprompt = doprompt;
11638                                }
11639
11640                                p = strchr(xxreadtoken_chars, c);
11641                                if (p == NULL)
11642                                        break; /* return readtoken1(...) */
11643
11644                                if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11645                                        int cc = pgetc();
11646                                        if (cc == c) {    /* double occurrence? */
11647                                                p += xxreadtoken_doubles + 1;
11648                                        } else {
11649                                                pungetc();
11650#if ENABLE_ASH_BASH_COMPAT
11651                                                if (c == '&' && cc == '>') /* &> */
11652                                                        break; /* return readtoken1(...) */
11653#endif
11654                                        }
11655                                }
11656                        }
11657                        lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11658                        return lasttoken;
11659                }
11660        } /* for (;;) */
11661
11662        return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11663}
11664#else /* old xxreadtoken */
11665#define RETURN(token)   return lasttoken = token
11666static int
11667xxreadtoken(void)
11668{
11669        int c;
11670
11671        if (tokpushback) {
11672                tokpushback = 0;
11673                return lasttoken;
11674        }
11675        if (needprompt) {
11676                setprompt(2);
11677        }
11678        startlinno = g_parsefile->linno;
11679        for (;;) {      /* until token or start of word found */
11680                c = pgetc_fast();
11681                switch (c) {
11682                case ' ': case '\t':
11683                IF_ASH_ALIAS(case PEOA:)
11684                        continue;
11685                case '#':
11686                        while ((c = pgetc()) != '\n' && c != PEOF)
11687                                continue;
11688                        pungetc();
11689                        continue;
11690                case '\\':
11691                        if (pgetc() == '\n') {
11692                                startlinno = ++g_parsefile->linno;
11693                                if (doprompt)
11694                                        setprompt(2);
11695                                continue;
11696                        }
11697                        pungetc();
11698                        goto breakloop;
11699                case '\n':
11700                        g_parsefile->linno++;
11701                        needprompt = doprompt;
11702                        RETURN(TNL);
11703                case PEOF:
11704                        RETURN(TEOF);
11705                case '&':
11706                        if (pgetc() == '&')
11707                                RETURN(TAND);
11708                        pungetc();
11709                        RETURN(TBACKGND);
11710                case '|':
11711                        if (pgetc() == '|')
11712                                RETURN(TOR);
11713                        pungetc();
11714                        RETURN(TPIPE);
11715                case ';':
11716                        if (pgetc() == ';')
11717                                RETURN(TENDCASE);
11718                        pungetc();
11719                        RETURN(TSEMI);
11720                case '(':
11721                        RETURN(TLP);
11722                case ')':
11723                        RETURN(TRP);
11724                default:
11725                        goto breakloop;
11726                }
11727        }
11728 breakloop:
11729        return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11730#undef RETURN
11731}
11732#endif /* old xxreadtoken */
11733
11734static int
11735readtoken(void)
11736{
11737        int t;
11738#if DEBUG
11739        smallint alreadyseen = tokpushback;
11740#endif
11741
11742#if ENABLE_ASH_ALIAS
11743 top:
11744#endif
11745
11746        t = xxreadtoken();
11747
11748        /*
11749         * eat newlines
11750         */
11751        if (checkkwd & CHKNL) {
11752                while (t == TNL) {
11753                        parseheredoc();
11754                        t = xxreadtoken();
11755                }
11756        }
11757
11758        if (t != TWORD || quoteflag) {
11759                goto out;
11760        }
11761
11762        /*
11763         * check for keywords
11764         */
11765        if (checkkwd & CHKKWD) {
11766                const char *const *pp;
11767
11768                pp = findkwd(wordtext);
11769                if (pp) {
11770                        lasttoken = t = pp - tokname_array;
11771                        TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
11772                        goto out;
11773                }
11774        }
11775
11776        if (checkkwd & CHKALIAS) {
11777#if ENABLE_ASH_ALIAS
11778                struct alias *ap;
11779                ap = lookupalias(wordtext, 1);
11780                if (ap != NULL) {
11781                        if (*ap->val) {
11782                                pushstring(ap->val, ap);
11783                        }
11784                        goto top;
11785                }
11786#endif
11787        }
11788 out:
11789        checkkwd = 0;
11790#if DEBUG
11791        if (!alreadyseen)
11792                TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
11793        else
11794                TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
11795#endif
11796        return t;
11797}
11798
11799static char
11800peektoken(void)
11801{
11802        int t;
11803
11804        t = readtoken();
11805        tokpushback = 1;
11806        return tokname_array[t][0];
11807}
11808
11809/*
11810 * Read and parse a command.  Returns NODE_EOF on end of file.
11811 * (NULL is a valid parse tree indicating a blank line.)
11812 */
11813static union node *
11814parsecmd(int interact)
11815{
11816        int t;
11817
11818        tokpushback = 0;
11819        doprompt = interact;
11820        if (doprompt)
11821                setprompt(doprompt);
11822        needprompt = 0;
11823        t = readtoken();
11824        if (t == TEOF)
11825                return NODE_EOF;
11826        if (t == TNL)
11827                return NULL;
11828        tokpushback = 1;
11829        return list(1);
11830}
11831
11832/*
11833 * Input any here documents.
11834 */
11835static void
11836parseheredoc(void)
11837{
11838        struct heredoc *here;
11839        union node *n;
11840
11841        here = heredoclist;
11842        heredoclist = NULL;
11843
11844        while (here) {
11845                if (needprompt) {
11846                        setprompt(2);
11847                }
11848                readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11849                                here->eofmark, here->striptabs);
11850                n = stzalloc(sizeof(struct narg));
11851                n->narg.type = NARG;
11852                /*n->narg.next = NULL; - stzalloc did it */
11853                n->narg.text = wordtext;
11854                n->narg.backquote = backquotelist;
11855                here->here->nhere.doc = n;
11856                here = here->next;
11857        }
11858}
11859
11860
11861/*
11862 * called by editline -- any expansions to the prompt should be added here.
11863 */
11864#if ENABLE_ASH_EXPAND_PRMT
11865static const char *
11866expandstr(const char *ps)
11867{
11868        union node n;
11869
11870        /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
11871         * and token processing _can_ alter it (delete NULs etc). */
11872        setinputstring((char *)ps);
11873        readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11874        popfile();
11875
11876        n.narg.type = NARG;
11877        n.narg.next = NULL;
11878        n.narg.text = wordtext;
11879        n.narg.backquote = backquotelist;
11880
11881        expandarg(&n, NULL, 0);
11882        return stackblock();
11883}
11884#endif
11885
11886/*
11887 * Execute a command or commands contained in a string.
11888 */
11889static int
11890evalstring(char *s, int mask)
11891{
11892        union node *n;
11893        struct stackmark smark;
11894        int skip;
11895
11896        setinputstring(s);
11897        setstackmark(&smark);
11898
11899        skip = 0;
11900        while ((n = parsecmd(0)) != NODE_EOF) {
11901                evaltree(n, 0);
11902                popstackmark(&smark);
11903                skip = evalskip;
11904                if (skip)
11905                        break;
11906        }
11907        popfile();
11908
11909        skip &= mask;
11910        evalskip = skip;
11911        return skip;
11912}
11913
11914/*
11915 * The eval command.
11916 */
11917static int FAST_FUNC
11918evalcmd(int argc UNUSED_PARAM, char **argv)
11919{
11920        char *p;
11921        char *concat;
11922
11923        if (argv[1]) {
11924                p = argv[1];
11925                argv += 2;
11926                if (argv[0]) {
11927                        STARTSTACKSTR(concat);
11928                        for (;;) {
11929                                concat = stack_putstr(p, concat);
11930                                p = *argv++;
11931                                if (p == NULL)
11932                                        break;
11933                                STPUTC(' ', concat);
11934                        }
11935                        STPUTC('\0', concat);
11936                        p = grabstackstr(concat);
11937                }
11938                evalstring(p, ~SKIPEVAL);
11939
11940        }
11941        return exitstatus;
11942}
11943
11944/*
11945 * Read and execute commands.
11946 * "Top" is nonzero for the top level command loop;
11947 * it turns on prompting if the shell is interactive.
11948 */
11949static int
11950cmdloop(int top)
11951{
11952        union node *n;
11953        struct stackmark smark;
11954        int inter;
11955        int numeof = 0;
11956
11957        TRACE(("cmdloop(%d) called\n", top));
11958        for (;;) {
11959                int skip;
11960
11961                setstackmark(&smark);
11962#if JOBS
11963                if (doing_jobctl)
11964                        showjobs(stderr, SHOW_CHANGED);
11965#endif
11966                inter = 0;
11967                if (iflag && top) {
11968                        inter++;
11969#if ENABLE_ASH_MAIL
11970                        chkmail();
11971#endif
11972                }
11973                n = parsecmd(inter);
11974#if DEBUG
11975                if (DEBUG > 2 && debug && (n != NODE_EOF))
11976                        showtree(n);
11977#endif
11978                if (n == NODE_EOF) {
11979                        if (!top || numeof >= 50)
11980                                break;
11981                        if (!stoppedjobs()) {
11982                                if (!Iflag)
11983                                        break;
11984                                out2str("\nUse \"exit\" to leave shell.\n");
11985                        }
11986                        numeof++;
11987                } else if (nflag == 0) {
11988                        /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11989                        job_warning >>= 1;
11990                        numeof = 0;
11991                        evaltree(n, 0);
11992                }
11993                popstackmark(&smark);
11994                skip = evalskip;
11995
11996                if (skip) {
11997                        evalskip = 0;
11998                        return skip & SKIPEVAL;
11999                }
12000        }
12001        return 0;
12002}
12003
12004/*
12005 * Take commands from a file.  To be compatible we should do a path
12006 * search for the file, which is necessary to find sub-commands.
12007 */
12008static char *
12009find_dot_file(char *name)
12010{
12011        char *fullname;
12012        const char *path = pathval();
12013        struct stat statb;
12014
12015        /* don't try this for absolute or relative paths */
12016        if (strchr(name, '/'))
12017                return name;
12018
12019        /* IIRC standards do not say whether . is to be searched.
12020         * And it is even smaller this way, making it unconditional for now:
12021         */
12022        if (1) { /* ENABLE_ASH_BASH_COMPAT */
12023                fullname = name;
12024                goto try_cur_dir;
12025        }
12026
12027        while ((fullname = path_advance(&path, name)) != NULL) {
12028 try_cur_dir:
12029                if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12030                        /*
12031                         * Don't bother freeing here, since it will
12032                         * be freed by the caller.
12033                         */
12034                        return fullname;
12035                }
12036                if (fullname != name)
12037                        stunalloc(fullname);
12038        }
12039
12040        /* not found in the PATH */
12041        ash_msg_and_raise_error("%s: not found", name);
12042        /* NOTREACHED */
12043}
12044
12045static int FAST_FUNC
12046dotcmd(int argc, char **argv)
12047{
12048        char *fullname;
12049        struct strlist *sp;
12050        volatile struct shparam saveparam;
12051
12052        for (sp = cmdenviron; sp; sp = sp->next)
12053                setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
12054
12055        if (!argv[1]) {
12056                /* bash says: "bash: .: filename argument required" */
12057                return 2; /* bash compat */
12058        }
12059
12060        /* "false; . empty_file; echo $?" should print 0, not 1: */
12061        exitstatus = 0;
12062
12063        fullname = find_dot_file(argv[1]);
12064
12065        argv += 2;
12066        argc -= 2;
12067        if (argc) { /* argc > 0, argv[0] != NULL */
12068                saveparam = shellparam;
12069                shellparam.malloced = 0;
12070                shellparam.nparam = argc;
12071                shellparam.p = argv;
12072        };
12073
12074        setinputfile(fullname, INPUT_PUSH_FILE);
12075        commandname = fullname;
12076        cmdloop(0);
12077        popfile();
12078
12079        if (argc) {
12080                freeparam(&shellparam);
12081                shellparam = saveparam;
12082        };
12083
12084        return exitstatus;
12085}
12086
12087static int FAST_FUNC
12088exitcmd(int argc UNUSED_PARAM, char **argv)
12089{
12090        if (stoppedjobs())
12091                return 0;
12092        if (argv[1])
12093                exitstatus = number(argv[1]);
12094        raise_exception(EXEXIT);
12095        /* NOTREACHED */
12096}
12097
12098/*
12099 * Read a file containing shell functions.
12100 */
12101static void
12102readcmdfile(char *name)
12103{
12104        setinputfile(name, INPUT_PUSH_FILE);
12105        cmdloop(0);
12106        popfile();
12107}
12108
12109
12110/* ============ find_command inplementation */
12111
12112/*
12113 * Resolve a command name.  If you change this routine, you may have to
12114 * change the shellexec routine as well.
12115 */
12116static void
12117find_command(char *name, struct cmdentry *entry, int act, const char *path)
12118{
12119        struct tblentry *cmdp;
12120        int idx;
12121        int prev;
12122        char *fullname;
12123        struct stat statb;
12124        int e;
12125        int updatetbl;
12126        struct builtincmd *bcmd;
12127
12128        /* If name contains a slash, don't use PATH or hash table */
12129        if (strchr(name, '/') != NULL) {
12130                entry->u.index = -1;
12131                if (act & DO_ABS) {
12132                        while (stat(name, &statb) < 0) {
12133#ifdef SYSV
12134                                if (errno == EINTR)
12135                                        continue;
12136#endif
12137                                entry->cmdtype = CMDUNKNOWN;
12138                                return;
12139                        }
12140                }
12141                entry->cmdtype = CMDNORMAL;
12142                return;
12143        }
12144
12145/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12146
12147        updatetbl = (path == pathval());
12148        if (!updatetbl) {
12149                act |= DO_ALTPATH;
12150                if (strstr(path, "%builtin") != NULL)
12151                        act |= DO_ALTBLTIN;
12152        }
12153
12154        /* If name is in the table, check answer will be ok */
12155        cmdp = cmdlookup(name, 0);
12156        if (cmdp != NULL) {
12157                int bit;
12158
12159                switch (cmdp->cmdtype) {
12160                default:
12161#if DEBUG
12162                        abort();
12163#endif
12164                case CMDNORMAL:
12165                        bit = DO_ALTPATH;
12166                        break;
12167                case CMDFUNCTION:
12168                        bit = DO_NOFUNC;
12169                        break;
12170                case CMDBUILTIN:
12171                        bit = DO_ALTBLTIN;
12172                        break;
12173                }
12174                if (act & bit) {
12175                        updatetbl = 0;
12176                        cmdp = NULL;
12177                } else if (cmdp->rehash == 0)
12178                        /* if not invalidated by cd, we're done */
12179                        goto success;
12180        }
12181
12182        /* If %builtin not in path, check for builtin next */
12183        bcmd = find_builtin(name);
12184        if (bcmd) {
12185                if (IS_BUILTIN_REGULAR(bcmd))
12186                        goto builtin_success;
12187                if (act & DO_ALTPATH) {
12188                        if (!(act & DO_ALTBLTIN))
12189                                goto builtin_success;
12190                } else if (builtinloc <= 0) {
12191                        goto builtin_success;
12192                }
12193        }
12194
12195#if ENABLE_FEATURE_SH_STANDALONE
12196        {
12197                int applet_no = find_applet_by_name(name);
12198                if (applet_no >= 0) {
12199                        entry->cmdtype = CMDNORMAL;
12200                        entry->u.index = -2 - applet_no;
12201                        return;
12202                }
12203        }
12204#endif
12205
12206        /* We have to search path. */
12207        prev = -1;              /* where to start */
12208        if (cmdp && cmdp->rehash) {     /* doing a rehash */
12209                if (cmdp->cmdtype == CMDBUILTIN)
12210                        prev = builtinloc;
12211                else
12212                        prev = cmdp->param.index;
12213        }
12214
12215        e = ENOENT;
12216        idx = -1;
12217 loop:
12218        while ((fullname = path_advance(&path, name)) != NULL) {
12219                stunalloc(fullname);
12220                /* NB: code below will still use fullname
12221                 * despite it being "unallocated" */
12222                idx++;
12223                if (pathopt) {
12224                        if (prefix(pathopt, "builtin")) {
12225                                if (bcmd)
12226                                        goto builtin_success;
12227                                continue;
12228                        }
12229                        if ((act & DO_NOFUNC)
12230                         || !prefix(pathopt, "func")
12231                        ) {     /* ignore unimplemented options */
12232                                continue;
12233                        }
12234                }
12235                /* if rehash, don't redo absolute path names */
12236                if (fullname[0] == '/' && idx <= prev) {
12237                        if (idx < prev)
12238                                continue;
12239                        TRACE(("searchexec \"%s\": no change\n", name));
12240                        goto success;
12241                }
12242                while (stat(fullname, &statb) < 0) {
12243#ifdef SYSV
12244                        if (errno == EINTR)
12245                                continue;
12246#endif
12247                        if (errno != ENOENT && errno != ENOTDIR)
12248                                e = errno;
12249                        goto loop;
12250                }
12251                e = EACCES;     /* if we fail, this will be the error */
12252                if (!S_ISREG(statb.st_mode))
12253                        continue;
12254                if (pathopt) {          /* this is a %func directory */
12255                        stalloc(strlen(fullname) + 1);
12256                        /* NB: stalloc will return space pointed by fullname
12257                         * (because we don't have any intervening allocations
12258                         * between stunalloc above and this stalloc) */
12259                        readcmdfile(fullname);
12260                        cmdp = cmdlookup(name, 0);
12261                        if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12262                                ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12263                        stunalloc(fullname);
12264                        goto success;
12265                }
12266                TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12267                if (!updatetbl) {
12268                        entry->cmdtype = CMDNORMAL;
12269                        entry->u.index = idx;
12270                        return;
12271                }
12272                INT_OFF;
12273                cmdp = cmdlookup(name, 1);
12274                cmdp->cmdtype = CMDNORMAL;
12275                cmdp->param.index = idx;
12276                INT_ON;
12277                goto success;
12278        }
12279
12280        /* We failed.  If there was an entry for this command, delete it */
12281        if (cmdp && updatetbl)
12282                delete_cmd_entry();
12283        if (act & DO_ERR)
12284                ash_msg("%s: %s", name, errmsg(e, "not found"));
12285        entry->cmdtype = CMDUNKNOWN;
12286        return;
12287
12288 builtin_success:
12289        if (!updatetbl) {
12290                entry->cmdtype = CMDBUILTIN;
12291                entry->u.cmd = bcmd;
12292                return;
12293        }
12294        INT_OFF;
12295        cmdp = cmdlookup(name, 1);
12296        cmdp->cmdtype = CMDBUILTIN;
12297        cmdp->param.cmd = bcmd;
12298        INT_ON;
12299 success:
12300        cmdp->rehash = 0;
12301        entry->cmdtype = cmdp->cmdtype;
12302        entry->u = cmdp->param;
12303}
12304
12305
12306/* ============ trap.c */
12307
12308/*
12309 * The trap builtin.
12310 */
12311static int FAST_FUNC
12312trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12313{
12314        char *action;
12315        char **ap;
12316        int signo, exitcode;
12317
12318        nextopt(nullstr);
12319        ap = argptr;
12320        if (!*ap) {
12321                for (signo = 0; signo < NSIG; signo++) {
12322                        char *tr = trap_ptr[signo];
12323                        if (tr) {
12324                                /* note: bash adds "SIG", but only if invoked
12325                                 * as "bash". If called as "sh", or if set -o posix,
12326                                 * then it prints short signal names.
12327                                 * We are printing short names: */
12328                                out1fmt("trap -- %s %s\n",
12329                                                single_quote(tr),
12330                                                get_signame(signo));
12331                /* trap_ptr != trap only if we are in special-cased `trap` code.
12332                 * In this case, we will exit very soon, no need to free(). */
12333                                /* if (trap_ptr != trap && tp[0]) */
12334                                /*      free(tr); */
12335                        }
12336                }
12337                /*
12338                if (trap_ptr != trap) {
12339                        free(trap_ptr);
12340                        trap_ptr = trap;
12341                }
12342                */
12343                return 0;
12344        }
12345
12346        action = NULL;
12347        if (ap[1])
12348                action = *ap++;
12349        exitcode = 0;
12350        while (*ap) {
12351                signo = get_signum(*ap);
12352                if (signo < 0) {
12353                        /* Mimic bash message exactly */
12354                        ash_msg("%s: invalid signal specification", *ap);
12355                        exitcode = 1;
12356                        goto next;
12357                }
12358                INT_OFF;
12359                if (action) {
12360                        if (LONE_DASH(action))
12361                                action = NULL;
12362                        else
12363                                action = ckstrdup(action);
12364                }
12365                free(trap[signo]);
12366                if (action)
12367                        may_have_traps = 1;
12368                trap[signo] = action;
12369                if (signo != 0)
12370                        setsignal(signo);
12371                INT_ON;
12372 next:
12373                ap++;
12374        }
12375        return exitcode;
12376}
12377
12378
12379/* ============ Builtins */
12380
12381#if !ENABLE_FEATURE_SH_EXTRA_QUIET
12382/*
12383 * Lists available builtins
12384 */
12385static int FAST_FUNC
12386helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12387{
12388        unsigned col;
12389        unsigned i;
12390
12391        out1fmt(
12392                "Built-in commands:\n"
12393                "------------------\n");
12394        for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12395                col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12396                                        builtintab[i].name + 1);
12397                if (col > 60) {
12398                        out1fmt("\n");
12399                        col = 0;
12400                }
12401        }
12402#if ENABLE_FEATURE_SH_STANDALONE
12403        {
12404                const char *a = applet_names;
12405                while (*a) {
12406                        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12407                        if (col > 60) {
12408                                out1fmt("\n");
12409                                col = 0;
12410                        }
12411                        a += strlen(a) + 1;
12412                }
12413        }
12414#endif
12415        out1fmt("\n\n");
12416        return EXIT_SUCCESS;
12417}
12418#endif /* FEATURE_SH_EXTRA_QUIET */
12419
12420/*
12421 * The export and readonly commands.
12422 */
12423static int FAST_FUNC
12424exportcmd(int argc UNUSED_PARAM, char **argv)
12425{
12426        struct var *vp;
12427        char *name;
12428        const char *p;
12429        char **aptr;
12430        int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
12431
12432        if (nextopt("p") != 'p') {
12433                aptr = argptr;
12434                name = *aptr;
12435                if (name) {
12436                        do {
12437                                p = strchr(name, '=');
12438                                if (p != NULL) {
12439                                        p++;
12440                                } else {
12441                                        vp = *findvar(hashvar(name), name);
12442                                        if (vp) {
12443                                                vp->flags |= flag;
12444                                                continue;
12445                                        }
12446                                }
12447                                setvar(name, p, flag);
12448                        } while ((name = *++aptr) != NULL);
12449                        return 0;
12450                }
12451        }
12452        showvars(argv[0], flag, 0);
12453        return 0;
12454}
12455
12456/*
12457 * Delete a function if it exists.
12458 */
12459static void
12460unsetfunc(const char *name)
12461{
12462        struct tblentry *cmdp;
12463
12464        cmdp = cmdlookup(name, 0);
12465        if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
12466                delete_cmd_entry();
12467}
12468
12469/*
12470 * The unset builtin command.  We unset the function before we unset the
12471 * variable to allow a function to be unset when there is a readonly variable
12472 * with the same name.
12473 */
12474static int FAST_FUNC
12475unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12476{
12477        char **ap;
12478        int i;
12479        int flag = 0;
12480        int ret = 0;
12481
12482        while ((i = nextopt("vf")) != 0) {
12483                flag = i;
12484        }
12485
12486        for (ap = argptr; *ap; ap++) {
12487                if (flag != 'f') {
12488                        i = unsetvar(*ap);
12489                        ret |= i;
12490                        if (!(i & 2))
12491                                continue;
12492                }
12493                if (flag != 'v')
12494                        unsetfunc(*ap);
12495        }
12496        return ret & 1;
12497}
12498
12499static const unsigned char timescmd_str[] ALIGN1 = {
12500        ' ',  offsetof(struct tms, tms_utime),
12501        '\n', offsetof(struct tms, tms_stime),
12502        ' ',  offsetof(struct tms, tms_cutime),
12503        '\n', offsetof(struct tms, tms_cstime),
12504        0
12505};
12506static int FAST_FUNC
12507timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12508{
12509        unsigned long clk_tck, s, t;
12510        const unsigned char *p;
12511        struct tms buf;
12512
12513        clk_tck = sysconf(_SC_CLK_TCK);
12514        times(&buf);
12515
12516        p = timescmd_str;
12517        do {
12518                t = *(clock_t *)(((char *) &buf) + p[1]);
12519                s = t / clk_tck;
12520                t = t % clk_tck;
12521                out1fmt("%lum%lu.%03lus%c",
12522                        s / 60, s % 60,
12523                        (t * 1000) / clk_tck,
12524                        p[0]);
12525                p += 2;
12526        } while (*p);
12527
12528        return 0;
12529}
12530
12531#if ENABLE_SH_MATH_SUPPORT
12532/*
12533 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
12534 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12535 *
12536 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12537 */
12538static int FAST_FUNC
12539letcmd(int argc UNUSED_PARAM, char **argv)
12540{
12541        arith_t i;
12542
12543        argv++;
12544        if (!*argv)
12545                ash_msg_and_raise_error("expression expected");
12546        do {
12547                i = ash_arith(*argv);
12548        } while (*++argv);
12549
12550        return !i;
12551}
12552#endif
12553
12554/*
12555 * The read builtin. Options:
12556 *      -r              Do not interpret '\' specially
12557 *      -s              Turn off echo (tty only)
12558 *      -n NCHARS       Read NCHARS max
12559 *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
12560 *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
12561 *      -u FD           Read from given FD instead of fd 0
12562 * This uses unbuffered input, which may be avoidable in some cases.
12563 * TODO: bash also has:
12564 *      -a ARRAY        Read into array[0],[1],etc
12565 *      -d DELIM        End on DELIM char, not newline
12566 *      -e              Use line editing (tty only)
12567 */
12568static int FAST_FUNC
12569readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12570{
12571        char *opt_n = NULL;
12572        char *opt_p = NULL;
12573        char *opt_t = NULL;
12574        char *opt_u = NULL;
12575        int read_flags = 0;
12576        const char *r;
12577        int i;
12578
12579        while ((i = nextopt("p:u:rt:n:s")) != '\0') {
12580                switch (i) {
12581                case 'p':
12582                        opt_p = optionarg;
12583                        break;
12584                case 'n':
12585                        opt_n = optionarg;
12586                        break;
12587                case 's':
12588                        read_flags |= BUILTIN_READ_SILENT;
12589                        break;
12590                case 't':
12591                        opt_t = optionarg;
12592                        break;
12593                case 'r':
12594                        read_flags |= BUILTIN_READ_RAW;
12595                        break;
12596                case 'u':
12597                        opt_u = optionarg;
12598                        break;
12599                default:
12600                        break;
12601                }
12602        }
12603
12604        r = shell_builtin_read(setvar2,
12605                argptr,
12606                bltinlookup("IFS"), /* can be NULL */
12607                read_flags,
12608                opt_n,
12609                opt_p,
12610                opt_t,
12611                opt_u
12612        );
12613
12614        if ((uintptr_t)r > 1)
12615                ash_msg_and_raise_error(r);
12616
12617        return (uintptr_t)r;
12618}
12619
12620static int FAST_FUNC
12621umaskcmd(int argc UNUSED_PARAM, char **argv)
12622{
12623        static const char permuser[3] ALIGN1 = "ugo";
12624        static const char permmode[3] ALIGN1 = "rwx";
12625        static const short permmask[] ALIGN2 = {
12626                S_IRUSR, S_IWUSR, S_IXUSR,
12627                S_IRGRP, S_IWGRP, S_IXGRP,
12628                S_IROTH, S_IWOTH, S_IXOTH
12629        };
12630
12631        /* TODO: use bb_parse_mode() instead */
12632
12633        char *ap;
12634        mode_t mask;
12635        int i;
12636        int symbolic_mode = 0;
12637
12638        while (nextopt("S") != '\0') {
12639                symbolic_mode = 1;
12640        }
12641
12642        INT_OFF;
12643        mask = umask(0);
12644        umask(mask);
12645        INT_ON;
12646
12647        ap = *argptr;
12648        if (ap == NULL) {
12649                if (symbolic_mode) {
12650                        char buf[18];
12651                        char *p = buf;
12652
12653                        for (i = 0; i < 3; i++) {
12654                                int j;
12655
12656                                *p++ = permuser[i];
12657                                *p++ = '=';
12658                                for (j = 0; j < 3; j++) {
12659                                        if ((mask & permmask[3 * i + j]) == 0) {
12660                                                *p++ = permmode[j];
12661                                        }
12662                                }
12663                                *p++ = ',';
12664                        }
12665                        *--p = 0;
12666                        puts(buf);
12667                } else {
12668                        out1fmt("%.4o\n", mask);
12669                }
12670        } else {
12671                if (isdigit((unsigned char) *ap)) {
12672                        mask = 0;
12673                        do {
12674                                if (*ap >= '8' || *ap < '0')
12675                                        ash_msg_and_raise_error(msg_illnum, argv[1]);
12676                                mask = (mask << 3) + (*ap - '0');
12677                        } while (*++ap != '\0');
12678                        umask(mask);
12679                } else {
12680                        mask = ~mask & 0777;
12681                        if (!bb_parse_mode(ap, &mask)) {
12682                                ash_msg_and_raise_error("illegal mode: %s", ap);
12683                        }
12684                        umask(~mask & 0777);
12685                }
12686        }
12687        return 0;
12688}
12689
12690static int FAST_FUNC
12691ulimitcmd(int argc UNUSED_PARAM, char **argv)
12692{
12693        return shell_builtin_ulimit(argv);
12694}
12695
12696/* ============ main() and helpers */
12697
12698/*
12699 * Called to exit the shell.
12700 */
12701static void exitshell(void) NORETURN;
12702static void
12703exitshell(void)
12704{
12705        struct jmploc loc;
12706        char *p;
12707        int status;
12708
12709        status = exitstatus;
12710        TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12711        if (setjmp(loc.loc)) {
12712                if (exception_type == EXEXIT)
12713/* dash bug: it just does _exit(exitstatus) here
12714 * but we have to do setjobctl(0) first!
12715 * (bug is still not fixed in dash-0.5.3 - if you run dash
12716 * under Midnight Commander, on exit from dash MC is backgrounded) */
12717                        status = exitstatus;
12718                goto out;
12719        }
12720        exception_handler = &loc;
12721        p = trap[0];
12722        if (p) {
12723                trap[0] = NULL;
12724                evalstring(p, 0);
12725                free(p);
12726        }
12727        flush_stdout_stderr();
12728 out:
12729        setjobctl(0);
12730        _exit(status);
12731        /* NOTREACHED */
12732}
12733
12734static void
12735init(void)
12736{
12737        /* from input.c: */
12738        /* we will never free this */
12739        basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
12740
12741        /* from trap.c: */
12742        signal(SIGCHLD, SIG_DFL);
12743        /* bash re-enables SIGHUP which is SIG_IGNed on entry.
12744         * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
12745         */
12746        signal(SIGHUP, SIG_DFL);
12747
12748        /* from var.c: */
12749        {
12750                char **envp;
12751                const char *p;
12752                struct stat st1, st2;
12753
12754                initvar();
12755                for (envp = environ; envp && *envp; envp++) {
12756                        if (strchr(*envp, '=')) {
12757                                setvareq(*envp, VEXPORT|VTEXTFIXED);
12758                        }
12759                }
12760
12761                setvar("PPID", utoa(getppid()), 0);
12762
12763                p = lookupvar("PWD");
12764                if (p)
12765                        if (*p != '/' || stat(p, &st1) || stat(".", &st2)
12766                         || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
12767                                p = '\0';
12768                setpwd(p, 0);
12769        }
12770}
12771
12772/*
12773 * Process the shell command line arguments.
12774 */
12775static void
12776procargs(char **argv)
12777{
12778        int i;
12779        const char *xminusc;
12780        char **xargv;
12781
12782        xargv = argv;
12783        arg0 = xargv[0];
12784        /* if (xargv[0]) - mmm, this is always true! */
12785                xargv++;
12786        for (i = 0; i < NOPTS; i++)
12787                optlist[i] = 2;
12788        argptr = xargv;
12789        if (options(1)) {
12790                /* it already printed err message */
12791                raise_exception(EXERROR);
12792        }
12793        xargv = argptr;
12794        xminusc = minusc;
12795        if (*xargv == NULL) {
12796                if (xminusc)
12797                        ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
12798                sflag = 1;
12799        }
12800        if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
12801                iflag = 1;
12802        if (mflag == 2)
12803                mflag = iflag;
12804        for (i = 0; i < NOPTS; i++)
12805                if (optlist[i] == 2)
12806                        optlist[i] = 0;
12807#if DEBUG == 2
12808        debug = 1;
12809#endif
12810        /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
12811        if (xminusc) {
12812                minusc = *xargv++;
12813                if (*xargv)
12814                        goto setarg0;
12815        } else if (!sflag) {
12816                setinputfile(*xargv, 0);
12817 setarg0:
12818                arg0 = *xargv++;
12819                commandname = arg0;
12820        }
12821
12822        shellparam.p = xargv;
12823#if ENABLE_ASH_GETOPTS
12824        shellparam.optind = 1;
12825        shellparam.optoff = -1;
12826#endif
12827        /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
12828        while (*xargv) {
12829                shellparam.nparam++;
12830                xargv++;
12831        }
12832        optschanged();
12833}
12834
12835/*
12836 * Read /etc/profile or .profile.
12837 */
12838static void
12839read_profile(const char *name)
12840{
12841        int skip;
12842
12843        if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
12844                return;
12845        skip = cmdloop(0);
12846        popfile();
12847        if (skip)
12848                exitshell();
12849}
12850
12851/*
12852 * This routine is called when an error or an interrupt occurs in an
12853 * interactive shell and control is returned to the main command loop.
12854 */
12855static void
12856reset(void)
12857{
12858        /* from eval.c: */
12859        evalskip = 0;
12860        loopnest = 0;
12861        /* from input.c: */
12862        g_parsefile->left_in_buffer = 0;
12863        g_parsefile->left_in_line = 0;      /* clear input buffer */
12864        popallfiles();
12865        /* from parser.c: */
12866        tokpushback = 0;
12867        checkkwd = 0;
12868        /* from redir.c: */
12869        clearredir(/*drop:*/ 0);
12870}
12871
12872#if PROFILE
12873static short profile_buf[16384];
12874extern int etext();
12875#endif
12876
12877/*
12878 * Main routine.  We initialize things, parse the arguments, execute
12879 * profiles if we're a login shell, and then call cmdloop to execute
12880 * commands.  The setjmp call sets up the location to jump to when an
12881 * exception occurs.  When an exception occurs the variable "state"
12882 * is used to figure out how far we had gotten.
12883 */
12884int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
12885int ash_main(int argc UNUSED_PARAM, char **argv)
12886{
12887        const char *shinit;
12888        volatile smallint state;
12889        struct jmploc jmploc;
12890        struct stackmark smark;
12891
12892        /* Initialize global data */
12893        INIT_G_misc();
12894        INIT_G_memstack();
12895        INIT_G_var();
12896#if ENABLE_ASH_ALIAS
12897        INIT_G_alias();
12898#endif
12899        INIT_G_cmdtable();
12900
12901#if PROFILE
12902        monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
12903#endif
12904
12905#if ENABLE_FEATURE_EDITING
12906        line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
12907#endif
12908        state = 0;
12909        if (setjmp(jmploc.loc)) {
12910                smallint e;
12911                smallint s;
12912
12913                reset();
12914
12915                e = exception_type;
12916                if (e == EXERROR)
12917                        exitstatus = 2;
12918                s = state;
12919                if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
12920                        exitshell();
12921                if (e == EXINT)
12922                        outcslow('\n', stderr);
12923
12924                popstackmark(&smark);
12925                FORCE_INT_ON; /* enable interrupts */
12926                if (s == 1)
12927                        goto state1;
12928                if (s == 2)
12929                        goto state2;
12930                if (s == 3)
12931                        goto state3;
12932                goto state4;
12933        }
12934        exception_handler = &jmploc;
12935#if DEBUG
12936        opentrace();
12937        TRACE(("Shell args: "));
12938        trace_puts_args(argv);
12939#endif
12940        rootpid = getpid();
12941
12942        init();
12943        setstackmark(&smark);
12944        procargs(argv);
12945
12946#if ENABLE_FEATURE_EDITING_SAVEHISTORY
12947        if (iflag) {
12948                const char *hp = lookupvar("HISTFILE");
12949
12950                if (hp == NULL) {
12951                        hp = lookupvar("HOME");
12952                        if (hp != NULL) {
12953                                char *defhp = concat_path_file(hp, ".ash_history");
12954                                setvar("HISTFILE", defhp, 0);
12955                                free(defhp);
12956                        }
12957                }
12958        }
12959#endif
12960        if (/* argv[0] && */ argv[0][0] == '-')
12961                isloginsh = 1;
12962        if (isloginsh) {
12963                state = 1;
12964                read_profile("/etc/profile");
12965 state1:
12966                state = 2;
12967                read_profile(".profile");
12968        }
12969 state2:
12970        state = 3;
12971        if (
12972#ifndef linux
12973         getuid() == geteuid() && getgid() == getegid() &&
12974#endif
12975         iflag
12976        ) {
12977                shinit = lookupvar("ENV");
12978                if (shinit != NULL && *shinit != '\0') {
12979                        read_profile(shinit);
12980                }
12981        }
12982 state3:
12983        state = 4;
12984        if (minusc) {
12985                /* evalstring pushes parsefile stack.
12986                 * Ensure we don't falsely claim that 0 (stdin)
12987                 * is one of stacked source fds.
12988                 * Testcase: ash -c 'exec 1>&0' must not complain. */
12989                // if (!sflag) g_parsefile->pf_fd = -1;
12990                // ^^ not necessary since now we special-case fd 0
12991                // in is_hidden_fd() to not be considered "hidden fd"
12992                evalstring(minusc, 0);
12993        }
12994
12995        if (sflag || minusc == NULL) {
12996#if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
12997                if (iflag) {
12998                        const char *hp = lookupvar("HISTFILE");
12999                        if (hp)
13000                                line_input_state->hist_file = hp;
13001                }
13002#endif
13003 state4: /* XXX ??? - why isn't this before the "if" statement */
13004                cmdloop(1);
13005        }
13006#if PROFILE
13007        monitor(0);
13008#endif
13009#ifdef GPROF
13010        {
13011                extern void _mcleanup(void);
13012                _mcleanup();
13013        }
13014#endif
13015        exitshell();
13016        /* NOTREACHED */
13017}
13018
13019
13020/*-
13021 * Copyright (c) 1989, 1991, 1993, 1994
13022 *      The Regents of the University of California.  All rights reserved.
13023 *
13024 * This code is derived from software contributed to Berkeley by
13025 * Kenneth Almquist.
13026 *
13027 * Redistribution and use in source and binary forms, with or without
13028 * modification, are permitted provided that the following conditions
13029 * are met:
13030 * 1. Redistributions of source code must retain the above copyright
13031 *    notice, this list of conditions and the following disclaimer.
13032 * 2. Redistributions in binary form must reproduce the above copyright
13033 *    notice, this list of conditions and the following disclaimer in the
13034 *    documentation and/or other materials provided with the distribution.
13035 * 3. Neither the name of the University nor the names of its contributors
13036 *    may be used to endorse or promote products derived from this software
13037 *    without specific prior written permission.
13038 *
13039 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13040 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13041 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13042 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13043 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13044 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13045 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13046 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13047 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13048 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13049 * SUCH DAMAGE.
13050 */
13051