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