1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157#define FOR_sh
158#include "toys.h"
159
160GLOBALS(
161 union {
162 struct {
163 char *c;
164 } sh;
165 struct {
166 char *a;
167 } exec;
168 };
169
170
171 long lineno;
172 char *ifs, *isexec;
173 struct double_list functions;
174 unsigned options, jobcnt;
175 int hfd, pid, varslen, shift, cdcount;
176 unsigned long long SECONDS;
177
178 struct sh_vars {
179 long flags;
180 char *str;
181 } *vars;
182
183
184 struct sh_job {
185 struct sh_job *next, *prev;
186 unsigned jobno;
187
188
189 struct sh_arg {
190 char **v;
191 int c;
192 } pipeline;
193
194
195 struct sh_process {
196 struct sh_process *next, *prev;
197 struct arg_list *delete;
198
199 int *urd, envlen, pid, exit, not;
200 struct sh_arg arg;
201 } *procs, *proc;
202 } *jobs, *job;
203
204 struct sh_process *pp;
205 struct sh_arg *arg;
206)
207
208
209
210static int sh_run(char *new);
211
212
213struct sh_pipeline {
214 struct sh_pipeline *next, *prev;
215 int count, here, type;
216 struct sh_arg arg[1];
217};
218
219
220
221struct sh_function {
222 char *name;
223 struct sh_pipeline *pipeline;
224 struct double_list *expect;
225
226 struct sh_arg *arg;
227 char *end;
228};
229
230#define BUGBUG 0
231
232
233static void dump_state(struct sh_function *sp)
234{
235 struct sh_pipeline *pl;
236 long i;
237 int q = 0, fd = open("/proc/self/fd", O_RDONLY);
238 DIR *dir = fdopendir(fd);
239 char buf[256];
240
241 if (sp && sp->expect) {
242 struct double_list *dl;
243
244 for (dl = sp->expect; dl; dl = (dl->next == sp->expect) ? 0 : dl->next)
245 dprintf(255, "expecting %s\n", dl->data);
246 if (sp->pipeline)
247 dprintf(255, "pipeline count=%d here=%d\n", sp->pipeline->prev->count,
248 sp->pipeline->prev->here);
249 }
250
251 if (sp) for (pl = sp->pipeline; pl ; pl = (pl->next == sp->pipeline) ? 0 : pl->next) {
252 for (i = 0; i<pl->arg->c; i++)
253 dprintf(255, "arg[%d][%ld]=%s\n", q, i, pl->arg->v[i]);
254 if (pl->arg->c<0) dprintf(255, "argc=%d\n", pl->arg->c);
255 else dprintf(255, "type=%d term[%d]=%s\n", pl->type, q++, pl->arg->v[pl->arg->c]);
256 }
257
258 if (dir) {
259 struct dirent *dd;
260
261 while ((dd = readdir(dir))) {
262 if (atoi(dd->d_name)!=fd && 0<readlinkat(fd, dd->d_name, buf,sizeof(buf)))
263 dprintf(255, "OPEN %d: %s = %s\n", getpid(), dd->d_name, buf);
264 }
265 closedir(dir);
266 }
267 close(fd);
268}
269
270
271
272
273static const char *redirectors[] = {"<<<", "<<-", "<<", "<&", "<>", "<", ">>",
274 ">&", ">|", ">", "&>>", "&>", 0};
275
276#define OPT_I 1
277#define OPT_BRACE 2
278#define OPT_NOCLOBBER 4
279#define OPT_S 8
280#define OPT_C 16
281
282static void syntax_err(char *s)
283{
284 error_msg("syntax error: %s", s);
285 toys.exitval = 2;
286}
287
288
289static void array_add(char ***list, unsigned count, char *data)
290{
291 if (!(count&31)) *list = xrealloc(*list, sizeof(char *)*(count+33));
292 (*list)[count] = data;
293 (*list)[count+1] = 0;
294}
295
296
297static void add_arg(struct arg_list **list, char *arg)
298{
299 struct arg_list *al;
300
301 if (!list) return;
302 al = xmalloc(sizeof(struct arg_list));
303 al->next = *list;
304 al->arg = arg;
305 *list = al;
306}
307
308static void array_add_del(char ***list, unsigned count, char *data,
309 struct arg_list **delete)
310{
311 add_arg(delete, data);
312 array_add(list, count, data);
313}
314
315
316static char *varend(char *s)
317{
318 if (isdigit(*s)) return s;
319 while (*s>' ' && (*s=='_' || !ispunct(*s))) s++;
320
321 return s;
322}
323
324
325static struct sh_vars *findvar(char *name)
326{
327 int len = varend(name)-name;
328 struct sh_vars *var = TT.vars+TT.varslen;
329
330 if (len) while (var-- != TT.vars)
331 if (!strncmp(var->str, name, len) && var->str[len] == '=') return var;
332
333 return 0;
334}
335
336
337static struct sh_vars *addvar(char *s)
338{
339 if (!(TT.varslen&31))
340 TT.vars = xrealloc(TT.vars, (TT.varslen+32)*sizeof(*TT.vars));
341 TT.vars[TT.varslen].flags = 0;
342 TT.vars[TT.varslen].str = s;
343
344 return TT.vars+TT.varslen++;
345}
346
347
348long long do_math(char *s)
349{
350 return atoll(s);
351}
352
353
354
355#define VAR_DICT 256
356#define VAR_ARRAY 128
357#define VAR_INT 64
358#define VAR_TOLOWER 32
359#define VAR_TOUPPER 16
360#define VAR_NAMEREF 8
361#define VAR_GLOBAL 4
362#define VAR_READONLY 2
363#define VAR_MAGIC 1
364
365
366
367static struct sh_vars *setvar(char *s)
368{
369 int len = varend(s)-s;
370 long flags;
371 struct sh_vars *var;
372
373 if (s[len] != '=') {
374 error_msg("bad setvar %s\n", s);
375 free(s);
376 return 0;
377 }
378 if (len == 3 && !memcmp(s, "IFS", 3)) TT.ifs = s+4;
379
380 if (!(var = findvar(s))) return addvar(s);
381 flags = var->flags;
382
383 if (flags&VAR_READONLY) {
384 error_msg("%.*s: read only", len, s);
385 free(s);
386
387 return var;
388 } else if (flags&VAR_MAGIC) {
389 if (*s == 'S') TT.SECONDS = millitime() - 1000*do_math(s+len-1);
390 else if (*s == 'R') srandom(do_math(s+len-1));
391 } else if (flags&VAR_GLOBAL) xsetenv(var->str = s, 0);
392 else {
393 free(var->str);
394 var->str = s;
395 }
396
397
398
399
400
401
402 return var;
403}
404
405static void unsetvar(char *name)
406{
407 struct sh_vars *var = findvar(name);
408 int ii = var-TT.vars;
409
410 if (!var) return;
411 if (var->flags&VAR_GLOBAL) xunsetenv(name);
412 else free(var->str);
413
414 memmove(TT.vars+ii, TT.vars+ii+1, TT.varslen-ii);
415 TT.varslen--;
416}
417
418static struct sh_vars *setvarval(char *name, char *val)
419{
420 return setvar(xmprintf("%s=%s", name, val));
421}
422
423
424static char *getvar(char *s)
425{
426 struct sh_vars *var = findvar(s);
427
428 if (!var) return 0;
429
430 if (var->flags & VAR_MAGIC) {
431 char c = *var->str;
432
433 if (c == 'S') sprintf(toybuf, "%lld", (millitime()-TT.SECONDS)/1000);
434 else if (c == 'R') sprintf(toybuf, "%ld", random()&((1<<16)-1));
435 else if (c == 'L') sprintf(toybuf, "%ld", TT.lineno);
436 else if (c == 'G') sprintf(toybuf, "TODO: GROUPS");
437
438 return toybuf;
439 }
440
441 return varend(var->str)+1;
442}
443
444
445static char *declarep(struct sh_vars *var)
446{
447 char *types = "-rgnuliaA", *in = types, flags[16], *out = flags, *ss;
448 int len;
449
450 while (*++in) if (var->flags&(1<<(in-types))) *out++ = *in;
451 if (in == types) *out++ = *types;
452 *out = 0;
453 len = out-flags;
454
455 for (in = types = varend(var->str); *in; in++) len += !!strchr("$\"\\`", *in);
456 len += in-types;
457 ss = xmalloc(len+13);
458
459 out = ss + sprintf(ss, "declare -%s \"", out);
460 while (types) {
461 if (strchr("$\"\\`", *in)) *out++ = '\\';
462 *out++ = *types++;
463 }
464 *out++ = '"';
465 *out = 0;
466
467 return ss;
468}
469
470
471static int anystart(char *s, char **try)
472{
473 char *ss = s;
474
475 while (*try) if (strstart(&s, *try++)) return s-ss;
476
477 return 0;
478}
479
480
481static int anystr(char *s, char **try)
482{
483 while (*try) if (!strcmp(s, *try++)) return 1;
484
485 return 0;
486}
487
488
489static int redir_prefix(char *word)
490{
491 char *s = word;
492
493 if (*s == '{') {
494 if (*(s = varend(s+1)) == '}' && s != word+1) s++;
495 else s = word;
496 } else while (isdigit(*s)) s++;
497
498 return s-word;
499}
500
501
502
503static char *parse_word(char *start, int early)
504{
505 int i, quote = 0, q, qc = 0;
506 char *end = start, *s;
507
508
509
510 if (strstart(&end, "<(") || strstart(&end, ">(")) toybuf[quote++]=')';
511
512
513 s = end + redir_prefix(end);
514 if ((i = anystart(s, (void *)redirectors))) return s+i;
515
516
517 if (strstart(&end, "((")) toybuf[quote++] = 254;
518
519
520 while (*end) {
521 i = 0;
522
523
524 if (quote>4000) {
525 syntax_err("tilt");
526 return (void *)1;
527 }
528
529
530 if ((q = quote ? toybuf[quote-1] : 0)) {
531
532
533 if ((q == ')' || q >= 254) && (*end == '(' || *end == ')')) {
534 if (*end == '(') qc++;
535 else if (qc) qc--;
536 else if (q >= 254) {
537
538 if (strstart(&end, "))")) quote--;
539 else if (q == 254) return start+1;
540 else if (q == 255) toybuf[quote-1] = ')';
541 } else if (*end == ')') quote--;
542 end++;
543
544
545 } else if (*end == q) quote--, end++;
546
547
548 else if (q == '\'') end++;
549 else i++;
550
551
552 if (early && !quote) return end;
553 if (!i) continue;
554 } else {
555
556
557 if (isspace(*end)) break;
558 if (*end == ')') return end+(start==end);
559
560
561 s = end + anystart(end, (char *[]){";;&", ";;", ";&", ";", "||",
562 "|&", "|", "&&", "&", "(", ")", 0});
563 if (s != end) return (end == start) ? s : end;
564 }
565
566
567
568
569 if (strchr("\"'`", *end)) toybuf[quote++] = *end;
570
571
572 else if (*end == '\\') {
573 if (!end[1] || (end[1]=='\n' && !end[2])) return 0;
574 end += 2;
575 } else if (*end == '$' && -1 != (i = stridx("({[", end[1]))) {
576 end++;
577 if (strstart(&end, "((")) toybuf[quote++] = 255;
578 else {
579 toybuf[quote++] = ")}]"[i];
580 end++;
581 }
582 }
583 if (early && !quote) return end;
584 end++;
585 }
586
587 return quote ? 0 : end;
588}
589
590
591static int next_hfd()
592{
593 int hfd;
594
595 for (; TT.hfd<=99999; TT.hfd++) if (-1 == fcntl(TT.hfd, F_GETFL)) break;
596 hfd = TT.hfd;
597 if (TT.hfd > 99999) {
598 hfd = -1;
599 if (!errno) errno = EMFILE;
600 }
601
602 return hfd;
603}
604
605
606
607
608
609static int save_redirect(int **rd, int from, int to)
610{
611 int cnt, hfd, *rr;
612
613 if (from == to) return 0;
614
615
616 if (from>-2) {
617 if ((hfd = next_hfd())==-1) return 1;
618 if (hfd != dup2(to, hfd)) hfd = -1;
619 else fcntl(hfd, F_SETFD, FD_CLOEXEC);
620if (BUGBUG) dprintf(255, "%d redir from=%d to=%d hfd=%d\n", getpid(), from, to, hfd);
621
622 if (from >= 0 && to != dup2(from, to)) {
623 if (hfd >= 0) close(hfd);
624
625 return 1;
626 }
627 } else {
628if (BUGBUG) dprintf(255, "%d schedule close %d\n", getpid(), to);
629 hfd = to;
630 to = -1;
631 }
632
633
634 if (!((cnt = *rd ? **rd : 0)&31)) *rd = xrealloc(*rd, (cnt+33)*2*sizeof(int));
635 *(rr = *rd) = ++cnt;
636 rr[2*cnt-1] = hfd;
637 rr[2*cnt] = to;
638
639 return 0;
640}
641
642
643static void subshell_callback(char **argv)
644{
645 char *s;
646
647 xsetenv(s = xmprintf("@%d,%d=", getpid(), getppid()), 0);
648 s[strlen(s)-1] = 0;
649 xsetenv(xmprintf("$=%d", TT.pid), 0);
650
651}
652
653
654
655
656
657static int run_subshell(char *str, int len)
658{
659 pid_t pid;
660
661if (BUGBUG) dprintf(255, "run_subshell %.*s\n", len, str);
662
663 if (CFG_TOYBOX_FORK) {
664 char *s;
665
666 if ((pid = fork())<0) perror_msg("fork");
667 else if (!pid) {
668 s = xstrndup(str, len);
669 sh_run(s);
670 free(s);
671 _exit(toys.exitval);
672 }
673
674
675 } else {
676 int pipes[2], i, c;
677
678
679 if (pipe(pipes) || 254 != dup2(pipes[0], 254)) return 1;
680 close(pipes[0]);
681 fcntl(pipes[1], F_SETFD, FD_CLOEXEC);
682
683
684 pid = xpopen_setup(0, 0, subshell_callback);
685
686
687 for (i = 0; environ[i]; i++) {
688 c = environ[i][0];
689 if (c == '_' || !ispunct(c)) continue;
690 free(environ[i]);
691 environ[i] = 0;
692 }
693
694
695 close(254);
696 for (i = 0; i<TT.varslen; i++) {
697 char *s;
698
699 if (TT.vars[i].flags&VAR_GLOBAL) continue;
700 dprintf(pipes[1], "%s\n", s = declarep(TT.vars+i));
701 free(s);
702 }
703 dprintf(pipes[1], "%.*s\n", len, str);
704 close(pipes[1]);
705 }
706
707 return pid;
708}
709
710
711static void unredirect(int *urd)
712{
713 int *rr = urd+1, i;
714
715 if (!urd) return;
716
717 for (i = 0; i<*urd; i++, rr += 2) {
718if (BUGBUG) dprintf(255, "%d urd %d %d\n", getpid(), rr[0], rr[1]);
719 if (rr[0] != -1) {
720
721 dup2(rr[0], rr[1]);
722 close(rr[0]);
723 }
724 }
725 free(urd);
726}
727
728
729static int pipe_subshell(char *s, int len, int out)
730{
731 int pipes[2], *uu = 0, in = !out;
732
733
734 if (pipe(pipes)) {
735 perror_msg("%.*s", len, s);
736
737 return -1;
738 }
739
740
741 save_redirect(&uu, pipes[in], in);
742 close(pipes[in]);
743 run_subshell(s, len);
744 unredirect(uu);
745
746 return pipes[out];
747}
748
749
750
751static int utf8chr(char *wc, char *chrs, int *len)
752{
753 wchar_t wc1, wc2;
754 int ll;
755
756 if (len) *len = 1;
757 if (!*wc) return 0;
758 if (0<(ll = utf8towc(&wc1, wc, 99))) {
759 if (len) *len = ll;
760 while (*chrs) {
761 if(1>(ll = utf8towc(&wc2, chrs, 99))) chrs++;
762 else {
763 if (wc1 == wc2) return wc1;
764 chrs += ll;
765 }
766 }
767 }
768
769 return 0;
770}
771
772#define NO_PATH (1<<0)
773#define NO_SPLIT (1<<1)
774#define NO_BRACE (1<<2)
775#define NO_TILDE (1<<3)
776#define NO_QUOTE (1<<4)
777#define SEMI_IFS (1<<5)
778
779
780
781
782
783
784
785
786static int expand_arg_nobrace(struct sh_arg *arg, char *str, unsigned flags,
787 struct arg_list **delete)
788{
789 char cc, qq = 0, *old = str, *new = str, *s, *ss, *ifs, **aa;
790 int ii = 0, dd, jj, kk, ll, oo = 0, nodel;
791
792if (BUGBUG) dprintf(255, "expand %s\n", str);
793
794
795 if (!(flags&NO_TILDE) && *str == '~') {
796 struct passwd *pw = 0;
797
798 ss = 0;
799 while (str[ii] && str[ii]!=':' && str[ii]!='/') ii++;
800 if (ii==1) {
801 if (!(ss = getvar("HOME")) || !*ss) pw = bufgetpwuid(getuid());
802 } else {
803
804 pw = getpwnam(s = xstrndup(str+1, ii-1));
805 free(s);
806 }
807 if (pw) {
808 ss = pw->pw_dir;
809 if (!ss || !*ss) ss = "/";
810 }
811 if (ss) {
812 oo = strlen(ss);
813 s = xmprintf("%s%s", ss, str+ii);
814 if (old != new) free(new);
815 new = s;
816 }
817 }
818
819
820
821 for (; (cc = str[ii++]); old!=new && (new[oo] = 0)) {
822
823
824 if (!strchr("$'`\\\"", cc)) {
825 if (old != new) new[oo++] = cc;
826 continue;
827 }
828
829
830 if (old == new) {
831 new = xstrdup(new);
832 new[oo = ii-1] = 0;
833 }
834 ifs = 0;
835 aa = 0;
836 nodel = 0;
837
838
839 if (cc == '\\') new[oo++] = str[ii] ? str[ii++] : cc;
840 else if (cc == '"') qq++;
841 else if (cc == '\'') {
842 if (qq&1) new[oo++] = cc;
843 else {
844 qq += 2;
845 while ((cc = str[ii++]) != '\'') new[oo++] = cc;
846 }
847
848
849 } else if (cc == '`' || (cc == '$' && strchr("([", str[ii]))) {
850 off_t pp = 0;
851
852 s = str+ii-1;
853 kk = parse_word(s, 1)-s;
854 if (str[ii] == '[' || *toybuf == 255) {
855 s += 2+(str[ii]!='[');
856 kk -= 3+2*(str[ii]!='[');
857dprintf(2, "TODO: do math for %.*s\n", kk, s);
858 } else {
859
860 s += (jj = 1+(cc == '$'));
861 ii += --kk;
862 kk -= jj;
863
864
865 for (ss = s; isspace(*ss); ss++);
866 if (*ss != '<') ss = 0;
867 else {
868 while (isspace(*++ss));
869 if (!(ll = parse_word(ss, 0)-ss)) ss = 0;
870 else {
871 jj = ll+(ss-s);
872 while (isspace(s[jj])) jj++;
873 if (jj != kk) ss = 0;
874 else {
875 jj = xcreate_stdio(ss = xstrndup(ss, ll), O_RDONLY|WARN_ONLY, 0);
876 free(ss);
877 }
878 }
879 }
880
881
882 if (!ss) jj = pipe_subshell(s, kk, 0);
883 if ((ifs = readfd(jj, 0, &pp)))
884 for (kk = strlen(ifs); kk && ifs[kk-1]=='\n'; ifs[--kk] = 0);
885 close(jj);
886 }
887 } else if (cc == '$') {
888
889
890
891 cc = str[ii++];
892 if (cc=='\'') {
893 for (s = str+ii; *s != '\''; oo += wcrtomb(new+oo, unescape2(&s, 0),0));
894 ii = s-str+1;
895
896 continue;
897 } else if (cc == '{') {
898 cc = *(ss = str+ii);
899 if (!(jj = strchr(ss, '}')-ss)) ifs = (void *)1;
900 ii += jj+1;
901
902 if (jj>1) {
903
904 if (*ss == '!') {
905 if (!(ss = getvar(ss+1)) || !*ss) continue;
906 jj = varend(ss)-ss;
907 if (ss[jj]) ifs = (void *)1;
908 } else if (*ss == '#') {
909 if (jj == 2 && (*ss == '@' || *ss == '*')) jj--;
910 else ifs = xmprintf("%ld", (long)strlen(getvar(ss) ? : ""));
911 }
912 }
913 } else {
914 ss = str+--ii;
915 if (!(jj = varend(ss)-ss)) jj++;
916 ii += jj;
917 }
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944 if (ifs);
945 else if (cc == '-') {
946 s = ifs = xmalloc(8);
947 if (TT.options&OPT_I) *s++ = 'i';
948 if (TT.options&OPT_BRACE) *s++ = 'B';
949 if (TT.options&OPT_S) *s++ = 's';
950 if (TT.options&OPT_C) *s++ = 'c';
951 *s = 0;
952 } else if (cc == '?') ifs = xmprintf("%d", toys.exitval);
953 else if (cc == '$') ifs = xmprintf("%d", TT.pid);
954 else if (cc == '#') ifs = xmprintf("%d", TT.arg->c?TT.arg->c-1:0);
955 else if (cc == '*' || cc == '@') aa = TT.arg->v+1;
956 else if (isdigit(cc)) {
957 for (kk = ll = 0; kk<jj && isdigit(ss[kk]); kk++)
958 ll = (10*ll)+ss[kk]-'0';
959 if (ll) ll += TT.shift;
960 if (ll<TT.arg->c) ifs = TT.arg->v[ll];
961 nodel = 1;
962
963
964 } else {
965 if (ss == varend(ss)) {
966 ii--;
967 if (ss[-1] == '$') new[oo++] = '$';
968 else ifs = (void *)1;
969 } else ifs = getvar(ss);
970 nodel = 1;
971 }
972 }
973
974
975
976
977
978 if (ifs == (void *)1) {
979 error_msg("%.*s: bad substitution", (int)(s-(str+ii)+3), str+ii-2);
980 free(new);
981
982 return 1;
983 }
984
985
986 if (ifs || aa) {
987 char sep[8];
988
989
990 if (!aa && !*ifs && !qq) continue;
991
992
993 *sep = 0;
994 if ((qq&1) && cc=='*') {
995 wchar_t wc;
996
997 if (flags&SEMI_IFS) strcpy(sep, " ");
998 else if (0<(dd = utf8towc(&wc, TT.ifs, 4)))
999 sprintf(sep, "%.*s", dd, TT.ifs);
1000 }
1001
1002
1003 do {
1004
1005
1006 if (aa) {
1007 ifs = *aa ? : "";
1008 if (*aa) aa++;
1009 nodel = 1;
1010 }
1011 if (qq&1) ss = ifs+strlen(ifs);
1012 else for (ss = ifs; *ss; ss += kk)
1013 if ((ll = utf8chr(ss, TT.ifs, &kk))) break;
1014 kk = !aa || !*aa;
1015
1016
1017 do {
1018
1019
1020 if (!oo && !*ss && (!kk || !str[ii]) && !((qq&1) && cc=='*')) {
1021 if (!qq && ss==ifs) break;
1022 array_add_del(&arg->v, arg->c++, ifs, nodel ? 0 : delete);
1023 nodel = 1;
1024
1025 continue;
1026 }
1027
1028
1029 new = xrealloc(new, oo + (ss-ifs) + strlen(sep) +
1030 ((jj = kk && !*ss) ? strlen(str+ii) : 0) + 1);
1031 oo += sprintf(new + oo, "%.*s", (int)(ss-ifs), ifs);
1032 if (!nodel) free(ifs);
1033 nodel = 1;
1034 if (jj) break;
1035
1036
1037 if ((qq&1) && cc == '*') oo += sprintf(new+oo, "%s", sep);
1038
1039
1040 else {
1041 if (qq || *new || *ss) {
1042 array_add_del(&arg->v, arg->c++, new, nodel ? 0 : delete);
1043 nodel = 1;
1044 }
1045 qq &= 1;
1046 new = xstrdup(str+ii);
1047 oo = 0;
1048 }
1049
1050
1051 while ((jj = utf8chr(ss, TT.ifs, &ll)) && iswspace(jj)) ss += ll;
1052
1053 } while (*(ifs = ss));
1054 } while (!kk);
1055 }
1056 }
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068 if (*new || qq)
1069 array_add_del(&arg->v, arg->c++, new, (old != new) ? delete : 0);
1070 else if(old != new) free(new);
1071
1072 return 0;
1073}
1074
1075
1076static int expand_arg(struct sh_arg *arg, char *old, unsigned flags,
1077 struct arg_list **delete)
1078{
1079 struct brace {
1080 struct brace *next, *prev, *stack;
1081 int active, cnt, idx, dots[2], commas[];
1082 } *bb = 0, *blist = 0, *bstk, *bnext;
1083 int i, j;
1084 char *s, *ss;
1085
1086
1087 if ((TT.options&OPT_BRACE) && !(flags&NO_BRACE)) for (i = 0; ; i++) {
1088 while ((s = parse_word(old+i, 1)) != old+i) i += s-(old+i);
1089 if (!bb && !old[i]) break;
1090 if (bb && (!old[i] || old[i] == '}')) {
1091 bb->active = bb->commas[bb->cnt+1] = i;
1092 for (bnext = bb; bb && bb->active; bb = (bb==blist)?0:bb->prev);
1093 if (!old[i] || !bnext->cnt)
1094 free(dlist_pop((blist == bnext) ? &blist : &bnext));
1095 } else if (old[i] == '{') {
1096 dlist_add_nomalloc((void *)&blist,
1097 (void *)(bb = xzalloc(sizeof(struct brace)+34*4)));
1098 bb->commas[0] = i;
1099 } else if (!bb) continue;
1100 else if (bb && old[i] == ',') {
1101 if (bb->cnt && !(bb->cnt&31)) {
1102 dlist_lpop(&blist);
1103 dlist_add_nomalloc((void *)&blist,
1104 (void *)(bb = xrealloc(bb, sizeof(struct brace)+(bb->cnt+34)*4)));
1105 }
1106 bb->commas[++bb->cnt] = i;
1107 }
1108 }
1109
1110
1111
1112 if (!blist) return expand_arg_nobrace(arg, old, flags, delete);
1113
1114
1115 (bstk = xzalloc(sizeof(struct brace)+8))->commas[1] = strlen(old)+1;
1116 bstk->commas[0] = -1;
1117
1118
1119 for (;;) {
1120
1121
1122 s = ss = xmalloc(bstk->commas[1]);
1123
1124
1125 for (bb = blist; bb;) {
1126
1127
1128 if (bstk == bb) bstk = bstk->stack;
1129 i = bstk->commas[bstk->idx]+1;
1130 if (bstk->commas[bstk->cnt+1]>bb->commas[0])
1131 s = stpncpy(s, old+i, bb->commas[0]-i);
1132
1133
1134 if (bstk->commas[bstk->cnt+1]<bb->commas[0]) bstk = bstk->stack;
1135
1136 bb->stack = bstk;
1137 bb->active = 1;
1138 bstk = bnext = bb;
1139
1140
1141 while ((bnext = (bnext->next==blist) ? 0 : bnext->next)) {
1142 i = bnext->commas[0];
1143
1144
1145 if (i>bb->commas[bb->cnt+1]) break;
1146
1147
1148 if (i<bb->commas[bb->idx] || i>bb->commas[bb->idx+1]) {
1149 bnext->active = 0;
1150 bnext->stack = 0;
1151
1152
1153 } else break;
1154 }
1155
1156
1157 if (!bnext || bnext->commas[0]>bb->commas[bb->idx+1]) {
1158
1159
1160 i = bb->commas[bstk->idx]+1;
1161 s = stpncpy(s, old+i, bb->commas[bb->idx+1]-i);
1162
1163
1164 while (!bnext || bnext->commas[0] > bstk->commas[bstk->cnt+1]) {
1165 if (!(bb = bstk->stack)) break;
1166 i = bstk->commas[bstk->cnt+1]+1;
1167 j = bb->commas[bb->idx+1];
1168
1169 while (bnext) {
1170 if (bnext->commas[0]<j) {
1171 j = bnext->commas[0];
1172 break;
1173 } else if (bb->commas[bb->cnt+1]>bnext->commas[0])
1174 bnext = (bnext->next == blist) ? 0 : bnext->next;
1175 else break;
1176 }
1177 s = stpncpy(s, old+i, j-i);
1178
1179
1180 if (bnext && bnext->commas[0]<bstk->stack->commas[bstk->stack->cnt+1])
1181 break;
1182 bstk = bstk->stack;
1183 }
1184 }
1185 bb = (bnext == blist) ? 0 : bnext;
1186 }
1187
1188
1189 add_arg(delete, ss);
1190 if (expand_arg_nobrace(arg, ss, flags, delete)) {
1191 llist_traverse(blist, free);
1192
1193 return 1;
1194 }
1195
1196
1197 for (bb = blist->prev; bb; bb = (bb == blist) ? 0 : bb->prev) {
1198 if (!bb->stack) continue;
1199 else if (++bb->idx > bb->cnt) bb->idx = 0;
1200 else break;
1201 }
1202
1203
1204 if (!bb) break;
1205 }
1206 llist_traverse(blist, free);
1207
1208 return 0;
1209}
1210
1211
1212static char *expand_one_arg(char *new, unsigned flags, struct arg_list **del)
1213{
1214 struct sh_arg arg;
1215 char *s = 0;
1216 int i;
1217
1218 memset(&arg, 0, sizeof(arg));
1219 if (!expand_arg(&arg, new, flags, del) && arg.c == 1) s = *arg.v;
1220 if (!del && !s) for (i = 0; i < arg.c; i++) free(arg.v[i]);
1221 free(arg.v);
1222
1223 return s;
1224}
1225
1226
1227
1228
1229static char *pl2str(struct sh_pipeline *pl)
1230{
1231 struct sh_pipeline *end = 0;
1232 int level = 0, len = 0, i, j;
1233 char *s, *ss, *sss;
1234
1235
1236 for (j = 0; ; j++) for (end = pl; end; end = end->next) {
1237 if (end->type == 1) level++;
1238 else if (end->type == 3 && --level<0) break;
1239
1240 for (i = 0; i<pl->arg->c; i++)
1241 if (j) ss += sprintf(ss, "%s ", pl->arg->v[i]);
1242 else len += strlen(pl->arg->v[i])+1;
1243
1244 sss = pl->arg->v[pl->arg->c];
1245 if (!sss) sss = ";";
1246 if (j) ss = stpcpy(ss, sss);
1247 else len += strlen(sss);
1248
1249
1250 if (j) return s;
1251 s = ss = xmalloc(len+1);
1252 }
1253}
1254
1255
1256
1257static struct sh_process *expand_redir(struct sh_arg *arg, int envlen, int *urd)
1258{
1259 struct sh_process *pp;
1260 char *s = s, *ss, *sss, *cv = 0;
1261 int j, to, from, here = 0;
1262
1263 TT.hfd = 10;
1264
1265 pp = xzalloc(sizeof(struct sh_process));
1266 pp->urd = urd;
1267
1268
1269
1270
1271 for (j = envlen; j<arg->c; j++) {
1272 int saveclose = 0, bad = 0;
1273
1274 s = arg->v[j];
1275
1276 if (!strcmp(s, "!")) {
1277 pp->not ^= 1;
1278
1279 continue;
1280 }
1281
1282
1283 if ((*s == '<' || *s == '>') && s[1] == '(') {
1284 int new = pipe_subshell(s+2, strlen(s+2)-1, *s == '>');
1285
1286
1287 if (new == -1) {
1288 pp->exit = 1;
1289
1290 return pp;
1291 }
1292 save_redirect(&pp->urd, -2, new);
1293
1294
1295
1296 array_add_del(&pp->arg.v, pp->arg.c++,
1297 ss = xmprintf("/proc/self/fd/%d", new), &pp->delete);
1298
1299 continue;
1300 }
1301
1302
1303 ss = s + redir_prefix(arg->v[j]);
1304 sss = ss + anystart(ss, (void *)redirectors);
1305 if (ss == sss) {
1306
1307 if (expand_arg(&pp->arg, s, 0, &pp->delete)) {
1308 pp->exit = 1;
1309
1310 return pp;
1311 }
1312 continue;
1313 } else if (j+1 >= arg->c) {
1314
1315 s = "\\n";
1316 break;
1317 }
1318 sss = arg->v[++j];
1319
1320
1321 if (isdigit(*s) && ss-s>5) break;
1322
1323
1324 if (strncmp(ss, "<<", 2) && ss[2] != '<' &&
1325 !(sss = expand_one_arg(sss, NO_PATH, &pp->delete)))
1326 {
1327 s = 0;
1328 break;
1329 }
1330
1331
1332 to = *ss != '<';
1333 if (isdigit(*s)) to = atoi(s);
1334 else if (*s == '{') {
1335 if (*varend(s+1) != '}') break;
1336
1337 if ((!strcmp(ss, "<&") || !strcmp(ss, ">&")) && !strcmp(sss, "-")) {
1338 if (!(ss = getvar(s+1))) break;
1339 to = atoi(ss);
1340 if (save_redirect(&pp->urd, -1, to)) break;
1341 close(to);
1342
1343 continue;
1344
1345 } else {
1346
1347 if (-1 == (to = next_hfd())) break;
1348 cv = xmprintf("%.*s=%d", (int)(ss-s-2), s+1, to);
1349 }
1350 }
1351
1352
1353 if (!strcmp(ss, "<<<") || !strcmp(ss, "<<-") || !strcmp(ss, "<<")) {
1354 char *tmp = getvar("TMPDIR");
1355 int i, len, zap = (ss[2] == '-'), x = !ss[strcspn(ss, "\"'")];
1356
1357
1358 tmp = xmprintf("%s/sh-XXXXXX", tmp ? tmp : "/tmp");
1359 if ((from = mkstemp(tmp))>=0) {
1360 if (unlink(tmp)) bad++;
1361
1362
1363 else if (ss[2] == '<') {
1364 if (x && !(sss = expand_one_arg(sss, NO_PATH|NO_SPLIT, 0))) {
1365 s = 0;
1366 break;
1367 }
1368 len = strlen(sss);
1369 if (len != writeall(from, sss, len)) bad++;
1370 if (x) free(sss);
1371 } else {
1372 struct sh_arg *hh = arg+here++;
1373
1374 for (i = 0; i<hh->c; i++) {
1375 ss = hh->v[i];
1376 sss = 0;
1377
1378
1379 if (x && !(ss = sss = expand_one_arg(ss,
1380 NO_PATH|NO_SPLIT|NO_BRACE|NO_TILDE|NO_QUOTE, 0)))
1381 {
1382 s = 0;
1383 break;
1384 }
1385
1386 while (zap && *ss == '\t') ss++;
1387 x = writeall(from, ss, len = strlen(ss));
1388 free(sss);
1389 if (len != x) break;
1390 }
1391 if (i != hh->c) bad++;
1392 }
1393 if (!bad && lseek(from, 0, SEEK_SET)) bad++;
1394 if (bad) close(from);
1395 } else bad++;
1396 free(tmp);
1397 if (bad) break;
1398
1399
1400
1401
1402
1403
1404
1405 } else if (*ss == '&' || ss[1] == '&') {
1406
1407
1408 for (ss = sss; isdigit(*ss); ss++);
1409 if (ss-sss>5 || (*ss && (*ss != '-' || ss[1]))) {
1410 if (*ss=='&') ss++;
1411 saveclose = 4;
1412 goto notfd;
1413 }
1414
1415 from = (ss==sss) ? to : atoi(sss);
1416 saveclose = 2-(*ss == '-');
1417 } else {
1418notfd:
1419
1420 if (!strcmp(ss, "<>")) from = O_CREAT|O_RDWR;
1421 else if (strstr(ss, ">>")) from = O_CREAT|O_APPEND|O_WRONLY;
1422 else {
1423 from = (*ss == '<') ? O_RDONLY : O_CREAT|O_WRONLY|O_TRUNC;
1424 if (!strcmp(ss, ">") && (TT.options&OPT_NOCLOBBER)) {
1425 struct stat st;
1426
1427
1428 if (stat(sss, &st) || !S_ISREG(st.st_mode)) from |= O_EXCL;
1429 }
1430 }
1431
1432
1433
1434
1435
1436
1437 if (-1 == (from = xcreate_stdio(sss, from|WARN_ONLY, 0666))) {
1438 s = 0;
1439
1440 break;
1441 }
1442 }
1443
1444
1445 if (save_redirect(&pp->urd, from, to)) bad++;
1446
1447 if (cv) {
1448 --*pp->urd;
1449 setvar(cv);
1450 cv = 0;
1451 }
1452 if ((saveclose&1) && save_redirect(&pp->urd, -1, from)) bad++;
1453 if ((saveclose&4) && save_redirect(&pp->urd, from, 2)) bad++;
1454 if (!(saveclose&2)) close(from);
1455 if (bad) break;
1456 }
1457
1458
1459 if (j != arg->c) {
1460 if (s) syntax_err(s);
1461 if (!pp->exit) pp->exit = 1;
1462 free(cv);
1463 }
1464
1465 return pp;
1466}
1467
1468static void shexec(char *cmd, char **argv)
1469{
1470 xsetenv(xmprintf("_=%s", cmd), 0);
1471 execve(cmd, argv, environ);
1472 if (errno == ENOEXEC) run_subshell("source \"$_\"", 11);
1473}
1474
1475
1476static void sh_exec(char **argv)
1477{
1478 char *pp = getvar("PATH" ? : _PATH_DEFPATH), *cc = TT.isexec ? : *argv;
1479 struct string_list *sl;
1480
1481 if (getpid() != TT.pid) signal(SIGINT, SIG_DFL);
1482 if (strchr(cc, '/')) shexec(cc, argv);
1483 else for (sl = find_in_path(pp, cc); sl; free(llist_pop(&sl)))
1484 shexec(sl->str, argv);
1485
1486 perror_msg("%s", *argv);
1487 if (!TT.isexec) _exit(127);
1488}
1489
1490
1491static struct sh_process *run_command(struct sh_arg *arg)
1492{
1493 char *s, *ss = 0, *sss, **env = 0, **old = environ;
1494 int envlen, jj, kk, ll;
1495 struct sh_process *pp;
1496 struct toy_list *tl;
1497
1498if (BUGBUG) dprintf(255, "run_command %s\n", arg->v[0]);
1499
1500
1501 for (envlen = 0; envlen<arg->c; envlen++) {
1502 s = varend(arg->v[envlen]);
1503 if (s == arg->v[envlen] || *s != '=') break;
1504 }
1505
1506
1507 pp = expand_redir(arg, envlen, 0);
1508
1509if (BUGBUG) { int i; dprintf(255, "envlen=%d arg->c=%d run=", envlen, arg->c); for (i=0; i<pp->arg.c; i++) dprintf(255, "'%s' ", pp->arg.v[i]); dprintf(255, "\n"); }
1510
1511 if (envlen == arg->c) {
1512 for (jj = 0; jj<envlen; jj++) {
1513 if (!(s = expand_one_arg(arg->v[jj], NO_PATH|NO_SPLIT, 0))) break;
1514 if (s == arg->v[jj]) s = xstrdup(s);
1515 setvar(s);
1516 }
1517 goto out;
1518 }
1519
1520 if (envlen) {
1521 for (kk = 0; environ[kk]; kk++);
1522 env = xmalloc(sizeof(char *)*(kk+33));
1523 memcpy(env, environ, sizeof(char *)*(kk+1));
1524 environ = env;
1525
1526
1527 for (jj = 0; jj<envlen; jj++) {
1528 if (!(sss = expand_one_arg(arg->v[jj], NO_PATH|NO_SPLIT, &pp->delete)))
1529 break;
1530 for (ll = 0; ll<kk; ll++) {
1531 for (s = sss, ss = environ[ll]; *s == *ss && *s != '='; s++, ss++);
1532 if (*s != '=') continue;
1533 environ[ll] = sss;
1534 break;
1535 }
1536 if (ll == kk) array_add(&environ, kk++, sss);
1537 }
1538 } else jj = 0;
1539
1540
1541 if (jj != envlen || pp->exit || !pp->arg.v);
1542
1543
1544
1545
1546 else if ((tl = toy_find(*pp->arg.v))
1547 && (tl->flags & (TOYFLAG_NOFORK|TOYFLAG_MAYFORK)))
1548 {
1549 sigjmp_buf rebound;
1550 char temp[jj = offsetof(struct toy_context, rebound)];
1551
1552
1553 memcpy(&temp, &toys, jj);
1554 memset(&toys, 0, jj);
1555
1556
1557
1558
1559
1560 memset(&TT, 0, offsetof(struct sh_data, lineno));
1561
1562 TT.pp = pp;
1563 if (!sigsetjmp(rebound, 1)) {
1564 toys.rebound = &rebound;
1565 toy_singleinit(tl, pp->arg.v);
1566 tl->toy_main();
1567 xflush(0);
1568 }
1569 TT.pp = 0;
1570 toys.rebound = 0;
1571 pp->exit = toys.exitval;
1572 if (toys.optargs != toys.argv+1) free(toys.optargs);
1573 if (toys.old_umask) umask(toys.old_umask);
1574 memcpy(&toys, &temp, jj);
1575 } else if (-1==(pp->pid = xpopen_setup(pp->arg.v+envlen, 0, sh_exec)))
1576 perror_msg("%s: vfork", *pp->arg.v);
1577
1578
1579 environ = old;
1580 free(env);
1581
1582out:
1583 setvarval("_", (envlen == arg->c) ? "" : s);
1584
1585 unredirect(pp->urd);
1586
1587 return pp;
1588}
1589
1590static void free_process(void *ppp)
1591{
1592 struct sh_process *pp = ppp;
1593 llist_traverse(pp->delete, llist_free_arg);
1594 free(pp);
1595}
1596
1597
1598
1599
1600static void free_pipeline(void *pipeline)
1601{
1602 struct sh_pipeline *pl = pipeline;
1603 int i, j;
1604
1605
1606 if (pl) for (j=0; j<=pl->count; j++) {
1607 for (i = 0; i<=pl->arg[j].c; i++) free(pl->arg[j].v[i]);
1608 free(pl->arg[j].v);
1609 }
1610 free(pl);
1611}
1612
1613
1614static struct sh_pipeline *block_end(struct sh_pipeline *pl)
1615{
1616 int i = 0;
1617
1618
1619
1620
1621 while (pl) {
1622 if (pl->type == 1 || pl->type == 'f') i++;
1623 else if (pl->type == 3) if (--i<1) break;
1624 pl = pl->next;
1625 }
1626
1627 return pl;
1628}
1629
1630static void free_function(struct sh_function *sp)
1631{
1632 llist_traverse(sp->pipeline, free_pipeline);
1633 llist_traverse(sp->expect, free);
1634 memset(sp, 0, sizeof(struct sh_function));
1635}
1636
1637
1638static struct sh_pipeline *add_function(char *name, struct sh_pipeline *pl)
1639{
1640dprintf(2, "stub add_function");
1641
1642 return block_end(pl->next);
1643}
1644
1645
1646
1647static int parse_line(char *line, struct sh_function *sp)
1648{
1649 char *start = line, *delete = 0, *end, *last = 0, *s, *ex, done = 0,
1650 *tails[] = {"fi", "done", "esac", "}", "]]", ")", 0};
1651 struct sh_pipeline *pl = sp->pipeline ? sp->pipeline->prev : 0;
1652 struct sh_arg *arg = 0;
1653 long i;
1654
1655
1656 if (pl) {
1657 arg = pl->arg;
1658
1659
1660 if (arg->c<0) {
1661 delete = start = xmprintf("%s%s", arg->v[arg->c = (-arg->c)-1], start);
1662 free(arg->v[arg->c]);
1663 arg->v[arg->c] = 0;
1664
1665
1666 } else if (pl->count != pl->here) {
1667 arg += 1+pl->here;
1668
1669
1670 for (s = line, end = arg->v[arg->c]; *s && *end; s++) {
1671 s += strspn(s, "\\\"'");
1672 if (*s != *end) break;
1673 }
1674 if (!*s && !*end) {
1675
1676 array_add(&arg->v, arg->c++, xstrdup(line));
1677 array_add(&arg->v, arg->c, arg->v[arg->c]);
1678 arg->c++;
1679
1680 } else {
1681 arg->v[arg->c] = 0;
1682 pl->here++;
1683 }
1684 start = 0;
1685
1686
1687 } else pl = 0;
1688 }
1689
1690
1691 if (start) for (;;) {
1692 ex = sp->expect ? sp->expect->prev->data : 0;
1693
1694
1695 if (pl && pl->count == -1) {
1696 pl->count = 0;
1697 arg = pl->arg;
1698
1699if (BUGBUG>1) dprintf(255, "{%d:%s}\n", pl->type, ex ? ex : (sp->expect ? "*" : ""));
1700
1701
1702 for (i = 0; i<arg->c; i++) {
1703 s = arg->v[i] + redir_prefix(arg->v[i]);
1704
1705
1706 if (strcmp(s, "<<") && strcmp(s, "<<-") && strcmp(s, "<<<")) continue;
1707 if (i+1 == arg->c) goto flush;
1708
1709
1710
1711 dlist_lpop(&sp->pipeline);
1712 pl = xrealloc(pl, sizeof(*pl) + ++pl->count*sizeof(struct sh_arg));
1713 dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl);
1714
1715
1716 arg[pl->count].v = xzalloc(2*sizeof(void *));
1717 arg[pl->count].v[0] = arg->v[++i];
1718 arg[pl->count].v[1] = 0;
1719 arg[pl->count].c = 0;
1720 if (s[2] == '<') pl->here++;
1721 }
1722 pl = 0;
1723 }
1724 if (done) break;
1725 s = 0;
1726
1727
1728 while (isspace(*start)) ++start;
1729 if (*start=='#') while (*start && *start != '\n') ++start;
1730
1731
1732 if ((end = parse_word(start, 0)) == (void *)1) goto flush;
1733
1734if (BUGBUG>1) dprintf(255, "[%.*s] ", end ? (int)(end-start) : 0, start);
1735
1736 if (!pl) {
1737 pl = xzalloc(sizeof(struct sh_pipeline));
1738 arg = pl->arg;
1739 dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl);
1740 }
1741
1742
1743 if (!end) {
1744
1745 array_add(&arg->v, arg->c++, xstrndup(start, strlen(start)));
1746 arg->c = -arg->c;
1747 free(delete);
1748
1749 return 1;
1750 }
1751
1752
1753
1754
1755
1756 if (end == start || (arg->c && *start == ')' && pl->type!='f')) {
1757 if (!arg->v) array_add(&arg->v, arg->c, 0);
1758
1759 if (pl->type == 'f' && arg->c<3) {
1760 s = "function()";
1761 goto flush;
1762 }
1763
1764
1765 if (arg->c == 1 && ex && !memcmp(ex, "do\0A", 4)) {
1766 s = "newline";
1767 goto flush;
1768 }
1769
1770
1771 if (!arg->c) free_pipeline(dlist_lpop(&sp->pipeline));
1772
1773
1774 if (end == start) done++;
1775 pl->count = -1;
1776 last = 0;
1777
1778 continue;
1779 }
1780
1781
1782 array_add(&arg->v, arg->c, s = xstrndup(start, end-start));
1783 start = end;
1784
1785 if (strchr(";|&", *s) && strncmp(s, "&>", 2)) {
1786
1787
1788 if (!strcmp(s, ";")) {
1789 arg->v[arg->c] = 0;
1790 free(s);
1791 s = 0;
1792
1793 if (!arg->c && ex && !memcmp(ex, "do\0C", 4)) continue;
1794
1795
1796 } else if (*s == ';' && (!ex || strcmp(ex, "esac"))) goto flush;
1797 last = s;
1798
1799
1800 if (!arg->c) goto flush;
1801 pl->count = -1;
1802
1803 continue;
1804 } else arg->v[++arg->c] = 0;
1805
1806
1807 if (arg->c>1 && !strcmp(s, "(")) pl->type = 'f';
1808 if (pl->type=='f') {
1809 if (arg->c == 2 && strcmp(s, "(")) goto flush;
1810 if (arg->c == 3) {
1811 if (strcmp(s, ")")) goto flush;
1812
1813
1814 pl->count = -1;
1815 last = 0;
1816 dlist_add(&sp->expect, "}");
1817 dlist_add(&sp->expect, 0);
1818 dlist_add(&sp->expect, "{");
1819
1820 continue;
1821 }
1822
1823
1824 } else if (ex && !memcmp(ex, "do\0A", 4)) {
1825
1826
1827 if (strncmp(s, "((", 2) && strchr(s, '=')) goto flush;
1828 pl->count = -1;
1829 sp->expect->prev->data = "do\0C";
1830
1831 continue;
1832
1833
1834 } else if (arg->c>1) continue;
1835
1836
1837 if (ex) {
1838
1839 if (!strcmp(ex, "{")) {
1840 if (strcmp(s, "{")) goto flush;
1841 free(arg->v[--arg->c]);
1842 free(dlist_lpop(&sp->expect));
1843
1844 continue;
1845
1846
1847
1848 } else if (!memcmp(ex, "do\0C", 4)) {
1849 if (strcmp(s, "do")) {
1850
1851 if (pl->prev->type == 's') goto flush;
1852 if (!strncmp(pl->prev->arg->v[1], "((", 2)) goto flush;
1853 else if (strcmp(s, "in")) goto flush;
1854 pl->type = 's';
1855
1856 continue;
1857 }
1858 }
1859 }
1860
1861
1862
1863
1864 if (!strcmp(s, "for") || !strcmp(s, "select")) {
1865 if (!pl->type) pl->type = 1;
1866 dlist_add(&sp->expect, "do\0A");
1867
1868 continue;
1869 }
1870
1871 end = 0;
1872 if (!strcmp(s, "if")) end = "then";
1873 else if (!strcmp(s, "while") || !strcmp(s, "until")) end = "do\0B";
1874 else if (!strcmp(s, "case")) end = "esac";
1875 else if (!strcmp(s, "{")) end = "}";
1876 else if (!strcmp(s, "[[")) end = "]]";
1877 else if (!strcmp(s, "(")) end = ")";
1878
1879
1880 if (!ex && sp->expect) free(dlist_lpop(&sp->expect));
1881
1882
1883 if (end) {
1884 pl->type = 1;
1885
1886
1887 if (sp->expect && !sp->expect->prev->data) free(dlist_lpop(&sp->expect));
1888
1889
1890 } else if (!ex);
1891
1892
1893 else if (!strcmp(s, ex)) {
1894
1895 if (last && (strcmp(ex, "then") || strcmp(last, "&"))) {
1896 s = end;
1897 goto flush;
1898 }
1899
1900 free(dlist_lpop(&sp->expect));
1901 pl->type = anystr(s, tails) ? 3 : 2;
1902
1903
1904 if (!strcmp(s, "do")) end = "done";
1905 else if (!strcmp(s, "then")) end = "fi\0A";
1906
1907
1908 } else if (!strcmp(ex, "fi")) {
1909 if (!strcmp(s, "elif")) {
1910 free(dlist_lpop(&sp->expect));
1911 end = "then";
1912
1913 } else if (!strcmp(s, "else")) {
1914 if (ex[3] != 'A') {
1915 s = "2 else";
1916 goto flush;
1917 }
1918 free(dlist_lpop(&sp->expect));
1919 end = "fi\0B";
1920 }
1921 }
1922
1923
1924 if (end) {
1925 if (!pl->type) pl->type = 2;
1926
1927 dlist_add(&sp->expect, end);
1928 if (!anystr(end, tails)) dlist_add(&sp->expect, 0);
1929 pl->count = -1;
1930 }
1931
1932
1933 if (!pl->type && anystr(s, (char *[]){"then", "do", "esac", "}", "]]", ")",
1934 "done", "fi", "elif", "else", 0})) goto flush;
1935 }
1936 free(delete);
1937
1938
1939 if (!sp->pipeline) return 0;
1940
1941
1942
1943 pl = sp->pipeline->prev;
1944 while (pl->count<pl->here && pl->arg[pl->count].c<0)
1945 pl->arg[pl->count++].c = 0;
1946
1947
1948 if (sp->expect) return 1;
1949 if (sp->pipeline && pl->count != pl->here) return 1;
1950 if (pl->arg->v[pl->arg->c]) return 1;
1951
1952
1953
1954 dlist_terminate(sp->pipeline);
1955 return 0;
1956
1957flush:
1958 if (s) syntax_err(s);
1959 free_function(sp);
1960
1961 return 0-!!s;
1962}
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972static int wait_pipeline(struct sh_process *pp)
1973{
1974 int rc = 0;
1975
1976 for (dlist_terminate(pp); pp; pp = pp->next) {
1977 if (pp->pid) {
1978
1979 pp->exit = xwaitpid(pp->pid);
1980 pp->pid = 0;
1981 }
1982
1983 rc = pp->not ? !pp->exit : pp->exit;
1984 }
1985
1986 return rc;
1987}
1988
1989
1990static int pipe_segments(char *ctl, int *pipes, int **urd)
1991{
1992 unredirect(*urd);
1993 *urd = 0;
1994
1995
1996 if (*pipes != -1) {
1997 if (save_redirect(urd, *pipes, 0)) return 1;
1998 close(*pipes);
1999 *pipes = -1;
2000 }
2001
2002
2003 if (ctl && *ctl == '|' && ctl[1] != '|') {
2004 if (pipe(pipes)) {
2005 perror_msg("pipe");
2006
2007
2008 return 1;
2009 }
2010 if (save_redirect(urd, pipes[1], 1)) {
2011 close(pipes[0]);
2012 close(pipes[1]);
2013
2014 return 1;
2015 }
2016 if (pipes[1] != 1) close(pipes[1]);
2017 fcntl(*pipes, F_SETFD, FD_CLOEXEC);
2018 if (ctl[1] == '&') save_redirect(urd, 1, 2);
2019 }
2020
2021 return 0;
2022}
2023
2024
2025static struct sh_pipeline *skip_andor(int rc, struct sh_pipeline *pl)
2026{
2027 char *ctl = pl->arg->v[pl->arg->c];
2028
2029
2030 while (ctl && ((!strcmp(ctl, "&&") && rc) || (!strcmp(ctl, "||") && !rc))) {
2031 if (!pl->next || pl->next->type == 2 || pl->next->type == 3) break;
2032 pl = pl->type ? block_end(pl) : pl->next;
2033 ctl = pl ? pl->arg->v[pl->arg->c] : 0;
2034 }
2035
2036 return pl;
2037}
2038
2039struct blockstack {
2040 struct blockstack *next;
2041 struct sh_pipeline *start, *end;
2042 struct sh_process *pin;
2043 int run, loop, *urd, pout;
2044 struct sh_arg farg;
2045 struct arg_list *fdelete;
2046 char *fvar;
2047};
2048
2049
2050static struct sh_pipeline *pop_block(struct blockstack **blist, int *pout)
2051{
2052 struct blockstack *blk = *blist;
2053 struct sh_pipeline *pl = blk->end;
2054
2055
2056 if (*pout != -1) close(*pout);
2057 *pout = blk->pout;
2058 unredirect(blk->urd);
2059 llist_traverse(blk->fdelete, free);
2060 free(llist_pop(blist));
2061
2062 return pl;
2063}
2064
2065
2066
2067
2068static void run_function(struct sh_pipeline *pl)
2069{
2070 struct sh_pipeline *end;
2071 struct blockstack *blk = 0, *new;
2072 struct sh_process *pplist = 0;
2073 int *urd = 0, pipes[2] = {-1, -1};
2074 long i;
2075
2076
2077
2078 TT.hfd = 10;
2079
2080
2081 while (pl) {
2082 struct sh_arg *arg = pl->arg;
2083 char *s = *arg->v, *ss = arg->v[1], *ctl = arg->v[arg->c];
2084if (BUGBUG) dprintf(255, "%d runtype=%d %s %s\n", getpid(), pl->type, s, ctl);
2085
2086 if (!pl->type) {
2087
2088
2089 if (blk && !blk->run) {
2090 pl = pl->next;
2091 continue;
2092 }
2093 if (pipe_segments(ctl, pipes, &urd)) break;
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105 if (!strcmp(s, "break") || !strcmp(s, "continue")) {
2106
2107
2108 i = ss ? atol(ss) : 0;
2109 if (i<1) i = 1;
2110 if (!blk || arg->c>2 || ss[strspn(ss, "0123456789")]) {
2111 syntax_err(s);
2112 break;
2113 }
2114
2115 while (i && blk)
2116 if (!--i && *s == 'c') pl = blk->start;
2117 else pl = pop_block(&blk, pipes);
2118 if (i) {
2119 syntax_err("break outside loop");
2120 break;
2121 }
2122 pl = pl->next;
2123 continue;
2124
2125
2126 } else {
2127
2128
2129
2130
2131
2132
2133 dlist_add_nomalloc((void *)&pplist, (void *)run_command(arg));
2134 }
2135
2136 if (*pipes == -1) {
2137 toys.exitval = wait_pipeline(pplist);
2138 llist_traverse(pplist, free_process);
2139 pplist = 0;
2140 pl = skip_andor(toys.exitval, pl);
2141 }
2142
2143
2144 } else if (pl->type == 1) {
2145 struct sh_process *pp = 0;
2146 int rc;
2147
2148
2149 if (!blk || blk->start != pl) {
2150
2151
2152 end = block_end(pl->next);
2153 if (blk && !blk->run) {
2154 pl = end;
2155 if (pl) pl = pl->next;
2156 continue;
2157 }
2158
2159
2160 if (pipe_segments(end->arg->v[end->arg->c], pipes, &urd)) break;
2161
2162
2163 new = xzalloc(sizeof(*blk));
2164 new->next = blk;
2165 blk = new;
2166 blk->start = pl;
2167 blk->end = end;
2168 blk->run = 1;
2169
2170
2171 blk->pout = *pipes;
2172 blk->urd = urd;
2173 urd = 0;
2174 *pipes = -1;
2175
2176
2177 pp = expand_redir(end->arg, 1, blk->urd);
2178 blk->urd = pp->urd;
2179 rc = pp->exit;
2180 if (pp->arg.c) {
2181 syntax_err(*pp->arg.v);
2182 rc = 1;
2183 }
2184 llist_traverse(pp->delete, free);
2185 free(pp);
2186 if (rc) {
2187 toys.exitval = rc;
2188 break;
2189 }
2190 }
2191
2192
2193
2194
2195
2196
2197 if (!strcmp(s, "for") || !strcmp(s, "select")) {
2198 if (blk->loop);
2199 else if (!strncmp(blk->fvar = ss, "((", 2)) {
2200 blk->loop = 1;
2201dprintf(2, "TODO skipped init for((;;)), need math parser\n");
2202 } else {
2203
2204
2205 if (pl->next->type == 's') {
2206 for (i = 1; i<pl->next->arg->c; i++)
2207 if (expand_arg(&blk->farg, pl->next->arg->v[i], 0, &blk->fdelete))
2208 break;
2209 if (i != pl->next->arg->c) {
2210 pl = pop_block(&blk, pipes)->next;
2211 continue;
2212 }
2213
2214 } else expand_arg(&blk->farg, "\"$@\"", 0, &blk->fdelete);
2215 }
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228 } else if (!strcmp(s, "(")) {
2229 if (!CFG_TOYBOX_FORK) {
2230 ss = pl2str(pl->next);
2231 pp->pid = run_subshell(ss, strlen(ss));
2232 free(ss);
2233 } else {
2234 if (!(pp->pid = fork())) {
2235 run_function(pl->next);
2236 _exit(toys.exitval);
2237 }
2238 }
2239
2240 dlist_add_nomalloc((void *)&pplist, (void *)pp);
2241 pl = blk->end->prev;
2242 }
2243
2244
2245 } else if (pl->type == 2) {
2246
2247
2248 if (!strcmp(s, "then")) blk->run = blk->run && !toys.exitval;
2249 else if (!strcmp(s, "else") || !strcmp(s, "elif")) blk->run = !blk->run;
2250 else if (!strcmp(s, "do")) {
2251 ss = *blk->start->arg->v;
2252 if (!strcmp(ss, "while")) blk->run = blk->run && !toys.exitval;
2253 else if (!strcmp(ss, "until")) blk->run = blk->run && toys.exitval;
2254 else if (blk->loop >= blk->farg.c) {
2255 blk->run = 0;
2256 pl = block_end(pl);
2257 continue;
2258 } else if (!strncmp(blk->fvar, "((", 2)) {
2259dprintf(2, "TODO skipped running for((;;)), need math parser\n");
2260 } else setvarval(blk->fvar, blk->farg.v[blk->loop++]);
2261 }
2262
2263
2264 } else if (pl->type == 3) {
2265
2266
2267 if (!blk) break;
2268
2269
2270 if (blk->run && !strcmp(s, "done")) {
2271 pl = blk->start;
2272 continue;
2273 }
2274
2275 pop_block(&blk, pipes);
2276 } else if (pl->type == 'f') pl = add_function(s, pl);
2277
2278 pl = pl->next;
2279 }
2280
2281
2282
2283 if (*pipes != -1) close(*pipes);
2284 if (pplist) {
2285 toys.exitval = wait_pipeline(pplist);
2286 llist_traverse(pplist, free_process);
2287 }
2288 unredirect(urd);
2289
2290
2291 while (blk) pop_block(&blk, pipes);
2292}
2293
2294
2295static int sh_run(char *new)
2296{
2297 struct sh_function scratch;
2298
2299
2300
2301 memset(&scratch, 0, sizeof(struct sh_function));
2302 if (!parse_line(new, &scratch)) run_function(scratch.pipeline);
2303 free_function(&scratch);
2304
2305 return toys.exitval;
2306}
2307
2308
2309
2310static void do_prompt(char *prompt)
2311{
2312 char *s, *ss, c, cc, *pp = toybuf;
2313 int len, ll;
2314
2315 if (!prompt) return;
2316 while ((len = sizeof(toybuf)-(pp-toybuf))>0 && *prompt) {
2317 c = *(prompt++);
2318
2319 if (c=='!') {
2320 if (*prompt=='!') prompt++;
2321 else {
2322 pp += snprintf(pp, len, "%ld", TT.lineno);
2323 continue;
2324 }
2325 } else if (c=='\\') {
2326 cc = *(prompt++);
2327 if (!cc) {
2328 *pp++ = c;
2329 break;
2330 }
2331
2332
2333
2334 if (cc=='[' || cc==']') continue;
2335 else if (cc=='$') *pp++ = getuid() ? '$' : '#';
2336 else if (cc=='h' || cc=='H') {
2337 *pp = 0;
2338 gethostname(pp, len);
2339 pp[len-1] = 0;
2340 if (cc=='h' && (s = strchr(pp, '.'))) *s = 0;
2341 pp += strlen(pp);
2342 } else if (cc=='s') {
2343 s = getbasename(*toys.argv);
2344 while (*s && len--) *pp++ = *s++;
2345 } else if (cc=='w') {
2346 if ((s = getvar("PWD"))) {
2347 if ((ss = getvar("HOME")) && strstart(&s, ss)) {
2348 *pp++ = '~';
2349 if (--len && *s!='/') *pp++ = '/';
2350 len--;
2351 }
2352 if (len>0) {
2353 ll = strlen(s);
2354 pp = stpncpy(pp, s, ll>len ? len : ll);
2355 }
2356 }
2357 } else if (!(c = unescape(cc))) {
2358 *pp++ = '\\';
2359 if (--len) *pp++ = c;
2360 } else *pp++ = c;
2361 } else *pp++ = c;
2362 }
2363 len = pp-toybuf;
2364 if (len>=sizeof(toybuf)) len = sizeof(toybuf);
2365 writeall(2, toybuf, len);
2366}
2367
2368
2369static struct sh_vars *initlocal(char *name, char *val)
2370{
2371 return addvar(xmprintf("%s=%s", name, val ? val : ""));
2372}
2373
2374static struct sh_vars *initlocaldef(char *name, char *val, char *def)
2375{
2376 return initlocal(name, (!val || !*val) ? def : val);
2377}
2378
2379
2380static void export(char *str)
2381{
2382 struct sh_vars *shv = 0;
2383 char *s;
2384
2385
2386 if (strchr(str, '=')) shv = setvar(xstrdup(str));
2387 else if (!(shv = findvar(str))) shv = addvar(str = xmprintf("%s=", str));
2388 if (!shv || (shv->flags&VAR_GLOBAL)) return;
2389
2390
2391 if (shv->flags&VAR_MAGIC) {
2392 s = shv->str;
2393 shv->str = xmprintf("%.*s=%s", (int)(varend(str)-str), str, getvar(str));
2394 free(s);
2395 }
2396
2397 xsetenv(shv->str, 0);
2398 shv->flags |= VAR_GLOBAL;
2399}
2400
2401static void unexport(char *str)
2402{
2403 struct sh_vars *shv = findvar(str);
2404
2405 if (shv) {
2406 if (shv->flags&VAR_GLOBAL) shv->str = xpop_env(str);
2407 shv->flags &=~VAR_GLOBAL;
2408 }
2409 if (strchr(str, '=')) setvar(str);
2410}
2411
2412
2413static void subshell_setup(void)
2414{
2415 int ii, to, from, pid, ppid, zpid, myppid = getppid(), len, uid = getuid();
2416 struct passwd *pw = getpwuid(uid);
2417 char *s, *ss, *magic[] = {"SECONDS","RANDOM","LINENO","GROUPS"},
2418 *readonly[] = {xmprintf("EUID=%d", geteuid()), xmprintf("UID=%d", uid),
2419 xmprintf("PPID=%d", myppid)};
2420 struct stat st;
2421 struct utsname uu;
2422 FILE *fp;
2423
2424
2425 srandom(TT.SECONDS = millitime());
2426 for (ii = 0; ii<ARRAY_LEN(magic); ii++)
2427 initlocal(magic[ii], "")->flags = VAR_MAGIC|(VAR_INT*('G'!=*magic[ii]));
2428 for (ii = 0; ii<ARRAY_LEN(readonly); ii++)
2429 addvar(readonly[ii])->flags = VAR_READONLY|VAR_INT;
2430
2431
2432 initlocal("PATH", _PATH_DEFPATH);
2433 if (!pw) pw = (void *)toybuf;
2434 sprintf(toybuf+1024, "%u", uid);
2435 initlocaldef("HOME", pw->pw_dir, "/");
2436 initlocaldef("SHELL", pw->pw_shell, "/bin/sh");
2437 initlocaldef("USER", pw->pw_name, toybuf+1024);
2438 initlocaldef("LOGNAME", pw->pw_name, toybuf+1024);
2439 gethostname(toybuf, sizeof(toybuf)-1);
2440 initlocal("HOSTNAME", toybuf);
2441 uname(&uu);
2442 initlocal("HOSTTYPE", uu.machine);
2443 sprintf(toybuf, "%s-unknown-linux", uu.machine);
2444 initlocal("MACHTYPE", toybuf);
2445 initlocal("OSTYPE", uu.sysname);
2446
2447
2448 initlocal("OPTERR", "1");
2449 if (readlink0("/proc/self/exe", s = toybuf, sizeof(toybuf))||(s=getenv("_")))
2450 initlocal("BASH", s);
2451 initlocal("PS2", "> ");
2452
2453
2454 TT.ifs = " \t\n";
2455 xsetenv("", 0);
2456 for (to = from = pid = ppid = zpid = 0; (s = environ[from]); from++) {
2457
2458
2459 if (!CFG_TOYBOX_FORK && !toys.stacktop) {
2460 len = 0;
2461 sscanf(s, "@%d,%d%n", &pid, &ppid, &len);
2462 if (s[len]) pid = ppid = 0;
2463 if (*s == '$' && s[1] == '=') zpid = atoi(s+2);
2464
2465 }
2466
2467
2468
2469 ss = varend(s);
2470 if (*ss == '=') {
2471 struct sh_vars *shv = findvar(s);
2472
2473 if (!shv) addvar(environ[from])->flags = VAR_GLOBAL;
2474 else if (shv->flags&VAR_READONLY) continue;
2475 else {
2476 shv->flags |= VAR_GLOBAL;
2477 free(shv->str);
2478 shv->str = s;
2479 }
2480 environ[to++] = s;
2481 }
2482 if (!memcmp(s, "IFS=", 4)) TT.ifs = s+4;
2483 }
2484 environ[toys.optc = to] = 0;
2485
2486
2487 sh_run("cd .");
2488
2489
2490 s = toys.argv[0];
2491 ss = 0;
2492 if (!strchr(s, '/')) {
2493 if ((ss = getcwd(0, 0))) {
2494 s = xmprintf("%s/%s", ss, s);
2495 free(ss);
2496 ss = s;
2497 } else if (*toybuf) s = toybuf;
2498 }
2499 s = xsetenv("_", s);
2500 if (!findvar(s)) addvar(s)->flags = VAR_GLOBAL;
2501 free(ss);
2502 if (!(ss = getvar("SHLVL"))) export("SHLVL=1");
2503 else {
2504 char buf[16];
2505
2506 sprintf(buf, "%u", atoi(ss+6)+1);
2507 xsetenv("SHLVL", buf);
2508 export("SHLVL");
2509 }
2510
2511
2512
2513
2514
2515 if (CFG_TOYBOX_FORK || toys.stacktop || pid!=getpid() || ppid!=myppid) return;
2516 if (fstat(254, &st) || !S_ISFIFO(st.st_mode)) error_exit(0);
2517 TT.pid = zpid;
2518 fcntl(254, F_SETFD, FD_CLOEXEC);
2519 fp = fdopen(254, "r");
2520
2521
2522
2523 while ((s = xgetline(fp, 0))) toys.exitval = sh_run(s);
2524 fclose(fp);
2525
2526 xexit();
2527}
2528
2529void sh_main(void)
2530{
2531 char *new, *cc = TT.sh.c;
2532 struct sh_function scratch;
2533 int prompt = 0;
2534 struct string_list *sl = 0;
2535 struct sh_arg arg;
2536 FILE *f;
2537
2538 signal(SIGPIPE, SIG_IGN);
2539 TT.options = OPT_BRACE;
2540
2541 TT.pid = getpid();
2542 TT.SECONDS = time(0);
2543 TT.arg = &arg;
2544 if (!(arg.c = toys.optc)) {
2545 arg.v = xmalloc(2*sizeof(char *));
2546 arg.v[arg.c++] = *toys.argv;
2547 arg.v[arg.c] = 0;
2548 } else memcpy(arg.v = xmalloc((arg.c+1)*sizeof(char *)), toys.optargs,
2549 (arg.c+1)*sizeof(char *));
2550
2551
2552
2553
2554
2555
2556
2557if (BUGBUG) { int fd = open("/dev/tty", O_RDWR); if (fd == -1) fd = open("/dev/console", O_RDWR); if (fd == -1) dup2(2, 255); else dup2(fd, 255); close(fd); }
2558
2559
2560 if (FLAG(s) || (!FLAG(c) && !toys.optc)) TT.options |= OPT_S;
2561 if (FLAG(i) || (!FLAG(c) && (TT.options&OPT_S) && isatty(0)))
2562 TT.options |= OPT_I;
2563 if (FLAG(c)) TT.options |= OPT_C;
2564
2565
2566
2567
2568 subshell_setup();
2569 if (TT.options&OPT_I) {
2570 if (!getvar("PS1")) setvarval("PS1", getpid() ? "\\$ " : "# ");
2571
2572
2573
2574 xsignal(SIGINT, SIG_IGN);
2575 }
2576
2577 memset(&scratch, 0, sizeof(scratch));
2578
2579
2580 if (cc) f = fmemopen(cc, strlen(cc), "r");
2581 else if (TT.options&OPT_S) f = stdin;
2582
2583 else if (!(f = fopen(*toys.optargs, "r"))) {
2584 char *pp = getvar("PATH") ? : _PATH_DEFPATH;
2585
2586 for (sl = find_in_path(pp, *toys.optargs); sl; free(llist_pop(&sl)))
2587 if ((f = fopen(sl->str, "r"))) break;
2588 if (sl) llist_traverse(sl->next, free);
2589 else perror_exit_raw(*toys.optargs);
2590 }
2591
2592
2593 for (;;) {
2594 TT.lineno++;
2595 if ((TT.options&(OPT_I|OPT_S|OPT_C)) == (OPT_I|OPT_S))
2596 do_prompt(getvar(prompt ? "PS2" : "PS1"));
2597
2598
2599 if (!(new = xgetline(f, 0))) {
2600
2601 if (errno != EINTR) break;
2602 free_function(&scratch);
2603 prompt = 0;
2604 if (f != stdin) break;
2605 continue;
2606
2607
2608 }
2609
2610if (BUGBUG) dprintf(255, "line=%s\n", new);
2611 if (sl) {
2612 if (*new == 0x7f) error_exit("'%s' is ELF", sl->str);
2613 free(sl);
2614 sl = 0;
2615 }
2616
2617
2618
2619 prompt = parse_line(new, &scratch);
2620if (BUGBUG) dump_state(&scratch);
2621 if (prompt != 1) {
2622
2623 if (!prompt) run_function(scratch.pipeline);
2624 free_function(&scratch);
2625 prompt = 0;
2626 }
2627 free(new);
2628 }
2629
2630 if (prompt) error_exit("%ld:unfinished line"+4*!TT.lineno, TT.lineno);
2631}
2632
2633
2634
2635#define CLEANUP_sh
2636#define FOR_cd
2637#include "generated/flags.h"
2638void cd_main(void)
2639{
2640 char *home = getvar("HOME") ? : "/", *pwd = getvar("PWD"), *from, *to = 0,
2641 *dd = xstrdup(*toys.optargs ? *toys.optargs : home);
2642 int bad = 0;
2643
2644
2645
2646
2647 if (*dd != '/') {
2648 from = pwd ? : (to = getcwd(0, 0));
2649 if (!from) setvarval("PWD", "(nowhere)");
2650 else {
2651 from = xmprintf("%s/%s", from, dd);
2652 free(dd);
2653 free(to);
2654 dd = from;
2655 }
2656 }
2657
2658 if (FLAG(P)) {
2659 struct stat st;
2660 char *pp;
2661
2662
2663 if ((pp = xabspath(dd, 1)) && stat(pp, &st) && !S_ISDIR(st.st_mode))
2664 bad++, errno = ENOTDIR;
2665 else {
2666 free(dd);
2667 dd = pp;
2668 }
2669 } else {
2670
2671
2672 for (from = to = dd; *from;) {
2673 if (*from=='/' && from[1]=='/') from++;
2674 else if (*from!='/' || from[1]!='.') *to++ = *from++;
2675 else if (!from[2] || from[2]=='/') from += 2;
2676 else if (from[2]=='.' && (!from[3] || from[3]=='/')) {
2677 from += 3;
2678 while (to>dd && *--to != '/');
2679 } else *to++ = *from++;
2680 }
2681 if (to == dd) to++;
2682 if (to-dd>1 && to[-1]=='/') to--;
2683 *to = 0;
2684 }
2685
2686 if (bad || chdir(dd)) perror_msg("chdir '%s'", dd);
2687 else {
2688 if (pwd) {
2689 setvarval("OLDPWD", pwd);
2690 if (TT.cdcount == 1) {
2691 export("OLDPWD");
2692 TT.cdcount++;
2693 }
2694 }
2695 setvarval("PWD", dd);
2696 if (!TT.cdcount) {
2697 export("PWD");
2698 TT.cdcount++;
2699 }
2700 }
2701 free(dd);
2702}
2703
2704void exit_main(void)
2705{
2706 exit(*toys.optargs ? atoi(*toys.optargs) : 0);
2707}
2708
2709void unset_main(void)
2710{
2711 char **arg, *s;
2712
2713 for (arg = toys.optargs; *arg; arg++) {
2714 s = varend(*arg);
2715 if (s == *arg || *s) {
2716 error_msg("bad '%s'", *arg);
2717 continue;
2718 }
2719
2720
2721 if (!strcmp(*arg, "IFS")) TT.ifs = " \t\n";
2722 unsetvar(*arg);
2723 }
2724}
2725
2726#define CLEANUP_cd
2727#define FOR_export
2728#include "generated/flags.h"
2729
2730void export_main(void)
2731{
2732 char **arg, *eq;
2733
2734
2735 if (!toys.optc) {
2736 for (arg = environ; *arg; arg++) xprintf("declare -x %s\n", *arg);
2737 return;
2738 }
2739
2740
2741 for (arg = toys.optargs; *arg; arg++) {
2742 eq = varend(*arg);
2743 if (eq == *arg || (*eq && *eq != '=')) {
2744 error_msg("bad %s", *arg);
2745 continue;
2746 }
2747
2748 if (FLAG(n)) unexport(*arg);
2749 else export(*arg);
2750 }
2751}
2752
2753void eval_main(void)
2754{
2755 struct sh_arg *old = TT.arg, new = {toys.argv, toys.optc+1};
2756 char *s;
2757
2758 TT.arg = &new;
2759 s = expand_one_arg("\"$*\"", SEMI_IFS, 0);
2760 TT.arg = old;
2761 sh_run(s);
2762 free(s);
2763}
2764
2765#define CLEANUP_export
2766#define FOR_exec
2767#include "generated/flags.h"
2768
2769void exec_main(void)
2770{
2771 char *ee[1] = {0}, **old = environ;
2772
2773
2774 free(TT.pp->urd);
2775 TT.pp->urd = 0;
2776 if (!toys.optc) return;
2777
2778
2779 TT.isexec = *toys.optargs;
2780 if (FLAG(c)) environ = ee;
2781 if (TT.exec.a || FLAG(l))
2782 *toys.optargs = xmprintf("%s%s", FLAG(l) ? "-" : "", TT.exec.a?:TT.isexec);
2783 sh_exec(toys.optargs);
2784
2785
2786 perror_msg("%s", TT.isexec);
2787 TT.isexec = 0;
2788 toys.exitval = 127;
2789 environ = old;
2790}
2791
2792void shift_main(void)
2793{
2794 long long by = 1;
2795
2796 if (toys.optc) by = atolx(*toys.optargs);
2797 by += TT.shift;
2798 if (by<0 || by>= TT.arg->c) toys.exitval++;
2799 else TT.shift = by;
2800}
2801