• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * deviations from posix: don't care about $LANG or $LC_ALL
13  * deviations from bash:
14  *   redirect+expansion in one pass so we can't report errors between them.
15  *   Trailing redirects error at runtime, not parse time.
16 
17  * builtins: alias bg command fc fg getopts jobs newgrp read umask unalias wait
18  *          disown suspend source pushd popd dirs logout times trap cd hash exit
19  *           unset local export readonly set : . let history declare ulimit type
20  * "special" builtins: break continue eval exec return shift
21  * external with extra shell behavior: kill pwd time test
22 
23  * * ? [ # ~ = % [[ ]] function select exit label:
24 
25  * TODO: case, wildcard +(*|?), job control (find_plus_minus), ${x//}, $(())
26 
27  * TODO: support case in $() because $(case a in a) ;; ; esac) stops at first )
28  * TODO: test exit from "trap EXIT" doesn't recurse
29  * TODO: ! history expansion
30  * TODO: getuid() vs geteuid()
31  * TODO: test that $PS1 color changes work without stupid \[ \] hack
32  * TODO: Handle embedded NUL bytes in the command line? (When/how?)
33  * TODO: set -e -u -o pipefail, shopt -s nullglob
34  *
35  * bash man page:
36  * control operators || & && ; ;; ;& ;;& ( ) | |& <newline>
37  * reserved words
38  *   ! case  coproc  do done elif else esac fi for  function  if  in  select
39  *   then until while { } time [[ ]]
40  *
41  * Flow control statements:
42  *
43  * if/then/elif/else/fi, for select while until/do/done, case/esac,
44  * {/}, [[/]], (/), function assignment
45 
46 USE_SH(NEWTOY(cd, ">1LP[-LP]", TOYFLAG_NOFORK))
47 USE_SH(NEWTOY(declare, "pAailunxr", TOYFLAG_NOFORK))
48  // TODO tpgfF
49 USE_SH(NEWTOY(eval, 0, TOYFLAG_NOFORK))
50 USE_SH(NEWTOY(exec, "^cla:", TOYFLAG_NOFORK))
51 USE_SH(NEWTOY(exit, 0, TOYFLAG_NOFORK))
52 USE_SH(NEWTOY(export, "np", TOYFLAG_NOFORK))
53 USE_SH(NEWTOY(jobs, "lnprs", TOYFLAG_NOFORK))
54 USE_SH(NEWTOY(set, 0, TOYFLAG_NOFORK))
55 USE_SH(NEWTOY(shift, ">1", TOYFLAG_NOFORK))
56 USE_SH(NEWTOY(source, "<1", TOYFLAG_NOFORK))
57 USE_SH(OLDTOY(., source, TOYFLAG_NOFORK))
58 USE_SH(NEWTOY(unset, "fvn[!fv]", TOYFLAG_NOFORK))
59 USE_SH(NEWTOY(wait, "n", TOYFLAG_NOFORK))
60 
61 USE_SH(NEWTOY(sh, "0(noediting)(noprofile)(norc)sc:i", TOYFLAG_BIN))
62 USE_SH(OLDTOY(toysh, sh, TOYFLAG_BIN))
63 USE_SH(OLDTOY(bash, sh, TOYFLAG_BIN))
64 // Login lies in argv[0], so add some aliases to catch that
65 USE_SH(OLDTOY(-sh, sh, 0))
66 USE_SH(OLDTOY(-toysh, sh, 0))
67 USE_SH(OLDTOY(-bash, sh, 0))
68 
69 config SH
70   bool "sh (toysh)"
71   default n
72   help
73     usage: sh [-c command] [script]
74 
75     Command shell.  Runs a shell script, or reads input interactively
76     and responds to it. Roughly compatible with "bash". Run "help" for
77     list of built-in commands.
78 
79     -c	command line to execute
80     -i	interactive mode (default when STDIN is a tty)
81     -s	don't run script (args set $* parameters but read commands from stdin)
82 
83     Command shells parse each line of input (prompting when interactive), perform
84     variable expansion and redirection, execute commands (spawning child processes
85     and background jobs), and perform flow control based on the return code.
86 
87     Parsing:
88       syntax errors
89 
90     Interactive prompts:
91       line continuation
92 
93     Variable expansion:
94       Note: can cause syntax errors at runtime
95 
96     Redirection:
97       HERE documents (parsing)
98       Pipelines (flow control and job control)
99 
100     Running commands:
101       process state
102       builtins
103         cd [[ ]] (( ))
104         ! : [ # TODO: help for these?
105         true false help echo kill printf pwd test
106       child processes
107 
108     Job control:
109       &    Background process
110       Ctrl-C kill process
111       Ctrl-Z suspend process
112       bg fg jobs kill
113 
114     Flow control:
115     ;    End statement (same as newline)
116     &    Background process (returns true unless syntax error)
117     &&   If this fails, next command fails without running
118     ||   If this succeeds, next command succeeds without running
119     |    Pipelines! (Can of worms...)
120     for {name [in...]}|((;;)) do; BODY; done
121     if TEST; then BODY; fi
122     while TEST; do BODY; done
123     case a in X);; esac
124     [[ TEST ]]
125     ((MATH))
126 
127     Job control:
128     &    Background process
129     Ctrl-C kill process
130     Ctrl-Z suspend process
131     bg fg jobs kill
132 
133 # These are here for the help text, they're not selectable and control nothing
134 config CD
135   bool
136   default n
137   depends on SH
138   help
139     usage: cd [-PL] [-] [path]
140 
141     Change current directory. With no arguments, go $HOME. Sets $OLDPWD to
142     previous directory: cd - to return to $OLDPWD.
143 
144     -P	Physical path: resolve symlinks in path
145     -L	Local path: .. trims directories off $PWD (default)
146 
147 config DECLARE
148   bool
149   default n
150   depends on SH
151   help
152     usage: declare [-pAailunxr] [NAME...]
153 
154     Set or print variable attributes and values.
155 
156     -p	Print variables instead of setting
157     -A	Associative array
158     -a	Indexed array
159     -i	Integer
160     -l	Lower case
161     -n	Name reference (symlink)
162     -r	Readonly
163     -u	Uppercase
164     -x	Export
165 
166 config EXIT
167   bool
168   default n
169   depends on SH
170   help
171     usage: exit [status]
172 
173     Exit shell.  If no return value supplied on command line, use value
174     of most recent command, or 0 if none.
175 
176 config SET
177   bool
178   default n
179   depends on SH
180   help
181     usage: set [+a] [+o OPTION] [VAR...]
182 
183     Set variables and shell attributes. Use + to disable and - to enable.
184     NAME=VALUE arguments assign to the variable, any leftovers set $1, $2...
185     With no arguments, prints current variables.
186 
187     -f	NAME is a function
188     -v	NAME is a variable
189     -n	don't follow name reference
190 
191     OPTIONs:
192       history - enable command history
193 
194 config UNSET
195   bool
196   default n
197   depends on SH
198   help
199     usage: unset [-fvn] NAME...
200 
201     -f	NAME is a function
202     -v	NAME is a variable
203     -n	dereference NAME and unset that
204 
205 config EVAL
206   bool
207   default n
208   depends on SH
209   help
210     usage: eval COMMAND...
211 
212     Execute (combined) arguments as a shell command.
213 
214 config EXEC
215   bool
216   default n
217   depends on SH
218   help
219     usage: exec [-cl] [-a NAME] COMMAND...
220 
221     -a	set argv[0] to NAME
222     -c	clear environment
223     -l	prepend - to argv[0]
224 
225 config EXPORT
226   bool
227   default n
228   depends on SH
229   help
230     usage: export [-n] [NAME[=VALUE]...]
231 
232     Make variables available to child processes. NAME exports existing local
233     variable(s), NAME=VALUE sets and exports.
234 
235     -n	Unexport. Turn listed variable(s) into local variables.
236 
237     With no arguments list exported variables/attributes as "declare" statements.
238 
239 config JOBS
240   bool
241   default n
242   depends on SH
243   help
244     usage: jobs [-lnprs] [%JOB | -x COMMAND...]
245 
246     List running/stopped background jobs.
247 
248     -l Include process ID in list
249     -n Show only new/changed processes
250     -p Show process IDs only
251     -r Show running processes
252     -s Show stopped processes
253 
254 config LOCAL
255   bool
256   default n
257   depends on SH
258   help
259     usage: local [NAME[=VALUE]...]
260 
261     Create a local variable that lasts until return from this function.
262     With no arguments lists local variables in current function context.
263     TODO: implement "declare" options.
264 
265 config SHIFT
266   bool
267   default n
268   depends on SH
269   help
270     usage: shift [N]
271 
272     Skip N (default 1) positional parameters, moving $1 and friends along the list.
273     Does not affect $0.
274 
275 config SOURCE
276   bool
277   default n
278   depends on SH
279   help
280     usage: source FILE [ARGS...]
281 
282     Read FILE and execute commands. Any ARGS become positional parameters.
283 
284 config WAIT
285   bool
286   default n
287   depends on SH
288   help
289     usage: wait [-n] [ID...]
290 
291     Wait for background processes to exit, returning its exit code.
292     ID can be PID or job, with no IDs waits for all backgrounded processes.
293 
294     -n	Wait for next process to exit
295 */
296 
297 #define FOR_sh
298 #include "toys.h"
299 
300 GLOBALS(
301   union {
302     struct {
303       char *c;
304     } sh;
305     struct {
306       char *a;
307     } exec;
308   };
309 
310   // keep SECONDS here: used to work around compiler limitation in run_command()
311   long long SECONDS;
312   char *isexec, *wcpat;
313   unsigned options, jobcnt, LINENO;
314   int hfd, pid, bangpid, srclvl, recursion;
315 
316   // Callable function array
317   struct sh_function {
318     char *name;
319     struct sh_pipeline {  // pipeline segments: linked list of arg w/metadata
320       struct sh_pipeline *next, *prev, *end;
321       int count, here, type, lineno;
322       struct sh_arg {
323         char **v;
324         int c;
325       } arg[1];
326     } *pipeline;
327     unsigned long refcount;
328   } **functions;
329   long funcslen;
330 
331   // runtime function call stack
332   struct sh_fcall {
333     struct sh_fcall *next, *prev;
334 
335     // This dlist in reverse order: TT.ff current function, TT.ff->prev globals
336     struct sh_vars {
337       long flags;
338       char *str;
339     } *vars;
340     long varslen, varscap, shift, oldlineno;
341 
342     struct sh_function *func; // TODO wire this up
343     struct sh_pipeline *pl;
344     char *ifs, *omnom;
345     struct sh_arg arg;
346     struct arg_list *delete;
347 
348     // Runtime stack of nested if/else/fi and for/do/done contexts.
349     struct sh_blockstack {
350       struct sh_blockstack *next;
351       struct sh_pipeline *start, *middle;
352       struct sh_process *pp;       // list of processes piping in to us
353       int run, loop, *urd, pout, pipe;
354       struct sh_arg farg;          // for/select arg stack, case wildcard deck
355       struct arg_list *fdelete;    // farg's cleanup list
356       char *fvar;                  // for/select's iteration variable name
357     } *blk;
358   } *ff;
359 
360 // TODO ctrl-Z suspend should stop script
361   struct sh_process {
362     struct sh_process *next, *prev; // | && ||
363     struct arg_list *delete;   // expanded strings
364     // undo redirects, a=b at start, child PID, exit status, has !, job #
365     int *urd, envlen, pid, exit, flags, job, dash;
366     long long when; // when job backgrounded/suspended
367     struct sh_arg *raw, arg;
368   } *pp; // currently running process
369 
370   // job list, command line for $*, scratch space for do_wildcard_files()
371   struct sh_arg jobs, *wcdeck;
372 )
373 
374 // Prototype because $($($(blah))) nests, leading to run->parse->run loop
375 int do_source(char *name, FILE *ff);
376 // functions contain pipelines contain functions: prototype because loop
377 static void free_pipeline(void *pipeline);
378 // recalculate needs to get/set variables, but setvar_found calls recalculate
379 static struct sh_vars *setvar(char *str);
380 
381 // ordered for greedy matching, so >&; becomes >& ; not > &;
382 // making these const means I need to typecast the const away later to
383 // avoid endless warnings.
384 static const char *redirectors[] = {"<<<", "<<-", "<<", "<&", "<>", "<", ">>",
385   ">&", ">|", ">", "&>>", "&>", 0};
386 
387 // The order of these has to match the string in set_main()
388 #define OPT_B	0x100
389 #define OPT_C	0x200
390 #define OPT_x	0x400
391 
392 // only export $PWD and $OLDPWD on first cd
393 #define OPT_cd  0x80000000
394 
395 // struct sh_process->flags
396 #define PFLAG_NOT    1
397 
syntax_err(char * s)398 static void syntax_err(char *s)
399 {
400   struct sh_fcall *ff = TT.ff;
401 // TODO: script@line only for script not interactive.
402   for (ff = TT.ff; ff != TT.ff->prev; ff = ff->next) if (ff->omnom) break;
403   error_msg("syntax error '%s'@%u: %s", ff->omnom ? : "-c", TT.LINENO, s);
404   toys.exitval = 2;
405   if (!(TT.options&FLAG_i)) xexit();
406 }
407 
debug_show_fds()408 void debug_show_fds()
409 {
410   int x = 0, fd = open("/proc/self/fd", O_RDONLY);
411   DIR *X = fdopendir(fd);
412   struct dirent *DE;
413   char *s, *ss = 0, buf[4096], *sss = buf;
414 
415   if (!X) return;
416   for (; (DE = readdir(X));) {
417     if (atoi(DE->d_name) == fd) continue;
418     s = xreadlink(ss = xmprintf("/proc/self/fd/%s", DE->d_name));
419     if (s && *s != '.') sss += sprintf(sss, ", %s=%s"+2*!x++, DE->d_name, s);
420     free(s); free(ss);
421   }
422   *sss = 0;
423   dprintf(2, "%d fd:%s\n", getpid(), buf);
424   closedir(X);
425 }
426 
nospace(char ** ss)427 static char **nospace(char **ss)
428 {
429   while (isspace(**ss)) ++*ss;
430 
431   return ss;
432 }
433 
434 // append to array with null terminator and realloc as necessary
arg_add(struct sh_arg * arg,char * data)435 static void arg_add(struct sh_arg *arg, char *data)
436 {
437   // expand with stride 32. Micro-optimization: don't realloc empty stack
438   if (!(arg->c&31) && (arg->c || !arg->v))
439     arg->v = xrealloc(arg->v, sizeof(char *)*(arg->c+33));
440   arg->v[arg->c++] = data;
441   arg->v[arg->c] = 0;
442 }
443 
444 // add argument to an arg_list
push_arg(struct arg_list ** list,void * arg)445 static void *push_arg(struct arg_list **list, void *arg)
446 {
447   struct arg_list *al;
448 
449   if (list) {
450     al = xmalloc(sizeof(struct arg_list));
451     al->next = *list;
452     al->arg = arg;
453     *list = al;
454   }
455 
456   return arg;
457 }
458 
arg_add_del(struct sh_arg * arg,char * data,struct arg_list ** delete)459 static void arg_add_del(struct sh_arg *arg, char *data,struct arg_list **delete)
460 {
461   arg_add(arg, push_arg(delete, data));
462 }
463 
464 // Assign one variable from malloced key=val string, returns var struct
465 // TODO implement remaining types
466 #define VAR_NOFREE    (1<<10)
467 #define VAR_WHITEOUT  (1<<9)
468 #define VAR_DICT      (1<<8)
469 #define VAR_ARRAY     (1<<7)
470 #define VAR_INT       (1<<6)
471 #define VAR_TOLOWER   (1<<5)
472 #define VAR_TOUPPER   (1<<4)
473 #define VAR_NAMEREF   (1<<3)
474 #define VAR_EXPORT    (1<<2)
475 #define VAR_READONLY  (1<<1)
476 #define VAR_MAGIC     (1<<0)
477 
478 // return length of valid variable name
varend(char * s)479 static char *varend(char *s)
480 {
481   if (isdigit(*s)) return s;
482   while (*s>' ' && (*s=='_' || !ispunct(*s))) s++;
483 
484   return s;
485 }
486 
487 // TODO: this has to handle VAR_NAMEREF, but return dangling symlink
488 // Also, unset -n, also "local ISLINK" to parent var.
489 // Return sh_vars * or 0 if not found.
490 // Sets *pff to function (only if found), only returns whiteouts if pff not NULL
findvar(char * name,struct sh_fcall ** pff)491 static struct sh_vars *findvar(char *name, struct sh_fcall **pff)
492 {
493   int len = varend(name)-name;
494   struct sh_fcall *ff = TT.ff;
495 
496   // advance through locals to global context, ignoring whiteouts
497   if (len) do {
498     struct sh_vars *var = ff->vars+ff->varslen;
499 
500     if (var) while (var--!=ff->vars) {
501       if (strncmp(var->str, name, len) || var->str[len]!='=') continue;
502       if (pff) *pff = ff;
503       else if (var->flags&VAR_WHITEOUT) return 0;
504 
505       return var;
506     }
507   } while ((ff = ff->next)!=TT.ff);
508 
509   return 0;
510 }
511 
512 // get value of variable starting at s.
getvar(char * s)513 static char *getvar(char *s)
514 {
515   struct sh_vars *var = findvar(s, 0);
516 
517   if (!var) return 0;
518 
519   if (var->flags & VAR_MAGIC) {
520     char c = *var->str;
521 
522     if (c == 'S') sprintf(toybuf, "%lld", (millitime()-TT.SECONDS)/1000);
523     else if (c == 'R') sprintf(toybuf, "%ld", random()&((1<<16)-1));
524     else if (c == 'L') sprintf(toybuf, "%u", TT.ff->pl->lineno);
525     else if (c == 'G') sprintf(toybuf, "TODO: GROUPS");
526     else if (c == 'B') sprintf(toybuf, "%d", getpid());
527     else if (c == 'E') {
528       struct timespec ts;
529 
530       clock_gettime(CLOCK_REALTIME, &ts);
531       sprintf(toybuf, "%lld%c%06ld", (long long)ts.tv_sec, (s[5]=='R')*'.',
532               ts.tv_nsec/1000);
533     }
534 
535     return toybuf;
536   }
537 
538   return varend(var->str)+1;
539 }
540 
541 // Append variable to ff->vars, returning *struct. Does not check duplicates.
addvar(char * s,struct sh_fcall * ff)542 static struct sh_vars *addvar(char *s, struct sh_fcall *ff)
543 {
544   if (ff->varslen == ff->varscap && !(ff->varslen&31)) {
545     ff->varscap += 32;
546     ff->vars = xrealloc(ff->vars, (ff->varscap)*sizeof(*ff->vars));
547   }
548   if (!s) return ff->vars;
549   ff->vars[ff->varslen].flags = 0;
550   ff->vars[ff->varslen].str = s;
551 
552   return ff->vars+ff->varslen++;
553 }
554 
555 // Recursively calculate string into dd, returns 0 if failed, ss = error point
556 // Recursion resolves operators of lower priority level to a value
557 // Loops through operators at same priority
558 #define NO_ASSIGN 128
recalculate(long long * dd,char ** ss,int lvl)559 static int recalculate(long long *dd, char **ss, int lvl)
560 {
561   long long ee, ff;
562   char *var = 0, *val, cc = **nospace(ss);
563   int ii, noa = lvl&NO_ASSIGN;
564   lvl &= NO_ASSIGN-1;
565 
566   // Unary prefixes can only occur at the start of a parse context
567   if (cc=='!' || cc=='~') {
568     ++*ss;
569     if (!recalculate(dd, ss, noa|15)) return 0;
570     *dd = (cc=='!') ? !*dd : ~*dd;
571   } else if (cc=='+' || cc=='-') {
572     // Is this actually preincrement/decrement? (Requires assignable var.)
573     if (*++*ss==cc) {
574       val = (*ss)++;
575       nospace(ss);
576       if (*ss==(var = varend(*ss))) {
577         *ss = val;
578         var = 0;
579       }
580     }
581     if (!var) {
582       if (!recalculate(dd, ss, noa|15)) return 0;
583       if (cc=='-') *dd = -*dd;
584     }
585   } else if (cc=='(') {
586     ++*ss;
587     if (!recalculate(dd, ss, noa|1)) return 0;
588     if (**ss!=')') return 0;
589     else ++*ss;
590   } else if (isdigit(cc)) {
591     *dd = strtoll(*ss, ss, 0);
592     if (**ss=='#') {
593       if (!*++*ss || isspace(**ss) || ispunct(**ss)) return 0;
594       *dd = strtoll(val = *ss, ss, *dd);
595       if (val == *ss) return 0;
596     }
597   } else if ((var = varend(*ss))==*ss) {
598     // At lvl 0 "" is ok, anything higher needs a non-empty equation
599     if (lvl || (cc && cc!=')')) return 0;
600     *dd = 0;
601 
602     return 1;
603   }
604 
605   // If we got a variable, evaluate its contents to set *dd
606   if (var) {
607     // Recursively evaluate, catching x=y; y=x; echo $((x))
608     if (TT.recursion++ == 50+200*CFG_TOYBOX_FORK) {
609       perror_msg("recursive occlusion");
610       --TT.recursion;
611 
612       return 0;
613     }
614     val = getvar(var = *ss) ? : "";
615     ii = recalculate(dd, &val, noa);
616     TT.recursion--;
617     if (!ii) return 0;
618     if (*val) {
619       perror_msg("bad math: %s @ %d", var, (int)(val-var));
620 
621       return 0;
622     }
623     val = *ss = varend(var);
624 
625     // Operators that assign to a varible must be adjacent to one:
626 
627     // Handle preincrement/predecrement (only gets here if var set before else)
628     if (cc=='+' || cc=='-') {
629       if (cc=='+') ee = ++*dd;
630       else ee = --*dd;
631     } else cc = 0;
632 
633     // handle postinc/postdec
634     if ((**nospace(ss)=='+' || **ss=='-') && (*ss)[1]==**ss) {
635       ee = ((cc = **ss)=='+') ? 1+*dd : -1+*dd;
636       *ss += 2;
637 
638     // Assignment operators: = *= /= %= += -= <<= >>= &= ^= |=
639     } else if (lvl<=2 && (*ss)[ii = (-1 != stridx("*/%+-", **ss))
640                +2*!smemcmp(*ss, "<<", 2)+2*!smemcmp(*ss, ">>", 2)]=='=')
641     {
642       // TODO: assignments are lower priority BUT must go after variable,
643       // come up with precedence checking tests?
644       cc = **ss;
645       *ss += ii+1;
646       if (!recalculate(&ee, ss, noa|1)) return 0; // TODO lvl instead of 1?
647       if (cc=='*') *dd *= ee;
648       else if (cc=='+') *dd += ee;
649       else if (cc=='-') *dd -= ee;
650       else if (cc=='<') *dd <<= ee;
651       else if (cc=='>') *dd >>= ee;
652       else if (cc=='&') *dd &= ee;
653       else if (cc=='^') *dd ^= ee;
654       else if (cc=='|') *dd |= ee;
655       else if (!cc) *dd = ee;
656       else if (!ee) {
657         perror_msg("%c0", cc);
658 
659         return 0;
660       } else if (cc=='/') *dd /= ee;
661       else if (cc=='%') *dd %= ee;
662       ee = *dd;
663     }
664     if (cc && !noa) setvar(xmprintf("%.*s=%lld", (int)(val-var), var, ee));
665   }
666 
667   // x**y binds first
668   if (lvl<=14) while (strstart(nospace(ss), "**")) {
669     if (!recalculate(&ee, ss, noa|15)) return 0;
670     if (ee<0) perror_msg("** < 0");
671     for (ff = *dd, *dd = 1; ee; ee--) *dd *= ff;
672   }
673 
674   // w*x/y%z bind next
675   if (lvl<=13) while ((cc = **nospace(ss)) && strchr("*/%", cc)) {
676     ++*ss;
677     if (!recalculate(&ee, ss, noa|14)) return 0;
678     if (cc=='*') *dd *= ee;
679     else if (!ee) {
680       perror_msg("%c0", cc);
681 
682       return 0;
683     } else if (cc=='%') *dd %= ee;
684     else *dd /= ee;
685   }
686 
687   // x+y-z
688   if (lvl<=12) while ((cc = **nospace(ss)) && strchr("+-", cc)) {
689     ++*ss;
690     if (!recalculate(&ee, ss, noa|13)) return 0;
691     if (cc=='+') *dd += ee;
692     else *dd -= ee;
693   }
694 
695   // x<<y >>
696 
697   if (lvl<=11) while ((cc = **nospace(ss)) && strchr("<>", cc) && cc==(*ss)[1]){
698     *ss += 2;
699     if (!recalculate(&ee, ss, noa|12)) return 0;
700     if (cc == '<') *dd <<= ee;
701     else *dd >>= ee;
702   }
703 
704   // x<y <= > >=
705   if (lvl<=10) while ((cc = **nospace(ss)) && strchr("<>", cc)) {
706     if ((ii = *++*ss=='=')) ++*ss;
707     if (!recalculate(&ee, ss, noa|11)) return 0;
708     if (cc=='<') *dd = ii ? (*dd<=ee) : (*dd<ee);
709     else *dd = ii ? (*dd>=ee) : (*dd>ee);
710   }
711 
712   if (lvl<=9) while ((cc = **nospace(ss)) && strchr("=!", cc) && (*ss)[1]=='='){
713     *ss += 2;
714     if (!recalculate(&ee, ss, noa|10)) return 0;
715     *dd = (cc=='!') ? *dd != ee : *dd == ee;
716   }
717 
718   if (lvl<=8) while (**nospace(ss)=='&' && (*ss)[1]!='&') {
719     ++*ss;
720     if (!recalculate(&ee, ss, noa|9)) return 0;
721     *dd &= ee;
722   }
723 
724   if (lvl<=7) while (**nospace(ss)=='^') {
725     ++*ss;
726     if (!recalculate(&ee, ss, noa|8)) return 0;
727     *dd ^= ee;
728   }
729 
730   if (lvl<=6) while (**nospace(ss)=='|' && (*ss)[1]!='|') {
731     ++*ss;
732     if (!recalculate(&ee, ss, noa|7)) return 0;
733     *dd |= ee;
734   }
735 
736   if (lvl<=5) while (strstart(nospace(ss), "&&")) {
737     if (!recalculate(&ee, ss, noa|6|NO_ASSIGN*!*dd)) return 0;
738     *dd = *dd && ee;
739   }
740 
741   if (lvl<=4) while (strstart(nospace(ss), "||")) {
742     if (!recalculate(&ee, ss, noa|5|NO_ASSIGN*!!*dd)) return 0;
743     *dd = *dd || ee;
744   }
745 
746   // ? : slightly weird: recurses with lower priority instead of looping
747   // because a ? b ? c : d ? e : f : g == a ? (b ? c : (d ? e : f) : g)
748   if (lvl<=3) if (**nospace(ss)=='?') {
749     ++*ss;
750     if (**nospace(ss)==':' && *dd) ee = *dd;
751     else if (!recalculate(&ee, ss, noa|1|NO_ASSIGN*!*dd) || **nospace(ss)!=':')
752       return 0;
753     ++*ss;
754     if (!recalculate(&ff, ss, noa|1|NO_ASSIGN*!!*dd)) return 0;
755     *dd = *dd ? ee : ff;
756   }
757 
758   // lvl<=2 assignment would go here, but handled above because variable
759 
760   // , (slightly weird, replaces dd instead of modifying it via ee/ff)
761   if (lvl<=1) while (**nospace(ss)==',') {
762     ++*ss;
763     if (!recalculate(dd, ss, noa|2)) return 0;
764   }
765 
766   return 1;
767 }
768 
769 // Return length of utf8 char @s fitting in len, writing value into *cc
getutf8(char * s,int len,int * cc)770 static int getutf8(char *s, int len, int *cc)
771 {
772   unsigned wc;
773 
774   if (len<0) wc = len = 0;
775   else if (1>(len = utf8towc(&wc, s, len))) wc = *s, len = 1;
776   if (cc) *cc = wc;
777 
778   return len;
779 }
780 
781 // utf8 strchr: return wide char matched at wc from chrs, or 0 if not matched
782 // if len, save length of next wc (whether or not it's in list)
utf8chr(char * wc,char * chrs,int * len)783 static int utf8chr(char *wc, char *chrs, int *len)
784 {
785   unsigned wc1, wc2;
786   int ll;
787 
788   if (len) *len = 1;
789   if (!*wc) return 0;
790   if (0<(ll = utf8towc(&wc1, wc, 99))) {
791     if (len) *len = ll;
792     while (*chrs) {
793       if(1>(ll = utf8towc(&wc2, chrs, 99))) chrs++;
794       else {
795         if (wc1 == wc2) return wc1;
796         chrs += ll;
797       }
798     }
799   }
800 
801   return 0;
802 }
803 
804 // return length of match found at this point (try is null terminated array)
anystart(char * s,char ** try)805 static int anystart(char *s, char **try)
806 {
807   char *ss = s;
808 
809   while (*try) if (strstart(&s, *try++)) return s-ss;
810 
811   return 0;
812 }
813 
814 // does this entire string match one of the strings in try[]
anystr(char * s,char ** try)815 static int anystr(char *s, char **try)
816 {
817   while (*try) if (!strcmp(s, *try++)) return 1;
818 
819   return 0;
820 }
821 
822 // Update $IFS cache in function call stack after variable assignment
cache_ifs(char * s,struct sh_fcall * ff)823 static void cache_ifs(char *s, struct sh_fcall *ff)
824 {
825   if (!strncmp(s, "IFS=", 4))
826     do ff->ifs = s+4; while ((ff = ff->next) != TT.ff->prev);
827 }
828 
829 // declare -aAilnrux
830 // ft
831 // TODO VAR_ARRAY VAR_DICT
832 
833 // Assign new name=value string for existing variable. s takes x=y or x+=y
setvar_found(char * s,int freeable,struct sh_vars * var)834 static struct sh_vars *setvar_found(char *s, int freeable, struct sh_vars *var)
835 {
836   char *ss, *sss, *sd, buf[24];
837   long ii, jj, kk, flags = var->flags&~VAR_WHITEOUT;
838   long long ll;
839   int cc, vlen = varend(s)-s;
840 
841   if (flags&VAR_READONLY) {
842     error_msg("%.*s: read only", vlen, s);
843     goto bad;
844   }
845 
846   // If += has no old value (addvar placeholder or empty old var) yank the +
847   if (s[vlen]=='+' && (var->str==s || !strchr(var->str, '=')[1])) {
848     ss = xmprintf("%.*s%s", vlen, s, s+vlen+1);
849     if (var->str==s) {
850       if (!freeable++) var->flags |= VAR_NOFREE;
851     } else if (freeable++) free(s);
852     s = ss;
853   }
854 
855   // Handle VAR_NAMEREF mismatch by replacing name
856   if (strncmp(var->str, s, vlen)) {
857     ss = s+vlen+(s[vlen]=='+')+1;
858     ss = xmprintf("%.*s%s", (vlen = varend(var->str)-var->str)+1, var->str, ss);
859     if (freeable++) free(s);
860     s = ss;
861   }
862 
863   // utf8 aware case conversion, two pass (measure, allocate, convert) because
864   // unicode IS stupid enough for upper/lower case to be different utf8 byte
865   // lengths, for example lowercase of U+023a (c8 ba) is U+2c65 (e2 b1 a5)
866   if (flags&(VAR_TOUPPER|VAR_TOLOWER)) {
867     for (jj = kk = 0, sss = 0; jj<2; jj++, sss = sd = xmalloc(vlen+kk+2)) {
868       sd = jj ? stpncpy(sss, s, vlen+1) : (void *)&sss;
869       for (ss = s+vlen+1; (ii = getutf8(ss, 4, &cc)); ss += ii) {
870         kk += wctoutf8(sd, (flags&VAR_TOUPPER) ? towupper(cc) : towlower(cc));
871         if (jj) {
872           sd += kk;
873           kk = 0;
874         }
875       }
876     }
877     *sd = 0;
878     if (freeable++) free(s);
879     s = sss;
880   }
881 
882   // integer variables treat += differently
883   ss = s+vlen+(s[vlen]=='+')+1;
884   if (flags&VAR_INT) {
885     sd = ss;
886     if (!recalculate(&ll, &sd, 0) || *sd) {
887       perror_msg("bad math: %s @ %d", ss, (int)(sd-ss));
888 
889       goto bad;
890     }
891 
892     sprintf(buf, "%lld", ll);
893     if (flags&VAR_MAGIC) {
894       if (*s == 'S') {
895         ll *= 1000;
896         TT.SECONDS = (s[vlen]=='+') ? TT.SECONDS+ll : millitime()-ll;
897       } else if (*s == 'R') srandom(ll);
898       if (freeable) free(s);
899 
900       // magic can't be whiteout or nofree, and keeps old string
901       return var;
902     } else if (s[vlen]=='+' || strcmp(buf, ss)) {
903       if (s[vlen]=='+') ll += atoll(strchr(var->str, '=')+1);
904       ss = xmprintf("%.*s=%lld", vlen, s, ll);
905       if (freeable++) free(s);
906       s = ss;
907     }
908   } else if (s[vlen]=='+' && !(flags&VAR_MAGIC)) {
909     ss = xmprintf("%s%s", var->str, ss);
910     if (freeable++) free(s);
911     s = ss;
912   }
913 
914   // Replace old string with new one, adjusting nofree status
915   if (flags&VAR_NOFREE) flags ^= VAR_NOFREE;
916   else free(var->str);
917   if (!freeable) flags |= VAR_NOFREE;
918   var->str = s;
919   var->flags = flags;
920 
921   return var;
922 bad:
923   if (freeable) free(s);
924 
925   return 0;
926 }
927 
928 // Creates new variables (local or global) and handles +=
929 // returns 0 on error, else sh_vars of new entry.
setvar_long(char * s,int freeable,struct sh_fcall * ff)930 static struct sh_vars *setvar_long(char *s, int freeable, struct sh_fcall *ff)
931 {
932   struct sh_vars *vv = 0, *was;
933   char *ss;
934 
935   if (!s) return 0;
936   ss = varend(s);
937   if (ss[*ss=='+']!='=') {
938     error_msg("bad setvar %s\n", s);
939     if (freeable) free(s);
940 
941     return 0;
942   }
943 
944   // Add if necessary, set value, and remove again if we added but set failed
945   if (!(was = vv = findvar(s, &ff))) (vv = addvar(s, ff))->flags = VAR_NOFREE;
946   if (!setvar_found(s, freeable, vv)) {
947     if (!was) memmove(vv, vv+1, sizeof(ff->vars)*(--ff->varslen-(vv-ff->vars)));
948 
949     return 0;
950   }
951   cache_ifs(vv->str, ff);
952 
953   return vv;
954 }
955 
956 // Set variable via a malloced "name=value" (or "name+=value") string.
957 // Returns sh_vars * or 0 for failure (readonly, etc)
setvar(char * str)958 static struct sh_vars *setvar(char *str)
959 {
960   return setvar_long(str, 0, TT.ff->prev);
961 }
962 
963 
964 // returns whether variable found (whiteout doesn't count)
unsetvar(char * name)965 static int unsetvar(char *name)
966 {
967   struct sh_fcall *ff;
968   struct sh_vars *var = findvar(name, &ff);
969   int len = varend(name)-name;
970 
971   if (!var || (var->flags&VAR_WHITEOUT)) return 0;
972   if (var->flags&VAR_READONLY) error_msg("readonly %.*s", len, name);
973   else {
974     // turn local into whiteout
975     if (ff != TT.ff->prev) {
976       var->flags = VAR_WHITEOUT;
977       if (!(var->flags&VAR_NOFREE))
978         (var->str = xrealloc(var->str, len+2))[len+1] = 0;
979     // free from global context
980     } else {
981       if (!(var->flags&VAR_NOFREE)) free(var->str);
982       memmove(var, var+1, sizeof(ff->vars)*(ff->varslen-(var-ff->vars)));
983     }
984     if (!strcmp(name, "IFS"))
985       do ff->ifs = " \t\n"; while ((ff = ff->next) != TT.ff->prev);
986   }
987 
988   return 1;
989 }
990 
setvarval(char * name,char * val)991 static struct sh_vars *setvarval(char *name, char *val)
992 {
993   return setvar(xmprintf("%s=%s", name, val));
994 }
995 
996 // TODO: keep variable arrays sorted for binary search
997 
998 // create array of variables visible in current function.
visible_vars(void)999 static struct sh_vars **visible_vars(void)
1000 {
1001   struct sh_arg arg;
1002   struct sh_fcall *ff;
1003   struct sh_vars *vv;
1004   unsigned ii, jj, len;
1005 
1006   arg.c = 0;
1007   arg.v = 0;
1008 
1009   // Find non-duplicate entries: TODO, sort and binary search
1010   for (ff = TT.ff; ; ff = ff->next) {
1011     if (ff->vars) for (ii = ff->varslen; ii--;) {
1012       vv = ff->vars+ii;
1013       len = 1+(varend(vv->str)-vv->str);
1014       for (jj = 0; ;jj++) {
1015         if (jj == arg.c) arg_add(&arg, (void *)vv);
1016         else if (strncmp(arg.v[jj], vv->str, len)) continue;
1017 
1018         break;
1019       }
1020     }
1021     if (ff->next == TT.ff) break;
1022   }
1023 
1024   return (void *)arg.v;
1025 }
1026 
1027 // malloc declare -x "escaped string"
declarep(struct sh_vars * var)1028 static char *declarep(struct sh_vars *var)
1029 {
1030   char *types = "rxnuliaA", *esc = "$\"\\`", *in, flags[16], *out = flags, *ss;
1031   int len;
1032 
1033   for (len = 0; types[len]; len++) if (var->flags&(2<<len)) *out++ = types[len];
1034   if (out==flags) *out++ = '-';
1035   *out = 0;
1036   len = out-flags;
1037 
1038   for (in = var->str; *in; in++) len += !!strchr(esc, *in);
1039   len += in-var->str;
1040   ss = xmalloc(len+15);
1041 
1042   len = varend(var->str)-var->str;
1043   out = ss + sprintf(ss, "declare -%s %.*s", flags, len, var->str);
1044   if (var->flags != VAR_MAGIC)  {
1045     out = stpcpy(out, "=\"");
1046     for (in = var->str+len+1; *in; *out++ = *in++)
1047       if (strchr(esc, *in)) *out++ = '\\';
1048     *out++ = '"';
1049   }
1050   *out = 0;
1051 
1052   return ss;
1053 }
1054 
1055 // Skip past valid prefix that could go before redirect
skip_redir_prefix(char * word)1056 static char *skip_redir_prefix(char *word)
1057 {
1058   char *s = word;
1059 
1060   if (*s == '{') {
1061     if (*(s = varend(s+1)) == '}' && s != word+1) s++;
1062     else s = word;
1063   } else while (isdigit(*s)) s++;
1064 
1065   return s;
1066 }
1067 
1068 // parse next word from command line. Returns end, or 0 if need continuation
1069 // caller eats leading spaces. early = skip one quote block (or return start)
1070 // quote is depth of existing quote stack in toybuf (usually 0)
parse_word(char * start,int early,int quote)1071 static char *parse_word(char *start, int early, int quote)
1072 {
1073   int ii, qq, qc = 0;
1074   char *end = start, *ss;
1075 
1076   // Handle redirections, <(), (( )) that only count at the start of word
1077   ss = skip_redir_prefix(end); // 123<<file- parses as 2 args: "123<<" "file-"
1078   if (strstart(&ss, "<(") || strstart(&ss, ">(")) {
1079     toybuf[quote++]=')';
1080     end = ss;
1081   } else if ((ii = anystart(ss, (void *)redirectors))) return ss+ii;
1082   if (strstart(&end, "((")) toybuf[quote++] = 254;
1083 
1084   // Loop to find end of this word
1085   while (*end) {
1086     // If we're stopping early and already handled a symbol...
1087     if (early && end!=start && !quote) break;
1088 
1089     // barf if we're near overloading quote stack (nesting ridiculously deep)
1090     if (quote>4000) {
1091       syntax_err("bad quote depth");
1092       return (void *)1;
1093     }
1094 
1095     // Are we in a quote context?
1096     if ((qq = quote ? toybuf[quote-1] : 0)) {
1097       ii = *end++;
1098       if ((qq==')' || qq>=254) && (ii=='(' || ii==')')) { // parentheses nest
1099         if (ii=='(') qc++;
1100         else if (qc) qc--;
1101         else if (qq>=254) {
1102           // (( can end with )) or retroactively become two (( if we hit one )
1103           if (ii==')' && *end==')') quote--, end++;
1104           else if (qq==254) return start+1;
1105           else if (qq==255) toybuf[quote-1] = ')';
1106         } else if (ii==')') quote--;
1107       } else if (ii==qq) quote--;        // matching end quote
1108       else if (qq!='\'') end--, ii = 0;  // single quote claims everything
1109       if (ii) continue;                  // fall through for other quote types
1110 
1111     // space and flow control chars only end word when not quoted in any way
1112     } else {
1113       if (isspace(*end)) break;
1114       ss = end + anystart(end, (char *[]){";;&", ";;", ";&", ";", "||",
1115         "|&", "|", "&&", "&", "(", ")", 0});
1116       if (ss!=end) return (end==start) ? ss : end;
1117     }
1118 
1119     // start new quote context? (' not special within ")
1120     if (strchr("'\"`"+(qq=='"'), ii = *end++)) toybuf[quote++] = ii;
1121 
1122     // \? $() ${} $[] ?() *() +() @() !()
1123     else {
1124       if (ii=='\\') { // TODO why end[1] here? sh -c $'abc\\\ndef' Add test.
1125         if (!*end || (*end=='\n' && !end[1])) return early ? end : 0;
1126       } else if (ii=='$' && -1!=(qq = stridx("({[", *end))) {
1127         if (strstart(&end, "((")) {
1128           end--;
1129           toybuf[quote++] = 255;
1130         } else toybuf[quote++] = ")}]"[qq];
1131       } else if (*end=='(' && strchr("?*+@!", ii)) toybuf[quote++] = ')';
1132       else {
1133         end--;
1134         if (early && !quote) return end;
1135       }
1136       end++;
1137     }
1138   }
1139 
1140   return (quote && !early) ? 0 : end;
1141 }
1142 
1143 // Return next available high (>=10) file descriptor
next_hfd()1144 static int next_hfd()
1145 {
1146   int hfd;
1147 
1148   for (; TT.hfd<=99999; TT.hfd++) if (-1 == fcntl(TT.hfd, F_GETFL)) break;
1149   hfd = TT.hfd;
1150   if (TT.hfd>99999) {
1151     hfd = -1;
1152     if (!errno) errno = EMFILE;
1153   }
1154 
1155   return hfd;
1156 }
1157 
1158 // Perform a redirect, saving displaced filehandle to a high (>10) fd
1159 // rd is an int array: [0] = count, followed by from/to pairs to restore later.
1160 // If from >= 0 dup from->to after saving to. If from == -1 just save to.
1161 // if from == -2 schedule "to" to be closed by unredirect.
save_redirect(int ** rd,int from,int to)1162 static int save_redirect(int **rd, int from, int to)
1163 {
1164   int cnt, hfd, *rr;
1165 
1166 //dprintf(2, "%d redir %d to %d\n", getpid(), from, to);
1167   if (from == to) return 0;
1168   // save displaced to, copying to high (>=10) file descriptor to undo later
1169   // except if we're saving to environment variable instead (don't undo that)
1170   if (from>-2) {
1171     if ((hfd = next_hfd())==-1) return 1;
1172     if (hfd != dup2(to, hfd)) hfd = -1;
1173     else fcntl(hfd, F_SETFD, FD_CLOEXEC);
1174 
1175     // dup "to"
1176     if (from >= 0 && to != dup2(from, to)) {
1177       if (hfd >= 0) close(hfd);
1178 
1179       return 1;
1180     }
1181   } else {
1182     hfd = to;
1183     to = -1;
1184   }
1185 
1186   // Append undo information to redirect list so we can restore saved hfd later.
1187   if (!((cnt = *rd ? **rd : 0)&31)) *rd = xrealloc(*rd, (cnt+33)*2*sizeof(int));
1188   *(rr = *rd) = ++cnt;
1189   rr[2*cnt-1] = hfd;
1190   rr[2*cnt] = to;
1191 
1192   return 0;
1193 }
1194 
1195 // restore displaced filehandles, closing high filehandles they were copied to
unredirect(int * urd)1196 static void unredirect(int *urd)
1197 {
1198   int *rr = urd+1, i;
1199 
1200   if (!urd) return;
1201 
1202   for (i = 0; i<*urd; i++, rr += 2) if (rr[0] != -1) {
1203     // No idea what to do about fd exhaustion here, so Steinbach's Guideline.
1204     dup2(rr[0], rr[1]);
1205     close(rr[0]);
1206   }
1207   free(urd);
1208 }
1209 
1210 // TODO: waitpid(WNOHANG) to clean up zombies and catch background& ending
subshell_callback(char ** argv)1211 static void subshell_callback(char **argv)
1212 {
1213   // This depends on environ having been replaced by caller
1214   environ[1] = xmprintf("@%d,%d", getpid(), getppid());
1215   environ[2] = xmprintf("$=%d", TT.pid);
1216 // TODO: test $$ in (nommu)
1217 }
1218 
1219 // TODO what happens when you background a function?
1220 // turn a parsed pipeline back into a string.
pl2str(struct sh_pipeline * pl,int one)1221 static char *pl2str(struct sh_pipeline *pl, int one)
1222 {
1223   struct sh_pipeline *end = 0, *pp;
1224   int len QUIET, i;
1225   char *ss;
1226 
1227   // Find end of block (or one argument)
1228   if (one) end = pl->next;
1229   else for (end = pl, len = 0; end; end = end->next)
1230     if (end->type == 1) len++;
1231     else if (end->type == 3 && --len<0) break;
1232 
1233   // measure, then allocate
1234   for (ss = 0;; ss = xmalloc(len+1)) {
1235     for (pp = pl; pp != end; pp = pp->next) {
1236       if (pp->type == 'F') continue; // TODO fix this
1237       for (i = len = 0; i<=pp->arg->c; i++)
1238         len += snprintf(ss+len, ss ? INT_MAX : 0, " %s"+!i,
1239            pp->arg->v[i] ? : ";"+(pp->next==end));
1240     }
1241     if (ss) return ss;
1242   }
1243 
1244 // TODO test output with case and function
1245 // TODO add HERE documents back in
1246 // TODO handle functions
1247 }
1248 
clear_block(struct sh_blockstack * blk)1249 static struct sh_blockstack *clear_block(struct sh_blockstack *blk)
1250 {
1251   memset(blk, 0, sizeof(*blk));
1252   blk->start = TT.ff->pl;
1253   blk->run = 1;
1254   blk->pout = -1;
1255 
1256   return blk;
1257 }
1258 
1259 // when ending a block, free, cleanup redirects and pop stack.
pop_block(void)1260 static struct sh_pipeline *pop_block(void)
1261 {
1262   struct sh_pipeline *pl = 0;
1263   struct sh_blockstack *blk = TT.ff->blk;
1264 
1265   // when ending a block, free, cleanup redirects and pop stack.
1266   if (blk->pout != -1) close(blk->pout);
1267   unredirect(blk->urd);
1268   llist_traverse(blk->fdelete, llist_free_arg);
1269   free(blk->farg.v);
1270   if (TT.ff->blk->next) {
1271     pl = blk->start->end;
1272     free(llist_pop(&TT.ff->blk));
1273   } else clear_block(blk);
1274 
1275   return pl;
1276 }
1277 
1278 // Push a new empty block to the stack
add_block(void)1279 static void add_block(void)
1280 {
1281   struct sh_blockstack *blk = clear_block(xmalloc(sizeof(*blk)));
1282 
1283   blk->next = TT.ff->blk;
1284   TT.ff->blk = blk;
1285 }
1286 
1287 // Add entry to runtime function call stack
call_function(void)1288 static void call_function(void)
1289 {
1290   // dlist in reverse order: TT.ff = current function, TT.ff->prev = globals
1291   dlist_add_nomalloc((void *)&TT.ff, xzalloc(sizeof(struct sh_fcall)));
1292   TT.ff = TT.ff->prev;
1293   add_block();
1294 
1295 // TODO caller needs to set pl, vars, func
1296   // default $* is to copy previous
1297   TT.ff->arg.v = TT.ff->next->arg.v;
1298   TT.ff->arg.c = TT.ff->next->arg.c;
1299   TT.ff->ifs = TT.ff->next->ifs;
1300 }
1301 
free_function(struct sh_function * funky)1302 static void free_function(struct sh_function *funky)
1303 {
1304   if (--funky->refcount) return;
1305 
1306   free(funky->name);
1307   llist_traverse(funky->pipeline, free_pipeline);
1308   free(funky);
1309 }
1310 
1311 // TODO: old function-vs-source definition is "has variables", but no ff->func?
1312 // returns 0 if source popped, nonzero if function popped
end_function(int funconly)1313 static int end_function(int funconly)
1314 {
1315   struct sh_fcall *ff = TT.ff;
1316   int func = ff->next!=ff && ff->vars;
1317 
1318   if (!func && funconly) return 0;
1319   llist_traverse(ff->delete, llist_free_arg);
1320   ff->delete = 0;
1321   while (TT.ff->blk->next) pop_block();
1322   pop_block();
1323 
1324   // for a function, free variables and pop context
1325   if (!func) return 0;
1326   while (ff->varslen)
1327     if (!(ff->vars[--ff->varslen].flags&VAR_NOFREE))
1328       free(ff->vars[ff->varslen].str);
1329   free(ff->vars);
1330   free(TT.ff->blk);
1331   if (ff->func) free_function(ff->func);
1332   free(dlist_pop(&TT.ff));
1333 
1334   return 1;
1335 }
1336 
1337 // TODO check every caller of run_subshell for error, or syntax_error() here
1338 // from pipe() failure
1339 
1340 // TODO need CLOFORK? CLOEXEC doesn't help if we don't exec...
1341 
1342 // Pass environment and command string to child shell, return PID of child
run_subshell(char * str,int len)1343 static int run_subshell(char *str, int len)
1344 {
1345   pid_t pid;
1346 //dprintf(2, "%d run_subshell %.*s\n", getpid(), len, str); debug_show_fds();
1347   // The with-mmu path is significantly faster.
1348   if (CFG_TOYBOX_FORK) {
1349     if ((pid = fork())<0) perror_msg("fork");
1350     else if (!pid) {
1351       call_function();
1352       if (str) {
1353         do_source(0, fmemopen(str, len, "r"));
1354         _exit(toys.exitval);
1355       }
1356     }
1357 
1358   // On nommu vfork, exec /proc/self/exe, and pipe state data to ourselves.
1359   } else {
1360     int pipes[2];
1361     unsigned i;
1362     char **oldenv = environ, *ss = str ? : pl2str(TT.ff->pl->next, 0);
1363     struct sh_vars **vv;
1364 
1365     // open pipe to child
1366     if (pipe(pipes) || 254 != dup2(pipes[0], 254)) return 1;
1367     close(pipes[0]);
1368     fcntl(pipes[1], F_SETFD, FD_CLOEXEC);
1369 
1370     // vfork child with clean environment
1371     environ = xzalloc(4*sizeof(char *));
1372     *environ = getvar("PATH") ? : "PATH=";
1373     pid = xpopen_setup(0, 0, subshell_callback);
1374 // TODO what if pid -1? Handle process exhaustion.
1375     // free entries added to end of environment by callback (shared heap)
1376     free(environ[1]);
1377     free(environ[2]);
1378     free(environ);
1379     environ = oldenv;
1380 
1381     // marshall context to child
1382     close(254);
1383     dprintf(pipes[1], "%lld %u %u %u %u\n", TT.SECONDS,
1384       TT.options, TT.LINENO, TT.pid, TT.bangpid);
1385 
1386     for (i = 0, vv = visible_vars(); vv[i]; i++)
1387       dprintf(pipes[1], "%u %lu\n%.*s", (unsigned)strlen(vv[i]->str),
1388               vv[i]->flags, (int)strlen(vv[i]->str), vv[i]->str);
1389     free(vv);
1390 
1391     // send command
1392     dprintf(pipes[1], "0 0\n%.*s\n", len, ss);
1393     if (!str) free(ss);
1394     close(pipes[1]);
1395   }
1396 
1397   return pid;
1398 }
1399 
1400 // Call subshell with either stdin/stdout redirected, return other end of pipe
pipe_subshell(char * s,int len,int out)1401 static int pipe_subshell(char *s, int len, int out)
1402 {
1403   int pipes[2], *uu = 0, in = !out;
1404 
1405   // Grab subshell data
1406   if (pipe(pipes)) {
1407     perror_msg("%.*s", len, s);
1408 
1409     return -1;
1410   }
1411 
1412   // Perform input or output redirect and launch process (ignoring errors)
1413   save_redirect(&uu, pipes[in], in);
1414   close(pipes[in]);
1415   fcntl(pipes[!in], F_SETFD, FD_CLOEXEC);
1416   run_subshell(s, len);
1417   fcntl(pipes[!in], F_SETFD, 0);
1418   unredirect(uu);
1419 
1420   return pipes[out];
1421 }
1422 
1423 // grab variable or special param (ala $$) up to len bytes. Return value.
1424 // set *used to length consumed. Does not handle $* and $@
getvar_special(char * str,int len,int * used,struct arg_list ** delete)1425 char *getvar_special(char *str, int len, int *used, struct arg_list **delete)
1426 {
1427   char *s = 0, *ss, cc = *str;
1428   unsigned uu;
1429 
1430   *used = 1;
1431   if (cc == '-') {
1432     s = ss = xmalloc(8);
1433     if (TT.options&FLAG_i) *ss++ = 'i';
1434     if (TT.options&OPT_B) *ss++ = 'B';
1435     if (TT.options&FLAG_s) *ss++ = 's';
1436     if (TT.options&FLAG_c) *ss++ = 'c';
1437     *ss = 0;
1438   } else if (cc == '?') s = xmprintf("%d", toys.exitval);
1439   else if (cc == '$') s = xmprintf("%d", TT.pid);
1440   else if (cc == '#') s = xmprintf("%d", TT.ff->arg.c ? TT.ff->arg.c-1 : 0);
1441   else if (cc == '!') s = xmprintf("%d"+2*!TT.bangpid, TT.bangpid);
1442   else {
1443     delete = 0;
1444     for (*used = uu = 0; *used<len && isdigit(str[*used]); ++*used)
1445       uu = (10*uu)+str[*used]-'0';
1446     if (*used) {
1447       if (uu) uu += TT.ff->shift;
1448       if (uu<TT.ff->arg.c) s = TT.ff->arg.v[uu];
1449     } else if ((*used = varend(str)-str)) return getvar(str);
1450   }
1451   if (s) push_arg(delete, s);
1452 
1453   return s;
1454 }
1455 
1456 #define WILD_SHORT 1 // else longest match
1457 #define WILD_CASE  2 // case insensitive
1458 #define WILD_ANY   4 // advance through pattern instead of str
1459 // Returns length of str matched by pattern, or -1 if not all pattern consumed
wildcard_matchlen(char * str,int len,char * pattern,int plen,struct sh_arg * deck,int flags)1460 static int wildcard_matchlen(char *str, int len, char *pattern, int plen,
1461   struct sh_arg *deck, int flags)
1462 {
1463   struct sh_arg ant = {0};    // stack: of str offsets
1464   long ss, pp, dd, best = -1;
1465   int i, j, c, not;
1466 
1467   // Loop through wildcards in pattern.
1468   for (ss = pp = dd = 0; ;) {
1469     if ((flags&WILD_ANY) && best!=-1) break;
1470 
1471     // did we consume pattern?
1472     if (pp==plen) {
1473       if (ss>best) best = ss;
1474       if (ss==len || (flags&WILD_SHORT)) break;
1475     // attempt literal match?
1476     } else if (dd>=deck->c || pp!=(long)deck->v[dd]) {
1477       if (ss<len) {
1478         if (flags&WILD_CASE) {
1479           ss += getutf8(str+ss, len-ss, &c);
1480           c = towupper(c);
1481           pp += getutf8(pattern+pp, pp-plen, &i);
1482           i = towupper(i);
1483         } else c = str[ss++], i = pattern[pp++];
1484         if (c==i) continue;
1485       }
1486 
1487     // Wildcard chars: |+@!*?()[]
1488     } else {
1489       c = pattern[pp++];
1490       dd++;
1491       if (c=='?' || ((flags&WILD_ANY) && c=='*')) {
1492         ss += (i = getutf8(str+ss, len-ss, 0));
1493         if (i) continue;
1494       } else if (c=='*') {
1495 
1496         // start with zero length match, don't record consecutive **
1497         if (dd==1 || pp-2!=(long)deck->v[dd-1] || pattern[pp-2]!='*') {
1498           arg_add(&ant, (void *)ss);
1499           arg_add(&ant, 0);
1500         }
1501 
1502         continue;
1503       } else if (c == '[') {
1504         pp += (not = !!strchr("!^", pattern[pp]));
1505         ss += getutf8(str+ss, len-ss, &c);
1506         for (i = 0; pp<(long)deck->v[dd]; i = 0) {
1507           pp += getutf8(pattern+pp, plen-pp, &i);
1508           if (pattern[pp]=='-') {
1509             ++pp;
1510             pp += getutf8(pattern+pp, plen-pp, &j);
1511             if (not^(i<=c && j>=c)) break;
1512           } else if (not^(i==c)) break;
1513         }
1514         if (i) {
1515           pp = 1+(long)deck->v[dd++];
1516 
1517           continue;
1518         }
1519 
1520       // ( preceded by +@!*?
1521 
1522       } else { // TODO ( ) |
1523         dd++;
1524         continue;
1525       }
1526     }
1527 
1528     // match failure
1529     if (flags&WILD_ANY) {
1530       ss = 0;
1531       if (plen==pp) break;
1532       continue;
1533     }
1534 
1535     // pop retry stack or return failure (TODO: seek to next | in paren)
1536     while (ant.c) {
1537       if ((c = pattern[(long)deck->v[--dd]])=='*') {
1538         if (len<(ss = (long)ant.v[ant.c-2]+(long)++ant.v[ant.c-1])) ant.c -= 2;
1539         else {
1540           pp = (long)deck->v[dd++]+1;
1541           break;
1542         }
1543       } else if (c == '(') dprintf(2, "TODO: (");
1544     }
1545 
1546     if (!ant.c) break;
1547   }
1548   free (ant.v);
1549 
1550   return best;
1551 }
1552 
wildcard_match(char * s,char * p,struct sh_arg * deck,int flags)1553 static int wildcard_match(char *s, char *p, struct sh_arg *deck, int flags)
1554 {
1555   return wildcard_matchlen(s, strlen(s), p, strlen(p), deck, flags);
1556 }
1557 
1558 
1559 // TODO: test that * matches ""
1560 
1561 // skip to next slash in wildcard path, passing count active ranges.
1562 // start at pattern[off] and deck[*idx], return pattern pos and update *idx
wildcard_path(char * pattern,int off,struct sh_arg * deck,int * idx,int count)1563 char *wildcard_path(char *pattern, int off, struct sh_arg *deck, int *idx,
1564   int count)
1565 {
1566   char *p, *old;
1567   int i = 0, j = 0;
1568 
1569   // Skip [] and nested () ranges within deck until / or NUL
1570   for (p = old = pattern+off;; p++) {
1571     if (!*p) return p;
1572     while (*p=='/') {
1573       old = p++;
1574       if (j && !count) return old;
1575       j = 0;
1576     }
1577 
1578     // Got wildcard? Return start of name if out of count, else skip [] ()
1579     if (*idx<deck->c && p-pattern == (long)deck->v[*idx]) {
1580       if (!j++ && !count--) return old;
1581       ++*idx;
1582       if (*p=='[') p = pattern+(long)deck->v[(*idx)++];
1583       else if (*p=='(') while (*++p) if (p-pattern == (long)deck->v[*idx]) {
1584         ++*idx;
1585         if (*p == ')') {
1586           if (!i) break;
1587           i--;
1588         } else if (*p == '(') i++;
1589       }
1590     }
1591   }
1592 }
1593 
1594 // TODO ** means this directory as well as ones below it, shopt -s globstar
1595 
1596 // Filesystem traversal callback
1597 // pass on: filename, portion of deck, portion of pattern,
1598 // input: pattern+offset, deck+offset. Need to update offsets.
do_wildcard_files(struct dirtree * node)1599 int do_wildcard_files(struct dirtree *node)
1600 {
1601   struct dirtree *nn;
1602   char *pattern, *patend;
1603   int lvl, ll = 0, ii = 0, rc;
1604   struct sh_arg ant;
1605 
1606   // Top level entry has no pattern in it
1607   if (!node->parent) return DIRTREE_RECURSE;
1608 
1609   // Find active pattern range
1610   for (nn = node->parent; nn; nn = nn->parent) if (nn->parent) ii++;
1611   pattern = wildcard_path(TT.wcpat, 0, TT.wcdeck, &ll, ii);
1612   while (*pattern=='/') pattern++;
1613   lvl = ll;
1614   patend = wildcard_path(TT.wcpat, pattern-TT.wcpat, TT.wcdeck, &ll, 1);
1615 
1616   // Don't include . entries unless explicitly asked for them
1617   if (*node->name=='.' && *pattern!='.') return 0;
1618 
1619   // Don't descend into non-directory (was called with DIRTREE_SYMFOLLOW)
1620   if (*patend && !S_ISDIR(node->st.st_mode) && *node->name) return 0;
1621 
1622   // match this filename from pattern to p in deck from lvl to ll
1623   ant.c = ll-lvl;
1624   ant.v = TT.wcdeck->v+lvl;
1625   for (ii = 0; ii<ant.c; ii++) TT.wcdeck->v[lvl+ii] -= pattern-TT.wcpat;
1626   rc = wildcard_matchlen(node->name, strlen(node->name), pattern,
1627     patend-pattern, &ant, 0);
1628   for (ii = 0; ii<ant.c; ii++) TT.wcdeck->v[lvl+ii] += pattern-TT.wcpat;
1629 
1630   // Return failure or save exact match.
1631   if (rc<0 || node->name[rc]) return 0;
1632   if (!*patend) return DIRTREE_SAVE;
1633 
1634   // Are there more wildcards to test children against?
1635   if (TT.wcdeck->c!=ll) return DIRTREE_RECURSE;
1636 
1637   // No more wildcards: check for child and return failure if it isn't there.
1638   pattern = xmprintf("%s%s", node->name, patend);
1639   rc = faccessat(dirtree_parentfd(node), pattern, F_OK, AT_SYMLINK_NOFOLLOW);
1640   free(pattern);
1641   if (rc) return 0;
1642 
1643   // Save child and self. (Child could be trailing / but only one saved.)
1644   while (*patend=='/' && patend[1]) patend++;
1645   node->child = xzalloc(sizeof(struct dirtree)+1+strlen(patend));
1646   node->child->parent = node;
1647   strcpy(node->child->name, patend);
1648 
1649   return DIRTREE_SAVE;
1650 }
1651 
1652 // Record active wildcard chars in output string
1653 // *new start of string, oo offset into string, deck is found wildcards,
collect_wildcards(char * new,long oo,struct sh_arg * deck)1654 static void collect_wildcards(char *new, long oo, struct sh_arg *deck)
1655 {
1656   long bracket, *vv;
1657   char cc = new[oo];
1658 
1659   // Record unescaped/unquoted wildcard metadata for later processing
1660 
1661   if (!deck->c) arg_add(deck, 0);
1662   vv = (long *)deck->v;
1663 
1664   // vv[0] used for paren level (bottom 16 bits) + bracket start offset<<16
1665 
1666   // at end loop backwards through live wildcards to remove pending unmatched (
1667   if (!cc) {
1668     long ii = 0, jj = 65535&*vv, kk;
1669 
1670     for (kk = deck->c; jj;) {
1671       if (')' == (cc = new[vv[--kk]])) ii++;
1672       else if ('(' == cc) {
1673         if (ii) ii--;
1674         else {
1675           memmove(vv+kk, vv+kk+1, sizeof(long)*(deck->c-- -kk));
1676           jj--;
1677         }
1678       }
1679     }
1680     if (deck->c) memmove(vv, vv+1, sizeof(long)*deck->c--);
1681 
1682     return;
1683   }
1684 
1685   // Start +( range, or remove first char that isn't wildcard without (
1686   if (deck->c>1 && vv[deck->c-1] == oo-1 && strchr("+@!*?", new[oo-1])) {
1687     if (cc == '(') {
1688       vv[deck->c-1] = oo;
1689       return;
1690     } else if (!strchr("*?", new[oo-1])) deck->c--;
1691   }
1692 
1693   // fall through to add wildcard, popping parentheses stack as necessary
1694   if (strchr("|+@!*?", cc));
1695   else if (cc == ')' && (65535&*vv)) --*vv;
1696 
1697   // complete [range], discard wildcards within, add [, fall through to add ]
1698   else if (cc == ']' && (bracket = *vv>>16)) {
1699 
1700     // don't end range yet for [] or [^]
1701     if (bracket+1 == oo || (bracket+2 == oo && strchr("!^", new[oo-1]))) return;
1702     while (deck->c>1 && vv[deck->c-1]>=bracket) deck->c--;
1703     *vv &= 65535;
1704     arg_add(deck, (void *)bracket);
1705 
1706   // Not a wildcard
1707   } else {
1708     // [ is speculative, don't add to deck yet, just record we saw it
1709     if (cc == '[' && !(*vv>>16)) *vv = (oo<<16)+(65535&*vv);
1710     return;
1711   }
1712 
1713   // add active wildcard location
1714   arg_add(deck, (void *)oo);
1715 }
1716 
1717 // wildcard expand data against filesystem, and add results to arg list
1718 // Note: this wildcard deck has extra argument at start (leftover from parsing)
wildcard_add_files(struct sh_arg * arg,char * pattern,struct sh_arg * deck,struct arg_list ** delete)1719 static void wildcard_add_files(struct sh_arg *arg, char *pattern,
1720   struct sh_arg *deck, struct arg_list **delete)
1721 {
1722   struct dirtree *dt;
1723   char *pp;
1724   int ll = 0;
1725 
1726   // fast path: when no wildcards, add pattern verbatim
1727   collect_wildcards("", 0, deck);
1728   if (!deck->c) return arg_add(arg, pattern);
1729 
1730   // Traverse starting with leading patternless path.
1731   pp = wildcard_path(TT.wcpat = pattern, 0, TT.wcdeck = deck, &ll, 0);
1732   pp = (pp==pattern) ? 0 : xstrndup(pattern, pp-pattern);
1733   dt = dirtree_flagread(pp, DIRTREE_STATLESS|DIRTREE_SYMFOLLOW,
1734     do_wildcard_files);
1735   free(pp);
1736   deck->c = 0;
1737 
1738   // If no match save pattern, else free tree saving each path found.
1739   if (!dt) return arg_add(arg, pattern);
1740   while (dt) {
1741     while (dt->child) dt = dt->child;
1742     arg_add(arg, push_arg(delete, dirtree_path(dt, 0)));
1743     do {
1744       pp = (void *)dt;
1745       if ((dt = dt->parent)) dt->child = dt->child->next;
1746       free(pp);
1747     } while (dt && !dt->child);
1748   }
1749 // TODO: test .*/../
1750 }
1751 
1752 // Copy string until } including escaped }
1753 // if deck collect wildcards, and store terminator at deck->v[deck->c]
slashcopy(char * s,char * c,struct sh_arg * deck)1754 char *slashcopy(char *s, char *c, struct sh_arg *deck)
1755 {
1756   char *ss;
1757   long ii, jj;
1758 
1759   for (ii = 0; !strchr(c, s[ii]); ii++) if (s[ii] == '\\') ii++;
1760   ss = xmalloc(ii+1);
1761   for (ii = jj = 0; !strchr(c, s[jj]); ii++)
1762     if ('\\'==(ss[ii] = s[jj++])) ss[ii] = s[jj++];
1763     else if (deck) collect_wildcards(ss, ii, deck);
1764   ss[ii] = 0;
1765   if (deck) {
1766     arg_add(deck, 0);
1767     deck->v[--deck->c] = (void *)jj;
1768     collect_wildcards("", 0, deck);
1769   }
1770 
1771   return ss;
1772 }
1773 
1774 #define NO_QUOTE (1<<0)    // quote removal
1775 #define NO_PATH  (1<<1)    // path expansion (wildcards)
1776 #define NO_SPLIT (1<<2)    // word splitting
1777 #define NO_BRACE (1<<3)    // {brace,expansion}
1778 #define NO_TILDE (1<<4)    // ~username/path
1779 #define NO_NULL  (1<<5)    // Expand to "" instead of NULL
1780 #define SEMI_IFS (1<<6)    // Use ' ' instead of IFS to combine $*
1781 // expand str appending to arg using above flag defines, add mallocs to delete
1782 // if ant not null, save wildcard deck there instead of expanding vs filesystem
1783 // returns 0 for success, 1 for error.
1784 // If measure stop at *measure and return input bytes consumed in *measure
expand_arg_nobrace(struct sh_arg * arg,char * str,unsigned flags,struct arg_list ** delete,struct sh_arg * ant,long * measure)1785 static int expand_arg_nobrace(struct sh_arg *arg, char *str, unsigned flags,
1786   struct arg_list **delete, struct sh_arg *ant, long *measure)
1787 {
1788   char cc, qq = flags&NO_QUOTE, sep[6], *new = str, *s, *ss = ss, *ifs, *slice;
1789   int ii = 0, oo = 0, xx, yy, dd, jj, kk, ll, mm;
1790   struct sh_arg deck = {0};
1791 
1792   // Tilde expansion
1793   if (!(flags&NO_TILDE) && *str == '~') {
1794     struct passwd *pw = 0;
1795 
1796     ss = 0;
1797     while (str[ii] && str[ii]!=':' && str[ii]!='/') ii++;
1798     if (ii==1) {
1799       if (!(ss = getvar("HOME")) || !*ss) pw = bufgetpwuid(getuid());
1800     } else {
1801       // TODO bufgetpwnam
1802       pw = getpwnam(s = xstrndup(str+1, ii-1));
1803       free(s);
1804     }
1805     if (pw) {
1806       ss = pw->pw_dir;
1807       if (!ss || !*ss) ss = "/";
1808     }
1809     if (ss) {
1810       oo = strlen(ss);
1811       s = xmprintf("%s%s", ss, str+ii);
1812       if (str != new) free(new);
1813       new = s;
1814     }
1815   }
1816 
1817   // parameter/variable expansion and dequoting
1818   if (!ant) ant = &deck;
1819   for (; (cc = str[ii++]); str!=new && (new[oo] = 0)) {
1820     struct sh_arg aa = {0};
1821     int nosplit = 0;
1822 
1823     if (measure && cc==*measure) break;
1824 
1825     // skip literal chars
1826     if (!strchr("'\"\\$`"+2*(flags&NO_QUOTE), cc)) {
1827       if (str != new) new[oo] = cc;
1828       if (!(flags&NO_PATH) && !(qq&1)) collect_wildcards(new, oo, ant);
1829       oo++;
1830       continue;
1831     }
1832 
1833     // allocate snapshot if we just started modifying
1834     if (str == new) {
1835       new = xstrdup(new);
1836       new[oo] = 0;
1837     }
1838     ifs = slice = 0;
1839 
1840     // handle escapes and quoting
1841     if (cc == '"') qq++;
1842     else if (cc == '\'') {
1843       if (qq&1) new[oo++] = cc;
1844       else {
1845         qq += 2;
1846         while ((cc = str[ii++]) != '\'') new[oo++] = cc;
1847       }
1848 
1849     // both types of subshell work the same, so do $( here not in '$' below
1850 // TODO $((echo hello) | cat) ala $(( becomes $( ( retroactively
1851     } else if (cc == '`' || (cc == '$' && (str[ii]=='(' || str[ii]=='['))) {
1852       off_t pp = 0;
1853 
1854       s = str+ii-1;
1855       kk = parse_word(s, 1, 0)-s;
1856       if (str[ii] == '[' || *toybuf == 255) { // (( parsed together, not (( ) )
1857         struct sh_arg aa = {0};
1858         long long ll;
1859 
1860         // Expand $VARS in math string
1861         ss = str+ii+1+(str[ii]=='(');
1862         push_arg(delete, ss = xstrndup(ss, kk - (3+2*(str[ii]!='['))));
1863         expand_arg_nobrace(&aa, ss, NO_PATH|NO_SPLIT, delete, 0, 0);
1864         s = ss = (aa.v && *aa.v) ? *aa.v : "";
1865         free(aa.v);
1866 
1867         // Recursively calculate result
1868         if (!recalculate(&ll, &s, 0) || *s) {
1869           error_msg("bad math: %s @ %ld", ss, (long)(s-ss)+1);
1870           goto fail;
1871         }
1872         ii += kk-1;
1873         push_arg(delete, ifs = xmprintf("%lld", ll));
1874       } else {
1875         // Run subshell and trim trailing newlines
1876         s += (jj = 1+(cc == '$'));
1877         ii += --kk;
1878         kk -= jj;
1879 
1880         // Special case echo $(<input)
1881         for (ss = s; isspace(*ss); ss++);
1882         if (*ss != '<') ss = 0;
1883         else {
1884           while (isspace(*++ss));
1885           if (!(ll = parse_word(ss, 0, 0)-ss)) ss = 0;
1886           else {
1887             jj = ll+(ss-s);
1888             while (isspace(s[jj])) jj++;
1889             if (jj != kk) ss = 0;
1890             else {
1891               jj = xcreate_stdio(ss = xstrndup(ss, ll), O_RDONLY|WARN_ONLY, 0);
1892               free(ss);
1893             }
1894           }
1895         }
1896 
1897 // TODO what does \ in `` mean? What is echo `printf %s \$x` supposed to do?
1898         // This has to be async so pipe buffer doesn't fill up
1899         if (!ss) jj = pipe_subshell(s, kk, 0); // TODO $(true &&) syntax_err()
1900         if ((ifs = readfd(jj, 0, &pp)))
1901           for (kk = strlen(ifs); kk && ifs[kk-1]=='\n'; ifs[--kk] = 0);
1902         close(jj);
1903       }
1904     } else if (cc=='\\' || !str[ii]) {
1905       if (!(qq&1) || (str[ii] && strchr("\"\\$`", str[ii])))
1906         new[oo++] = str[ii] ? str[ii++] : cc;
1907 
1908     // $VARIABLE expansions
1909 
1910     } else if (cc == '$' && str[ii]) {
1911       cc = *(ss = str+ii++);
1912       if (cc=='\'') {
1913         for (s = str+ii; *s != '\''; oo += wcrtomb(new+oo, unescape2(&s, 0),0));
1914         ii = s-str+1;
1915 
1916         continue;
1917       } else if (cc=='"' && !(qq&1)) {
1918         qq++;
1919 
1920         continue;
1921       } else if (cc == '{') {
1922 
1923         // Skip escapes to find }, parse_word() guarantees ${} terminates
1924         for (cc = *++ss; str[ii] != '}'; ii++) if (str[ii]=='\\') ii++;
1925         ii++;
1926 
1927         if (cc == '}') ifs = (void *)1;
1928         else if (strchr("#!", cc)) ss++;
1929         if (!(jj = varend(ss)-ss)) while (isdigit(ss[jj])) jj++;
1930         if (!jj && strchr("#$_*", *ss)) jj++;
1931         // parameter or operator? Maybe not a prefix: ${#-} vs ${#-x}
1932         if (!jj && strchr("-?@", *ss)) if (ss[++jj]!='}' && ss[-1]!='{') ss--;
1933         slice = ss+jj;        // start of :operation
1934 
1935         if (!jj) {
1936           // literal ${#} or ${!} wasn't a prefix
1937           if (strchr("#!", cc)) ifs = getvar_special(--ss, 1, &kk, delete);
1938           else ifs = (void *)1;  // unrecognized char ala ${~}
1939         } else if (ss[-1]=='{'); // not prefix, fall through
1940         else if (cc == '#') {  // TODO ${#x[@]}
1941           dd = !!strchr("@*", *ss);  // For ${#@} or ${#*} do normal ${#}
1942           ifs = getvar_special(ss-dd, jj, &kk, delete) ? : "";
1943           if (!dd) push_arg(delete, ifs = xmprintf("%zu", strlen(ifs)));
1944         // ${!@} ${!@Q} ${!x} ${!x@} ${!x@Q} ${!x#} ${!x[} ${!x[*]}
1945         } else if (cc == '!') {  // TODO: ${var[@]} array
1946 
1947           // special case: normal varname followed by @} or *} = prefix list
1948           if (ss[jj] == '*' || (ss[jj] == '@' && !isalpha(ss[jj+1]))) {
1949             struct sh_vars **vv = visible_vars();
1950 
1951             for (slice++, kk = 0; vv[kk]; kk++) {
1952               if (vv[kk]->flags&VAR_WHITEOUT) continue;
1953               if (!strncmp(s = vv[kk]->str, ss, jj))
1954                 arg_add(&aa, push_arg(delete, s = xstrndup(s, stridx(s, '='))));
1955             }
1956             if (aa.c) push_arg(delete, aa.v);
1957             free(vv);
1958 
1959           // else dereference to get new varname, discarding if none, check err
1960           } else {
1961             // First expansion
1962             if (strchr("@*", *ss)) { // special case ${!*}/${!@}
1963               expand_arg_nobrace(&aa, "\"$*\"", NO_PATH|NO_SPLIT, delete, 0, 0);
1964               ifs = *aa.v;
1965               free(aa.v);
1966               memset(&aa, 0, sizeof(aa));
1967               jj = 1;
1968             } else ifs = getvar_special(ss, jj, &jj, delete);
1969             slice = ss+jj;
1970 
1971             // Second expansion
1972             if (!jj) ifs = (void *)1;
1973             else if (ifs && *(ss = ifs)) {
1974               if (strchr("@*", cc)) {
1975                 aa.c = TT.ff->arg.c-1;
1976                 aa.v = TT.ff->arg.v+1;
1977                 jj = 1;
1978               } else ifs = getvar_special(ifs, strlen(ifs), &jj, delete);
1979               if (ss && ss[jj]) {
1980                 ifs = (void *)1;
1981                 slice = ss+strlen(ss);
1982               }
1983             }
1984           }
1985         }
1986 
1987         // Substitution error?
1988         if (ifs == (void *)1) {
1989 barf:
1990           if (!(((unsigned long)ifs)>>1)) ifs = "bad substitution";
1991           error_msg("%.*s: %s", (int)(slice-ss), ss, ifs);
1992           goto fail;
1993         }
1994       } else jj = 1;
1995 
1996       // Resolve unprefixed variables
1997       if (strchr("{$", ss[-1])) {
1998         if (strchr("@*", cc)) {
1999           aa.c = TT.ff->arg.c-1;
2000           aa.v = TT.ff->arg.v+1;
2001         } else {
2002           ifs = getvar_special(ss, jj, &jj, delete);
2003           if (!jj) {
2004             if (ss[-1] == '{') goto barf;
2005             new[oo++] = '$';
2006             ii--;
2007             continue;
2008           } else if (ss[-1] != '{') ii += jj-1;
2009         }
2010       }
2011     }
2012 
2013     // combine before/ifs/after sections & split words on $IFS in ifs
2014     // keep oo bytes of str before (already parsed)
2015     // insert ifs (active for wildcards+splitting)
2016     // keep str+ii after (still to parse)
2017 
2018     // Fetch separator to glue string back together with
2019     *sep = 0;
2020     if (((qq&1) && cc=='*') || (flags&NO_SPLIT)) {
2021       unsigned wc;
2022 
2023       nosplit++;
2024       if (flags&SEMI_IFS) strcpy(sep, " ");
2025 // TODO what if separator is bigger? Need to grab 1 column of combining chars
2026       else if (0<(dd = utf8towc(&wc, TT.ff->ifs, 4)))
2027         sprintf(sep, "%.*s", dd, TT.ff->ifs);
2028     }
2029 
2030     // when aa proceed through entries until NULL, else process ifs once
2031     mm = yy = 0;
2032     do {
2033       // get next argument
2034       if (aa.c) ifs = aa.v[mm++] ? : "";
2035 
2036       // Are we performing surgery on this argument?
2037       if (slice && *slice != '}') {
2038         dd = slice[xx = (*slice == ':')];
2039         if (!ifs || (xx && !*ifs)) {
2040           if (strchr("-?=", dd)) { // - use default = assign default ? error
2041             push_arg(delete, ifs = slashcopy(slice+xx+1, "}", 0));
2042             if (dd == '?' || (dd == '=' &&
2043               !(setvar(s = xmprintf("%.*s=%s", (int)(slice-ss), ss, ifs)))))
2044                 goto barf; // TODO ? exits past "source" boundary
2045           }
2046         } else if (dd == '-'); // NOP when ifs not empty
2047         // use alternate value
2048         else if (dd == '+')
2049           push_arg(delete, ifs = slashcopy(slice+xx+1, "}", 0));
2050         else if (xx) { // ${x::}
2051           long long la = 0, lb = LLONG_MAX, lc = 1;
2052 
2053           ss = ++slice;
2054           if ((lc = recalculate(&la, &ss, 0)) && *ss == ':') {
2055             ss++;
2056             lc = recalculate(&lb, &ss, 0);
2057           }
2058           if (!lc || *ss != '}') {
2059             for (s = ss; *s != '}' && *s != ':'; s++);
2060             error_msg("bad %.*s @ %ld", (int)(s-slice), slice,(long)(ss-slice));
2061 //TODO fix error message
2062             goto fail;
2063           }
2064 
2065           // This isn't quite what bash does, but close enough.
2066           if (!(lc = aa.c)) lc = strlen(ifs);
2067           else if (!la && !yy && strchr("@*", *slice)) {
2068             aa.v--; // ${*:0} shows $0 even though default is 1-indexed
2069             aa.c++;
2070             yy++;
2071           }
2072           if (la<0 && (la += lc)<0) continue;
2073           if (lb<0) lb = lc+lb-la;
2074           if (aa.c) {
2075             if (mm<la || mm>=la+lb) continue;
2076           } else if (la>=lc || lb<0) ifs = "";
2077           else if (la+lb>=lc) ifs += la;
2078           else if (!*delete || ifs != (*delete)->arg)
2079             push_arg(delete, ifs = xmprintf("%.*s", (int)lb, ifs+la));
2080           else {
2081             for (dd = 0; dd<lb ; dd++) if (!(ifs[dd] = ifs[dd+la])) break;
2082             ifs[dd] = 0;
2083           }
2084         } else if (strchr("#%^,", *slice)) {
2085           struct sh_arg wild = {0};
2086           char buf[8];
2087 
2088           s = slashcopy(slice+(xx = slice[1]==*slice)+1, "}", &wild);
2089 
2090           // ${x^pat} ${x^^pat} uppercase ${x,} ${x,,} lowercase (no pat = ?)
2091           if (strchr("^,", *slice)) {
2092             for (ss = ifs; *ss; ss += dd) {
2093               dd = getutf8(ss, 4, &jj);
2094               if (!*s || 0<wildcard_match(ss, s, &wild, WILD_ANY)) {
2095                 ll = ((*slice=='^') ? towupper : towlower)(jj);
2096 
2097                 // Of COURSE unicode case switch can change utf8 encoding length
2098                 // Lower case U+0069 becomes u+0130 in turkish.
2099                 // Greek U+0390 becomes 3 characters TODO test this
2100                 if (ll != jj) {
2101                   yy = ss-ifs;
2102                   if (!*delete || (*delete)->arg!=ifs)
2103                     push_arg(delete, ifs = xstrdup(ifs));
2104                   if (dd != (ll = wctoutf8(buf, ll))) {
2105                     if (dd<ll)
2106                       ifs = (*delete)->arg = xrealloc(ifs, strlen(ifs)+1+dd-ll);
2107                     memmove(ifs+yy+dd-ll, ifs+yy+ll, strlen(ifs+yy+ll)+1);
2108                   }
2109                   memcpy(ss = ifs+yy, buf, dd = ll);
2110                 }
2111               }
2112               if (!xx) break;
2113             }
2114           // ${x#y} remove shortest prefix ${x##y} remove longest prefix
2115           } else if (*slice=='#') {
2116             if (0<(dd = wildcard_match(ifs, s, &wild, WILD_SHORT*!xx)))
2117               ifs += dd;
2118           // ${x%y} ${x%%y} suffix
2119           } else if (*slice=='%') {
2120             for (ss = ifs+strlen(ifs), yy = -1; ss>=ifs; ss--) {
2121               if (0<(dd = wildcard_match(ss, s, &wild, WILD_SHORT*xx))&&!ss[dd])
2122               {
2123                 yy = ss-ifs;
2124                 if (!xx) break;
2125               }
2126             }
2127 
2128             if (yy != -1) {
2129               if (delete && *delete && (*delete)->arg==ifs) ifs[yy] = 0;
2130               else push_arg(delete, ifs = xstrndup(ifs, yy));
2131             }
2132           }
2133           free(s);
2134           free(wild.v);
2135 
2136         // ${x/pat/sub} substitute ${x//pat/sub} global ${x/#pat/sub} begin
2137         // ${x/%pat/sub} end ${x/pat} delete pat (x can be @ or *)
2138         } else if (*slice=='/') {
2139           struct sh_arg wild = {0};
2140 
2141           s = slashcopy(ss = slice+(xx = !!strchr("/#%", slice[1]))+1, "/}",
2142             &wild);
2143           ss += (long)wild.v[wild.c];
2144           ss = (*ss == '/') ? slashcopy(ss+1, "}", 0) : 0;
2145           jj = ss ? strlen(ss) : 0;
2146           ll = 0;
2147           for (ll = 0; ifs[ll];) {
2148             // TODO nocasematch option
2149             if (0<(dd = wildcard_match(ifs+ll, s, &wild, 0))) {
2150               char *bird = 0;
2151 
2152               if (slice[1]=='%' && ifs[ll+dd]) {
2153                 ll++;
2154                 continue;
2155               }
2156               if (delete && *delete && (*delete)->arg==ifs) {
2157                 if (jj==dd) memcpy(ifs+ll, ss, jj);
2158                 else if (jj<dd) sprintf(ifs+ll, "%s%s", ss, ifs+ll+dd);
2159                 else bird = ifs;
2160               } else bird = (void *)1;
2161               if (bird) {
2162                 ifs = xmprintf("%.*s%s%s", ll, ifs, ss ? : "", ifs+ll+dd);
2163                 if (bird != (void *)1) {
2164                   free(bird);
2165                   (*delete)->arg = ifs;
2166                 } else push_arg(delete, ifs);
2167               }
2168               if (slice[1]!='/') break;
2169             } else ll++;
2170             if (slice[1]=='#') break;
2171           }
2172 
2173 // ${x@QEPAa} Q=$'blah' E=blah without the $'' wrap, P=expand as $PS1
2174 //   A=declare that recreates var a=attribute flags
2175 //   x can be @*
2176 //      } else if (*slice=='@') {
2177 
2178 // TODO test x can be @ or *
2179         } else {
2180 // TODO test ${-abc} as error
2181           ifs = slice;
2182           goto barf;
2183         }
2184 
2185 // TODO: $((a=42)) can change var, affect lifetime
2186 // must replace ifs AND any previous output arg[] within pointer strlen()
2187 // also x=;echo $x${x:=4}$x
2188       }
2189 
2190       // Nothing left to do?
2191       if (!ifs) break;
2192       if (!*ifs && !qq) continue;
2193 
2194       // loop within current ifs checking region to split words
2195       do {
2196 
2197         // find end of (split) word
2198         if ((qq&1) || nosplit) ss = ifs+strlen(ifs);
2199         else for (ss = ifs; *ss; ss += kk)
2200           if (utf8chr(ss, TT.ff->ifs, &kk)) break;
2201 
2202         // when no prefix, not splitting, no suffix: use existing memory
2203         if (!oo && !*ss && !((mm==aa.c) ? str[ii] : nosplit)) {
2204           if (qq || ss!=ifs) {
2205             if (!(flags&NO_PATH))
2206               for (jj = 0; ifs[jj]; jj++) collect_wildcards(ifs, jj, ant);
2207             wildcard_add_files(arg, ifs, &deck, delete);
2208           }
2209           continue;
2210         }
2211 
2212         // resize allocation and copy next chunk of IFS-free data
2213         jj = (mm == aa.c) && !*ss;
2214         new = xrealloc(new, oo + (ss-ifs) + ((nosplit&!jj) ? strlen(sep) : 0) +
2215                        (jj ? strlen(str+ii) : 0) + 1);
2216         dd = sprintf(new + oo, "%.*s%s", (int)(ss-ifs), ifs,
2217           (nosplit&!jj) ? sep : "");
2218         if (flags&NO_PATH) oo += dd;
2219         else while (dd--) collect_wildcards(new, oo++, ant);
2220         if (jj) break;
2221 
2222         // If splitting, keep quoted, non-blank, or non-whitespace separator
2223         if (!nosplit) {
2224           if (qq || *new || *ss) {
2225             push_arg(delete, new = xrealloc(new, strlen(new)+1));
2226             wildcard_add_files(arg, new, &deck, delete);
2227             new = xstrdup(str+ii);
2228           }
2229           qq &= 1;
2230           oo = 0;
2231         }
2232 
2233         // Skip trailing seperator (combining whitespace)
2234         kk = 0;
2235         while ((jj = utf8chr(ss, TT.ff->ifs, &ll))) {
2236           if (!iswspace(jj) && kk++) break;
2237           ss += ll;
2238         }
2239       } while (*(ifs = ss));
2240     } while (!(mm == aa.c));
2241   }
2242 
2243 // TODO globbing * ? [] +() happens after variable resolution
2244 
2245 // TODO test word splitting completely eliminating argument when no non-$IFS data left
2246 // wordexp keeps pattern when no matches
2247 
2248 // TODO test NO_SPLIT cares about IFS, see also trailing \n
2249 
2250   // Record result.
2251   if (*new || qq) {
2252     if (str != new) push_arg(delete, new);
2253     wildcard_add_files(arg, new, &deck, delete);
2254     new = 0;
2255   }
2256 
2257   // return success after freeing
2258   arg = 0;
2259 
2260 fail:
2261   if (str != new) free(new);
2262   free(deck.v);
2263   if (ant!=&deck && ant->v) collect_wildcards("", 0, ant);
2264   if (measure) *measure = --ii;
2265 
2266   return !!arg;
2267 }
2268 
2269 struct sh_brace {
2270   struct sh_brace *next, *prev, *stack;
2271   int active, cnt, idx, commas[];
2272 };
2273 
brace_end(struct sh_brace * bb)2274 static int brace_end(struct sh_brace *bb)
2275 {
2276   return bb->commas[(bb->cnt<0 ? 0 : bb->cnt)+1];
2277 }
2278 
2279 // expand braces (ala {a,b,c}) and call expand_arg_nobrace() each permutation
expand_arg(struct sh_arg * arg,char * old,unsigned flags,struct arg_list ** delete)2280 static int expand_arg(struct sh_arg *arg, char *old, unsigned flags,
2281   struct arg_list **delete)
2282 {
2283   struct sh_brace *bb = 0, *blist = 0, *bstk, *bnext;
2284   int i, j, k, x;
2285   char *s, *ss;
2286 
2287   // collect brace spans
2288   if ((TT.options&OPT_B) && !(flags&NO_BRACE)) for (i = 0; ; i++) {
2289     // skip quoted/escaped text
2290     while ((s = parse_word(old+i, 1, 0)) != old+i) i += s-(old+i);
2291 
2292     // start a new span
2293     if (old[i] == '{') {
2294       dlist_add_nomalloc((void *)&blist,
2295         (void *)(bb = xzalloc(sizeof(struct sh_brace)+34*4)));
2296       bb->commas[0] = i;
2297     // end of string: abort unfinished spans and end loop
2298     } else if (!old[i]) {
2299       for (bb = blist; bb;) {
2300         if (!bb->active) {
2301           if (bb==blist) {
2302             dlist_pop(&blist);
2303             bb = blist;
2304           } else dlist_pop(&bb);
2305         } else bb = (bb->next==blist) ? 0 : bb->next;
2306       }
2307       break;
2308     // no active span?
2309     } else if (!bb) continue;
2310     // end current span
2311     else if (old[i] == '}') {
2312       bb->active = bb->commas[bb->cnt+1] = i;
2313       // Is this a .. span?
2314       j = 1+*bb->commas;
2315       if (!bb->cnt && i-j>=4) {
2316         // a..z span? Single digit numbers handled here too. TODO: utf8
2317         if (old[j+1]=='.' && old[j+2]=='.') {
2318           bb->commas[2] = old[j];
2319           bb->commas[3] = old[j+3];
2320           k = 0;
2321           if (old[j+4]=='}' ||
2322             (sscanf(old+j+4, "..%u}%n", bb->commas+4, &k) && k))
2323               bb->cnt = -1;
2324         }
2325         // 3..11 numeric span?
2326         if (!bb->cnt) {
2327           for (k=0, j = 1+*bb->commas; k<3; k++, j += x)
2328             if (!sscanf(old+j, "..%u%n"+2*!k, bb->commas+2+k, &x)) break;
2329           if (old[j]=='}') bb->cnt = -2;
2330         }
2331         // Increment goes in the right direction by at least 1
2332         if (bb->cnt) {
2333           if (!bb->commas[4]) bb->commas[4] = 1;
2334           if ((bb->commas[3]-bb->commas[2]>0) != (bb->commas[4]>0))
2335             bb->commas[4] *= -1;
2336         }
2337       }
2338       // discard commaless span that wasn't x..y
2339       if (!bb->cnt) free(dlist_pop((blist==bb) ? &blist : &bb));
2340       // Set bb to last unfinished brace (if any)
2341       for (bb = blist ? blist->prev : 0; bb && bb->active;
2342            bb = (bb==blist) ? 0 : bb->prev);
2343     // add a comma to current span
2344     } else if (old[i] == ',') {
2345       if (bb->cnt && !(bb->cnt&31)) {
2346         dlist_lpop(&blist);
2347         dlist_add_nomalloc((void *)&blist,
2348           (void *)(bb = xrealloc(bb, sizeof(struct sh_brace)+(bb->cnt+34)*4)));
2349       }
2350       bb->commas[++bb->cnt] = i;
2351     }
2352   }
2353 
2354 // TODO NO_SPLIT with braces? (Collate with spaces?)
2355   // If none, pass on verbatim
2356   if (!blist) return expand_arg_nobrace(arg, old, flags, delete, 0, 0);
2357 
2358   // enclose entire range in top level brace.
2359   (bstk = xzalloc(sizeof(struct sh_brace)+8))->commas[1] = strlen(old)+1;
2360   bstk->commas[0] = -1;
2361 
2362   // loop through each combination
2363   for (;;) {
2364 
2365     // Brace expansion can't be longer than original string. Keep start to {
2366     s = ss = xmalloc(bstk->commas[1]);
2367 
2368     // Append output from active braces to string
2369     for (bb = blist; bb; bb = (bnext == blist) ? 0 : bnext) {
2370 
2371       // If this brace already tip of stack, pop it. (We'll re-add in a moment.)
2372       if (bstk == bb) bstk = bstk->stack;
2373       // if bb is within bstk, save prefix text from bstk's "," to bb's "{"
2374       if (brace_end(bstk)>bb->commas[0]) {
2375         i = bstk->commas[bstk->idx]+1;
2376         s = stpncpy(s, old+i, bb->commas[0]-i);
2377       }
2378       else bstk = bstk->stack; // bb past bstk so done with old bstk, pop it
2379       // push self onto stack as active
2380       bb->stack = bstk;
2381       bb->active = 1;
2382       bstk = bnext = bb;
2383 
2384       // Find next active range: skip inactive spans from earlier/later commas
2385       while ((bnext = (bnext->next==blist) ? 0 : bnext->next)) {
2386 
2387         // past end of this brace (always true for a..b ranges)
2388         if ((i = bnext->commas[0])>brace_end(bb)) break;
2389 
2390         // in this brace but not this section
2391         if (i<bb->commas[bb->idx] || i>bb->commas[bb->idx+1]) {
2392           bnext->active = 0;
2393           bnext->stack = 0;
2394 
2395         // in this section
2396         } else break;
2397       }
2398 
2399       // is next span past this range?
2400       if (!bnext || bb->cnt<0 || bnext->commas[0]>bb->commas[bb->idx+1]) {
2401 
2402         // output uninterrupted span
2403         if (bb->cnt<0) {
2404           k = bb->commas[2]+bb->commas[4]*bb->idx;
2405           s += sprintf(s, (bb->cnt==-1) ? "\\%c"+!ispunct(k) : "%d", k);
2406         } else {
2407           i = bb->commas[bstk->idx]+1;
2408           s = stpncpy(s, old+i, bb->commas[bb->idx+1]-i);
2409         }
2410 
2411         // While not sibling, output tail and pop
2412         while (!bnext || bnext->commas[0]>brace_end(bstk)) {
2413           if (!(bb = bstk->stack)) break;
2414           i = brace_end(bstk)+1; // start of span
2415           j = bb->commas[bb->idx+1]; // enclosing comma span (can't be a..b)
2416 
2417           while (bnext) {
2418             if (bnext->commas[0]<j) {
2419               j = bnext->commas[0];// sibling
2420               break;
2421             } else if (brace_end(bb)>bnext->commas[0])
2422               bnext = (bnext->next == blist) ? 0 : bnext->next;
2423             else break;
2424           }
2425           s = stpncpy(s, old+i, j-i);
2426 
2427           // if next is sibling but parent _not_ a sibling, don't pop
2428           if (bnext && bnext->commas[0]<brace_end(bb)) break;
2429           bstk = bb;
2430         }
2431       }
2432     }
2433 
2434     // Save result, aborting on expand error
2435     if (expand_arg_nobrace(arg, push_arg(delete, ss), flags, delete, 0, 0)) {
2436       llist_traverse(blist, free);
2437 
2438       return 1;
2439     }
2440 
2441     // increment
2442     for (bb = blist->prev; bb; bb = (bb == blist) ? 0 : bb->prev) {
2443       if (!bb->stack) continue;
2444       else if (bb->cnt<0) {
2445         if (abs(bb->commas[2]-bb->commas[3]) < abs(++bb->idx*bb->commas[4]))
2446           bb->idx = 0;
2447         else break;
2448       } else if (++bb->idx > bb->cnt) bb->idx = 0;
2449       else break;
2450     }
2451 
2452     // if increment went off left edge, done expanding
2453     if (!bb) break;
2454   }
2455   llist_traverse(blist, free);
2456 
2457   return 0;
2458 }
2459 
2460 // Expand exactly one arg, returning NULL on error.
expand_one_arg(char * new,unsigned flags,struct arg_list ** del)2461 static char *expand_one_arg(char *new, unsigned flags, struct arg_list **del)
2462 {
2463   struct sh_arg arg = {0};
2464   char *s = 0;
2465 
2466   // TODO: ${var:?error} here?
2467   if (!expand_arg(&arg, new, flags|NO_PATH|NO_SPLIT, del))
2468     if (!(s = *arg.v) && (flags&(SEMI_IFS|NO_NULL))) s = "";
2469   free(arg.v);
2470 
2471   return s;
2472 }
2473 
2474 // TODO |&
2475 
2476 // Expand arguments and perform redirections. Return new process object with
2477 // expanded args. This can be called from command or block context.
expand_redir(struct sh_arg * arg,int skip,int * urd)2478 static struct sh_process *expand_redir(struct sh_arg *arg, int skip, int *urd)
2479 {
2480   struct sh_process *pp;
2481   char *s = s, *ss, *sss, *cv = 0;
2482   int j, to, from, here = 0;
2483 
2484   TT.hfd = 10;
2485   pp = xzalloc(sizeof(struct sh_process));
2486   pp->urd = urd;
2487   pp->raw = arg;
2488 
2489   // When redirecting, copy each displaced filehandle to restore it later.
2490 
2491   // Expand arguments and perform redirections
2492   for (j = skip; j<arg->c; j++) {
2493     int saveclose = 0, bad = 0;
2494 
2495     if (!strcmp(s = arg->v[j], "!")) {
2496       pp->flags ^= PFLAG_NOT;
2497 
2498       continue;
2499     }
2500 
2501     // Handle <() >() redirectionss
2502     if ((*s == '<' || *s == '>') && s[1] == '(') {
2503       int new = pipe_subshell(s+2, strlen(s+2)-1, *s == '>');
2504 
2505       // Grab subshell data
2506       if (new == -1) {
2507         pp->exit = 1;
2508 
2509         return pp;
2510       }
2511       save_redirect(&pp->urd, -2, new);
2512 
2513       // bash uses /dev/fd/%d which requires /dev/fd to be a symlink to
2514       // /proc/self/fd so we just produce that directly.
2515       arg_add_del(&pp->arg, ss = xmprintf("/proc/self/fd/%d", new),&pp->delete);
2516 
2517       continue;
2518     }
2519 
2520     // Is this a redirect? s = prefix, ss = operator
2521     ss = skip_redir_prefix(s);
2522     sss = ss + anystart(ss, (void *)redirectors);
2523     if (ss == sss) {
2524       // Nope: save/expand argument and loop
2525       if (expand_arg(&pp->arg, s, 0, &pp->delete)) {
2526         pp->exit = 1;
2527 
2528         return pp;
2529       }
2530       continue;
2531     } else if (j+1 >= arg->c) {
2532       // redirect needs one argument
2533       s = "\\n";
2534       break;
2535     }
2536     sss = arg->v[++j];
2537 
2538     // It's a redirect: for [to]<from s = start of [to], ss = <, sss = from
2539     if (isdigit(*s) && ss-s>5) break;
2540 
2541     // expand arguments for everything but HERE docs
2542     if (strncmp(ss, "<<", 2)) {
2543       struct sh_arg tmp = {0};
2544 
2545       if (!expand_arg(&tmp, sss, 0, &pp->delete) && tmp.c == 1) sss = *tmp.v;
2546       else {
2547         if (tmp.c > 1) error_msg("%s: ambiguous redirect", sss);
2548         s = 0;
2549       }
2550       free(tmp.v);
2551       if (!s) break;
2552     }
2553 
2554     // Parse the [fd] part of [fd]<name
2555     to = *ss != '<';
2556     if (isdigit(*s)) to = atoi(s);
2557     else if (*s == '{') {
2558       if (*varend(s+1) != '}') break;
2559       // when we close a filehandle, we _read_ from {var}, not write to it
2560       if ((!strcmp(ss, "<&") || !strcmp(ss, ">&")) && !strcmp(sss, "-")) {
2561         if (!(ss = getvar(s+1))) break;
2562         to = atoi(ss); // TODO trailing garbage?
2563         if (save_redirect(&pp->urd, -1, to)) break;
2564         close(to);
2565 
2566         continue;
2567       // record high file descriptor in {to}<from environment variable
2568       } else {
2569         // we don't save this, it goes in the env var and user can close it.
2570         if (-1 == (to = next_hfd())) break;
2571         cv = xmprintf("%.*s=%d", (int)(ss-s-2), s+1, to);
2572       }
2573     }
2574 
2575     // HERE documents?
2576     if (!strncmp(ss, "<<", 2)) {
2577       char *tmp = xmprintf("%s/sh-XXXXXX", getvar("TMPDIR") ? : "/tmp");
2578       int i, len, zap = (ss[2] == '-'), x = !ss[strcspn(ss, "\"'")];
2579 
2580       // store contents in open-but-deleted /tmp file: write then lseek(start)
2581       if ((from = mkstemp(tmp))>=0) {
2582         if (unlink(tmp)) bad++;
2583         else if (ss[2] == '<') { // not stored in arg[here]
2584           if (!(ss = expand_one_arg(sss, 0, 0))) {
2585             s = 0;
2586             break;
2587           }
2588           len = strlen(ss);
2589           if (len != writeall(from, ss, len)) bad++;
2590           if (ss != sss) free(ss);
2591         } else {
2592           struct sh_arg *hh = arg+ ++here;
2593 
2594           for (i = 0; i<hh->c; i++) {
2595             ss = hh->v[i];
2596             sss = 0;
2597 // TODO audit this ala man page
2598             // expand_parameter, commands, and arithmetic
2599             if (x && !(sss = expand_one_arg(ss, ~SEMI_IFS, 0))) {
2600               s = 0;
2601               break;
2602             }
2603 
2604             while (zap && *ss == '\t') ss++;
2605             x = writeall(from, ss, len = strlen(ss));
2606             if (ss != sss) free(sss);
2607             if (len != x) break;
2608           }
2609           if (i != hh->c) bad++;
2610         }
2611         if (!bad && lseek(from, 0, SEEK_SET)) bad++;
2612         if (bad) close(from);
2613       } else bad++;
2614       free(tmp);
2615       if (bad) break;
2616 
2617     // from is fd<<2 (new fd to dup2() after vfork()) plus
2618     // 2 if we should close(from>>2) after dup2(from>>2, to),
2619     // 1 if we should close but dup for nofork recovery (ala <&2-)
2620 
2621     // Handle file descriptor duplication/close (&> &>> <& >& with number or -)
2622     // These redirect existing fd so nothing to open()
2623     } else if (*ss == '&' || ss[1] == '&') {
2624 
2625       // is there an explicit fd?
2626       for (ss = sss; isdigit(*ss); ss++);
2627       if (ss-sss>5 || (*ss && (*ss != '-' || ss[1]))) {
2628         if (*ss=='&') ss++;
2629         saveclose = 4;
2630         goto notfd;
2631       }
2632 
2633       from = (ss==sss) ? to : atoi(sss);
2634       saveclose = 2-(*ss == '-');
2635     } else {
2636 notfd:
2637       // Permissions to open external file with: < > >> <& >& <> >| &>> &>
2638       if (!strcmp(ss, "<>")) from = O_CREAT|O_RDWR;
2639       else if (strstr(ss, ">>")) from = O_CREAT|O_APPEND|O_WRONLY;
2640       else {
2641         from = (*ss == '<') ? O_RDONLY : O_CREAT|O_WRONLY|O_TRUNC;
2642         if (!strcmp(ss, ">") && (TT.options&OPT_C)) {
2643           struct stat st;
2644 
2645           // Not _just_ O_EXCL: > /dev/null allowed
2646           if (stat(sss, &st) || !S_ISREG(st.st_mode)) from |= O_EXCL;
2647         }
2648       }
2649 
2650       // we expect /dev/fd/# and /dev/{stdin,stdout,stderr} to be in /dev
2651 
2652 // TODO: /dev/{tcp,udp}/host/port
2653 
2654       // Open the file
2655       if (-1 == (from = xcreate_stdio(sss, from|WARN_ONLY, 0666))) {
2656         s = 0;
2657 
2658         break;
2659       }
2660     }
2661 
2662     // perform redirect, saving displaced "to".
2663     if (save_redirect(&pp->urd, from, to)) bad++;
2664     // Do we save displaced "to" in env variable instead of undo list?
2665     if (cv) {
2666       --*pp->urd;
2667       if (!setvar(cv)) bad++;
2668       cv = 0;
2669     }
2670     if ((saveclose&1) && save_redirect(&pp->urd, -1, from)) bad++;
2671     if ((saveclose&4) && save_redirect(&pp->urd, from, 2)) bad++;
2672     if (!(saveclose&2)) close(from);
2673     if (bad) break;
2674   }
2675 
2676   // didn't parse everything?
2677   if (j != arg->c) {
2678     if (s) syntax_err(s);
2679     if (!pp->exit) pp->exit = 1;
2680     free(cv);
2681   }
2682 
2683   return pp;
2684 }
2685 
2686 // Call binary, or run script via xexec("sh --")
sh_exec(char ** argv)2687 static void sh_exec(char **argv)
2688 {
2689   char *pp = getvar("PATH" ? : _PATH_DEFPATH), *cc = TT.isexec ? : *argv, *ss,
2690     **sss = 0, **oldenv = environ, **argv2;
2691   struct string_list *sl;
2692 
2693   if (getpid() != TT.pid) signal(SIGINT, SIG_DFL); // TODO: restore all?
2694   errno = ENOENT;
2695   if (strchr(ss = cc, '/')) {
2696     if (access(ss, X_OK)) ss = 0;
2697   } else for (sl = find_in_path(pp, cc); sl || (ss = 0); free(llist_pop(&sl)))
2698     if (!access(ss = sl->str, X_OK)) break;
2699 
2700   if (ss) {
2701     struct sh_vars **vv = visible_vars();
2702     struct sh_arg aa;
2703     unsigned uu, argc;
2704 
2705     // convert vars in-place and use original sh_arg alloc to add one more
2706     aa.v = environ = (void *)vv;
2707     for (aa.c = uu = 0; vv[uu]; uu++) {
2708       if ((vv[uu]->flags&(VAR_WHITEOUT|VAR_EXPORT))==VAR_EXPORT) {
2709         if (*(pp = vv[uu]->str)=='_' && pp[1]=='=') sss = aa.v+aa.c;
2710         aa.v[aa.c++] = pp;
2711       }
2712     }
2713     aa.v[aa.c] = 0;
2714     if (!sss) {
2715       arg_add(&aa, 0);
2716       sss = aa.v+aa.c-1;
2717     }
2718     *sss = xmprintf("_=%s", ss);
2719 
2720     // exec or source
2721     execve(ss, argv, environ);
2722     if (errno == ENOEXEC) {
2723       for (argc = 0; argv[argc]; argc++);
2724       argv2 = xmalloc((argc+3)*sizeof(char *));
2725       memcpy(argv2+3, argv+1, argc*sizeof(char *));
2726       argv2[0] = "sh";
2727       argv2[1] = "--";
2728       argv2[2] = ss;
2729       xexec(argv2);
2730       free(argv2);
2731     }
2732     environ = oldenv;
2733     free(*sss);
2734     free(aa.v);
2735   }
2736 
2737   perror_msg("%s", *argv);
2738   if (!TT.isexec) _exit(127);
2739   llist_traverse(sl, free);
2740 }
2741 
2742 // Execute a single command at TT.ff->pl
run_command(void)2743 static struct sh_process *run_command(void)
2744 {
2745   char *s, *ss, *sss;
2746   struct sh_arg *arg = TT.ff->pl->arg;
2747   int envlen, skiplen, funk = TT.funcslen, ii, jj = 0, prefix = 0;
2748   struct sh_process *pp;
2749 
2750   // Count leading variable assignments
2751   for (envlen = skiplen = 0; envlen<arg->c; envlen++)
2752     if ((ss = varend(arg->v[envlen]))==arg->v[envlen] || ss[*ss=='+']!='=')
2753       break;
2754 
2755   // Skip [[ ]] and (( )) contents for now
2756   if ((s = arg->v[envlen])) {
2757     if (!smemcmp(s, "((", 2)) skiplen = 1;
2758     else if (!strcmp(s, "[[")) while (strcmp(arg->v[envlen+skiplen++], "]]"));
2759   }
2760   pp = expand_redir(arg, envlen+skiplen, 0);
2761 
2762 // TODO: if error stops redir, expansion assignments, prefix assignments,
2763 // what sequence do they occur in?
2764   if (skiplen) {
2765     // Trailing redirects can't expand to any contents
2766     if (pp->arg.c) {
2767       syntax_err(*pp->arg.v);
2768       pp->exit = 1;
2769     }
2770     if (!pp->exit) {
2771       for (ii = 0; ii<skiplen; ii++)
2772 // TODO: [[ ~ ] expands but ((~)) doesn't, what else?
2773         if (expand_arg(&pp->arg, arg->v[envlen+ii], NO_PATH|NO_SPLIT, &pp->delete))
2774           break;
2775       if (ii != skiplen) pp->exit = toys.exitval = 1;
2776     }
2777     if (pp->exit) return pp;
2778   }
2779 
2780   // Are we calling a shell function?  TODO binary search
2781   if (pp->arg.c)
2782     if (!strchr(s, '/')) for (funk = 0; funk<TT.funcslen; funk++)
2783        if (!strcmp(s, TT.functions[funk]->name)) break;
2784 
2785   // Create new function context to hold local vars?
2786   if (funk != TT.funcslen || (envlen && pp->arg.c) || TT.ff->blk->pipe) {
2787     call_function();
2788 // TODO function needs to run asynchronously in pipeline
2789     if (funk != TT.funcslen) {
2790       TT.ff->delete = pp->delete;
2791       pp->delete = 0;
2792     }
2793     addvar(0, TT.ff); // function context (not source) so end_function deletes
2794     prefix = 1;  // create local variables for function prefix assignment
2795   }
2796 
2797   // perform any assignments
2798   if (envlen) for (; jj<envlen && !pp->exit; jj++) {
2799     struct sh_vars *vv;
2800 
2801     if ((sss = expand_one_arg(ss = arg->v[jj], SEMI_IFS, 0))) {
2802       if (!prefix && sss==ss) sss = xstrdup(sss);
2803       if ((vv = setvar_long(sss, sss!=ss, prefix ? TT.ff : TT.ff->prev))) {
2804         if (prefix) vv->flags |= VAR_EXPORT;
2805         continue;
2806       }
2807     }
2808     pp->exit = 1;
2809     break;
2810   }
2811 
2812   // Do the thing
2813   if (pp->exit || envlen==arg->c) s = 0; // leave $_ alone
2814   else if (!pp->arg.c) s = "";           // nothing to do but blank $_
2815 
2816 // TODO: call functions() FUNCTION
2817 // TODO what about "echo | x=1 | export fruit", must subshell? Test this.
2818 //   Several NOFORK can just NOP in a pipeline? Except ${a?b} still errors
2819 
2820   // ((math))
2821   else if (!smemcmp(s = *pp->arg.v, "((", 2)) {
2822     char *ss = s+2;
2823     long long ll;
2824 
2825     funk = TT.funcslen;
2826     ii = strlen(s)-2;
2827     if (!recalculate(&ll, &ss, 0) || ss!=s+ii)
2828       perror_msg("bad math: %.*s @ %ld", ii-2, s+2, (long)(ss-s)-2);
2829     else toys.exitval = !ll;
2830     pp->exit = toys.exitval;
2831     s = 0; // Really!
2832 
2833   // call shell function
2834   } else if (funk != TT.funcslen) {
2835     s = 0; // $_ set on return, not here
2836     (TT.ff->func = TT.functions[funk])->refcount++;
2837     TT.ff->pl = TT.ff->func->pipeline;
2838     TT.ff->arg = pp->arg;
2839 // TODO: unredirect(pp->urd) called below but haven't traversed function yet
2840   } else {
2841     struct toy_list *tl = toy_find(*pp->arg.v);
2842 
2843     jj = tl ? tl->flags : 0;
2844     TT.pp = pp;
2845     s = pp->arg.v[pp->arg.c-1];
2846     sss = pp->arg.v[pp->arg.c];
2847 //dprintf(2, "%d run command %p %s\n", getpid(), TT.ff, *pp->arg.v); debug_show_fds();
2848 // TODO: figure out when can exec instead of forking, ala sh -c blah
2849 
2850     // Is this command a builtin that should run in this process?
2851     if ((jj&TOYFLAG_NOFORK) || ((jj&TOYFLAG_MAYFORK) && !prefix)) {
2852       sigjmp_buf rebound;
2853       char temp[jj = offsetof(struct toy_context, rebound)];
2854 
2855       // This fakes lots of what toybox_main() does.
2856       memcpy(&temp, &toys, jj);
2857       memset(&toys, 0, jj);
2858 
2859       // The compiler complains "declaration does not declare anything" if we
2860       // name the union in TT, only works WITHOUT name. So we can't
2861       // sizeof(union) instead offsetof() first thing after union to get size.
2862       memset(&TT, 0, offsetof(struct sh_data, SECONDS));
2863       if (!sigsetjmp(rebound, 1)) {
2864         toys.rebound = &rebound;
2865 //dprintf(2, "%d builtin", getpid()); for (int xx = 0; xx<=pp->arg.c; xx++) dprintf(2, "{%s}", pp->arg.v[xx]); dprintf(2, "\n");
2866         toy_singleinit(tl, pp->arg.v);
2867         tl->toy_main();
2868         xflush(0);
2869       }
2870       toys.rebound = 0;
2871       pp->exit = toys.exitval;
2872       clearerr(stdout);
2873       if (toys.optargs != toys.argv+1) free(toys.optargs);
2874       if (toys.old_umask) umask(toys.old_umask);
2875       memcpy(&toys, &temp, jj);
2876     } else if (-1==(pp->pid = xpopen_setup(pp->arg.v, 0, sh_exec)))
2877         perror_msg("%s: vfork", *pp->arg.v);
2878   }
2879 
2880   // cleanup process
2881   unredirect(pp->urd);
2882   pp->urd = 0;
2883   if (prefix && funk == TT.funcslen) end_function(0);
2884   if (s) setvarval("_", s);
2885 
2886   return pp;
2887 }
2888 
free_process(struct sh_process * pp)2889 static int free_process(struct sh_process *pp)
2890 {
2891   int rc;
2892 
2893   if (!pp) return 127;
2894   rc = pp->exit;
2895   llist_traverse(pp->delete, llist_free_arg);
2896   free(pp);
2897 
2898   return rc;
2899 }
2900 
2901 // if then fi for while until select done done case esac break continue return
2902 
2903 // Free one pipeline segment.
free_pipeline(void * pipeline)2904 static void free_pipeline(void *pipeline)
2905 {
2906   struct sh_pipeline *pl = pipeline;
2907   int i, j;
2908 
2909   if (!pl) return;
2910 
2911   // free either function or arguments and HERE doc contents
2912   if (pl->type == 'F') {
2913     free_function((void *)*pl->arg->v);
2914     *pl->arg->v = 0;
2915   }
2916   for (j=0; j<=pl->count; j++) {
2917     if (!pl->arg[j].v) continue;
2918     for (i = 0; i<=pl->arg[j].c; i++) free(pl->arg[j].v[i]);
2919     free(pl->arg[j].v);
2920   }
2921   free(pl);
2922 }
2923 
2924 // Append a new pipeline to function, returning pipeline and pipeline's arg
add_pl(struct sh_pipeline ** ppl,struct sh_arg ** arg)2925 static struct sh_pipeline *add_pl(struct sh_pipeline **ppl, struct sh_arg **arg)
2926 {
2927   struct sh_pipeline *pl = xzalloc(sizeof(struct sh_pipeline));
2928 
2929   if (arg) *arg = pl->arg;
2930   pl->lineno = TT.LINENO;
2931   dlist_add_nomalloc((void *)ppl, (void *)pl);
2932 
2933   return pl->end = pl;
2934 }
2935 
2936 // Add a line of shell script to a shell function. Returns 0 if finished,
2937 // 1 to request another line of input (> prompt), -1 for syntax err
parse_line(char * line,struct sh_pipeline ** ppl,struct double_list ** expect)2938 static int parse_line(char *line, struct sh_pipeline **ppl,
2939    struct double_list **expect)
2940 {
2941   char *start = line, *delete = 0, *end, *s, *ex, done = 0,
2942     *tails[] = {"fi", "done", "esac", "}", "]]", ")", 0};
2943   struct sh_pipeline *pl = *ppl ? (*ppl)->prev : 0, *pl2, *pl3;
2944   struct sh_arg *arg = 0;
2945   long i;
2946 
2947   // Resume appending to last statement?
2948   if (pl) {
2949     arg = pl->arg;
2950 
2951     // Extend/resume quoted block
2952     if (arg->c<0) {
2953       delete = start = xmprintf("%s%s", arg->v[arg->c = (-arg->c)-1], start);
2954       free(arg->v[arg->c]);
2955       arg->v[arg->c] = 0;
2956 
2957     // is a HERE document in progress?
2958     } else if (pl->count != pl->here) {
2959       // Back up to oldest unfinished pipeline segment.
2960       while (pl != *ppl && pl->prev->count != pl->prev->here) pl = pl->prev;
2961       arg = pl->arg+1+pl->here;
2962 
2963       // Match unquoted EOF.
2964       for (s = line, end = arg->v[arg->c]; *end; s++, end++) {
2965         s += strspn(s, "\\\"'");
2966         if (!*s || *s != *end) break;
2967       }
2968       // Add this line, else EOF hit so end HERE document
2969       if (*s || *end) {
2970         end = arg->v[arg->c];
2971         arg_add(arg, xstrdup(line));
2972         arg->v[arg->c] = end;
2973       } else {
2974         // End segment and advance/consume bridge segments
2975         arg->v[arg->c] = 0;
2976         if (pl->count == ++pl->here)
2977           while (pl->next != *ppl && (pl = pl->next)->here == -1)
2978             pl->here = pl->count;
2979       }
2980       if (pl->here != pl->count) return 1;
2981       start = 0;
2982 
2983     // Nope, new segment if not self-managing type
2984     } else if (pl->type < 128) pl = 0;
2985   }
2986 
2987   // Parse words, assemble argv[] pipelines, check flow control and HERE docs
2988   if (start) for (;;) {
2989     ex = *expect ? (*expect)->prev->data : 0;
2990 
2991     // Look for << HERE redirections in completed pipeline segment
2992     if (pl && pl->count == -1) {
2993       // find arguments of the form [{n}]<<[-] with another one after it
2994       for (arg = pl->arg, pl->count = i = 0; i<arg->c; i++) {
2995         s = skip_redir_prefix(arg->v[i]);
2996         if (strncmp(s, "<<", 2) || s[2]=='<') continue;
2997         if (i+1 == arg->c) goto flush;
2998 
2999         // Add another arg[] to the pipeline segment (removing/re-adding
3000         // to list because realloc can move pointer, and adjusing end pointers)
3001         dlist_lpop(ppl);
3002         pl2 = pl;
3003         pl = xrealloc(pl, sizeof(*pl)+(++pl->count+1)*sizeof(struct sh_arg));
3004         arg = pl->arg;
3005         dlist_add_nomalloc((void *)ppl, (void *)pl);
3006         for (pl3 = *ppl;;) {
3007           if (pl3->end == pl2) pl3->end = pl;
3008           if ((pl3 = pl3->next) == *ppl) break;
3009         }
3010 
3011         // queue up HERE EOF so input loop asks for more lines.
3012         *(arg[pl->count].v = xzalloc(2*sizeof(void *))) = arg->v[++i];
3013         arg[pl->count].c = 0;
3014       }
3015       // Mark "bridge" segment when previous pl had HERE but this doesn't
3016       if (!pl->count && pl->prev->count != pl->prev->here) pl->prev->here = -1;
3017       pl = 0;
3018     }
3019     if (done) break;
3020     s = 0;
3021 
3022     // skip leading whitespace/comment here to know where next word starts
3023     while (isspace(*start)) ++start;
3024     if (*start=='#') while (*start && *start != '\n') ++start;
3025 
3026     // Parse next word and detect overflow (too many nested quotes).
3027     if ((end = parse_word(start, 0, 0)) == (void *)1) goto flush;
3028 //dprintf(2, "%d %p(%d) %s word=%.*s\n", getpid(), pl, pl ? pl->type : -1, ex, (int)(end-start), end ? start : "");
3029 
3030     // End function declaration?
3031     if (pl && pl->type == 'f' && arg->c == 1 && (end-start!=1 || *start!='(')) {
3032       // end (possibly multiline) function segment, expect function body next
3033       dlist_add(expect, 0);
3034       pl = 0;
3035 
3036       continue;
3037     }
3038 
3039     // Is this a new pipeline segment?
3040     if (!pl) pl = add_pl(ppl, &arg);
3041 
3042     // Do we need to request another line to finish word (find ending quote)?
3043     if (!end) {
3044       // Save unparsed bit of this line, we'll need to re-parse it.
3045       arg_add(arg, xstrndup(start, strlen(start)));
3046       arg->c = -arg->c;
3047       free(delete);
3048 
3049       return 1;
3050     }
3051 
3052     // Ok, we have a word. What does it _mean_?
3053 
3054     // case/esac parsing is weird (unbalanced parentheses!), handle first
3055     i = ex && !strcmp(ex, "esac") &&
3056         ((pl->type && pl->type != 3) || (*start==';' && end-start>1));
3057     if (i) {
3058 
3059       // Premature EOL in type 1 (case x\nin) or 2 (at start or after ;;) is ok
3060       if (end == start) {
3061         if (pl->type==128 && arg->c==2) break;  // case x\nin
3062         if (pl->type==129 && (!arg->c || (arg->c==1 && **arg->v==';'))) break;
3063         s = "newline";
3064         goto flush;
3065       }
3066 
3067       // type 0 means just got ;; so start new type 2
3068       if (!pl->type || pl->type==3) {
3069         // catch "echo | ;;" errors
3070         if (arg->v && arg->v[arg->c] && strcmp(arg->v[arg->c], "&")) goto flush;
3071         if (!arg->c) {
3072           if (pl->prev->type == 2) {
3073             // Add a call to "true" between empty ) ;;
3074             arg_add(arg, xstrdup(":"));
3075             pl = add_pl(ppl, &arg);
3076           }
3077           pl->type = 129;
3078         } else {
3079           // check for here documents
3080           pl->count = -1;
3081           continue;
3082         }
3083       }
3084 
3085     // Did we hit end of line or ) outside a function declaration?
3086     // ) is only saved at start of a statement, ends current statement
3087     } else if (end == start || (arg->c && *start == ')' && pl->type!='f')) {
3088 //TODO: test ) within ]]
3089       // function () needs both parentheses or neither
3090       if (pl->type == 'f' && arg->c != 1 && arg->c != 3) {
3091         s = "function(";
3092         goto flush;
3093       }
3094 
3095       // "for" on its own line is an error.
3096       if (arg->c == 1 && !smemcmp(ex, "do\0A", 4)) {
3097         s = "newline";
3098         goto flush;
3099       }
3100 
3101       // Stop at EOL. Discard blank pipeline segment, else end segment
3102       if (end == start) done++;
3103       if (!pl->type && !arg->c) {
3104         free_pipeline(dlist_lpop(ppl));
3105         pl = *ppl ? (*ppl)->prev : 0;
3106       } else pl->count = -1;
3107 
3108       continue;
3109     }
3110 
3111     // Save word and check for flow control
3112     arg_add(arg, s = xstrndup(start, end-start));
3113     start = end;
3114 
3115     // Second half of case/esac parsing
3116     if (i) {
3117       // type 1 (128): case x [\n] in
3118       if (pl->type==128) {
3119         if (arg->c==2 && strchr("()|;&", *s)) goto flush;
3120         if (arg->c==3) {
3121           if (strcmp(s, "in")) goto flush;
3122           pl->type = 1;
3123           (pl = add_pl(ppl, &arg))->type = 129;
3124         }
3125 
3126         continue;
3127 
3128       // type 2 (129): [;;] [(] pattern [|pattern...] )
3129       } else {
3130 
3131         // can't start with line break or ";;" or "case ? in ;;" without ")"
3132         if (*s==';') {
3133           if (arg->c>1 || (arg->c==1 && pl->prev->type==1)) goto flush;
3134         } else pl->type = 2;
3135         i = arg->c - (**arg->v==';' && arg->v[0][1]);
3136         if (i==1 && !strcmp(s, "esac")) {
3137           // esac right after "in" or ";;" ends block, fall through
3138           if (arg->c>1) {
3139             arg->v[1] = 0;
3140             pl = add_pl(ppl, &arg);
3141             arg_add(arg, s);
3142           } else pl->type = 0;
3143         } else {
3144           if (arg->c>1) i -= *arg->v[1]=='(';
3145           if (i>0 && ((i&1)==!!strchr("|)", *s) || strchr(";(", *s)))
3146             goto flush;
3147           if (*s=='&' || !strcmp(s, "||")) goto flush;
3148           if (*s==')') pl = add_pl(ppl, &arg);
3149 
3150           continue;
3151         }
3152       }
3153     }
3154 
3155     // Are we starting a new [function] name [()] definition
3156     if (!pl->type || pl->type=='f') {
3157       if (!pl->type && arg->c==1 && !strcmp(s, "function")) {
3158         free(arg->v[--arg->c]);
3159         arg->v[arg->c] = 0;
3160         pl->type = 'f';
3161         continue;
3162       } else if (arg->c==2 && !strcmp(s, "(")) pl->type = 'f';
3163     }
3164 
3165     // one or both of [function] name[()]
3166     if (pl->type=='f') {
3167       if (arg->v[0][strcspn(*arg->v, "\"'`><;|&$")]) {
3168         s = *arg->v;
3169         goto flush;
3170       }
3171       if (arg->c == 2 && strcmp(s, "(")) goto flush;
3172       if (arg->c == 3) {
3173         if (strcmp(s, ")")) goto flush;
3174         dlist_add(expect, 0);
3175         pl = 0;
3176       }
3177 
3178       continue;
3179 
3180     // is it a line break token?
3181     } else if (strchr(";|&", *s) && strncmp(s, "&>", 2)) {
3182       arg->c--;
3183 
3184       // Connecting nonexistent statements is an error
3185       if (!arg->c || !smemcmp(ex, "do\0A", 4)) goto flush;
3186 
3187       // treat ; as newline so we don't have to check both elsewhere.
3188       if (!strcmp(s, ";")) {
3189         arg->v[arg->c] = 0;
3190         free(s);
3191         s = 0;
3192 // TODO can't have ; between "for i" and in or do. (Newline yes, ; no. Why?)
3193         if (!arg->c && !smemcmp(ex, "do\0C", 4)) continue;
3194 
3195       // ;; and friends only allowed in case statements
3196       } else if (*s == ';') goto flush;
3197       pl->count = -1;
3198 
3199       continue;
3200 
3201     // a for/select must have at least one additional argument on same line
3202     } else if (!smemcmp(ex, "do\0A", 4)) {
3203       // Sanity check and break the segment
3204       if (strncmp(s, "((", 2) && *varend(s)) goto flush;
3205       pl->count = -1;
3206       (*expect)->prev->data = "do\0C";
3207 
3208       continue;
3209 
3210     // flow control is the first word of a pipeline segment
3211     } else if (arg->c>1) {
3212       // Except that [[ ]] is a type 0 segment
3213       if (ex && *ex==']' && !strcmp(s, ex)) free(dlist_lpop(expect));
3214 
3215       continue;
3216     }
3217 
3218     // The "test" part of for/select loops can have (at most) one "in" line,
3219     // for {((;;))|name [in...]} do
3220     if (!smemcmp(ex, "do\0C", 4)) {
3221       if (strcmp(s, "do")) {
3222         // can only have one "in" line between for/do, but not with for(())
3223         if (pl->prev->type == 's') goto flush;
3224         if (!strncmp(pl->prev->arg->v[1], "((", 2)) goto flush;
3225         else if (strcmp(s, "in")) goto flush;
3226         pl->type = 's';
3227 
3228         continue;
3229       }
3230     }
3231 
3232     // start of a new block?
3233 
3234     // for/select/case require var name on same line, can't break segment yet
3235     if (!strcmp(s, "for") || !strcmp(s, "select") || !strcmp(s, "case")) {
3236 // TODO why !pl->type here
3237       if (!pl->type) pl->type = (*s == 'c') ? 128 : 1;
3238       dlist_add(expect, (*s == 'c') ? "esac" : "do\0A");
3239 
3240       continue;
3241     }
3242 
3243     end = 0;
3244     if (!strcmp(s, "if")) end = "then";
3245     else if (!strcmp(s, "while") || !strcmp(s, "until")) end = "do\0B";
3246     else if (!strcmp(s, "{")) end = "}";
3247     else if (!strcmp(s, "(")) end = ")";
3248     else if (!strcmp(s, "[[")) end = "]]";
3249 
3250     // Expecting NULL means any statement (don't care which).
3251     if (!ex && *expect) {
3252       if (pl->prev->type == 'f' && !end && smemcmp(s, "((", 2)) goto flush;
3253       free(dlist_lpop(expect));
3254     }
3255 
3256     // Did we start a new statement
3257     if (end) {
3258       if (*end!=']') pl->type = 1;
3259       else {
3260         // [[ ]] is a type 0 segment, not a flow control block
3261         dlist_add(expect, end);
3262         continue;
3263       }
3264 
3265       // Only innermost statement needed in { { { echo ;} ;} ;} and such
3266       if (*expect && !(*expect)->prev->data) free(dlist_lpop(expect));
3267 
3268     // if not looking for end of statement skip next few tests
3269     } else if (!ex);
3270 
3271     // If we got here we expect a specific word to end this block: is this it?
3272     else if (!strcmp(s, ex)) {
3273       // can't "if | then" or "while && do", only ; & or newline works
3274       if (strcmp(pl->prev->arg->v[pl->prev->arg->c] ? : "&", "&")) goto flush;
3275 
3276       // consume word, record block end in earlier !0 type (non-nested) blocks
3277       free(dlist_lpop(expect));
3278       if (3 == (pl->type = anystr(s, tails) ? 3 : 2)) {
3279         for (i = 0, pl2 = pl3 = pl; (pl2 = pl2->prev);) {
3280           if (pl2->type == 3) i++;
3281           else if (pl2->type) {
3282             if (!i) {
3283               if (pl2->type == 2) {
3284                 pl2->end = pl3;
3285                 pl3 = pl2;   // chain multiple gearshifts for case/esac
3286               } else pl2->end = pl;
3287             }
3288             if (pl2->type == 1 && --i<0) break;
3289           }
3290         }
3291       }
3292 
3293       // if it's a multipart block, what comes next?
3294       if (!strcmp(s, "do")) end = "done";
3295       else if (!strcmp(s, "then")) end = "fi\0A";
3296 
3297     // fi could have elif, which queues a then.
3298     } else if (!strcmp(ex, "fi")) {
3299       if (!strcmp(s, "elif")) {
3300         free(dlist_lpop(expect));
3301         end = "then";
3302       // catch duplicate else while we're here
3303       } else if (!strcmp(s, "else")) {
3304         if (ex[3] != 'A') {
3305           s = "2 else";
3306           goto flush;
3307         }
3308         free(dlist_lpop(expect));
3309         end = "fi\0B";
3310       }
3311     }
3312 
3313     // Queue up the next thing to expect, all preceded by a statement
3314     if (end) {
3315       if (!pl->type) pl->type = 2;
3316 
3317       dlist_add(expect, end);
3318       if (!anystr(end, tails)) dlist_add(expect, 0);
3319       pl->count = -1;
3320     }
3321 
3322     // syntax error check: these can't be the first word in an unexpected place
3323     if (!pl->type && anystr(s, (char *[]){"then", "do", "esac", "}", "]]", ")",
3324         "done", "fi", "elif", "else", 0})) goto flush;
3325   }
3326   free(delete);
3327 
3328   // ignore blank and comment lines
3329   if (!*ppl) return 0;
3330   pl = (*ppl)->prev;
3331 
3332   // return if HERE document pending or more flow control needed to complete
3333   if (pl->count != pl->here) return 1;
3334   if (*expect) return 1;
3335   if (pl->arg->v[pl->arg->c] && strcmp(pl->arg->v[pl->arg->c], "&")) return 1;
3336 
3337   // Transplant completed function bodies into reference counted structures
3338   for (;;) {
3339     if (pl->type=='f') {
3340       struct sh_function *funky;
3341 
3342       // Create sh_function struct, attach to declaration's pipeline segment
3343       funky = xmalloc(sizeof(struct sh_function));
3344       funky->refcount = 1;
3345       funky->name = *pl->arg->v;
3346       *pl->arg->v = (void *)funky;
3347       pl->type = 'F'; // different cleanup
3348 
3349       // Transplant function body into new struct, re-circling both lists
3350       pl2 = pl->next;
3351       // Add NOP 'f' segment (TODO: remove need for this?)
3352       (funky->pipeline = add_pl(&pl2, 0))->type = 'f';
3353       // Find end of block
3354       for (i = 0, pl3 = pl2->next;;pl3 = pl3->next)
3355         if (pl3->type == 1) i++;
3356         else if (pl3->type == 3 && --i<0) break;
3357       // Chop removed segment out of old list.
3358       pl3->next->prev = pl;
3359       pl->next = pl3->next;
3360       // Terminate removed segment.
3361       pl2->prev = 0;
3362       pl3->next = 0;
3363     }
3364     if (pl == *ppl) break;
3365     pl = pl->prev;
3366   }
3367 
3368   // Don't need more input, can start executing.
3369 
3370   dlist_terminate(*ppl);
3371   return 0;
3372 
3373 flush:
3374   if (s) syntax_err(s);
3375   llist_traverse(*ppl, free_pipeline);
3376   *ppl = 0;
3377   llist_traverse(*expect, free);
3378   *expect = 0;
3379 
3380   return 0-!!s;
3381 }
3382 
3383 // Find + and - jobs. Returns index of plus, writes minus to *minus
find_plus_minus(int * minus)3384 int find_plus_minus(int *minus)
3385 {
3386   long long when, then;
3387   int i, plus;
3388 
3389   if (minus) *minus = 0;
3390   for (then = i = plus = 0; i<TT.jobs.c; i++) {
3391     if ((when = ((struct sh_process *)TT.jobs.v[i])->when) > then) {
3392       then = when;
3393       if (minus) *minus = plus;
3394       plus = i;
3395     }
3396   }
3397 
3398   return plus;
3399 }
3400 
is_plus_minus(int i,int plus,int minus)3401 char is_plus_minus(int i, int plus, int minus)
3402 {
3403   return (i == plus) ? '+' : (i == minus) ? '-' : ' ';
3404 }
3405 
3406 
3407 // We pass in dash to avoid looping over every job each time
show_job(struct sh_process * pp,char dash)3408 char *show_job(struct sh_process *pp, char dash)
3409 {
3410   char *s = "Run", *buf = 0;
3411   int i, j, len, len2;
3412 
3413 // TODO Terminated (Exited)
3414   if (pp->exit<0) s = "Stop";
3415   else if (pp->exit>126) s = "Kill";
3416   else if (pp->exit>0) s = "Done";
3417   for (i = len = len2 = 0;; i++) {
3418     len += snprintf(buf, len2, "[%d]%c  %-6s", pp->job, dash, s);
3419     for (j = 0; j<pp->raw->c; j++)
3420       len += snprintf(buf, len2, " %s"+!j, pp->raw->v[j]);
3421     if (!i) buf = xmalloc(len2 = len+1);
3422     else break;
3423   }
3424 
3425   return buf;
3426 }
3427 
3428 // Wait for pid to exit and remove from jobs table, returning process or 0.
wait_job(int pid,int nohang)3429 struct sh_process *wait_job(int pid, int nohang)
3430 {
3431   struct sh_process *pp = pp;
3432   int ii, status, minus, plus;
3433 
3434   if (TT.jobs.c<1) return 0;
3435   for (;;) {
3436     errno = 0;
3437     if (1>(pid = waitpid(pid, &status, nohang ? WNOHANG : 0))) {
3438       if (!nohang && errno==EINTR && !toys.signal) continue;
3439       return 0;
3440     }
3441     for (ii = 0; ii<TT.jobs.c; ii++) {
3442       pp = (void *)TT.jobs.v[ii];
3443       if (pp->pid == pid) break;
3444     }
3445     if (ii == TT.jobs.c) continue;
3446     if (pid<1) return 0;
3447     if (!WIFSTOPPED(status) && !WIFCONTINUED(status)) break;
3448   }
3449   plus = find_plus_minus(&minus);
3450   memmove(TT.jobs.v+ii, TT.jobs.v+ii+1, (TT.jobs.c--)-ii);
3451   pp->exit = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+128;
3452   pp->dash = is_plus_minus(ii, plus, minus);
3453 
3454   return pp;
3455 }
3456 
3457 // wait for every process in a pipeline to end
wait_pipeline(struct sh_process * pp)3458 static int wait_pipeline(struct sh_process *pp)
3459 {
3460   int rc = 0;
3461 
3462   for (dlist_terminate(pp); pp; pp = pp->next) {
3463     if (pp->pid) {
3464       // TODO job control: not xwait, handle EINTR ourselves and check signals
3465       pp->exit = xwaitpid(pp->pid);
3466       pp->pid = 0;
3467     }
3468     // TODO handle set -o pipefail here
3469     rc = (pp->flags&PFLAG_NOT) ? !pp->exit : pp->exit;
3470   }
3471 
3472   while ((pp = wait_job(-1, 1)) && (TT.options&FLAG_i)) {
3473     char *s = show_job(pp, pp->dash);
3474 
3475     dprintf(2, "%s\n", s);
3476     free(s);
3477   }
3478 
3479   return rc;
3480 }
3481 
3482 // Print prompt to stderr, parsing escapes
3483 // Truncated to 4k at the moment, waiting for somebody to complain.
do_prompt(char * prompt)3484 static void do_prompt(char *prompt)
3485 {
3486   char *s, *ss, c, cc, *pp = toybuf;
3487   int len, ll;
3488 
3489   if (!prompt) return;
3490   while ((len = sizeof(toybuf)-(pp-toybuf))>0 && *prompt) {
3491     c = *(prompt++);
3492 
3493     if (c=='!') {
3494       if (*prompt=='!') prompt++;
3495       else {
3496         pp += snprintf(pp, len, "%u", TT.LINENO);
3497         continue;
3498       }
3499     } else if (c=='\\') {
3500       cc = *(prompt++);
3501       if (!cc) {
3502         *pp++ = c;
3503         break;
3504       }
3505 
3506       // \nnn \dD{}hHjlstT@AuvVwW!#$
3507       // Ignore bash's "nonprintable" hack; query our cursor position instead.
3508       if (cc=='[' || cc==']') continue;
3509       else if (cc=='$') *pp++ = getuid() ? '$' : '#';
3510       else if (cc=='h' || cc=='H') {
3511         *pp = 0;
3512         gethostname(pp, len);
3513         pp[len-1] = 0;
3514         if (cc=='h' && (s = strchr(pp, '.'))) *s = 0;
3515         pp += strlen(pp);
3516       } else if (cc=='s') {
3517         s = getbasename(*toys.argv);
3518         while (*s && len--) *pp++ = *s++;
3519       } else if (cc=='w') {
3520         if ((s = getvar("PWD"))) {
3521           if ((ss = getvar("HOME")) && strstart(&s, ss)) {
3522             *pp++ = '~';
3523             if (--len && *s!='/') *pp++ = '/';
3524             len--;
3525           }
3526           if (len>0) {
3527             ll = strlen(s);
3528             pp = stpncpy(pp, s, ll>len ? len : ll);
3529           }
3530         }
3531       } else if (!(c = unescape(cc))) {
3532         *pp++ = '\\';
3533         if (--len) *pp++ = c;
3534       } else *pp++ = c;
3535     } else *pp++ = c;
3536   }
3537   len = pp-toybuf;
3538   if (len>=sizeof(toybuf)) len = sizeof(toybuf);
3539   writeall(2, toybuf, len);
3540 }
3541 
3542 // returns NULL for EOF, 1 for invalid, else null terminated string.
get_next_line(FILE * ff,int prompt)3543 static char *get_next_line(FILE *ff, int prompt)
3544 {
3545   char *new;
3546   int len, cc;
3547 
3548   if (!ff) {
3549     char ps[16];
3550 
3551     sprintf(ps, "PS%d", prompt);
3552     do_prompt(getvar(ps));
3553   }
3554 
3555 // TODO what should ctrl-C do? (also in "select")
3556 // TODO line editing/history, should set $COLUMNS $LINES and sigwinch update
3557 //  TODO: after first EINTR returns closed?
3558 // TODO: ctrl-z during script read having already read partial line,
3559 // SIGSTOP and SIGTSTP need SA_RESTART, but child proc should stop
3560 // TODO if (!isspace(*new)) add_to_history(line);
3561 // TODO: embedded nul bytes need signaling for the "tried to run binary" test.
3562 
3563   for (new = 0, len = 0;;) {
3564     errno = 0;
3565     if (!(cc = getc(ff ? : stdin))) {
3566       if (TT.LINENO) continue;
3567       free(new);
3568       return (char *)1;
3569     }
3570     if (cc<0) {
3571       if (errno == EINTR) continue;
3572       break;
3573     }
3574     if (!(len&63)) new = xrealloc(new, len+65);
3575     if (cc == '\n') break;
3576     new[len++] = cc;
3577   }
3578   if (new) new[len] = 0;
3579 
3580   return new;
3581 }
3582 
3583 /*
3584  TODO: "echo | read i" is backgroundable with ctrl-Z despite read = builtin.
3585        probably have to inline run_command here to do that? Implicit ()
3586        also "X=42 | true; echo $X" doesn't get X.
3587        I.E. run_subshell() here sometimes? (But when?)
3588  TODO: bash supports "break &" and "break > file". No idea why.
3589  TODO If we just started a new pipeline, implicit parentheses (subshell)
3590  TODO can't free sh_process delete until ready to dispose else no debug output
3591  TODO: a | b | c needs subshell for builtins?
3592         - anything that can produce output
3593         - echo declare dirs
3594       (a; b; c) like { } but subshell
3595       when to auto-exec? ps vs sh -c 'ps' vs sh -c '(ps)'
3596 */
3597 
3598 // run a parsed shell function. Handle flow control blocks and characters,
3599 // setup pipes and block redirection, break/continue, call builtins, functions,
3600 // vfork/exec external commands. Return when out of input.
run_lines(void)3601 static void run_lines(void)
3602 {
3603   char *ctl, *s, *ss, **vv;
3604   struct sh_process *pp, *pplist = 0; // processes piping into current level
3605   long i, j, k;
3606 
3607   // iterate through pipeline segments
3608   for (;;) {
3609     if (!TT.ff->pl) {
3610       if (!end_function(1)) break;
3611       goto advance;
3612     }
3613 
3614     ctl = TT.ff->pl->end->arg->v[TT.ff->pl->end->arg->c];
3615     s = *TT.ff->pl->arg->v;
3616     ss = TT.ff->pl->arg->v[1];
3617 //dprintf(2, "%d s=%s ss=%s ctl=%s type=%d pl=%p ff=%p\n", getpid(), (TT.ff->pl->type == 'F') ? ((struct sh_function *)s)->name : s, ss, ctl, TT.ff->pl->type, TT.ff->pl, TT.ff);
3618     if (!pplist) TT.hfd = 10;
3619 
3620     // Skip disabled blocks, handle pipes and backgrounding
3621     if (TT.ff->pl->type<2) {
3622       if (!TT.ff->blk->run) {
3623         TT.ff->pl = TT.ff->pl->end->next;
3624 
3625         continue;
3626       }
3627 
3628       if (TT.options&OPT_x) {
3629         unsigned lineno;
3630         char *ss, *ps4 = getvar("PS4");
3631 
3632         // duplicate first char of ps4 call depth times
3633         if (ps4 && *ps4) {
3634           j = getutf8(ps4, k = strlen(ps4), 0);
3635           ss = xmalloc(TT.srclvl*j+k+1);
3636           for (k = 0; k<TT.srclvl; k++) memcpy(ss+k*j, ps4, j);
3637           strcpy(ss+k*j, ps4+j);
3638           // show saved line number from function, not next to read
3639           lineno = TT.LINENO;
3640           TT.LINENO = TT.ff->pl->lineno;
3641           do_prompt(ss);
3642           TT.LINENO = lineno;
3643           free(ss);
3644 
3645           // TODO resolve variables
3646           ss = pl2str(TT.ff->pl, 1);
3647           dprintf(2, "%s\n", ss);
3648           free(ss);
3649         }
3650       }
3651 
3652       // pipe data into and out of this segment, I.E. leading/trailing |
3653       unredirect(TT.ff->blk->urd);
3654       TT.ff->blk->urd = 0;
3655       TT.ff->blk->pipe = 0;
3656 
3657       // Consume pipe from previous segment as stdin.
3658       if (TT.ff->blk->pout != -1) {
3659         TT.ff->blk->pipe++;
3660         if (save_redirect(&TT.ff->blk->urd, TT.ff->blk->pout, 0)) break;
3661         close(TT.ff->blk->pout);
3662         TT.ff->blk->pout = -1;
3663       }
3664 
3665       // Create output pipe and save next process's stdin in pout
3666       if (ctl && *ctl == '|' && ctl[1] != '|') {
3667         int pipes[2] = {-1, -1};
3668 
3669         TT.ff->blk->pipe++;
3670         if (pipe(pipes)) {
3671           perror_msg("pipe");
3672 
3673           break;
3674         }
3675         if (save_redirect(&TT.ff->blk->urd, pipes[1], 1)) {
3676           close(pipes[0]);
3677           close(pipes[1]);
3678 
3679           break;
3680         }
3681         if (pipes[1] != 1) close(pipes[1]);
3682         fcntl(TT.ff->blk->pout = *pipes, F_SETFD, FD_CLOEXEC);
3683         if (ctl[1] == '&') save_redirect(&TT.ff->blk->urd, 1, 2);
3684       }
3685     }
3686 
3687     // Is this an executable segment?
3688     if (!TT.ff->pl->type) {
3689       // Is it a flow control jump? These aren't handled as normal builtins
3690       // because they move *pl to other pipeline segments which is local here.
3691       if (!strcmp(s, "break") || !strcmp(s, "continue")) {
3692 
3693         // How many layers to peel off?
3694         i = ss ? atol(ss) : 0;
3695         if (i<1) i = 1;
3696         if (TT.ff->blk->next && TT.ff->pl->arg->c<3
3697             && (!ss || !ss[strspn(ss,"0123456789")]))
3698         {
3699           while (i && TT.ff->blk->next)
3700             if (TT.ff->blk->middle && !strcmp(*TT.ff->blk->middle->arg->v, "do")
3701               && !--i && *s=='c') TT.ff->pl = TT.ff->blk->start;
3702             else TT.ff->pl = pop_block();
3703         }
3704         if (i) {
3705           syntax_err(s);
3706           break;
3707         }
3708       // Parse and run next command, saving resulting process
3709       } else dlist_add_nomalloc((void *)&pplist, (void *)run_command());
3710 
3711     // Start of flow control block?
3712     } else if (TT.ff->pl->type == 1) {
3713 
3714 // TODO test cat | {thingy} is new PID: { is ( for |
3715 
3716       // perform/save trailing redirects
3717       pp = expand_redir(TT.ff->pl->end->arg, 1, TT.ff->blk->urd);
3718       TT.ff->blk->urd = pp->urd;
3719       pp->urd = 0;
3720       if (pp->arg.c) syntax_err(*pp->arg.v);
3721       llist_traverse(pp->delete, llist_free_arg);
3722       pp->delete = 0;
3723       if (pp->exit || pp->arg.c) {
3724         free(pp);
3725         toys.exitval = 1;
3726 
3727         break;
3728       }
3729       add_block();
3730 
3731 // TODO test background a block: { abc; } &
3732 
3733       // If we spawn a subshell, pass data off to child process
3734       if (TT.ff->blk->next->pipe || !strcmp(s, "(") || (ctl && !strcmp(ctl, "&"))) {
3735         if (!(pp->pid = run_subshell(0, -1))) {
3736 
3737           // zap forked child's cleanup context and advance to next statement
3738           pplist = 0;
3739           while (TT.ff->blk->next) TT.ff->blk = TT.ff->blk->next;
3740           TT.ff->blk->pout = -1;
3741           TT.ff->blk->urd = 0;
3742           TT.ff->pl = TT.ff->next->pl->next;
3743 
3744           continue;
3745         }
3746         TT.ff->pl = TT.ff->pl->end;
3747         pop_block();
3748         dlist_add_nomalloc((void *)&pplist, (void *)pp);
3749 
3750       // handle start of block in this process
3751       } else {
3752         free(pp);
3753 
3754         // What flow control statement is this?
3755 
3756         // {/} if/then/elif/else/fi, while until/do/done - no special handling
3757 
3758         // for/select/do/done: populate blk->farg with expanded args (if any)
3759         if (!strcmp(s, "for") || !strcmp(s, "select")) {
3760           if (TT.ff->blk->loop); // skip init, not first time through loop
3761 
3762           // in (;;)
3763           else if (!strncmp(TT.ff->blk->fvar = ss, "((", 2)) {
3764             char *in = ss+2, *out;
3765             long long ll;
3766 
3767             TT.ff->blk->loop = 1;
3768             for (i = 0; i<3; i++) {
3769               if (i==2) k = strlen(in)-2;
3770               else {
3771                 // perform expansion but immediately discard it to find ;
3772                 k = ';';
3773                 pp = xzalloc(sizeof(*pp));
3774                 if (expand_arg_nobrace(&pp->arg, ss+2, NO_PATH|NO_SPLIT,
3775                     &pp->delete, 0, &k)) break;
3776                 free_process(pp);
3777                 if (in[k] != ';') break;
3778               }
3779               (out = xmalloc(k+1))[k] = 0;
3780               memcpy(out, in, k);
3781               arg_add(&TT.ff->blk->farg, push_arg(&TT.ff->blk->fdelete, out));
3782               in += k+1;
3783             }
3784             if (i!=3) {
3785               syntax_err(ss);
3786               break;
3787             }
3788             in = out = *TT.ff->blk->farg.v;
3789             if (!recalculate(&ll, &in, 0) || *in) {
3790               perror_msg("bad math: %s @ %ld", in, (long)(in-out));
3791               break;
3792             }
3793 
3794           // in LIST
3795           } else if (TT.ff->pl->next->type == 's') {
3796             for (i = 1; i<TT.ff->pl->next->arg->c; i++)
3797               if (expand_arg(&TT.ff->blk->farg, TT.ff->pl->next->arg->v[i],
3798                              0, &TT.ff->blk->fdelete)) break;
3799             if (i != TT.ff->pl->next->arg->c) TT.ff->pl = pop_block();
3800 
3801           // in without LIST. (This expansion can't return error.)
3802           } else expand_arg(&TT.ff->blk->farg, "\"$@\"", 0,
3803                             &TT.ff->blk->fdelete);
3804 
3805           // TODO: ls -C style output
3806           if (*s == 's') for (i = 0; i<TT.ff->blk->farg.c; i++)
3807             dprintf(2, "%ld) %s\n", i+1, TT.ff->blk->farg.v[i]);
3808 
3809         // TODO: bash man page says it performs <(process substituion) here?!?
3810         } else if (!strcmp(s, "case")) {
3811           TT.ff->blk->fvar = expand_one_arg(ss, NO_NULL, &TT.ff->blk->fdelete);
3812           if (!TT.ff->blk->fvar) break;
3813         }
3814 
3815 // TODO [[/]] ((/)) function/}
3816       }
3817 
3818     // gearshift from block start to block body (end of flow control test)
3819     } else if (TT.ff->pl->type == 2) {
3820       int match, err;
3821 
3822       TT.ff->blk->middle = TT.ff->pl;
3823 
3824       // ;; end, ;& continue through next block, ;;& test next block
3825       if (!strcmp(*TT.ff->blk->start->arg->v, "case")) {
3826         if (!strcmp(s, ";;")) {
3827           while (TT.ff->pl->type!=3) TT.ff->pl = TT.ff->pl->end;
3828           continue;
3829         } else if (strcmp(s, ";&")) {
3830           struct sh_arg arg = {0}, arg2 = {0};
3831 
3832           for (err = 0, vv = 0;;) {
3833             if (!vv) {
3834               vv = TT.ff->pl->arg->v + (**TT.ff->pl->arg->v == ';');
3835               if (!*vv) {
3836                 // TODO syntax err if not type==3, catch above
3837                 TT.ff->pl = TT.ff->pl->next;
3838                 break;
3839               } else vv += **vv == '(';
3840             }
3841             arg.c = arg2.c = 0;
3842             if ((err = expand_arg_nobrace(&arg, *vv++, NO_SPLIT,
3843               &TT.ff->blk->fdelete, &arg2, 0))) break;
3844             s = arg.c ? *arg.v : "";
3845             match = wildcard_match(TT.ff->blk->fvar, s, &arg2, 0);
3846             if (match>=0 && !s[match]) break;
3847             else if (**vv++ == ')') {
3848               vv = 0;
3849               if ((TT.ff->pl = TT.ff->pl->end)->type!=2) break;
3850             }
3851           }
3852           free(arg.v);
3853           free(arg2.v);
3854           if (err) break;
3855           if (TT.ff->pl->type==3) continue;
3856         }
3857 
3858       // Handle if/else/elif statement
3859       } else if (!strcmp(s, "then"))
3860         TT.ff->blk->run = TT.ff->blk->run && !toys.exitval;
3861       else if (!strcmp(s, "else") || !strcmp(s, "elif"))
3862         TT.ff->blk->run = !TT.ff->blk->run;
3863 
3864       // Loop
3865       else if (!strcmp(s, "do")) {
3866         struct sh_blockstack *blk = TT.ff->blk;
3867 
3868         ss = *blk->start->arg->v;
3869         if (!strcmp(ss, "while")) blk->run = blk->run && !toys.exitval;
3870         else if (!strcmp(ss, "until")) blk->run = blk->run && toys.exitval;
3871         else if (!strcmp(ss, "select")) {
3872           if (!(ss = get_next_line(0, 3)) || ss==(void *)1) {
3873             TT.ff->pl = pop_block();
3874             printf("\n");
3875           } else {
3876             match = atoi(ss);
3877             free(ss);
3878             if (!*ss) {
3879               TT.ff->pl = blk->start;
3880               continue;
3881             } else setvarval(blk->fvar, (match<1 || match>blk->farg.c)
3882                                         ? "" : blk->farg.v[match-1]);
3883           }
3884         } else if (blk->loop >= blk->farg.c) TT.ff->pl = pop_block();
3885         else if (!strncmp(blk->fvar, "((", 2)) {
3886           char *aa, *bb;
3887           long long ll;
3888 
3889           for (i = 2; i; i--) {
3890             if (TT.ff->blk->loop == 1) {
3891               TT.ff->blk->loop++;
3892               i--;
3893             }
3894             aa = bb = TT.ff->blk->farg.v[i];
3895             if (!recalculate(&ll, &aa, 0) || *aa) {
3896               perror_msg("bad math: %s @ %ld", aa, (long)(aa-bb));
3897               break;
3898             }
3899             if (i==1 && !ll) TT.ff->pl = pop_block();
3900           }
3901         } else setvarval(blk->fvar, blk->farg.v[blk->loop++]);
3902       }
3903 
3904     // end of block
3905     } else if (TT.ff->pl->type == 3) {
3906       // If we end a block we're not in, exit subshell
3907       if (!TT.ff->blk->next) xexit();
3908 
3909       // repeating block?
3910       if (TT.ff->blk->run && !strcmp(s, "done")) {
3911         TT.ff->pl = TT.ff->blk->middle;
3912         continue;
3913       }
3914 
3915       // cleans up after trailing redirections/pipe
3916       pop_block();
3917 
3918     // declare a shell function
3919     } else if (TT.ff->pl->type == 'F') {
3920       struct sh_function *funky = (void *)*TT.ff->pl->arg->v;
3921 
3922 // TODO binary search
3923       for (i = 0; i<TT.funcslen; i++)
3924         if (!strcmp(TT.functions[i]->name, funky->name)) break;
3925       if (i == TT.funcslen) {
3926         struct sh_arg arg = {(void *)TT.functions, TT.funcslen};
3927 
3928         arg_add(&arg, (void *)funky); // TODO possibly an expand@31 function?
3929         TT.functions = (void *)arg.v;
3930         TT.funcslen++;
3931       } else {
3932         free_function(TT.functions[i]);
3933         TT.functions[i] = funky;
3934       }
3935       TT.functions[i]->refcount++;
3936     }
3937 
3938     // Three cases: 1) background & 2) pipeline | 3) last process in pipeline ;
3939     // If we ran a process and didn't pipe output, background or wait for exit
3940     if (pplist && TT.ff->blk->pout == -1) {
3941       if (ctl && !strcmp(ctl, "&")) {
3942         if (!TT.jobs.c) TT.jobcnt = 0;
3943         pplist->job = ++TT.jobcnt;
3944         arg_add(&TT.jobs, (void *)pplist);
3945         if (TT.options&FLAG_i) dprintf(2, "[%u] %u\n", pplist->job,pplist->pid);
3946       } else {
3947         toys.exitval = wait_pipeline(pplist);
3948         llist_traverse(pplist, (void *)free_process);
3949       }
3950       pplist = 0;
3951     }
3952 advance:
3953     // for && and || skip pipeline segment(s) based on return code
3954     if (!TT.ff->pl->type || TT.ff->pl->type == 3) {
3955       for (;;) {
3956         ctl = TT.ff->pl->arg->v[TT.ff->pl->arg->c];
3957         if (!ctl || strcmp(ctl, toys.exitval ? "&&" : "||")) break;
3958         if ((TT.ff->pl = TT.ff->pl->next)->type) TT.ff->pl = TT.ff->pl->end;
3959       }
3960     }
3961     TT.ff->pl = TT.ff->pl->next;
3962   }
3963 
3964   // clean up any unfinished stuff
3965   if (pplist) {
3966     toys.exitval = wait_pipeline(pplist);
3967     llist_traverse(pplist, (void *)free_process);
3968   }
3969 
3970   // exit source context (and function calls on syntax err)
3971   while (end_function(0));
3972 }
3973 
3974 // set variable
initvar(char * name,char * val)3975 static struct sh_vars *initvar(char *name, char *val)
3976 {
3977   return addvar(xmprintf("%s=%s", name, val ? val : ""), TT.ff);
3978 }
3979 
initvardef(char * name,char * val,char * def)3980 static struct sh_vars *initvardef(char *name, char *val, char *def)
3981 {
3982   return initvar(name, (!val || !*val) ? def : val);
3983 }
3984 
3985 // export existing "name" or assign/export name=value string (making new copy)
set_varflags(char * str,unsigned set_flags,unsigned unset_flags)3986 static void set_varflags(char *str, unsigned set_flags, unsigned unset_flags)
3987 {
3988   struct sh_vars *shv = 0;
3989   struct sh_fcall *ff;
3990   char *s;
3991 
3992   // Make sure variable exists and is updated
3993   if (strchr(str, '=')) shv = setvar(xstrdup(str));
3994   else if (!(shv = findvar(str, &ff))) {
3995     if (!set_flags) return;
3996     shv = addvar(str = xmprintf("%s=", str), TT.ff->prev);
3997     shv->flags = VAR_WHITEOUT;
3998   } else if (shv->flags&VAR_WHITEOUT) shv->flags |= VAR_EXPORT;
3999   if (!shv || (shv->flags&VAR_EXPORT)) return;
4000 
4001   // Resolve magic for export (bash bug compatibility, really should be dynamic)
4002   if (shv->flags&VAR_MAGIC) {
4003     s = shv->str;
4004     shv->str = xmprintf("%.*s=%s", (int)(varend(str)-str), str, getvar(str));
4005     if (!(shv->flags&VAR_NOFREE)) free(s);
4006     else shv->flags ^= VAR_NOFREE;
4007   }
4008   shv->flags |= set_flags;
4009   shv->flags &= ~unset_flags;
4010 }
4011 
export(char * str)4012 static void export(char *str)
4013 {
4014   set_varflags(str, VAR_EXPORT, 0);
4015 }
4016 
fpathopen(char * name)4017 FILE *fpathopen(char *name)
4018 {
4019   struct string_list *sl = 0;
4020   FILE *f = fopen(name, "r");
4021   char *pp = getvar("PATH") ? : _PATH_DEFPATH;
4022 
4023   if (!f) {
4024     for (sl = find_in_path(pp, name); sl; free(llist_pop(&sl)))
4025       if ((f = fopen(sl->str, "r"))) break;
4026     if (sl) llist_traverse(sl, free);
4027   }
4028 
4029   return f;
4030 }
4031 
4032 // Read script input and execute lines, with or without prompts
do_source(char * name,FILE * ff)4033 int do_source(char *name, FILE *ff)
4034 {
4035   struct sh_pipeline *pl = 0;
4036   struct double_list *expect = 0;
4037   unsigned lineno = TT.LINENO, more = 0, wc;
4038   int cc, ii;
4039   char *new;
4040 
4041   if (++TT.recursion>(50+200*CFG_TOYBOX_FORK)) {
4042     error_msg("recursive occlusion");
4043 
4044     goto end;
4045   }
4046 
4047   if (name) TT.ff->omnom = name;
4048 
4049 // TODO fix/catch NONBLOCK on input?
4050 // TODO when DO we reset lineno? (!LINENO means \0 returns 1)
4051 // when do we NOT reset lineno? Inherit but preserve perhaps? newline in $()?
4052   if (!name) TT.LINENO = 0;
4053 
4054   do {
4055     if ((void *)1 == (new = get_next_line(ff, more+1))) goto is_binary;
4056 //dprintf(2, "%d getline from %p %s\n", getpid(), ff, new); debug_show_fds();
4057     // did we exec an ELF file or something?
4058     if (!TT.LINENO++ && name && new) {
4059       // A shell script's first line has no high bytes that aren't valid utf-8.
4060       for (ii = 0; new[ii]>6 && 0<(cc = utf8towc(&wc, new+ii, 4)); ii += cc);
4061       if (new[ii]) {
4062 is_binary:
4063         if (name) error_msg("'%s' is binary", name); // TODO syntax_err() exit?
4064         if (new != (void *)1) free(new);
4065         new = 0;
4066       }
4067     }
4068 
4069     // TODO: source <(echo 'echo hello\') vs source <(echo -n 'echo hello\')
4070     // prints "hello" vs "hello\"
4071 
4072     // returns 0 if line consumed, command if it needs more data
4073     more = parse_line(new ? : " ", &pl, &expect);
4074     free(new);
4075     if (more==1) {
4076       if (!new) syntax_err("unexpected end of file");
4077       else continue;
4078     } else if (!more && pl) {
4079       TT.ff->pl = pl;
4080       run_lines();
4081     } else more = 0;
4082 
4083     llist_traverse(pl, free_pipeline);
4084     pl = 0;
4085     llist_traverse(expect, free);
4086     expect = 0;
4087   } while (new);
4088 
4089   if (ff) fclose(ff);
4090 
4091   if (!name) TT.LINENO = lineno;
4092 
4093 end:
4094   TT.recursion--;
4095 
4096   return more;
4097 }
4098 
4099 // On nommu we had to exec(), so parent environment is passed via a pipe.
nommu_reentry(void)4100 static void nommu_reentry(void)
4101 {
4102   struct stat st;
4103   int ii, pid, ppid, len;
4104   unsigned long ll;
4105   char *s = 0;
4106   FILE *fp;
4107 
4108   // Sanity check
4109   if (!fstat(254, &st) && S_ISFIFO(st.st_mode)) {
4110     for (ii = len = 0; (s = environ[ii]); ii++) {
4111       if (*s!='@') continue;
4112       sscanf(s, "@%u,%u%n", &pid, &ppid, &len);
4113       break;
4114     }
4115   }
4116   if (!s || s[len] || pid!=getpid() || ppid!=getppid()) error_exit(0);
4117 
4118 // TODO signal setup before this so fscanf can't EINTR.
4119 // TODO marshall TT.jobcnt TT.funcslen: child needs jobs and function list
4120   // Marshall magics: $SECONDS $- $LINENO $$ $!
4121   if (5!=fscanf(fp = fdopen(254, "r"), "%lld %u %u %u %u%*[^\n]", &TT.SECONDS,
4122       &TT.options, &TT.LINENO, &TT.pid, &TT.bangpid)) error_exit(0);
4123 
4124   // Read named variables: type, len, var=value\0
4125   for (;;) {
4126     len = ll = 0;
4127     (void)fscanf(fp, "%u %lu%*[^\n]", &len, &ll);
4128     fgetc(fp); // Discard the newline fscanf didn't eat.
4129     if (!len) break;
4130     (s = xmalloc(len+1))[len] = 0;
4131     for (ii = 0; ii<len; ii += pid)
4132       if (1>(pid = fread(s+ii, 1, len-ii, fp))) error_exit(0);
4133     set_varflags(s, ll, 0);
4134   }
4135 
4136   // Perform subshell command(s)
4137   do_source(0, fp);
4138   xexit();
4139 }
4140 
4141 // init locals, sanitize environment, handle nommu subshell handoff
subshell_setup(void)4142 static void subshell_setup(void)
4143 {
4144   int ii, from, uid = getuid();
4145   struct passwd *pw = getpwuid(uid);
4146   char *s, *ss, *magic[] = {"SECONDS", "RANDOM", "LINENO", "GROUPS", "BASHPID",
4147     "EPOCHREALTIME", "EPOCHSECONDS"},
4148     *readonly[] = {xmprintf("EUID=%d", geteuid()), xmprintf("UID=%d", uid),
4149                    xmprintf("PPID=%d", getppid())};
4150   struct sh_vars *shv;
4151   struct utsname uu;
4152 
4153   // Initialize magic and read only local variables
4154   for (ii = 0; ii<ARRAY_LEN(magic) && (s = magic[ii]); ii++)
4155     initvar(s, "")->flags = VAR_MAGIC+VAR_INT*('G'!=*s)+VAR_READONLY*('B'==*s);
4156   for (ii = 0; ii<ARRAY_LEN(readonly); ii++)
4157     addvar(readonly[ii], TT.ff)->flags = VAR_READONLY|VAR_INT;
4158 
4159   // Add local variables that can be overwritten
4160   initvar("PATH", _PATH_DEFPATH);
4161   if (!pw) pw = (void *)toybuf; // first use, so still zeroed
4162   sprintf(toybuf+1024, "%u", uid);
4163   initvardef("HOME", pw->pw_dir, "/");
4164   initvardef("SHELL", pw->pw_shell, "/bin/sh");
4165   initvardef("USER", pw->pw_name, toybuf+1024);
4166   initvardef("LOGNAME", pw->pw_name, toybuf+1024);
4167   gethostname(toybuf, sizeof(toybuf)-1);
4168   initvar("HOSTNAME", toybuf);
4169   uname(&uu);
4170   initvar("HOSTTYPE", uu.machine);
4171   sprintf(toybuf, "%s-unknown-linux", uu.machine);
4172   initvar("MACHTYPE", toybuf);
4173   initvar("OSTYPE", uu.sysname);
4174   // sprintf(toybuf, "%s-toybox", TOYBOX_VERSION);
4175   // initvar("BASH_VERSION", toybuf); TODO
4176   initvar("OPTERR", "1"); // TODO: test if already exported?
4177   if (readlink0("/proc/self/exe", s = toybuf, sizeof(toybuf))||(s=getenv("_")))
4178     initvar("BASH", s);
4179   initvar("PS2", "> ");
4180   initvar("PS3", "#? ");
4181   initvar("PS4", "+ ");
4182 
4183   // Ensure environ copied and toys.envc set, and clean out illegal entries
4184   for (from = 0; (s = environ[from]); from++) {
4185     if (*varend(s) != '=') continue;
4186     if (!(shv = findvar(s, 0))) addvar(s, TT.ff)->flags = VAR_EXPORT|VAR_NOFREE;
4187     else if (shv->flags&VAR_READONLY) continue;
4188     else {
4189       if (!(shv->flags&VAR_NOFREE)) {
4190         free(shv->str);
4191         shv->flags ^= VAR_NOFREE;
4192       }
4193       shv->flags |= VAR_EXPORT;
4194       shv->str = s;
4195     }
4196     cache_ifs(s, TT.ff); // TODO: replace with set(get("IFS")) after loop
4197   }
4198 
4199   // set/update PWD
4200   do_source(0, fmemopen("cd .", 4, "r"));
4201 
4202   // set _ to path to this shell
4203   s = toys.argv[0];
4204   ss = 0;
4205   if (!strchr(s, '/')) {
4206     if ((ss = getcwd(0, 0))) {
4207       s = xmprintf("%s/%s", ss, s);
4208       free(ss);
4209       ss = s;
4210     } else if (*toybuf) s = toybuf; // from /proc/self/exe
4211   }
4212   setvarval("_", s)->flags |= VAR_EXPORT;
4213   free(ss);
4214 
4215   // TODO: this is in pipe, not environment
4216   if (!(ss = getvar("SHLVL"))) export("SHLVL=1"); // Bash 5.0
4217   else {
4218     char buf[16];
4219 
4220     sprintf(buf, "%u", atoi(ss+6)+1);
4221     setvarval("SHLVL", buf)->flags |= VAR_EXPORT;
4222   }
4223 }
4224 
sh_main(void)4225 void sh_main(void)
4226 {
4227   char *cc = 0;
4228   FILE *ff;
4229 
4230 //unsigned uu; dprintf(2, "%d main", getpid()); for (uu = 0; toys.argv[uu]; uu++) dprintf(2, " %s", toys.argv[uu]); dprintf(2, "\n");
4231 
4232   signal(SIGPIPE, SIG_IGN);
4233   TT.options = OPT_B;
4234   TT.pid = getpid();
4235   srandom(TT.SECONDS = millitime());
4236 
4237   // TODO euid stuff?
4238   // TODO login shell?
4239   // TODO read profile, read rc
4240 
4241   // if (!FLAG(noprofile)) { }
4242 
4243   // If not reentering, figure out if this is an interactive shell.
4244   if (toys.stacktop) {
4245     cc = TT.sh.c;
4246     if (!FLAG(c)) {
4247       if (toys.optc==1) toys.optflags |= FLAG_s;
4248       if (FLAG(s) && isatty(0)) toys.optflags |= FLAG_i;
4249     }
4250     if (toys.optc>1) {
4251       toys.optargs++;
4252       toys.optc--;
4253     }
4254     TT.options |= toys.optflags&0xff;
4255   }
4256 
4257   // Create initial function context
4258   call_function();
4259   TT.ff->arg.v = toys.optargs;
4260   TT.ff->arg.c = toys.optc;
4261   TT.ff->ifs = " \t\n";
4262 
4263   // Set up environment variables.
4264   // Note: can call run_command() which blanks argument sections of TT and this,
4265   // so parse everything we need from shell command line before here.
4266   if (CFG_TOYBOX_FORK || toys.stacktop) subshell_setup(); // returns
4267   else nommu_reentry(); // does not return
4268 
4269   if (TT.options&FLAG_i) {
4270     if (!getvar("PS1")) setvarval("PS1", getpid() ? "\\$ " : "# ");
4271     // TODO Set up signal handlers and grab control of this tty.
4272     // ^C SIGINT ^\ SIGQUIT ^Z SIGTSTP SIGTTIN SIGTTOU SIGCHLD
4273     // setsid(), setpgid(), tcsetpgrp()...
4274     xsignal(SIGINT, SIG_IGN);
4275   }
4276 
4277   if (cc) ff = fmemopen(cc, strlen(cc), "r");
4278   else if (TT.options&FLAG_s) ff = (TT.options&FLAG_i) ? 0 : stdin;
4279   else if (!(ff = fpathopen(*toys.optargs))) perror_exit_raw(*toys.optargs);
4280 
4281   // Read and execute lines from file
4282   if (do_source(cc ? : *toys.optargs, ff))
4283     error_exit("%u:unfinished line"+3*!TT.LINENO, TT.LINENO);
4284 }
4285 
4286 // TODO: ./blah.sh one two three: put one two three in scratch.arg
4287 
4288 /********************* shell builtin functions *************************/
4289 
4290 #define FOR_cd
4291 #include "generated/flags.h"
cd_main(void)4292 void cd_main(void)
4293 {
4294   char *from, *to = 0, *dd = *toys.optargs ? : (getvar("HOME") ? : "/"),
4295        *pwd = FLAG(P) ? 0 : getvar("PWD"), *zap = 0;
4296   struct stat st1, st2;
4297 
4298   // TODO: CDPATH? Really?
4299 
4300   // For cd - use $OLDPWD as destination directory
4301   if (!strcmp(dd, "-") && (!(dd = getvar("OLDPWD")) || !*dd))
4302     return perror_msg("No $OLDPWD");
4303 
4304   if (*dd == '/') pwd = 0;
4305 
4306   // Did $PWD move out from under us?
4307   if (pwd && !stat(".", &st1))
4308     if (stat(pwd, &st2) || st1.st_dev!=st2.st_dev || st1.st_ino!=st2.st_ino)
4309       pwd = 0;
4310 
4311   // Handle logical relative path
4312   if (pwd) {
4313     zap = xmprintf("%s/%s", pwd, dd);
4314 
4315     // cancel out . and .. in the string
4316     for (from = to = zap; *from;) {
4317       if (*from=='/' && from[1]=='/') from++;
4318       else if (*from!='/' || from[1]!='.') *to++ = *from++;
4319       else if (!from[2] || from[2]=='/') from += 2;
4320       else if (from[2]=='.' && (!from[3] || from[3]=='/')) {
4321         from += 3;
4322         while (to>zap && *--to != '/');
4323       } else *to++ = *from++;
4324     }
4325     if (to == zap) to++;
4326     if (to-zap>1 && to[-1]=='/') to--;
4327     *to = 0;
4328   }
4329 
4330   // If logical chdir doesn't work, fall back to physical
4331   if (!zap || chdir(zap)) {
4332     free(zap);
4333     if (chdir(dd)) return perror_msg("%s", dd);
4334     if (!(dd = getcwd(0, 0))) dd = xstrdup("(nowhere)");
4335   } else dd = zap;
4336 
4337   if ((pwd = getvar("PWD"))) setvarval("OLDPWD", pwd);
4338   setvarval("PWD", dd);
4339   free(dd);
4340 
4341   if (!(TT.options&OPT_cd)) {
4342     export("OLDPWD");
4343     export("PWD");
4344     TT.options |= OPT_cd;
4345   }
4346 }
4347 
exit_main(void)4348 void exit_main(void)
4349 {
4350   exit(*toys.optargs ? atoi(*toys.optargs) : 0);
4351 }
4352 
4353 // lib/args.c can't +prefix & "+o history" needs space so parse cmdline here
set_main(void)4354 void set_main(void)
4355 {
4356   char *cc, *ostr[] = {"braceexpand", "noclobber", "xtrace"};
4357   int ii, jj, kk, oo = 0, dd = 0;
4358 
4359   // display visible variables
4360   if (!*toys.optargs) {
4361     struct sh_vars **vv = visible_vars();
4362 
4363 // TODO escape properly
4364     for (ii = 0; vv[ii]; ii++)
4365       if (!(vv[ii]->flags&VAR_WHITEOUT)) printf("%s\n", vv[ii]->str);
4366     free(vv);
4367 
4368     return;
4369   }
4370 
4371   // Handle options
4372   for (ii = 0;; ii++) {
4373     if ((cc = toys.optargs[ii]) && !(dd = stridx("-+", *cc)+1) && oo--) {
4374       for (jj = 0; jj<ARRAY_LEN(ostr); jj++) if (!strcmp(cc, ostr[jj])) break;
4375       if (jj != ARRAY_LEN(ostr)) {
4376         if (dd==1) TT.options |= OPT_B<<kk;
4377         else TT.options &= ~(OPT_B<<kk);
4378 
4379         continue;
4380       }
4381       error_exit("bad -o %s", cc);
4382     }
4383     if (oo>0) for (jj = 0; jj<ARRAY_LEN(ostr); jj++)
4384       printf("%s\t%s\n", ostr[jj], TT.options&(OPT_B<<jj) ? "on" : "off");
4385     oo = 0;
4386     if (!cc || !dd) break;
4387     for (jj = 1; cc[jj]; jj++) {
4388       if (cc[jj] == 'o') oo++;
4389       else if (-1 != (kk = stridx("BCx", cc[jj]))) {
4390         if (*cc == '-') TT.options |= OPT_B<<kk;
4391         else TT.options &= ~(OPT_B<<kk);
4392       } else error_exit("bad -%c", toys.optargs[ii][1]);
4393     }
4394   }
4395 
4396   // handle positional parameters
4397   if (cc) {
4398     struct arg_list *al, **head;
4399     struct sh_arg *arg = &TT.ff->arg;
4400 
4401     // don't free memory that's already scheduled for deletion
4402     for (al = *(head = &TT.ff->delete); al; al = *(head = &al->next))
4403       if (al->arg == (void *)arg->v) break;
4404 
4405     // free last set's memory (if any) so it doesn't accumulate in loop
4406     if (al) for (jj = arg->c+1; jj; jj--) {
4407       *head = al->next;
4408       free(al->arg);
4409       free(al);
4410     }
4411 
4412     while (toys.optargs[ii])
4413       arg_add(arg, push_arg(&TT.ff->delete, strdup(toys.optargs[ii++])));
4414     push_arg(&TT.ff->delete, arg->v);
4415   }
4416 }
4417 
4418 // TODO need test: unset clears var first and stops, function only if no var.
4419 #define FOR_unset
4420 #include "generated/flags.h"
4421 
unset_main(void)4422 void unset_main(void)
4423 {
4424   char **arg, *s;
4425   int ii;
4426 
4427   for (arg = toys.optargs; *arg; arg++) {
4428     s = varend(*arg);
4429     if (s == *arg || *s) {
4430       error_msg("bad '%s'", *arg);
4431       continue;
4432     }
4433 
4434     // TODO -n and name reference support
4435     // unset variable
4436     if (!FLAG(f) && unsetvar(*arg)) continue;
4437     // unset function TODO binary search
4438     for (ii = 0; ii<TT.funcslen; ii++)
4439       if (!strcmp(*arg, TT.functions[ii]->name)) break;
4440     if (ii != TT.funcslen) {
4441       free_function(TT.functions[ii]);
4442       memmove(TT.functions+ii, TT.functions+ii+1, TT.funcslen+1-ii);
4443     }
4444   }
4445 }
4446 
4447 #define FOR_export
4448 #include "generated/flags.h"
4449 
export_main(void)4450 void export_main(void)
4451 {
4452   char **arg, *eq;
4453 
4454   // list existing variables?
4455   if (!toys.optc) {
4456     struct sh_vars **vv = visible_vars();
4457     unsigned uu;
4458 
4459     for (uu = 0; vv[uu]; uu++) {
4460       if ((vv[uu]->flags&(VAR_WHITEOUT|VAR_EXPORT))==VAR_EXPORT) {
4461         xputs(eq = declarep(vv[uu]));
4462         free(eq);
4463       }
4464     }
4465     free(vv);
4466 
4467     return;
4468   }
4469 
4470   // set/move variables
4471   for (arg = toys.optargs; *arg; arg++) {
4472     eq = varend(*arg);
4473     if (eq == *arg || (*eq && eq[*eq=='+'] != '=')) {
4474       error_msg("bad %s", *arg);
4475       continue;
4476     }
4477 
4478     if (FLAG(n)) set_varflags(*arg, 0, VAR_EXPORT);
4479     else export(*arg);
4480   }
4481 }
4482 
4483 #define FOR_declare
4484 #include "generated/flags.h"
4485 
declare_main(void)4486 void declare_main(void)
4487 {
4488   unsigned uu, fl = toys.optflags&(FLAG(p)-1);
4489   char *ss, **arg;
4490 // TODO: need a show_vars() to collate all the visible_vars() loop output
4491 // TODO: -g support including -gp
4492 // TODO: dump everything key=value and functions too
4493   if (!toys.optc) {
4494     struct sh_vars **vv = visible_vars();
4495 
4496     for (uu = 0; vv[uu]; uu++) {
4497       if ((vv[uu]->flags&VAR_WHITEOUT) || (fl && !(vv[uu]->flags&fl))) continue;
4498       xputs(ss = declarep(vv[uu]));
4499       free(ss);
4500     }
4501     free(vv);
4502   } else if (FLAG(p)) for (arg = toys.optargs; *arg; arg++) {
4503     struct sh_vars *vv = *varend(ss = *arg) ? 0 : findvar(ss, 0);
4504 
4505     if (!vv) perror_msg("%s: not found", ss);
4506     else {
4507       xputs(ss = declarep(vv));
4508       free(ss);
4509     }
4510   } else for (arg = toys.optargs; *arg; arg++) {
4511     ss = varend(*arg);
4512     if (ss == *arg || (*ss && ss[*ss=='+'] != '=')) {
4513       error_msg("bad %s", *arg);
4514       continue;
4515     }
4516     set_varflags(*arg, toys.optflags<<1, 0); // TODO +x unset
4517   }
4518 }
4519 
eval_main(void)4520 void eval_main(void)
4521 {
4522   char *s;
4523 
4524   // borrow the $* expand infrastructure
4525   call_function();
4526   TT.ff->arg.v = toys.argv;
4527   TT.ff->arg.c = toys.optc+1;
4528   s = expand_one_arg("\"$*\"", SEMI_IFS, 0);
4529   TT.ff->arg.v = TT.ff->next->arg.v;
4530   TT.ff->arg.c = TT.ff->next->arg.c;
4531   do_source(0, fmemopen(s, strlen(s), "r"));
4532   free(dlist_pop(&TT.ff));
4533   free(s);
4534 }
4535 
4536 #define FOR_exec
4537 #include "generated/flags.h"
4538 
exec_main(void)4539 void exec_main(void)
4540 {
4541   char *ee[1] = {0}, **old = environ;
4542 
4543   // discard redirects and return if nothing to exec
4544   free(TT.pp->urd);
4545   TT.pp->urd = 0;
4546   if (!toys.optc) return;
4547 
4548   // exec, handling -acl
4549   TT.isexec = *toys.optargs;
4550   if (FLAG(c)) environ = ee;
4551   if (TT.exec.a || FLAG(l))
4552     *toys.optargs = xmprintf("%s%s", FLAG(l) ? "-" : "", TT.exec.a?:TT.isexec);
4553   sh_exec(toys.optargs);
4554 
4555   // report error (usually ENOENT) and return
4556   perror_msg("%s", TT.isexec);
4557   if (*toys.optargs != TT.isexec) free(*toys.optargs);
4558   TT.isexec = 0;
4559   toys.exitval = 127;
4560   environ = old;
4561 }
4562 
4563 // Return T.jobs index or -1 from identifier
4564 // Note, we don't return "ambiguous job spec", we return the first hit or -1.
4565 // TODO %% %+ %- %?ab
find_job(char * s)4566 int find_job(char *s)
4567 {
4568   char *ss;
4569   long ll = strtol(s, &ss, 10);
4570   int i, j;
4571 
4572   if (!TT.jobs.c) return -1;
4573   if (!*s || (!s[1] && strchr("%+-", *s))) {
4574     int minus, plus = find_plus_minus(&minus);
4575 
4576     return (*s == '-') ? minus : plus;
4577   }
4578 
4579   // Is this a %1 numeric jobspec?
4580   if (s != ss && !*ss)
4581     for (i = 0; i<TT.jobs.c; i++)
4582       if (((struct sh_process *)TT.jobs.v[i])->job == ll) return i;
4583 
4584   // Match start of command or %?abc
4585   for (i = 0; i<TT.jobs.c; i++) {
4586     struct sh_process *pp = (void *)TT.jobs.v[i];
4587 
4588     if (strstart(&s, *pp->arg.v)) return i;
4589     if (*s != '?' || !s[1]) continue;
4590     for (j = 0; j<pp->arg.c; j++) if (strstr(pp->arg.v[j], s+1)) return i;
4591   }
4592 
4593   return -1;
4594 }
4595 
jobs_main(void)4596 void jobs_main(void)
4597 {
4598   int i, j, minus, plus = find_plus_minus(&minus);
4599   char *s;
4600 
4601 // TODO -lnprs
4602 
4603   for (i = 0;;i++) {
4604     if (toys.optc) {
4605       if (!(s = toys.optargs[i])) break;
4606       if ((j = find_job(s+('%' == *s))) == -1) {
4607         perror_msg("%s: no such job", s);
4608 
4609         continue;
4610       }
4611     } else if ((j = i) >= TT.jobs.c) break;
4612 
4613     s = show_job((void *)TT.jobs.v[i], is_plus_minus(i, plus, minus));
4614     printf("%s\n", s);
4615     free(s);
4616   }
4617 }
4618 
4619 #define FOR_local
4620 #include "generated/flags.h"
4621 
local_main(void)4622 void local_main(void)
4623 {
4624   struct sh_fcall *ff, *ff2;
4625   struct sh_vars *var;
4626   char **arg, *eq;
4627 
4628   // find local variable context
4629   for (ff = TT.ff;; ff = ff->next) {
4630     if (ff == TT.ff->prev) return error_msg("not in function");
4631     if (ff->vars) break;
4632   }
4633 
4634   // list existing vars (todo:
4635   if (!toys.optc) {
4636     for (var = ff->vars; var; var++) xputs(var->str); // TODO escape
4637     return;
4638   }
4639 
4640   // set/move variables
4641   for (arg = toys.optargs; *arg; arg++) {
4642     if ((eq = varend(*arg)) == *arg || (*eq && *eq != '=')) {
4643       error_msg("bad %s", *arg);
4644       continue;
4645     }
4646 
4647     if ((var = findvar(*arg, &ff2)) && ff == ff2 && !*eq) continue;
4648     if (var && (var->flags&VAR_READONLY)) {
4649       error_msg("%.*s: readonly variable", (int)(varend(*arg)-*arg), *arg);
4650       continue;
4651     }
4652 
4653     // Add local inheriting global status and setting whiteout if blank.
4654     if (!var || ff!=ff2) {
4655       int flags = var ? var->flags&VAR_EXPORT : 0;
4656 
4657       var = addvar(xmprintf("%s%s", *arg, *eq ? "" : "="), ff);
4658       var->flags = flags|(VAR_WHITEOUT*!*eq);
4659     }
4660 
4661     // TODO accept declare options to set more flags
4662     // TODO, integer, uppercase take effect. Setvar?
4663   }
4664 }
4665 
shift_main(void)4666 void shift_main(void)
4667 {
4668   long long by = 1;
4669 
4670   if (toys.optc) by = atolx(*toys.optargs);
4671   by += TT.ff->shift;
4672   if (by<0 || by>=TT.ff->arg.c) toys.exitval++;
4673   else TT.ff->shift = by;
4674 }
4675 
source_main(void)4676 void source_main(void)
4677 {
4678   char *name = *toys.optargs;
4679   FILE *ff = fpathopen(name);
4680 
4681   if (!ff) return perror_msg_raw(name);
4682   // $0 is shell name, not source file name while running this
4683 // TODO add tests: sh -c "source input four five" one two three
4684   *toys.optargs = *toys.argv;
4685   ++TT.srclvl;
4686   call_function();
4687   TT.ff->arg.v = toys.optargs;
4688   TT.ff->arg.c = toys.optc;
4689   TT.ff->oldlineno = TT.LINENO;
4690   TT.LINENO = 0;
4691   do_source(name, ff);
4692   TT.LINENO = TT.ff->oldlineno;
4693   free(dlist_pop(&TT.ff));
4694   --TT.srclvl;
4695 }
4696 
4697 #define FOR_wait
4698 #include "generated/flags.h"
4699 
wait_main(void)4700 void wait_main(void)
4701 {
4702   struct sh_process *pp;
4703   int ii, jj;
4704   long long ll;
4705   char *s;
4706 
4707   // TODO does -o pipefail affect return code here
4708   if (FLAG(n)) toys.exitval = free_process(wait_job(-1, 0));
4709   else if (!toys.optc) while (TT.jobs.c) {
4710     if (!(pp = wait_job(-1, 0))) break;
4711   } else for (ii = 0; ii<toys.optc; ii++) {
4712     ll = estrtol(toys.optargs[ii], &s, 10);
4713     if (errno || *s) {
4714       if (-1 == (jj = find_job(toys.optargs[ii]))) {
4715         error_msg("%s: bad pid/job", toys.optargs[ii]);
4716         continue;
4717       }
4718       ll = ((struct sh_process *)TT.jobs.v[jj])->pid;
4719     }
4720     if (!(pp = wait_job(ll, 0))) {
4721       if (toys.signal) toys.exitval = 128+toys.signal;
4722       break;
4723     }
4724     toys.exitval = free_process(pp);
4725   }
4726 }
4727