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