busybox/shell/msh.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Minix shell port for busybox
   4 *
   5 * This version of the Minix shell was adapted for use in busybox
   6 * by Erik Andersen <andersen@codepoet.org>
   7 *
   8 * - backtick expansion did not work properly
   9 *   Jonas Holmberg <jonas.holmberg@axis.com>
  10 *   Robert Schwebel <r.schwebel@pengutronix.de>
  11 *   Erik Andersen <andersen@codepoet.org>
  12 *
  13 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  14 */
  15#include <sys/times.h>
  16#include <setjmp.h>
  17
  18#ifdef STANDALONE
  19# ifndef _GNU_SOURCE
  20#  define _GNU_SOURCE
  21# endif
  22# include <sys/types.h>
  23# include <sys/stat.h>
  24# include <sys/wait.h>
  25# include <signal.h>
  26# include <stdio.h>
  27# include <stdlib.h>
  28# include <unistd.h>
  29# include <string.h>
  30# include <errno.h>
  31# include <dirent.h>
  32# include <fcntl.h>
  33# include <ctype.h>
  34# include <assert.h>
  35# define bb_dev_null "/dev/null"
  36# define DEFAULT_SHELL "/proc/self/exe"
  37# define bb_banner "busybox standalone"
  38# define ENABLE_FEATURE_SH_STANDALONE 0
  39# define bb_msg_memory_exhausted "memory exhausted"
  40# define xmalloc(size) malloc(size)
  41# define msh_main(argc,argv) main(argc,argv)
  42# define safe_read(fd,buf,count) read(fd,buf,count)
  43# define nonblock_safe_read(fd,buf,count) read(fd,buf,count)
  44# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
  45# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
  46# define NORETURN __attribute__ ((__noreturn__))
  47static int find_applet_by_name(const char *applet)
  48{
  49        return -1;
  50}
  51static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
  52{
  53        unsigned i, out, res;
  54        assert(sizeof(unsigned) == 4);
  55        if (buflen) {
  56                out = 0;
  57                for (i = 1000000000; i; i /= 10) {
  58                        res = n / i;
  59                        if (res || out || i == 1) {
  60                                if (!--buflen) break;
  61                                out++;
  62                                n -= res*i;
  63                                *buf++ = '0' + res;
  64                        }
  65                }
  66        }
  67        return buf;
  68}
  69static char *itoa_to_buf(int n, char *buf, unsigned buflen)
  70{
  71        if (buflen && n < 0) {
  72                n = -n;
  73                *buf++ = '-';
  74                buflen--;
  75        }
  76        return utoa_to_buf((unsigned)n, buf, buflen);
  77}
  78static char local_buf[12];
  79static char *itoa(int n)
  80{
  81        *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
  82        return local_buf;
  83}
  84#else
  85# include "busybox.h" /* for applet_names */
  86#endif
  87
  88//#define MSHDEBUG 4
  89
  90#ifdef MSHDEBUG
  91static int mshdbg = MSHDEBUG;
  92
  93#define DBGPRINTF(x)    if (mshdbg > 0) printf x
  94#define DBGPRINTF0(x)   if (mshdbg > 0) printf x
  95#define DBGPRINTF1(x)   if (mshdbg > 1) printf x
  96#define DBGPRINTF2(x)   if (mshdbg > 2) printf x
  97#define DBGPRINTF3(x)   if (mshdbg > 3) printf x
  98#define DBGPRINTF4(x)   if (mshdbg > 4) printf x
  99#define DBGPRINTF5(x)   if (mshdbg > 5) printf x
 100#define DBGPRINTF6(x)   if (mshdbg > 6) printf x
 101#define DBGPRINTF7(x)   if (mshdbg > 7) printf x
 102#define DBGPRINTF8(x)   if (mshdbg > 8) printf x
 103#define DBGPRINTF9(x)   if (mshdbg > 9) printf x
 104
 105static int mshdbg_rc = 0;
 106
 107#define RCPRINTF(x)     if (mshdbg_rc) printf x
 108
 109#else
 110
 111#define DBGPRINTF(x)
 112#define DBGPRINTF0(x) ((void)0)
 113#define DBGPRINTF1(x) ((void)0)
 114#define DBGPRINTF2(x) ((void)0)
 115#define DBGPRINTF3(x) ((void)0)
 116#define DBGPRINTF4(x) ((void)0)
 117#define DBGPRINTF5(x) ((void)0)
 118#define DBGPRINTF6(x) ((void)0)
 119#define DBGPRINTF7(x) ((void)0)
 120#define DBGPRINTF8(x) ((void)0)
 121#define DBGPRINTF9(x) ((void)0)
 122
 123#define RCPRINTF(x) ((void)0)
 124
 125#endif  /* MSHDEBUG */
 126
 127
 128#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
 129# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
 130# define DEFAULT_USER_PROMPT "\\u:\\w$ "
 131#else
 132# define DEFAULT_ROOT_PROMPT "# "
 133# define DEFAULT_USER_PROMPT "$ "
 134#endif
 135
 136
 137/* -------- sh.h -------- */
 138/*
 139 * shell
 140 */
 141
 142#define LINELIM   2100
 143#define NPUSH     8             /* limit to input nesting */
 144
 145#undef NOFILE
 146#define NOFILE    20            /* Number of open files */
 147#define NUFILE    10            /* Number of user-accessible files */
 148#define FDBASE    10            /* First file usable by Shell */
 149
 150/*
 151 * values returned by wait
 152 */
 153#define WAITSIG(s)  ((s) & 0177)
 154#define WAITVAL(s)  (((s) >> 8) & 0377)
 155#define WAITCORE(s) (((s) & 0200) != 0)
 156
 157/*
 158 * library and system definitions
 159 */
 160typedef void xint;              /* base type of jmp_buf, for not broken compilers */
 161
 162/*
 163 * shell components
 164 */
 165#define NOBLOCK ((struct op *)NULL)
 166#define NOWORD  ((char *)NULL)
 167#define NOWORDS ((char **)NULL)
 168#define NOPIPE  ((int *)NULL)
 169
 170/*
 171 * redirection
 172 */
 173struct ioword {
 174        smallint io_flag;               /* action (below) */
 175        int io_fd;                      /* fd affected */
 176        char *io_name;                  /* file name */
 177};
 178
 179#define IOREAD   1                      /* < */
 180#define IOHERE   2                      /* << (here file) */
 181#define IOWRITE  4                      /* > */
 182#define IOCAT    8                      /* >> */
 183#define IOXHERE  16                     /* ${}, ` in << */
 184#define IODUP    32                     /* >&digit */
 185#define IOCLOSE  64                     /* >&- */
 186
 187#define IODEFAULT (-1)                  /* "default" IO fd */
 188
 189
 190/*
 191 * Description of a command or an operation on commands.
 192 * Might eventually use a union.
 193 */
 194struct op {
 195        smallint op_type;               /* operation type, see Txxxx below */
 196        char **op_words;                /* arguments to a command */
 197        struct ioword **ioact;          /* IO actions (eg, < > >>) */
 198        struct op *left;
 199        struct op *right;
 200        char *str;                      /* identifier for case and for */
 201};
 202
 203#define TCOM    1       /* command */
 204#define TPAREN  2       /* (c-list) */
 205#define TPIPE   3       /* a | b */
 206#define TLIST   4       /* a [&;] b */
 207#define TOR     5       /* || */
 208#define TAND    6       /* && */
 209#define TFOR    7
 210#define TDO     8
 211#define TCASE   9
 212#define TIF     10
 213#define TWHILE  11
 214#define TUNTIL  12
 215#define TELIF   13
 216#define TPAT    14      /* pattern in case */
 217#define TBRACE  15      /* {c-list} */
 218#define TASYNC  16      /* c & */
 219/* Added to support "." file expansion */
 220#define TDOT    17
 221
 222/* Strings for names to make debug easier */
 223#ifdef MSHDEBUG
 224static const char *const T_CMD_NAMES[] = {
 225        "PLACEHOLDER",
 226        "TCOM",
 227        "TPAREN",
 228        "TPIPE",
 229        "TLIST",
 230        "TOR",
 231        "TAND",
 232        "TFOR",
 233        "TDO",
 234        "TCASE",
 235        "TIF",
 236        "TWHILE",
 237        "TUNTIL",
 238        "TELIF",
 239        "TPAT",
 240        "TBRACE",
 241        "TASYNC",
 242        "TDOT",
 243};
 244#endif
 245
 246#define AREASIZE (90000)
 247
 248/*
 249 * flags to control evaluation of words
 250 */
 251#define DOSUB    1      /* interpret $, `, and quotes */
 252#define DOBLANK  2      /* perform blank interpretation */
 253#define DOGLOB   4      /* interpret [?* */
 254#define DOKEY    8      /* move words with `=' to 2nd arg. list */
 255#define DOTRIM   16     /* trim resulting string */
 256
 257#define DOALL    (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
 258
 259
 260struct brkcon {
 261        jmp_buf brkpt;
 262        struct brkcon *nextlev;
 263};
 264
 265
 266static smallint trapset;                        /* trap pending (signal number) */
 267
 268static smallint yynerrs;                        /* yacc (flag) */
 269
 270/* moved to G: static char line[LINELIM]; */
 271
 272#if ENABLE_FEATURE_EDITING
 273static char *current_prompt;
 274static line_input_t *line_input_state;
 275#endif
 276
 277
 278/*
 279 * other functions
 280 */
 281static const char *rexecve(char *c, char **v, char **envp);
 282static char *evalstr(char *cp, int f);
 283static char *putn(int n);
 284static char *unquote(char *as);
 285static int rlookup(char *n);
 286static struct wdblock *glob(char *cp, struct wdblock *wb);
 287static int my_getc(int ec);
 288static int subgetc(char ec, int quoted);
 289static char **makenv(int all, struct wdblock *wb);
 290static char **eval(char **ap, int f);
 291static int setstatus(int s);
 292static int waitfor(int lastpid, int canintr);
 293
 294static void onintr(int s);              /* SIGINT handler */
 295
 296static int newenv(int f);
 297static void quitenv(void);
 298static void next(int f);
 299static void setdash(void);
 300static void onecommand(void);
 301static void runtrap(int i);
 302
 303
 304/* -------- area stuff -------- */
 305
 306#define REGSIZE   sizeof(struct region)
 307#define GROWBY    (256)
 308/* #define SHRINKBY (64) */
 309#undef  SHRINKBY
 310#define FREE      (32767)
 311#define BUSY      (0)
 312#define ALIGN     (sizeof(int)-1)
 313
 314
 315struct region {
 316        struct region *next;
 317        int area;
 318};
 319
 320
 321/* -------- grammar stuff -------- */
 322typedef union {
 323        char *cp;
 324        char **wp;
 325        int i;
 326        struct op *o;
 327} YYSTYPE;
 328
 329#define WORD    256
 330#define LOGAND  257
 331#define LOGOR   258
 332#define BREAK   259
 333#define IF      260
 334#define THEN    261
 335#define ELSE    262
 336#define ELIF    263
 337#define FI      264
 338#define CASE    265
 339#define ESAC    266
 340#define FOR     267
 341#define WHILE   268
 342#define UNTIL   269
 343#define DO      270
 344#define DONE    271
 345#define IN      272
 346/* Added for "." file expansion */
 347#define DOT     273
 348
 349#define YYERRCODE 300
 350
 351/* flags to yylex */
 352#define CONTIN 01     /* skip new lines to complete command */
 353
 354static struct op *pipeline(int cf);
 355static struct op *andor(void);
 356static struct op *c_list(void);
 357static int synio(int cf);
 358static void musthave(int c, int cf);
 359static struct op *simple(void);
 360static struct op *nested(int type, int mark);
 361static struct op *command(int cf);
 362static struct op *dogroup(int onlydone);
 363static struct op *thenpart(void);
 364static struct op *elsepart(void);
 365static struct op *caselist(void);
 366static struct op *casepart(void);
 367static char **pattern(void);
 368static char **wordlist(void);
 369static struct op *list(struct op *t1, struct op *t2);
 370static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
 371static struct op *newtp(void);
 372static struct op *namelist(struct op *t);
 373static char **copyw(void);
 374static void word(char *cp);
 375static struct ioword **copyio(void);
 376static struct ioword *io(int u, int f, char *cp);
 377static int yylex(int cf);
 378static int collect(int c, int c1);
 379static int dual(int c);
 380static void diag(int ec);
 381static char *tree(unsigned size);
 382
 383/* -------- var.h -------- */
 384
 385struct var {
 386        char *value;
 387        char *name;
 388        struct var *next;
 389        char status;
 390};
 391
 392#define COPYV   1                               /* flag to setval, suggesting copy */
 393#define RONLY   01                              /* variable is read-only */
 394#define EXPORT  02                              /* variable is to be exported */
 395#define GETCELL 04                              /* name & value space was got with getcell */
 396
 397static int yyparse(void);
 398
 399
 400/* -------- io.h -------- */
 401/* io buffer */
 402struct iobuf {
 403        unsigned id;            /* buffer id */
 404        char buf[512];          /* buffer */
 405        char *bufp;             /* pointer into buffer */
 406        char *ebufp;            /* pointer to end of buffer */
 407};
 408
 409/* possible arguments to an IO function */
 410struct ioarg {
 411        const char *aword;
 412        char **awordlist;
 413        int afile;              /* file descriptor */
 414        unsigned afid;          /* buffer id */
 415        off_t afpos;            /* file position */
 416        struct iobuf *afbuf;    /* buffer for this file */
 417};
 418
 419/* an input generator's state */
 420struct io {
 421        int (*iofn) (struct ioarg *, struct io *);
 422        struct ioarg *argp;
 423        int peekc;
 424        char prev;              /* previous character read by readc() */
 425        char nlcount;           /* for `'s */
 426        char xchar;             /* for `'s */
 427        char task;              /* reason for pushed IO */
 428};
 429/* ->task: */
 430#define XOTHER  0       /* none of the below */
 431#define XDOLL   1       /* expanding ${} */
 432#define XGRAVE  2       /* expanding `'s */
 433#define XIO     3       /* file IO */
 434
 435
 436/*
 437 * input generators for IO structure
 438 */
 439static int nlchar(struct ioarg *ap);
 440static int strchar(struct ioarg *ap);
 441static int qstrchar(struct ioarg *ap);
 442static int filechar(struct ioarg *ap);
 443static int herechar(struct ioarg *ap);
 444static int linechar(struct ioarg *ap);
 445static int gravechar(struct ioarg *ap, struct io *iop);
 446static int qgravechar(struct ioarg *ap, struct io *iop);
 447static int dolchar(struct ioarg *ap);
 448static int wdchar(struct ioarg *ap);
 449static void scraphere(void);
 450static void freehere(int area);
 451static void gethere(void);
 452static void markhere(char *s, struct ioword *iop);
 453static int herein(char *hname, int xdoll);
 454static int run(struct ioarg *argp, int (*f) (struct ioarg *));
 455
 456
 457static int eofc(void);
 458static int readc(void);
 459static void unget(int c);
 460static void ioecho(char c);
 461
 462
 463/*
 464 * IO control
 465 */
 466static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
 467#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
 468static int remap(int fd);
 469static int openpipe(int *pv);
 470static void closepipe(int *pv);
 471static struct io *setbase(struct io *ip);
 472
 473/* -------- word.h -------- */
 474
 475#define NSTART  16                              /* default number of words to allow for initially */
 476
 477struct wdblock {
 478        short w_bsize;
 479        short w_nword;
 480        /* bounds are arbitrary */
 481        char *w_words[1];
 482};
 483
 484static struct wdblock *addword(char *wd, struct wdblock *wb);
 485static struct wdblock *newword(int nw);
 486static char **getwords(struct wdblock *wb);
 487
 488/* -------- misc stuff -------- */
 489
 490static int dolabel(struct op *t, char **args);
 491static int dohelp(struct op *t, char **args);
 492static int dochdir(struct op *t, char **args);
 493static int doshift(struct op *t, char **args);
 494static int dologin(struct op *t, char **args);
 495static int doumask(struct op *t, char **args);
 496static int doexec(struct op *t, char **args);
 497static int dodot(struct op *t, char **args);
 498static int dowait(struct op *t, char **args);
 499static int doread(struct op *t, char **args);
 500static int doeval(struct op *t, char **args);
 501static int dotrap(struct op *t, char **args);
 502static int dobreak(struct op *t, char **args);
 503static int doexit(struct op *t, char **args);
 504static int doexport(struct op *t, char **args);
 505static int doreadonly(struct op *t, char **args);
 506static int doset(struct op *t, char **args);
 507static int dotimes(struct op *t, char **args);
 508static int docontinue(struct op *t, char **args);
 509
 510static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
 511static int execute(struct op *t, int *pin, int *pout, int no_fork);
 512static int iosetup(struct ioword *iop, int pipein, int pipeout);
 513static void brkset(struct brkcon *bc);
 514static int getsig(char *s);
 515static void setsig(int n, sighandler_t f);
 516static int getn(char *as);
 517static int brkcontin(char *cp, int val);
 518static void rdexp(char **wp, void (*f) (struct var *), int key);
 519static void badid(char *s);
 520static void varput(char *s, int out);
 521static int expand(const char *cp, struct wdblock **wbp, int f);
 522static char *blank(int f);
 523static int dollar(int quoted);
 524static int grave(int quoted);
 525static void globname(char *we, char *pp);
 526static char *generate(char *start1, char *end1, char *middle, char *end);
 527static int anyspcl(struct wdblock *wb);
 528static void readhere(char **name, char *s, int ec);
 529static int xxchar(struct ioarg *ap);
 530
 531struct here {
 532        char *h_tag;
 533        char h_dosub;
 534        struct ioword *h_iop;
 535        struct here *h_next;
 536};
 537
 538static const char *const signame[] = {
 539        "Signal 0",
 540        "Hangup",
 541        NULL,  /* interrupt */
 542        "Quit",
 543        "Illegal instruction",
 544        "Trace/BPT trap",
 545        "Abort",
 546        "Bus error",
 547        "Floating Point Exception",
 548        "Killed",
 549        "SIGUSR1",
 550        "SIGSEGV",
 551        "SIGUSR2",
 552        NULL,  /* broken pipe */
 553        "Alarm clock",
 554        "Terminated"
 555};
 556
 557
 558typedef int (*builtin_func_ptr)(struct op *, char **);
 559
 560struct builtincmd {
 561        const char *name;
 562        builtin_func_ptr builtinfunc;
 563};
 564
 565static const struct builtincmd builtincmds[] = {
 566        { "."       , dodot      },
 567        { ":"       , dolabel    },
 568        { "break"   , dobreak    },
 569        { "cd"      , dochdir    },
 570        { "continue", docontinue },
 571        { "eval"    , doeval     },
 572        { "exec"    , doexec     },
 573        { "exit"    , doexit     },
 574        { "export"  , doexport   },
 575        { "help"    , dohelp     },
 576        { "login"   , dologin    },
 577        { "newgrp"  , dologin    },
 578        { "read"    , doread     },
 579        { "readonly", doreadonly },
 580        { "set"     , doset      },
 581        { "shift"   , doshift    },
 582        { "times"   , dotimes    },
 583        { "trap"    , dotrap     },
 584        { "umask"   , doumask    },
 585        { "wait"    , dowait     },
 586        { NULL      , NULL       },
 587};
 588
 589static struct op *dowholefile(int /*, int*/);
 590
 591
 592/* Globals */
 593static char **dolv;
 594static int dolc;
 595static uint8_t exstat;
 596static smallint gflg;                   /* (seems to be a parse error indicator) */
 597static smallint interactive;            /* Is this an interactive shell */
 598static smallint execflg;
 599static smallint isbreak;                /* "break" statement was seen */
 600static int multiline;                   /* '\n' changed to ';' (counter) */
 601static struct op *outtree;              /* result from parser */
 602static xint *failpt;
 603static xint *errpt;
 604static struct brkcon *brklist;
 605static struct wdblock *wdlist;
 606static struct wdblock *iolist;
 607
 608#ifdef MSHDEBUG
 609static struct var *mshdbg_var;
 610#endif
 611static struct var *vlist;               /* dictionary */
 612static struct var *homedir;             /* home directory */
 613static struct var *prompt;              /* main prompt */
 614static struct var *cprompt;             /* continuation prompt */
 615static struct var *path;                /* search path for commands */
 616static struct var *shell;               /* shell to interpret command files */
 617static struct var *ifs;                 /* field separators */
 618
 619static int areanum;                     /* current allocation area */
 620static smallint intr;                   /* interrupt pending (bool) */
 621static smallint heedint = 1;            /* heed interrupt signals (bool) */
 622static int inparse;
 623static char *null = (char*)"";          /* null value for variable */
 624static void (*qflag)(int) = SIG_IGN;
 625static int startl;
 626static int peeksym;
 627static int nlseen;
 628static int iounit = IODEFAULT;
 629static YYSTYPE yylval;
 630static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
 631
 632static struct here *inhere;     /* list of hear docs while parsing */
 633static struct here *acthere;    /* list of active here documents */
 634static struct region *areabot;  /* bottom of area */
 635static struct region *areatop;  /* top of area */
 636static struct region *areanxt;  /* starting point of scan */
 637static void *brktop;
 638static void *brkaddr;
 639
 640#define AFID_NOBUF      (~0)
 641#define AFID_ID         0
 642
 643
 644/*
 645 * parsing & execution environment
 646 */
 647struct env {
 648        char *linep;
 649        struct io *iobase;
 650        struct io *iop;
 651        xint *errpt;            /* void * */
 652        int iofd;
 653        struct env *oenv;
 654};
 655
 656
 657struct globals {
 658        struct env global_env;
 659        struct ioarg temparg; // = { .afid = AFID_NOBUF };      /* temporary for PUSHIO */
 660        unsigned bufid; // = AFID_ID;   /* buffer id counter */
 661        char ourtrap[_NSIG + 1];
 662        char *trap[_NSIG + 1];
 663        struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
 664        struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
 665        struct ioarg ioargstack[NPUSH];
 666        /*
 667         * flags:
 668         * -e: quit on error
 669         * -k: look for name=value everywhere on command line
 670         * -n: no execution
 671         * -t: exit after reading and executing one command
 672         * -v: echo as read
 673         * -x: trace
 674         * -u: unset variables net diagnostic
 675         */
 676        char flags['z' - 'a' + 1];
 677        char filechar_cmdbuf[BUFSIZ];
 678        char line[LINELIM];
 679        char child_cmd[LINELIM];
 680
 681        struct io iostack[NPUSH];
 682
 683        char grave__var_name[LINELIM];
 684        char grave__alt_value[LINELIM];
 685};
 686
 687#define G (*ptr_to_globals)
 688#define global_env      (G.global_env     )
 689#define temparg         (G.temparg        )
 690#define bufid           (G.bufid          )
 691#define ourtrap         (G.ourtrap        )
 692#define trap            (G.trap           )
 693#define sharedbuf       (G.sharedbuf      )
 694#define mainbuf         (G.mainbuf        )
 695#define ioargstack      (G.ioargstack     )
 696/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
 697#define FLAG            (G.flags - 'a'    )
 698#define filechar_cmdbuf (G.filechar_cmdbuf)
 699#define line            (G.line           )
 700#define child_cmd       (G.child_cmd      )
 701#define iostack         (G.iostack        )
 702#define INIT_G() do { \
 703        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
 704        global_env.linep = line; \
 705        global_env.iobase = iostack; \
 706        global_env.iop = iostack - 1; \
 707        global_env.iofd = FDBASE; \
 708        temparg.afid = AFID_NOBUF; \
 709        bufid = AFID_ID; \
 710} while (0)
 711
 712
 713/* in substitution */
 714#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
 715
 716#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
 717
 718#ifdef MSHDEBUG
 719static void print_tree(struct op *head)
 720{
 721        if (head == NULL) {
 722                DBGPRINTF(("PRINT_TREE: no tree\n"));
 723                return;
 724        }
 725
 726        DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
 727                           head->right));
 728
 729        if (head->left)
 730                print_tree(head->left);
 731
 732        if (head->right)
 733                print_tree(head->right);
 734}
 735#endif /* MSHDEBUG */
 736
 737
 738/*
 739 * IO functions
 740 */
 741static void prs(const char *s)
 742{
 743        if (*s)
 744                xwrite_str(STDERR_FILENO, s);
 745}
 746
 747static void prn(unsigned u)
 748{
 749        prs(itoa(u));
 750}
 751
 752static void echo(char **wp)
 753{
 754        int i;
 755
 756        prs("+");
 757        for (i = 0; wp[i]; i++) {
 758                if (i)
 759                        prs(" ");
 760                prs(wp[i]);
 761        }
 762        prs("\n");
 763}
 764
 765static void closef(int i)
 766{
 767        if (i > 2)
 768                close(i);
 769}
 770
 771static void closeall(void)
 772{
 773        int u;
 774
 775        for (u = NUFILE; u < NOFILE;)
 776                close(u++);
 777}
 778
 779
 780/* fail but return to process next command */
 781static void fail(void) NORETURN;
 782static void fail(void)
 783{
 784        longjmp(failpt, 1);
 785        /* NOTREACHED */
 786}
 787
 788/* abort shell (or fail in subshell) */
 789static void leave(void) NORETURN;
 790static void leave(void)
 791{
 792        DBGPRINTF(("LEAVE: leave called!\n"));
 793
 794        if (execflg)
 795                fail();
 796        scraphere();
 797        freehere(1);
 798        runtrap(0);
 799        _exit(exstat);
 800        /* NOTREACHED */
 801}
 802
 803static void warn(const char *s)
 804{
 805        if (*s) {
 806                prs(s);
 807                if (!exstat)
 808                        exstat = 255;
 809        }
 810        prs("\n");
 811        if (FLAG['e'])
 812                leave();
 813}
 814
 815static void err(const char *s)
 816{
 817        warn(s);
 818        if (FLAG['n'])
 819                return;
 820        if (!interactive)
 821                leave();
 822        if (global_env.errpt)
 823                longjmp(global_env.errpt, 1);
 824        closeall();
 825        global_env.iop = global_env.iobase = iostack;
 826}
 827
 828
 829/* -------- area.c -------- */
 830
 831/*
 832 * All memory between (char *)areabot and (char *)(areatop+1) is
 833 * exclusively administered by the area management routines.
 834 * It is assumed that sbrk() and brk() manipulate the high end.
 835 */
 836
 837#define sbrk(X) ({ \
 838        void * __q = (void *)-1; \
 839        if (brkaddr + (int)(X) < brktop) { \
 840                __q = brkaddr; \
 841                brkaddr += (int)(X); \
 842        } \
 843        __q; \
 844})
 845
 846static void initarea(void)
 847{
 848        brkaddr = xmalloc(AREASIZE);
 849        brktop = brkaddr + AREASIZE;
 850
 851        while ((long) sbrk(0) & ALIGN)
 852                sbrk(1);
 853        areabot = (struct region *) sbrk(REGSIZE);
 854
 855        areabot->next = areabot;
 856        areabot->area = BUSY;
 857        areatop = areabot;
 858        areanxt = areabot;
 859}
 860
 861static char *getcell(unsigned nbytes)
 862{
 863        int nregio;
 864        struct region *p, *q;
 865        int i;
 866
 867        if (nbytes == 0) {
 868                puts("getcell(0)");
 869                abort();
 870        }
 871        /* silly and defeats the algorithm */
 872        /*
 873         * round upwards and add administration area
 874         */
 875        nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
 876        p = areanxt;
 877        for (;;) {
 878                if (p->area > areanum) {
 879                        /*
 880                         * merge free cells
 881                         */
 882                        while ((q = p->next)->area > areanum && q != areanxt)
 883                                p->next = q->next;
 884                        /*
 885                         * exit loop if cell big enough
 886                         */
 887                        if (q >= p + nregio)
 888                                goto found;
 889                }
 890                p = p->next;
 891                if (p == areanxt)
 892                        break;
 893        }
 894        i = nregio >= GROWBY ? nregio : GROWBY;
 895        p = (struct region *) sbrk(i * REGSIZE);
 896        if (p == (struct region *) -1)
 897                return NULL;
 898        p--;
 899        if (p != areatop) {
 900                puts("not contig");
 901                abort();                                /* allocated areas are contiguous */
 902        }
 903        q = p + i;
 904        p->next = q;
 905        p->area = FREE;
 906        q->next = areabot;
 907        q->area = BUSY;
 908        areatop = q;
 909 found:
 910        /*
 911         * we found a FREE area big enough, pointed to by 'p', and up to 'q'
 912         */
 913        areanxt = p + nregio;
 914        if (areanxt < q) {
 915                /*
 916                 * split into requested area and rest
 917                 */
 918                if (areanxt + 1 > q) {
 919                        puts("OOM");
 920                        abort();                        /* insufficient space left for admin */
 921                }
 922                areanxt->next = q;
 923                areanxt->area = FREE;
 924                p->next = areanxt;
 925        }
 926        p->area = areanum;
 927        return (char *) (p + 1);
 928}
 929
 930static void freecell(char *cp)
 931{
 932        struct region *p;
 933
 934        p = (struct region *) cp;
 935        if (p != NULL) {
 936                p--;
 937                if (p < areanxt)
 938                        areanxt = p;
 939                p->area = FREE;
 940        }
 941}
 942#define DELETE(obj) freecell((char *)obj)
 943
 944static void freearea(int a)
 945{
 946        struct region *p, *top;
 947
 948        top = areatop;
 949        for (p = areabot; p != top; p = p->next)
 950                if (p->area >= a)
 951                        p->area = FREE;
 952}
 953
 954static void setarea(char *cp, int a)
 955{
 956        struct region *p;
 957
 958        p = (struct region *) cp;
 959        if (p != NULL)
 960                (p - 1)->area = a;
 961}
 962
 963static int getarea(char *cp)
 964{
 965        return ((struct region *) cp - 1)->area;
 966}
 967
 968static void garbage(void)
 969{
 970        struct region *p, *q, *top;
 971
 972        top = areatop;
 973        for (p = areabot; p != top; p = p->next) {
 974                if (p->area > areanum) {
 975                        while ((q = p->next)->area > areanum)
 976                                p->next = q->next;
 977                        areanxt = p;
 978                }
 979        }
 980#ifdef SHRINKBY
 981        if (areatop >= q + SHRINKBY && q->area > areanum) {
 982                brk((char *) (q + 1));
 983                q->next = areabot;
 984                q->area = BUSY;
 985                areatop = q;
 986        }
 987#endif
 988}
 989
 990static void *get_space(int n)
 991{
 992        char *cp;
 993
 994        cp = getcell(n);
 995        if (cp == NULL)
 996                err("out of string space");
 997        return cp;
 998}
 999
