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