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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176#define FOR_sh
177#include "toys.h"
178
179GLOBALS(
180 union {
181 struct {
182 char *c;
183 } sh;
184 struct {
185 char *a;
186 } exec;
187 };
188
189
190 long lineno;
191 char *ifs, *isexec, *wcpat;
192 unsigned options, jobcnt;
193 int hfd, pid, bangpid, varslen, shift, cdcount;
194 long long SECONDS;
195
196
197 struct sh_vars {
198 long flags;
199 char *str;
200 } *vars;
201
202
203 struct sh_function {
204 char *name;
205 struct sh_pipeline {
206 struct sh_pipeline *next, *prev, *end;
207 int count, here, type;
208 struct sh_arg {
209 char **v;
210 int c;
211 } arg[1];
212 } *pipeline;
213 struct double_list *expect;
214 } *functions;
215
216
217 struct sh_process {
218 struct sh_process *next, *prev;
219 struct arg_list *delete;
220
221 int *urd, envlen, pid, exit, not, job;
222 long long when;
223 struct sh_arg *raw, arg;
224 } *pp;
225
226
227 struct sh_arg jobs, *arg, *wcdeck;
228)
229
230
231
232static int sh_run(char *new);
233
234
235
236
237static const char *redirectors[] = {"<<<", "<<-", "<<", "<&", "<>", "<", ">>",
238 ">&", ">|", ">", "&>>", "&>", 0};
239
240#define OPT_I 1
241#define OPT_BRACE 2
242#define OPT_NOCLOBBER 4
243#define OPT_S 8
244#define OPT_C 16
245
246static void syntax_err(char *s)
247{
248 error_msg("syntax error: %s", s);
249 toys.exitval = 2;
250 if (!(TT.options&OPT_I)) xexit();
251}
252
253
254static void arg_add(struct sh_arg *arg, char *data)
255{
256
257 if (!(arg->c&31) && (arg->c || !arg->v))
258 arg->v = xrealloc(arg->v, sizeof(char *)*(arg->c+33));
259 arg->v[arg->c++] = data;
260 arg->v[arg->c] = 0;
261}
262
263
264static char *push_arg(struct arg_list **list, char *arg)
265{
266 struct arg_list *al;
267
268 if (list) {
269 al = xmalloc(sizeof(struct arg_list));
270 al->next = *list;
271 al->arg = arg;
272 *list = al;
273 }
274
275 return arg;
276}
277
278static void arg_add_del(struct sh_arg *arg, char *data,struct arg_list **delete)
279{
280 arg_add(arg, push_arg(delete, data));
281}
282
283
284static char *varend(char *s)
285{
286 if (isdigit(*s)) return s;
287 while (*s>' ' && (*s=='_' || !ispunct(*s))) s++;
288
289 return s;
290}
291
292
293static struct sh_vars *findvar(char *name)
294{
295 int len = varend(name)-name;
296 struct sh_vars *var = TT.vars+TT.varslen;
297
298 if (len) while (var-- != TT.vars)
299 if (!strncmp(var->str, name, len) && var->str[len] == '=') return var;
300
301 return 0;
302}
303
304
305static struct sh_vars *addvar(char *s)
306{
307 if (!(TT.varslen&31))
308 TT.vars = xrealloc(TT.vars, (TT.varslen+32)*sizeof(*TT.vars));
309 TT.vars[TT.varslen].flags = 0;
310 TT.vars[TT.varslen].str = s;
311
312 return TT.vars+TT.varslen++;
313}
314
315
316long long do_math(char **s)
317{
318 long long ll;
319
320 while (isspace(**s)) ++*s;
321 ll = strtoll(*s, s, 0);
322 while (isspace(**s)) ++*s;
323
324 return ll;
325}
326
327
328
329#define VAR_DICT 256
330#define VAR_ARRAY 128
331#define VAR_INT 64
332#define VAR_TOLOWER 32
333#define VAR_TOUPPER 16
334#define VAR_NAMEREF 8
335#define VAR_GLOBAL 4
336#define VAR_READONLY 2
337#define VAR_MAGIC 1
338
339
340
341static struct sh_vars *setvar(char *s)
342{
343 int len = varend(s)-s;
344 long flags;
345 struct sh_vars *var;
346
347 if (s[len] != '=') {
348 error_msg("bad setvar %s\n", s);
349 free(s);
350
351 return 0;
352 }
353 if (!strncmp(s, "IFS=", 4)) TT.ifs = s+4;
354 if (!(var = findvar(s))) return addvar(s);
355 flags = var->flags;
356
357 if (flags&VAR_READONLY) {
358 error_msg("%.*s: read only", len, s);
359 free(s);
360
361 return 0;
362 }
363
364
365
366
367
368
369
370 if (flags&VAR_MAGIC) {
371 char *ss = s+len-1;
372
373
374 if (*s == 'S') TT.SECONDS = millitime() - 1000*do_math(&ss);
375 else if (*s == 'R') srandom(do_math(&ss));
376 } else if (flags&VAR_GLOBAL) xsetenv(var->str = s, 0);
377 else {
378 free(var->str);
379 var->str = s;
380 }
381
382 return var;
383}
384
385static void unsetvar(char *name)
386{
387 struct sh_vars *var = findvar(name);
388 int ii = var-TT.vars;
389
390 if (!var) return;
391 if (var->flags&VAR_GLOBAL) xunsetenv(name);
392 else free(var->str);
393
394 memmove(TT.vars+ii, TT.vars+ii+1, TT.varslen-ii);
395 TT.varslen--;
396}
397
398static struct sh_vars *setvarval(char *name, char *val)
399{
400 return setvar(xmprintf("%s=%s", name, val));
401}
402
403
404static char *getvar(char *s)
405{
406 struct sh_vars *var = findvar(s);
407
408 if (!var) return 0;
409
410 if (var->flags & VAR_MAGIC) {
411 char c = *var->str;
412
413 if (c == 'S') sprintf(toybuf, "%lld", (millitime()-TT.SECONDS)/1000);
414 else if (c == 'R') sprintf(toybuf, "%ld", random()&((1<<16)-1));
415 else if (c == 'L') sprintf(toybuf, "%ld", TT.lineno);
416 else if (c == 'G') sprintf(toybuf, "TODO: GROUPS");
417
418 return toybuf;
419 }
420
421 return varend(var->str)+1;
422}
423
424
425static char *declarep(struct sh_vars *var)
426{
427 char *types = "-rgnuliaA", *in = types, flags[16], *out = flags, *ss;
428 int len;
429
430 while (*++in) if (var->flags&(1<<(in-types))) *out++ = *in;
431 if (in == types) *out++ = *types;
432 *out = 0;
433 len = out-flags;
434
435 for (in = types = varend(var->str); *in; in++) len += !!strchr("$\"\\`", *in);
436 len += in-types;
437 ss = xmalloc(len+15);
438
439 out = ss + sprintf(ss, "declare -%s \"", out);
440 while (*types) {
441 if (strchr("$\"\\`", *types)) *out++ = '\\';
442 *out++ = *types++;
443 }
444 *out++ = '"';
445 *out = 0;
446
447 return ss;
448}
449
450
451static int anystart(char *s, char **try)
452{
453 char *ss = s;
454
455 while (*try) if (strstart(&s, *try++)) return s-ss;
456
457 return 0;
458}
459
460
461static int anystr(char *s, char **try)
462{
463 while (*try) if (!strcmp(s, *try++)) return 1;
464
465 return 0;
466}
467
468
469static int redir_prefix(char *word)
470{
471 char *s = word;
472
473 if (*s == '{') {
474 if (*(s = varend(s+1)) == '}' && s != word+1) s++;
475 else s = word;
476 } else while (isdigit(*s)) s++;
477
478 return s-word;
479}
480
481
482
483
484static char *parse_word(char *start, int early, int quote)
485{
486 int i, q, qc = 0;
487 char *end = start, *s;
488
489
490
491 if (strstart(&end, "<(") || strstart(&end, ">(")) toybuf[quote++]=')';
492
493
494 s = end + redir_prefix(end);
495 if ((i = anystart(s, (void *)redirectors))) return s+i;
496
497
498 if (strstart(&end, "((")) toybuf[quote++] = 254;
499
500
501 while (*end) {
502 i = 0;
503
504
505 if (quote>4000) {
506 syntax_err("tilt");
507 return (void *)1;
508 }
509
510
511 if ((q = quote ? toybuf[quote-1] : 0)) {
512
513
514 if ((q == ')' || q >= 254) && (*end == '(' || *end == ')')) {
515 if (*end == '(') qc++;
516 else if (qc) qc--;
517 else if (q >= 254) {
518
519 if (strstart(&end, "))")) quote--;
520 else if (q == 254) return start+1;
521 else if (q == 255) toybuf[quote-1] = ')';
522 } else if (*end == ')') quote--;
523 end++;
524
525
526 } else if (*end == q) quote--, end++;
527
528
529 else if (q == '\'') end++;
530 else i++;
531
532
533 if (early && !quote) return end;
534 if (!i) continue;
535 } else {
536
537
538 if (isspace(*end)) break;
539 if (*end == ')') return end+(start==end);
540
541
542 s = end + anystart(end, (char *[]){";;&", ";;", ";&", ";", "||",
543 "|&", "|", "&&", "&", "(", ")", 0});
544 if (s != end) return (end == start) ? s : end;
545 }
546
547
548
549
550 if (strchr("\"'`", *end)) toybuf[quote++] = *end;
551
552
553 else if (*end == '\\') {
554 if (!end[1] || (end[1]=='\n' && !end[2])) return early ? end+1 : 0;
555 end += 2;
556 } else if (*end == '$' && -1 != (i = stridx("({[", end[1]))) {
557 end++;
558 if (strstart(&end, "((")) toybuf[quote++] = 255;
559 else {
560 toybuf[quote++] = ")}]"[i];
561 end++;
562 }
563 } else if (end[1]=='(' && strchr("?*+@!", *end)) {
564 toybuf[quote++] = ')';
565 end += 2;
566 }
567
568 if (early && !quote) return end;
569 end++;
570 }
571
572 return (quote && !early) ? 0 : end;
573}
574
575
576static int next_hfd()
577{
578 int hfd;
579
580 for (; TT.hfd<=99999; TT.hfd++) if (-1 == fcntl(TT.hfd, F_GETFL)) break;
581 hfd = TT.hfd;
582 if (TT.hfd>99999) {
583 hfd = -1;
584 if (!errno) errno = EMFILE;
585 }
586
587 return hfd;
588}
589
590
591
592
593
594static int save_redirect(int **rd, int from, int to)
595{
596 int cnt, hfd, *rr;
597
598 if (from == to) return 0;
599
600
601 if (from>-2) {
602 if ((hfd = next_hfd())==-1) return 1;
603 if (hfd != dup2(to, hfd)) hfd = -1;
604 else fcntl(hfd, F_SETFD, FD_CLOEXEC);
605
606
607 if (from >= 0 && to != dup2(from, to)) {
608 if (hfd >= 0) close(hfd);
609
610 return 1;
611 }
612 } else {
613 hfd = to;
614 to = -1;
615 }
616
617
618 if (!((cnt = *rd ? **rd : 0)&31)) *rd = xrealloc(*rd, (cnt+33)*2*sizeof(int));
619 *(rr = *rd) = ++cnt;
620 rr[2*cnt-1] = hfd;
621 rr[2*cnt] = to;
622
623 return 0;
624}
625
626
627static void subshell_callback(char **argv)
628{
629 char *s;
630
631 xsetenv(s = xmprintf("@%d,%d=", getpid(), getppid()), 0);
632 s[strlen(s)-1] = 0;
633 xsetenv(xmprintf("$=%d", TT.pid), 0);
634
635}
636
637
638
639
640
641static int run_subshell(char *str, int len)
642{
643 pid_t pid;
644
645
646 if (CFG_TOYBOX_FORK) {
647 char *s;
648
649 if ((pid = fork())<0) perror_msg("fork");
650 else if (!pid) {
651 s = xstrndup(str, len);
652 sh_run(s);
653 free(s);
654 _exit(toys.exitval);
655 }
656
657
658 } else {
659 int pipes[2], i, c;
660
661
662 if (pipe(pipes) || 254 != dup2(pipes[0], 254)) return 1;
663 close(pipes[0]);
664 fcntl(pipes[1], F_SETFD, FD_CLOEXEC);
665
666
667 pid = xpopen_setup(0, 0, subshell_callback);
668
669
670 for (i = 0; environ[i]; i++) {
671 c = environ[i][0];
672 if (c == '_' || !ispunct(c)) continue;
673 free(environ[i]);
674 environ[i] = 0;
675 }
676
677
678 close(254);
679 for (i = 0; i<TT.varslen; i++) {
680 char *s;
681
682 if (TT.vars[i].flags&VAR_GLOBAL) continue;
683 dprintf(pipes[1], "%s\n", s = declarep(TT.vars+i));
684 free(s);
685 }
686 dprintf(pipes[1], "%.*s\n", len, str);
687 close(pipes[1]);
688 }
689
690 return pid;
691}
692
693
694static void unredirect(int *urd)
695{
696 int *rr = urd+1, i;
697
698 if (!urd) return;
699
700 for (i = 0; i<*urd; i++, rr += 2) if (rr[0] != -1) {
701
702 dup2(rr[0], rr[1]);
703 close(rr[0]);
704 }
705 free(urd);
706}
707
708
709static int pipe_subshell(char *s, int len, int out)
710{
711 int pipes[2], *uu = 0, in = !out;
712
713
714 if (pipe(pipes)) {
715 perror_msg("%.*s", len, s);
716
717 return -1;
718 }
719
720
721 save_redirect(&uu, pipes[in], in);
722 close(pipes[in]);
723 run_subshell(s, len);
724 unredirect(uu);
725
726 return pipes[out];
727}
728
729
730
731static int utf8chr(char *wc, char *chrs, int *len)
732{
733 wchar_t wc1, wc2;
734 int ll;
735
736 if (len) *len = 1;
737 if (!*wc) return 0;
738 if (0<(ll = utf8towc(&wc1, wc, 99))) {
739 if (len) *len = ll;
740 while (*chrs) {
741 if(1>(ll = utf8towc(&wc2, chrs, 99))) chrs++;
742 else {
743 if (wc1 == wc2) return wc1;
744 chrs += ll;
745 }
746 }
747 }
748
749 return 0;
750}
751
752
753
754char *getvar_special(char *str, int len, int *used, struct arg_list **delete)
755{
756 char *s = 0, *ss, cc = *str;
757 unsigned uu;
758
759 *used = 1;
760 if (cc == '-') {
761 s = ss = xmalloc(8);
762 if (TT.options&OPT_I) *ss++ = 'i';
763 if (TT.options&OPT_BRACE) *ss++ = 'B';
764 if (TT.options&OPT_S) *ss++ = 's';
765 if (TT.options&OPT_C) *ss++ = 'c';
766 *ss = 0;
767 } else if (cc == '?') s = xmprintf("%d", toys.exitval);
768 else if (cc == '$') s = xmprintf("%d", TT.pid);
769 else if (cc == '#') s = xmprintf("%d", TT.arg->c?TT.arg->c-1:0);
770 else if (cc == '!') s = xmprintf("%d"+2*!TT.bangpid, TT.bangpid);
771 else {
772 delete = 0;
773 for (*used = uu = 0; *used<len && isdigit(str[*used]); ++*used)
774 uu = (10*uu)+str[*used]-'0';
775 if (*used) {
776 if (uu) uu += TT.shift;
777 if (uu<TT.arg->c) s = TT.arg->v[uu];
778 } else if ((*used = varend(str)-str)) return getvar(str);
779 }
780 if (s) push_arg(delete, s);
781
782 return s;
783}
784
785
786int getutf8(char *s, int len, int *cc)
787{
788 wchar_t wc;
789
790 if (len<0) wc = len = 0;
791 else if (1>(len = utf8towc(&wc, s, len))) wc = *s, len = 1;
792 if (cc) *cc = wc;
793
794 return len;
795}
796
797#define WILD_SHORT 1
798#define WILD_CASE 2
799#define WILD_ANY 4
800
801static int wildcard_matchlen(char *str, int len, char *pattern, int plen,
802 struct sh_arg *deck, int flags)
803{
804 struct sh_arg ant = {0};
805 long ss, pp, dd, best = -1;
806 int i, j, c, not;
807
808
809 for (ss = pp = dd = 0; ;) {
810 if ((flags&WILD_ANY) && best!=-1) break;
811
812
813 if (pp==plen) {
814 if (ss>best) best = ss;
815 if (ss==len || (flags&WILD_SHORT)) break;
816
817 } else if (dd>=deck->c || pp!=(long)deck->v[dd]) {
818 if (ss<len) {
819 if (flags&WILD_CASE) {
820 c = towupper(getutf8(str+ss, len-ss, &i));
821 ss += i;
822 i = towupper(getutf8(pattern+pp, pp-plen, &j));
823 pp += j;
824 } else c = str[ss++], i = pattern[pp++];
825 if (c==i) continue;
826 }
827
828
829 } else {
830 c = pattern[pp++];
831 dd++;
832 if (c=='?' || ((flags&WILD_ANY) && c=='*')) {
833 ss += (i = getutf8(str+ss, len-ss, 0));
834 if (i) continue;
835 } else if (c=='*') {
836
837
838 if (dd==1 || pp-2!=(long)deck->v[dd-1] || pattern[pp-2]!='*') {
839 arg_add(&ant, (void *)ss);
840 arg_add(&ant, 0);
841 }
842
843 continue;
844 } else if (c == '[') {
845 pp += (not = !!strchr("!^", pattern[pp]));
846 ss += getutf8(str+ss, len-ss, &c);
847 for (i = 0; pp<(long)deck->v[dd]; i = 0) {
848 pp += getutf8(pattern+pp, plen-pp, &i);
849 if (pattern[pp]=='-') {
850 ++pp;
851 pp += getutf8(pattern+pp, plen-pp, &j);
852 if (not^(i<=c && j>=c)) break;
853 } else if (not^(i==c)) break;
854 }
855 if (i) {
856 pp = 1+(long)deck->v[dd++];
857
858 continue;
859 }
860
861
862
863 } else {
864 dd++;
865 continue;
866 }
867 }
868
869
870 if (flags&WILD_ANY) {
871 ss = 0;
872 if (plen==pp) break;
873 continue;
874 }
875
876
877 while (ant.c) {
878 if ((c = pattern[(long)deck->v[--dd]])=='*') {
879 if (len<(ss = (long)ant.v[ant.c-2]+(long)++ant.v[ant.c-1])) ant.c -= 2;
880 else {
881 pp = (long)deck->v[dd++]+1;
882 break;
883 }
884 } else if (c == '(') dprintf(2, "TODO: (");
885 }
886
887 if (!ant.c) break;
888 }
889 free (ant.v);
890
891 return best;
892}
893
894static int wildcard_match(char *s, char *p, struct sh_arg *deck, int flags)
895{
896 return wildcard_matchlen(s, strlen(s), p, strlen(p), deck, flags);
897}
898
899
900
901
902
903
904char *wildcard_path(char *pattern, int off, struct sh_arg *deck, int *idx,
905 int count)
906{
907 char *p, *old;
908 int i = 0, j = 0;
909
910
911 for (p = old = pattern+off;; p++) {
912 if (!*p) return p;
913 while (*p=='/') {
914 old = p++;
915 if (j && !count) return old;
916 j = 0;
917 }
918
919
920 if (*idx<deck->c && p-pattern == (long)deck->v[*idx]) {
921 if (!j++ && !count--) return old;
922 ++*idx;
923 if (*p=='[') p = pattern+(long)deck->v[(*idx)++];
924 else if (*p=='(') while (*++p) if (p-pattern == (long)deck->v[*idx]) {
925 ++*idx;
926 if (*p == ')') {
927 if (!i) break;
928 i--;
929 } else if (*p == '(') i++;
930 }
931 }
932 }
933}
934
935
936
937
938
939
940int do_wildcard_files(struct dirtree *node)
941{
942 struct dirtree *nn;
943 char *pattern, *patend;
944 int lvl, ll = 0, ii = 0, rc;
945 struct sh_arg ant;
946
947
948 if (!node->parent) return DIRTREE_RECURSE;
949
950
951 for (nn = node->parent; nn; nn = nn->parent) if (nn->parent) ii++;
952 pattern = wildcard_path(TT.wcpat, 0, TT.wcdeck, &ll, ii);
953 while (*pattern=='/') pattern++;
954 lvl = ll;
955 patend = wildcard_path(TT.wcpat, pattern-TT.wcpat, TT.wcdeck, &ll, 1);
956
957
958 if (*node->name=='.' && *pattern!='.') return 0;
959
960
961 if (*patend && !S_ISDIR(node->st.st_mode) && *node->name) return 0;
962
963
964 ant.c = ll-lvl;
965 ant.v = TT.wcdeck->v+lvl;
966 for (ii = 0; ii<ant.c; ii++) TT.wcdeck->v[lvl+ii] -= pattern-TT.wcpat;
967 rc = wildcard_matchlen(node->name, strlen(node->name), pattern,
968 patend-pattern, &ant, 0);
969 for (ii = 0; ii<ant.c; ii++) TT.wcdeck->v[lvl+ii] += pattern-TT.wcpat;
970
971
972 if (rc<0 || node->name[rc]) return 0;
973 if (!*patend) return DIRTREE_SAVE;
974
975
976 if (TT.wcdeck->c!=ll) return DIRTREE_RECURSE;
977
978
979 pattern = xmprintf("%s%s", node->name, patend);
980 rc = faccessat(dirtree_parentfd(node), pattern, F_OK, AT_SYMLINK_NOFOLLOW);
981 free(pattern);
982 if (rc) return 0;
983
984
985 while (*patend=='/' && patend[1]) patend++;
986 node->child = xzalloc(sizeof(struct dirtree)+1+strlen(patend));
987 node->child->parent = node;
988 strcpy(node->child->name, patend);
989
990 return DIRTREE_SAVE;
991}
992
993
994
995static void collect_wildcards(char *new, long oo, struct sh_arg *deck)
996{
997 long bracket, *vv;
998 char cc = new[oo];
999
1000
1001
1002 if (!deck->c) arg_add(deck, 0);
1003 vv = (long *)deck->v;
1004
1005
1006
1007
1008 if (!cc) {
1009 long ii = 0, jj = 65535&*vv, kk;
1010
1011 for (kk = deck->c; jj;) {
1012 if (')' == (cc = new[vv[--kk]])) ii++;
1013 else if ('(' == cc) {
1014 if (ii) ii--;
1015 else {
1016 memmove(vv+kk, vv+kk+1, sizeof(long)*(deck->c-- -kk));
1017 jj--;
1018 }
1019 }
1020 }
1021 if (deck->c) memmove(vv, vv+1, sizeof(long)*deck->c--);
1022
1023 return;
1024 }
1025
1026
1027 if (deck->c>1 && vv[deck->c-1] == oo-1 && strchr("+@!*?", new[oo-1])) {
1028 if (cc == '(') {
1029 vv[deck->c-1] = oo;
1030 return;
1031 } else if (!strchr("*?", new[oo-1])) deck->c--;
1032 }
1033
1034
1035 if (strchr("|+@!*?", cc));
1036 else if (cc == ')' && (65535&*vv)) --*vv;
1037
1038
1039 else if (cc == ']' && (bracket = *vv>>16)) {
1040
1041
1042 if (bracket+1 == oo || (bracket+2 == oo && strchr("!^", new[oo-1]))) return;
1043 while (deck->c>1 && vv[deck->c-1]>=bracket) deck->c--;
1044 *vv &= 65535;
1045 arg_add(deck, (void *)bracket);
1046
1047
1048 } else {
1049
1050 if (cc == '[' && !(*vv>>16)) *vv = (oo<<16)+(65535&*vv);
1051 return;
1052 }
1053
1054
1055 arg_add(deck, (void *)oo);
1056}
1057
1058
1059
1060static void wildcard_add_files(struct sh_arg *arg, char *pattern,
1061 struct sh_arg *deck, struct arg_list **delete)
1062{
1063 struct dirtree *dt;
1064 char *pp;
1065 int ll = 0;
1066
1067
1068 collect_wildcards("", 0, deck);
1069 if (!deck->c) return arg_add(arg, pattern);
1070
1071
1072 pp = wildcard_path(TT.wcpat = pattern, 0, TT.wcdeck = deck, &ll, 0);
1073 pp = (pp==pattern) ? 0 : xstrndup(pattern, pp-pattern);
1074 dt = dirtree_flagread(pp, DIRTREE_STATLESS|DIRTREE_SYMFOLLOW,
1075 do_wildcard_files);
1076 free(pp);
1077 deck->c = 0;
1078
1079
1080 if (!dt) return arg_add(arg, pattern);
1081 while (dt) {
1082 while (dt->child) dt = dt->child;
1083 arg_add(arg, dirtree_path(dt, 0));
1084 do {
1085 pp = (void *)dt;
1086 if ((dt = dt->parent)) dt->child = dt->child->next;
1087 free(pp);
1088 } while (dt && !dt->child);
1089 }
1090
1091}
1092
1093
1094
1095char *slashcopy(char *s, char *c, struct sh_arg *deck)
1096{
1097 char *ss;
1098 long ii, jj;
1099
1100 for (ii = 0; !strchr(c, s[ii]); ii++) if (s[ii] == '\\') ii++;
1101 ss = xmalloc(ii+1);
1102 for (ii = jj = 0; !strchr(c, s[jj]); ii++)
1103 if ('\\'==(ss[ii] = s[jj++])) ss[ii] = s[jj++];
1104 else if (deck) collect_wildcards(ss, ii, deck);
1105 ss[ii] = 0;
1106 if (deck) {
1107 arg_add(deck, 0);
1108 deck->v[--deck->c] = (void *)jj;
1109 collect_wildcards("", 0, deck);
1110 }
1111
1112 return ss;
1113}
1114
1115#define NO_QUOTE (1<<0)
1116#define NO_PATH (1<<1)
1117#define NO_SPLIT (1<<2)
1118#define NO_BRACE (1<<3)
1119#define NO_TILDE (1<<4)
1120#define NO_NULL (1<<5)
1121#define SEMI_IFS (1<<6)
1122
1123
1124
1125static int expand_arg_nobrace(struct sh_arg *arg, char *str, unsigned flags,
1126 struct arg_list **delete, struct sh_arg *ant)
1127{
1128 char cc, qq = flags&NO_QUOTE, sep[6], *new = str, *s, *ss, *ifs, *slice;
1129 int ii = 0, oo = 0, xx, yy, dd, jj, kk, ll, mm;
1130 struct sh_arg deck = {0};
1131
1132
1133 if (!(flags&NO_TILDE) && *str == '~') {
1134 struct passwd *pw = 0;
1135
1136 ss = 0;
1137 while (str[ii] && str[ii]!=':' && str[ii]!='/') ii++;
1138 if (ii==1) {
1139 if (!(ss = getvar("HOME")) || !*ss) pw = bufgetpwuid(getuid());
1140 } else {
1141
1142 pw = getpwnam(s = xstrndup(str+1, ii-1));
1143 free(s);
1144 }
1145 if (pw) {
1146 ss = pw->pw_dir;
1147 if (!ss || !*ss) ss = "/";
1148 }
1149 if (ss) {
1150 oo = strlen(ss);
1151 s = xmprintf("%s%s", ss, str+ii);
1152 if (str != new) free(new);
1153 new = s;
1154 }
1155 }
1156
1157
1158 if (!ant) ant = &deck;
1159 for (; (cc = str[ii++]); str!=new && (new[oo] = 0)) {
1160 struct sh_arg aa = {0};
1161 int nosplit = 0;
1162
1163
1164 if (!strchr("'\"\\$`"+2*(flags&NO_QUOTE), cc)) {
1165 if (str != new) new[oo] = cc;
1166 if (!(flags&NO_PATH) && !(qq&1)) collect_wildcards(new, oo, ant);
1167 oo++;
1168 continue;
1169 }
1170
1171
1172 if (str == new) {
1173 new = xstrdup(new);
1174 new[oo] = 0;
1175 }
1176 ifs = slice = 0;
1177
1178
1179 if (cc == '\\') {
1180 if (!(qq&1) || (str[ii] && strchr("\"\\$`", str[ii])))
1181 new[oo++] = str[ii] ? str[ii++] : cc;
1182 } else if (cc == '"') qq++;
1183 else if (cc == '\'') {
1184 if (qq&1) new[oo++] = cc;
1185 else {
1186 qq += 2;
1187 while ((cc = str[ii++]) != '\'') new[oo++] = cc;
1188 }
1189
1190
1191
1192 } else if (cc == '`' || (cc == '$' && strchr("([", str[ii]))) {
1193 off_t pp = 0;
1194
1195 s = str+ii-1;
1196 kk = parse_word(s, 1, 0)-s;
1197 if (str[ii] == '[' || *toybuf == 255) {
1198 s += 2+(str[ii]!='[');
1199 kk -= 3+2*(str[ii]!='[');
1200dprintf(2, "TODO: do math for %.*s\n", kk, s);
1201 } else {
1202
1203 s += (jj = 1+(cc == '$'));
1204 ii += --kk;
1205 kk -= jj;
1206
1207
1208 for (ss = s; isspace(*ss); ss++);
1209 if (*ss != '<') ss = 0;
1210 else {
1211 while (isspace(*++ss));
1212 if (!(ll = parse_word(ss, 0, 0)-ss)) ss = 0;
1213 else {
1214 jj = ll+(ss-s);
1215 while (isspace(s[jj])) jj++;
1216 if (jj != kk) ss = 0;
1217 else {
1218 jj = xcreate_stdio(ss = xstrndup(ss, ll), O_RDONLY|WARN_ONLY, 0);
1219 free(ss);
1220 }
1221 }
1222 }
1223
1224
1225 if (!ss) jj = pipe_subshell(s, kk, 0);
1226 if ((ifs = readfd(jj, 0, &pp)))
1227 for (kk = strlen(ifs); kk && ifs[kk-1]=='\n'; ifs[--kk] = 0);
1228 close(jj);
1229 }
1230
1231
1232
1233 } else if (cc == '$') {
1234 cc = *(ss = str+ii++);
1235 if (cc=='\'') {
1236 for (s = str+ii; *s != '\''; oo += wcrtomb(new+oo, unescape2(&s, 0),0));
1237 ii = s-str+1;
1238
1239 continue;
1240 } else if (cc=='"' && !(qq&1)) {
1241 qq++;
1242
1243 continue;
1244 } else if (cc == '{') {
1245
1246
1247 for (cc = *++ss; str[ii] != '}'; ii++) if (str[ii]=='\\') ii++;
1248 ii++;
1249
1250 if (cc == '}') ifs = (void *)1;
1251 else if (strchr("#!", cc)) ss++;
1252 jj = varend(ss)-ss;
1253 if (!jj) while (isdigit(ss[jj])) jj++;
1254 if (!jj && strchr("#$!_*", *ss)) jj++;
1255
1256 if (!jj && strchr("-?@", *ss)) if (ss[++jj]!='}' && ss[-1]!='{') ss--;
1257 slice = ss+jj;
1258
1259 if (!jj) {
1260 ifs = (void *)1;
1261
1262 if (strchr("#!", cc)) ifs = getvar_special(--ss, 1, &kk, delete);
1263 } else if (ss[-1]=='{');
1264 else if (cc == '#') {
1265 dd = !!strchr("@*", *ss);
1266 ifs = getvar_special(ss-dd, jj, &kk, delete) ? : "";
1267 if (!dd) push_arg(delete, ifs = xmprintf("%zu", strlen(ifs)));
1268
1269 } else if (cc == '!') {
1270
1271
1272 if (ss[jj] == '*' || (ss[jj] == '@' && !isalpha(ss[jj+1]))) {
1273 for (slice++, kk = 0; kk<TT.varslen; kk++)
1274 if (!strncmp(s = TT.vars[kk].str, ss, jj))
1275 arg_add(&aa, push_arg(delete, s = xstrndup(s, stridx(s, '='))));
1276 if (aa.c) push_arg(delete, (void *)aa.v);
1277
1278
1279 } else {
1280
1281 if (strchr("@*", *ss)) {
1282 expand_arg_nobrace(&aa, "\"$*\"", NO_PATH|NO_SPLIT, delete, 0);
1283 ifs = *aa.v;
1284 free(aa.v);
1285 memset(&aa, 0, sizeof(aa));
1286 jj = 1;
1287 } else ifs = getvar_special(ss, jj, &jj, delete);
1288 slice = ss+jj;
1289
1290
1291 if (!jj) ifs = (void *)1;
1292 else if (ifs && *(ss = ifs)) {
1293 if (strchr("@*", cc)) {
1294 aa.c = TT.arg->c-1;
1295 aa.v = TT.arg->v+1;
1296 jj = 1;
1297 } else ifs = getvar_special(ifs, strlen(ifs), &jj, delete);
1298 if (ss && ss[jj]) {
1299 ifs = (void *)1;
1300 slice = ss+strlen(ss);
1301 }
1302 }
1303 }
1304 }
1305
1306
1307 if (ifs == (void *)1) {
1308barf:
1309 if (!(((unsigned long)ifs)>>1)) ifs = "bad substitution";
1310 error_msg("%.*s: %s", (int)(slice-ss), ss, ifs);
1311 goto fail;
1312 }
1313 } else jj = 1;
1314
1315
1316 if (strchr("{$", ss[-1])) {
1317 if (strchr("@*", cc)) {
1318 aa.c = TT.arg->c-1;
1319 aa.v = TT.arg->v+1;
1320 } else {
1321 ifs = getvar_special(ss, jj, &jj, delete);
1322 if (!jj) {
1323 if (ss[-1] == '{') goto barf;
1324 new[oo++] = '$';
1325 ii--;
1326 continue;
1327 } else if (ss[-1] != '{') ii += jj-1;
1328 }
1329 }
1330 }
1331
1332
1333
1334
1335
1336
1337
1338 *sep = 0;
1339 if (((qq&1) && cc=='*') || (flags&NO_SPLIT)) {
1340 wchar_t wc;
1341
1342 nosplit++;
1343 if (flags&SEMI_IFS) strcpy(sep, " ");
1344
1345 else if (0<(dd = utf8towc(&wc, TT.ifs, 4)))
1346 sprintf(sep, "%.*s", dd, TT.ifs);
1347 }
1348
1349
1350 mm = yy = 0;
1351 do {
1352
1353
1354 if (aa.c) ifs = aa.v[mm++] ? : "";
1355
1356
1357 if (slice && *slice != '}') {
1358 dd = slice[xx = (*slice == ':')];
1359 if (!ifs || (xx && !*ifs)) {
1360 if (strchr("-?=", dd)) {
1361 push_arg(delete, ifs = slashcopy(slice+xx+1, "}", 0));
1362 if (dd == '?' || (dd == '=' &&
1363 !(setvar(s = xmprintf("%.*s=%s", (int)(slice-ss), ss, ifs)))))
1364 goto barf;
1365 }
1366 } else if (dd == '-');
1367
1368 else if (dd == '+')
1369 push_arg(delete, ifs = slashcopy(slice+xx+1, "}", 0));
1370 else if (xx) {
1371 long long la, lb, lc;
1372
1373
1374 ss = slice+1;
1375 la = do_math(&s);
1376 if (s && *s == ':') {
1377 s++;
1378 lb = do_math(&s);
1379 } else lb = LLONG_MAX;
1380 if (s && *s != '}') {
1381 error_msg("%.*s: bad '%c'", (int)(slice-ss), ss, *s);
1382 s = 0;
1383 }
1384 if (!s) goto fail;
1385
1386
1387 if (!(lc = aa.c)) lc = strlen(ifs);
1388 else if (!la && !yy && strchr("@*", slice[1])) {
1389 aa.v--;
1390 aa.c++;
1391 yy++;
1392 }
1393 if (la<0 && (la += lc)<0) continue;
1394 if (lb<0) lb = lc+lb-la;
1395 if (aa.c) {
1396 if (mm<la || mm>=la+lb) continue;
1397 } else if (la>=lc || lb<0) ifs = "";
1398 else if (la+lb>=lc) ifs += la;
1399 else if (!*delete || ifs != (*delete)->arg)
1400 push_arg(delete, ifs = xmprintf("%.*s", (int)lb, ifs+la));
1401 else {
1402 for (dd = 0; dd<lb ; dd++) if (!(ifs[dd] = ifs[dd+la])) break;
1403 ifs[dd] = 0;
1404 }
1405 } else if (strchr("#%^,", *slice)) {
1406 struct sh_arg wild = {0};
1407 char buf[8];
1408
1409 s = slashcopy(slice+(xx = slice[1]==*slice)+1, "}", &wild);
1410
1411
1412 if (strchr("^,", *slice)) {
1413 for (ss = ifs; *ss; ss += dd) {
1414 dd = getutf8(ss, 4, &jj);
1415 if (!*s || 0<wildcard_match(ss, s, &wild, WILD_ANY)) {
1416 ll = ((*slice=='^') ? towupper : towlower)(jj);
1417
1418
1419
1420
1421 if (ll != jj) {
1422 yy = ss-ifs;
1423 if (!*delete || (*delete)->arg!=ifs)
1424 push_arg(delete, ifs = xstrdup(ifs));
1425 if (dd != (ll = wctoutf8(buf, ll))) {
1426 if (dd<ll)
1427 ifs = (*delete)->arg = xrealloc(ifs, strlen(ifs)+1+dd-ll);
1428 memmove(ifs+yy+dd-ll, ifs+yy+ll, strlen(ifs+yy+ll)+1);
1429 }
1430 memcpy(ss = ifs+yy, buf, dd = ll);
1431 }
1432 }
1433 if (!xx) break;
1434 }
1435
1436 } else if (*slice=='#') {
1437 if (0<(dd = wildcard_match(ifs, s, &wild, WILD_SHORT*!xx)))
1438 ifs += dd;
1439
1440 } else if (*slice=='%') {
1441 for (ss = ifs+strlen(ifs), yy = -1; ss>=ifs; ss--) {
1442 if (0<(dd = wildcard_match(ss, s, &wild, WILD_SHORT*xx))&&!ss[dd])
1443 {
1444 yy = ss-ifs;
1445 if (!xx) break;
1446 }
1447 }
1448
1449 if (yy != -1) {
1450 if (*delete && (*delete)->arg==ifs) ifs[yy] = 0;
1451 else push_arg(delete, ifs = xstrndup(ifs, yy));
1452 }
1453 }
1454 free(s);
1455 free(wild.v);
1456
1457
1458
1459 } else if (*slice=='/') {
1460 struct sh_arg wild = {0};
1461
1462 s = slashcopy(ss = slice+(xx = !!strchr("/#%", slice[1]))+1, "/}",
1463 &wild);
1464 ss += (long)wild.v[wild.c];
1465 ss = (*ss == '/') ? slashcopy(ss+1, "}", 0) : 0;
1466 jj = ss ? strlen(ss) : 0;
1467 ll = 0;
1468 for (ll = 0; ifs[ll];) {
1469
1470 if (0<(dd = wildcard_match(ifs+ll, s, &wild, 0))) {
1471 char *bird = 0;
1472
1473 if (slice[1]=='%' && ifs[ll+dd]) {
1474 ll++;
1475 continue;
1476 }
1477 if (*delete && (*delete)->arg==ifs) {
1478 if (jj==dd) memcpy(ifs+ll, ss, jj);
1479 else if (jj<dd) sprintf(ifs+ll, "%s%s", ss, ifs+ll+dd);
1480 else bird = ifs;
1481 } else bird = (void *)1;
1482 if (bird) {
1483 ifs = xmprintf("%.*s%s%s", ll, ifs, ss ? : "", ifs+ll+dd);
1484 if (bird != (void *)1) {
1485 free(bird);
1486 (*delete)->arg = ifs;
1487 } else push_arg(delete, ifs);
1488 }
1489 if (slice[1]!='/') break;
1490 } else ll++;
1491 if (slice[1]=='#') break;
1492 }
1493
1494
1495
1496
1497
1498
1499
1500 } else {
1501
1502 ifs = slice;
1503 goto barf;
1504 }
1505
1506
1507
1508
1509 }
1510
1511
1512 if (!ifs) break;
1513 if (!*ifs && !qq) continue;
1514
1515
1516 do {
1517
1518
1519 if ((qq&1) || nosplit) ss = ifs+strlen(ifs);
1520 else for (ss = ifs; *ss; ss += kk) if (utf8chr(ss, TT.ifs, &kk)) break;
1521
1522
1523 if (!oo && !*ss && !((mm==aa.c) ? str[ii] : nosplit)) {
1524 if (qq || ss!=ifs) {
1525 if (!(flags&NO_PATH))
1526 for (jj = 0; ifs[jj]; jj++) collect_wildcards(ifs, jj, ant);
1527 wildcard_add_files(arg, ifs, &deck, delete);
1528 }
1529 continue;
1530 }
1531
1532
1533 jj = (mm == aa.c) && !*ss;
1534 new = xrealloc(new, oo + (ss-ifs) + ((nosplit&!jj) ? strlen(sep) : 0) +
1535 (jj ? strlen(str+ii) : 0) + 1);
1536 dd = sprintf(new + oo, "%.*s%s", (int)(ss-ifs), ifs,
1537 (nosplit&!jj) ? sep : "");
1538 if (flags&NO_PATH) oo += dd;
1539 else while (dd--) collect_wildcards(new, oo++, ant);
1540 if (jj) break;
1541
1542
1543 if (!nosplit) {
1544 if (qq || *new || *ss) {
1545 push_arg(delete, new = xrealloc(new, strlen(new)+1));
1546 wildcard_add_files(arg, new, &deck, delete);
1547 new = xstrdup(str+ii);
1548 }
1549 qq &= 1;
1550 oo = 0;
1551 }
1552
1553
1554 while ((jj = utf8chr(ss, TT.ifs, &ll))) {
1555 ss += ll;
1556 if (!iswspace(jj)) break;
1557 }
1558 } while (*(ifs = ss));
1559 } while (!(mm == aa.c));
1560 }
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570 if (*new || qq) {
1571 if (str != new) push_arg(delete, new);
1572 wildcard_add_files(arg, new, &deck, delete);
1573 new = 0;
1574 }
1575
1576
1577 arg = 0;
1578
1579fail:
1580 if (str != new) free(new);
1581 free(deck.v);
1582 if (ant!=&deck && ant->v) collect_wildcards("", 0, ant);
1583
1584 return !!arg;
1585}
1586
1587struct sh_brace {
1588 struct sh_brace *next, *prev, *stack;
1589 int active, cnt, idx, commas[];
1590};
1591
1592static int brace_end(struct sh_brace *bb)
1593{
1594 return bb->commas[(bb->cnt<0 ? 0 : bb->cnt)+1];
1595}
1596
1597
1598static int expand_arg(struct sh_arg *arg, char *old, unsigned flags,
1599 struct arg_list **delete)
1600{
1601 struct sh_brace *bb = 0, *blist = 0, *bstk, *bnext;
1602 int i, j, k, x;
1603 char *s, *ss;
1604
1605
1606 if ((TT.options&OPT_BRACE) && !(flags&NO_BRACE)) for (i = 0; ; i++) {
1607
1608 while ((s = parse_word(old+i, 1, 0)) != old+i) i += s-(old+i);
1609
1610 if (!bb && !old[i]) break;
1611
1612 if (bb && (!old[i] || old[i] == '}')) {
1613 bb->active = bb->commas[bb->cnt+1] = i;
1614
1615 for (bnext = bb; bb && bb->active; bb = (bb==blist) ? 0 : bb->prev);
1616
1617 j = 1+*bnext->commas;
1618 if (old[i] && !bnext->cnt && i-j>=4) {
1619
1620 if (old[j+1]=='.' && old[j+2]=='.') {
1621 bnext->commas[2] = old[j];
1622 bnext->commas[3] = old[j+3];
1623 k = 0;
1624 if (old[j+4]=='}' ||
1625 (sscanf(old+j+4, "..%u}%n", bnext->commas+4, &k) && k))
1626 bnext->cnt = -1;
1627 }
1628
1629 if (!bnext->cnt) {
1630 for (k=0, j = 1+*bnext->commas; k<3; k++, j += x)
1631 if (!sscanf(old+j, "..%u%n"+2*!k, bnext->commas+2+k, &x)) break;
1632 if (old[j] == '}') bnext->cnt = -2;
1633 }
1634
1635 if (bnext->cnt) {
1636 if (!bnext->commas[4]) bnext->commas[4] = 1;
1637 if ((bnext->commas[3]-bnext->commas[2]>0) != (bnext->commas[4]>0))
1638 bnext->commas[4] *= -1;
1639 }
1640 }
1641
1642 if (!old[i] || !bnext->cnt)
1643 free(dlist_pop((blist == bnext) ? &blist : &bnext));
1644
1645 } else if (old[i] == '{') {
1646 dlist_add_nomalloc((void *)&blist,
1647 (void *)(bb = xzalloc(sizeof(struct sh_brace)+34*4)));
1648 bb->commas[0] = i;
1649
1650 } else if (!bb) continue;
1651
1652 else if (bb && old[i] == ',') {
1653 if (bb->cnt && !(bb->cnt&31)) {
1654 dlist_lpop(&blist);
1655 dlist_add_nomalloc((void *)&blist,
1656 (void *)(bb = xrealloc(bb, sizeof(struct sh_brace)+(bb->cnt+34)*4)));
1657 }
1658 bb->commas[++bb->cnt] = i;
1659 }
1660 }
1661
1662
1663
1664 if (!blist) return expand_arg_nobrace(arg, old, flags, delete, 0);
1665
1666
1667 (bstk = xzalloc(sizeof(struct sh_brace)+8))->commas[1] = strlen(old)+1;
1668 bstk->commas[0] = -1;
1669
1670
1671 for (;;) {
1672
1673
1674 s = ss = xmalloc(bstk->commas[1]);
1675
1676
1677 for (bb = blist; bb; bb = (bnext == blist) ? 0 : bnext) {
1678
1679
1680 if (bstk == bb) bstk = bstk->stack;
1681
1682 if (brace_end(bstk)>bb->commas[0]) {
1683 i = bstk->commas[bstk->idx]+1;
1684 s = stpncpy(s, old+i, bb->commas[0]-i);
1685 }
1686 else bstk = bstk->stack;
1687
1688 bb->stack = bstk;
1689 bb->active = 1;
1690 bstk = bnext = bb;
1691
1692
1693 while ((bnext = (bnext->next==blist) ? 0 : bnext->next)) {
1694
1695
1696 if ((i = bnext->commas[0])>brace_end(bb)) break;
1697
1698
1699 if (i<bb->commas[bb->idx] || i>bb->commas[bb->idx+1]) {
1700 bnext->active = 0;
1701 bnext->stack = 0;
1702
1703
1704 } else break;
1705 }
1706
1707
1708 if (!bnext || bb->cnt<0 || bnext->commas[0]>bb->commas[bb->idx+1]) {
1709
1710
1711 if (bb->cnt<0) {
1712 k = bb->commas[2]+bb->commas[4]*bb->idx;
1713 s += sprintf(s, (bb->cnt==-1) ? "\\%c"+!ispunct(k) : "%d", k);
1714 } else {
1715 i = bb->commas[bstk->idx]+1;
1716 s = stpncpy(s, old+i, bb->commas[bb->idx+1]-i);
1717 }
1718
1719
1720 while (!bnext || bnext->commas[0]>brace_end(bstk)) {
1721 if (!(bb = bstk->stack)) break;
1722 i = brace_end(bstk)+1;
1723 j = bb->commas[bb->idx+1];
1724
1725 while (bnext) {
1726 if (bnext->commas[0]<j) {
1727 j = bnext->commas[0];
1728 break;
1729 } else if (brace_end(bb)>bnext->commas[0])
1730 bnext = (bnext->next == blist) ? 0 : bnext->next;
1731 else break;
1732 }
1733 s = stpncpy(s, old+i, j-i);
1734
1735
1736 if (bnext && bnext->commas[0]<brace_end(bb)) break;
1737 bstk = bb;
1738 }
1739 }
1740 }
1741
1742
1743 if (expand_arg_nobrace(arg, push_arg(delete, ss), flags, delete, 0)) {
1744 llist_traverse(blist, free);
1745
1746 return 1;
1747 }
1748
1749
1750 for (bb = blist->prev; bb; bb = (bb == blist) ? 0 : bb->prev) {
1751 if (!bb->stack) continue;
1752 else if (bb->cnt<0) {
1753 if (abs(bb->commas[2]-bb->commas[3]) < abs(++bb->idx*bb->commas[4]))
1754 bb->idx = 0;
1755 else break;
1756 } else if (++bb->idx > bb->cnt) bb->idx = 0;
1757 else break;
1758 }
1759
1760
1761 if (!bb) break;
1762 }
1763 llist_traverse(blist, free);
1764
1765 return 0;
1766}
1767
1768
1769static char *expand_one_arg(char *new, unsigned flags, struct arg_list **del)
1770{
1771 struct sh_arg arg = {0};
1772 char *s = 0;
1773
1774 if (!expand_arg(&arg, new, flags|NO_PATH|NO_SPLIT, del))
1775 if (!(s = *arg.v) && (flags&(SEMI_IFS|NO_NULL))) s = "";
1776 free(arg.v);
1777
1778 return s;
1779}
1780
1781
1782
1783
1784static char *pl2str(struct sh_pipeline *pl)
1785{
1786 struct sh_pipeline *end = 0;
1787 int level = 0, len = 0, i, j;
1788 char *s, *ss, *sss;
1789
1790
1791 for (j = 0; ; j++) for (end = pl; end; end = end->next) {
1792 if (end->type == 1) level++;
1793 else if (end->type == 3 && --level<0) break;
1794
1795 for (i = 0; i<pl->arg->c; i++)
1796 if (j) ss += sprintf(ss, "%s ", pl->arg->v[i]);
1797 else len += strlen(pl->arg->v[i])+1;
1798
1799 sss = pl->arg->v[pl->arg->c];
1800 if (!sss) sss = ";";
1801 if (j) ss = stpcpy(ss, sss);
1802 else len += strlen(sss);
1803
1804
1805
1806 if (j) return s;
1807 s = ss = xmalloc(len+1);
1808 }
1809}
1810
1811
1812
1813static struct sh_process *expand_redir(struct sh_arg *arg, int skip, int *urd)
1814{
1815 struct sh_process *pp;
1816 char *s = s, *ss, *sss, *cv = 0;
1817 int j, to, from, here = 0;
1818
1819 TT.hfd = 10;
1820
1821 pp = xzalloc(sizeof(struct sh_process));
1822 pp->urd = urd;
1823 pp->raw = arg;
1824
1825
1826
1827
1828 for (j = skip; j<arg->c; j++) {
1829 int saveclose = 0, bad = 0;
1830
1831 s = arg->v[j];
1832
1833 if (!strcmp(s, "!")) {
1834 pp->not ^= 1;
1835
1836 continue;
1837 }
1838
1839
1840 if ((*s == '<' || *s == '>') && s[1] == '(') {
1841 int new = pipe_subshell(s+2, strlen(s+2)-1, *s == '>');
1842
1843
1844 if (new == -1) {
1845 pp->exit = 1;
1846
1847 return pp;
1848 }
1849 save_redirect(&pp->urd, -2, new);
1850
1851
1852
1853 arg_add_del(&pp->arg, ss = xmprintf("/proc/self/fd/%d", new),&pp->delete);
1854
1855 continue;
1856 }
1857
1858
1859 ss = s + redir_prefix(arg->v[j]);
1860 sss = ss + anystart(ss, (void *)redirectors);
1861 if (ss == sss) {
1862
1863 if (expand_arg(&pp->arg, s, 0, &pp->delete)) {
1864 pp->exit = 1;
1865
1866 return pp;
1867 }
1868 continue;
1869 } else if (j+1 >= arg->c) {
1870
1871 s = "\\n";
1872 break;
1873 }
1874 sss = arg->v[++j];
1875
1876
1877 if (isdigit(*s) && ss-s>5) break;
1878
1879
1880 if (strncmp(ss, "<<", 2) && ss[2] != '<') {
1881 struct sh_arg tmp = {0};
1882
1883 if (!expand_arg(&tmp, sss, 0, &pp->delete) && tmp.c == 1) sss = *tmp.v;
1884 else {
1885 if (tmp.c > 1) error_msg("%s: ambiguous redirect", sss);
1886 s = 0;
1887 }
1888 free(tmp.v);
1889 if (!s) break;
1890 }
1891
1892
1893 to = *ss != '<';
1894 if (isdigit(*s)) to = atoi(s);
1895 else if (*s == '{') {
1896 if (*varend(s+1) != '}') break;
1897
1898 if ((!strcmp(ss, "<&") || !strcmp(ss, ">&")) && !strcmp(sss, "-")) {
1899 if (!(ss = getvar(s+1))) break;
1900 to = atoi(ss);
1901 if (save_redirect(&pp->urd, -1, to)) break;
1902 close(to);
1903
1904 continue;
1905
1906 } else {
1907
1908 if (-1 == (to = next_hfd())) break;
1909 cv = xmprintf("%.*s=%d", (int)(ss-s-2), s+1, to);
1910 }
1911 }
1912
1913
1914 if (!strcmp(ss, "<<<") || !strcmp(ss, "<<-") || !strcmp(ss, "<<")) {
1915 char *tmp = getvar("TMPDIR");
1916 int i, len, zap = (ss[2] == '-'), x = !ss[strcspn(ss, "\"'")];
1917
1918
1919 tmp = xmprintf("%s/sh-XXXXXX", tmp ? tmp : "/tmp");
1920 if ((from = mkstemp(tmp))>=0) {
1921 if (unlink(tmp)) bad++;
1922
1923
1924 else if (ss[2] == '<') {
1925 if (!(ss = expand_one_arg(sss, 0, 0))) {
1926 s = 0;
1927 break;
1928 }
1929 len = strlen(ss);
1930 if (len != writeall(from, ss, len)) bad++;
1931 if (ss != sss) free(ss);
1932 } else {
1933 struct sh_arg *hh = arg+here++;
1934
1935 for (i = 0; i<hh->c; i++) {
1936 ss = hh->v[i];
1937 sss = 0;
1938
1939
1940 if (x && !(ss = sss = expand_one_arg(ss, ~SEMI_IFS, 0))) {
1941 s = 0;
1942 break;
1943 }
1944
1945 while (zap && *ss == '\t') ss++;
1946 x = writeall(from, ss, len = strlen(ss));
1947 free(sss);
1948 if (len != x) break;
1949 }
1950 if (i != hh->c) bad++;
1951 }
1952 if (!bad && lseek(from, 0, SEEK_SET)) bad++;
1953 if (bad) close(from);
1954 } else bad++;
1955 free(tmp);
1956 if (bad) break;
1957
1958
1959
1960
1961
1962
1963
1964 } else if (*ss == '&' || ss[1] == '&') {
1965
1966
1967 for (ss = sss; isdigit(*ss); ss++);
1968 if (ss-sss>5 || (*ss && (*ss != '-' || ss[1]))) {
1969 if (*ss=='&') ss++;
1970 saveclose = 4;
1971 goto notfd;
1972 }
1973
1974 from = (ss==sss) ? to : atoi(sss);
1975 saveclose = 2-(*ss == '-');
1976 } else {
1977notfd:
1978
1979 if (!strcmp(ss, "<>")) from = O_CREAT|O_RDWR;
1980 else if (strstr(ss, ">>")) from = O_CREAT|O_APPEND|O_WRONLY;
1981 else {
1982 from = (*ss == '<') ? O_RDONLY : O_CREAT|O_WRONLY|O_TRUNC;
1983 if (!strcmp(ss, ">") && (TT.options&OPT_NOCLOBBER)) {
1984 struct stat st;
1985
1986
1987 if (stat(sss, &st) || !S_ISREG(st.st_mode)) from |= O_EXCL;
1988 }
1989 }
1990
1991
1992
1993
1994
1995
1996 if (-1 == (from = xcreate_stdio(sss, from|WARN_ONLY, 0666))) {
1997 s = 0;
1998
1999 break;
2000 }
2001 }
2002
2003
2004 if (save_redirect(&pp->urd, from, to)) bad++;
2005
2006 if (cv) {
2007 --*pp->urd;
2008 if (!setvar(cv)) bad++;
2009 cv = 0;
2010 }
2011 if ((saveclose&1) && save_redirect(&pp->urd, -1, from)) bad++;
2012 if ((saveclose&4) && save_redirect(&pp->urd, from, 2)) bad++;
2013 if (!(saveclose&2)) close(from);
2014 if (bad) break;
2015 }
2016
2017
2018 if (j != arg->c) {
2019 if (s) syntax_err(s);
2020 if (!pp->exit) pp->exit = 1;
2021 free(cv);
2022 }
2023
2024 return pp;
2025}
2026
2027static void shexec(char *cmd, char **argv)
2028{
2029 xsetenv(xmprintf("_=%s", cmd), 0);
2030 execve(cmd, argv, environ);
2031
2032 if (errno == ENOEXEC) run_subshell("source \"$_\"", 11);
2033}
2034
2035
2036static void sh_exec(char **argv)
2037{
2038 char *pp = getvar("PATH" ? : _PATH_DEFPATH), *cc = TT.isexec ? : *argv;
2039 struct string_list *sl;
2040
2041 if (getpid() != TT.pid) signal(SIGINT, SIG_DFL);
2042 if (strchr(cc, '/')) shexec(cc, argv);
2043 else for (sl = find_in_path(pp, cc); sl; free(llist_pop(&sl)))
2044 shexec(sl->str, argv);
2045
2046 perror_msg("%s", *argv);
2047 if (!TT.isexec) _exit(127);
2048}
2049
2050
2051static struct sh_process *run_command(struct sh_arg *arg)
2052{
2053 char *s, *ss = 0, *sss, **old = environ;
2054 struct sh_arg env = {0};
2055 int envlen, jj = 0, ll;
2056 struct sh_process *pp;
2057 struct arg_list *delete = 0;
2058 struct toy_list *tl;
2059
2060
2061 for (envlen = 0; envlen<arg->c; envlen++) {
2062 s = varend(arg->v[envlen]);
2063 if (s == arg->v[envlen] || *s != '=') break;
2064 }
2065
2066
2067 if (envlen == arg->c) {
2068 while (jj<envlen) {
2069 if (!(s = expand_one_arg(arg->v[jj], SEMI_IFS, 0))) break;
2070 setvar((s == arg->v[jj++]) ? xstrdup(s) : s);
2071 }
2072 if (jj == envlen) setvarval("_", "");
2073
2074
2075 } else if (envlen) {
2076 while (environ[env.c]) env.c++;
2077 memcpy(env.v = xmalloc(sizeof(char *)*(env.c+33)), environ,
2078 sizeof(char *)*(env.c+1));
2079 for (; jj<envlen; jj++) {
2080 if (!(sss = expand_one_arg(arg->v[jj], SEMI_IFS, &delete))) break;
2081 for (ll = 0; ll<env.c; ll++) {
2082 for (s = sss, ss = env.v[ll]; *s == *ss && *s != '='; s++, ss++);
2083 if (*s != '=') continue;
2084 env.v[ll] = sss;
2085 break;
2086 }
2087 if (ll == env.c) arg_add(&env, sss);
2088 }
2089 environ = env.v;
2090 }
2091
2092
2093 if (envlen == arg->c || jj != envlen) {
2094 pp = xzalloc(sizeof(struct sh_process));
2095 pp->exit = jj != envlen;
2096
2097 goto out;
2098 }
2099
2100
2101 pp = expand_redir(arg, envlen, 0);
2102
2103
2104 if (pp->exit || !pp->arg.v);
2105
2106
2107
2108
2109 else if ((tl = toy_find(*pp->arg.v))
2110 && (tl->flags & (TOYFLAG_NOFORK|TOYFLAG_MAYFORK)))
2111 {
2112 sigjmp_buf rebound;
2113 char temp[jj = offsetof(struct toy_context, rebound)];
2114
2115
2116 memcpy(&temp, &toys, jj);
2117 memset(&toys, 0, jj);
2118
2119
2120
2121
2122
2123 memset(&TT, 0, offsetof(struct sh_data, lineno));
2124
2125 TT.pp = pp;
2126 if (!sigsetjmp(rebound, 1)) {
2127 toys.rebound = &rebound;
2128 toy_singleinit(tl, pp->arg.v);
2129 tl->toy_main();
2130 xflush(0);
2131 }
2132 TT.pp = 0;
2133 toys.rebound = 0;
2134 pp->exit = toys.exitval;
2135 if (toys.optargs != toys.argv+1) free(toys.optargs);
2136 if (toys.old_umask) umask(toys.old_umask);
2137 memcpy(&toys, &temp, jj);
2138 } else if (-1==(pp->pid = xpopen_setup(pp->arg.v, 0, sh_exec)))
2139 perror_msg("%s: vfork", *pp->arg.v);
2140
2141
2142 environ = old;
2143 free(env.v);
2144
2145 if (pp->arg.c) setvarval("_", pp->arg.v[pp->arg.c-1]);
2146
2147 unredirect(pp->urd);
2148out:
2149 llist_traverse(delete, llist_free_arg);
2150
2151 return pp;
2152}
2153
2154static void free_process(void *ppp)
2155{
2156 struct sh_process *pp = ppp;
2157 llist_traverse(pp->delete, llist_free_arg);
2158 free(pp);
2159}
2160
2161
2162
2163
2164static void free_pipeline(void *pipeline)
2165{
2166 struct sh_pipeline *pl = pipeline;
2167 int i, j;
2168
2169
2170 if (pl) for (j=0; j<=pl->count; j++) {
2171 if (!pl->arg[j].v) continue;
2172 for (i = 0; i<=pl->arg[j].c; i++) free(pl->arg[j].v[i]);
2173 free(pl->arg[j].v);
2174 }
2175 free(pl);
2176}
2177
2178static void free_function(struct sh_function *sp)
2179{
2180 llist_traverse(sp->pipeline, free_pipeline);
2181 llist_traverse(sp->expect, free);
2182 memset(sp, 0, sizeof(struct sh_function));
2183}
2184
2185
2186static struct sh_pipeline *add_function(char *name, struct sh_pipeline *pl)
2187{
2188dprintf(2, "stub add_function");
2189
2190 return pl->end;
2191}
2192
2193static struct sh_pipeline *add_pl(struct sh_function *sp, struct sh_arg **arg)
2194{
2195 struct sh_pipeline *pl = xzalloc(sizeof(struct sh_pipeline));
2196
2197 *arg = pl->arg;
2198 dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl);
2199
2200 return pl->end = pl;
2201}
2202
2203
2204
2205static int parse_line(char *line, struct sh_function *sp)
2206{
2207 char *start = line, *delete = 0, *end, *s, *ex, done = 0,
2208 *tails[] = {"fi", "done", "esac", "}", "]]", ")", 0};
2209 struct sh_pipeline *pl = sp->pipeline ? sp->pipeline->prev : 0, *pl2, *pl3;
2210 struct sh_arg *arg = 0;
2211 long i;
2212
2213
2214 if (pl) {
2215 arg = pl->arg;
2216
2217
2218 if (arg->c<0) {
2219 delete = start = xmprintf("%s%s", arg->v[arg->c = (-arg->c)-1], start);
2220 free(arg->v[arg->c]);
2221 arg->v[arg->c] = 0;
2222
2223
2224 } else if (pl->count != pl->here) {
2225 arg += 1+pl->here;
2226
2227
2228 for (s = line, end = arg->v[arg->c]; *s && *end; s++) {
2229 s += strspn(s, "\\\"'");
2230 if (*s != *end) break;
2231 }
2232
2233 if (!*s && !*end) {
2234 end = arg->v[arg->c];
2235 arg_add(arg, xstrdup(line));
2236 arg->v[arg->c] = end;
2237 } else {
2238 arg->v[arg->c] = 0;
2239 pl->here++;
2240 }
2241 start = 0;
2242
2243
2244 } else if (pl->type < 128) pl = 0;
2245 }
2246
2247
2248 if (start) for (;;) {
2249 ex = sp->expect ? sp->expect->prev->data : 0;
2250
2251
2252 if (pl && pl->count == -1) {
2253 pl->count = 0;
2254 arg = pl->arg;
2255
2256
2257 for (i = 0; i<arg->c; i++) {
2258 s = arg->v[i] + redir_prefix(arg->v[i]);
2259
2260
2261 if (strcmp(s, "<<") && strcmp(s, "<<-") && strcmp(s, "<<<")) continue;
2262 if (i+1 == arg->c) goto flush;
2263
2264
2265
2266 dlist_lpop(&sp->pipeline);
2267 pl = xrealloc(pl, sizeof(*pl) + ++pl->count*sizeof(struct sh_arg));
2268 dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl);
2269
2270
2271 arg[pl->count].v = xzalloc(2*sizeof(void *));
2272 arg[pl->count].v[0] = arg->v[++i];
2273 arg[pl->count].v[1] = 0;
2274 arg[pl->count].c = 0;
2275 if (s[2] == '<') pl->here++;
2276 }
2277 pl = 0;
2278 }
2279 if (done) break;
2280 s = 0;
2281
2282
2283 while (isspace(*start)) ++start;
2284 if (*start=='#') while (*start && *start != '\n') ++start;
2285
2286
2287 if ((end = parse_word(start, 0, 0)) == (void *)1) goto flush;
2288
2289
2290 if (!pl) pl = add_pl(sp, &arg);
2291
2292
2293 if (!end) {
2294
2295 arg_add(arg, xstrndup(start, strlen(start)));
2296 arg->c = -arg->c;
2297 free(delete);
2298
2299 return 1;
2300 }
2301
2302
2303
2304
2305 i = ex && !strcmp(ex, "esac") && (pl->type || (*start==';' && end-start>1));
2306 if (i) {
2307
2308 if (end == start) {
2309 if (pl->type==128 && arg->c==2) break;
2310 if (pl->type==129 && (!arg->c || (arg->c==1 && **arg->v==';'))) break;
2311 s = "newline";
2312 goto flush;
2313 }
2314
2315
2316 if (!pl->type) {
2317
2318 if (arg->v && arg->v[arg->c] && strcmp(arg->v[arg->c], "&")) goto flush;
2319 if (!arg->c) {
2320 if (pl->prev->type == 2) {
2321
2322 arg_add(arg, xstrdup(":"));
2323 pl = add_pl(sp, &arg);
2324 }
2325 pl->type = 129;
2326 } else {
2327
2328 pl->count = -1;
2329 continue;
2330 }
2331 }
2332
2333
2334
2335 } else if (end == start || (arg->c && *start == ')' && pl->type!='f')) {
2336 if (pl->type == 'f' && arg->c<3) {
2337 s = "function()";
2338 goto flush;
2339 }
2340
2341
2342 if (arg->c == 1 && ex && !memcmp(ex, "do\0A", 4)) {
2343 s = "newline";
2344 goto flush;
2345 }
2346
2347
2348 if (!arg->c) free_pipeline(dlist_lpop(&sp->pipeline));
2349
2350
2351 if (end == start) done++;
2352 pl->count = -1;
2353
2354 continue;
2355 }
2356
2357
2358 arg_add(arg, s = xstrndup(start, end-start));
2359 start = end;
2360
2361
2362 if (i) {
2363
2364 if (pl->type==128) {
2365 if (arg->c==2 && strchr("()|;&", *s)) goto flush;
2366 if (arg->c==3) {
2367 if (strcmp(s, "in")) goto flush;
2368 pl->type = 1;
2369 (pl = add_pl(sp, &arg))->type = 129;
2370 }
2371
2372 continue;
2373
2374
2375 } else {
2376
2377
2378 if (*s==';') {
2379 if (arg->c>1 || (arg->c==1 && pl->prev->type==1)) goto flush;
2380 } else pl->type = 2;
2381 i = arg->c - (**arg->v==';' && arg->v[0][1]);
2382 if (i==1 && !strcmp(s, "esac")) {
2383
2384 if (arg->c>1) {
2385 arg->v[1] = 0;
2386 pl = add_pl(sp, &arg);
2387 arg_add(arg, s);
2388 } else pl->type = 0;
2389 } else {
2390 if (arg->c>1) i -= *arg->v[1]=='(';
2391 if (i>0 && ((i&1)==!!strchr("|)", *s) || strchr(";(", *s)))
2392 goto flush;
2393 if (*s=='&' || !strcmp(s, "||")) goto flush;
2394 if (*s==')') pl = add_pl(sp, &arg);
2395
2396 continue;
2397 }
2398 }
2399 }
2400
2401
2402 if (strchr(";|&", *s) && strncmp(s, "&>", 2)) {
2403 arg->c--;
2404
2405
2406 if (!strcmp(s, ";")) {
2407 arg->v[arg->c] = 0;
2408 free(s);
2409 s = 0;
2410
2411 if (!arg->c && ex && !memcmp(ex, "do\0C", 4)) continue;
2412
2413
2414 } else if (*s == ';') goto flush;
2415
2416
2417 if (!arg->c) goto flush;
2418 pl->count = -1;
2419
2420 continue;
2421 }
2422
2423
2424 if (arg->c>1 && !strcmp(s, "(")) pl->type = 'f';
2425 if (pl->type=='f') {
2426 if (arg->c == 2 && strcmp(s, "(")) goto flush;
2427 if (arg->c == 3) {
2428 if (strcmp(s, ")")) goto flush;
2429
2430
2431 pl->count = -1;
2432 dlist_add(&sp->expect, "}");
2433 dlist_add(&sp->expect, 0);
2434 dlist_add(&sp->expect, "{");
2435
2436 continue;
2437 }
2438
2439
2440 } else if (ex && !memcmp(ex, "do\0A", 4)) {
2441
2442
2443 if (strncmp(s, "((", 2) && *varend(s)) goto flush;
2444 pl->count = -1;
2445 sp->expect->prev->data = "do\0C";
2446
2447 continue;
2448
2449
2450 } else if (arg->c>1) continue;
2451
2452
2453 if (ex) {
2454
2455 if (!strcmp(ex, "{")) {
2456 if (strcmp(s, "{")) goto flush;
2457 free(arg->v[--arg->c]);
2458 free(dlist_lpop(&sp->expect));
2459
2460 continue;
2461
2462
2463
2464 } else if (!memcmp(ex, "do\0C", 4)) {
2465 if (strcmp(s, "do")) {
2466
2467 if (pl->prev->type == 's') goto flush;
2468 if (!strncmp(pl->prev->arg->v[1], "((", 2)) goto flush;
2469 else if (strcmp(s, "in")) goto flush;
2470 pl->type = 's';
2471
2472 continue;
2473 }
2474 }
2475 }
2476
2477
2478
2479
2480 if (!strcmp(s, "for") || !strcmp(s, "select") || !strcmp(s, "case")) {
2481
2482 if (!pl->type) pl->type = (*s == 'c') ? 128 : 1;
2483 dlist_add(&sp->expect, (*s == 'c') ? "esac" : "do\0A");
2484
2485 continue;
2486 }
2487
2488 end = 0;
2489 if (!strcmp(s, "if")) end = "then";
2490 else if (!strcmp(s, "while") || !strcmp(s, "until")) end = "do\0B";
2491 else if (!strcmp(s, "{")) end = "}";
2492 else if (!strcmp(s, "[[")) end = "]]";
2493 else if (!strcmp(s, "(")) end = ")";
2494
2495
2496 if (!ex && sp->expect) free(dlist_lpop(&sp->expect));
2497
2498
2499 if (end) {
2500 pl->type = 1;
2501
2502
2503 if (sp->expect && !sp->expect->prev->data) free(dlist_lpop(&sp->expect));
2504
2505
2506 } else if (!ex);
2507
2508
2509 else if (!strcmp(s, ex)) {
2510 struct sh_arg *aa = pl->prev->arg;
2511
2512
2513 if (aa->v[aa->c] && strcmp(aa->v[aa->c], "&")) goto flush;
2514
2515
2516 free(dlist_lpop(&sp->expect));
2517 if (3 == (pl->type = anystr(s, tails) ? 3 : 2)) {
2518 for (i = 0, pl2 = pl3 = pl; (pl2 = pl2->prev);) {
2519 if (pl2->type == 3) i++;
2520 else if (pl2->type) {
2521 if (!i) {
2522 if (pl2->type == 2) {
2523 pl2->end = pl3;
2524 pl3 = pl2;
2525 } else pl2->end = pl;
2526 }
2527 if ((pl2->type == 1 || pl2->type == 'f') && --i<0) break;
2528 }
2529 }
2530 }
2531
2532
2533 if (!strcmp(s, "do")) end = "done";
2534 else if (!strcmp(s, "then")) end = "fi\0A";
2535
2536
2537 } else if (!strcmp(ex, "fi")) {
2538 if (!strcmp(s, "elif")) {
2539 free(dlist_lpop(&sp->expect));
2540 end = "then";
2541
2542 } else if (!strcmp(s, "else")) {
2543 if (ex[3] != 'A') {
2544 s = "2 else";
2545 goto flush;
2546 }
2547 free(dlist_lpop(&sp->expect));
2548 end = "fi\0B";
2549 }
2550 }
2551
2552
2553 if (end) {
2554 if (!pl->type) pl->type = 2;
2555
2556 dlist_add(&sp->expect, end);
2557 if (!anystr(end, tails)) dlist_add(&sp->expect, 0);
2558 pl->count = -1;
2559 }
2560
2561
2562 if (!pl->type && anystr(s, (char *[]){"then", "do", "esac", "}", "]]", ")",
2563 "done", "fi", "elif", "else", 0})) goto flush;
2564 }
2565 free(delete);
2566
2567
2568 if (!sp->pipeline) return 0;
2569
2570
2571
2572 pl = sp->pipeline->prev;
2573 while (pl->count<pl->here && pl->arg[pl->count].c<0)
2574 pl->arg[pl->count++].c = 0;
2575
2576
2577 if (sp->expect) return 1;
2578 if (sp->pipeline && pl->count != pl->here) return 1;
2579 if (pl->arg->v[pl->arg->c] && strcmp(pl->arg->v[pl->arg->c], "&")) return 1;
2580
2581
2582
2583 dlist_terminate(sp->pipeline);
2584 return 0;
2585
2586flush:
2587 if (s) syntax_err(s);
2588 free_function(sp);
2589
2590 return 0-!!s;
2591}
2592
2593
2594static int wait_pipeline(struct sh_process *pp)
2595{
2596 int rc = 0;
2597
2598 for (dlist_terminate(pp); pp; pp = pp->next) {
2599 if (pp->pid) {
2600
2601 pp->exit = xwaitpid(pp->pid);
2602 pp->pid = 0;
2603 }
2604
2605 rc = pp->not ? !pp->exit : pp->exit;
2606 }
2607
2608 return rc;
2609}
2610
2611
2612static int pipe_segments(char *ctl, int *pipes, int **urd)
2613{
2614 unredirect(*urd);
2615 *urd = 0;
2616
2617
2618 if (*pipes != -1) {
2619 if (save_redirect(urd, *pipes, 0)) return 1;
2620 close(*pipes);
2621 *pipes = -1;
2622 }
2623
2624
2625 if (ctl && *ctl == '|' && ctl[1] != '|') {
2626 if (pipe(pipes)) {
2627 perror_msg("pipe");
2628
2629
2630 return 1;
2631 }
2632 if (save_redirect(urd, pipes[1], 1)) {
2633 close(pipes[0]);
2634 close(pipes[1]);
2635
2636 return 1;
2637 }
2638 if (pipes[1] != 1) close(pipes[1]);
2639 fcntl(*pipes, F_SETFD, FD_CLOEXEC);
2640 if (ctl[1] == '&') save_redirect(urd, 1, 2);
2641 }
2642
2643 return 0;
2644}
2645
2646struct blockstack {
2647 struct blockstack *next;
2648 struct sh_pipeline *start, *middle;
2649 struct sh_process *pp;
2650 int run, loop, *urd, pout;
2651 struct sh_arg farg;
2652 struct arg_list *fdelete;
2653 char *fvar;
2654};
2655
2656
2657static struct sh_pipeline *pop_block(struct blockstack **blist, int *pout)
2658{
2659 struct blockstack *blk = *blist;
2660 struct sh_pipeline *pl = blk->start->end;
2661
2662
2663 if (*pout != -1) close(*pout);
2664 *pout = blk->pout;
2665 unredirect(blk->urd);
2666 llist_traverse(blk->fdelete, free);
2667 free(blk->farg.v);
2668 free(llist_pop(blist));
2669
2670 return pl;
2671}
2672
2673
2674
2675static void do_prompt(char *prompt)
2676{
2677 char *s, *ss, c, cc, *pp = toybuf;
2678 int len, ll;
2679
2680 if (!prompt) return;
2681 while ((len = sizeof(toybuf)-(pp-toybuf))>0 && *prompt) {
2682 c = *(prompt++);
2683
2684 if (c=='!') {
2685 if (*prompt=='!') prompt++;
2686 else {
2687 pp += snprintf(pp, len, "%ld", TT.lineno);
2688 continue;
2689 }
2690 } else if (c=='\\') {
2691 cc = *(prompt++);
2692 if (!cc) {
2693 *pp++ = c;
2694 break;
2695 }
2696
2697
2698
2699 if (cc=='[' || cc==']') continue;
2700 else if (cc=='$') *pp++ = getuid() ? '$' : '#';
2701 else if (cc=='h' || cc=='H') {
2702 *pp = 0;
2703 gethostname(pp, len);
2704 pp[len-1] = 0;
2705 if (cc=='h' && (s = strchr(pp, '.'))) *s = 0;
2706 pp += strlen(pp);
2707 } else if (cc=='s') {
2708 s = getbasename(*toys.argv);
2709 while (*s && len--) *pp++ = *s++;
2710 } else if (cc=='w') {
2711 if ((s = getvar("PWD"))) {
2712 if ((ss = getvar("HOME")) && strstart(&s, ss)) {
2713 *pp++ = '~';
2714 if (--len && *s!='/') *pp++ = '/';
2715 len--;
2716 }
2717 if (len>0) {
2718 ll = strlen(s);
2719 pp = stpncpy(pp, s, ll>len ? len : ll);
2720 }
2721 }
2722 } else if (!(c = unescape(cc))) {
2723 *pp++ = '\\';
2724 if (--len) *pp++ = c;
2725 } else *pp++ = c;
2726 } else *pp++ = c;
2727 }
2728 len = pp-toybuf;
2729 if (len>=sizeof(toybuf)) len = sizeof(toybuf);
2730 writeall(2, toybuf, len);
2731}
2732
2733
2734
2735
2736static void run_function(struct sh_pipeline *pl)
2737{
2738 struct blockstack *blk = 0, *new;
2739 struct sh_process *pplist = 0;
2740 int *urd = 0, pipes[2] = {-1, -1};
2741 long i;
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758 TT.hfd = 10;
2759
2760
2761 while (pl) {
2762 char *ctl = pl->end->arg->v[pl->end->arg->c], **vv,
2763 *s = *pl->arg->v, *ss = pl->arg->v[1];
2764
2765
2766 if (pl->type<2) {
2767 if (blk && !blk->run) {
2768 pl = pl->end->next;
2769 continue;
2770 }
2771 if (pipe_segments(ctl, pipes, &urd)) break;
2772 }
2773
2774
2775 if (!pl->type) {
2776
2777
2778
2779 if (!strcmp(s, "break") || !strcmp(s, "continue")) {
2780
2781
2782 i = ss ? atol(ss) : 0;
2783 if (i<1) i = 1;
2784 if (!blk || pl->arg->c>2 || ss[strspn(ss, "0123456789")]) {
2785 syntax_err(s);
2786 break;
2787 }
2788
2789 while (i && blk)
2790 if (!--i && *s == 'c') pl = blk->start;
2791 else pl = pop_block(&blk, pipes);
2792 if (i) {
2793 syntax_err("break");
2794 break;
2795 }
2796 } else {
2797
2798 dlist_add_nomalloc((void *)&pplist, (void *)run_command(pl->arg));
2799
2800
2801 if (ctl && !strcmp(ctl, "&")) {
2802 pplist->job = ++TT.jobcnt;
2803 arg_add(&TT.jobs, (void *)pplist);
2804 pplist = 0;
2805 }
2806 }
2807
2808
2809 } else if (pl->type == 1) {
2810 struct sh_process *pp = 0;
2811 int rc;
2812
2813
2814 new = xzalloc(sizeof(*blk));
2815 new->next = blk;
2816 blk = new;
2817 blk->start = pl;
2818 blk->run = 1;
2819
2820
2821 blk->pout = *pipes;
2822 *pipes = -1;
2823 pp = expand_redir(pl->end->arg, 1, blk->urd = urd);
2824 urd = 0;
2825 rc = pp->exit;
2826 if (pp->arg.c) {
2827 syntax_err(*pp->arg.v);
2828 rc = 1;
2829 }
2830
2831
2832 if (rc || strcmp(s, "(")) {
2833 llist_traverse(pp->delete, free);
2834 free(pp);
2835 if (rc) {
2836 toys.exitval = rc;
2837 break;
2838 }
2839 } else {
2840
2841 if (!CFG_TOYBOX_FORK) {
2842 ss = pl2str(pl->next);
2843 pp->pid = run_subshell(ss, strlen(ss));
2844 free(ss);
2845 } else if (!(pp->pid = fork())) {
2846 run_function(pl->next);
2847 _exit(toys.exitval);
2848 }
2849
2850
2851 dlist_add_nomalloc((void *)&pplist, (void *)pp);
2852 pl = pl->end;
2853 continue;
2854 }
2855
2856
2857
2858
2859
2860
2861 if (!strcmp(s, "for") || !strcmp(s, "select")) {
2862 if (blk->loop);
2863 else if (!strncmp(blk->fvar = ss, "((", 2)) {
2864 blk->loop = 1;
2865dprintf(2, "TODO skipped init for((;;)), need math parser\n");
2866
2867
2868 } else if (pl->next->type == 's') {
2869 for (i = 1; i<pl->next->arg->c; i++)
2870 if (expand_arg(&blk->farg, pl->next->arg->v[i], 0, &blk->fdelete))
2871 break;
2872 if (i != pl->next->arg->c) pl = pop_block(&blk, pipes);
2873
2874 } else expand_arg(&blk->farg, "\"$@\"", 0, &blk->fdelete);
2875
2876
2877 if (*s == 's') for (i = 0; i<blk->farg.c; i++)
2878 dprintf(2, "%ld) %s\n", i+1, blk->farg.v[i]);
2879
2880
2881 } else if (!strcmp(s, "case"))
2882 if (!(blk->fvar = expand_one_arg(ss, NO_NULL, &blk->fdelete))) break;
2883
2884
2885
2886
2887 } else if (pl->type == 2) {
2888 int match, err;
2889
2890 blk->middle = pl;
2891
2892
2893 if (!strcmp(*blk->start->arg->v, "case")) {
2894 if (!strcmp(s, ";;")) {
2895 while (pl->type!=3) pl = pl->end;
2896 continue;
2897 } else if (strcmp(s, ";&")) {
2898 struct sh_arg arg = {0}, arg2 = {0};
2899
2900 for (err = 0, vv = 0;;) {
2901 if (!vv) {
2902 vv = pl->arg->v + (**pl->arg->v == ';');
2903 if (!*vv) {
2904 pl = pl->next;
2905 break;
2906 } else vv += **vv == '(';
2907 }
2908 arg.c = 0;
2909 if ((err = expand_arg_nobrace(&arg, *vv++, NO_SPLIT, &blk->fdelete,
2910 &arg2))) break;
2911 s = arg.c ? *arg.v : "";
2912 match = wildcard_match(blk->fvar, s, &arg2, 0);
2913 if (match>=0 && !s[match]) break;
2914 else if (**vv++ == ')') {
2915 vv = 0;
2916 if ((pl = pl->end)->type!=2) break;
2917 }
2918 }
2919 free(arg.v);
2920 free(arg2.v);
2921 if (err) break;
2922 if (pl->type==3) continue;
2923 }
2924
2925
2926 } else if (!strcmp(s, "then")) blk->run = blk->run && !toys.exitval;
2927 else if (!strcmp(s, "else") || !strcmp(s, "elif")) blk->run = !blk->run;
2928
2929
2930 else if (!strcmp(s, "do")) {
2931 ss = *blk->start->arg->v;
2932 if (!strcmp(ss, "while")) blk->run = blk->run && !toys.exitval;
2933 else if (!strcmp(ss, "until")) blk->run = blk->run && toys.exitval;
2934 else if (!strcmp(ss, "select")) {
2935 do_prompt(getvar("PS3"));
2936
2937 if (!(ss = xgetline(stdin, 0))) {
2938 pl = pop_block(&blk, pipes);
2939 printf("\n");
2940 } else if (!*ss) {
2941 pl = blk->start;
2942 continue;
2943 } else {
2944 match = atoi(ss);
2945 setvarval(blk->fvar, (match<1 || match>blk->farg.c)
2946 ? "" : blk->farg.v[match-1]);
2947 }
2948 } else if (blk->loop >= blk->farg.c) pl = pop_block(&blk, pipes);
2949 else if (!strncmp(blk->fvar, "((", 2)) {
2950dprintf(2, "TODO skipped running for((;;)), need math parser\n");
2951 } else setvarval(blk->fvar, blk->farg.v[blk->loop++]);
2952 }
2953
2954
2955 } else if (pl->type == 3) {
2956
2957
2958 if (!blk) break;
2959
2960
2961 if (blk->run && !strcmp(s, "done")) {
2962 pl = blk->middle;
2963 continue;
2964 }
2965
2966 pop_block(&blk, pipes);
2967 } else if (pl->type == 'f') pl = add_function(s, pl);
2968
2969
2970 if (pplist && *pipes == -1) {
2971 toys.exitval = wait_pipeline(pplist);
2972 llist_traverse(pplist, free_process);
2973 pplist = 0;
2974 }
2975
2976
2977 if (!pl->type || pl->type == 3) {
2978 while (ctl && !strcmp(ctl, toys.exitval ? "&&" : "||")) {
2979 if ((pl = pl->next)->type) pl = pl->end;
2980 ctl = pl->arg->v[pl->arg->c];
2981 }
2982 }
2983 pl = pl->next;
2984 }
2985
2986
2987
2988 if (*pipes != -1) close(*pipes);
2989 if (pplist) {
2990 toys.exitval = wait_pipeline(pplist);
2991 llist_traverse(pplist, free_process);
2992 }
2993 unredirect(urd);
2994
2995
2996 while (blk) pop_block(&blk, pipes);
2997}
2998
2999
3000static int sh_run(char *new)
3001{
3002 struct sh_function scratch;
3003
3004
3005
3006 memset(&scratch, 0, sizeof(struct sh_function));
3007 if (!parse_line(new, &scratch)) run_function(scratch.pipeline);
3008 free_function(&scratch);
3009
3010 return toys.exitval;
3011}
3012
3013
3014static struct sh_vars *initlocal(char *name, char *val)
3015{
3016 return addvar(xmprintf("%s=%s", name, val ? val : ""));
3017}
3018
3019static struct sh_vars *initlocaldef(char *name, char *val, char *def)
3020{
3021 return initlocal(name, (!val || !*val) ? def : val);
3022}
3023
3024
3025static void export(char *str)
3026{
3027 struct sh_vars *shv = 0;
3028 char *s;
3029
3030
3031 if (strchr(str, '=')) shv = setvar(xstrdup(str));
3032 else if (!(shv = findvar(str))) shv = addvar(str = xmprintf("%s=", str));
3033 if (!shv || (shv->flags&VAR_GLOBAL)) return;
3034
3035
3036 if (shv->flags&VAR_MAGIC) {
3037 s = shv->str;
3038 shv->str = xmprintf("%.*s=%s", (int)(varend(str)-str), str, getvar(str));
3039 free(s);
3040 }
3041
3042 xsetenv(shv->str, 0);
3043 shv->flags |= VAR_GLOBAL;
3044}
3045
3046static void unexport(char *str)
3047{
3048 struct sh_vars *shv = findvar(str);
3049
3050 if (shv) {
3051 if (shv->flags&VAR_GLOBAL) shv->str = xpop_env(str);
3052 shv->flags &=~VAR_GLOBAL;
3053 }
3054 if (strchr(str, '=')) setvar(str);
3055}
3056
3057
3058static void subshell_setup(void)
3059{
3060 int ii, to, from, pid, ppid, zpid, myppid = getppid(), len, uid = getuid();
3061 struct passwd *pw = getpwuid(uid);
3062 char *s, *ss, *magic[] = {"SECONDS","RANDOM","LINENO","GROUPS"},
3063 *readonly[] = {xmprintf("EUID=%d", geteuid()), xmprintf("UID=%d", uid),
3064 xmprintf("PPID=%d", myppid)};
3065 struct stat st;
3066 struct utsname uu;
3067 FILE *fp;
3068
3069
3070 srandom(TT.SECONDS = millitime());
3071 for (ii = 0; ii<ARRAY_LEN(magic); ii++)
3072 initlocal(magic[ii], "")->flags = VAR_MAGIC|(VAR_INT*('G'!=*magic[ii]));
3073 for (ii = 0; ii<ARRAY_LEN(readonly); ii++)
3074 addvar(readonly[ii])->flags = VAR_READONLY|VAR_INT;
3075
3076
3077 initlocal("PATH", _PATH_DEFPATH);
3078 if (!pw) pw = (void *)toybuf;
3079 sprintf(toybuf+1024, "%u", uid);
3080 initlocaldef("HOME", pw->pw_dir, "/");
3081 initlocaldef("SHELL", pw->pw_shell, "/bin/sh");
3082 initlocaldef("USER", pw->pw_name, toybuf+1024);
3083 initlocaldef("LOGNAME", pw->pw_name, toybuf+1024);
3084 gethostname(toybuf, sizeof(toybuf)-1);
3085 initlocal("HOSTNAME", toybuf);
3086 uname(&uu);
3087 initlocal("HOSTTYPE", uu.machine);
3088 sprintf(toybuf, "%s-unknown-linux", uu.machine);
3089 initlocal("MACHTYPE", toybuf);
3090 initlocal("OSTYPE", uu.sysname);
3091
3092
3093 initlocal("OPTERR", "1");
3094 if (readlink0("/proc/self/exe", s = toybuf, sizeof(toybuf))||(s=getenv("_")))
3095 initlocal("BASH", s);
3096 initlocal("PS2", "> ");
3097 initlocal("PS3", "#? ");
3098
3099
3100 TT.ifs = " \t\n";
3101 xsetenv("", 0);
3102 for (to = from = pid = ppid = zpid = 0; (s = environ[from]); from++) {
3103
3104
3105 if (!CFG_TOYBOX_FORK && !toys.stacktop) {
3106 len = 0;
3107 sscanf(s, "@%d,%d%n", &pid, &ppid, &len);
3108 if (s[len]) pid = ppid = 0;
3109 if (*s == '$' && s[1] == '=') zpid = atoi(s+2);
3110
3111 }
3112
3113
3114
3115 ss = varend(s);
3116 if (*ss == '=') {
3117 struct sh_vars *shv = findvar(s);
3118
3119 if (!shv) addvar(environ[from])->flags = VAR_GLOBAL;
3120 else if (shv->flags&VAR_READONLY) continue;
3121 else {
3122 shv->flags |= VAR_GLOBAL;
3123 free(shv->str);
3124 shv->str = s;
3125 }
3126 environ[to++] = s;
3127 }
3128 if (!memcmp(s, "IFS=", 4)) TT.ifs = s+4;
3129 }
3130 environ[toys.optc = to] = 0;
3131
3132
3133 sh_run("cd .");
3134
3135
3136 s = toys.argv[0];
3137 ss = 0;
3138 if (!strchr(s, '/')) {
3139 if ((ss = getcwd(0, 0))) {
3140 s = xmprintf("%s/%s", ss, s);
3141 free(ss);
3142 ss = s;
3143 } else if (*toybuf) s = toybuf;
3144 }
3145 s = xsetenv("_", s);
3146 if (!findvar(s)) addvar(s)->flags = VAR_GLOBAL;
3147 free(ss);
3148 if (!(ss = getvar("SHLVL"))) export("SHLVL=1");
3149 else {
3150 char buf[16];
3151
3152 sprintf(buf, "%u", atoi(ss+6)+1);
3153 xsetenv("SHLVL", buf);
3154 export("SHLVL");
3155 }
3156
3157
3158
3159
3160
3161 if (CFG_TOYBOX_FORK || toys.stacktop || pid!=getpid() || ppid!=myppid) return;
3162 if (fstat(254, &st) || !S_ISFIFO(st.st_mode)) error_exit(0);
3163 TT.pid = zpid;
3164 fcntl(254, F_SETFD, FD_CLOEXEC);
3165 fp = fdopen(254, "r");
3166
3167
3168
3169 while ((s = xgetline(fp, 0))) toys.exitval = sh_run(s);
3170 fclose(fp);
3171
3172 xexit();
3173}
3174
3175FILE *fpathopen(char *name)
3176{
3177 struct string_list *sl = 0;
3178 FILE *f = fopen(name, "r");
3179 char *pp = getvar("PATH") ? : _PATH_DEFPATH;
3180
3181 if (!f) {
3182 for (sl = find_in_path(pp, *toys.optargs); sl; free(llist_pop(&sl)))
3183 if ((f = fopen(sl->str, "r"))) break;
3184 if (sl) llist_traverse(sl, free);
3185 }
3186
3187 return f;
3188}
3189
3190void sh_main(void)
3191{
3192 char *new, *cc = 0;
3193 struct sh_function scratch;
3194 int prompt = 0;
3195 struct string_list *sl = 0;
3196 struct sh_arg arg;
3197 FILE *f;
3198
3199 signal(SIGPIPE, SIG_IGN);
3200 TT.options = OPT_BRACE;
3201
3202 TT.pid = getpid();
3203 TT.SECONDS = time(0);
3204 TT.arg = &arg;
3205 if (!(arg.c = toys.optc)) {
3206 arg.v = xmalloc(2*sizeof(char *));
3207 arg.v[arg.c++] = *toys.argv;
3208 arg.v[arg.c] = 0;
3209 } else memcpy(arg.v = xmalloc((arg.c+1)*sizeof(char *)), toys.optargs,
3210 (arg.c+1)*sizeof(char *));
3211
3212
3213
3214
3215
3216
3217
3218
3219 if (toys.stacktop) {
3220 cc = TT.sh.c;
3221 if (FLAG(s) || (!FLAG(c) && !toys.optc)) TT.options |= OPT_S;
3222 if (FLAG(i) || (!FLAG(c) && (TT.options&OPT_S) && isatty(0)))
3223 TT.options |= OPT_I;
3224 if (FLAG(c)) TT.options |= OPT_C;
3225 }
3226
3227
3228
3229
3230 subshell_setup();
3231 if (TT.options&OPT_I) {
3232 if (!getvar("PS1")) setvarval("PS1", getpid() ? "\\$ " : "# ");
3233
3234
3235
3236 xsignal(SIGINT, SIG_IGN);
3237 }
3238
3239 memset(&scratch, 0, sizeof(scratch));
3240
3241
3242 if (cc) f = fmemopen(cc, strlen(cc), "r");
3243 else if (TT.options&OPT_S) f = stdin;
3244 else if (!(f = fpathopen(*toys.optargs))) perror_exit_raw(*toys.optargs);
3245
3246
3247 for (;;) {
3248 TT.lineno++;
3249 if ((TT.options&(OPT_I|OPT_S|OPT_C)) == (OPT_I|OPT_S))
3250 do_prompt(getvar(prompt ? "PS2" : "PS1"));
3251
3252
3253 if (!(new = xgetline(f, 0))) {
3254
3255 if (errno != EINTR) break;
3256 free_function(&scratch);
3257 prompt = 0;
3258 if (f != stdin) break;
3259 continue;
3260
3261
3262 }
3263
3264 if (sl) {
3265 if (*new == 0x7f) error_exit("'%s' is ELF", sl->str);
3266 free(sl);
3267 sl = 0;
3268 }
3269
3270
3271
3272 if (1 != (prompt = parse_line(new, &scratch))) {
3273
3274 if (!prompt) run_function(scratch.pipeline);
3275 free_function(&scratch);
3276 prompt = 0;
3277 }
3278 free(new);
3279 }
3280
3281 if (prompt) error_exit("%ld:unfinished line"+4*!TT.lineno, TT.lineno);
3282}
3283
3284
3285
3286#define CLEANUP_sh
3287#define FOR_cd
3288#include "generated/flags.h"
3289void cd_main(void)
3290{
3291 char *home = getvar("HOME") ? : "/", *pwd = getvar("PWD"), *from, *to = 0,
3292 *dd = xstrdup(*toys.optargs ? *toys.optargs : home);
3293 int bad = 0;
3294
3295
3296
3297
3298 if (*dd != '/') {
3299 from = pwd ? : (to = getcwd(0, 0));
3300 if (!from) setvarval("PWD", "(nowhere)");
3301 else {
3302 from = xmprintf("%s/%s", from, dd);
3303 free(dd);
3304 free(to);
3305 dd = from;
3306 }
3307 }
3308
3309 if (FLAG(P)) {
3310 struct stat st;
3311 char *pp;
3312
3313
3314 if ((pp = xabspath(dd, 1)) && stat(pp, &st) && !S_ISDIR(st.st_mode))
3315 bad++, errno = ENOTDIR;
3316 else {
3317 free(dd);
3318 dd = pp;
3319 }
3320 } else {
3321
3322
3323 for (from = to = dd; *from;) {
3324 if (*from=='/' && from[1]=='/') from++;
3325 else if (*from!='/' || from[1]!='.') *to++ = *from++;
3326 else if (!from[2] || from[2]=='/') from += 2;
3327 else if (from[2]=='.' && (!from[3] || from[3]=='/')) {
3328 from += 3;
3329 while (to>dd && *--to != '/');
3330 } else *to++ = *from++;
3331 }
3332 if (to == dd) to++;
3333 if (to-dd>1 && to[-1]=='/') to--;
3334 *to = 0;
3335 }
3336
3337 if (bad || chdir(dd)) perror_msg("chdir '%s'", dd);
3338 else {
3339 if (pwd) {
3340 setvarval("OLDPWD", pwd);
3341 if (TT.cdcount == 1) {
3342 export("OLDPWD");
3343 TT.cdcount++;
3344 }
3345 }
3346 setvarval("PWD", dd);
3347 if (!TT.cdcount) {
3348 export("PWD");
3349 TT.cdcount++;
3350 }
3351 }
3352 free(dd);
3353}
3354
3355void exit_main(void)
3356{
3357 exit(*toys.optargs ? atoi(*toys.optargs) : 0);
3358}
3359
3360void unset_main(void)
3361{
3362 char **arg, *s;
3363
3364 for (arg = toys.optargs; *arg; arg++) {
3365 s = varend(*arg);
3366 if (s == *arg || *s) {
3367 error_msg("bad '%s'", *arg);
3368 continue;
3369 }
3370
3371
3372 if (!strcmp(*arg, "IFS")) TT.ifs = " \t\n";
3373 unsetvar(*arg);
3374 }
3375}
3376
3377#define CLEANUP_cd
3378#define FOR_export
3379#include "generated/flags.h"
3380
3381void export_main(void)
3382{
3383 char **arg, *eq;
3384
3385
3386 if (!toys.optc) {
3387 for (arg = environ; *arg; arg++) xprintf("declare -x %s\n", *arg);
3388 return;
3389 }
3390
3391
3392 for (arg = toys.optargs; *arg; arg++) {
3393 eq = varend(*arg);
3394 if (eq == *arg || (*eq && *eq != '=')) {
3395 error_msg("bad %s", *arg);
3396 continue;
3397 }
3398
3399 if (FLAG(n)) unexport(*arg);
3400 else export(*arg);
3401 }
3402}
3403
3404void eval_main(void)
3405{
3406 struct sh_arg *old = TT.arg, new = {toys.argv, toys.optc+1};
3407 char *s;
3408
3409 TT.arg = &new;
3410 s = expand_one_arg("\"$*\"", SEMI_IFS, 0);
3411 TT.arg = old;
3412 sh_run(s);
3413 free(s);
3414}
3415
3416#define CLEANUP_export
3417#define FOR_exec
3418#include "generated/flags.h"
3419
3420void exec_main(void)
3421{
3422 char *ee[1] = {0}, **old = environ;
3423
3424
3425 free(TT.pp->urd);
3426 TT.pp->urd = 0;
3427 if (!toys.optc) return;
3428
3429
3430 TT.isexec = *toys.optargs;
3431 if (FLAG(c)) environ = ee;
3432 if (TT.exec.a || FLAG(l))
3433 *toys.optargs = xmprintf("%s%s", FLAG(l) ? "-" : "", TT.exec.a?:TT.isexec);
3434 sh_exec(toys.optargs);
3435
3436
3437 perror_msg("%s", TT.isexec);
3438 if (*toys.optargs != TT.isexec) free(*toys.optargs);
3439 TT.isexec = 0;
3440 toys.exitval = 127;
3441 environ = old;
3442}
3443
3444
3445int find_plus_minus(int *minus)
3446{
3447 long long when, then;
3448 int i, plus;
3449
3450 if (minus) *minus = 0;
3451 for (then = i = plus = 0; i<TT.jobs.c; i++) {
3452 if ((when = ((struct sh_process *)TT.jobs.v[i])->when) > then) {
3453 then = when;
3454 if (minus) *minus = plus;
3455 plus = i;
3456 }
3457 }
3458
3459 return plus;
3460}
3461
3462
3463
3464
3465int find_job(char *s)
3466{
3467 char *ss;
3468 long ll = strtol(s, &ss, 10);
3469 int i, j;
3470
3471 if (!TT.jobs.c) return -1;
3472 if (!*s || (!s[1] && strchr("%+-", *s))) {
3473 int minus, plus = find_plus_minus(&minus);
3474
3475 return (*s == '-') ? minus : plus;
3476 }
3477
3478
3479 if (s != ss && !*ss)
3480 for (i = 0; i<TT.jobs.c; i++)
3481 if (((struct sh_process *)TT.jobs.v[i])->job == ll) return i;
3482
3483
3484 for (i = 0; i<TT.jobs.c; i++) {
3485 struct sh_process *pp = (void *)TT.jobs.v[i];
3486
3487 if (strstart(&s, *pp->arg.v)) return i;
3488 if (*s != '?' || !s[1]) continue;
3489 for (j = 0; j<pp->arg.c; j++) if (strstr(pp->arg.v[j], s+1)) return i;
3490 }
3491
3492 return -1;
3493}
3494
3495
3496void print_job(int i, char dash)
3497{
3498 struct sh_process *pp = (void *)TT.jobs.v[i];
3499 char *s = "Run";
3500 int j;
3501
3502
3503 if (pp->exit<0) s = "Stop";
3504 else if (pp->exit>126) s = "Kill";
3505 else if (pp->exit>0) s = "Done";
3506 printf("[%d]%c %-6s", pp->job, dash, s);
3507 for (j = 0; j<pp->raw->c; j++) printf(" %s"+!j, pp->raw->v[j]);
3508 printf("\n");
3509}
3510
3511void jobs_main(void)
3512{
3513 int i, j, minus, plus = find_plus_minus(&minus);
3514 char *s;
3515
3516
3517
3518 for (i = 0;;i++) {
3519 if (toys.optc) {
3520 if (!(s = toys.optargs[i])) break;
3521 if ((j = find_job(s+('%' == *s))) == -1) {
3522 perror_msg("%s: no such job", s);
3523
3524 continue;
3525 }
3526 } else if ((j = i) >= TT.jobs.c) break;
3527
3528 print_job(i, (i == plus) ? '+' : (i == minus) ? '-' : ' ');
3529 }
3530}
3531
3532void shift_main(void)
3533{
3534 long long by = 1;
3535
3536 if (toys.optc) by = atolx(*toys.optargs);
3537 by += TT.shift;
3538 if (by<0 || by>=TT.arg->c) toys.exitval++;
3539 else TT.shift = by;
3540}
3541
3542void source_main(void)
3543{
3544 struct sh_function scratch;
3545 FILE *ff = fpathopen(*toys.optargs);
3546 long lineno = TT.lineno, shift = TT.shift, prompt;
3547 struct sh_arg arg, *old = TT.arg;
3548 char *new;
3549
3550 if (!ff) return perror_msg_raw(*toys.optargs);
3551
3552 arg.c = toys.optc;
3553 arg.v = toys.optargs;
3554 TT.arg = &arg;
3555 memset(&scratch, 0, sizeof(scratch));
3556
3557
3558 for (TT.lineno = TT.shift = 0;;) {
3559 new = xgetline(ff, 0);
3560 if (!TT.lineno++ && new && *new == 0x7f) {
3561 error_msg("'%s' is ELF", *toys.optargs);
3562 free(new);
3563
3564 break;
3565 }
3566 if (1!=(prompt = parse_line(new ? : " ", &scratch))) {
3567 if (!prompt) run_function(scratch.pipeline);
3568 free_function(&scratch);
3569 if (!new) {
3570 if (prompt) syntax_err("unexpected end of file");
3571
3572 break;
3573 }
3574 }
3575 free(new);
3576 }
3577 fclose(ff);
3578 TT.lineno = lineno;
3579 TT.shift = shift;
3580 TT.arg = old;
3581}
3582