1000static char *strsave(const char *s, int a)
1001{
1002        char *cp;
1003
1004        cp = get_space(strlen(s) + 1);
1005        if (cp == NULL) {
1006// FIXME: I highly doubt this is good.
1007                return (char*)"";
1008        }
1009        setarea(cp, a);
1010        strcpy(cp, s);
1011        return cp;
1012}
1013
1014
1015/* -------- var.c -------- */
1016
1017static int eqname(const char *n1, const char *n2)
1018{
1019        for (; *n1 != '=' && *n1 != '\0'; n1++)
1020                if (*n2++ != *n1)
1021                        return 0;
1022        return *n2 == '\0' || *n2 == '=';
1023}
1024
1025static const char *findeq(const char *cp)
1026{
1027        while (*cp != '\0' && *cp != '=')
1028                cp++;
1029        return cp;
1030}
1031
1032/*
1033 * Find the given name in the dictionary
1034 * and return its value.  If the name was
1035 * not previously there, enter it now and
1036 * return a null value.
1037 */
1038static struct var *lookup(const char *n)
1039{
1040// FIXME: dirty hack
1041        static struct var dummy;
1042
1043        struct var *vp;
1044        const char *cp;
1045        char *xp;
1046        int c;
1047
1048        if (isdigit(*n)) {
1049                dummy.name = (char*)n;
1050                for (c = 0; isdigit(*n) && c < 1000; n++)
1051                        c = c * 10 + *n - '0';
1052                dummy.status = RONLY;
1053                dummy.value = (c <= dolc ? dolv[c] : null);
1054                return &dummy;
1055        }
1056
1057        for (vp = vlist; vp; vp = vp->next)
1058                if (eqname(vp->name, n))
1059                        return vp;
1060
1061        cp = findeq(n);
1062        vp = get_space(sizeof(*vp));
1063        if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) {
1064                dummy.name = dummy.value = (char*)"";
1065                return &dummy;
1066        }
1067
1068        xp = vp->name;
1069        while ((*xp = *n++) != '\0' && *xp != '=')
1070                xp++;
1071        *xp++ = '=';
1072        *xp = '\0';
1073        setarea((char *) vp, 0);
1074        setarea((char *) vp->name, 0);
1075        vp->value = null;
1076        vp->next = vlist;
1077        vp->status = GETCELL;
1078        vlist = vp;
1079        return vp;
1080}
1081
1082/*
1083 * if name is not NULL, it must be
1084 * a prefix of the space `val',
1085 * and end with `='.
1086 * this is all so that exporting
1087 * values is reasonably painless.
1088 */
1089static void nameval(struct var *vp, const char *val, const char *name)
1090{
1091        const char *cp;
1092        char *xp;
1093        int fl;
1094
1095        if (vp->status & RONLY) {
1096                xp = vp->name;
1097                while (*xp && *xp != '=')
1098                        fputc(*xp++, stderr);
1099                err(" is read-only");
1100                return;
1101        }
1102        fl = 0;
1103        if (name == NULL) {
1104                xp = get_space(strlen(vp->name) + strlen(val) + 2);
1105                if (xp == NULL)
1106                        return;
1107                /* make string: name=value */
1108                setarea(xp, 0);
1109                name = xp;
1110                cp = vp->name;
1111                while ((*xp = *cp++) != '\0' && *xp != '=')
1112                        xp++;
1113                *xp++ = '=';
1114                strcpy(xp, val);
1115                val = xp;
1116                fl = GETCELL;
1117        }
1118        if (vp->status & GETCELL)
1119                freecell(vp->name);             /* form new string `name=value' */
1120        vp->name = (char*)name;
1121        vp->value = (char*)val;
1122        vp->status |= fl;
1123}
1124
1125/*
1126 * give variable at `vp' the value `val'.
1127 */
1128static void setval(struct var *vp, const char *val)
1129{
1130        nameval(vp, val, NULL);
1131}
1132
1133static void export(struct var *vp)
1134{
1135        vp->status |= EXPORT;
1136}
1137
1138static void ronly(struct var *vp)
1139{
1140        if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1141                vp->status |= RONLY;
1142}
1143
1144static int isassign(const char *s)
1145{
1146        unsigned char c;
1147        DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1148
1149        c = *s;
1150        /* no isalpha() - we shouldn't use locale */
1151        /* c | 0x20 - lowercase (Latin) letters */
1152        if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1153                /* not letter */
1154                return 0;
1155
1156        while (1) {
1157                c = *++s;
1158                if (c == '=')
1159                        return 1;
1160                if (c == '\0')
1161                        return 0;
1162                if (c != '_'
1163                 && (unsigned)(c - '0') > 9  /* not number */
1164                 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
1165                ) {
1166                        return 0;
1167                }
1168        }
1169}
1170
1171static int assign(const char *s, int cf)
1172{
1173        const char *cp;
1174        struct var *vp;
1175
1176        DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1177
1178        if (!isalpha(*s) && *s != '_')
1179                return 0;
1180        for (cp = s; *cp != '='; cp++)
1181                if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1182                        return 0;
1183        vp = lookup(s);
1184        nameval(vp, ++cp, cf == COPYV ? NULL : s);
1185        if (cf != COPYV)
1186                vp->status &= ~GETCELL;
1187        return 1;
1188}
1189
1190static int checkname(char *cp)
1191{
1192        DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1193
1194        if (!isalpha(*cp++) && *(cp - 1) != '_')
1195                return 0;
1196        while (*cp)
1197                if (!isalnum(*cp++) && *(cp - 1) != '_')
1198                        return 0;
1199        return 1;
1200}
1201
1202static void putvlist(int f, int out)
1203{
1204        struct var *vp;
1205
1206        for (vp = vlist; vp; vp = vp->next) {
1207                if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1208                        if (vp->status & EXPORT)
1209                                write(out, "export ", 7);
1210                        if (vp->status & RONLY)
1211                                write(out, "readonly ", 9);
1212                        write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1213                        write(out, "\n", 1);
1214                }
1215        }
1216}
1217
1218
1219/*
1220 * trap handling
1221 */
1222static void sig(int i)
1223{
1224        trapset = i;
1225        signal(i, sig);
1226}
1227
1228static void runtrap(int i)
1229{
1230        char *trapstr;
1231
1232        trapstr = trap[i];
1233        if (trapstr == NULL)
1234                return;
1235
1236        if (i == 0)
1237                trap[i] = NULL;
1238
1239        RUN(aword, trapstr, nlchar);
1240}
1241
1242
1243static void setdash(void)
1244{
1245        char *cp;
1246        int c;
1247        char m['z' - 'a' + 1];
1248
1249        cp = m;
1250        for (c = 'a'; c <= 'z'; c++)
1251                if (FLAG[c])
1252                        *cp++ = c;
1253        *cp = '\0';
1254        setval(lookup("-"), m);
1255}
1256
1257static int newfile(char *s)
1258{
1259        int f;
1260
1261        DBGPRINTF7(("NEWFILE: opening %s\n", s));
1262
1263        f = 0;
1264        if (NOT_LONE_DASH(s)) {
1265                DBGPRINTF(("NEWFILE: s is %s\n", s));
1266                f = open(s, O_RDONLY);
1267                if (f < 0) {
1268                        prs(s);
1269                        err(": can't open");
1270                        return 1;
1271                }
1272        }
1273
1274        next(remap(f));
1275        return 0;
1276}
1277
1278
1279#ifdef UNUSED
1280struct op *scantree(struct op *head)
1281{
1282        struct op *dotnode;
1283
1284        if (head == NULL)
1285                return NULL;
1286
1287        if (head->left != NULL) {
1288                dotnode = scantree(head->left);
1289                if (dotnode)
1290                        return dotnode;
1291        }
1292
1293        if (head->right != NULL) {
1294                dotnode = scantree(head->right);
1295                if (dotnode)
1296                        return dotnode;
1297        }
1298
1299        if (head->op_words == NULL)
1300                return NULL;
1301
1302        DBGPRINTF5(("SCANTREE: checking node %p\n", head));
1303
1304        if ((head->op_type != TDOT) && LONE_CHAR(head->op_words[0], '.')) {
1305                DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
1306                return head;
1307        }
1308
1309        return NULL;
1310}
1311#endif
1312
1313
1314static void onecommand(void)
1315{
1316        int i;
1317        jmp_buf m1;
1318
1319        DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
1320
1321        while (global_env.oenv)
1322                quitenv();
1323
1324        areanum = 1;
1325        freehere(areanum);
1326        freearea(areanum);
1327        garbage();
1328        wdlist = NULL;
1329        iolist = NULL;
1330        global_env.errpt = NULL;
1331        global_env.linep = line;
1332        yynerrs = 0;
1333        multiline = 0;
1334        inparse = 1;
1335        intr = 0;
1336        execflg = 0;
1337
1338        failpt = m1;
1339        setjmp(failpt);         /* Bruce Evans' fix */
1340        failpt = m1;
1341        if (setjmp(failpt) || yyparse() || intr) {
1342                DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1343
1344                while (global_env.oenv)
1345                        quitenv();
1346                scraphere();
1347                if (!interactive && intr)
1348                        leave();
1349                inparse = 0;
1350                intr = 0;
1351                return;
1352        }
1353
1354        inparse = 0;
1355        brklist = 0;
1356        intr = 0;
1357        execflg = 0;
1358
1359        if (!FLAG['n']) {
1360                DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
1361                                   outtree));
1362                execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
1363        }
1364
1365        if (!interactive && intr) {
1366                execflg = 0;
1367                leave();
1368        }
1369
1370        i = trapset;
1371        if (i != 0) {
1372                trapset = 0;
1373                runtrap(i);
1374        }
1375}
1376
1377static int newenv(int f)
1378{
1379        struct env *ep;
1380
1381        DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
1382
1383        if (f) {
1384                quitenv();
1385                return 1;
1386        }
1387
1388        ep = get_space(sizeof(*ep));
1389        if (ep == NULL) {
1390                while (global_env.oenv)
1391                        quitenv();
1392                fail();
1393        }
1394        *ep = global_env;
1395        global_env.oenv = ep;
1396        global_env.errpt = errpt;
1397
1398        return 0;
1399}
1400
1401static void quitenv(void)
1402{
1403        struct env *ep;
1404        int fd;
1405
1406        DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
1407
1408        ep = global_env.oenv;
1409        if (ep != NULL) {
1410                fd = global_env.iofd;
1411                global_env = *ep;
1412                /* should close `'d files */
1413                DELETE(ep);
1414                while (--fd >= global_env.iofd)
1415                        close(fd);
1416        }
1417}
1418
1419/*
1420 * Is character c in s?
1421 */
1422static int any(int c, const char *s)
1423{
1424        while (*s)
1425                if (*s++ == c)
1426                        return 1;
1427        return 0;
1428}
1429
1430/*
1431 * Is any character from s1 in s2?
1432 */
1433static int anys(const char *s1, const char *s2)
1434{
1435        while (*s1)
1436                if (any(*s1++, s2))
1437                        return 1;
1438        return 0;
1439}
1440
1441static char *putn(int n)
1442{
1443        return itoa(n);
1444}
1445
1446static void next(int f)
1447{
1448        PUSHIO(afile, f, filechar);
1449}
1450
1451static void onintr(int s UNUSED_PARAM) /* ANSI C requires a parameter */
1452{
1453        signal(SIGINT, onintr);
1454        intr = 1;
1455        if (interactive) {
1456                if (inparse) {
1457                        prs("\n");
1458                        fail();
1459                }
1460        } else if (heedint) {
1461                execflg = 0;
1462                leave();
1463        }
1464}
1465
1466
1467/* -------- gmatch.c -------- */
1468/*
1469 * int gmatch(string, pattern)
1470 * char *string, *pattern;
1471 *
1472 * Match a pattern as in sh(1).
1473 */
1474
1475#define CMASK   0377
1476#define QUOTE   0200
1477#define QMASK   (CMASK & ~QUOTE)
1478#define NOT     '!'                                     /* might use ^ */
1479
1480static const char *cclass(const char *p, int sub)
1481{
1482        int c, d, not, found;
1483
1484        not = (*p == NOT);
1485        if (not != 0)
1486                p++;
1487        found = not;
1488        do {
1489                if (*p == '\0')
1490                        return NULL;
1491                c = *p & CMASK;
1492                if (p[1] == '-' && p[2] != ']') {
1493                        d = p[2] & CMASK;
1494                        p++;
1495                } else
1496                        d = c;
1497                if (c == sub || (c <= sub && sub <= d))
1498                        found = !not;
1499        } while (*++p != ']');
1500        return found ? p + 1 : NULL;
1501}
1502
1503static int gmatch(const char *s, const char *p)
1504{
1505        int sc, pc;
1506
1507        if (s == NULL || p == NULL)
1508                return 0;
1509
1510        while ((pc = *p++ & CMASK) != '\0') {
1511                sc = *s++ & QMASK;
1512                switch (pc) {
1513                case '[':
1514                        p = cclass(p, sc);
1515                        if (p == NULL)
1516                                return 0;
1517                        break;
1518
1519                case '?':
1520                        if (sc == 0)
1521                                return 0;
1522                        break;
1523
1524                case '*':
1525                        s--;
1526                        do {
1527                                if (*p == '\0' || gmatch(s, p))
1528                                        return 1;
1529                        } while (*s++ != '\0');
1530                        return 0;
1531
1532                default:
1533                        if (sc != (pc & ~QUOTE))
1534                                return 0;
1535                }
1536        }
1537        return *s == '\0';
1538}
1539
1540
1541/* -------- csyn.c -------- */
1542/*
1543 * shell: syntax (C version)
1544 */
1545
1546static void yyerror(const char *s) NORETURN;
1547static void yyerror(const char *s)
1548{
1549        yynerrs = 1;
1550        if (interactive && global_env.iop <= iostack) {
1551                multiline = 0;
1552                while (eofc() == 0 && yylex(0) != '\n')
1553                        continue;
1554        }
1555        err(s);
1556        fail();
1557}
1558
1559static void zzerr(void) NORETURN;
1560static void zzerr(void)
1561{
1562        yyerror("syntax error");
1563}
1564
1565int yyparse(void)
1566{
1567        DBGPRINTF7(("YYPARSE: enter...\n"));
1568
1569        startl = 1;
1570        peeksym = 0;
1571        yynerrs = 0;
1572        outtree = c_list();
1573        musthave('\n', 0);
1574        return yynerrs; /* 0/1 */
1575}
1576
1577static struct op *pipeline(int cf)
1578{
1579        struct op *t, *p;
1580        int c;
1581
1582        DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
1583
1584        t = command(cf);
1585
1586        DBGPRINTF9(("PIPELINE: t=%p\n", t));
1587
1588        if (t != NULL) {
1589                while ((c = yylex(0)) == '|') {
1590                        p = command(CONTIN);
1591                        if (p == NULL) {
1592                                DBGPRINTF8(("PIPELINE: error!\n"));
1593                                zzerr();
1594                        }
1595
1596                        if (t->op_type != TPAREN && t->op_type != TCOM) {
1597                                /* shell statement */
1598                                t = block(TPAREN, t, NOBLOCK, NOWORDS);
1599                        }
1600
1601                        t = block(TPIPE, t, p, NOWORDS);
1602                }
1603                peeksym = c;
1604        }
1605
1606        DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
1607        return t;
1608}
1609
1610static struct op *andor(void)
1611{
1612        struct op *t, *p;
1613        int c;
1614
1615        DBGPRINTF7(("ANDOR: enter...\n"));
1616
1617        t = pipeline(0);
1618
1619        DBGPRINTF9(("ANDOR: t=%p\n", t));
1620
1621        if (t != NULL) {
1622                while ((c = yylex(0)) == LOGAND || c == LOGOR) {
1623                        p = pipeline(CONTIN);
1624                        if (p == NULL) {
1625                                DBGPRINTF8(("ANDOR: error!\n"));
1626                                zzerr();
1627                        }
1628
1629                        t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
1630                }
1631
1632                peeksym = c;
1633        }
1634
1635        DBGPRINTF7(("ANDOR: returning t=%p\n", t));
1636        return t;
1637}
1638
1639static struct op *c_list(void)
1640{
1641        struct op *t, *p;
1642        int c;
1643
1644        DBGPRINTF7(("C_LIST: enter...\n"));
1645
1646        t = andor();
1647
1648        if (t != NULL) {
1649                peeksym = yylex(0);
1650                if (peeksym == '&')
1651                        t = block(TASYNC, t, NOBLOCK, NOWORDS);
1652
1653                while ((c = yylex(0)) == ';' || c == '&'
1654                 || (multiline && c == '\n')
1655                ) {
1656                        p = andor();
1657                        if (p== NULL)
1658                                return t;
1659
1660                        peeksym = yylex(0);
1661                        if (peeksym == '&')
1662                                p = block(TASYNC, p, NOBLOCK, NOWORDS);
1663
1664                        t = list(t, p);
1665                }                                               /* WHILE */
1666
1667                peeksym = c;
1668        }
1669        /* IF */
1670        DBGPRINTF7(("C_LIST: returning t=%p\n", t));
1671        return t;
1672}
1673
1674static int synio(int cf)
1675{
1676        struct ioword *iop;
1677        int i;
1678        int c;
1679
1680        DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
1681
1682        c = yylex(cf);
1683        if (c != '<' && c != '>') {
1684                peeksym = c;
1685                return 0;
1686        }
1687
1688        i = yylval.i;
1689        musthave(WORD, 0);
1690        iop = io(iounit, i, yylval.cp);
1691        iounit = IODEFAULT;
1692
1693        if (i & IOHERE)
1694                markhere(yylval.cp, iop);
1695
1696        DBGPRINTF7(("SYNIO: returning 1\n"));
1697        return 1;
1698}
1699
1700static void musthave(int c, int cf)
1701{
1702        peeksym = yylex(cf);
1703        if (peeksym != c) {
1704                DBGPRINTF7(("MUSTHAVE: error!\n"));
1705                zzerr();
1706        }
1707
1708        peeksym = 0;
1709}
1710
1711static struct op *simple(void)
1712{
1713        struct op *t;
1714
1715        t = NULL;
1716        for (;;) {
1717                switch (peeksym = yylex(0)) {
1718                case '<':
1719                case '>':
1720                        (void) synio(0);
1721                        break;
1722
1723                case WORD:
1724                        if (t == NULL) {
1725                                t = newtp();
1726                                t->op_type = TCOM;
1727                        }
1728                        peeksym = 0;
1729                        word(yylval.cp);
1730                        break;
1731
1732                default:
1733                        return t;
1734                }
1735        }
1736}
1737
1738static struct op *nested(int type, int mark)
1739{
1740        struct op *t;
1741
1742        DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
1743
1744        multiline++;
1745        t = c_list();
1746        musthave(mark, 0);
1747        multiline--;
1748        return block(type, t, NOBLOCK, NOWORDS);
1749}
1750
1751static struct op *command(int cf)
1752{
1753        struct op *t;
1754        struct wdblock *iosave;
1755        int c;
1756
1757        DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
1758
1759        iosave = iolist;
1760        iolist = NULL;
1761
1762        if (multiline)
1763                cf |= CONTIN;
1764
1765        while (synio(cf))
1766                cf = 0;
1767
1768        c = yylex(cf);
1769
1770        switch (c) {
1771        default:
1772                peeksym = c;
1773                t = simple();
1774                if (t == NULL) {
1775                        if (iolist == NULL)
1776                                return NULL;
1777                        t = newtp();
1778                        t->op_type = TCOM;
1779                }
1780                break;
1781
1782        case '(':
1783                t = nested(TPAREN, ')');
1784                break;
1785
1786        case '{':
1787                t = nested(TBRACE, '}');
1788                break;
1789
1790        case FOR:
1791                t = newtp();
1792                t->op_type = TFOR;
1793                musthave(WORD, 0);
1794                startl = 1;
1795                t->str = yylval.cp;
1796                multiline++;
1797                t->op_words = wordlist();
1798                c = yylex(0);
1799                if (c != '\n' && c != ';')
1800                        peeksym = c;
1801                t->left = dogroup(0);
1802                multiline--;
1803                break;
1804
1805        case WHILE:
1806        case UNTIL:
1807                multiline++;
1808                t = newtp();
1809                t->op_type = (c == WHILE ? TWHILE : TUNTIL);
1810                t->left = c_list();
1811                t->right = dogroup(1);
1812                /* t->op_words = NULL; - newtp() did this */
1813                multiline--;
1814                break;
1815
1816        case CASE:
1817                t = newtp();
1818                t->op_type = TCASE;
1819                musthave(WORD, 0);
1820                t->str = yylval.cp;
1821                startl++;
1822                multiline++;
1823                musthave(IN, CONTIN);
1824                startl++;
1825
1826                t->left = caselist();
1827
1828                musthave(ESAC, 0);
1829                multiline--;
1830                break;
1831
1832        case IF:
1833                multiline++;
1834                t = newtp();
1835                t->op_type = TIF;
1836                t->left = c_list();
1837                t->right = thenpart();
1838                musthave(FI, 0);
1839                multiline--;
1840                break;
1841
1842        case DOT:
1843                t = newtp();
1844                t->op_type = TDOT;
1845
1846                musthave(WORD, 0);              /* gets name of file */
1847                DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1848
1849                word(yylval.cp);                /* add word to wdlist */
1850                word(NOWORD);                   /* terminate  wdlist */
1851                t->op_words = copyw();          /* dup wdlist */
1852                break;
1853
1854        }
1855
1856        while (synio(0))
1857                continue;
1858
1859        t = namelist(t);
1860        iolist = iosave;
1861
1862        DBGPRINTF(("COMMAND: returning %p\n", t));
1863
1864        return t;
1865}
1866
1867static struct op *dowholefile(int type /*, int mark*/)
1868{
1869        struct op *t;
1870
1871        DBGPRINTF(("DOWHOLEFILE: enter, type=%d\n", type /*, mark*/));
1872
1873        multiline++;
1874        t = c_list();
1875        multiline--;
1876        t = block(type, t, NOBLOCK, NOWORDS);
1877        DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
1878        return t;
1879}
1880
1881static struct op *dogroup(int onlydone)
1882{
1883        int c;
1884        struct op *mylist;
1885
1886        c = yylex(CONTIN);
1887        if (c == DONE && onlydone)
1888                return NULL;
1889        if (c != DO)
1890                zzerr();
1891        mylist = c_list();
1892        musthave(DONE, 0);
1893        return mylist;
1894}
1895
1896static struct op *thenpart(void)
1897{
1898        int c;
1899        struct op *t;
1900
1901        c = yylex(0);
1902        if (c != THEN) {
1903                peeksym = c;
1904                return NULL;
1905        }
1906        t = newtp();
1907        /*t->op_type = 0; - newtp() did this */
1908        t->left = c_list();
1909        if (t->left == NULL)
1910                zzerr();
1911        t->right = elsepart();
1912        return t;
1913}
1914
1915static struct op *elsepart(void)
1916{
1917        int c;
1918        struct op *t;
1919
1920        switch (c = yylex(0)) {
1921        case ELSE:
1922                t = c_list();
1923                if (t == NULL)
1924                        zzerr();
1925                return t;
1926
1927        case ELIF:
1928                t = newtp();
1929                t->op_type = TELIF;
1930                t->left = c_list();
1931                t->right = thenpart();
1932                return t;
1933
1934        default:
1935                peeksym = c;
1936                return NULL;
1937        }
1938}
1939
1940static struct op *caselist(void)
1941{
1942        struct op *t;
1943
1944        t = NULL;
1945        while ((peeksym = yylex(CONTIN)) != ESAC) {
1946                DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
1947                t = list(t, casepart());
1948        }
1949
1950        DBGPRINTF(("CASELIST, returning t=%p\n", t));
1951        return t;
1952}
1953
1954static struct op *casepart(void)
1955{
1956        struct op *t;
1957
1958        DBGPRINTF7(("CASEPART: enter...\n"));
1959
1960        t = newtp();
1961        t->op_type = TPAT;
1962        t->op_words = pattern();
1963        musthave(')', 0);
1964        t->left = c_list();
1965        peeksym = yylex(CONTIN);
1966        if (peeksym != ESAC)
1967                musthave(BREAK, CONTIN);
1968
1969        DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
1970
1971        return t;
1972}
1973
1974static char **pattern(void)
1975{
1976        int c, cf;
1977
1978        cf = CONTIN;
1979        do {
1980                musthave(WORD, cf);
1981                word(yylval.cp);
1982                cf = 0;
1983                c = yylex(0);
1984        } while (c == '|');
1985        peeksym = c;
1986        word(NOWORD);
1987
1988        return copyw();
1989}
1990
1991static char **wordlist(void)
1992{
1993        int c;
1994
1995        c = yylex(0);
1996        if (c != IN) {
1997                peeksym = c;
1998                return NULL;
1999        }
2000        startl = 0;
2001        while ((c = yylex(0)) == WORD)
2002                word(yylval.cp);
2003        word(NOWORD);
2004        peeksym = c;
2005        return copyw();
2006}
2007
2008/*
2009 * supporting functions
2010 */
2011static struct op *list(struct op *t1, struct op *t2)
2012{
2013        DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
2014
2015        if (t1 == NULL)
2016                return t2;
2017        if (t2 == NULL)
2018                return t1;
2019
2020        return block(TLIST, t1, t2, NOWORDS);
2021}
2022
2023static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
2024{
2025        struct op *t;
2026
2027        DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
2028
2029        t = newtp();
2030        t->op_type = type;
2031        t->left = t1;
2032        t->right = t2;
2033        t->op_words = wp;
2034
2035        DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
2036
2037        return t;
2038}
2039
2040/* See if given string is a shell multiline (FOR, IF, etc) */
2041static int rlookup(char *n)
2042{
2043        struct res {
2044                char r_name[6];
2045                int16_t r_val;
2046        };
2047        static const struct res restab[] = {
2048                { "for"  , FOR    },
2049                { "case" , CASE   },
2050                { "esac" , ESAC   },
2051                { "while", WHILE  },
2052                { "do"   , DO     },
2053                { "done" , DONE   },
2054                { "if"   , IF     },
2055                { "in"   , IN     },
2056                { "then" , THEN   },
2057                { "else" , ELSE   },
2058                { "elif" , ELIF   },
2059                { "until", UNTIL  },
2060                { "fi"   , FI     },
2061                { ";;"   , BREAK  },
2062                { "||"   , LOGOR  },
2063                { "&&"   , LOGAND },
2064                { "{"    , '{'    },
2065                { "}"    , '}'    },
2066                { "."    , DOT    },
2067                { },
2068        };
2069
2070        const struct res *rp;
2071
2072        DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
2073
2074        for (rp = restab; rp->r_name[0]; rp++)
2075                if (strcmp(rp->r_name, n) == 0) {
2076                        DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
2077                        return rp->r_val;       /* Return numeric code for shell multiline */
2078                }
2079
2080        DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2081        return 0;                                       /* Not a shell multiline */
2082}
2083
2084static struct op *newtp(void)
2085{
2086        struct op *t;
2087
2088        t = (struct op *) tree(sizeof(*t));
2089        memset(t, 0, sizeof(*t));
2090
2091        DBGPRINTF3(("NEWTP: allocated %p\n", t));
2092
2093        return t;
2094}
2095
2096static struct op *namelist(struct op *t)
2097{
2098        DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
2099                                T_CMD_NAMES[t->op_type], iolist));
2100
2101        if (iolist) {
2102                iolist = addword((char *) NULL, iolist);
2103                t->ioact = copyio();
2104        } else
2105                t->ioact = NULL;
2106
2107        if (t->op_type != TCOM) {
2108                if (t->op_type != TPAREN && t->ioact != NULL) {
2109                        t = block(TPAREN, t, NOBLOCK, NOWORDS);
2110                        t->ioact = t->left->ioact;
2111                        t->left->ioact = NULL;
2112                }
2113                return t;
2114        }
2115
2116        word(NOWORD);
2117        t->op_words = copyw();
2118
2119        return t;
2120}
2121
2122static char **copyw(void)
2123{
2124        char **wd;
2125
2126        wd = getwords(wdlist);
2127        wdlist = NULL;
2128        return wd;
2129}
2130
2131static void word(char *cp)
2132{
2133        wdlist = addword(cp, wdlist);
2134}
2135
2136static struct ioword **copyio(void)
2137{
2138        struct ioword **iop;
2139
2140        iop = (struct ioword **) getwords(iolist);
2141        iolist = NULL;
2142        return iop;
2143}
2144
2145static struct ioword *io(int u, int f, char *cp)
2146{
2147        struct ioword *iop;
2148
2149        iop = (struct ioword *) tree(sizeof(*iop));
2150        iop->io_fd = u;
2151        iop->io_flag = f;
2152        iop->io_name = cp;
2153        iolist = addword((char *) iop, iolist);
2154        return iop;
2155}
2156
2157static int yylex(int cf)
2158{
2159        int c, c1;
2160        int atstart;
2161
2162        c = peeksym;
2163        if (c > 0) {
2164                peeksym = 0;
2165                if (c == '\n')
2166                        startl = 1;
2167                return c;
2168        }
2169
2170        nlseen = 0;
2171        atstart = startl;
2172        startl = 0;
2173        yylval.i = 0;
2174        global_env.linep = line;
2175
2176/* MALAMO */
2177        line[LINELIM - 1] = '\0';
2178
2179 loop:
2180        while ((c = my_getc(0)) == ' ' || c == '\t')    /* Skip whitespace */
2181                continue;
2182
2183        switch (c) {
2184        default:
2185                if (any(c, "0123456789")) {
2186                        c1 = my_getc(0);
2187                        unget(c1);
2188                        if (c1 == '<' || c1 == '>') {
2189                                iounit = c - '0';
2190                                goto loop;
2191                        }
2192                        *global_env.linep++ = c;
2193                        c = c1;
2194                }
2195                break;
2196
2197        case '#':       /* Comment, skip to next newline or End-of-string */
2198                while ((c = my_getc(0)) != '\0' && c != '\n')
2199                        continue;
2200                unget(c);
2201                goto loop;
2202
2203        case 0:
2204                DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
2205                return c;
2206
2207        case '$':
2208                DBGPRINTF9(("YYLEX: found $\n"));
2209                *global_env.linep++ = c;
2210                c = my_getc(0);
2211                if (c == '{') {
2212                        c = collect(c, '}');
2213                        if (c != '\0')
2214                                return c;
2215                        goto pack;
2216                }
2217                break;
2218
2219        case '`':
2220        case '\'':
2221        case '"':
2222                c = collect(c, c);
2223                if (c != '\0')
2224                        return c;
2225                goto pack;
2226
2227        case '|':
2228        case '&':
2229        case ';':
2230                startl = 1;
2231                /* If more chars process them, else return NULL char */
2232                c1 = dual(c);
2233                if (c1 != '\0')
2234                        return c1;
2235                return c;
2236
2237        case '^':
2238                startl = 1;
2239                return '|';
2240        case '>':
2241        case '<':
2242                diag(c);
2243                return c;
2244
2245        case '\n':
2246                nlseen++;
2247                gethere();
2248                startl = 1;
2249                if (multiline || cf & CONTIN) {
2250                        if (interactive && global_env.iop <= iostack) {
2251#if ENABLE_FEATURE_EDITING
2252                                current_prompt = cprompt->value;
2253#else
2254                                prs(cprompt->value);
2255#endif
2256                        }
2257                        if (cf & CONTIN)
2258                                goto loop;
2259                }
2260                return c;
2261
2262        case '(':
2263        case ')':
2264                startl = 1;
2265                return c;
2266        }
2267
2268        unget(c);
2269
2270 pack:
2271        while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
2272                if (global_env.linep >= elinep)
2273                        err("word too long");
2274                else
2275                        *global_env.linep++ = c;
2276        };
2277
2278        unget(c);
2279
2280        if (any(c, "\"'`$"))
2281                goto loop;
2282
2283        *global_env.linep++ = '\0';
2284
2285        if (atstart) {
2286                c = rlookup(line);
2287                if (c != 0) {
2288                        startl = 1;
2289                        return c;
2290                }
2291        }
2292
2293        yylval.cp = strsave(line, areanum);
2294        return WORD;
2295}
2296
2297
2298static int collect(int c, int c1)
2299{
2300        char s[2];
2301
2302        DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2303
2304        *global_env.linep++ = c;
2305        while ((c = my_getc(c1)) != c1) {
2306                if (c == 0) {
2307                        unget(c);
2308                        s[0] = c1;
2309                        s[1] = 0;
2310                        prs("no closing ");
2311                        yyerror(s);
2312                        return YYERRCODE;
2313                }
2314                if (interactive && c == '\n' && global_env.iop <= iostack) {
2315#if ENABLE_FEATURE_EDITING
2316                        current_prompt = cprompt->value;
2317#else
2318                        prs(cprompt->value);
2319#endif
2320                }
2321                *global_env.linep++ = c;
2322        }
2323
2324        *global_env.linep++ = c;
2325
2326        DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2327
2328        return 0;
2329}
2330
2331/* "multiline commands" helper func */
2332/* see if next 2 chars form a shell multiline */
2333static int dual(int c)
2334{
2335        char s[3];
2336        char *cp = s;
2337
2338        DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2339
2340        *cp++ = c;              /* c is the given "peek" char */
2341        *cp++ = my_getc(0);     /* get next char of input */
2342        *cp = '\0';             /* add EOS marker */
2343
2344        c = rlookup(s);         /* see if 2 chars form a shell multiline */
2345        if (c == 0)
2346                unget(*--cp);   /* String is not a shell multiline, put peek char back */
2347
2348        return c;               /* String is multiline, return numeric multiline (restab) code */
2349}
2350
2351static void diag(int ec)
2352{
2353        int c;
2354
2355        DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
2356
2357        c = my_getc(0);
2358        if (c == '>' || c == '<') {
2359                if (c != ec)
2360                        zzerr();
2361                yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
2362                c = my_getc(0);
2363        } else
2364                yylval.i = (ec == '>' ? IOWRITE : IOREAD);
2365        if (c != '&' || yylval.i == IOHERE)
2366                unget(c);
2367        else
2368                yylval.i |= IODUP;
2369}
2370
2371static char *tree(unsigned size)
2372{
2373        char *t;
2374
2375        t = getcell(size);
2376        if (t == NULL) {
2377                DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
2378                prs("command line too complicated\n");
2379                fail();
2380                /* NOTREACHED */
2381        }
2382        return t;
2383}
2384
2385
2386/* VARARGS1 */
2387/* ARGSUSED */
2388
2389/* -------- exec.c -------- */
2390
2391static struct op **find1case(struct op *t, const char *w)
2392{
2393        struct op *t1;
2394        struct op **tp;
2395        char **wp;
2396        char *cp;
2397
2398        if (t == NULL) {
2399                DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2400                return NULL;
2401        }
2402
2403        DBGPRINTF3(("FIND1CASE: enter, t->op_type=%d (%s)\n", t->op_type,
2404                                T_CMD_NAMES[t->op_type]));
2405
2406        if (t->op_type == TLIST) {
2407                tp = find1case(t->left, w);
2408                if (tp != NULL) {
2409                        DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2410                        return tp;
2411                }
2412                t1 = t->right;                  /* TPAT */
2413        } else
2414                t1 = t;
2415
2416        for (wp = t1->op_words; *wp;) {
2417                cp = evalstr(*wp++, DOSUB);
2418                if (cp && gmatch(w, cp)) {
2419                        DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2420                                                &t1->left));
2421                        return &t1->left;
2422                }
2423        }
2424
2425        DBGPRINTF(("FIND1CASE: returning NULL\n"));
2426        return NULL;
2427}
2428
2429static struct op *findcase(struct op *t, const char *w)
2430{
2431        struct op **tp;
2432
2433        tp = find1case(t, w);
2434        return tp != NULL ? *tp : NULL;
2435}
2436
2437/*
2438 * execute tree
2439 */
2440
2441static int execute(struct op *t, int *pin, int *pout, int no_fork)
2442{
2443        struct op *t1;
2444        volatile int i, rv, a;
2445        const char *cp;
2446        char **wp, **wp2;
2447        struct var *vp;
2448        struct op *outtree_save;
2449        struct brkcon bc;
2450
2451#if __GNUC__
2452        /* Avoid longjmp clobbering */
2453        (void) &wp;
2454#endif
2455
2456        if (t == NULL) {
2457                DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
2458                return 0;
2459        }
2460
2461        DBGPRINTF(("EXECUTE: t=%p, t->op_type=%d (%s), t->op_words is %s\n", t,
2462                           t->op_type, T_CMD_NAMES[t->op_type],
2463                           ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
2464
2465        rv = 0;
2466        a = areanum++;
2467        wp2 = t->op_words;
2468        wp = (wp2 != NULL)
2469                ? eval(wp2, t->op_type == TCOM ? DOALL : DOALL & ~DOKEY)
2470                : NULL;
2471
2472        switch (t->op_type) {
2473        case TDOT:
2474                DBGPRINTF3(("EXECUTE: TDOT\n"));
2475
2476                outtree_save = outtree;
2477
2478                newfile(evalstr(t->op_words[0], DOALL));
2479
2480                t->left = dowholefile(TLIST /*, 0*/);
2481                t->right = NULL;
2482
2483                outtree = outtree_save;
2484
2485                if (t->left)
2486                        rv = execute(t->left, pin, pout, /* no_fork: */ 0);
2487                if (t->right)
2488                        rv = execute(t->right, pin, pout, /* no_fork: */ 0);
2489                break;
2490
2491        case TPAREN:
2492                rv = execute(t->left, pin, pout, /* no_fork: */ 0);
2493                break;
2494
2495        case TCOM:
2496                rv = forkexec(t, pin, pout, no_fork, wp);
2497                break;
2498
2499        case TPIPE:
2500                {
2501                        int pv[2];
2502
2503                        rv = openpipe(pv);
2504                        if (rv < 0)
2505                                break;
2506                        pv[0] = remap(pv[0]);
2507                        pv[1] = remap(pv[1]);
2508                        (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2509                        rv = execute(t->right, pv, pout, /* no_fork: */ 0);
2510                }
2511                break;
2512
2513        case TLIST:
2514                (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2515                rv = execute(t->right, pin, pout, /* no_fork: */ 0);
2516                break;
2517
2518        case TASYNC:
2519                {
2520                        smallint hinteractive = interactive;
2521
2522                        DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2523
2524                        i = vfork();
2525                        if (i == 0) { /* child */
2526                                signal(SIGINT, SIG_IGN);
2527                                signal(SIGQUIT, SIG_IGN);
2528                                if (interactive)
2529                                        signal(SIGTERM, SIG_DFL);
2530                                interactive = 0;
2531                                if (pin == NULL) {
2532                                        close(0);
2533                                        xopen(bb_dev_null, O_RDONLY);
2534                                }
2535                                _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
2536                        }
2537                        interactive = hinteractive;
2538                        if (i != -1) {
2539                                setval(lookup("!"), putn(i));
2540                                closepipe(pin);
2541                                if (interactive) {
2542                                        prs(putn(i));
2543                                        prs("\n");
2544                                }
2545                        } else
2546                                rv = -1;
2547                        setstatus(rv);
2548                }
2549                break;
2550
2551        case TOR:
2552        case TAND:
2553                rv = execute(t->left, pin, pout, /* no_fork: */ 0);
2554                t1 = t->right;
2555                if (t1 != NULL && (rv == 0) == (t->op_type == TAND))
2556                        rv = execute(t1, pin, pout, /* no_fork: */ 0);
2557                break;
2558
2559        case TFOR:
2560                if (wp == NULL) {
2561                        wp = dolv + 1;
2562                        i = dolc;
2563                        if (i < 0)
2564                                i = 0;
2565                } else {
2566                        i = -1;
2567                        while (*wp++ != NULL)
2568                                continue;
2569                }
2570                vp = lookup(t->str);
2571                while (setjmp(bc.brkpt))
2572                        if (isbreak)
2573                                goto broken;
2574                /* Restore areanum value. It may be incremented by execute()
2575                 * below, and then "continue" may jump back to setjmp above */
2576                areanum = a + 1;
2577                freearea(areanum + 1);
2578                brkset(&bc);
2579                for (t1 = t->left; i-- && *wp != NULL;) {
2580                        setval(vp, *wp++);
2581                        rv = execute(t1, pin, pout, /* no_fork: */ 0);
2582                }
2583                brklist = brklist->nextlev;
2584                break;
2585
2586        case TWHILE:
2587        case TUNTIL:
2588                while (setjmp(bc.brkpt))
2589                        if (isbreak)
2590                                goto broken;
2591                /* Restore areanum value. It may be incremented by execute()
2592                 * below, and then "continue" may jump back to setjmp above */
2593                areanum = a + 1;
2594                freearea(areanum + 1);
2595                brkset(&bc);
2596                t1 = t->left;
2597                while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->op_type == TWHILE))
2598                        rv = execute(t->right, pin, pout, /* no_fork: */ 0);
2599                brklist = brklist->nextlev;
2600                break;
2601
2602        case TIF:
2603        case TELIF:
2604                if (t->right != NULL) {
2605                        rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2606                                execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2607                                execute(t->right->right, pin, pout, /* no_fork: */ 0);
2608                }
2609                break;
2610
2611        case TCASE:
2612                cp = evalstr(t->str, DOSUB | DOTRIM);
2613                if (cp == NULL)
2614                        cp = "";
2615
2616                DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2617                                        ((t->str == NULL) ? "NULL" : t->str),
2618                                        ((cp == NULL) ? "NULL" : cp)));
2619
2620                t1 = findcase(t->left, cp);
2621                if (t1 != NULL) {
2622                        DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
2623                        rv = execute(t1, pin, pout, /* no_fork: */ 0);
2624                        DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
2625                }
2626                break;
2627
2628        case TBRACE:
2629/*
2630                iopp = t->ioact;
2631                if (i)
2632                        while (*iopp)
2633                                if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2634                                        rv = -1;
2635                                        break;
2636                                }
2637*/
2638                if (rv >= 0) {
2639                        t1 = t->left;
2640                        if (t1) {
2641                                rv = execute(t1, pin, pout, /* no_fork: */ 0);
2642                        }
2643                }
2644                break;
2645
2646        };
2647
2648 broken:
2649// Restoring op_words is most likely not needed now: see comment in forkexec()
2650// (also take a look at exec builtin (doexec) - it touches t->op_words)
2651        t->op_words = wp2;
2652        isbreak = 0;
2653        freehere(areanum);
2654        freearea(areanum);
2655        areanum = a;
2656        if (interactive && intr) {
2657                closeall();
2658                fail();
2659        }
2660
2661        i = trapset;
2662        if (i != 0) {
2663                trapset = 0;
2664                runtrap(i);
2665        }
2666
2667        DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
2668        return rv;
2669}
2670
2671static builtin_func_ptr inbuilt(const char *s)
2672{
2673        const struct builtincmd *bp;
2674
2675        for (bp = builtincmds; bp->name; bp++)
2676                if (strcmp(bp->name, s) == 0)
2677                        return bp->builtinfunc;
2678        return NULL;
2679}
2680
2681static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
2682{
2683        pid_t newpid;
2684        int i;
2685        builtin_func_ptr bltin = NULL;
2686        const char *bltin_name = NULL;
2687        const char *cp;
2688        struct ioword **iopp;
2689        int resetsig;
2690        char **owp;
2691        int forked;
2692
2693        int *hpin = pin;
2694        int *hpout = pout;
2695        char *hwp;
2696        smallint hinteractive;
2697        smallint hintr;
2698        smallint hexecflg;
2699        struct brkcon *hbrklist;
2700
2701#if __GNUC__
2702        /* Avoid longjmp clobbering */
2703        (void) &pin;
2704        (void) &pout;
2705        (void) &wp;
2706        (void) &bltin;
2707        (void) &cp;
2708        (void) &resetsig;
2709        (void) &owp;
2710#endif
2711
2712        DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2713                        pout, no_fork));
2714        DBGPRINTF7(("FORKEXEC: t->op_words is %s\n",
2715                        ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
2716        owp = wp;
2717        resetsig = 0;
2718        if (t->op_type == TCOM) {
2719                while (*wp++ != NULL)
2720                        continue;
2721                cp = *wp;
2722
2723                /* strip all initial assignments */
2724                /* FIXME: not correct wrt PATH=yyy command etc */
2725                if (FLAG['x']) {
2726                        DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
2727                                                cp, wp, owp));
2728                        echo(cp ? wp : owp);
2729                }
2730
2731                if (cp == NULL) {
2732                        if (t->ioact == NULL) {
2733                                while ((cp = *owp++) != NULL && assign(cp, COPYV))
2734                                        continue;
2735                                DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2736                                return setstatus(0);
2737                        }
2738                } else { /* cp != NULL */
2739                        bltin_name = cp;
2740                        bltin = inbuilt(cp);
2741                }
2742        }
2743
2744        forked = 0;
2745        // We were pointing t->op_words to temporary (expanded) arg list:
2746        // t->op_words = wp;
2747        // and restored it later (in execute()), but "break"
2748        // longjmps away (at "Run builtin" below), leaving t->op_words clobbered!
2749        // See http://bugs.busybox.net/view.php?id=846.
2750        // Now we do not touch t->op_words, but separately pass wp as param list
2751        // to builtins
2752        DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2753                        no_fork, owp));
2754        /* Don't fork if it is a lone builtin (not in pipe)
2755         * OR we are told to _not_ fork */
2756        if ((!bltin || pin || pout)   /* not lone bltin AND */
2757         && !no_fork                  /* not told to avoid fork */
2758        ) {
2759                /* Save values in case child alters them after vfork */
2760                hpin = pin;
2761                hpout = pout;
2762                hwp = *wp;
2763                hinteractive = interactive;
2764                hintr = intr;
2765                hbrklist = brklist;
2766                hexecflg = execflg;
2767
2768                DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2769                newpid = vfork();
2770                if (newpid == -1) {
2771                        DBGPRINTF(("FORKEXEC: ERROR, can't vfork()!\n"));
2772                        return -1;
2773                }
2774
2775                if (newpid > 0) {  /* Parent */
2776                        /* Restore values */
2777                        pin = hpin;
2778                        pout = hpout;
2779                        *wp = hwp;
2780                        interactive = hinteractive;
2781                        intr = hintr;
2782                        brklist = hbrklist;
2783                        execflg = hexecflg;
2784
2785                        closepipe(pin);
2786                        return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
2787                }
2788
2789                /* Child */
2790                DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
2791                if (interactive) {
2792                        signal(SIGINT, SIG_IGN);
2793                        signal(SIGQUIT, SIG_IGN);
2794                        resetsig = 1;
2795                }
2796                interactive = 0;
2797                intr = 0;
2798                forked = 1;
2799                brklist = 0;
2800                execflg = 0;
2801        }
2802
2803        if (owp)
2804                while ((cp = *owp++) != NULL && assign(cp, COPYV))
2805                        if (!bltin)
2806                                export(lookup(cp));
2807
2808        if (pin) { /* NB: close _first_, then move fds! */
2809                close(pin[1]);
2810                xmove_fd(pin[0], 0);
2811        }
2812        if (pout) {
2813                close(pout[0]);
2814                xmove_fd(pout[1], 1);
2815        }
2816
2817        iopp = t->ioact;
2818        if (iopp) {
2819                if (bltin && bltin != doexec) {
2820                        prs(bltin_name);
2821                        err(": can't redirect shell command");
2822                        if (forked)
2823                                _exit(-1);
2824                        return -1;
2825                }
2826                while (*iopp) {
2827                        if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2828                                /* system-detected error */
2829                                if (forked)
2830                                        _exit(-1);
2831                                return -1;
2832                        }
2833                }
2834        }
2835
2836        if (bltin) {
2837                if (forked || pin || pout) {
2838                        /* Builtin in pipe: disallowed */
2839                        /* TODO: allow "exec"? */
2840                        prs(bltin_name);
2841                        err(": can't run builtin as part of pipe");
2842                        if (forked)
2843                                _exit(-1);
2844                        return -1;
2845                }
2846                /* Run builtin */
2847                i = setstatus(bltin(t, wp));
2848                if (forked)
2849                        _exit(i);
2850                DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
2851                return i;
2852        }
2853
2854        /* should use FIOCEXCL */
2855        for (i = FDBASE; i < NOFILE; i++)
2856                close(i);
2857        if (resetsig) {
2858                signal(SIGINT, SIG_DFL);
2859                signal(SIGQUIT, SIG_DFL);
2860        }
2861
2862        if (t->op_type == TPAREN)
2863                _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
2864        if (wp[0] == NULL)
2865                _exit(EXIT_SUCCESS);
2866
2867        cp = rexecve(wp[0], wp, makenv(0, NULL));
2868        prs(wp[0]);
2869        prs(": ");
2870        err(cp);
2871        if (!execflg)
2872                trap[0] = NULL;
2873
2874        DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
2875
2876        leave();
2877        /* NOTREACHED */
2878        return 0;
2879}
2880
2881/*
2882 * 0< 1> are ignored as required
2883 * within pipelines.
2884 */
2885static int iosetup(struct ioword *iop, int pipein, int pipeout)
2886{
2887        int u = -1;
2888        char *cp = NULL;
2889        const char *msg;
2890
2891        DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
2892                           pipein, pipeout));
2893
2894        if (iop->io_fd == IODEFAULT)    /* take default */
2895                iop->io_fd = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
2896
2897        if (pipein && iop->io_fd == 0)
2898                return 0;
2899
2900        if (pipeout && iop->io_fd == 1)
2901                return 0;
2902
2903        msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
2904        if ((iop->io_flag & IOHERE) == 0) {
2905                cp = iop->io_name; /* huh?? */
2906                cp = evalstr(cp, DOSUB | DOTRIM);
2907                if (cp == NULL)
2908                        return 1;
2909        }
2910
2911        if (iop->io_flag & IODUP) {
2912                if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2913                        prs(cp);
2914                        err(": illegal >& argument");
2915                        return 1;
2916                }
2917                if (*cp == '-')
2918                        iop->io_flag = IOCLOSE;
2919                iop->io_flag &= ~(IOREAD | IOWRITE);
2920        }
2921
2922        switch (iop->io_flag) {
2923        case IOREAD:
2924                u = open(cp, O_RDONLY);
2925                break;
2926
2927        case IOHERE:
2928        case IOHERE | IOXHERE:
2929                u = herein(iop->io_name, iop->io_flag & IOXHERE);
2930                cp = (char*)"here file";
2931                break;
2932
2933        case IOWRITE | IOCAT:
2934                u = open(cp, O_WRONLY);
2935                if (u >= 0) {
2936                        lseek(u, (long) 0, SEEK_END);
2937                        break;
2938                }
2939                /* fall through to creation if >>file doesn't exist */
2940
2941        case IOWRITE:
2942                u = creat(cp, 0666);
2943                break;
2944
2945        case IODUP:
2946                u = dup2(*cp - '0', iop->io_fd);
2947                break;
2948
2949        case IOCLOSE:
2950                close(iop->io_fd);
2951                return 0;
2952        }
2953
2954        if (u < 0) {
2955                prs(cp);
2956                prs(": can't ");
2957                warn(msg);
2958                return 1;
2959        }
2960        xmove_fd(u, iop->io_fd);
2961        return 0;
2962}
2963
2964/*
2965 * Enter a new loop level (marked for break/continue).
2966 */
2967static void brkset(struct brkcon *bc)
2968{
2969        bc->nextlev = brklist;
2970        brklist = bc;
2971}
2972
2973/*
2974 * Wait for the last process created.
2975 * Print a message for each process found
2976 * that was killed by a signal.
2977 * Ignore interrupt signals while waiting
2978 * unless `canintr' is true.
2979 */
2980static int waitfor(int lastpid, int canintr)
2981{
2982        int pid, rv;
2983        int s;
2984        smallint oheedint = heedint;
2985
2986        heedint = 0;
2987        rv = 0;
2988        do {
2989                pid = wait(&s);
2990                if (pid == -1) {
2991                        if (errno != EINTR || canintr)
2992                                break;
2993                } else {
2994                        rv = WAITSIG(s);
2995                        if (rv != 0) {
2996                                if (rv < ARRAY_SIZE(signame)) {
2997                                        if (signame[rv] != NULL) {
2998                                                if (pid != lastpid) {
2999                                                        prn(pid);
3000                                                        prs(": ");
3001                                                }
3002                                                prs(signame[rv]);
3003                                        }
3004                                } else {
3005                                        if (pid != lastpid) {
3006                                                prn(pid);
3007                                                prs(": ");
3008                                        }
3009                                        prs("Signal ");
3010                                        prn(rv);
3011                                        prs(" ");
3012                                }
3013                                if (WAITCORE(s))
3014                                        prs(" - core dumped");
3015                                if (rv >= ARRAY_SIZE(signame) || signame[rv])
3016                                        prs("\n");
3017                                rv |= 0x80;
3018                        } else
3019                                rv = WAITVAL(s);
3020                }
3021        } while (pid != lastpid);
3022        heedint = oheedint;
3023        if (intr) {
3024                if (interactive) {
3025                        if (canintr)
3026                                intr = 0;
3027                } else {
3028                        if (exstat == 0)
3029                                exstat = rv;
3030                        onintr(0);
3031                }
3032        }
3033        return rv;
3034}
3035
3036static int setstatus(int s)
3037{
3038        exstat = s;
3039        setval(lookup("?"), putn(s));
3040        return s;
3041}
3042
3043/*
3044 * PATH-searching interface to execve.
3045 * If getenv("PATH") were kept up-to-date,
3046 * execvp might be used.
3047 */
3048static const char *rexecve(char *c, char **v, char **envp)
3049{
3050        const char *sp;
3051        char *tp;
3052        int asis = 0;
3053        char *name = c;
3054
3055        if (ENABLE_FEATURE_SH_STANDALONE) {
3056                if (find_applet_by_name(name) >= 0) {
3057                        /* We have to exec here since we vforked.  Running
3058                         * run_applet_and_exit() won't work and bad things
3059                         * will happen. */
3060                        execve(bb_busybox_exec_path, v, envp);
3061                }
3062        }
3063
3064        DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
3065
3066        sp = any('/', c) ? "" : path->value;
3067        asis = (*sp == '\0');
3068        while (asis || *sp != '\0') {
3069                asis = 0;
3070                tp = global_env.linep;
3071                for (; *sp != '\0'; tp++) {
3072                        *tp = *sp++;
3073                        if (*tp == ':') {
3074                                asis = (*sp == '\0');
3075                                break;
3076                        }
3077                }
3078                if (tp != global_env.linep)
3079                        *tp++ = '/';
3080                strcpy(tp, c);
3081
3082                DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
3083
3084                execve(global_env.linep, v, envp);
3085
3086                switch (errno) {
3087                case ENOEXEC:
3088                        /* File is executable but file format isnt recognized */
3089                        /* Run it as a shell script */
3090                        /* (execve above didnt do it itself, unlike execvp) */
3091                        *v = global_env.linep;
3092                        v--;
3093                        tp = *v;
3094                        *v = (char*)DEFAULT_SHELL;
3095                        execve(DEFAULT_SHELL, v, envp);
3096                        *v = tp;
3097                        return "no shell";
3098
3099                case ENOMEM:
3100                        return (char *) bb_msg_memory_exhausted;
3101
3102                case E2BIG:
3103                        return "argument list too long";
3104                }
3105        }
3106        if (errno == ENOENT) {
3107                exstat = 127; /* standards require this */
3108                return "not found";
3109        }
3110        exstat = 126; /* mimic bash */
3111        return "can't execute";
3112}
3113
3114/*
3115 * Run the command produced by generator `f'
3116 * applied to stream `arg'.
3117 */
3118static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3119{
3120        struct op *otree;
3121        struct wdblock *swdlist;
3122        struct wdblock *siolist;
3123        jmp_buf ev, rt;
3124        xint *ofail;
3125        int rv;
3126
3127#if __GNUC__
3128        /* Avoid longjmp clobbering */
3129        (void) &rv;
3130#endif
3131
3132        DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
3133                           areanum, outtree, failpt));
3134
3135        areanum++;
3136        swdlist = wdlist;
3137        siolist = iolist;
3138        otree = outtree;
3139        ofail = failpt;
3140        rv = -1;
3141
3142        errpt = ev;
3143        if (newenv(setjmp(errpt)) == 0) {
3144                wdlist = NULL;
3145                iolist = NULL;
3146                pushio(argp, f);
3147                global_env.iobase = global_env.iop;
3148                yynerrs = 0;
3149                failpt = rt;
3150                if (setjmp(failpt) == 0 && yyparse() == 0)
3151                        rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
3152                quitenv();
3153        } else {
3154                DBGPRINTF(("RUN: error from newenv()!\n"));
3155        }
3156
3157        wdlist = swdlist;
3158        iolist = siolist;
3159        failpt = ofail;
3160        outtree = otree;
3161        freearea(areanum--);
3162
3163        return rv;
3164}
3165
3166/* -------- do.c -------- */
3167
3168/*
3169 * built-in commands: doX
3170 */
3171
3172static int dohelp(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
3173{
3174        int col;
3175        const struct builtincmd *x;
3176
3177        printf("\n"
3178                "Built-in commands:\n"
3179                "------------------\n");
3180
3181        col = 0;
3182        x = builtincmds;
3183        while (x->name) {
3184                col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
3185                if (col > 60) {
3186                        bb_putchar('\n');
3187                        col = 0;
3188                }
3189                x++;
3190        }
3191#if ENABLE_FEATURE_SH_STANDALONE
3192        {
3193                const char *applet = applet_names;
3194
3195                while (*applet) {
3196                        col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
3197                        if (col > 60) {
3198                                bb_putchar('\n');
3199                                col = 0;
3200                        }
3201                        applet += strlen(applet) + 1;
3202                }
3203        }
3204#endif
3205        puts("\n");
3206        return EXIT_SUCCESS;
3207}
3208
3209static int dolabel(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
3210{
3211        return 0;
3212}
3213
3214static int dochdir(struct op *t UNUSED_PARAM, char **args)
3215{
3216        const char *cp, *er;
3217
3218        cp = args[1];
3219        if (cp == NULL) {
3220                cp = homedir->value;
3221                if (cp != NULL)
3222                        goto do_cd;
3223                er = ": no home directory";
3224        } else {
3225 do_cd:
3226                if (chdir(cp) >= 0)
3227                        return 0;
3228                er = ": bad directory";
3229        }
3230        prs(cp != NULL ? cp : "cd");
3231        err(er);
3232        return 1;
3233}
3234
3235static int doshift(struct op *t UNUSED_PARAM, char **args)
3236{
3237        int n;
3238
3239        n = args[1] ? getn(args[1]) : 1;
3240        if (dolc < n) {
3241                err("nothing to shift");
3242                return 1;
3243        }
3244        dolv[n] = dolv[0];
3245        dolv += n;
3246        dolc -= n;
3247        setval(lookup("#"), putn(dolc));
3248        return 0;
3249}
3250
3251/*
3252 * execute login and newgrp directly
3253 */
3254static int dologin(struct op *t UNUSED_PARAM, char **args)
3255{
3256        const char *cp;
3257
3258        if (interactive) {
3259                signal(SIGINT, SIG_DFL);
3260                signal(SIGQUIT, SIG_DFL);
3261        }
3262        cp = rexecve(args[0], args, makenv(0, NULL));
3263        prs(args[0]);
3264        prs(": ");
3265        err(cp);
3266        return 1;
3267}
3268
3269static int doumask(struct op *t UNUSED_PARAM, char **args)
3270{
3271        int i;
3272        char *cp;
3273
3274        cp = args[1];
3275        if (cp == NULL) {
3276                i = umask(0);
3277                umask(i);
3278                printf("%04o\n", i);
3279        } else {
3280                i = bb_strtou(cp, NULL, 8);
3281                if (errno) {
3282                        err("umask: bad octal number");
3283                        return 1;
3284                }
3285                umask(i);
3286        }
3287        return 0;
3288}
3289
3290static int doexec(struct op *t, char **args)
3291{
3292        jmp_buf ex;
3293        xint *ofail;
3294        char **sv_words;
3295
3296        t->ioact = NULL;
3297        if (!args[1])
3298                return 1;
3299
3300        execflg = 1;
3301        ofail = failpt;
3302        failpt = ex;
3303
3304        sv_words = t->op_words;
3305        t->op_words = args + 1;
3306// TODO: test what will happen with "exec break" -
3307// will it leave t->op_words pointing to garbage?
3308// (see http://bugs.busybox.net/view.php?id=846)
3309        if (setjmp(failpt) == 0)
3310                execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
3311        t->op_words = sv_words;
3312
3313        failpt = ofail;
3314        execflg = 0;
3315
3316        return 1;
3317}
3318
3319static int dodot(struct op *t UNUSED_PARAM, char **args)
3320{
3321        int i;
3322        const char *sp;
3323        char *tp;
3324        char *cp;
3325        int maltmp;
3326
3327        DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3328                t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
3329
3330        cp = args[1];
3331        if (cp == NULL) {
3332                DBGPRINTF(("DODOT: bad args, ret 0\n"));
3333                return 0;
3334        }
3335        DBGPRINTF(("DODOT: cp is %s\n", cp));
3336
3337        sp = any('/', cp) ? ":" : path->value;
3338
3339        DBGPRINTF(("DODOT: sp is %s,  global_env.linep is %s\n",
3340                           ((sp == NULL) ? "NULL" : sp),
3341                           ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
3342
3343        while (*sp) {
3344                tp = global_env.linep;
3345                while (*sp && (*tp = *sp++) != ':')
3346                        tp++;
3347                if (tp != global_env.linep)
3348                        *tp++ = '/';
3349                strcpy(tp, cp);
3350
3351                /* Original code */
3352                i = open(global_env.linep, O_RDONLY);
3353                if (i >= 0) {
3354                        exstat = 0;
3355                        maltmp = remap(i);
3356                        DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3357                                maltmp, exstat, global_env.iofd, i, global_env.linep));
3358
3359                        next(maltmp);           /* Basically a PUSHIO */
3360
3361                        DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3362
3363                        return exstat;
3364                }
3365        } /* while */
3366
3367        prs(cp);
3368        err(": not found");
3369
3370        return -1;
3371}
3372
3373static int dowait(struct op *t UNUSED_PARAM, char **args)
3374{
3375        int i;
3376        char *cp;
3377
3378        cp = args[1];
3379        if (cp != NULL) {
3380                i = getn(cp);
3381                if (i == 0)
3382                        return 0;
3383        } else
3384                i = -1;
3385        setstatus(waitfor(i, 1));
3386        return 0;
3387}
3388
3389static int doread(struct op *t UNUSED_PARAM, char **args)
3390{
3391        char *cp, **wp;
3392        int nb = 0;
3393        int nl = 0;
3394
3395        if (args[1] == NULL) {
3396                err("Usage: read name ...");
3397                return 1;
3398        }
3399        for (wp = args + 1; *wp; wp++) {
3400                for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
3401                        nb = nonblock_safe_read(STDIN_FILENO, cp, sizeof(*cp));
3402                        if (nb != sizeof(*cp))
3403                                break;
3404                        nl = (*cp == '\n');
3405                        if (nl || (wp[1] && any(*cp, ifs->value)))
3406                                break;
3407                }
3408                *cp = '\0';
3409                if (nb <= 0)
3410                        break;
3411                setval(lookup(*wp), global_env.linep);
3412        }
3413        return nb <= 0;
3414}
3415
3416static int doeval(struct op *t UNUSED_PARAM, char **args)
3417{
3418        return RUN(awordlist, args + 1, wdchar);
3419}
3420
3421static int dotrap(struct op *t UNUSED_PARAM, char **args)
3422{
3423        int n, i;
3424        int resetsig;
3425
3426        if (args[1] == NULL) {
3427                for (i = 0; i <= _NSIG; i++)
3428                        if (trap[i]) {
3429                                prn(i);
3430                                prs(": ");
3431                                prs(trap[i]);
3432                                prs("\n");
3433                        }
3434                return 0;
3435        }
3436        resetsig = isdigit(args[1][0]);
3437        for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3438                n = getsig(args[i]);
3439                freecell(trap[n]);
3440                trap[n] = 0;
3441                if (!resetsig) {
3442                        if (args[1][0] != '\0') {
3443                                trap[n] = strsave(args[1], 0);
3444                                setsig(n, sig);
3445                        } else
3446                                setsig(n, SIG_IGN);
3447                } else {
3448                        if (interactive) {
3449                                if (n == SIGINT)
3450                                        setsig(n, onintr);
3451                                else
3452                                        setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
3453                        } else
3454                                setsig(n, SIG_DFL);
3455                }
3456        }
3457        return 0;
3458}
3459
3460static int getsig(char *s)
3461{
3462        int n;
3463
3464        n = getn(s);
3465        if (n < 0 || n > _NSIG) {
3466                err("trap: bad signal number");
3467                n = 0;
3468        }
3469        return n;
3470}
3471
3472static void setsig(int n, sighandler_t f)
3473{
3474        if (n == 0)
3475                return;
3476        if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3477                ourtrap[n] = 1;
3478                signal(n, f);
3479        }
3480}
3481
3482static int getn(char *as)
3483{
3484        char *s;
3485        int n, m;
3486
3487        s = as;
3488        m = 1;
3489        if (*s == '-') {
3490                m = -1;
3491                s++;
3492        }
3493        for (n = 0; isdigit(*s); s++)
3494                n = (n * 10) + (*s - '0');
3495        if (*s) {
3496                prs(as);
3497                err(": bad number");
3498        }
3499        return n * m;
3500}
3501
3502static int dobreak(struct op *t UNUSED_PARAM, char **args)
3503{
3504        return brkcontin(args[1], 1);
3505}
3506
3507static int docontinue(struct op *t UNUSED_PARAM, char **args)
3508{
3509        return brkcontin(args[1], 0);
3510}
3511
3512static int brkcontin(char *cp, int val)
3513{
3514        struct brkcon *bc;
3515        int nl;
3516
3517        nl = cp == NULL ? 1 : getn(cp);
3518        if (nl <= 0)
3519                nl = 999;
3520        do {
3521                bc = brklist;
3522                if (bc == NULL)
3523                        break;
3524                brklist = bc->nextlev;
3525        } while (--nl);
3526        if (nl) {
3527                err("bad break/continue level");
3528                return 1;
3529        }
3530        isbreak = (val != 0);
3531        longjmp(bc->brkpt, 1);
3532        /* NOTREACHED */
3533}
3534
3535static int doexit(struct op *t UNUSED_PARAM, char **args)
3536{
3537        char *cp;
3538
3539        execflg = 0;
3540        cp = args[1];
3541        if (cp != NULL)
3542                setstatus(getn(cp));
3543
3544        DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
3545
3546        leave();
3547        /* NOTREACHED */
3548        return 0;
3549}
3550
3551static int doexport(struct op *t UNUSED_PARAM, char **args)
3552{
3553        rdexp(args + 1, export, EXPORT);
3554        return 0;
3555}
3556
3557static int doreadonly(struct op *t UNUSED_PARAM, char **args)
3558{
3559        rdexp(args + 1, ronly, RONLY);
3560        return 0;
3561}
3562
3563static void rdexp(char **wp, void (*f) (struct var *), int key)
3564{
3565        DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
3566        DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3567
3568        if (*wp != NULL) {
3569                for (; *wp != NULL; wp++) {
3570                        if (isassign(*wp)) {
3571                                char *cp;
3572
3573                                assign(*wp, COPYV);
3574                                for (cp = *wp; *cp != '='; cp++)
3575                                        continue;
3576                                *cp = '\0';
3577                        }
3578                        if (checkname(*wp))
3579                                (*f) (lookup(*wp));
3580                        else
3581                                badid(*wp);
3582                }
3583        } else
3584                putvlist(key, 1);
3585}
3586
3587static void badid(char *s)
3588{
3589        prs(s);
3590        err(": bad identifier");
3591}
3592
3593static int doset(struct op *t UNUSED_PARAM, char **args)
3594{
3595        struct var *vp;
3596        char *cp;
3597        int n;
3598
3599        cp = args[1];
3600        if (cp == NULL) {
3601                for (vp = vlist; vp; vp = vp->next)
3602                        varput(vp->name, STDOUT_FILENO);
3603                return 0;
3604        }
3605        if (*cp == '-') {
3606                args++;
3607                if (*++cp == 0)
3608                        FLAG['x'] = FLAG['v'] = 0;
3609                else {
3610                        for (; *cp; cp++) {
3611                                switch (*cp) {
3612                                case 'e':
3613                                        if (!interactive)
3614                                                FLAG['e']++;
3615                                        break;
3616
3617                                default:
3618                                        if (*cp >= 'a' && *cp <= 'z')
3619                                                FLAG[(int) *cp]++;
3620                                        break;
3621                                }
3622                        }
3623                }
3624                setdash();
3625        }
3626        if (args[1]) {
3627                args[0] = dolv[0];
3628                for (n = 1; args[n]; n++)
3629                        setarea((char *) args[n], 0);
3630                dolc = n - 1;
3631                dolv = args;
3632                setval(lookup("#"), putn(dolc));
3633                setarea((char *) (dolv - 1), 0);
3634        }
3635        return 0;
3636}
3637
3638static void varput(char *s, int out)
3639{
3640        if (isalnum(*s) || *s == '_') {
3641                xwrite_str(out, s);
3642                xwrite(out, "\n", 1);
3643        }
3644}
3645
3646
3647/*
3648 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3649 * This file contains code for the times builtin.
3650 */
3651static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3652{
3653        unsigned min, sec;
3654        if (sizeof(val) > sizeof(int))
3655                sec = ((unsigned long)val) / clk_tck;
3656        else
3657                sec = ((unsigned)val) / clk_tck;
3658        min = sec / 60;
3659#if ENABLE_DESKTOP
3660        sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3661        /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3662        );
3663#else
3664        sprintf(buf, "%um%us", min, (sec - min * 60));
3665#endif
3666}
3667
3668static int dotimes(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
3669{
3670        struct tms buf;
3671        unsigned clk_tck = sysconf(_SC_CLK_TCK);
3672        /* How much do we need for "NmN.NNNs" ? */
3673        enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3674        char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3675        char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
3676
3677        times(&buf);
3678
3679        times_fmt(u, buf.tms_utime, clk_tck);
3680        times_fmt(s, buf.tms_stime, clk_tck);
3681        times_fmt(cu, buf.tms_cutime, clk_tck);
3682        times_fmt(cs, buf.tms_cstime, clk_tck);
3683
3684        printf("%s %s\n%s %s\n", u, s, cu, cs);
3685        return 0;
3686}
3687
3688
3689/* -------- eval.c -------- */
3690
3691/*
3692 * ${}
3693 * `command`
3694 * blank interpretation
3695 * quoting
3696 * glob
3697 */
3698
3699static char **eval(char **ap, int f)
3700{
3701        struct wdblock *wb;
3702        char **wp;
3703        char **wf;
3704        jmp_buf ev;
3705
3706#if __GNUC__
3707        /* Avoid longjmp clobbering */
3708        (void) &wp;
3709        (void) &ap;
3710#endif
3711
3712        DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3713
3714        wp = NULL;
3715        wb = NULL;
3716        wf = NULL;
3717        errpt = ev;
3718        if (newenv(setjmp(errpt)) == 0) {
3719                while (*ap && isassign(*ap))
3720                        expand(*ap++, &wb, f & ~DOGLOB);
3721                if (FLAG['k']) {
3722                        for (wf = ap; *wf; wf++) {
3723                                if (isassign(*wf))
3724                                        expand(*wf, &wb, f & ~DOGLOB);
3725                        }
3726                }
3727                for (wb = addword((char *) NULL, wb); *ap; ap++) {
3728                        if (!FLAG['k'] || !isassign(*ap))
3729                                expand(*ap, &wb, f & ~DOKEY);
3730                }
3731                wb = addword((char *) 0, wb);
3732                wp = getwords(wb);
3733                quitenv();
3734        } else
3735                gflg = 1;
3736
3737        return gflg ? (char **) NULL : wp;
3738}
3739
3740
3741/*
3742 * Make the exported environment from the exported
3743 * names in the dictionary. Keyword assignments
3744 * will already have been done.
3745 */
3746static char **makenv(int all, struct wdblock *wb)
3747{
3748        struct var *vp;
3749
3750        DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
3751
3752        for (vp = vlist; vp; vp = vp->next)
3753                if (all || vp->status & EXPORT)
3754                        wb = addword(vp->name, wb);
3755        wb = addword((char *) 0, wb);
3756        return getwords(wb);
3757}
3758
3759static int expand(const char *cp, struct wdblock **wbp, int f)
3760{
3761        jmp_buf ev;
3762        char *xp;
3763
3764#if __GNUC__
3765        /* Avoid longjmp clobbering */
3766        (void) &cp;
3767#endif
3768
3769        DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3770
3771        gflg = 0;
3772
3773        if (cp == NULL)
3774                return 0;
3775
3776        if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3777         && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3778        ) {
3779                xp = strsave(cp, areanum);
3780                if (f & DOTRIM)
3781                        unquote(xp);
3782                *wbp = addword(xp, *wbp);
3783                return 1;
3784        }
3785        errpt = ev;
3786        if (newenv(setjmp(errpt)) == 0) {
3787                PUSHIO(aword, cp, strchar);
3788                global_env.iobase = global_env.iop;
3789                while ((xp = blank(f)) && gflg == 0) {
3790                        global_env.linep = xp;
3791                        xp = strsave(xp, areanum);
3792                        if ((f & DOGLOB) == 0) {
3793                                if (f & DOTRIM)
3794                                        unquote(xp);
3795                                *wbp = addword(xp, *wbp);
3796                        } else
3797                                *wbp = glob(xp, *wbp);
3798                }
3799                quitenv();
3800        } else
3801                gflg = 1;
3802        return gflg == 0;
3803}
3804
3805static char *evalstr(char *cp, int f)
3806{
3807        struct wdblock *wb;
3808
3809        DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3810
3811        wb = NULL;
3812        if (expand(cp, &wb, f)) {
3813                if (wb == NULL || wb->w_nword == 0
3814                 || (cp = wb->w_words[0]) == NULL
3815                ) {
3816// TODO: I suspect that
3817// char *evalstr(char *cp, int f)  is actually
3818// const char *evalstr(const char *cp, int f)!
3819                        cp = (char*)"";
3820                }
3821                DELETE(wb);
3822        } else
3823                cp = NULL;
3824        return cp;
3825}
3826
3827
3828/*
3829 * Blank interpretation and quoting
3830 */
3831static char *blank(int f)
3832{
3833        int c, c1;
3834        char *sp;
3835        int scanequals, foundequals;
3836
3837        DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3838
3839        sp = global_env.linep;
3840        scanequals = f & DOKEY;
3841        foundequals = 0;
3842
3843 loop:
3844        c = subgetc('"', foundequals);
3845        switch (c) {
3846        case 0:
3847                if (sp == global_env.linep)
3848                        return 0;
3849                *global_env.linep++ = 0;
3850                return sp;
3851
3852        default:
3853                if (f & DOBLANK && any(c, ifs->value))
3854                        goto loop;
3855                break;
3856
3857        case '"':
3858        case '\'':
3859                scanequals = 0;
3860                if (INSUB())
3861                        break;
3862                for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3863                        if (c == 0)
3864                                break;
3865                        if (c == '\'' || !any(c, "$`\""))
3866                                c |= QUOTE;
3867                        *global_env.linep++ = c;
3868                }
3869                c = 0;
3870        }
3871        unget(c);
3872        if (!isalpha(c) && c != '_')
3873                scanequals = 0;
3874        for (;;) {
3875                c = subgetc('"', foundequals);
3876                if (c == 0 ||
3877                        f & (DOBLANK && any(c, ifs->value)) ||
3878                        (!INSUB() && any(c, "\"'"))) {
3879                        scanequals = 0;
3880                        unget(c);
3881                        if (any(c, "\"'"))
3882                                goto loop;
3883                        break;
3884                }
3885                if (scanequals) {
3886                        if (c == '=') {
3887                                foundequals = 1;
3888                                scanequals = 0;
3889                        } else if (!isalnum(c) && c != '_')
3890                                scanequals = 0;
3891                }
3892                *global_env.linep++ = c;
3893        }
3894        *global_env.linep++ = 0;
3895        return sp;
3896}
3897
3898/*
3899 * Get characters, substituting for ` and $
3900 */
3901static int subgetc(char ec, int quoted)
3902{
3903        char c;
3904
3905        DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
3906
3907 again:
3908        c = my_getc(ec);
3909        if (!INSUB() && ec != '\'') {
3910                if (c == '`') {
3911                        if (grave(quoted) == 0)
3912                                return 0;
3913                        global_env.iop->task = XGRAVE;
3914                        goto again;
3915                }
3916                if (c == '$') {
3917                        c = dollar(quoted);
3918                        if (c == 0) {
3919                                global_env.iop->task = XDOLL;
3920                                goto again;
3921                        }
3922                }
3923        }
3924        return c;
3925}
3926
3927/*
3928 * Prepare to generate the string returned by ${} substitution.
3929 */
3930static int dollar(int quoted)
3931{
3932        int otask;
3933        struct io *oiop;
3934        char *dolp;
3935        char *s, c, *cp = NULL;
3936        struct var *vp;
3937
3938        DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3939
3940        c = readc();
3941        s = global_env.linep;
3942        if (c != '{') {
3943                *global_env.linep++ = c;
3944                if (isalpha(c) || c == '_') {
3945                        while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
3946                                if (global_env.linep < elinep)
3947                                        *global_env.linep++ = c;
3948                        unget(c);
3949                }
3950                c = 0;
3951        } else {
3952                oiop = global_env.iop;
3953                otask = global_env.iop->task;
3954
3955                global_env.iop->task = XOTHER;
3956                while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
3957                        if (global_env.linep < elinep)
3958                                *global_env.linep++ = c;
3959                if (oiop == global_env.iop)
3960                        global_env.iop->task = otask;
3961                if (c != '}') {
3962                        err("unclosed ${");
3963                        gflg = 1;
3964                        return c;
3965                }
3966        }
3967        if (global_env.linep >= elinep) {
3968                err("string in ${} too long");
3969                gflg = 1;
3970                global_env.linep -= 10;
3971        }
3972        *global_env.linep = 0;
3973        if (*s)
3974                for (cp = s + 1; *cp; cp++)
3975                        if (any(*cp, "=-+?")) {
3976                                c = *cp;
3977                                *cp++ = 0;
3978                                break;
3979                        }
3980        if (s[1] == 0 && (*s == '*' || *s == '@')) {
3981                if (dolc > 1) {
3982                        /* currently this does not distinguish $* and $@ */
3983                        /* should check dollar */
3984                        global_env.linep = s;
3985                        PUSHIO(awordlist, dolv + 1, dolchar);
3986                        return 0;
3987                } else {                                /* trap the nasty ${=} */
3988                        s[0] = '1';
3989                        s[1] = '\0';
3990                }
3991        }
3992        vp = lookup(s);
3993        dolp = vp->value;
3994        if (dolp == null) {
3995                switch (c) {
3996                case '=':
3997                        if (isdigit(*s)) {
3998                                err("can't use ${...=...} with $n");
3999                                gflg = 1;
4000                                break;
4001                        }
4002                        setval(vp, cp);
4003                        dolp = vp->value;
4004                        break;
4005
4006                case '-':
4007                        dolp = strsave(cp, areanum);
4008                        break;
4009
4010                case '?':
4011                        if (*cp == 0) {
4012                                prs("missing value for ");
4013                                err(s);
4014                        } else
4015                                err(cp);
4016                        gflg = 1;
4017                        break;
4018                }
4019        } else if (c == '+')
4020                dolp = strsave(cp, areanum);
4021        if (FLAG['u'] && dolp == null) {
4022                prs("unset variable: ");
4023                err(s);
4024                gflg = 1;
4025        }
4026        global_env.linep = s;
4027        PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
4028        return 0;
4029}
4030
4031/*
4032 * Run the command in `...` and read its output.
4033 */
4034
4035static int grave(int quoted)
4036{
4037        /* moved to G: static char child_cmd[LINELIM]; */
4038
4039        const char *cp;
4040        int i;
4041        int j;
4042        int pf[2];
4043        const char *src;
4044        char *dest;
4045        int count;
4046        int ignore;
4047        int ignore_once;
4048        char *argument_list[4];
4049        struct wdblock *wb = NULL;
4050
4051#if __GNUC__
4052        /* Avoid longjmp clobbering */
4053        (void) &cp;
4054#endif
4055
4056        for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
4057                if (*cp == 0) {
4058                        err("no closing `");
4059                        return 0;
4060                }
4061        }
4062
4063        /* string copy with dollar expansion */
4064        src = global_env.iop->argp->aword;
4065        dest = child_cmd;
4066        count = 0;
4067        ignore = 0;
4068        ignore_once = 0;
4069        while ((*src != '`') && (count < LINELIM)) {
4070                if (*src == '\'')
4071                        ignore = !ignore;
4072                if (*src == '\\')
4073                        ignore_once = 1;
4074                if (*src == '$' && !ignore && !ignore_once) {
4075                        struct var *vp;
4076                        /* moved to G to reduce stack usage
4077                        char var_name[LINELIM];
4078                        char alt_value[LINELIM];
4079                        */
4080#define var_name (G.grave__var_name)
4081#define alt_value (G.grave__alt_value)
4082                        int var_index = 0;
4083                        int alt_index = 0;
4084                        char operator = 0;
4085                        int braces = 0;
4086                        char *value;
4087
4088                        src++;
4089                        if (*src == '{') {
4090                                braces = 1;
4091                                src++;
4092                        }
4093
4094                        var_name[var_index++] = *src++;
4095                        while (isalnum(*src) || *src=='_')
4096                                var_name[var_index++] = *src++;
4097                        var_name[var_index] = 0;
4098
4099                        if (braces) {
4100                                switch (*src) {
4101                                case '}':
4102                                        break;
4103                                case '-':
4104                                case '=':
4105                                case '+':
4106                                case '?':
4107                                        operator = * src;
4108                                        break;
4109                                default:
4110                                        err("unclosed ${\n");
4111                                        return 0;
4112                                }
4113                                if (operator) {
4114                                        src++;
4115                                        while (*src && (*src != '}')) {
4116                                                alt_value[alt_index++] = *src++;
4117                                        }
4118                                        alt_value[alt_index] = 0;
4119                                        if (*src != '}') {
4120                                                err("unclosed ${\n");
4121                                                return 0;
4122                                        }
4123                                }
4124                                src++;
4125                        }
4126
4127                        if (isalpha(*var_name)) {
4128                                /* let subshell handle it instead */
4129
4130                                char *namep = var_name;
4131
4132                                *dest++ = '$';
4133                                if (braces)
4134                                        *dest++ = '{';
4135                                while (*namep)
4136                                        *dest++ = *namep++;
4137                                if (operator) {
4138                                        char *altp = alt_value;
4139                                        *dest++ = operator;
4140                                        while (*altp)
4141                                                *dest++ = *altp++;
4142                                }
4143                                if (braces)
4144                                        *dest++ = '}';
4145
4146                                wb = addword(lookup(var_name)->name, wb);
4147                        } else {
4148                                /* expand */
4149
4150                                vp = lookup(var_name);
4151                                if (vp->value != null)
4152                                        value = (operator == '+') ?
4153                                                alt_value : vp->value;
4154                                else if (operator == '?') {
4155                                        err(alt_value);
4156                                        return 0;
4157                                } else if (alt_index && (operator != '+')) {
4158                                        value = alt_value;
4159                                        if (operator == '=')
4160                                                setval(vp, value);
4161                                } else
4162                                        continue;
4163
4164                                while (*value && (count < LINELIM)) {
4165                                        *dest++ = *value++;
4166                                        count++;
4167                                }
4168                        }
4169#undef var_name
4170#undef alt_value
4171                } else {
4172                        *dest++ = *src++;
4173                        count++;
4174                        ignore_once = 0;
4175                }
4176        }
4177        *dest = '\0';
4178
4179        if (openpipe(pf) < 0)
4180                return 0;
4181
4182        while ((i = vfork()) == -1 && errno == EAGAIN)
4183                continue;
4184
4185        DBGPRINTF3(("GRAVE: i is %p\n", io));
4186
4187        if (i < 0) {
4188                closepipe(pf);
4189                err((char *) bb_msg_memory_exhausted);
4190                return 0;
4191        }
4192        if (i != 0) {
4193                waitpid(i, NULL, 0); // safe_waitpid?
4194                global_env.iop->argp->aword = ++cp;
4195                close(pf[1]);
4196                PUSHIO(afile, remap(pf[0]),
4197                        (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
4198                return 1;
4199        }
4200        /* allow trapped signals */
4201        /* XXX - Maybe this signal stuff should go as well? */
4202        for (j = 0; j <= _NSIG; j++)
4203                if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4204                        signal(j, SIG_DFL);
4205
4206        /* Testcase where below checks are needed:
4207         * close stdout & run this script:
4208         *  files=`ls`
4209         *  echo "$files" >zz
4210         */
4211        xmove_fd(pf[1], 1);
4212        if (pf[0] != 1)
4213                close(pf[0]);
4214
4215        argument_list[0] = (char *) DEFAULT_SHELL;
4216        argument_list[1] = (char *) "-c";
4217        argument_list[2] = child_cmd;
4218        argument_list[3] = NULL;
4219
4220        cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
4221        prs(argument_list[0]);
4222        prs(": ");
4223        err(cp);
4224        _exit(EXIT_FAILURE);
4225}
4226
4227
4228static char *unquote(char *as)
4229{
4230        char *s;
4231
4232        s = as;
4233        if (s != NULL)
4234                while (*s)
4235                        *s++ &= ~QUOTE;
4236        return as;
4237}
4238
4239/* -------- glob.c -------- */
4240
4241/*
4242 * glob
4243 */
4244
4245#define scopy(x) strsave((x), areanum)
4246#define BLKSIZ  512
4247#define NDENT   ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4248
4249static struct wdblock *cl, *nl;
4250static const char spcl[] ALIGN1= "[?*";
4251
4252static struct wdblock *glob(char *cp, struct wdblock *wb)
4253{
4254        int i;
4255        char *pp;
4256
4257        if (cp == 0)
4258                return wb;
4259        i = 0;
4260        for (pp = cp; *pp; pp++)
4261                if (any(*pp, spcl))
4262                        i++;
4263                else if (!any(*pp & ~QUOTE, spcl))
4264                        *pp &= ~QUOTE;
4265        if (i != 0) {
4266                for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
4267                        nl = newword(cl->w_nword * 2);
4268                        for (i = 0; i < cl->w_nword; i++) {     /* for each argument */
4269                                for (pp = cl->w_words[i]; *pp; pp++)
4270                                        if (any(*pp, spcl)) {
4271                                                globname(cl->w_words[i], pp);
4272                                                break;
4273                                        }
4274                                if (*pp == '\0')
4275                                        nl = addword(scopy(cl->w_words[i]), nl);
4276                        }
4277                        for (i = 0; i < cl->w_nword; i++)
4278                                DELETE(cl->w_words[i]);
4279                        DELETE(cl);
4280                }
4281                if (cl->w_nword) {
4282                        for (i = 0; i < cl->w_nword; i++)
4283                                unquote(cl->w_words[i]);
4284                        qsort_string_vector(cl->w_words, cl->w_nword);
4285                        for (i = 0; i < cl->w_nword; i++)
4286                                wb = addword(cl->w_words[i], wb);
4287                        DELETE(cl);
4288                        return wb;
4289                }
4290        }
4291        wb = addword(unquote(cp), wb);
4292        return wb;
4293}
4294
4295static void globname(char *we, char *pp)
4296{
4297        char *np, *cp;
4298        char *name, *gp, *dp;
4299        int k;
4300        DIR *dirp;
4301        struct dirent *de;
4302        char dname[NAME_MAX + 1];
4303        struct stat dbuf;
4304
4305        for (np = we; np != pp; pp--)
4306                if (pp[-1] == '/')
4307                        break;
4308        dp = cp = get_space((int) (pp - np) + 3);
4309        while (np < pp)
4310                *cp++ = *np++;
4311        *cp++ = '.';
4312        *cp = '\0';
4313        gp = cp = get_space(strlen(pp) + 1);
4314        while (*np && *np != '/')
4315                *cp++ = *np++;
4316        *cp = '\0';
4317        dirp = opendir(dp);
4318        if (dirp == 0) {
4319                DELETE(dp);
4320                DELETE(gp);
4321                return;
4322        }
4323        dname[NAME_MAX] = '\0';
4324        while ((de = readdir(dirp)) != NULL) {
4325                /* XXX Hmmm... What this could be? (abial) */
4326                /* if (ent[j].d_ino == 0) continue;
4327                 */
4328                strncpy(dname, de->d_name, NAME_MAX);
4329                if (dname[0] == '.')
4330                        if (*gp != '.')
4331                                continue;
4332                for (k = 0; k < NAME_MAX; k++)
4333                        if (any(dname[k], spcl))
4334                                dname[k] |= QUOTE;
4335                if (gmatch(dname, gp)) {
4336                        name = generate(we, pp, dname, np);
4337                        if (*np && !anys(np, spcl)) {
4338                                if (stat(name, &dbuf)) {
4339                                        DELETE(name);
4340                                        continue;
4341                                }
4342                        }
4343                        nl = addword(name, nl);
4344                }
4345        }
4346        closedir(dirp);
4347        DELETE(dp);
4348        DELETE(gp);
4349}
4350
4351/*
4352 * generate a pathname as below.
4353 * start..end1 / middle end
4354 * the slashes come for free
4355 */
4356static char *generate(char *start1, char *end1, char *middle, char *end)
4357{
4358        char *p;
4359        char *op, *xp;
4360
4361        p = op = get_space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4362        xp = start1;
4363        while (xp != end1)
4364                *op++ = *xp++;
4365        xp = middle;
4366        while (*xp != '\0')
4367                *op++ = *xp++;
4368        strcpy(op, end);
4369        return p;
4370}
4371
4372static int anyspcl(struct wdblock *wb)
4373{
4374        int i;
4375        char **wd;
4376
4377        wd = wb->w_words;
4378        for (i = 0; i < wb->w_nword; i++)
4379                if (anys(spcl, *wd++))
4380                        return 1;
4381        return 0;
4382}
4383
4384
4385/* -------- word.c -------- */
4386
4387static struct wdblock *newword(int nw)
4388{
4389        struct wdblock *wb;
4390
4391        wb = get_space(sizeof(*wb) + nw * sizeof(char *));
4392        wb->w_bsize = nw;
4393        wb->w_nword = 0;
4394        return wb;
4395}
4396
4397static struct wdblock *addword(char *wd, struct wdblock *wb)
4398{
4399        struct wdblock *wb2;
4400        int nw;
4401
4402        if (wb == NULL)
4403                wb = newword(NSTART);
4404        nw = wb->w_nword;
4405        if (nw >= wb->w_bsize) {
4406                wb2 = newword(nw * 2);
4407                memcpy((char *) wb2->w_words, (char *) wb->w_words,
4408                           nw * sizeof(char *));
4409                wb2->w_nword = nw;
4410                DELETE(wb);
4411                wb = wb2;
4412        }
4413        wb->w_words[wb->w_nword++] = wd;
4414        return wb;
4415}
4416
4417static char **getwords(struct wdblock *wb)
4418{
4419        char **wd;
4420        int nb;
4421
4422        if (wb == NULL)
4423                return NULL;
4424        if (wb->w_nword == 0) {
4425                DELETE(wb);
4426                return NULL;
4427        }
4428        nb = sizeof(*wd) * wb->w_nword;
4429        wd = get_space(nb);
4430        memcpy(wd, wb->w_words, nb);
4431        DELETE(wb);                     /* perhaps should done by caller */
4432        return wd;
4433}
4434
4435
4436/* -------- io.c -------- */
4437
4438/*
4439 * shell IO
4440 */
4441
4442static int my_getc(int ec)
4443{
4444        int c;
4445
4446        if (global_env.linep > elinep) {
4447                while ((c = readc()) != '\n' && c)
4448                        continue;
4449                err("input line too long");
4450                gflg = 1;
4451                return c;
4452        }
4453        c = readc();
4454        if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
4455                if (c == '\\') {
4456                        c = readc();
4457                        if (c == '\n' && ec != '\"')
4458                                return my_getc(ec);
4459                        c |= QUOTE;
4460                }
4461        }
4462        return c;
4463}
4464
4465static void unget(int c)
4466{
4467        if (global_env.iop >= global_env.iobase)
4468                global_env.iop->peekc = c;
4469}
4470
4471static int eofc(void)
4472{
4473        return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
4474}
4475
4476static int readc(void)
4477{
4478        int c;
4479
4480        RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
4481
4482        for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4483                RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4484                c = global_env.iop->peekc;
4485                if (c != '\0') {
4486                        global_env.iop->peekc = 0;
4487                        return c;
4488                }
4489                if (global_env.iop->prev != 0) {
4490                        c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
4491                        if (c != '\0') {
4492                                if (c == -1) {
4493                                        global_env.iop++;
4494                                        continue;
4495                                }
4496                                if (global_env.iop == iostack)
4497                                        ioecho(c);
4498                                global_env.iop->prev = c;
4499                                return c;
4500                        }
4501                        if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4502                                global_env.iop->prev = 0;
4503                                if (global_env.iop == iostack)
4504                                        ioecho('\n');
4505                                return '\n';
4506                        }
4507                }
4508                if (global_env.iop->task == XIO) {
4509                        if (multiline) {
4510                                global_env.iop->prev = 0;
4511                                return 0;
4512                        }
4513                        if (interactive && global_env.iop == iostack + 1) {
4514#if ENABLE_FEATURE_EDITING
4515                                current_prompt = prompt->value;
4516#else
4517                                prs(prompt->value);
4518#endif
4519                        }
4520                }
4521        }                                                       /* FOR */
4522
4523        if (global_env.iop >= iostack) {
4524                RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
4525                return 0;
4526        }
4527
4528        DBGPRINTF(("READC: leave()...\n"));
4529        leave();
4530        /* NOTREACHED */
4531        return 0;
4532}
4533
4534static void ioecho(char c)
4535{
4536        if (FLAG['v'])
4537                write(STDERR_FILENO, &c, sizeof c);
4538}
4539
4540static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
4541{
4542        DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4543                           argp->afid, global_env.iop));
4544
4545        /* Set env ptr for io source to next array spot and check for array overflow */
4546        if (++global_env.iop >= &iostack[NPUSH]) {
4547                global_env.iop--;
4548                err("Shell input nested too deeply");
4549                gflg = 1;
4550                return;
4551        }
4552
4553        /* We did not overflow the NPUSH array spots so setup data structs */
4554
4555        global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn;       /* Store data source func ptr */
4556
4557        if (argp->afid != AFID_NOBUF)
4558                global_env.iop->argp = argp;
4559        else {
4560
4561                global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4562                *global_env.iop->argp = *argp;  /* copy data from temp area into stack spot */
4563
4564                /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4565
4566                if (global_env.iop == &iostack[0])
4567                        global_env.iop->argp->afbuf = &mainbuf;
4568                else
4569                        global_env.iop->argp->afbuf = &sharedbuf;
4570
4571                /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4572                /* This line appears to be active when running scripts from command line */
4573                if ((isatty(global_env.iop->argp->afile) == 0)
4574                        && (global_env.iop == &iostack[0]
4575                                || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
4576                        if (++bufid == AFID_NOBUF)      /* counter rollover check, AFID_NOBUF = 11111111  */
4577                                bufid = AFID_ID;        /* AFID_ID = 0 */
4578
4579                        global_env.iop->argp->afid = bufid;     /* assign buffer id */
4580                }
4581
4582                DBGPRINTF(("PUSHIO: iostack %p,  global_env.iop %p, afbuf %p\n",
4583                                   iostack, global_env.iop, global_env.iop->argp->afbuf));
4584                DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4585                                   &mainbuf, &sharedbuf, bufid, global_env.iop));
4586
4587        }
4588
4589        global_env.iop->prev = ~'\n';
4590        global_env.iop->peekc = 0;
4591        global_env.iop->xchar = 0;
4592        global_env.iop->nlcount = 0;
4593
4594        if (fn == filechar || fn == linechar)
4595                global_env.iop->task = XIO;
4596        else if (fn == (int (*)(struct ioarg *)) gravechar
4597              || fn == (int (*)(struct ioarg *)) qgravechar)
4598                global_env.iop->task = XGRAVE;
4599        else
4600                global_env.iop->task = XOTHER;
4601}
4602
4603static struct io *setbase(struct io *ip)
4604{
4605        struct io *xp;
4606
4607        xp = global_env.iobase;
4608        global_env.iobase = ip;
4609        return xp;
4610}
4611
4612/*
4613 * Input generating functions
4614 */
4615
4616/*
4617 * Produce the characters of a string, then a newline, then NUL.
4618 */
4619static int nlchar(struct ioarg *ap)
4620{
4621        char c;
4622
4623        if (ap->aword == NULL)
4624                return '\0';
4625        c = *ap->aword++;
4626        if (c == '\0') {
4627                ap->aword = NULL;
4628                return '\n';
4629        }
4630        return c;
4631}
4632
4633/*
4634 * Given a list of words, produce the characters
4635 * in them, with a space after each word.
4636 */
4637static int wdchar(struct ioarg *ap)
4638{
4639        char c;
4640        char **wl;
4641
4642        wl = ap->awordlist;
4643        if (wl == NULL)
4644                return 0;
4645        if (*wl != NULL) {
4646                c = *(*wl)++;
4647                if (c != 0)
4648                        return c & 0177;
4649                ap->awordlist++;
4650                return ' ';
4651        }
4652        ap->awordlist = NULL;
4653        return '\n';
4654}
4655
4656/*
4657 * Return the characters of a list of words,
4658 * producing a space between them.
4659 */
4660static int dolchar(struct ioarg *ap)
4661{
4662        char *wp;
4663
4664        wp = *ap->awordlist++;
4665        if (wp != NULL) {
4666                PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4667                return -1;
4668        }
4669        return 0;
4670}
4671
4672static int xxchar(struct ioarg *ap)
4673{
4674        int c;
4675
4676        if (ap->aword == NULL)
4677                return 0;
4678        c = *ap->aword++;
4679        if (c == '\0') {
4680                ap->aword = NULL;
4681                return ' ';
4682        }
4683        return c;
4684}
4685
4686/*
4687 * Produce the characters from a single word (string).
4688 */
4689static int strchar(struct ioarg *ap)
4690{
4691        if (ap->aword == NULL)
4692                return 0;
4693        return *ap->aword++;
4694}
4695
4696/*
4697 * Produce quoted characters from a single word (string).
4698 */
4699static int qstrchar(struct ioarg *ap)
4700{
4701        int c;
4702
4703        if (ap->aword == NULL)
4704                return 0;
4705        c = *ap->aword++;
4706        if (c)
4707                c |= QUOTE;
4708        return c;
4709}
4710
4711/*
4712 * Return the characters from a file.
4713 */
4714static int filechar(struct ioarg *ap)
4715{
4716        int i;
4717        char c;
4718        struct iobuf *bp = ap->afbuf;
4719
4720        if (ap->afid != AFID_NOBUF) {
4721                i = (ap->afid != bp->id);
4722                if (i || bp->bufp == bp->ebufp) {
4723                        if (i)
4724                                lseek(ap->afile, ap->afpos, SEEK_SET);
4725
4726                        i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4727                        if (i <= 0) {
4728                                closef(ap->afile);
4729                                return 0;
4730                        }
4731
4732                        bp->id = ap->afid;
4733                        bp->bufp = bp->buf;
4734                        bp->ebufp = bp->bufp + i;
4735                }
4736
4737                ap->afpos++;
4738                return *bp->bufp++ & 0177;
4739        }
4740#if ENABLE_FEATURE_EDITING
4741        if (interactive && isatty(ap->afile)) {
4742                /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
4743                static int position = 0, size = 0;
4744
4745                while (size == 0 || position >= size) {
4746                        size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4747                        if (size < 0) /* Error/EOF */
4748                                exit(EXIT_SUCCESS);
4749                        position = 0;
4750                        /* if Ctrl-C, size == 0 and loop will repeat */
4751                }
4752                c = filechar_cmdbuf[position];
4753                position++;
4754                return c;
4755        }
4756#endif
4757        i = nonblock_safe_read(ap->afile, &c, sizeof(c));
4758        return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
4759}
4760
4761/*
4762 * Return the characters from a here temp file.
4763 */
4764static int herechar(struct ioarg *ap)
4765{
4766        char c;
4767
4768        if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4769                close(ap->afile);
4770                c = '\0';
4771        }
4772        return c;
4773}
4774
4775/*
4776 * Return the characters produced by a process (`...`).
4777 * Quote them if required, and remove any trailing newline characters.
4778 */
4779static int gravechar(struct ioarg *ap, struct io *iop)
4780{
4781        int c;
4782
4783        c = qgravechar(ap, iop) & ~QUOTE;
4784        if (c == '\n')
4785                c = ' ';
4786        return c;
4787}
4788
4789static int qgravechar(struct ioarg *ap, struct io *iop)
4790{
4791        int c;
4792
4793        DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
4794
4795        if (iop->xchar) {
4796                if (iop->nlcount) {
4797                        iop->nlcount--;
4798                        return '\n' | QUOTE;
4799                }
4800                c = iop->xchar;
4801                iop->xchar = 0;
4802        } else if ((c = filechar(ap)) == '\n') {
4803                iop->nlcount = 1;
4804                while ((c = filechar(ap)) == '\n')
4805                        iop->nlcount++;
4806                iop->xchar = c;
4807                if (c == 0)
4808                        return c;
4809                iop->nlcount--;
4810                c = '\n';
4811        }
4812        return c != 0 ? c | QUOTE : 0;
4813}
4814
4815/*
4816 * Return a single command (usually the first line) from a file.
4817 */
4818static int linechar(struct ioarg *ap)
4819{
4820        int c;
4821
4822        c = filechar(ap);
4823        if (c == '\n') {
4824                if (!multiline) {
4825                        closef(ap->afile);
4826                        ap->afile = -1;         /* illegal value */
4827                }
4828        }
4829        return c;
4830}
4831
4832/*
4833 * Remap fd into shell's fd space
4834 */
4835static int remap(int fd)
4836{
4837        int i;
4838        int map[NOFILE];
4839        int newfd;
4840
4841        DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
4842
4843        if (fd < global_env.iofd) {
4844                for (i = 0; i < NOFILE; i++)
4845                        map[i] = 0;
4846
4847                do {
4848                        map[fd] = 1;
4849                        newfd = dup(fd);
4850                        fd = newfd;
4851                } while (fd >= 0 && fd < global_env.iofd);
4852
4853                for (i = 0; i < NOFILE; i++)
4854                        if (map[i])
4855                                close(i);
4856
4857                if (fd < 0)
4858                        err("too many files open in shell");
4859        }
4860
4861        return fd;
4862}
4863
4864static int openpipe(int *pv)
4865{
4866        int i;
4867
4868        i = pipe(pv);
4869        if (i < 0)
4870                err("can't create pipe - try again");
4871        return i;
4872}
4873
4874static void closepipe(int *pv)
4875{
4876        if (pv != NULL) {
4877                close(pv[0]);
4878                close(pv[1]);
4879        }
4880}
4881
4882
4883/* -------- here.c -------- */
4884
4885/*
4886 * here documents
4887 */
4888
4889static void markhere(char *s, struct ioword *iop)
4890{
4891        struct here *h, *lh;
4892
4893        DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
4894
4895        h = get_space(sizeof(struct here));
4896        if (h == NULL)
4897                return;
4898
4899        h->h_tag = evalstr(s, DOSUB);
4900        if (h->h_tag == 0)
4901                return;
4902
4903        h->h_iop = iop;
4904        iop->io_name = 0;
4905        h->h_next = NULL;
4906        if (inhere == 0)
4907                inhere = h;
4908        else {
4909                for (lh = inhere; lh != NULL; lh = lh->h_next) {
4910                        if (lh->h_next == 0) {
4911                                lh->h_next = h;
4912                                break;
4913                        }
4914                }
4915        }
4916        iop->io_flag |= IOHERE | IOXHERE;
4917        for (s = h->h_tag; *s; s++) {
4918                if (*s & QUOTE) {
4919                        iop->io_flag &= ~IOXHERE;
4920                        *s &= ~QUOTE;
4921                }
4922        }
4923        h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
4924}
4925
4926static void gethere(void)
4927{
4928        struct here *h, *hp;
4929
4930        DBGPRINTF7(("GETHERE: enter...\n"));
4931
4932        /* Scan here files first leaving inhere list in place */
4933        for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
4934                readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
4935
4936        /* Make inhere list active - keep list intact for scraphere */
4937        if (hp != NULL) {
4938                hp->h_next = acthere;
4939                acthere = inhere;
4940                inhere = NULL;
4941        }
4942}
4943
4944static void readhere(char **name, char *s, int ec)
4945{
4946        int tf;
4947        char tname[30] = ".msh_XXXXXX";
4948        int c;
4949        jmp_buf ev;
4950        char myline[LINELIM + 1];
4951        char *thenext;
4952
4953        DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
4954
4955        tf = mkstemp(tname);
4956        if (tf < 0)
4957                return;
4958
4959        *name = strsave(tname, areanum);
4960        errpt = ev;
4961        if (newenv(setjmp(errpt)) != 0)
4962                unlink(tname);
4963        else {
4964                pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
4965                global_env.iobase = global_env.iop;
4966                for (;;) {
4967                        if (interactive && global_env.iop <= iostack) {
4968#if ENABLE_FEATURE_EDITING
4969                                current_prompt = cprompt->value;
4970#else
4971                                prs(cprompt->value);
4972#endif
4973                        }
4974                        thenext = myline;
4975                        while ((c = my_getc(ec)) != '\n' && c) {
4976                                if (ec == '\'')
4977                                        c &= ~QUOTE;
4978                                if (thenext >= &myline[LINELIM]) {
4979                                        c = 0;
4980                                        break;
4981                                }
4982                                *thenext++ = c;
4983                        }
4984                        *thenext = 0;
4985                        if (strcmp(s, myline) == 0 || c == 0)
4986                                break;
4987                        *thenext++ = '\n';
4988                        write(tf, myline, (int) (thenext - myline));
4989                }
4990                if (c == 0) {
4991                        prs("here document `");
4992                        prs(s);
4993                        err("' unclosed");
4994                }
4995                quitenv();
4996        }
4997        close(tf);
4998}
4999
5000/*
5001 * open here temp file.
5002 * if unquoted here, expand here temp file into second temp file.
5003 */
5004static int herein(char *hname, int xdoll)
5005{
5006        int hf;
5007        int tf;
5008
5009#if __GNUC__
5010        /* Avoid longjmp clobbering */
5011        (void) &tf;
5012#endif
5013        if (hname == NULL)
5014                return -1;
5015
5016        DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5017
5018        hf = open(hname, O_RDONLY);
5019        if (hf < 0)
5020                return -1;
5021
5022        if (xdoll) {
5023                char c;
5024                char tname[30] = ".msh_XXXXXX";
5025                jmp_buf ev;
5026
5027                tf = mkstemp(tname);
5028                if (tf < 0)
5029                        return -1;
5030                errpt = ev;
5031                if (newenv(setjmp(errpt)) == 0) {
5032                        PUSHIO(afile, hf, herechar);
5033                        setbase(global_env.iop);
5034                        while ((c = subgetc(0, 0)) != 0) {
5035                                c &= ~QUOTE;
5036                                write(tf, &c, sizeof c);
5037                        }
5038                        quitenv();
5039                } else
5040                        unlink(tname);
5041                close(tf);
5042                tf = open(tname, O_RDONLY);
5043                unlink(tname);
5044                return tf;
5045        }
5046        return hf;
5047}
5048
5049static void scraphere(void)
5050{
5051        struct here *h;
5052
5053        DBGPRINTF7(("SCRAPHERE: enter...\n"));
5054
5055        for (h = inhere; h != NULL; h = h->h_next) {
5056                if (h->h_iop && h->h_iop->io_name)
5057                        unlink(h->h_iop->io_name);
5058        }
5059        inhere = NULL;
5060}
5061
5062/* unlink here temp files before a freearea(area) */
5063static void freehere(int area)
5064{
5065        struct here *h, *hl;
5066
5067        DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
5068
5069        hl = NULL;
5070        for (h = acthere; h != NULL; h = h->h_next) {
5071                if (getarea((char *) h) >= area) {
5072                        if (h->h_iop->io_name != NULL)
5073                                unlink(h->h_iop->io_name);
5074                        if (hl == NULL)
5075                                acthere = h->h_next;
5076                        else
5077                                hl->h_next = h->h_next;
5078                } else {
5079                        hl = h;
5080                }
5081        }
5082}
5083
5084
5085/* -------- sh.c -------- */
5086/*
5087 * shell
5088 */
5089
5090int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
5091int msh_main(int argc, char **argv)
5092{
5093        int f;
5094        char *s;
5095        int cflag;
5096        char *name, **ap;
5097        int (*iof) (struct ioarg *);
5098
5099        INIT_G();
5100
5101        sharedbuf.id = AFID_NOBUF;
5102        mainbuf.id = AFID_NOBUF;
5103        elinep = line + sizeof(line) - 5;
5104
5105#if ENABLE_FEATURE_EDITING
5106        line_input_state = new_line_input_t(FOR_SHELL);
5107#endif
5108
5109        DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5110
5111        initarea();
5112        ap = environ;
5113        if (ap != NULL) {
5114                while (*ap)
5115                        assign(*ap++, !COPYV);
5116                for (ap = environ; *ap;)
5117                        export(lookup(*ap++));
5118        }
5119        closeall();
5120        areanum = 1;
5121
5122        shell = lookup("SHELL");
5123        if (shell->value == null)
5124                setval(shell, (char *)DEFAULT_SHELL);
5125        export(shell);
5126
5127        homedir = lookup("HOME");
5128        if (homedir->value == null)
5129                setval(homedir, "/");
5130        export(homedir);
5131
5132        setval(lookup("$"), putn(getpid()));
5133
5134        path = lookup("PATH");
5135        if (path->value == null) {
5136                /* Can be merged with same string elsewhere in bbox */
5137                if (geteuid() == 0)
5138                        setval(path, bb_default_root_path);
5139                else
5140                        setval(path, bb_default_path);
5141        }
5142        export(path);
5143
5144        ifs = lookup("IFS");
5145        if (ifs->value == null)
5146                setval(ifs, " \t\n");
5147
5148#ifdef MSHDEBUG
5149        mshdbg_var = lookup("MSHDEBUG");
5150        if (mshdbg_var->value == null)
5151                setval(mshdbg_var, "0");
5152#endif
5153
5154        prompt = lookup("PS1");
5155#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5156        if (prompt->value == null)
5157#endif
5158                setval(prompt, DEFAULT_USER_PROMPT);
5159        if (geteuid() == 0) {
5160                setval(prompt, DEFAULT_ROOT_PROMPT);
5161                prompt->status &= ~EXPORT;
5162        }
5163        cprompt = lookup("PS2");
5164#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5165        if (cprompt->value == null)
5166#endif
5167                setval(cprompt, "> ");
5168
5169        iof = filechar;
5170        cflag = 0;
5171        name = *argv++;
5172        if (--argc >= 1) {
5173                if (argv[0][0] == '-' && argv[0][1] != '\0') {
5174                        for (s = argv[0] + 1; *s; s++)
5175                                switch (*s) {
5176                                case 'c':
5177                                        prompt->status &= ~EXPORT;
5178                                        cprompt->status &= ~EXPORT;
5179                                        setval(prompt, "");
5180                                        setval(cprompt, "");
5181                                        cflag = 1;
5182                                        if (--argc > 0)
5183                                                PUSHIO(aword, *++argv, iof = nlchar);
5184                                        break;
5185
5186                                case 'q':
5187                                        qflag = SIG_DFL;
5188                                        break;
5189
5190                                case 's':
5191                                        /* standard input */
5192                                        break;
5193
5194                                case 't':
5195                                        prompt->status &= ~EXPORT;
5196                                        setval(prompt, "");
5197                                        iof = linechar;
5198                                        break;
5199
5200                                case 'i':
5201                                        interactive = 1;
5202                                default:
5203                                        if (*s >= 'a' && *s <= 'z')
5204                                                FLAG[(int) *s]++;
5205                                }
5206                } else {
5207                        argv--;
5208                        argc++;
5209                }
5210
5211                if (iof == filechar && --argc > 0) {
5212                        setval(prompt, "");
5213                        setval(cprompt, "");
5214                        prompt->status &= ~EXPORT;
5215                        cprompt->status &= ~EXPORT;
5216
5217/* Shell is non-interactive, activate printf-based debug */
5218#ifdef MSHDEBUG
5219                        mshdbg = mshdbg_var->value[0] - '0';
5220                        if (mshdbg < 0)
5221                                mshdbg = 0;
5222#endif
5223                        DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5224
5225                        name = *++argv;
5226                        if (newfile(name))
5227                                exit(EXIT_FAILURE);  /* Exit on error */
5228                }
5229        }
5230
5231        setdash();
5232
5233        /* This won't be true if PUSHIO has been called, say from newfile() above */
5234        if (global_env.iop < iostack) {
5235                PUSHIO(afile, 0, iof);
5236                if (isatty(0) && isatty(1) && !cflag) {
5237                        interactive = 1;
5238#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5239#ifdef MSHDEBUG
5240                        printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
5241#else
5242                        printf("\n\n%s built-in shell (msh)\n", bb_banner);
5243#endif
5244                        printf("Enter 'help' for a list of built-in commands.\n\n");
5245#endif
5246                }
5247        }
5248
5249        signal(SIGQUIT, qflag);
5250        if (name && name[0] == '-') {
5251                interactive = 1;
5252                f = open(".profile", O_RDONLY);
5253                if (f >= 0)
5254                        next(remap(f));
5255                f = open("/etc/profile", O_RDONLY);
5256                if (f >= 0)
5257                        next(remap(f));
5258        }
5259        if (interactive)
5260                signal(SIGTERM, sig);
5261
5262        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5263                signal(SIGINT, onintr);
5264
5265/* Handle "msh SCRIPT VAR=val params..." */
5266/* Disabled: bash does not do it! */
5267#if 0
5268        argv++;
5269        /* skip leading args of the form VAR=val */
5270        while (*argv && assign(*argv, !COPYV)) {
5271                argc--;
5272                argv++;
5273        }
5274        argv--;
5275#endif
5276        dolv = argv;
5277        dolc = argc;
5278        dolv[0] = name;
5279
5280        setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5281
5282        DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, global_env.iop %p, iostack %p\n", interactive, global_env.iop, iostack));
5283
5284        for (;;) {
5285                if (interactive && global_env.iop <= iostack) {
5286#if ENABLE_FEATURE_EDITING
5287                        current_prompt = prompt->value;
5288#else
5289                        prs(prompt->value);
5290#endif
5291                }
5292                onecommand();
5293                /* Ensure that getenv("PATH") stays current */
5294                setenv("PATH", path->value, 1);
5295        }
5296
5297        DBGPRINTF(("MSH_MAIN: returning.\n"));
5298}
5299
5300
5301/*
5302 * Copyright (c) 1987,1997, Prentice Hall
5303 * All rights reserved.
5304 *
5305 * Redistribution and use of the MINIX operating system in source and
5306 * binary forms, with or without modification, are permitted provided
5307 * that the following conditions are met:
5308 *
5309 * Redistributions of source code must retain the above copyright
5310 * notice, this list of conditions and the following disclaimer.
5311 *
5312 * Redistributions in binary form must reproduce the above
5313 * copyright notice, this list of conditions and the following
5314 * disclaimer in the documentation and/or other materials provided
5315 * with the distribution.
5316 *
5317 * Neither the name of Prentice Hall nor the names of the software
5318 * authors or contributors may be used to endorse or promote
5319 * products derived from this software without specific prior
5320 * written permission.
5321 *
5322 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5323 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5324 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5325 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5326 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5327 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5328 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5329 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5330 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5331 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5332 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5333 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5334 *
5335 */
5336