toybox/toys/pending/sh.c
<<
>>
Prefs
   1/* sh.c - toybox shell
   2 *
   3 * Copyright 2006 Rob Landley <rob@landley.net>
   4 *
   5 * This shell aims for bash compatibility. The bash man page is at:
   6 * http://man7.org/linux/man-pages/man1/bash.1.html
   7 *
   8 * The POSIX-2008/SUSv4 shell spec is at:
   9 * http://opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
  10 * and http://opengroup.org/onlinepubs/9699919799/utilities/sh.html
  11 *
  12 * The chap02 link describes the following shell builtins:
  13 *
  14 *   break : continue exit
  15 *   . eval exec export readonly return set shift times trap unset
  16 *
  17 * The second link (the utilities directory) also contains specs for the
  18 * following shell builtins:
  19 *
  20 *   cd ulimit umask
  21 *   alias bg command fc fg getopts hash jobs kill read type unalias wait
  22 *
  23 * deviations from posix: don't care about $LANG or $LC_ALL
  24
  25 * TODO: test that $PS1 color changes work without stupid \[ \] hack
  26 * TODO: Handle embedded NUL bytes in the command line? (When/how?)
  27
  28 * builtins: alias bg command fc fg getopts jobs newgrp read umask unalias wait
  29 *           disown umask suspend source pushd popd dirs logout times trap
  30 *           unset local export readonly set : . let history declare
  31 * "special" builtins: break continue eval exec return shift
  32 * builtins with extra shell behavior: kill pwd time test
  33
  34 * | & ; < > ( ) $ ` \ " ' <space> <tab> <newline>
  35 * * ? [ # ~ = %
  36 * ! { } case do done elif else esac fi for if in then until while
  37 * [[ ]] function select
  38
  39 * label:
  40 * TODO: test exit from "trap EXIT" doesn't recurse
  41 * TODO: ! history expansion
  42 * TODO: getuid() vs geteuid()
  43 *
  44 * bash man page:
  45 * control operators || & && ; ;; ;& ;;& ( ) | |& <newline>
  46 * reserved words
  47 *   ! case  coproc  do done elif else esac fi for  function  if  in  select
  48 *   then until while { } time [[ ]]
  49
  50USE_SH(NEWTOY(cd, ">1LP[-LP]", TOYFLAG_NOFORK))
  51USE_SH(NEWTOY(eval, 0, TOYFLAG_NOFORK))
  52USE_SH(NEWTOY(exec, "^cla:", TOYFLAG_NOFORK))
  53USE_SH(NEWTOY(exit, 0, TOYFLAG_NOFORK))
  54USE_SH(NEWTOY(export, "np", TOYFLAG_NOFORK))
  55USE_SH(NEWTOY(shift, ">1", TOYFLAG_NOFORK))
  56USE_SH(NEWTOY(unset, "fvn", TOYFLAG_NOFORK))
  57
  58USE_SH(NEWTOY(sh, "(noediting)(noprofile)(norc)sc:i", TOYFLAG_BIN))
  59USE_SH(OLDTOY(toysh, sh, TOYFLAG_BIN))
  60USE_SH(OLDTOY(bash, sh, TOYFLAG_BIN))
  61// Login lies in argv[0], so add some aliases to catch that
  62USE_SH(OLDTOY(-sh, sh, 0))
  63USE_SH(OLDTOY(-toysh, sh, 0))
  64USE_SH(OLDTOY(-bash, sh, 0))
  65
  66config SH
  67  bool "sh (toysh)"
  68  default n
  69  help
  70    usage: sh [-c command] [script]
  71
  72    Command shell.  Runs a shell script, or reads input interactively
  73    and responds to it.
  74
  75    -c  command line to execute
  76    -i  interactive mode (default when STDIN is a tty)
  77
  78# These are here for the help text, they're not selectable and control nothing
  79config CD
  80  bool
  81  default n
  82  depends on SH
  83  help
  84    usage: cd [-PL] [path]
  85
  86    Change current directory.  With no arguments, go $HOME.
  87
  88    -P  Physical path: resolve symlinks in path
  89    -L  Local path: .. trims directories off $PWD (default)
  90
  91config EXIT
  92  bool
  93  default n
  94  depends on SH
  95  help
  96    usage: exit [status]
  97
  98    Exit shell.  If no return value supplied on command line, use value
  99    of most recent command, or 0 if none.
 100
 101config UNSET
 102  bool
 103  default n
 104  depends on SH
 105  help
 106    usage: unset [-fvn] NAME...
 107
 108    -f  NAME is a function
 109    -v  NAME is a variable
 110    -n  dereference NAME and unset that
 111
 112config EVAL
 113  bool
 114  default n
 115  depends on SH
 116  help
 117    usage: eval COMMAND...
 118
 119    Execute (combined) arguments as a shell command.
 120
 121config EXEC
 122  bool
 123  default n
 124  depends on SH
 125  help
 126    usage: exec [-cl] [-a NAME] COMMAND...
 127
 128    -a  set argv[0] to NAME
 129    -c  clear environment
 130    -l  prepend - to argv[0]
 131
 132config EXPORT
 133  bool
 134  default n
 135  depends on SH
 136  help
 137    usage: export [-n] [NAME[=VALUE]...]
 138
 139    Make variables available to child processes. NAME exports existing local
 140    variable(s), NAME=VALUE sets and exports.
 141
 142    -n  Unexport. Turn listed variable(s) into local variables.
 143
 144    With no arguments list exported variables/attributes as "declare" statements.
 145
 146config SHIFT
 147  bool
 148  default n
 149  depends on SH
 150  help
 151    usage: shift [N]
 152
 153    Skip N (default 1) positional parameters, moving $1 and friends along the list.
 154    Does not affect $0.
 155*/
 156
 157#define FOR_sh
 158#include "toys.h"
 159
 160GLOBALS(
 161  union {
 162    struct {
 163      char *c;
 164    } sh;
 165    struct {
 166      char *a;
 167    } exec;
 168  };
 169
 170  // keep lineno here, we use it to work around a compiler bug
 171  long lineno;
 172  char *ifs, *isexec;
 173  struct double_list functions;
 174  unsigned options, jobcnt;
 175  int hfd, pid, varslen, shift, cdcount;
 176  unsigned long long SECONDS;
 177
 178  struct sh_vars {
 179    long flags;
 180    char *str;
 181  } *vars;
 182
 183  // Running jobs for job control.
 184  struct sh_job {
 185    struct sh_job *next, *prev;
 186    unsigned jobno;
 187
 188    // Every pipeline has at least one set of arguments or it's Not A Thing
 189    struct sh_arg {
 190      char **v;
 191      int c;
 192    } pipeline;
 193
 194    // null terminated array of running processes in pipeline
 195    struct sh_process {
 196      struct sh_process *next, *prev;
 197      struct arg_list *delete;   // expanded strings
 198      // undo redirects, a=b at start, child PID, exit status, has !
 199      int *urd, envlen, pid, exit, not;
 200      struct sh_arg arg;
 201    } *procs, *proc;
 202  } *jobs, *job;
 203
 204  struct sh_process *pp;
 205  struct sh_arg *arg;
 206)
 207
 208// Can't yet avoid this prototype. Fundamental problem is $($($(blah))) nests,
 209// leading to function loop with run->parse->run
 210static int sh_run(char *new);
 211
 212// Pipeline segments
 213struct sh_pipeline {
 214  struct sh_pipeline *next, *prev;
 215  int count, here, type;
 216  struct sh_arg arg[1];
 217};
 218
 219// scratch space (state held between calls). Don't want to make it global yet
 220// because this could be reentrant.
 221struct sh_function {
 222  char *name;
 223  struct sh_pipeline *pipeline;
 224  struct double_list *expect;
 225// TODO: lifetime rules for arg? remember "shift" command.
 226  struct sh_arg *arg; // arguments to function call
 227  char *end;
 228};
 229
 230#define BUGBUG 0
 231
 232// call with NULL to just dump FDs
 233static void dump_state(struct sh_function *sp)
 234{
 235  struct sh_pipeline *pl;
 236  long i;
 237  int q = 0, fd = open("/proc/self/fd", O_RDONLY);
 238  DIR *dir = fdopendir(fd);
 239  char buf[256];
 240
 241  if (sp && sp->expect) {
 242    struct double_list *dl;
 243
 244    for (dl = sp->expect; dl; dl = (dl->next == sp->expect) ? 0 : dl->next)
 245      dprintf(255, "expecting %s\n", dl->data);
 246    if (sp->pipeline)
 247      dprintf(255, "pipeline count=%d here=%d\n", sp->pipeline->prev->count,
 248        sp->pipeline->prev->here);
 249  }
 250
 251  if (sp) for (pl = sp->pipeline; pl ; pl = (pl->next == sp->pipeline) ? 0 : pl->next) {
 252    for (i = 0; i<pl->arg->c; i++)
 253      dprintf(255, "arg[%d][%ld]=%s\n", q, i, pl->arg->v[i]);
 254    if (pl->arg->c<0) dprintf(255, "argc=%d\n", pl->arg->c);
 255    else dprintf(255, "type=%d term[%d]=%s\n", pl->type, q++, pl->arg->v[pl->arg->c]);
 256  }
 257
 258  if (dir) {
 259    struct dirent *dd;
 260
 261    while ((dd = readdir(dir))) {
 262      if (atoi(dd->d_name)!=fd && 0<readlinkat(fd, dd->d_name, buf,sizeof(buf)))
 263        dprintf(255, "OPEN %d: %s = %s\n", getpid(), dd->d_name, buf);
 264    }
 265    closedir(dir);
 266  }
 267  close(fd);
 268}
 269
 270// ordered for greedy matching, so >&; becomes >& ; not > &;
 271// making these const means I need to typecast the const away later to
 272// avoid endless warnings.
 273static const char *redirectors[] = {"<<<", "<<-", "<<", "<&", "<>", "<", ">>",
 274  ">&", ">|", ">", "&>>", "&>", 0};
 275
 276#define OPT_I           1
 277#define OPT_BRACE       2   // set -B
 278#define OPT_NOCLOBBER   4   // set -C
 279#define OPT_S           8
 280#define OPT_C          16
 281
 282static void syntax_err(char *s)
 283{
 284  error_msg("syntax error: %s", s);
 285  toys.exitval = 2;
 286}
 287
 288// append to array with null terminator and realloc as necessary
 289static void array_add(char ***list, unsigned count, char *data)
 290{
 291  if (!(count&31)) *list = xrealloc(*list, sizeof(char *)*(count+33));
 292  (*list)[count] = data;
 293  (*list)[count+1] = 0;
 294}
 295
 296// add argument to an arg_list
 297static void add_arg(struct arg_list **list, char *arg)
 298{
 299  struct arg_list *al;
 300
 301  if (!list) return;
 302  al = xmalloc(sizeof(struct arg_list));
 303  al->next = *list;
 304  al->arg = arg;
 305  *list = al;
 306}
 307
 308static void array_add_del(char ***list, unsigned count, char *data,
 309  struct arg_list **delete)
 310{
 311  add_arg(delete, data);
 312  array_add(list, count, data);
 313}
 314
 315// return length of valid variable name
 316static char *varend(char *s)
 317{
 318  if (isdigit(*s)) return s;
 319  while (*s>' ' && (*s=='_' || !ispunct(*s))) s++;
 320
 321  return s;
 322}
 323
 324// Return index of variable within this list
 325static struct sh_vars *findvar(char *name)
 326{
 327  int len = varend(name)-name;
 328  struct sh_vars *var = TT.vars+TT.varslen;
 329
 330  if (len) while (var-- != TT.vars) 
 331    if (!strncmp(var->str, name, len) && var->str[len] == '=') return var;
 332
 333  return 0;
 334}
 335
 336// Append variable to TT.vars, returning *struct. Does not check duplicates.
 337static struct sh_vars *addvar(char *s)
 338{
 339  if (!(TT.varslen&31))
 340    TT.vars = xrealloc(TT.vars, (TT.varslen+32)*sizeof(*TT.vars));
 341  TT.vars[TT.varslen].flags = 0;
 342  TT.vars[TT.varslen].str = s;
 343
 344  return TT.vars+TT.varslen++;
 345}
 346
 347// TODO function to resolve a string into a number for $((1+2)) etc
 348long long do_math(char *s)
 349{
 350  return atoll(s);
 351}
 352
 353// Assign one variable from malloced key=val string, returns var struct
 354// TODO implement remaining types
 355#define VAR_DICT      256
 356#define VAR_ARRAY     128
 357#define VAR_INT       64
 358#define VAR_TOLOWER   32
 359#define VAR_TOUPPER   16
 360#define VAR_NAMEREF   8
 361#define VAR_GLOBAL    4
 362#define VAR_READONLY  2
 363#define VAR_MAGIC     1
 364
 365// declare -aAilnrux
 366// ft
 367static struct sh_vars *setvar(char *s)
 368{
 369  int len = varend(s)-s;
 370  long flags;
 371  struct sh_vars *var;
 372
 373  if (s[len] != '=') {
 374    error_msg("bad setvar %s\n", s);
 375    free(s);
 376    return 0;
 377  }
 378  if (len == 3 && !memcmp(s, "IFS", 3)) TT.ifs = s+4;
 379
 380  if (!(var = findvar(s))) return addvar(s);
 381  flags = var->flags;
 382
 383  if (flags&VAR_READONLY) {
 384    error_msg("%.*s: read only", len, s);
 385    free(s);
 386
 387    return var;
 388  } else if (flags&VAR_MAGIC) {
 389    if (*s == 'S') TT.SECONDS = millitime() - 1000*do_math(s+len-1);
 390    else if (*s == 'R') srandom(do_math(s+len-1));
 391  } else if (flags&VAR_GLOBAL) xsetenv(var->str = s, 0);
 392  else {
 393    free(var->str);
 394    var->str = s;
 395  }
 396// TODO if (flags&(VAR_TOUPPER|VAR_TOLOWER)) 
 397// unicode _is stupid enough for upper/lower case to be different utf8 byte
 398// lengths. example: lowercase of U+0130 (C4 B0) is U+0069 (69)
 399// TODO VAR_INT
 400// TODO VAR_ARRAY VAR_DICT
 401
 402  return var;
 403}
 404
 405static void unsetvar(char *name)
 406{
 407  struct sh_vars *var = findvar(name);
 408  int ii = var-TT.vars;
 409
 410  if (!var) return;
 411  if (var->flags&VAR_GLOBAL) xunsetenv(name);
 412  else free(var->str);
 413
 414  memmove(TT.vars+ii, TT.vars+ii+1, TT.varslen-ii);
 415  TT.varslen--;
 416}
 417
 418static struct sh_vars *setvarval(char *name, char *val)
 419{
 420  return setvar(xmprintf("%s=%s", name, val));
 421}
 422
 423// get value of variable starting at s.
 424static char *getvar(char *s)
 425{
 426  struct sh_vars *var = findvar(s);
 427
 428  if (!var) return 0;
 429
 430  if (var->flags & VAR_MAGIC) {
 431    char c = *var->str;
 432
 433    if (c == 'S') sprintf(toybuf, "%lld", (millitime()-TT.SECONDS)/1000);
 434    else if (c == 'R') sprintf(toybuf, "%ld", random()&((1<<16)-1));
 435    else if (c == 'L') sprintf(toybuf, "%ld", TT.lineno);
 436    else if (c == 'G') sprintf(toybuf, "TODO: GROUPS");
 437
 438    return toybuf;
 439  }
 440
 441  return varend(var->str)+1;
 442}
 443
 444// malloc declare -x "escaped string"
 445static char *declarep(struct sh_vars *var)
 446{
 447  char *types = "-rgnuliaA", *in = types, flags[16], *out = flags, *ss;
 448  int len;
 449
 450  while (*++in) if (var->flags&(1<<(in-types))) *out++ = *in;
 451  if (in == types) *out++ = *types;
 452  *out = 0;
 453  len = out-flags;
 454
 455  for (in = types = varend(var->str); *in; in++) len += !!strchr("$\"\\`", *in);
 456  len += in-types;
 457  ss = xmalloc(len+13);
 458
 459  out = ss + sprintf(ss, "declare -%s \"", out);
 460  while (types) {
 461    if (strchr("$\"\\`", *in)) *out++ = '\\';
 462    *out++ = *types++;
 463  }
 464  *out++ = '"';
 465  *out = 0;
 466 
 467  return ss; 
 468}
 469
 470// return length of match found at this point (try is null terminated array)
 471static int anystart(char *s, char **try)
 472{
 473  char *ss = s;
 474
 475  while (*try) if (strstart(&s, *try++)) return s-ss;
 476
 477  return 0;
 478}
 479
 480// does this entire string match one of the strings in try[]
 481static int anystr(char *s, char **try)
 482{
 483  while (*try) if (!strcmp(s, *try++)) return 1;
 484
 485  return 0;
 486}
 487
 488// return length of valid prefix that could go before redirect
 489static int redir_prefix(char *word)
 490{
 491  char *s = word;
 492
 493  if (*s == '{') {
 494    if (*(s = varend(s+1)) == '}' && s != word+1) s++;
 495    else s = word;
 496  } else while (isdigit(*s)) s++;
 497
 498  return s-word;
 499}
 500
 501// parse next word from command line. Returns end, or 0 if need continuation
 502// caller eats leading spaces. early = skip one quote block (or return start)
 503static char *parse_word(char *start, int early)
 504{
 505  int i, quote = 0, q, qc = 0;
 506  char *end = start, *s;
 507
 508  // Things we should only return at the _start_ of a word
 509
 510  if (strstart(&end, "<(") || strstart(&end, ">(")) toybuf[quote++]=')';
 511
 512  // Redirections. 123<<file- parses as 2 args: "123<<" "file-".
 513  s = end + redir_prefix(end);
 514  if ((i = anystart(s, (void *)redirectors))) return s+i;
 515
 516  // (( is a special quote at the start of a word
 517  if (strstart(&end, "((")) toybuf[quote++] = 254;
 518
 519  // find end of this word
 520  while (*end) {
 521    i = 0;
 522
 523    // barf if we're near overloading quote stack (nesting ridiculously deep)
 524    if (quote>4000) {
 525      syntax_err("tilt");
 526      return (void *)1;
 527    }
 528
 529    // Handle quote contexts
 530    if ((q = quote ? toybuf[quote-1] : 0)) {
 531
 532      // when waiting for parentheses, they nest
 533      if ((q == ')' || q >= 254) && (*end == '(' || *end == ')')) {
 534        if (*end == '(') qc++;
 535        else if (qc) qc--;
 536        else if (q >= 254) {
 537          // (( can end with )) or retroactively become two (( if we hit one )
 538          if (strstart(&end, "))")) quote--;
 539          else if (q == 254) return start+1;
 540          else if (q == 255) toybuf[quote-1] = ')';
 541        } else if (*end == ')') quote--;
 542        end++;
 543
 544      // end quote?
 545      } else if (*end == q) quote--, end++;
 546
 547      // single quote claims everything
 548      else if (q == '\'') end++;
 549      else i++;
 550
 551      // loop if we already handled a symbol and aren't stopping early
 552      if (early && !quote) return end;
 553      if (!i) continue;
 554    } else {
 555      // Things that only matter when unquoted
 556
 557      if (isspace(*end)) break;
 558      if (*end == ')') return end+(start==end);
 559
 560      // Flow control characters that end pipeline segments
 561      s = end + anystart(end, (char *[]){";;&", ";;", ";&", ";", "||",
 562        "|&", "|", "&&", "&", "(", ")", 0});
 563      if (s != end) return (end == start) ? s : end;
 564    }
 565
 566    // Things the same unquoted or in most non-single-quote contexts
 567
 568    // start new quote context?
 569    if (strchr("\"'`", *end)) toybuf[quote++] = *end;
 570
 571    // backslash escapes
 572    else if (*end == '\\') {
 573      if (!end[1] || (end[1]=='\n' && !end[2])) return 0;
 574      end += 2;
 575    } else if (*end == '$' && -1 != (i = stridx("({[", end[1]))) {
 576      end++;
 577      if (strstart(&end, "((")) toybuf[quote++] = 255;
 578      else {
 579        toybuf[quote++] = ")}]"[i];
 580        end++;
 581      }
 582    }
 583    if (early && !quote) return end;
 584    end++;
 585  }
 586
 587  return quote ? 0 : end;
 588}
 589
 590// Return next available high (>=10) file descriptor
 591static int next_hfd()
 592{
 593  int hfd;
 594
 595  for (; TT.hfd<=99999; TT.hfd++) if (-1 == fcntl(TT.hfd, F_GETFL)) break;
 596  hfd = TT.hfd;
 597  if (TT.hfd > 99999) {
 598    hfd = -1;
 599    if (!errno) errno = EMFILE;
 600  }
 601
 602  return hfd;
 603}
 604
 605// Perform a redirect, saving displaced filehandle to a high (>10) fd
 606// rd is an int array: [0] = count, followed by from/to pairs to restore later.
 607// If from >= 0 dup from->to after saving to. If from == -1 just save to.
 608// if from == -2 schedule "to" to be closed by unredirect.
 609static int save_redirect(int **rd, int from, int to)
 610{
 611  int cnt, hfd, *rr;
 612
 613  if (from == to) return 0;
 614  // save displaced to, copying to high (>=10) file descriptor to undo later
 615  // except if we're saving to environment variable instead (don't undo that)
 616  if (from>-2) {
 617    if ((hfd = next_hfd())==-1) return 1;
 618    if (hfd != dup2(to, hfd)) hfd = -1;
 619    else fcntl(hfd, F_SETFD, FD_CLOEXEC);
 620if (BUGBUG) dprintf(255, "%d redir from=%d to=%d hfd=%d\n", getpid(), from, to, hfd);
 621    // dup "to"
 622    if (from >= 0 && to != dup2(from, to)) {
 623      if (hfd >= 0) close(hfd);
 624
 625      return 1;
 626    }
 627  } else {
 628if (BUGBUG) dprintf(255, "%d schedule close %d\n", getpid(), to);
 629    hfd = to;
 630    to = -1;
 631  }
 632
 633  // Append undo information to redirect list so we can restore saved hfd later.
 634  if (!((cnt = *rd ? **rd : 0)&31)) *rd = xrealloc(*rd, (cnt+33)*2*sizeof(int));
 635  *(rr = *rd) = ++cnt;
 636  rr[2*cnt-1] = hfd;
 637  rr[2*cnt] = to;
 638
 639  return 0;
 640}
 641
 642// TODO: waitpid(WNOHANG) to clean up zombies and catch background& ending
 643static void subshell_callback(char **argv)
 644{
 645  char *s;
 646
 647  xsetenv(s = xmprintf("@%d,%d=", getpid(), getppid()), 0);
 648  s[strlen(s)-1] = 0;
 649  xsetenv(xmprintf("$=%d", TT.pid), 0);
 650// TODO: test $$ in (nommu)
 651}
 652
 653// TODO check every caller of run_subshell for error, or syntax_error() here
 654// from pipe() failure
 655
 656// Pass environment and command string to child shell, return PID of child
 657static int run_subshell(char *str, int len)
 658{
 659  pid_t pid;
 660
 661if (BUGBUG) dprintf(255, "run_subshell %.*s\n", len, str);
 662  // The with-mmu path is significantly faster.
 663  if (CFG_TOYBOX_FORK) {
 664    char *s;
 665
 666    if ((pid = fork())<0) perror_msg("fork");
 667    else if (!pid) {
 668      s = xstrndup(str, len);
 669      sh_run(s);
 670      free(s);
 671      _exit(toys.exitval);
 672    }
 673
 674  // On nommu vfork, exec /proc/self/exe, and pipe state data to ourselves.
 675  } else {
 676    int pipes[2], i, c;
 677
 678    // open pipe to child
 679    if (pipe(pipes) || 254 != dup2(pipes[0], 254)) return 1;
 680    close(pipes[0]);
 681    fcntl(pipes[1], F_SETFD, FD_CLOEXEC);
 682
 683    // vfork child
 684    pid = xpopen_setup(0, 0, subshell_callback);
 685
 686    // free entries added to end of environment by callback (shared heap)
 687    for (i = 0; environ[i]; i++) {
 688      c = environ[i][0];
 689      if (c == '_' || !ispunct(c)) continue;
 690      free(environ[i]);
 691      environ[i] = 0;
 692    }
 693
 694    // marshall data to child
 695    close(254);
 696    for (i = 0; i<TT.varslen; i++) {
 697      char *s;
 698
 699      if (TT.vars[i].flags&VAR_GLOBAL) continue;
 700      dprintf(pipes[1], "%s\n", s = declarep(TT.vars+i));
 701      free(s);
 702    }
 703    dprintf(pipes[1], "%.*s\n", len, str);
 704    close(pipes[1]);
 705  }
 706
 707  return pid;
 708}
 709
 710// restore displaced filehandles, closing high filehandles they were copied to
 711static void unredirect(int *urd)
 712{
 713  int *rr = urd+1, i;
 714
 715  if (!urd) return;
 716
 717  for (i = 0; i<*urd; i++, rr += 2) {
 718if (BUGBUG) dprintf(255, "%d urd %d %d\n", getpid(), rr[0], rr[1]);
 719    if (rr[0] != -1) {
 720      // No idea what to do about fd exhaustion here, so Steinbach's Guideline.
 721      dup2(rr[0], rr[1]);
 722      close(rr[0]);
 723    }
 724  }
 725  free(urd);
 726}
 727
 728// Call subshell with either stdin/stdout redirected, return other end of pipe
 729static int pipe_subshell(char *s, int len, int out)
 730{
 731  int pipes[2], *uu = 0, in = !out;
 732
 733  // Grab subshell data
 734  if (pipe(pipes)) {
 735    perror_msg("%.*s", len, s);
 736
 737    return -1;
 738  }
 739
 740  // Perform input or output redirect and launch process (ignoring errors)
 741  save_redirect(&uu, pipes[in], in);
 742  close(pipes[in]);
 743  run_subshell(s, len);
 744  unredirect(uu);
 745
 746  return pipes[out];
 747}
 748
 749// utf8 strchr: return wide char matched at wc from chrs, or 0 if not matched
 750// if len, save length of wc
 751static int utf8chr(char *wc, char *chrs, int *len)
 752{
 753  wchar_t wc1, wc2;
 754  int ll;
 755
 756  if (len) *len = 1;
 757  if (!*wc) return 0;
 758  if (0<(ll = utf8towc(&wc1, wc, 99))) {
 759    if (len) *len = ll;
 760    while (*chrs) {
 761      if(1>(ll = utf8towc(&wc2, chrs, 99))) chrs++;
 762      else {
 763        if (wc1 == wc2) return wc1;
 764        chrs += ll;
 765      }
 766    }
 767  }
 768
 769  return 0;
 770}
 771
 772#define NO_PATH  (1<<0)    // path expansion (wildcards)
 773#define NO_SPLIT (1<<1)    // word splitting
 774#define NO_BRACE (1<<2)    // {brace,expansion}
 775#define NO_TILDE (1<<3)    // ~username/path
 776#define NO_QUOTE (1<<4)    // quote removal
 777#define SEMI_IFS (1<<5)    // Use ' ' instead of IFS to combine $*
 778// TODO: parameter/variable $(command) $((math)) split pathglob
 779// TODO: ${name:?error} causes an error/abort here (syntax_err longjmp?)
 780// TODO: $1 $@ $* need args marshalled down here: function+structure?
 781// arg = append to this
 782// str = string to expand
 783// flags = type of expansions (not) to do
 784// delete = append new allocations to this so they can be freed later
 785// TODO: at_args: $1 $2 $3 $* $@
 786static int expand_arg_nobrace(struct sh_arg *arg, char *str, unsigned flags,
 787  struct arg_list **delete)
 788{
 789  char cc, qq = 0, *old = str, *new = str, *s, *ss, *ifs, **aa;
 790  int ii = 0, dd, jj, kk, ll, oo = 0, nodel;
 791
 792if (BUGBUG) dprintf(255, "expand %s\n", str);
 793
 794  // Tilde expansion
 795  if (!(flags&NO_TILDE) && *str == '~') {
 796    struct passwd *pw = 0;
 797
 798    ss = 0;
 799    while (str[ii] && str[ii]!=':' && str[ii]!='/') ii++;
 800    if (ii==1) {
 801      if (!(ss = getvar("HOME")) || !*ss) pw = bufgetpwuid(getuid());
 802    } else {
 803      // TODO bufgetpwnam
 804      pw = getpwnam(s = xstrndup(str+1, ii-1));
 805      free(s);
 806    }
 807    if (pw) {
 808      ss = pw->pw_dir;
 809      if (!ss || !*ss) ss = "/";
 810    }
 811    if (ss) {
 812      oo = strlen(ss);
 813      s = xmprintf("%s%s", ss, str+ii);
 814      if (old != new) free(new);
 815      new = s;
 816    }
 817  }
 818
 819  // parameter/variable expansion, and dequoting
 820
 821  for (; (cc = str[ii++]); old!=new && (new[oo] = 0)) {
 822
 823    // skip literal chars
 824    if (!strchr("$'`\\\"", cc)) {
 825      if (old != new) new[oo++] = cc;
 826      continue;
 827    }
 828
 829    // allocate snapshot if we just started modifying
 830    if (old == new) {
 831      new = xstrdup(new);
 832      new[oo = ii-1] = 0;
 833    }
 834    ifs = 0;
 835    aa = 0;
 836    nodel = 0;
 837
 838    // handle different types of escapes
 839    if (cc == '\\') new[oo++] = str[ii] ? str[ii++] : cc;
 840    else if (cc == '"') qq++;
 841    else if (cc == '\'') {
 842      if (qq&1) new[oo++] = cc;
 843      else {
 844        qq += 2;
 845        while ((cc = str[ii++]) != '\'') new[oo++] = cc;
 846      }
 847    // both types of subshell work the same, so do $( here not in '$' below
 848// TODO $((echo hello) | cat) ala $(( becomes $( ( retroactively
 849    } else if (cc == '`' || (cc == '$' && strchr("([", str[ii]))) {
 850      off_t pp = 0;
 851
 852      s = str+ii-1;
 853      kk = parse_word(s, 1)-s;
 854      if (str[ii] == '[' || *toybuf == 255) {
 855        s += 2+(str[ii]!='[');
 856        kk -= 3+2*(str[ii]!='[');
 857dprintf(2, "TODO: do math for %.*s\n", kk, s);
 858      } else {
 859        // Run subshell and trim trailing newlines
 860        s += (jj = 1+(cc == '$'));
 861        ii += --kk;
 862        kk -= jj;
 863
 864        // Special case echo $(<input)
 865        for (ss = s; isspace(*ss); ss++);
 866        if (*ss != '<') ss = 0;
 867        else {
 868          while (isspace(*++ss));
 869          if (!(ll = parse_word(ss, 0)-ss)) ss = 0;
 870          else {
 871            jj = ll+(ss-s);
 872            while (isspace(s[jj])) jj++;
 873            if (jj != kk) ss = 0;
 874            else {
 875              jj = xcreate_stdio(ss = xstrndup(ss, ll), O_RDONLY|WARN_ONLY, 0);
 876              free(ss);
 877            }
 878          }
 879        }
 880
 881// TODO what does \ in `` mean? What is echo `printf %s \$x` supposed to do?
 882        if (!ss) jj = pipe_subshell(s, kk, 0);
 883        if ((ifs = readfd(jj, 0, &pp)))
 884          for (kk = strlen(ifs); kk && ifs[kk-1]=='\n'; ifs[--kk] = 0);
 885        close(jj);
 886      }
 887    } else if (cc == '$') {
 888
 889      // parse $ $'' ${} or $VAR
 890
 891      cc = str[ii++];
 892      if (cc=='\'') {
 893        for (s = str+ii; *s != '\''; oo += wcrtomb(new+oo, unescape2(&s, 0),0));
 894        ii = s-str+1;
 895
 896        continue;
 897      } else if (cc == '{') {
 898        cc = *(ss = str+ii);
 899        if (!(jj = strchr(ss, '}')-ss)) ifs = (void *)1;
 900        ii += jj+1;
 901
 902        if (jj>1) {
 903          // handle ${!x} and ${#x}
 904          if (*ss == '!') {
 905            if (!(ss = getvar(ss+1)) || !*ss) continue;
 906            jj = varend(ss)-ss;
 907            if (ss[jj]) ifs = (void *)1;
 908          } else if (*ss == '#') {
 909            if (jj == 2 && (*ss == '@' || *ss == '*')) jj--;
 910            else ifs = xmprintf("%ld", (long)strlen(getvar(ss) ? : ""));
 911          }
 912        }
 913      } else {
 914        ss = str+--ii;
 915        if (!(jj = varend(ss)-ss)) jj++;
 916        ii += jj;
 917      }
 918
 919// ${#nom} ${} ${x}
 920// ${x:-y} use default
 921// ${x:=y} assign default (error if positional)
 922// ${x:?y} err if null
 923// ${x:+y} alt value
 924// ${x:off} ${x:off:len} off<0 from end (must ": -"), len<0 also from end must
 925//   0-based indexing
 926// ${@:off:len} positional parameters, off -1 = len, -len is error
 927//   1-based indexing
 928// ${!x} deref (does bad substitution if name has : in it)
 929// ${!x*} ${!x@} names matching prefix
 930//   note: expands something other than arg->c
 931// ${x#y} remove shortest prefix ${x##y} remove longest prefix
 932//   x can be @ or *
 933// ${x%y} ${x%%y} suffix
 934// ${x/pat/sub} substitute ${x//pat/sub} global ${x/#pat/sub} begin
 935// ${x/%pat/sub} end ${x/pat} delete pat
 936//   x can be @ or *
 937// ${x^pat} ${x^^pat} uppercase/g ${x,} ${x,,} lowercase/g (no pat = ?)
 938// ${x@QEPAa} Q=$'blah' E=blah without the $'' wrap, P=expand as $PS1
 939//   A=declare that recreates var a=attribute flags
 940//   x can be @*
 941
 942// TODO: $_ is last arg of last command, and exported as path to exe run
 943// TODO: $! is PID of most recent background job
 944      if (ifs);
 945      else if (cc == '-') {
 946        s = ifs = xmalloc(8);
 947        if (TT.options&OPT_I) *s++ = 'i';
 948        if (TT.options&OPT_BRACE) *s++ = 'B';
 949        if (TT.options&OPT_S) *s++ = 's';
 950        if (TT.options&OPT_C) *s++ = 'c';
 951        *s = 0;
 952      } else if (cc == '?') ifs = xmprintf("%d", toys.exitval);
 953      else if (cc == '$') ifs = xmprintf("%d", TT.pid);
 954      else if (cc == '#') ifs = xmprintf("%d", TT.arg->c?TT.arg->c-1:0);
 955      else if (cc == '*' || cc == '@') aa = TT.arg->v+1;
 956      else if (isdigit(cc)) {
 957        for (kk = ll = 0; kk<jj && isdigit(ss[kk]); kk++)
 958          ll = (10*ll)+ss[kk]-'0';
 959        if (ll) ll += TT.shift;
 960        if (ll<TT.arg->c) ifs = TT.arg->v[ll];
 961        nodel = 1;
 962
 963      // $VARIABLE
 964      } else {
 965        if (ss == varend(ss)) {
 966          ii--;
 967          if (ss[-1] == '$') new[oo++] = '$';
 968          else ifs = (void *)1;
 969        } else ifs = getvar(ss);
 970        nodel = 1;
 971      }
 972    }
 973
 974// TODO: $((a=42)) can change var, affect lifetime
 975// must replace ifs AND any previous output arg[] within pointer strlen()
 976// TODO ${blah} here
 977
 978    if (ifs == (void *)1) {
 979      error_msg("%.*s: bad substitution", (int)(s-(str+ii)+3), str+ii-2);
 980      free(new);
 981
 982      return 1;
 983    }
 984
 985    // combine before/ifs/after sections, splitting words on $IFS in ifs
 986    if (ifs || aa) {
 987      char sep[8];
 988
 989      // If not gluing together, nothing to substitute, not quoted: do nothing
 990      if (!aa && !*ifs && !qq) continue;
 991
 992      // Fetch separator
 993      *sep = 0;
 994      if ((qq&1) && cc=='*') {
 995        wchar_t wc;
 996
 997        if (flags&SEMI_IFS) strcpy(sep, " ");
 998        else if (0<(dd = utf8towc(&wc, TT.ifs, 4)))
 999          sprintf(sep, "%.*s", dd, TT.ifs);
1000      }
1001
1002      // when aa proceed through entries until NULL, else process ifs once
1003      do {
1004
1005        // get next argument, is this last entry, find end of word
1006        if (aa) {
1007          ifs = *aa ? : "";
1008          if (*aa) aa++;
1009          nodel = 1;
1010        }
1011        if (qq&1) ss = ifs+strlen(ifs);
1012        else for (ss = ifs; *ss; ss += kk)
1013          if ((ll = utf8chr(ss, TT.ifs, &kk))) break;
1014        kk = !aa || !*aa;
1015
1016        // loop within current ifs checking region to split words
1017        do {
1018          // fast path: use existing memory when no prefix, not splitting it,
1019          // and either not last entry or no suffix
1020          if (!oo && !*ss && (!kk || !str[ii]) && !((qq&1) && cc=='*')) {
1021            if (!qq && ss==ifs) break;
1022            array_add_del(&arg->v, arg->c++, ifs, nodel ? 0 : delete);
1023            nodel = 1;
1024
1025            continue;
1026          }
1027
1028          // resize allocation and copy next chunk of IFS-free data
1029          new = xrealloc(new, oo + (ss-ifs) + strlen(sep) +
1030                         ((jj = kk && !*ss) ? strlen(str+ii) : 0) + 1);
1031          oo += sprintf(new + oo, "%.*s", (int)(ss-ifs), ifs);
1032          if (!nodel) free(ifs);
1033          nodel = 1;
1034          if (jj) break;
1035
1036          // for single quoted "$*" append IFS
1037          if ((qq&1) && cc == '*') oo += sprintf(new+oo, "%s", sep);
1038
1039          // add argument if quoted, non-blank, or non-whitespace separator
1040          else {
1041            if (qq || *new || *ss) {
1042              array_add_del(&arg->v, arg->c++, new, nodel ? 0 : delete);
1043              nodel = 1;
1044            }
1045            qq &= 1;
1046            new = xstrdup(str+ii);
1047            oo = 0;
1048          }
1049
1050          // Skip trailing seperator (combining whitespace)
1051          while ((jj = utf8chr(ss, TT.ifs, &ll)) && iswspace(jj)) ss += ll;
1052
1053        } while (*(ifs = ss));
1054      } while (!kk);
1055    }
1056  }
1057
1058// TODO globbing * ? [
1059
1060// Word splitting completely eliminating argument when no non-$IFS data left
1061// wordexp keeps pattern when no matches
1062
1063// TODO NO_SPLIT cares about IFS, see also trailing \n
1064
1065// quote removal
1066
1067  // Record result.
1068  if (*new || qq)
1069    array_add_del(&arg->v, arg->c++, new, (old != new) ? delete : 0);
1070  else if(old != new) free(new);
1071
1072  return 0;
1073}
1074
1075// expand braces (ala {a,b,c}) and call expand_arg_nobrace() each permutation
1076static int expand_arg(struct sh_arg *arg, char *old, unsigned flags,
1077  struct arg_list **delete)
1078{
1079  struct brace {
1080    struct brace *next, *prev, *stack;
1081    int active, cnt, idx, dots[2], commas[];
1082  } *bb = 0, *blist = 0, *bstk, *bnext;
1083  int i, j;
1084  char *s, *ss;
1085
1086  // collect brace spans
1087  if ((TT.options&OPT_BRACE) && !(flags&NO_BRACE)) for (i = 0; ; i++) {
1088    while ((s = parse_word(old+i, 1)) != old+i) i += s-(old+i);
1089    if (!bb && !old[i]) break;
1090    if (bb && (!old[i] || old[i] == '}')) {
1091      bb->active = bb->commas[bb->cnt+1] = i;
1092      for (bnext = bb; bb && bb->active; bb = (bb==blist)?0:bb->prev);
1093      if (!old[i] || !bnext->cnt) // discard commaless brace from start/middle
1094        free(dlist_pop((blist == bnext) ? &blist : &bnext));
1095    } else if (old[i] == '{') {
1096      dlist_add_nomalloc((void *)&blist,
1097        (void *)(bb = xzalloc(sizeof(struct brace)+34*4)));
1098      bb->commas[0] = i;
1099    } else if (!bb) continue;
1100    else if  (bb && old[i] == ',') {
1101      if (bb->cnt && !(bb->cnt&31)) {
1102        dlist_lpop(&blist);
1103        dlist_add_nomalloc((void *)&blist,
1104          (void *)(bb = xrealloc(bb, sizeof(struct brace)+(bb->cnt+34)*4)));
1105      }
1106      bb->commas[++bb->cnt] = i;
1107    }
1108  }
1109
1110// TODO NOSPLIT with braces? (Collate with spaces?)
1111  // If none, pass on verbatim
1112  if (!blist) return expand_arg_nobrace(arg, old, flags, delete);
1113
1114  // enclose entire range in top level brace.
1115  (bstk = xzalloc(sizeof(struct brace)+8))->commas[1] = strlen(old)+1;
1116  bstk->commas[0] = -1;
1117
1118  // loop through each combination
1119  for (;;) {
1120
1121    // Brace expansion can't be longer than original string. Keep start to {
1122    s = ss = xmalloc(bstk->commas[1]);
1123
1124    // Append output from active braces (in "saved" list)
1125    for (bb = blist; bb;) {
1126
1127      // keep prefix and push self onto stack
1128      if (bstk == bb) bstk = bstk->stack;  // pop self
1129      i = bstk->commas[bstk->idx]+1;
1130      if (bstk->commas[bstk->cnt+1]>bb->commas[0])
1131        s = stpncpy(s, old+i, bb->commas[0]-i);
1132
1133      // pop sibling
1134      if (bstk->commas[bstk->cnt+1]<bb->commas[0]) bstk = bstk->stack;
1135 
1136      bb->stack = bstk; // push
1137      bb->active = 1;
1138      bstk = bnext = bb;
1139
1140      // skip inactive spans from earlier or later commas
1141      while ((bnext = (bnext->next==blist) ? 0 : bnext->next)) {
1142        i = bnext->commas[0];
1143
1144        // past end of this brace
1145        if (i>bb->commas[bb->cnt+1]) break;
1146
1147        // in this brace but not this selection
1148        if (i<bb->commas[bb->idx] || i>bb->commas[bb->idx+1]) {
1149          bnext->active = 0;
1150          bnext->stack = 0;
1151
1152        // in this selection
1153        } else break;
1154      }
1155
1156      // is next span past this range?
1157      if (!bnext || bnext->commas[0]>bb->commas[bb->idx+1]) {
1158
1159        // output uninterrupted span
1160        i = bb->commas[bstk->idx]+1;
1161        s = stpncpy(s, old+i, bb->commas[bb->idx+1]-i);
1162
1163        // While not sibling, output tail and pop
1164        while (!bnext || bnext->commas[0] > bstk->commas[bstk->cnt+1]) {
1165          if (!(bb = bstk->stack)) break;
1166          i = bstk->commas[bstk->cnt+1]+1; // start of span
1167          j = bb->commas[bb->idx+1]; // enclosing comma span
1168
1169          while (bnext) {
1170            if (bnext->commas[0]<j) {
1171              j = bnext->commas[0];// sibling
1172              break;
1173            } else if (bb->commas[bb->cnt+1]>bnext->commas[0])
1174              bnext = (bnext->next == blist) ? 0 : bnext->next;
1175            else break;
1176          }
1177          s = stpncpy(s, old+i, j-i);
1178
1179          // if next is sibling but parent _not_ a sibling, don't pop
1180          if (bnext && bnext->commas[0]<bstk->stack->commas[bstk->stack->cnt+1])
1181            break;
1182          bstk = bstk->stack;
1183        }
1184      }
1185      bb = (bnext == blist) ? 0 : bnext;
1186    }
1187
1188    // Save result, aborting on expand error
1189    add_arg(delete, ss);
1190    if (expand_arg_nobrace(arg, ss, flags, delete)) {
1191      llist_traverse(blist, free);
1192
1193      return 1;
1194    }
1195
1196    // increment
1197    for (bb = blist->prev; bb; bb = (bb == blist) ? 0 : bb->prev) {
1198      if (!bb->stack) continue;
1199      else if (++bb->idx > bb->cnt) bb->idx = 0;
1200      else break;
1201    }
1202
1203    // if increment went off left edge, done expanding
1204    if (!bb) break;
1205  }
1206  llist_traverse(blist, free);
1207
1208  return 0;
1209}
1210
1211// Expand exactly one arg, returning NULL on error.
1212static char *expand_one_arg(char *new, unsigned flags, struct arg_list **del)
1213{
1214  struct sh_arg arg;
1215  char *s = 0;
1216  int i;
1217
1218  memset(&arg, 0, sizeof(arg));
1219  if (!expand_arg(&arg, new, flags, del) && arg.c == 1) s = *arg.v;
1220  if (!del && !s) for (i = 0; i < arg.c; i++) free(arg.v[i]);
1221  free(arg.v);
1222
1223  return s;
1224}
1225
1226// TODO |&
1227
1228// turn a parsed pipeline back into a string.
1229static char *pl2str(struct sh_pipeline *pl)
1230{
1231  struct sh_pipeline *end = 0;
1232  int level = 0, len = 0, i, j;
1233  char *s, *ss, *sss;
1234
1235  // measure, then allocate
1236  for (j = 0; ; j++) for (end = pl; end; end = end->next) {
1237    if (end->type == 1) level++;
1238    else if (end->type == 3 && --level<0) break;
1239
1240    for (i = 0; i<pl->arg->c; i++)
1241      if (j) ss += sprintf(ss, "%s ", pl->arg->v[i]);
1242      else len += strlen(pl->arg->v[i])+1;
1243
1244    sss = pl->arg->v[pl->arg->c];
1245    if (!sss) sss = ";";
1246    if (j) ss = stpcpy(ss, sss);
1247    else len += strlen(sss);
1248
1249// TODO add HERE documents back in
1250    if (j) return s;
1251    s = ss = xmalloc(len+1);
1252  }
1253}
1254
1255// Expand arguments and perform redirections. Return new process object with
1256// expanded args. This can be called from command or block context.
1257static struct sh_process *expand_redir(struct sh_arg *arg, int envlen, int *urd)
1258{
1259  struct sh_process *pp;
1260  char *s = s, *ss, *sss, *cv = 0;
1261  int j, to, from, here = 0;
1262
1263  TT.hfd = 10;
1264
1265  pp = xzalloc(sizeof(struct sh_process));
1266  pp->urd = urd;
1267
1268  // When we redirect, we copy each displaced filehandle to restore it later.
1269
1270  // Expand arguments and perform redirections
1271  for (j = envlen; j<arg->c; j++) {
1272    int saveclose = 0, bad = 0;
1273
1274    s = arg->v[j];
1275
1276    if (!strcmp(s, "!")) {
1277      pp->not ^= 1;
1278
1279      continue;
1280    }
1281
1282    // Handle <() >() redirectionss
1283    if ((*s == '<' || *s == '>') && s[1] == '(') {
1284      int new = pipe_subshell(s+2, strlen(s+2)-1, *s == '>');
1285
1286      // Grab subshell data
1287      if (new == -1) {
1288        pp->exit = 1;
1289
1290        return pp;
1291      }
1292      save_redirect(&pp->urd, -2, new);
1293
1294      // bash uses /dev/fd/%d which requires /dev/fd to be a symlink to
1295      // /proc/self/fd so we just produce that directly.
1296      array_add_del(&pp->arg.v, pp->arg.c++,
1297        ss = xmprintf("/proc/self/fd/%d", new), &pp->delete);
1298
1299      continue;
1300    }
1301
1302    // Is this a redirect? s = prefix, ss = operator
1303    ss = s + redir_prefix(arg->v[j]);
1304    sss = ss + anystart(ss, (void *)redirectors);
1305    if (ss == sss) {
1306      // Nope: save/expand argument and loop
1307      if (expand_arg(&pp->arg, s, 0, &pp->delete)) {
1308        pp->exit = 1;
1309
1310        return pp;
1311      }
1312      continue;
1313    } else if (j+1 >= arg->c) {
1314      // redirect needs one argument
1315      s = "\\n";
1316      break;
1317    }
1318    sss = arg->v[++j];
1319
1320    // It's a redirect: for [to]<from s = start of [to], ss = <, sss = from
1321    if (isdigit(*s) && ss-s>5) break;
1322
1323    // expand arguments for everything but << and <<-
1324    if (strncmp(ss, "<<", 2) && ss[2] != '<' &&
1325      !(sss = expand_one_arg(sss, NO_PATH, &pp->delete)))
1326    {
1327      s = 0;
1328      break; // arg splitting here is an error
1329    }
1330
1331    // Parse the [fd] part of [fd]<name
1332    to = *ss != '<';
1333    if (isdigit(*s)) to = atoi(s);
1334    else if (*s == '{') {
1335      if (*varend(s+1) != '}') break;
1336      // when we close a filehandle, we _read_ from {var}, not write to it
1337      if ((!strcmp(ss, "<&") || !strcmp(ss, ">&")) && !strcmp(sss, "-")) {
1338        if (!(ss = getvar(s+1))) break;
1339        to = atoi(ss); // TODO trailing garbage?
1340        if (save_redirect(&pp->urd, -1, to)) break;
1341        close(to);
1342
1343        continue;
1344      // record high file descriptor in {to}<from environment variable
1345      } else {
1346        // we don't save this, it goes in the env var and user can close it.
1347        if (-1 == (to = next_hfd())) break;
1348        cv = xmprintf("%.*s=%d", (int)(ss-s-2), s+1, to);
1349      }
1350    }
1351
1352    // HERE documents?
1353    if (!strcmp(ss, "<<<") || !strcmp(ss, "<<-") || !strcmp(ss, "<<")) {
1354      char *tmp = getvar("TMPDIR");
1355      int i, len, zap = (ss[2] == '-'), x = !ss[strcspn(ss, "\"'")];
1356
1357      // store contents in open-but-deleted /tmp file.
1358      tmp = xmprintf("%s/sh-XXXXXX", tmp ? tmp : "/tmp");
1359      if ((from = mkstemp(tmp))>=0) {
1360        if (unlink(tmp)) bad++;
1361
1362        // write contents to file (if <<< else <<) then lseek back to start
1363        else if (ss[2] == '<') {
1364          if (x && !(sss = expand_one_arg(sss, NO_PATH|NO_SPLIT, 0))) {
1365            s = 0;
1366            break;
1367          }
1368          len = strlen(sss);
1369          if (len != writeall(from, sss, len)) bad++;
1370          if (x) free(sss);
1371        } else {
1372          struct sh_arg *hh = arg+here++;
1373
1374          for (i = 0; i<hh->c; i++) {
1375            ss = hh->v[i];
1376            sss = 0;
1377// TODO audit this ala man page
1378            // expand_parameter, commands, and arithmetic
1379            if (x && !(ss = sss = expand_one_arg(ss,
1380              NO_PATH|NO_SPLIT|NO_BRACE|NO_TILDE|NO_QUOTE, 0)))
1381            {
1382              s = 0;
1383              break;
1384            }
1385
1386            while (zap && *ss == '\t') ss++;
1387            x = writeall(from, ss, len = strlen(ss));
1388            free(sss);
1389            if (len != x) break;
1390          }
1391          if (i != hh->c) bad++;
1392        }
1393        if (!bad && lseek(from, 0, SEEK_SET)) bad++;
1394        if (bad) close(from);
1395      } else bad++;
1396      free(tmp);
1397      if (bad) break;
1398
1399    // from is fd<<2 (new fd to dup2() after vfork()) plus
1400    // 2 if we should close(from>>2) after dup2(from>>2, to),
1401    // 1 if we should close but dup for nofork recovery (ala <&2-)
1402
1403    // Handle file descriptor duplication/close (&> &>> <& >& with number or -)
1404    // These redirect existing fd so nothing to open()
1405    } else if (*ss == '&' || ss[1] == '&') {
1406
1407      // is there an explicit fd?
1408      for (ss = sss; isdigit(*ss); ss++);
1409      if (ss-sss>5 || (*ss && (*ss != '-' || ss[1]))) {
1410        if (*ss=='&') ss++;
1411        saveclose = 4;
1412        goto notfd;
1413      }
1414
1415      from = (ss==sss) ? to : atoi(sss);
1416      saveclose = 2-(*ss == '-');
1417    } else {
1418notfd:
1419      // Permissions to open external file with: < > >> <& >& <> >| &>> &>
1420      if (!strcmp(ss, "<>")) from = O_CREAT|O_RDWR;
1421      else if (strstr(ss, ">>")) from = O_CREAT|O_APPEND|O_WRONLY;
1422      else {
1423        from = (*ss == '<') ? O_RDONLY : O_CREAT|O_WRONLY|O_TRUNC;
1424        if (!strcmp(ss, ">") && (TT.options&OPT_NOCLOBBER)) {
1425          struct stat st;
1426
1427          // Not _just_ O_EXCL: > /dev/null allowed
1428          if (stat(sss, &st) || !S_ISREG(st.st_mode)) from |= O_EXCL;
1429        }
1430      }
1431
1432      // we expect /dev/fd/# and /dev/{stdin,stdout,stderr} to be in /dev
1433
1434// TODO: /dev/{tcp,udp}/host/port
1435
1436      // Open the file
1437      if (-1 == (from = xcreate_stdio(sss, from|WARN_ONLY, 0666))) {
1438        s = 0;
1439
1440        break;
1441      }
1442    }
1443
1444    // perform redirect, saving displaced "to".
1445    if (save_redirect(&pp->urd, from, to)) bad++;
1446    // Do we save displaced "to" in env variable instead of undo list?
1447    if (cv) {
1448      --*pp->urd;
1449      setvar(cv);
1450      cv = 0;
1451    }
1452    if ((saveclose&1) && save_redirect(&pp->urd, -1, from)) bad++;
1453    if ((saveclose&4) && save_redirect(&pp->urd, from, 2)) bad++;
1454    if (!(saveclose&2)) close(from);
1455    if (bad) break;
1456  }
1457
1458  // didn't parse everything?
1459  if (j != arg->c) {
1460    if (s) syntax_err(s);
1461    if (!pp->exit) pp->exit = 1;
1462    free(cv);
1463  }
1464
1465  return pp;
1466}
1467
1468static void shexec(char *cmd, char **argv)
1469{
1470  xsetenv(xmprintf("_=%s", cmd), 0);
1471  execve(cmd, argv, environ);
1472  if (errno == ENOEXEC) run_subshell("source \"$_\"", 11);
1473}
1474
1475// Call binary, or run via child shell
1476static void sh_exec(char **argv)
1477{
1478  char *pp = getvar("PATH" ? : _PATH_DEFPATH), *cc = TT.isexec ? : *argv;
1479  struct string_list *sl;
1480
1481  if (getpid() != TT.pid) signal(SIGINT, SIG_DFL);
1482  if (strchr(cc, '/')) shexec(cc, argv);
1483  else for (sl = find_in_path(pp, cc); sl; free(llist_pop(&sl)))
1484    shexec(sl->str, argv);
1485
1486  perror_msg("%s", *argv);
1487  if (!TT.isexec) _exit(127);
1488}
1489
1490// Execute a single command
1491static struct sh_process *run_command(struct sh_arg *arg)
1492{
1493  char *s, *ss = 0, *sss, **env = 0, **old = environ;
1494  int envlen, jj, kk, ll;
1495  struct sh_process *pp;
1496  struct toy_list *tl;
1497
1498if (BUGBUG) dprintf(255, "run_command %s\n", arg->v[0]);
1499
1500  // Grab leading variable assignments
1501  for (envlen = 0; envlen<arg->c; envlen++) {
1502    s = varend(arg->v[envlen]);
1503    if (s == arg->v[envlen] || *s != '=') break;
1504  }
1505
1506  // expand arguments and perform redirects
1507  pp = expand_redir(arg, envlen, 0);
1508
1509if (BUGBUG) { int i; dprintf(255, "envlen=%d arg->c=%d run=", envlen, arg->c); for (i=0; i<pp->arg.c; i++) dprintf(255, "'%s' ", pp->arg.v[i]); dprintf(255, "\n"); }
1510  // perform assignments locally if there's no command
1511  if (envlen == arg->c) {
1512    for (jj = 0; jj<envlen; jj++) {
1513      if (!(s = expand_one_arg(arg->v[jj], NO_PATH|NO_SPLIT, 0))) break;
1514      if (s == arg->v[jj]) s = xstrdup(s);
1515      setvar(s);
1516    }
1517    goto out;
1518  }
1519
1520  if (envlen) {
1521    for (kk = 0; environ[kk]; kk++);
1522    env = xmalloc(sizeof(char *)*(kk+33));
1523    memcpy(env, environ, sizeof(char *)*(kk+1));
1524    environ = env;
1525
1526    // assign leading environment variables
1527    for (jj = 0; jj<envlen; jj++) {
1528      if (!(sss = expand_one_arg(arg->v[jj], NO_PATH|NO_SPLIT, &pp->delete)))
1529        break;
1530      for (ll = 0; ll<kk; ll++) {
1531        for (s = sss, ss = environ[ll]; *s == *ss && *s != '='; s++, ss++);
1532        if (*s != '=') continue;
1533        environ[ll] = sss;
1534        break;
1535      }
1536      if (ll == kk) array_add(&environ, kk++, sss);
1537    }
1538  } else jj = 0;
1539
1540  // Do nothing if nothing to do
1541  if (jj != envlen || pp->exit || !pp->arg.v);
1542//  else if (!strcmp(*pp->arg.v, "(("))
1543// TODO: handle ((math)) currently totally broken
1544// TODO: call functions()
1545  // Is this command a builtin that should run in this process?
1546  else if ((tl = toy_find(*pp->arg.v))
1547    && (tl->flags & (TOYFLAG_NOFORK|TOYFLAG_MAYFORK)))
1548  {
1549    sigjmp_buf rebound;
1550    char temp[jj = offsetof(struct toy_context, rebound)];
1551
1552    // This fakes lots of what toybox_main() does.
1553    memcpy(&temp, &toys, jj);
1554    memset(&toys, 0, jj);
1555
1556    // If we give the union in TT a name, the compiler complains
1557    // "declaration does not declare anything", but if we DON'T give it a name
1558    // it accepts it. So we can't use the union's type name here, and have
1559    // to offsetof() the first thing _after_ the union to get the size.
1560    memset(&TT, 0, offsetof(struct sh_data, lineno));
1561
1562    TT.pp = pp;
1563    if (!sigsetjmp(rebound, 1)) {
1564      toys.rebound = &rebound;
1565      toy_singleinit(tl, pp->arg.v);  // arg.v must be null terminated
1566      tl->toy_main();
1567      xflush(0);
1568    }
1569    TT.pp = 0;
1570    toys.rebound = 0;
1571    pp->exit = toys.exitval;
1572    if (toys.optargs != toys.argv+1) free(toys.optargs);
1573    if (toys.old_umask) umask(toys.old_umask);
1574    memcpy(&toys, &temp, jj);
1575  } else if (-1==(pp->pid = xpopen_setup(pp->arg.v+envlen, 0, sh_exec)))
1576    perror_msg("%s: vfork", *pp->arg.v);
1577
1578  // Restore environment variables
1579  environ = old;
1580  free(env);
1581
1582out:
1583  setvarval("_", (envlen == arg->c) ? "" : s);
1584  // cleanup process
1585  unredirect(pp->urd);
1586
1587  return pp;
1588}
1589
1590static void free_process(void *ppp)
1591{
1592  struct sh_process *pp = ppp;
1593  llist_traverse(pp->delete, llist_free_arg);
1594  free(pp);
1595}
1596
1597// if then fi for while until select done done case esac break continue return
1598
1599// Free one pipeline segment.
1600static void free_pipeline(void *pipeline)
1601{
1602  struct sh_pipeline *pl = pipeline;
1603  int i, j;
1604
1605  // free arguments and HERE doc contents
1606  if (pl) for (j=0; j<=pl->count; j++) {
1607    for (i = 0; i<=pl->arg[j].c; i++) free(pl->arg[j].v[i]);
1608    free(pl->arg[j].v);
1609  }
1610  free(pl);
1611}
1612
1613// Return end of current block, or NULL if we weren't in block and fell off end.
1614static struct sh_pipeline *block_end(struct sh_pipeline *pl)
1615{
1616  int i = 0;
1617
1618// TODO: should this be inlined into type 1 processing to set blk->end and
1619// then everything else use that?
1620
1621  while (pl) {
1622    if (pl->type == 1 || pl->type == 'f') i++;
1623    else if (pl->type == 3) if (--i<1) break;
1624    pl = pl->next;
1625  }
1626
1627  return pl;
1628}
1629
1630static void free_function(struct sh_function *sp)
1631{
1632  llist_traverse(sp->pipeline, free_pipeline);
1633  llist_traverse(sp->expect, free);
1634  memset(sp, 0, sizeof(struct sh_function));
1635}
1636
1637// TODO this has to add to a namespace context. Functions within functions...
1638static struct sh_pipeline *add_function(char *name, struct sh_pipeline *pl)
1639{
1640dprintf(2, "stub add_function");
1641
1642  return block_end(pl->next);
1643}
1644
1645// Add a line of shell script to a shell function. Returns 0 if finished,
1646// 1 to request another line of input (> prompt), -1 for syntax err
1647static int parse_line(char *line, struct sh_function *sp)
1648{
1649  char *start = line, *delete = 0, *end, *last = 0, *s, *ex, done = 0,
1650    *tails[] = {"fi", "done", "esac", "}", "]]", ")", 0};
1651  struct sh_pipeline *pl = sp->pipeline ? sp->pipeline->prev : 0;
1652  struct sh_arg *arg = 0;
1653  long i;
1654
1655  // Resume appending to last statement?
1656  if (pl) {
1657    arg = pl->arg;
1658
1659    // Extend/resume quoted block
1660    if (arg->c<0) {
1661      delete = start = xmprintf("%s%s", arg->v[arg->c = (-arg->c)-1], start);
1662      free(arg->v[arg->c]);
1663      arg->v[arg->c] = 0;
1664
1665    // is a HERE document in progress?
1666    } else if (pl->count != pl->here) {
1667      arg += 1+pl->here;
1668
1669      // Match unquoted EOF.
1670      for (s = line, end = arg->v[arg->c]; *s && *end; s++) {
1671        s += strspn(s, "\\\"'");
1672        if (*s != *end) break;
1673      }
1674      if (!*s && !*end) {
1675        // Add this line
1676        array_add(&arg->v, arg->c++, xstrdup(line));
1677        array_add(&arg->v, arg->c, arg->v[arg->c]);
1678        arg->c++;
1679      // EOF hit, end HERE document
1680      } else {
1681        arg->v[arg->c] = 0;
1682        pl->here++;
1683      }
1684      start = 0;
1685
1686    // Nope, new segment
1687    } else pl = 0;
1688  }
1689
1690  // Parse words, assemble argv[] pipelines, check flow control and HERE docs
1691  if (start) for (;;) {
1692    ex = sp->expect ? sp->expect->prev->data : 0;
1693
1694    // Look for << HERE redirections in completed pipeline segment
1695    if (pl && pl->count == -1) {
1696      pl->count = 0;
1697      arg = pl->arg;
1698
1699if (BUGBUG>1) dprintf(255, "{%d:%s}\n", pl->type, ex ? ex : (sp->expect ? "*" : ""));
1700
1701      // find arguments of the form [{n}]<<[-] with another one after it
1702      for (i = 0; i<arg->c; i++) {
1703        s = arg->v[i] + redir_prefix(arg->v[i]);
1704// TODO <<< is funky
1705// argc[] entries removed from main list? Can have more than one?
1706        if (strcmp(s, "<<") && strcmp(s, "<<-") && strcmp(s, "<<<")) continue;
1707        if (i+1 == arg->c) goto flush;
1708
1709        // Add another arg[] to the pipeline segment (removing/readding to list
1710        // because realloc can move pointer)
1711        dlist_lpop(&sp->pipeline);
1712        pl = xrealloc(pl, sizeof(*pl) + ++pl->count*sizeof(struct sh_arg));
1713        dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl);
1714
1715        // queue up HERE EOF so input loop asks for more lines.
1716        arg[pl->count].v = xzalloc(2*sizeof(void *));
1717        arg[pl->count].v[0] = arg->v[++i];
1718        arg[pl->count].v[1] = 0;
1719        arg[pl->count].c = 0;
1720        if (s[2] == '<') pl->here++; // <<< doesn't load more data
1721      }
1722      pl = 0;
1723    }
1724    if (done) break;
1725    s = 0;
1726
1727    // skip leading whitespace/comment here to know where next word starts
1728    while (isspace(*start)) ++start;
1729    if (*start=='#') while (*start && *start != '\n') ++start;
1730
1731    // Parse next word and detect overflow (too many nested quotes).
1732    if ((end = parse_word(start, 0)) == (void *)1) goto flush;
1733
1734if (BUGBUG>1) dprintf(255, "[%.*s] ", end ? (int)(end-start) : 0, start);
1735    // Is this a new pipeline segment?
1736    if (!pl) {
1737      pl = xzalloc(sizeof(struct sh_pipeline));
1738      arg = pl->arg;
1739      dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl);
1740    }
1741
1742    // Do we need to request another line to finish word (find ending quote)?
1743    if (!end) {
1744      // Save unparsed bit of this line, we'll need to re-parse it.
1745      array_add(&arg->v, arg->c++, xstrndup(start, strlen(start)));
1746      arg->c = -arg->c;
1747      free(delete);
1748
1749      return 1;
1750    }
1751
1752    // Ok, we have a word. What does it _mean_?
1753
1754    // Did we hit end of line or ) outside a function declaration?
1755    // ) is only saved at start of a statement, ends current statement
1756    if (end == start || (arg->c && *start == ')' && pl->type!='f')) {
1757      if (!arg->v) array_add(&arg->v, arg->c, 0);
1758
1759      if (pl->type == 'f' && arg->c<3) {
1760        s = "function()";
1761        goto flush;
1762      }
1763
1764      // "for" on its own line is an error.
1765      if (arg->c == 1 && ex && !memcmp(ex, "do\0A", 4)) {
1766        s = "newline";
1767        goto flush;
1768      }
1769
1770      // don't save blank pipeline segments
1771      if (!arg->c) free_pipeline(dlist_lpop(&sp->pipeline));
1772
1773      // stop at EOL, else continue with new pipeline segment for )
1774      if (end == start) done++;
1775      pl->count = -1;
1776      last = 0;
1777
1778      continue;
1779    }
1780
1781    // Save argument (strdup) and check for flow control
1782    array_add(&arg->v, arg->c, s = xstrndup(start, end-start));
1783    start = end;
1784
1785    if (strchr(";|&", *s) && strncmp(s, "&>", 2)) {
1786
1787      // treat ; as newline so we don't have to check both elsewhere.
1788      if (!strcmp(s, ";")) {
1789        arg->v[arg->c] = 0;
1790        free(s);
1791        s = 0;
1792// TODO enforce only one ; allowed between "for i" and in or do.
1793        if (!arg->c && ex && !memcmp(ex, "do\0C", 4)) continue;
1794
1795      // ;; and friends only allowed in case statements
1796      } else if (*s == ';' && (!ex || strcmp(ex, "esac"))) goto flush;
1797      last = s;
1798
1799      // flow control without a statement is an error
1800      if (!arg->c) goto flush;
1801      pl->count = -1;
1802
1803      continue;
1804    } else arg->v[++arg->c] = 0;
1805
1806    // is a function() in progress?
1807    if (arg->c>1 && !strcmp(s, "(")) pl->type = 'f';
1808    if (pl->type=='f') {
1809      if (arg->c == 2 && strcmp(s, "(")) goto flush;
1810      if (arg->c == 3) {
1811        if (strcmp(s, ")")) goto flush;
1812
1813        // end function segment, expect function body
1814        pl->count = -1;
1815        last = 0;
1816        dlist_add(&sp->expect, "}");
1817        dlist_add(&sp->expect, 0);
1818        dlist_add(&sp->expect, "{");
1819
1820        continue;
1821      }
1822
1823    // a for/select must have at least one additional argument on same line
1824    } else if (ex && !memcmp(ex, "do\0A", 4)) {
1825
1826      // Sanity check and break the segment
1827      if (strncmp(s, "((", 2) && strchr(s, '=')) goto flush;
1828      pl->count = -1;
1829      sp->expect->prev->data = "do\0C";
1830
1831      continue;
1832
1833    // flow control is the first word of a pipeline segment
1834    } else if (arg->c>1) continue;
1835
1836    // Do we expect something that _must_ come next? (no multiple statements)
1837    if (ex) {
1838      // When waiting for { it must be next symbol, but can be on a new line.
1839      if (!strcmp(ex, "{")) {
1840        if (strcmp(s, "{")) goto flush;
1841        free(arg->v[--arg->c]);  // don't save the {, function starts the block
1842        free(dlist_lpop(&sp->expect));
1843
1844        continue;
1845
1846      // The "test" part of for/select loops can have (at most) one "in" line,
1847      // for {((;;))|name [in...]} do
1848      } else if (!memcmp(ex, "do\0C", 4)) {
1849        if (strcmp(s, "do")) {
1850          // can only have one "in" line between for/do, but not with for(())
1851          if (pl->prev->type == 's') goto flush;
1852          if (!strncmp(pl->prev->arg->v[1], "((", 2)) goto flush;
1853          else if (strcmp(s, "in")) goto flush;
1854          pl->type = 's';
1855
1856          continue;
1857        }
1858      }
1859    }
1860
1861    // start of a new block?
1862
1863    // for/select requires variable name on same line, can't break segment yet
1864    if (!strcmp(s, "for") || !strcmp(s, "select")) {
1865      if (!pl->type) pl->type = 1;
1866      dlist_add(&sp->expect, "do\0A");
1867
1868      continue;
1869    }
1870
1871    end = 0;
1872    if (!strcmp(s, "if")) end = "then";
1873    else if (!strcmp(s, "while") || !strcmp(s, "until")) end = "do\0B";
1874    else if (!strcmp(s, "case")) end = "esac";
1875    else if (!strcmp(s, "{")) end = "}";
1876    else if (!strcmp(s, "[[")) end = "]]";
1877    else if (!strcmp(s, "(")) end = ")";
1878
1879    // Expecting NULL means a statement: I.E. any otherwise unrecognized word
1880    if (!ex && sp->expect) free(dlist_lpop(&sp->expect));
1881
1882    // Did we start a new statement
1883    if (end) {
1884      pl->type = 1;
1885
1886      // Only innermost statement needed in { { { echo ;} ;} ;} and such
1887      if (sp->expect && !sp->expect->prev->data) free(dlist_lpop(&sp->expect));
1888
1889    // if can't end a statement here skip next few tests
1890    } else if (!ex);
1891
1892    // If we got here we expect a specific word to end this block: is this it?
1893    else if (!strcmp(s, ex)) {
1894      // can't "if | then" or "while && do", only ; & or newline works
1895      if (last && (strcmp(ex, "then") || strcmp(last, "&"))) {
1896        s = end;
1897        goto flush;
1898      }
1899
1900      free(dlist_lpop(&sp->expect));
1901      pl->type = anystr(s, tails) ? 3 : 2;
1902
1903      // if it's a multipart block, what comes next?
1904      if (!strcmp(s, "do")) end = "done";
1905      else if (!strcmp(s, "then")) end = "fi\0A";
1906
1907    // fi could have elif, which queues a then.
1908    } else if (!strcmp(ex, "fi")) {
1909      if (!strcmp(s, "elif")) {
1910        free(dlist_lpop(&sp->expect));
1911        end = "then";
1912      // catch duplicate else while we're here
1913      } else if (!strcmp(s, "else")) {
1914        if (ex[3] != 'A') {
1915          s = "2 else";
1916          goto flush;
1917        }
1918        free(dlist_lpop(&sp->expect));
1919        end = "fi\0B";
1920      }
1921    }
1922
1923    // Queue up the next thing to expect, all preceded by a statement
1924    if (end) {
1925      if (!pl->type) pl->type = 2;
1926
1927      dlist_add(&sp->expect, end);
1928      if (!anystr(end, tails)) dlist_add(&sp->expect, 0);
1929      pl->count = -1;
1930    }
1931
1932    // syntax error check: these can't be the first word in an unexpected place
1933    if (!pl->type && anystr(s, (char *[]){"then", "do", "esac", "}", "]]", ")",
1934        "done", "fi", "elif", "else", 0})) goto flush;
1935  }
1936  free(delete);
1937
1938  // ignore blank and comment lines
1939  if (!sp->pipeline) return 0;
1940
1941// TODO <<< has no parsing impact, why play with it here at all?
1942  // advance past <<< arguments (stored as here documents, but no new input)
1943  pl = sp->pipeline->prev;
1944  while (pl->count<pl->here && pl->arg[pl->count].c<0)
1945    pl->arg[pl->count++].c = 0;
1946
1947  // return if HERE document pending or more flow control needed to complete
1948  if (sp->expect) return 1;
1949  if (sp->pipeline && pl->count != pl->here) return 1;
1950  if (pl->arg->v[pl->arg->c]) return 1;
1951
1952  // Don't need more input, can start executing.
1953
1954  dlist_terminate(sp->pipeline);
1955  return 0;
1956
1957flush:
1958  if (s) syntax_err(s);
1959  free_function(sp);
1960
1961  return 0-!!s;
1962}
1963
1964/* Flow control statements:
1965
1966  if/then/elif/else/fi, for select while until/do/done, case/esac,
1967  {/}, [[/]], (/), function assignment
1968*/
1969
1970
1971// wait for every process in a pipeline to end
1972static int wait_pipeline(struct sh_process *pp)
1973{
1974  int rc = 0;
1975
1976  for (dlist_terminate(pp); pp; pp = pp->next) {
1977    if (pp->pid) {
1978      // TODO job control: not xwait, handle EINTR ourselves and check signals
1979      pp->exit = xwaitpid(pp->pid);
1980      pp->pid = 0;
1981    }
1982    // TODO handle set -o pipefail here
1983    rc = pp->not ? !pp->exit : pp->exit;
1984  }
1985
1986  return rc;
1987}
1988
1989// pipe data into and out of this segment, I.E. handle leading and trailing |
1990static int pipe_segments(char *ctl, int *pipes, int **urd)
1991{
1992  unredirect(*urd);
1993  *urd = 0;
1994
1995  // Did the previous pipe segment pipe input into us?
1996  if (*pipes != -1) {
1997    if (save_redirect(urd, *pipes, 0)) return 1;
1998    close(*pipes);
1999    *pipes = -1;
2000  }
2001
2002  // are we piping output to the next segment?
2003  if (ctl && *ctl == '|' && ctl[1] != '|') {
2004    if (pipe(pipes)) {
2005      perror_msg("pipe");
2006// TODO record pipeline rc
2007// TODO check did not reach end of pipeline after loop
2008      return 1;
2009    }
2010    if (save_redirect(urd, pipes[1], 1)) {
2011      close(pipes[0]);
2012      close(pipes[1]);
2013
2014      return 1;
2015    }
2016    if (pipes[1] != 1) close(pipes[1]);
2017    fcntl(*pipes, F_SETFD, FD_CLOEXEC);
2018    if (ctl[1] == '&') save_redirect(urd, 1, 2);
2019  }
2020
2021  return 0;
2022}
2023
2024// Handle && and || traversal in pipeline segments
2025static struct sh_pipeline *skip_andor(int rc, struct sh_pipeline *pl)
2026{
2027  char *ctl = pl->arg->v[pl->arg->c];
2028
2029  // For && and || skip pipeline segment(s) based on return code
2030  while (ctl && ((!strcmp(ctl, "&&") && rc) || (!strcmp(ctl, "||") && !rc))) {
2031    if (!pl->next || pl->next->type == 2 || pl->next->type == 3) break;
2032    pl = pl->type ? block_end(pl) : pl->next;
2033    ctl = pl ? pl->arg->v[pl->arg->c] : 0;
2034  }
2035
2036  return pl;
2037}
2038
2039struct blockstack {
2040  struct blockstack *next;
2041  struct sh_pipeline *start, *end;
2042  struct sh_process *pin;      // processes piping into this block
2043  int run, loop, *urd, pout;
2044  struct sh_arg farg;          // for/select arg stack
2045  struct arg_list *fdelete; // farg's cleanup list
2046  char *fvar;                  // for/select's iteration variable name
2047};
2048
2049// when ending a block, free, cleanup redirects and pop stack.
2050static struct sh_pipeline *pop_block(struct blockstack **blist, int *pout)
2051{
2052  struct blockstack *blk = *blist;
2053  struct sh_pipeline *pl = blk->end;
2054
2055  // when ending a block, free, cleanup redirects and pop stack.
2056  if (*pout != -1) close(*pout);
2057  *pout = blk->pout;
2058  unredirect(blk->urd);
2059  llist_traverse(blk->fdelete, free);
2060  free(llist_pop(blist));
2061
2062  return pl;
2063}
2064
2065// run a parsed shell function. Handle flow control blocks and characters,
2066// setup pipes and block redirection, break/continue, call builtins,
2067// vfork/exec external commands.
2068static void run_function(struct sh_pipeline *pl)
2069{
2070  struct sh_pipeline *end;
2071  struct blockstack *blk = 0, *new;
2072  struct sh_process *pplist = 0; // processes piping into current level
2073  int *urd = 0, pipes[2] = {-1, -1};
2074  long i;
2075
2076// TODO can't free sh_process delete until ready to dispose else no debug output
2077
2078  TT.hfd = 10;
2079
2080  // iterate through pipeline segments
2081  while (pl) {
2082    struct sh_arg *arg = pl->arg;
2083    char *s = *arg->v, *ss = arg->v[1], *ctl = arg->v[arg->c];
2084if (BUGBUG) dprintf(255, "%d runtype=%d %s %s\n", getpid(), pl->type, s, ctl);
2085    // Is this an executable segment?
2086    if (!pl->type) {
2087
2088      // Skip disabled block
2089      if (blk && !blk->run) {
2090        pl = pl->next;
2091        continue;
2092      }
2093      if (pipe_segments(ctl, pipes, &urd)) break;
2094
2095      // If we just started a new pipeline, implicit parentheses (subshell)
2096
2097// TODO: "echo | read i" is backgroundable with ctrl-Z despite read = builtin.
2098//       probably have to inline run_command here to do that? Implicit ()
2099//       also "X=42 | true; echo $X" doesn't get X.
2100
2101      // TODO: bash supports "break &" and "break > file". No idea why.
2102
2103      // Is it a flow control jump? These aren't handled as normal builtins
2104      // because they move *pl to other pipeline segments which is local here.
2105      if (!strcmp(s, "break") || !strcmp(s, "continue")) {
2106
2107        // How many layers to peel off?
2108        i = ss ? atol(ss) : 0;
2109        if (i<1) i = 1;
2110        if (!blk || arg->c>2 || ss[strspn(ss, "0123456789")]) {
2111          syntax_err(s);
2112          break;
2113        }
2114
2115        while (i && blk)
2116          if (!--i && *s == 'c') pl = blk->start;
2117          else pl = pop_block(&blk, pipes);
2118        if (i) {
2119          syntax_err("break outside loop");
2120          break;
2121        }
2122        pl = pl->next;
2123        continue;
2124
2125      // Parse and run next command
2126      } else {
2127
2128// TODO: "echo | read i" is backgroundable with ctrl-Z despite read = builtin.
2129//       probably have to inline run_command here to do that? Implicit ()
2130//       also "X=42 | true; echo $X" doesn't get X.
2131//       I.E. run_subshell() here sometimes? (But when?)
2132
2133        dlist_add_nomalloc((void *)&pplist, (void *)run_command(arg));
2134      }
2135
2136      if (*pipes == -1) {
2137        toys.exitval = wait_pipeline(pplist);
2138        llist_traverse(pplist, free_process);
2139        pplist = 0;
2140        pl = skip_andor(toys.exitval, pl);
2141      }
2142
2143    // Start of flow control block?
2144    } else if (pl->type == 1) {
2145      struct sh_process *pp = 0;
2146      int rc;
2147
2148      // are we entering this block (rather than looping back to it)?
2149      if (!blk || blk->start != pl) {
2150
2151        // If it's a nested block we're not running, skip ahead.
2152        end = block_end(pl->next);
2153        if (blk && !blk->run) {
2154          pl = end;
2155          if (pl) pl = pl->next;
2156          continue;
2157        }
2158
2159        // If previous piped into this block, save context until block end
2160        if (pipe_segments(end->arg->v[end->arg->c], pipes, &urd)) break;
2161
2162        // It's a new block we're running, save context and add it to the stack.
2163        new = xzalloc(sizeof(*blk));
2164        new->next = blk;
2165        blk = new;
2166        blk->start = pl;
2167        blk->end = end;
2168        blk->run = 1;
2169
2170        // save context until block end
2171        blk->pout = *pipes;
2172        blk->urd = urd;
2173        urd = 0;
2174        *pipes = -1;
2175
2176        // Perform redirects listed at end of block
2177        pp = expand_redir(end->arg, 1, blk->urd);
2178        blk->urd = pp->urd;
2179        rc = pp->exit;
2180        if (pp->arg.c) {
2181          syntax_err(*pp->arg.v);
2182          rc = 1;
2183        }
2184        llist_traverse(pp->delete, free);
2185        free(pp);
2186        if (rc) {
2187          toys.exitval = rc;
2188          break;
2189        }
2190      }
2191
2192      // What flow control statement is this?
2193
2194      // {/} if/then/elif/else/fi, while until/do/done - no special handling
2195
2196      // for select/do/done
2197      if (!strcmp(s, "for") || !strcmp(s, "select")) {
2198        if (blk->loop);
2199        else if (!strncmp(blk->fvar = ss, "((", 2)) {
2200          blk->loop = 1;
2201dprintf(2, "TODO skipped init for((;;)), need math parser\n");
2202        } else {
2203
2204          // populate blk->farg with expanded arguments
2205          if (pl->next->type == 's') {
2206            for (i = 1; i<pl->next->arg->c; i++)
2207              if (expand_arg(&blk->farg, pl->next->arg->v[i], 0, &blk->fdelete))
2208                break;
2209            if (i != pl->next->arg->c) {
2210              pl = pop_block(&blk, pipes)->next;
2211              continue;
2212            }
2213          // this can't fail
2214          } else expand_arg(&blk->farg, "\"$@\"", 0, &blk->fdelete);
2215        }
2216
2217// TODO case/esac [[/]] ((/)) function/}
2218
2219/*
2220TODO: a | b | c needs subshell for builtins?
2221        - anything that can produce output
2222        - echo declare dirs
2223      (a; b; c) like { } but subshell
2224      when to auto-exec? ps vs sh -c 'ps' vs sh -c '(ps)'
2225*/
2226
2227      // subshell
2228      } else if (!strcmp(s, "(")) {
2229        if (!CFG_TOYBOX_FORK) {
2230          ss = pl2str(pl->next);
2231          pp->pid = run_subshell(ss, strlen(ss));
2232          free(ss);
2233        } else {
2234          if (!(pp->pid = fork())) {
2235            run_function(pl->next);
2236            _exit(toys.exitval);
2237          }
2238        }
2239
2240        dlist_add_nomalloc((void *)&pplist, (void *)pp);
2241        pl = blk->end->prev;
2242      }
2243
2244    // gearshift from block start to block body (end of flow control test)
2245    } else if (pl->type == 2) {
2246
2247      // Handle if statement
2248      if (!strcmp(s, "then")) blk->run = blk->run && !toys.exitval;
2249      else if (!strcmp(s, "else") || !strcmp(s, "elif")) blk->run = !blk->run;
2250      else if (!strcmp(s, "do")) {
2251        ss = *blk->start->arg->v;
2252        if (!strcmp(ss, "while")) blk->run = blk->run && !toys.exitval;
2253        else if (!strcmp(ss, "until")) blk->run = blk->run && toys.exitval;
2254        else if (blk->loop >= blk->farg.c) {
2255          blk->run = 0;
2256          pl = block_end(pl);
2257          continue;
2258        } else if (!strncmp(blk->fvar, "((", 2)) {
2259dprintf(2, "TODO skipped running for((;;)), need math parser\n");
2260        } else setvarval(blk->fvar, blk->farg.v[blk->loop++]);
2261      }
2262
2263    // end of block, may have trailing redirections and/or pipe
2264    } else if (pl->type == 3) {
2265
2266      // if we end a block we're not in, we started in a block.
2267      if (!blk) break;
2268
2269      // repeating block?
2270      if (blk->run && !strcmp(s, "done")) {
2271        pl = blk->start;
2272        continue;
2273      }
2274
2275      pop_block(&blk, pipes);
2276    } else if (pl->type == 'f') pl = add_function(s, pl);
2277
2278    pl = pl->next;
2279  }
2280
2281  // did we exit with unfinished stuff?
2282  // TODO: current context isn't packaged into a block, so can't just pop it
2283  if (*pipes != -1) close(*pipes);
2284  if (pplist) {
2285    toys.exitval = wait_pipeline(pplist);
2286    llist_traverse(pplist, free_process);
2287  }
2288  unredirect(urd);
2289
2290  // Cleanup from syntax_err();
2291  while (blk) pop_block(&blk, pipes);
2292}
2293
2294// Parse and run a self-contained command line with no prompt/continuation
2295static int sh_run(char *new)
2296{
2297  struct sh_function scratch;
2298
2299// TODO switch the fmemopen for -c to use this? Error checking? $(blah)
2300
2301  memset(&scratch, 0, sizeof(struct sh_function));
2302  if (!parse_line(new, &scratch)) run_function(scratch.pipeline);
2303  free_function(&scratch);
2304
2305  return toys.exitval;
2306}
2307
2308// Print prompt to stderr, parsing escapes
2309// Truncated to 4k at the moment, waiting for somebody to complain.
2310static void do_prompt(char *prompt)
2311{
2312  char *s, *ss, c, cc, *pp = toybuf;
2313  int len, ll;
2314
2315  if (!prompt) return;
2316  while ((len = sizeof(toybuf)-(pp-toybuf))>0 && *prompt) {
2317    c = *(prompt++);
2318
2319    if (c=='!') {
2320      if (*prompt=='!') prompt++;
2321      else {
2322        pp += snprintf(pp, len, "%ld", TT.lineno);
2323        continue;
2324      }
2325    } else if (c=='\\') {
2326      cc = *(prompt++);
2327      if (!cc) {
2328        *pp++ = c;
2329        break;
2330      }
2331
2332      // \nnn \dD{}hHjlstT@AuvVwW!#$
2333      // Ignore bash's "nonprintable" hack; query our cursor position instead.
2334      if (cc=='[' || cc==']') continue;
2335      else if (cc=='$') *pp++ = getuid() ? '$' : '#';
2336      else if (cc=='h' || cc=='H') {
2337        *pp = 0;
2338        gethostname(pp, len);
2339        pp[len-1] = 0;
2340        if (cc=='h' && (s = strchr(pp, '.'))) *s = 0;
2341        pp += strlen(pp);
2342      } else if (cc=='s') {
2343        s = getbasename(*toys.argv);
2344        while (*s && len--) *pp++ = *s++;
2345      } else if (cc=='w') {
2346        if ((s = getvar("PWD"))) {
2347          if ((ss = getvar("HOME")) && strstart(&s, ss)) {
2348            *pp++ = '~';
2349            if (--len && *s!='/') *pp++ = '/';
2350            len--;
2351          }
2352          if (len>0) {
2353            ll = strlen(s);
2354            pp = stpncpy(pp, s, ll>len ? len : ll);
2355          }
2356        }
2357      } else if (!(c = unescape(cc))) {
2358        *pp++ = '\\';
2359        if (--len) *pp++ = c;
2360      } else *pp++ = c;
2361    } else *pp++ = c;
2362  }
2363  len = pp-toybuf;
2364  if (len>=sizeof(toybuf)) len = sizeof(toybuf);
2365  writeall(2, toybuf, len);
2366}
2367
2368// only set local variable when global not present, does not extend array
2369static struct sh_vars *initlocal(char *name, char *val)
2370{
2371  return addvar(xmprintf("%s=%s", name, val ? val : ""));
2372}
2373
2374static struct sh_vars *initlocaldef(char *name, char *val, char *def)
2375{
2376  return initlocal(name, (!val || !*val) ? def : val);
2377}
2378
2379// export existing "name" or assign/export name=value string (making new copy)
2380static void export(char *str)
2381{
2382  struct sh_vars *shv = 0;
2383  char *s;
2384
2385  // Make sure variable exists and is updated
2386  if (strchr(str, '=')) shv = setvar(xstrdup(str));
2387  else if (!(shv = findvar(str))) shv = addvar(str = xmprintf("%s=", str));
2388  if (!shv || (shv->flags&VAR_GLOBAL)) return;
2389
2390  // Resolve local magic for export
2391  if (shv->flags&VAR_MAGIC) {
2392    s = shv->str;
2393    shv->str = xmprintf("%.*s=%s", (int)(varend(str)-str), str, getvar(str));
2394    free(s);
2395  }
2396
2397  xsetenv(shv->str, 0);
2398  shv->flags |= VAR_GLOBAL;
2399}
2400
2401static void unexport(char *str)
2402{
2403  struct sh_vars *shv = findvar(str);
2404
2405  if (shv) {
2406    if (shv->flags&VAR_GLOBAL) shv->str = xpop_env(str);
2407    shv->flags &=~VAR_GLOBAL;
2408  }
2409  if (strchr(str, '=')) setvar(str);
2410}
2411
2412// init locals, sanitize environment, handle nommu subshell handoff
2413static void subshell_setup(void)
2414{
2415  int ii, to, from, pid, ppid, zpid, myppid = getppid(), len, uid = getuid();
2416  struct passwd *pw = getpwuid(uid);
2417  char *s, *ss, *magic[] = {"SECONDS","RANDOM","LINENO","GROUPS"},
2418    *readonly[] = {xmprintf("EUID=%d", geteuid()), xmprintf("UID=%d", uid),
2419                   xmprintf("PPID=%d", myppid)};
2420  struct stat st;
2421  struct utsname uu;
2422  FILE *fp;
2423
2424  // Initialize magic and read only local variables
2425  srandom(TT.SECONDS = millitime());
2426  for (ii = 0; ii<ARRAY_LEN(magic); ii++)
2427    initlocal(magic[ii], "")->flags = VAR_MAGIC|(VAR_INT*('G'!=*magic[ii]));
2428  for (ii = 0; ii<ARRAY_LEN(readonly); ii++)
2429    addvar(readonly[ii])->flags = VAR_READONLY|VAR_INT;
2430
2431  // Add local variables that can be overwritten
2432  initlocal("PATH", _PATH_DEFPATH);
2433  if (!pw) pw = (void *)toybuf; // first use, so still zeroed
2434  sprintf(toybuf+1024, "%u", uid);
2435  initlocaldef("HOME", pw->pw_dir, "/");
2436  initlocaldef("SHELL", pw->pw_shell, "/bin/sh");
2437  initlocaldef("USER", pw->pw_name, toybuf+1024);
2438  initlocaldef("LOGNAME", pw->pw_name, toybuf+1024);
2439  gethostname(toybuf, sizeof(toybuf)-1);
2440  initlocal("HOSTNAME", toybuf);
2441  uname(&uu);
2442  initlocal("HOSTTYPE", uu.machine);
2443  sprintf(toybuf, "%s-unknown-linux", uu.machine);
2444  initlocal("MACHTYPE", toybuf);
2445  initlocal("OSTYPE", uu.sysname);
2446  // sprintf(toybuf, "%s-toybox", TOYBOX_VERSION);
2447  // initlocal("BASH_VERSION", toybuf);
2448  initlocal("OPTERR", "1"); // TODO: test if already exported?
2449  if (readlink0("/proc/self/exe", s = toybuf, sizeof(toybuf))||(s=getenv("_")))
2450    initlocal("BASH", s);
2451  initlocal("PS2", "> ");
2452
2453  // Ensure environ copied and toys.envc set, and clean out illegal entries
2454  TT.ifs = " \t\n";
2455  xsetenv("", 0);
2456  for (to = from = pid = ppid = zpid = 0; (s = environ[from]); from++) {
2457
2458    // If nommu subshell gets handoff
2459    if (!CFG_TOYBOX_FORK && !toys.stacktop) {
2460      len = 0;
2461      sscanf(s, "@%d,%d%n", &pid, &ppid, &len);
2462      if (s[len]) pid = ppid = 0;
2463      if (*s == '$' && s[1] == '=') zpid = atoi(s+2);
2464// TODO marshall $- to subshell like $$
2465    }
2466
2467    // Filter out non-shell variable names from inherited environ.
2468    // (haven't xsetenv() yet so no need to free() or adjust toys.envc)
2469    ss = varend(s);
2470    if (*ss == '=') {
2471      struct sh_vars *shv = findvar(s);
2472
2473      if (!shv) addvar(environ[from])->flags = VAR_GLOBAL;
2474      else if (shv->flags&VAR_READONLY) continue;
2475      else {
2476        shv->flags |= VAR_GLOBAL;
2477        free(shv->str);
2478        shv->str = s;
2479      }
2480      environ[to++] = s;
2481    }
2482    if (!memcmp(s, "IFS=", 4)) TT.ifs = s+4;
2483  }
2484  environ[toys.optc = to] = 0;
2485
2486  // set/update PWD
2487  sh_run("cd .");
2488
2489  // set _ to path to this shell
2490  s = toys.argv[0];
2491  ss = 0;
2492  if (!strchr(s, '/')) {
2493    if ((ss = getcwd(0, 0))) {
2494      s = xmprintf("%s/%s", ss, s);
2495      free(ss);
2496      ss = s;
2497    } else if (*toybuf) s = toybuf;
2498  }
2499  s = xsetenv("_", s);
2500  if (!findvar(s)) addvar(s)->flags = VAR_GLOBAL;
2501  free(ss);
2502  if (!(ss = getvar("SHLVL"))) export("SHLVL=1");
2503  else {
2504    char buf[16];
2505
2506    sprintf(buf, "%u", atoi(ss+6)+1);
2507    xsetenv("SHLVL", buf);
2508    export("SHLVL");
2509  }
2510
2511//TODO indexed array,associative array,integer,local,nameref,readonly,uppercase
2512//          if (s+1<ss && strchr("aAilnru", *s)) {
2513
2514  // sanity check: magic env variable, pipe status
2515  if (CFG_TOYBOX_FORK || toys.stacktop || pid!=getpid() || ppid!=myppid) return;
2516  if (fstat(254, &st) || !S_ISFIFO(st.st_mode)) error_exit(0);
2517  TT.pid = zpid;
2518  fcntl(254, F_SETFD, FD_CLOEXEC);
2519  fp = fdopen(254, "r");
2520
2521  // This is not efficient, could array_add the local vars.
2522// TODO implicit exec when possible
2523  while ((s = xgetline(fp, 0))) toys.exitval = sh_run(s);
2524  fclose(fp);
2525
2526  xexit();
2527}
2528
2529void sh_main(void)
2530{
2531  char *new, *cc = TT.sh.c;
2532  struct sh_function scratch;
2533  int prompt = 0;
2534  struct string_list *sl = 0;
2535  struct sh_arg arg;
2536  FILE *f;
2537
2538  signal(SIGPIPE, SIG_IGN);
2539  TT.options = OPT_BRACE;
2540
2541  TT.pid = getpid();
2542  TT.SECONDS = time(0);
2543  TT.arg = &arg;
2544  if (!(arg.c = toys.optc)) {
2545    arg.v = xmalloc(2*sizeof(char *));
2546    arg.v[arg.c++] = *toys.argv;
2547    arg.v[arg.c] = 0;
2548  } else memcpy(arg.v = xmalloc((arg.c+1)*sizeof(char *)), toys.optargs,
2549      (arg.c+1)*sizeof(char *));
2550
2551  // TODO euid stuff?
2552  // TODO login shell?
2553  // TODO read profile, read rc
2554
2555  // if (!FLAG(noprofile)) { }
2556
2557if (BUGBUG) { int fd = open("/dev/tty", O_RDWR); if (fd == -1) fd = open("/dev/console", O_RDWR); if (fd == -1) dup2(2, 255); else dup2(fd, 255); close(fd); }
2558
2559  // Is this an interactive shell?
2560  if (FLAG(s) || (!FLAG(c) && !toys.optc)) TT.options |= OPT_S;
2561  if (FLAG(i) || (!FLAG(c) && (TT.options&OPT_S) && isatty(0)))
2562    TT.options |= OPT_I;
2563  if (FLAG(c)) TT.options |= OPT_C;
2564
2565  // Read environment for exports from parent shell. Note, calls run_sh()
2566  // which blanks argument sections of TT and this, so parse everything
2567  // we need from shell command line before that.
2568  subshell_setup();
2569  if (TT.options&OPT_I) {
2570    if (!getvar("PS1")) setvarval("PS1", getpid() ? "\\$ " : "# ");
2571    // TODO Set up signal handlers and grab control of this tty.
2572    // ^C SIGINT ^\ SIGQUIT ^Z SIGTSTP SIGTTIN SIGTTOU SIGCHLD
2573    // setsid(), setpgid(), tcsetpgrp()...
2574    xsignal(SIGINT, SIG_IGN);
2575  }
2576
2577  memset(&scratch, 0, sizeof(scratch));
2578
2579// TODO unify fmemopen() here with sh_run
2580  if (cc) f = fmemopen(cc, strlen(cc), "r");
2581  else if (TT.options&OPT_S) f = stdin;
2582// TODO: syntax_err should exit from shell scripts
2583  else if (!(f = fopen(*toys.optargs, "r"))) {
2584    char *pp = getvar("PATH") ? : _PATH_DEFPATH;
2585
2586    for (sl = find_in_path(pp, *toys.optargs); sl; free(llist_pop(&sl)))
2587      if ((f = fopen(sl->str, "r"))) break;
2588    if (sl) llist_traverse(sl->next, free);
2589    else perror_exit_raw(*toys.optargs);
2590  }
2591
2592  // Loop prompting and reading lines
2593  for (;;) {
2594    TT.lineno++;
2595    if ((TT.options&(OPT_I|OPT_S|OPT_C)) == (OPT_I|OPT_S))
2596      do_prompt(getvar(prompt ? "PS2" : "PS1"));
2597
2598// TODO line editing/history, should set $COLUMNS $LINES and sigwinch update
2599    if (!(new = xgetline(f, 0))) {
2600// TODO: after first EINTR getline returns always closed?
2601      if (errno != EINTR) break;
2602      free_function(&scratch);
2603      prompt = 0;
2604      if (f != stdin) break;
2605      continue;
2606// TODO: ctrl-z during script read having already read partial line,
2607// SIGSTOP and SIGTSTP need need SA_RESTART, but child proc should stop
2608    }
2609
2610if (BUGBUG) dprintf(255, "line=%s\n", new);
2611    if (sl) {
2612      if (*new == 0x7f) error_exit("'%s' is ELF", sl->str);
2613      free(sl);
2614      sl = 0;
2615    }
2616// TODO if (!isspace(*new)) add_to_history(line);
2617
2618    // returns 0 if line consumed, command if it needs more data
2619    prompt = parse_line(new, &scratch);
2620if (BUGBUG) dump_state(&scratch);
2621    if (prompt != 1) {
2622// TODO: ./blah.sh one two three: put one two three in scratch.arg
2623      if (!prompt) run_function(scratch.pipeline);
2624      free_function(&scratch);
2625      prompt = 0;
2626    }
2627    free(new);
2628  }
2629
2630  if (prompt) error_exit("%ld:unfinished line"+4*!TT.lineno, TT.lineno);
2631}
2632
2633/********************* shell builtin functions *************************/
2634
2635#define CLEANUP_sh
2636#define FOR_cd
2637#include "generated/flags.h"
2638void cd_main(void)
2639{
2640  char *home = getvar("HOME") ? : "/", *pwd = getvar("PWD"), *from, *to = 0,
2641    *dd = xstrdup(*toys.optargs ? *toys.optargs : home);
2642  int bad = 0;
2643
2644  // TODO: CDPATH? Really?
2645
2646  // prepend cwd or $PWD to relative path
2647  if (*dd != '/') {
2648    from = pwd ? : (to = getcwd(0, 0));
2649    if (!from) setvarval("PWD", "(nowhere)");
2650    else {
2651      from = xmprintf("%s/%s", from, dd);
2652      free(dd);
2653      free(to);
2654      dd = from;
2655    }
2656  }
2657
2658  if (FLAG(P)) {
2659    struct stat st;
2660    char *pp;
2661
2662    // Does this directory exist?
2663    if ((pp = xabspath(dd, 1)) && stat(pp, &st) && !S_ISDIR(st.st_mode))
2664      bad++, errno = ENOTDIR;
2665    else {
2666      free(dd);
2667      dd = pp;
2668    }
2669  } else {
2670
2671    // cancel out . and .. in the string
2672    for (from = to = dd; *from;) {
2673      if (*from=='/' && from[1]=='/') from++;
2674      else if (*from!='/' || from[1]!='.') *to++ = *from++;
2675      else if (!from[2] || from[2]=='/') from += 2;
2676      else if (from[2]=='.' && (!from[3] || from[3]=='/')) {
2677        from += 3;
2678        while (to>dd && *--to != '/');
2679      } else *to++ = *from++;
2680    }
2681    if (to == dd) to++;
2682    if (to-dd>1 && to[-1]=='/') to--;
2683    *to = 0;
2684  }
2685
2686  if (bad || chdir(dd)) perror_msg("chdir '%s'", dd);
2687  else {
2688    if (pwd) {
2689      setvarval("OLDPWD", pwd);
2690      if (TT.cdcount == 1) {
2691        export("OLDPWD");
2692        TT.cdcount++;
2693      }
2694    }
2695    setvarval("PWD", dd);
2696    if (!TT.cdcount) {
2697      export("PWD");
2698      TT.cdcount++;
2699    }
2700  }
2701  free(dd);
2702}
2703
2704void exit_main(void)
2705{
2706  exit(*toys.optargs ? atoi(*toys.optargs) : 0);
2707}
2708
2709void unset_main(void)
2710{
2711  char **arg, *s;
2712
2713  for (arg = toys.optargs; *arg; arg++) {
2714    s = varend(*arg);
2715    if (s == *arg || *s) {
2716      error_msg("bad '%s'", *arg);
2717      continue;
2718    }
2719
2720    // unset magic variable?
2721    if (!strcmp(*arg, "IFS")) TT.ifs = " \t\n";
2722    unsetvar(*arg);
2723  }
2724}
2725
2726#define CLEANUP_cd
2727#define FOR_export
2728#include "generated/flags.h"
2729
2730void export_main(void)
2731{
2732  char **arg, *eq;
2733
2734  // list existing variables?
2735  if (!toys.optc) {
2736    for (arg = environ; *arg; arg++) xprintf("declare -x %s\n", *arg);
2737    return;
2738  }
2739
2740  // set/move variables
2741  for (arg = toys.optargs; *arg; arg++) {
2742    eq = varend(*arg);
2743    if (eq == *arg || (*eq && *eq != '=')) {
2744      error_msg("bad %s", *arg);
2745      continue;
2746    }
2747
2748    if (FLAG(n)) unexport(*arg);
2749    else export(*arg);
2750  }
2751}
2752
2753void eval_main(void)
2754{
2755  struct sh_arg *old = TT.arg, new = {toys.argv, toys.optc+1};
2756  char *s;
2757
2758  TT.arg = &new;
2759  s = expand_one_arg("\"$*\"", SEMI_IFS, 0);
2760  TT.arg = old;
2761  sh_run(s);
2762  free(s);
2763}
2764
2765#define CLEANUP_export
2766#define FOR_exec
2767#include "generated/flags.h"
2768
2769void exec_main(void)
2770{
2771  char *ee[1] = {0}, **old = environ;
2772
2773  // discard redirects and return if nothing to exec
2774  free(TT.pp->urd);
2775  TT.pp->urd = 0;
2776  if (!toys.optc) return;
2777
2778  // exec, handling -acl
2779  TT.isexec = *toys.optargs;
2780  if (FLAG(c)) environ = ee;
2781  if (TT.exec.a || FLAG(l))
2782    *toys.optargs = xmprintf("%s%s", FLAG(l) ? "-" : "", TT.exec.a?:TT.isexec);
2783  sh_exec(toys.optargs);
2784
2785  // report error (usually ENOENT) and return
2786  perror_msg("%s", TT.isexec);
2787  TT.isexec = 0;
2788  toys.exitval = 127;
2789  environ = old;
2790}
2791
2792void shift_main(void)
2793{
2794  long long by = 1;
2795
2796  if (toys.optc) by = atolx(*toys.optargs);
2797  by += TT.shift;
2798  if (by<0 || by>= TT.arg->c) toys.exitval++;
2799  else TT.shift = by;
2800}
2801