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