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