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#define DEBUG 0
170
171#define DEBUG_TIME 0
172#define DEBUG_PID 1
173#define DEBUG_SIG 1
174#define DEBUG_INTONOFF 0
175
176#define PROFILE 0
177
178#define JOBS ENABLE_ASH_JOB_CONTROL
179
180#include <fnmatch.h>
181#include <sys/times.h>
182#include <sys/utsname.h>
183#include "busybox.h"
184
185
186
187
188#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
189#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
190
191#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
192#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
193
194#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
195#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
196#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
197#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
198#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
199#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
215#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
216#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
217#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
218#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
219#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
220#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
221#define IF_BASH_READ_D IF_ASH_BASH_COMPAT
222
223#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
224
225# undef ENABLE_ASH_INTERNAL_GLOB
226# define ENABLE_ASH_INTERNAL_GLOB 1
227#endif
228
229#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
230# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
231# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
232# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
233# error glob() should unbackslash them and match. uClibc does not unbackslash,
234# error fails to match dirname, subsequently not expanding <pattern> in it.
235
236
237
238#endif
239
240#if !ENABLE_ASH_INTERNAL_GLOB
241# include <glob.h>
242#endif
243
244#include "unicode.h"
245#include "shell_common.h"
246#if ENABLE_FEATURE_SH_MATH
247# include "math.h"
248#else
249typedef long arith_t;
250# define ARITH_FMT "%ld"
251#endif
252#if ENABLE_ASH_RANDOM_SUPPORT
253# include "random.h"
254#else
255# define CLEAR_RANDOM_T(rnd) ((void)0)
256#endif
257
258#include "NUM_APPLETS.h"
259#if NUM_APPLETS == 1
260
261# undef CONFIG_FEATURE_SH_STANDALONE
262# undef ENABLE_FEATURE_SH_STANDALONE
263# undef IF_FEATURE_SH_STANDALONE
264# undef IF_NOT_FEATURE_SH_STANDALONE
265# define ENABLE_FEATURE_SH_STANDALONE 0
266# define IF_FEATURE_SH_STANDALONE(...)
267# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
268#endif
269
270#ifndef F_DUPFD_CLOEXEC
271# define F_DUPFD_CLOEXEC F_DUPFD
272#endif
273#ifndef O_CLOEXEC
274# define O_CLOEXEC 0
275#endif
276#ifndef PIPE_BUF
277# define PIPE_BUF 4096
278#endif
279
280#if !BB_MMU
281# error "Do not even bother, ash will not run on NOMMU machine"
282#endif
283
284
285
286
287
288
289
290
291
292
293#ifndef BB_GLOBAL_CONST
294# define BB_GLOBAL_CONST const
295#endif
296
297
298
299
300#define VTABSIZE 39
301#define ATABSIZE 39
302#define CMDTABLESIZE 31
303
304
305
306
307static const char *const optletters_optnames[] = {
308 "e" "errexit",
309 "f" "noglob",
310 "I" "ignoreeof",
311 "i" "interactive",
312 "m" "monitor",
313 "n" "noexec",
314 "s" "stdin",
315 "x" "xtrace",
316 "v" "verbose",
317 "C" "noclobber",
318 "a" "allexport",
319 "b" "notify",
320 "u" "nounset",
321 "\0" "vi"
322#if BASH_PIPEFAIL
323 ,"\0" "pipefail"
324#endif
325#if DEBUG
326 ,"\0" "nolog"
327 ,"\0" "debug"
328#endif
329};
330
331#define optletters(n) optletters_optnames[n][0]
332#define optnames(n) (optletters_optnames[n] + 1)
333
334enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
335
336
337
338
339#define msg_illnum "Illegal number: %s"
340
341
342
343
344
345
346
347
348
349
350struct jmploc {
351 jmp_buf loc;
352};
353
354struct globals_misc {
355 uint8_t exitstatus;
356 uint8_t back_exitstatus;
357 smallint job_warning;
358 int rootpid;
359
360 int shlvl;
361#define rootshell (!shlvl)
362 int errlinno;
363
364 char *minusc;
365
366 char *curdir;
367 char *physdir;
368
369 char *arg0;
370
371 struct jmploc *exception_handler;
372
373 volatile int suppress_int;
374 volatile smallint pending_int;
375 volatile smallint got_sigchld;
376 volatile smallint pending_sig;
377 smallint exception_type;
378
379#define EXINT 0
380#define EXERROR 1
381#define EXEXIT 4
382
383 char nullstr[1];
384
385 char optlist[NOPTS];
386#define eflag optlist[0]
387#define fflag optlist[1]
388#define Iflag optlist[2]
389#define iflag optlist[3]
390#define mflag optlist[4]
391#define nflag optlist[5]
392#define sflag optlist[6]
393#define xflag optlist[7]
394#define vflag optlist[8]
395#define Cflag optlist[9]
396#define aflag optlist[10]
397#define bflag optlist[11]
398#define uflag optlist[12]
399#define viflag optlist[13]
400#if BASH_PIPEFAIL
401# define pipefail optlist[14]
402#else
403# define pipefail 0
404#endif
405#if DEBUG
406# define nolog optlist[14 + BASH_PIPEFAIL]
407# define debug optlist[15 + BASH_PIPEFAIL]
408#endif
409
410
411
412
413
414
415
416 char sigmode[NSIG - 1];
417#define S_DFL 1
418#define S_CATCH 2
419#define S_IGN 3
420#define S_HARD_IGN 4
421
422
423 uint8_t gotsig[NSIG - 1];
424 uint8_t may_have_traps;
425 char *trap[NSIG];
426 char **trap_ptr;
427
428
429#if ENABLE_ASH_RANDOM_SUPPORT
430 random_t random_gen;
431#endif
432 pid_t backgndpid;
433};
434extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
435#define G_misc (*ash_ptr_to_globals_misc)
436#define exitstatus (G_misc.exitstatus )
437#define back_exitstatus (G_misc.back_exitstatus )
438#define job_warning (G_misc.job_warning)
439#define rootpid (G_misc.rootpid )
440#define shlvl (G_misc.shlvl )
441#define errlinno (G_misc.errlinno )
442#define minusc (G_misc.minusc )
443#define curdir (G_misc.curdir )
444#define physdir (G_misc.physdir )
445#define arg0 (G_misc.arg0 )
446#define exception_handler (G_misc.exception_handler)
447#define exception_type (G_misc.exception_type )
448#define suppress_int (G_misc.suppress_int )
449#define pending_int (G_misc.pending_int )
450#define got_sigchld (G_misc.got_sigchld )
451#define pending_sig (G_misc.pending_sig )
452#define nullstr (G_misc.nullstr )
453#define optlist (G_misc.optlist )
454#define sigmode (G_misc.sigmode )
455#define gotsig (G_misc.gotsig )
456#define may_have_traps (G_misc.may_have_traps )
457#define trap (G_misc.trap )
458#define trap_ptr (G_misc.trap_ptr )
459#define random_gen (G_misc.random_gen )
460#define backgndpid (G_misc.backgndpid )
461#define INIT_G_misc() do { \
462 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
463 barrier(); \
464 curdir = nullstr; \
465 physdir = nullstr; \
466 trap_ptr = trap; \
467} while (0)
468
469
470
471#if DEBUG
472static void trace_printf(const char *fmt, ...);
473static void trace_vprintf(const char *fmt, va_list va);
474# define TRACE(param) trace_printf param
475# define TRACEV(param) trace_vprintf param
476# define close(fd) do { \
477 int dfd = (fd); \
478 if (close(dfd) < 0) \
479 bb_error_msg("bug on %d: closing %d(0x%x)", \
480 __LINE__, dfd, dfd); \
481} while (0)
482#else
483# define TRACE(param)
484# define TRACEV(param)
485#endif
486
487
488
489#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
490#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
491
492static int
493isdigit_str9(const char *str)
494{
495 int maxlen = 9 + 1;
496 while (--maxlen && isdigit(*str))
497 str++;
498 return (*str == '\0');
499}
500
501static const char *
502var_end(const char *var)
503{
504 while (*var)
505 if (*var++ == '=')
506 break;
507 return var;
508}
509
510
511
512
513static void exitshell(void) NORETURN;
514
515
516
517
518
519
520
521#if DEBUG_INTONOFF
522# define INT_OFF do { \
523 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
524 suppress_int++; \
525 barrier(); \
526} while (0)
527#else
528# define INT_OFF do { \
529 suppress_int++; \
530 barrier(); \
531} while (0)
532#endif
533
534
535
536
537
538
539static void raise_exception(int) NORETURN;
540static void
541raise_exception(int e)
542{
543#if DEBUG
544 if (exception_handler == NULL)
545 abort();
546#endif
547 INT_OFF;
548 exception_type = e;
549 longjmp(exception_handler->loc, 1);
550}
551#if DEBUG
552#define raise_exception(e) do { \
553 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
554 raise_exception(e); \
555} while (0)
556#endif
557
558
559
560
561
562
563
564
565static void raise_interrupt(void) NORETURN;
566static void
567raise_interrupt(void)
568{
569 pending_int = 0;
570
571
572 sigprocmask_allsigs(SIG_UNBLOCK);
573
574
575 if (!(rootshell && iflag)) {
576
577 signal(SIGINT, SIG_DFL);
578 raise(SIGINT);
579 }
580
581 exitstatus = SIGINT + 128;
582 raise_exception(EXINT);
583
584}
585#if DEBUG
586#define raise_interrupt() do { \
587 TRACE(("raising interrupt on line %d\n", __LINE__)); \
588 raise_interrupt(); \
589} while (0)
590#endif
591
592static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
593int_on(void)
594{
595 barrier();
596 if (--suppress_int == 0 && pending_int) {
597 raise_interrupt();
598 }
599}
600#if DEBUG_INTONOFF
601# define INT_ON do { \
602 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
603 int_on(); \
604} while (0)
605#else
606# define INT_ON int_on()
607#endif
608static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
609force_int_on(void)
610{
611 barrier();
612 suppress_int = 0;
613 if (pending_int)
614 raise_interrupt();
615}
616#define FORCE_INT_ON force_int_on()
617
618#define SAVE_INT(v) ((v) = suppress_int)
619
620#define RESTORE_INT(v) do { \
621 barrier(); \
622 suppress_int = (v); \
623 if (suppress_int == 0 && pending_int) \
624 raise_interrupt(); \
625} while (0)
626
627
628
629
630static void
631outstr(const char *p, FILE *file)
632{
633 INT_OFF;
634 fputs(p, file);
635 INT_ON;
636}
637
638static void
639flush_stdout_stderr(void)
640{
641 INT_OFF;
642 fflush_all();
643 INT_ON;
644}
645
646
647static void
648newline_and_flush(FILE *dest)
649{
650 INT_OFF;
651 putc('\n', dest);
652 fflush(dest);
653 INT_ON;
654}
655
656static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
657static int
658out1fmt(const char *fmt, ...)
659{
660 va_list ap;
661 int r;
662
663 INT_OFF;
664 va_start(ap, fmt);
665 r = vprintf(fmt, ap);
666 va_end(ap);
667 INT_ON;
668 return r;
669}
670
671static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
672static int
673fmtstr(char *outbuf, size_t length, const char *fmt, ...)
674{
675 va_list ap;
676 int ret;
677
678 INT_OFF;
679 va_start(ap, fmt);
680 ret = vsnprintf(outbuf, length, fmt, ap);
681 va_end(ap);
682 INT_ON;
683 return ret;
684}
685
686static void
687out1str(const char *p)
688{
689 outstr(p, stdout);
690}
691
692static void
693out2str(const char *p)
694{
695 outstr(p, stderr);
696 flush_stdout_stderr();
697}
698
699
700
701
702
703#define CTL_FIRST CTLESC
704#define CTLESC ((unsigned char)'\201')
705#define CTLVAR ((unsigned char)'\202')
706#define CTLENDVAR ((unsigned char)'\203')
707#define CTLBACKQ ((unsigned char)'\204')
708#define CTLARI ((unsigned char)'\206')
709#define CTLENDARI ((unsigned char)'\207')
710#define CTLQUOTEMARK ((unsigned char)'\210')
711#define CTL_LAST CTLQUOTEMARK
712
713
714#define VSTYPE 0x0f
715#define VSNUL 0x10
716
717
718#define VSNORMAL 0x1
719#define VSMINUS 0x2
720#define VSPLUS 0x3
721#define VSQUESTION 0x4
722#define VSASSIGN 0x5
723#define VSTRIMRIGHT 0x6
724#define VSTRIMRIGHTMAX 0x7
725#define VSTRIMLEFT 0x8
726#define VSTRIMLEFTMAX 0x9
727#define VSLENGTH 0xa
728#if BASH_SUBSTR
729#define VSSUBSTR 0xc
730#endif
731#if BASH_PATTERN_SUBST
732#define VSREPLACE 0xd
733#define VSREPLACEALL 0xe
734#endif
735
736static const char dolatstr[] ALIGN1 = {
737 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
738};
739#define DOLATSTRLEN 6
740
741#define NCMD 0
742#define NPIPE 1
743#define NREDIR 2
744#define NBACKGND 3
745#define NSUBSHELL 4
746#define NAND 5
747#define NOR 6
748#define NSEMI 7
749#define NIF 8
750#define NWHILE 9
751#define NUNTIL 10
752#define NFOR 11
753#define NCASE 12
754#define NCLIST 13
755#define NDEFUN 14
756#define NARG 15
757#define NTO 16
758#if BASH_REDIR_OUTPUT
759#define NTO2 17
760#endif
761#define NCLOBBER 18
762#define NFROM 19
763#define NFROMTO 20
764#define NAPPEND 21
765#define NTOFD 22
766#define NFROMFD 23
767#define NHERE 24
768#define NXHERE 25
769#define NNOT 26
770#define N_NUMBER 27
771
772union node;
773
774struct ncmd {
775 smallint type;
776 int linno;
777 union node *assign;
778 union node *args;
779 union node *redirect;
780};
781
782struct npipe {
783 smallint type;
784 smallint pipe_backgnd;
785 struct nodelist *cmdlist;
786};
787
788struct nredir {
789 smallint type;
790 int linno;
791 union node *n;
792 union node *redirect;
793};
794
795struct nbinary {
796 smallint type;
797 union node *ch1;
798 union node *ch2;
799};
800
801struct nif {
802 smallint type;
803 union node *test;
804 union node *ifpart;
805 union node *elsepart;
806};
807
808struct nfor {
809 smallint type;
810 int linno;
811 union node *args;
812 union node *body;
813 char *var;
814};
815
816struct ncase {
817 smallint type;
818 int linno;
819 union node *expr;
820 union node *cases;
821};
822
823struct nclist {
824 smallint type;
825 union node *next;
826 union node *pattern;
827 union node *body;
828};
829
830struct ndefun {
831 smallint type;
832 int linno;
833 char *text;
834 union node *body;
835};
836
837struct narg {
838 smallint type;
839 union node *next;
840 char *text;
841 struct nodelist *backquote;
842};
843
844
845
846
847
848struct nfile {
849 smallint type;
850 union node *next;
851 int fd;
852 int _unused_dupfd;
853 union node *fname;
854 char *expfname;
855};
856
857struct ndup {
858 smallint type;
859 union node *next;
860 int fd;
861 int dupfd;
862 union node *vname;
863 char *_unused_expfname;
864};
865
866struct nhere {
867 smallint type;
868 union node *next;
869 int fd;
870 union node *doc;
871};
872
873struct nnot {
874 smallint type;
875 union node *com;
876};
877
878union node {
879 smallint type;
880 struct ncmd ncmd;
881 struct npipe npipe;
882 struct nredir nredir;
883 struct nbinary nbinary;
884 struct nif nif;
885 struct nfor nfor;
886 struct ncase ncase;
887 struct nclist nclist;
888 struct ndefun ndefun;
889 struct narg narg;
890 struct nfile nfile;
891 struct ndup ndup;
892 struct nhere nhere;
893 struct nnot nnot;
894};
895
896
897
898
899
900#define NODE_EOF ((union node *) -1L)
901
902struct nodelist {
903 struct nodelist *next;
904 union node *n;
905};
906
907struct funcnode {
908 int count;
909 union node n;
910};
911
912
913
914
915static void
916freefunc(struct funcnode *f)
917{
918 if (f && --f->count < 0)
919 free(f);
920}
921
922
923
924
925#if DEBUG
926
927static FILE *tracefile;
928
929static void
930trace_printf(const char *fmt, ...)
931{
932 va_list va;
933
934 if (debug != 1)
935 return;
936 if (DEBUG_TIME)
937 fprintf(tracefile, "%u ", (int) time(NULL));
938 if (DEBUG_PID)
939 fprintf(tracefile, "[%u] ", (int) getpid());
940 if (DEBUG_SIG)
941 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
942 va_start(va, fmt);
943 vfprintf(tracefile, fmt, va);
944 va_end(va);
945}
946
947static void
948trace_vprintf(const char *fmt, va_list va)
949{
950 if (debug != 1)
951 return;
952 vfprintf(tracefile, fmt, va);
953 fprintf(tracefile, "\n");
954}
955
956static void
957trace_puts(const char *s)
958{
959 if (debug != 1)
960 return;
961 fputs(s, tracefile);
962}
963
964static void
965trace_puts_quoted(char *s)
966{
967 char *p;
968 char c;
969
970 if (debug != 1)
971 return;
972 putc('"', tracefile);
973 for (p = s; *p; p++) {
974 switch ((unsigned char)*p) {
975 case '\n': c = 'n'; goto backslash;
976 case '\t': c = 't'; goto backslash;
977 case '\r': c = 'r'; goto backslash;
978 case '\"': c = '\"'; goto backslash;
979 case '\\': c = '\\'; goto backslash;
980 case CTLESC: c = 'e'; goto backslash;
981 case CTLVAR: c = 'v'; goto backslash;
982 case CTLBACKQ: c = 'q'; goto backslash;
983 backslash:
984 putc('\\', tracefile);
985 putc(c, tracefile);
986 break;
987 default:
988 if (*p >= ' ' && *p <= '~')
989 putc(*p, tracefile);
990 else {
991 putc('\\', tracefile);
992 putc((*p >> 6) & 03, tracefile);
993 putc((*p >> 3) & 07, tracefile);
994 putc(*p & 07, tracefile);
995 }
996 break;
997 }
998 }
999 putc('"', tracefile);
1000}
1001
1002static void
1003trace_puts_args(char **ap)
1004{
1005 if (debug != 1)
1006 return;
1007 if (!*ap)
1008 return;
1009 while (1) {
1010 trace_puts_quoted(*ap);
1011 if (!*++ap) {
1012 putc('\n', tracefile);
1013 break;
1014 }
1015 putc(' ', tracefile);
1016 }
1017}
1018
1019static void
1020opentrace(void)
1021{
1022 char s[100];
1023#ifdef O_APPEND
1024 int flags;
1025#endif
1026
1027 if (debug != 1) {
1028 if (tracefile)
1029 fflush(tracefile);
1030
1031 return;
1032 }
1033 strcpy(s, "./trace");
1034 if (tracefile) {
1035 if (!freopen(s, "a", tracefile)) {
1036 fprintf(stderr, "Can't re-open %s\n", s);
1037 debug = 0;
1038 return;
1039 }
1040 } else {
1041 tracefile = fopen(s, "a");
1042 if (tracefile == NULL) {
1043 fprintf(stderr, "Can't open %s\n", s);
1044 debug = 0;
1045 return;
1046 }
1047 }
1048#ifdef O_APPEND
1049 flags = fcntl(fileno(tracefile), F_GETFL);
1050 if (flags >= 0)
1051 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1052#endif
1053 setlinebuf(tracefile);
1054 fputs("\nTracing started.\n", tracefile);
1055}
1056
1057static void
1058indent(int amount, char *pfx, FILE *fp)
1059{
1060 int i;
1061
1062 for (i = 0; i < amount; i++) {
1063 if (pfx && i == amount - 1)
1064 fputs(pfx, fp);
1065 putc('\t', fp);
1066 }
1067}
1068
1069
1070static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1071
1072static void
1073sharg(union node *arg, FILE *fp)
1074{
1075 char *p;
1076 struct nodelist *bqlist;
1077 unsigned char subtype;
1078
1079 if (arg->type != NARG) {
1080 out1fmt("<node type %d>\n", arg->type);
1081 abort();
1082 }
1083 bqlist = arg->narg.backquote;
1084 for (p = arg->narg.text; *p; p++) {
1085 switch ((unsigned char)*p) {
1086 case CTLESC:
1087 p++;
1088 putc(*p, fp);
1089 break;
1090 case CTLVAR:
1091 putc('$', fp);
1092 putc('{', fp);
1093 subtype = *++p;
1094 if (subtype == VSLENGTH)
1095 putc('#', fp);
1096
1097 while (*p != '=') {
1098 putc(*p, fp);
1099 p++;
1100 }
1101
1102 if (subtype & VSNUL)
1103 putc(':', fp);
1104
1105 switch (subtype & VSTYPE) {
1106 case VSNORMAL:
1107 putc('}', fp);
1108 break;
1109 case VSMINUS:
1110 putc('-', fp);
1111 break;
1112 case VSPLUS:
1113 putc('+', fp);
1114 break;
1115 case VSQUESTION:
1116 putc('?', fp);
1117 break;
1118 case VSASSIGN:
1119 putc('=', fp);
1120 break;
1121 case VSTRIMLEFT:
1122 putc('#', fp);
1123 break;
1124 case VSTRIMLEFTMAX:
1125 putc('#', fp);
1126 putc('#', fp);
1127 break;
1128 case VSTRIMRIGHT:
1129 putc('%', fp);
1130 break;
1131 case VSTRIMRIGHTMAX:
1132 putc('%', fp);
1133 putc('%', fp);
1134 break;
1135 case VSLENGTH:
1136 break;
1137 default:
1138 out1fmt("<subtype %d>", subtype);
1139 }
1140 break;
1141 case CTLENDVAR:
1142 putc('}', fp);
1143 break;
1144 case CTLBACKQ:
1145 putc('$', fp);
1146 putc('(', fp);
1147 shtree(bqlist->n, -1, NULL, fp);
1148 putc(')', fp);
1149 break;
1150 default:
1151 putc(*p, fp);
1152 break;
1153 }
1154 }
1155}
1156
1157static void
1158shcmd(union node *cmd, FILE *fp)
1159{
1160 union node *np;
1161 int first;
1162 const char *s;
1163 int dftfd;
1164
1165 first = 1;
1166 for (np = cmd->ncmd.args; np; np = np->narg.next) {
1167 if (!first)
1168 putc(' ', fp);
1169 sharg(np, fp);
1170 first = 0;
1171 }
1172 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1173 if (!first)
1174 putc(' ', fp);
1175 dftfd = 0;
1176 switch (np->nfile.type) {
1177 case NTO: s = ">>"+1; dftfd = 1; break;
1178 case NCLOBBER: s = ">|"; dftfd = 1; break;
1179 case NAPPEND: s = ">>"; dftfd = 1; break;
1180#if BASH_REDIR_OUTPUT
1181 case NTO2:
1182#endif
1183 case NTOFD: s = ">&"; dftfd = 1; break;
1184 case NFROM: s = "<"; break;
1185 case NFROMFD: s = "<&"; break;
1186 case NFROMTO: s = "<>"; break;
1187 default: s = "*error*"; break;
1188 }
1189 if (np->nfile.fd != dftfd)
1190 fprintf(fp, "%d", np->nfile.fd);
1191 fputs(s, fp);
1192 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1193 fprintf(fp, "%d", np->ndup.dupfd);
1194 } else {
1195 sharg(np->nfile.fname, fp);
1196 }
1197 first = 0;
1198 }
1199}
1200
1201static void
1202shtree(union node *n, int ind, char *pfx, FILE *fp)
1203{
1204 struct nodelist *lp;
1205 const char *s;
1206
1207 if (n == NULL)
1208 return;
1209
1210 indent(ind, pfx, fp);
1211
1212 if (n == NODE_EOF) {
1213 fputs("<EOF>", fp);
1214 return;
1215 }
1216
1217 switch (n->type) {
1218 case NSEMI:
1219 s = "; ";
1220 goto binop;
1221 case NAND:
1222 s = " && ";
1223 goto binop;
1224 case NOR:
1225 s = " || ";
1226 binop:
1227 shtree(n->nbinary.ch1, ind, NULL, fp);
1228
1229 fputs(s, fp);
1230 shtree(n->nbinary.ch2, ind, NULL, fp);
1231 break;
1232 case NCMD:
1233 shcmd(n, fp);
1234 if (ind >= 0)
1235 putc('\n', fp);
1236 break;
1237 case NPIPE:
1238 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1239 shtree(lp->n, 0, NULL, fp);
1240 if (lp->next)
1241 fputs(" | ", fp);
1242 }
1243 if (n->npipe.pipe_backgnd)
1244 fputs(" &", fp);
1245 if (ind >= 0)
1246 putc('\n', fp);
1247 break;
1248 default:
1249 fprintf(fp, "<node type %d>", n->type);
1250 if (ind >= 0)
1251 putc('\n', fp);
1252 break;
1253 }
1254}
1255
1256static void
1257showtree(union node *n)
1258{
1259 trace_puts("showtree called\n");
1260 shtree(n, 1, NULL, stderr);
1261}
1262
1263#endif
1264
1265
1266
1267
1268
1269
1270
1271struct strlist {
1272 struct strlist *next;
1273 char *text;
1274};
1275
1276struct alias;
1277
1278struct strpush {
1279 struct strpush *prev;
1280 char *prev_string;
1281 int prev_left_in_line;
1282#if ENABLE_ASH_ALIAS
1283 struct alias *ap;
1284#endif
1285 char *string;
1286
1287
1288 int lastc[2];
1289
1290
1291 int unget;
1292};
1293
1294
1295
1296
1297
1298struct parsefile {
1299 struct parsefile *prev;
1300 int linno;
1301 int pf_fd;
1302 int left_in_line;
1303 int left_in_buffer;
1304 char *next_to_pgetc;
1305 char *buf;
1306 struct strpush *strpush;
1307 struct strpush basestrpush;
1308
1309
1310 int lastc[2];
1311
1312
1313 int unget;
1314};
1315
1316static struct parsefile basepf;
1317static struct parsefile *g_parsefile = &basepf;
1318static char *commandname;
1319
1320
1321
1322
1323static void
1324ash_vmsg(const char *msg, va_list ap)
1325{
1326 fprintf(stderr, "%s: ", arg0);
1327 if (commandname) {
1328 if (strcmp(arg0, commandname))
1329 fprintf(stderr, "%s: ", commandname);
1330 if (!iflag || g_parsefile->pf_fd > 0)
1331 fprintf(stderr, "line %d: ", errlinno);
1332 }
1333 vfprintf(stderr, msg, ap);
1334 newline_and_flush(stderr);
1335}
1336
1337
1338
1339
1340
1341
1342static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1343static void
1344ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1345{
1346#if DEBUG
1347 if (msg) {
1348 TRACE(("ash_vmsg_and_raise(%d):", cond));
1349 TRACEV((msg, ap));
1350 } else
1351 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1352 if (msg)
1353#endif
1354 ash_vmsg(msg, ap);
1355
1356 flush_stdout_stderr();
1357 raise_exception(cond);
1358
1359}
1360
1361static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1362static void
1363ash_msg_and_raise_error(const char *msg, ...)
1364{
1365 va_list ap;
1366
1367 exitstatus = 2;
1368
1369 va_start(ap, msg);
1370 ash_vmsg_and_raise(EXERROR, msg, ap);
1371
1372 va_end(ap);
1373}
1374
1375
1376
1377
1378#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
1379
1380static void raise_error_syntax(const char *) NORETURN;
1381static void
1382raise_error_syntax(const char *msg)
1383{
1384 errlinno = g_parsefile->linno;
1385 ash_msg_and_raise_error("syntax error: %s", msg);
1386
1387}
1388
1389static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1390static void
1391ash_msg_and_raise(int cond, const char *msg, ...)
1392{
1393 va_list ap;
1394
1395 va_start(ap, msg);
1396 ash_vmsg_and_raise(cond, msg, ap);
1397
1398 va_end(ap);
1399}
1400
1401
1402
1403
1404static void
1405ash_msg(const char *fmt, ...)
1406{
1407 va_list ap;
1408
1409 va_start(ap, fmt);
1410 ash_vmsg(fmt, ap);
1411 va_end(ap);
1412}
1413
1414
1415
1416
1417
1418
1419static const char *
1420errmsg(int e, const char *em)
1421{
1422 if (e == ENOENT || e == ENOTDIR) {
1423 return em;
1424 }
1425 return strerror(e);
1426}
1427
1428
1429
1430
1431#if 0
1432
1433
1434
1435
1436
1437static void *
1438ckrealloc(void * p, size_t nbytes)
1439{
1440 p = realloc(p, nbytes);
1441 if (!p)
1442 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1443 return p;
1444}
1445
1446static void *
1447ckmalloc(size_t nbytes)
1448{
1449 return ckrealloc(NULL, nbytes);
1450}
1451
1452static void *
1453ckzalloc(size_t nbytes)
1454{
1455 return memset(ckmalloc(nbytes), 0, nbytes);
1456}
1457
1458static char *
1459ckstrdup(const char *s)
1460{
1461 char *p = strdup(s);
1462 if (!p)
1463 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1464 return p;
1465}
1466#else
1467
1468# define ckrealloc xrealloc
1469# define ckmalloc xmalloc
1470# define ckzalloc xzalloc
1471# define ckstrdup xstrdup
1472#endif
1473
1474
1475
1476
1477
1478#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1479enum {
1480
1481
1482
1483 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1484
1485 MINSIZE = SHELL_ALIGN(504),
1486};
1487
1488struct stack_block {
1489 struct stack_block *prev;
1490 char space[MINSIZE];
1491};
1492
1493struct stackmark {
1494 struct stack_block *stackp;
1495 char *stacknxt;
1496 size_t stacknleft;
1497};
1498
1499
1500struct globals_memstack {
1501 struct stack_block *g_stackp;
1502 char *g_stacknxt;
1503 char *sstrend;
1504 size_t g_stacknleft;
1505 struct stack_block stackbase;
1506};
1507extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1508#define G_memstack (*ash_ptr_to_globals_memstack)
1509#define g_stackp (G_memstack.g_stackp )
1510#define g_stacknxt (G_memstack.g_stacknxt )
1511#define sstrend (G_memstack.sstrend )
1512#define g_stacknleft (G_memstack.g_stacknleft)
1513#define stackbase (G_memstack.stackbase )
1514#define INIT_G_memstack() do { \
1515 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1516 barrier(); \
1517 g_stackp = &stackbase; \
1518 g_stacknxt = stackbase.space; \
1519 g_stacknleft = MINSIZE; \
1520 sstrend = stackbase.space + MINSIZE; \
1521} while (0)
1522
1523
1524#define stackblock() ((void *)g_stacknxt)
1525#define stackblocksize() g_stacknleft
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535static void *
1536stalloc(size_t nbytes)
1537{
1538 char *p;
1539 size_t aligned;
1540
1541 aligned = SHELL_ALIGN(nbytes);
1542 if (aligned > g_stacknleft) {
1543 size_t len;
1544 size_t blocksize;
1545 struct stack_block *sp;
1546
1547 blocksize = aligned;
1548 if (blocksize < MINSIZE)
1549 blocksize = MINSIZE;
1550 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1551 if (len < blocksize)
1552 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1553 INT_OFF;
1554 sp = ckmalloc(len);
1555 sp->prev = g_stackp;
1556 g_stacknxt = sp->space;
1557 g_stacknleft = blocksize;
1558 sstrend = g_stacknxt + blocksize;
1559 g_stackp = sp;
1560 INT_ON;
1561 }
1562 p = g_stacknxt;
1563 g_stacknxt += aligned;
1564 g_stacknleft -= aligned;
1565 return p;
1566}
1567
1568static void *
1569stzalloc(size_t nbytes)
1570{
1571 return memset(stalloc(nbytes), 0, nbytes);
1572}
1573
1574static void
1575stunalloc(void *p)
1576{
1577#if DEBUG
1578 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1579 write(STDERR_FILENO, "stunalloc\n", 10);
1580 abort();
1581 }
1582#endif
1583 g_stacknleft += g_stacknxt - (char *)p;
1584 g_stacknxt = p;
1585}
1586
1587
1588
1589
1590static char *
1591sstrdup(const char *p)
1592{
1593 size_t len = strlen(p) + 1;
1594 return memcpy(stalloc(len), p, len);
1595}
1596
1597static ALWAYS_INLINE void
1598grabstackblock(size_t len)
1599{
1600 stalloc(len);
1601}
1602
1603static void
1604pushstackmark(struct stackmark *mark, size_t len)
1605{
1606 mark->stackp = g_stackp;
1607 mark->stacknxt = g_stacknxt;
1608 mark->stacknleft = g_stacknleft;
1609 grabstackblock(len);
1610}
1611
1612static void
1613setstackmark(struct stackmark *mark)
1614{
1615 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1616}
1617
1618static void
1619popstackmark(struct stackmark *mark)
1620{
1621 struct stack_block *sp;
1622
1623 if (!mark->stackp)
1624 return;
1625
1626 INT_OFF;
1627 while (g_stackp != mark->stackp) {
1628 sp = g_stackp;
1629 g_stackp = sp->prev;
1630 free(sp);
1631 }
1632 g_stacknxt = mark->stacknxt;
1633 g_stacknleft = mark->stacknleft;
1634 sstrend = mark->stacknxt + mark->stacknleft;
1635 INT_ON;
1636}
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647static void
1648growstackblock(void)
1649{
1650 size_t newlen;
1651
1652 newlen = g_stacknleft * 2;
1653 if (newlen < g_stacknleft)
1654 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1655 if (newlen < 128)
1656 newlen += 128;
1657
1658 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1659 struct stack_block *sp;
1660 struct stack_block *prevstackp;
1661 size_t grosslen;
1662
1663 INT_OFF;
1664 sp = g_stackp;
1665 prevstackp = sp->prev;
1666 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1667 sp = ckrealloc(sp, grosslen);
1668 sp->prev = prevstackp;
1669 g_stackp = sp;
1670 g_stacknxt = sp->space;
1671 g_stacknleft = newlen;
1672 sstrend = sp->space + newlen;
1673 INT_ON;
1674 } else {
1675 char *oldspace = g_stacknxt;
1676 size_t oldlen = g_stacknleft;
1677 char *p = stalloc(newlen);
1678
1679
1680 g_stacknxt = memcpy(p, oldspace, oldlen);
1681 g_stacknleft += newlen;
1682 }
1683}
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702static void *
1703growstackstr(void)
1704{
1705 size_t len = stackblocksize();
1706 growstackblock();
1707 return (char *)stackblock() + len;
1708}
1709
1710
1711
1712
1713static char *
1714makestrspace(size_t newlen, char *p)
1715{
1716 size_t len = p - g_stacknxt;
1717 size_t size;
1718
1719 for (;;) {
1720 size_t nleft;
1721
1722 size = stackblocksize();
1723 nleft = size - len;
1724 if (nleft >= newlen)
1725 break;
1726 growstackblock();
1727 }
1728 return (char *)stackblock() + len;
1729}
1730
1731static char *
1732stack_nputstr(const char *s, size_t n, char *p)
1733{
1734 p = makestrspace(n, p);
1735 p = (char *)mempcpy(p, s, n);
1736 return p;
1737}
1738
1739static char *
1740stack_putstr(const char *s, char *p)
1741{
1742 return stack_nputstr(s, strlen(s), p);
1743}
1744
1745static char *
1746_STPUTC(int c, char *p)
1747{
1748 if (p == sstrend)
1749 p = growstackstr();
1750 *p++ = c;
1751 return p;
1752}
1753
1754#define STARTSTACKSTR(p) ((p) = stackblock())
1755#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1756#define CHECKSTRSPACE(n, p) do { \
1757 char *q = (p); \
1758 size_t l = (n); \
1759 size_t m = sstrend - q; \
1760 if (l > m) \
1761 (p) = makestrspace(l, q); \
1762} while (0)
1763#define USTPUTC(c, p) (*(p)++ = (c))
1764#define STACKSTRNUL(p) do { \
1765 if ((p) == sstrend) \
1766 (p) = growstackstr(); \
1767 *(p) = '\0'; \
1768} while (0)
1769#define STUNPUTC(p) (--(p))
1770#define STTOPC(p) ((p)[-1])
1771#define STADJUST(amount, p) ((p) += (amount))
1772
1773#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1774#define ungrabstackstr(s, p) stunalloc(s)
1775#define stackstrend() ((void *)sstrend)
1776
1777
1778
1779
1780
1781
1782
1783static char *
1784prefix(const char *string, const char *pfx)
1785{
1786 while (*pfx) {
1787 if (*pfx++ != *string++)
1788 return NULL;
1789 }
1790 return (char *) string;
1791}
1792
1793
1794
1795
1796static int
1797is_number(const char *p)
1798{
1799 do {
1800 if (!isdigit(*p))
1801 return 0;
1802 } while (*++p != '\0');
1803 return 1;
1804}
1805
1806
1807
1808
1809
1810static int
1811number(const char *s)
1812{
1813 if (!is_number(s))
1814 ash_msg_and_raise_error(msg_illnum, s);
1815 return atoi(s);
1816}
1817
1818
1819
1820
1821
1822static char *
1823single_quote(const char *s)
1824{
1825 char *p;
1826
1827 STARTSTACKSTR(p);
1828
1829 do {
1830 char *q;
1831 size_t len;
1832
1833 len = strchrnul(s, '\'') - s;
1834
1835 q = p = makestrspace(len + 3, p);
1836
1837 *q++ = '\'';
1838 q = (char *)mempcpy(q, s, len);
1839 *q++ = '\'';
1840 s += len;
1841
1842 STADJUST(q - p, p);
1843
1844 if (*s != '\'')
1845 break;
1846 len = 0;
1847 do len++; while (*++s == '\'');
1848
1849 q = p = makestrspace(len + 3, p);
1850
1851 *q++ = '"';
1852 q = (char *)mempcpy(q, s - len, len);
1853 *q++ = '"';
1854
1855 STADJUST(q - p, p);
1856 } while (*s);
1857
1858 USTPUTC('\0', p);
1859
1860 return stackblock();
1861}
1862
1863
1864
1865
1866
1867
1868static const char *
1869maybe_single_quote(const char *s)
1870{
1871 const char *p = s;
1872
1873 while (*p) {
1874
1875
1876 if (*p < '+')
1877 goto need_quoting;
1878
1879 if (*p >= ';' && *p <= '?')
1880 goto need_quoting;
1881
1882 if (*p == '`')
1883 goto need_quoting;
1884 if (*p == '[')
1885 goto need_quoting;
1886 if (*p == '\\')
1887 goto need_quoting;
1888
1889 if (*p > 'z')
1890 goto need_quoting;
1891
1892
1893 p++;
1894 }
1895 return s;
1896
1897 need_quoting:
1898 return single_quote(s);
1899}
1900
1901
1902
1903
1904static char **argptr;
1905static char *optionarg;
1906static char *optptr;
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918static int
1919nextopt(const char *optstring)
1920{
1921 char *p;
1922 const char *q;
1923 char c;
1924
1925 p = optptr;
1926 if (p == NULL || *p == '\0') {
1927
1928 p = *argptr;
1929 if (p == NULL)
1930 return '\0';
1931 if (*p != '-')
1932 return '\0';
1933 if (*++p == '\0')
1934 return '\0';
1935 argptr++;
1936 if (LONE_DASH(p))
1937 return '\0';
1938
1939 }
1940
1941 c = *p++;
1942 for (q = optstring; *q != c;) {
1943 if (*q == '\0')
1944 ash_msg_and_raise_error("illegal option -%c", c);
1945 if (*++q == ':')
1946 q++;
1947 }
1948 if (*++q == ':') {
1949 if (*p == '\0') {
1950 p = *argptr++;
1951 if (p == NULL)
1952 ash_msg_and_raise_error("no arg for -%c option", c);
1953 }
1954 optionarg = p;
1955 p = NULL;
1956 }
1957 optptr = p;
1958 return c;
1959}
1960
1961
1962
1963
1964struct shparam {
1965 int nparam;
1966#if ENABLE_ASH_GETOPTS
1967 int optind;
1968 int optoff;
1969#endif
1970 unsigned char malloced;
1971 char **p;
1972};
1973
1974
1975
1976
1977static void
1978freeparam(volatile struct shparam *param)
1979{
1980 if (param->malloced) {
1981 char **ap, **ap1;
1982 ap = ap1 = param->p;
1983 while (*ap)
1984 free(*ap++);
1985 free(ap1);
1986 }
1987}
1988
1989#if ENABLE_ASH_GETOPTS
1990static void FAST_FUNC getoptsreset(const char *value);
1991#endif
1992
1993struct var {
1994 struct var *next;
1995 int flags;
1996 const char *var_text;
1997 void (*var_func)(const char *) FAST_FUNC;
1998
1999};
2000
2001struct localvar {
2002 struct localvar *next;
2003 struct var *vp;
2004 int flags;
2005 const char *text;
2006};
2007
2008
2009#define VEXPORT 0x01
2010#define VREADONLY 0x02
2011#define VSTRFIXED 0x04
2012#define VTEXTFIXED 0x08
2013#define VSTACK 0x10
2014#define VUNSET 0x20
2015#define VNOFUNC 0x40
2016#define VNOSET 0x80
2017#define VNOSAVE 0x100
2018#if ENABLE_ASH_RANDOM_SUPPORT
2019# define VDYNAMIC 0x200
2020#else
2021# define VDYNAMIC 0
2022#endif
2023
2024
2025
2026#if ENABLE_LOCALE_SUPPORT
2027static void FAST_FUNC
2028change_lc_all(const char *value)
2029{
2030 if (value && *value != '\0')
2031 setlocale(LC_ALL, value);
2032}
2033static void FAST_FUNC
2034change_lc_ctype(const char *value)
2035{
2036 if (value && *value != '\0')
2037 setlocale(LC_CTYPE, value);
2038}
2039#endif
2040#if ENABLE_ASH_MAIL
2041static void chkmail(void);
2042static void changemail(const char *var_value) FAST_FUNC;
2043#else
2044# define chkmail() ((void)0)
2045#endif
2046static void changepath(const char *) FAST_FUNC;
2047#if ENABLE_ASH_RANDOM_SUPPORT
2048static void change_random(const char *) FAST_FUNC;
2049#endif
2050
2051static const struct {
2052 int flags;
2053 const char *var_text;
2054 void (*var_func)(const char *) FAST_FUNC;
2055} varinit_data[] = {
2056
2057
2058
2059
2060 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
2061#if ENABLE_ASH_MAIL
2062 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2063 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
2064#endif
2065 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2066 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2067 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2068 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
2069#if ENABLE_ASH_GETOPTS
2070 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
2071#endif
2072 { VSTRFIXED|VTEXTFIXED , NULL , NULL },
2073#if ENABLE_ASH_RANDOM_SUPPORT
2074 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2075#endif
2076#if ENABLE_LOCALE_SUPPORT
2077 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2078 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
2079#endif
2080#if ENABLE_FEATURE_EDITING_SAVEHISTORY
2081 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
2082#endif
2083};
2084
2085struct redirtab;
2086
2087struct globals_var {
2088 struct shparam shellparam;
2089 struct redirtab *redirlist;
2090 int preverrout_fd;
2091 struct var *vartab[VTABSIZE];
2092 struct var varinit[ARRAY_SIZE(varinit_data)];
2093 int lineno;
2094 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2095};
2096extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2097#define G_var (*ash_ptr_to_globals_var)
2098#define shellparam (G_var.shellparam )
2099
2100#define preverrout_fd (G_var.preverrout_fd)
2101#define vartab (G_var.vartab )
2102#define varinit (G_var.varinit )
2103#define lineno (G_var.lineno )
2104#define linenovar (G_var.linenovar )
2105#define vifs varinit[0]
2106#if ENABLE_ASH_MAIL
2107# define vmail (&vifs)[1]
2108# define vmpath (&vmail)[1]
2109# define vpath (&vmpath)[1]
2110#else
2111# define vpath (&vifs)[1]
2112#endif
2113#define vps1 (&vpath)[1]
2114#define vps2 (&vps1)[1]
2115#define vps4 (&vps2)[1]
2116#if ENABLE_ASH_GETOPTS
2117# define voptind (&vps4)[1]
2118# define vlineno (&voptind)[1]
2119# if ENABLE_ASH_RANDOM_SUPPORT
2120# define vrandom (&vlineno)[1]
2121# endif
2122#else
2123# define vlineno (&vps4)[1]
2124# if ENABLE_ASH_RANDOM_SUPPORT
2125# define vrandom (&vlineno)[1]
2126# endif
2127#endif
2128#define INIT_G_var() do { \
2129 unsigned i; \
2130 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2131 barrier(); \
2132 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2133 varinit[i].flags = varinit_data[i].flags; \
2134 varinit[i].var_text = varinit_data[i].var_text; \
2135 varinit[i].var_func = varinit_data[i].var_func; \
2136 } \
2137 strcpy(linenovar, "LINENO="); \
2138 vlineno.var_text = linenovar; \
2139} while (0)
2140
2141
2142
2143
2144
2145
2146#define ifsval() (vifs.var_text + 4)
2147#define ifsset() ((vifs.flags & VUNSET) == 0)
2148#if ENABLE_ASH_MAIL
2149# define mailval() (vmail.var_text + 5)
2150# define mpathval() (vmpath.var_text + 9)
2151# define mpathset() ((vmpath.flags & VUNSET) == 0)
2152#endif
2153#define pathval() (vpath.var_text + 5)
2154#define ps1val() (vps1.var_text + 4)
2155#define ps2val() (vps2.var_text + 4)
2156#define ps4val() (vps4.var_text + 4)
2157#if ENABLE_ASH_GETOPTS
2158# define optindval() (voptind.var_text + 7)
2159#endif
2160
2161#if ENABLE_ASH_GETOPTS
2162static void FAST_FUNC
2163getoptsreset(const char *value)
2164{
2165 shellparam.optind = 1;
2166 if (is_number(value))
2167 shellparam.optind = number(value) ?: 1;
2168 shellparam.optoff = -1;
2169}
2170#endif
2171
2172
2173
2174
2175
2176
2177static int
2178varcmp(const char *p, const char *q)
2179{
2180 int c, d;
2181
2182 while ((c = *p) == (d = *q)) {
2183 if (c == '\0' || c == '=')
2184 goto out;
2185 p++;
2186 q++;
2187 }
2188 if (c == '=')
2189 c = '\0';
2190 if (d == '=')
2191 d = '\0';
2192 out:
2193 return c - d;
2194}
2195
2196
2197
2198
2199static struct var **
2200hashvar(const char *p)
2201{
2202 unsigned hashval;
2203
2204 hashval = ((unsigned char) *p) << 4;
2205 while (*p && *p != '=')
2206 hashval += (unsigned char) *p++;
2207 return &vartab[hashval % VTABSIZE];
2208}
2209
2210static int
2211vpcmp(const void *a, const void *b)
2212{
2213 return varcmp(*(const char **)a, *(const char **)b);
2214}
2215
2216
2217
2218
2219static void
2220initvar(void)
2221{
2222 struct var *vp;
2223 struct var *end;
2224 struct var **vpp;
2225
2226
2227
2228
2229#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2230 vps1.var_text = "PS1=\\w \\$ ";
2231#else
2232 if (!geteuid())
2233 vps1.var_text = "PS1=# ";
2234#endif
2235 vp = varinit;
2236 end = vp + ARRAY_SIZE(varinit);
2237 do {
2238 vpp = hashvar(vp->var_text);
2239 vp->next = *vpp;
2240 *vpp = vp;
2241 } while (++vp < end);
2242}
2243
2244static struct var **
2245findvar(struct var **vpp, const char *name)
2246{
2247 for (; *vpp; vpp = &(*vpp)->next) {
2248 if (varcmp((*vpp)->var_text, name) == 0) {
2249 break;
2250 }
2251 }
2252 return vpp;
2253}
2254
2255
2256
2257
2258static const char* FAST_FUNC
2259lookupvar(const char *name)
2260{
2261 struct var *v;
2262
2263 v = *findvar(hashvar(name), name);
2264 if (v) {
2265#if ENABLE_ASH_RANDOM_SUPPORT
2266
2267
2268
2269
2270
2271
2272 if (v->flags & VDYNAMIC)
2273 v->var_func(NULL);
2274#endif
2275 if (!(v->flags & VUNSET)) {
2276 if (v == &vlineno && v->var_text == linenovar) {
2277 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2278 }
2279 return var_end(v->var_text);
2280 }
2281 }
2282 return NULL;
2283}
2284
2285#if ENABLE_UNICODE_SUPPORT
2286static void
2287reinit_unicode_for_ash(void)
2288{
2289
2290
2291
2292
2293 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2294 || ENABLE_UNICODE_USING_LOCALE
2295 ) {
2296 const char *s = lookupvar("LC_ALL");
2297 if (!s) s = lookupvar("LC_CTYPE");
2298 if (!s) s = lookupvar("LANG");
2299 reinit_unicode(s);
2300 }
2301}
2302#else
2303# define reinit_unicode_for_ash() ((void)0)
2304#endif
2305
2306
2307
2308
2309static ALWAYS_INLINE const char *
2310bltinlookup(const char *name)
2311{
2312 return lookupvar(name);
2313}
2314
2315
2316
2317
2318
2319
2320
2321
2322static struct var *
2323setvareq(char *s, int flags)
2324{
2325 struct var *vp, **vpp;
2326
2327 vpp = hashvar(s);
2328 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2329 vpp = findvar(vpp, s);
2330 vp = *vpp;
2331 if (vp) {
2332 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2333 const char *n;
2334
2335 if (flags & VNOSAVE)
2336 free(s);
2337 n = vp->var_text;
2338 exitstatus = 1;
2339 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2340 }
2341
2342 if (flags & VNOSET)
2343 goto out;
2344
2345 if (vp->var_func && !(flags & VNOFUNC))
2346 vp->var_func(var_end(s));
2347
2348 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2349 free((char*)vp->var_text);
2350
2351 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2352 *vpp = vp->next;
2353 free(vp);
2354 out_free:
2355 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2356 free(s);
2357 goto out;
2358 }
2359
2360 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2361 } else {
2362
2363 if (flags & VNOSET)
2364 goto out;
2365 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2366 goto out_free;
2367 vp = ckzalloc(sizeof(*vp));
2368 vp->next = *vpp;
2369
2370 *vpp = vp;
2371 }
2372 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2373 s = ckstrdup(s);
2374 vp->var_text = s;
2375 vp->flags = flags;
2376
2377 out:
2378 return vp;
2379}
2380
2381
2382
2383
2384
2385static struct var *
2386setvar(const char *name, const char *val, int flags)
2387{
2388 const char *q;
2389 char *p;
2390 char *nameeq;
2391 size_t namelen;
2392 size_t vallen;
2393 struct var *vp;
2394
2395 q = endofname(name);
2396 p = strchrnul(q, '=');
2397 namelen = p - name;
2398 if (!namelen || p != q)
2399 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2400 vallen = 0;
2401 if (val == NULL) {
2402 flags |= VUNSET;
2403 } else {
2404 vallen = strlen(val);
2405 }
2406
2407 INT_OFF;
2408 nameeq = ckmalloc(namelen + vallen + 2);
2409 p = mempcpy(nameeq, name, namelen);
2410 if (val) {
2411 *p++ = '=';
2412 p = mempcpy(p, val, vallen);
2413 }
2414 *p = '\0';
2415 vp = setvareq(nameeq, flags | VNOSAVE);
2416 INT_ON;
2417
2418 return vp;
2419}
2420
2421static void FAST_FUNC
2422setvar0(const char *name, const char *val)
2423{
2424 setvar(name, val, 0);
2425}
2426
2427
2428
2429
2430static void
2431unsetvar(const char *s)
2432{
2433 setvar(s, NULL, 0);
2434}
2435
2436
2437
2438
2439static void
2440listsetvar(struct strlist *list_set_var, int flags)
2441{
2442 struct strlist *lp = list_set_var;
2443
2444 if (!lp)
2445 return;
2446 INT_OFF;
2447 do {
2448 setvareq(lp->text, flags);
2449 lp = lp->next;
2450 } while (lp);
2451 INT_ON;
2452}
2453
2454
2455
2456
2457#if !ENABLE_FEATURE_SH_NOFORK
2458# define listvars(on, off, lp, end) listvars(on, off, end)
2459#endif
2460static char **
2461listvars(int on, int off, struct strlist *lp, char ***end)
2462{
2463 struct var **vpp;
2464 struct var *vp;
2465 char **ep;
2466 int mask;
2467
2468 STARTSTACKSTR(ep);
2469 vpp = vartab;
2470 mask = on | off;
2471 do {
2472 for (vp = *vpp; vp; vp = vp->next) {
2473 if ((vp->flags & mask) == on) {
2474#if ENABLE_FEATURE_SH_NOFORK
2475
2476
2477
2478
2479
2480
2481
2482 struct strlist *lp1 = lp;
2483 while (lp1) {
2484 if (strcmp(lp1->text, vp->var_text) == 0)
2485 goto skip;
2486 lp1 = lp1->next;
2487 }
2488#endif
2489 if (ep == stackstrend())
2490 ep = growstackstr();
2491 *ep++ = (char*)vp->var_text;
2492#if ENABLE_FEATURE_SH_NOFORK
2493 skip: ;
2494#endif
2495 }
2496 }
2497 } while (++vpp < vartab + VTABSIZE);
2498
2499#if ENABLE_FEATURE_SH_NOFORK
2500 while (lp) {
2501 if (ep == stackstrend())
2502 ep = growstackstr();
2503 *ep++ = lp->text;
2504 lp = lp->next;
2505 }
2506#endif
2507
2508 if (ep == stackstrend())
2509 ep = growstackstr();
2510 if (end)
2511 *end = ep;
2512 *ep++ = NULL;
2513 return grabstackstr(ep);
2514}
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527static const char *pathopt;
2528
2529static char *
2530path_advance(const char **path, const char *name)
2531{
2532 const char *p;
2533 char *q;
2534 const char *start;
2535 size_t len;
2536
2537 if (*path == NULL)
2538 return NULL;
2539 start = *path;
2540 for (p = start; *p && *p != ':' && *p != '%'; p++)
2541 continue;
2542 len = p - start + strlen(name) + 2;
2543 while (stackblocksize() < len)
2544 growstackblock();
2545 q = stackblock();
2546 if (p != start) {
2547 q = mempcpy(q, start, p - start);
2548 *q++ = '/';
2549 }
2550 strcpy(q, name);
2551 pathopt = NULL;
2552 if (*p == '%') {
2553 pathopt = ++p;
2554 while (*p && *p != ':')
2555 p++;
2556 }
2557 if (*p == ':')
2558 *path = p + 1;
2559 else
2560 *path = NULL;
2561 return stalloc(len);
2562}
2563
2564
2565
2566
2567static smallint doprompt;
2568static smallint needprompt;
2569
2570#if ENABLE_FEATURE_EDITING
2571static line_input_t *line_input_state;
2572static const char *cmdedit_prompt;
2573static void
2574putprompt(const char *s)
2575{
2576 if (ENABLE_ASH_EXPAND_PRMT) {
2577 free((char*)cmdedit_prompt);
2578 cmdedit_prompt = ckstrdup(s);
2579 return;
2580 }
2581 cmdedit_prompt = s;
2582}
2583#else
2584static void
2585putprompt(const char *s)
2586{
2587 out2str(s);
2588}
2589#endif
2590
2591
2592static const char *expandstr(const char *ps, int syntax_type);
2593
2594#define BASESYNTAX 0
2595#define DQSYNTAX 1
2596#define SQSYNTAX 2
2597#define ARISYNTAX 3
2598#if ENABLE_ASH_EXPAND_PRMT
2599# define PSSYNTAX 4
2600#endif
2601
2602
2603
2604
2605
2606static void
2607setprompt_if(smallint do_set, int whichprompt)
2608{
2609 const char *prompt;
2610 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2611
2612 if (!do_set)
2613 return;
2614
2615 needprompt = 0;
2616
2617 switch (whichprompt) {
2618 case 1:
2619 prompt = ps1val();
2620 break;
2621 case 2:
2622 prompt = ps2val();
2623 break;
2624 default:
2625 prompt = nullstr;
2626 }
2627#if ENABLE_ASH_EXPAND_PRMT
2628 pushstackmark(&smark, stackblocksize());
2629 putprompt(expandstr(prompt, PSSYNTAX));
2630 popstackmark(&smark);
2631#else
2632 putprompt(prompt);
2633#endif
2634}
2635
2636
2637
2638
2639#define CD_PHYSICAL 1
2640#define CD_PRINT 2
2641
2642static int
2643cdopt(void)
2644{
2645 int flags = 0;
2646 int i, j;
2647
2648 j = 'L';
2649 while ((i = nextopt("LP")) != '\0') {
2650 if (i != j) {
2651 flags ^= CD_PHYSICAL;
2652 j = i;
2653 }
2654 }
2655
2656 return flags;
2657}
2658
2659
2660
2661
2662
2663static const char *
2664updatepwd(const char *dir)
2665{
2666 char *new;
2667 char *p;
2668 char *cdcomppath;
2669 const char *lim;
2670
2671 cdcomppath = sstrdup(dir);
2672 STARTSTACKSTR(new);
2673 if (*dir != '/') {
2674 if (curdir == nullstr)
2675 return 0;
2676 new = stack_putstr(curdir, new);
2677 }
2678 new = makestrspace(strlen(dir) + 2, new);
2679 lim = (char *)stackblock() + 1;
2680 if (*dir != '/') {
2681 if (new[-1] != '/')
2682 USTPUTC('/', new);
2683 if (new > lim && *lim == '/')
2684 lim++;
2685 } else {
2686 USTPUTC('/', new);
2687 cdcomppath++;
2688 if (dir[1] == '/' && dir[2] != '/') {
2689 USTPUTC('/', new);
2690 cdcomppath++;
2691 lim++;
2692 }
2693 }
2694 p = strtok(cdcomppath, "/");
2695 while (p) {
2696 switch (*p) {
2697 case '.':
2698 if (p[1] == '.' && p[2] == '\0') {
2699 while (new > lim) {
2700 STUNPUTC(new);
2701 if (new[-1] == '/')
2702 break;
2703 }
2704 break;
2705 }
2706 if (p[1] == '\0')
2707 break;
2708
2709 default:
2710 new = stack_putstr(p, new);
2711 USTPUTC('/', new);
2712 }
2713 p = strtok(NULL, "/");
2714 }
2715 if (new > lim)
2716 STUNPUTC(new);
2717 *new = 0;
2718 return stackblock();
2719}
2720
2721
2722
2723
2724
2725static char *
2726getpwd(void)
2727{
2728 char *dir = getcwd(NULL, 0);
2729 return dir ? dir : nullstr;
2730}
2731
2732static void
2733setpwd(const char *val, int setold)
2734{
2735 char *oldcur, *dir;
2736
2737 oldcur = dir = curdir;
2738
2739 if (setold) {
2740 setvar("OLDPWD", oldcur, VEXPORT);
2741 }
2742 INT_OFF;
2743 if (physdir != nullstr) {
2744 if (physdir != oldcur)
2745 free(physdir);
2746 physdir = nullstr;
2747 }
2748 if (oldcur == val || !val) {
2749 char *s = getpwd();
2750 physdir = s;
2751 if (!val)
2752 dir = s;
2753 } else
2754 dir = ckstrdup(val);
2755 if (oldcur != dir && oldcur != nullstr) {
2756 free(oldcur);
2757 }
2758 curdir = dir;
2759 INT_ON;
2760 setvar("PWD", dir, VEXPORT);
2761}
2762
2763static void hashcd(void);
2764
2765
2766
2767
2768
2769static int
2770docd(const char *dest, int flags)
2771{
2772 const char *dir = NULL;
2773 int err;
2774
2775 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2776
2777 INT_OFF;
2778 if (!(flags & CD_PHYSICAL)) {
2779 dir = updatepwd(dest);
2780 if (dir)
2781 dest = dir;
2782 }
2783 err = chdir(dest);
2784 if (err)
2785 goto out;
2786 setpwd(dir, 1);
2787 hashcd();
2788 out:
2789 INT_ON;
2790 return err;
2791}
2792
2793static int FAST_FUNC
2794cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2795{
2796 const char *dest;
2797 const char *path;
2798 const char *p;
2799 char c;
2800 struct stat statb;
2801 int flags;
2802
2803 flags = cdopt();
2804 dest = *argptr;
2805 if (!dest)
2806 dest = bltinlookup("HOME");
2807 else if (LONE_DASH(dest)) {
2808 dest = bltinlookup("OLDPWD");
2809 flags |= CD_PRINT;
2810 }
2811 if (!dest)
2812 dest = nullstr;
2813 if (*dest == '/')
2814 goto step6;
2815 if (*dest == '.') {
2816 c = dest[1];
2817 dotdot:
2818 switch (c) {
2819 case '\0':
2820 case '/':
2821 goto step6;
2822 case '.':
2823 c = dest[2];
2824 if (c != '.')
2825 goto dotdot;
2826 }
2827 }
2828 if (!*dest)
2829 dest = ".";
2830 path = bltinlookup("CDPATH");
2831 while (path) {
2832 c = *path;
2833 p = path_advance(&path, dest);
2834 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2835 if (c && c != ':')
2836 flags |= CD_PRINT;
2837 docd:
2838 if (!docd(p, flags))
2839 goto out;
2840 goto err;
2841 }
2842 }
2843
2844 step6:
2845 p = dest;
2846 goto docd;
2847
2848 err:
2849 ash_msg_and_raise_perror("can't cd to %s", dest);
2850
2851 out:
2852 if (flags & CD_PRINT)
2853 out1fmt("%s\n", curdir);
2854 return 0;
2855}
2856
2857static int FAST_FUNC
2858pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2859{
2860 int flags;
2861 const char *dir = curdir;
2862
2863 flags = cdopt();
2864 if (flags) {
2865 if (physdir == nullstr)
2866 setpwd(dir, 0);
2867 dir = physdir;
2868 }
2869 out1fmt("%s\n", dir);
2870 return 0;
2871}
2872
2873
2874
2875
2876
2877#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2878
2879
2880#define CWORD 0
2881#define CNL 1
2882#define CBACK 2
2883#define CSQUOTE 3
2884#define CDQUOTE 4
2885#define CENDQUOTE 5
2886#define CBQUOTE 6
2887#define CVAR 7
2888#define CENDVAR 8
2889#define CLP 9
2890#define CRP 10
2891#define CENDFILE 11
2892#define CCTL 12
2893#define CSPCL 13
2894#define CIGN 14
2895
2896#define PEOF 256
2897#if ENABLE_ASH_ALIAS
2898# define PEOA 257
2899#endif
2900
2901#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2902
2903#if ENABLE_FEATURE_SH_MATH
2904# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2905#else
2906# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2907#endif
2908static const uint16_t S_I_T[] ALIGN2 = {
2909#if ENABLE_ASH_ALIAS
2910 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ),
2911#endif
2912 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ),
2913 SIT_ITEM(CNL , CNL , CNL , CNL ),
2914 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ),
2915 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ),
2916 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ),
2917 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD),
2918 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ),
2919 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ),
2920 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ),
2921 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE),
2922 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR),
2923#if !USE_SIT_FUNCTION
2924 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),
2925 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ),
2926 SIT_ITEM(CCTL , CCTL , CCTL , CCTL )
2927#endif
2928#undef SIT_ITEM
2929};
2930
2931enum {
2932#if ENABLE_ASH_ALIAS
2933 CSPCL_CIGN_CIGN_CIGN ,
2934#endif
2935 CSPCL_CWORD_CWORD_CWORD ,
2936 CNL_CNL_CNL_CNL ,
2937 CWORD_CCTL_CCTL_CWORD ,
2938 CDQUOTE_CENDQUOTE_CWORD_CWORD ,
2939 CVAR_CVAR_CWORD_CVAR ,
2940 CSQUOTE_CWORD_CENDQUOTE_CWORD ,
2941 CSPCL_CWORD_CWORD_CLP ,
2942 CSPCL_CWORD_CWORD_CRP ,
2943 CBACK_CBACK_CCTL_CBACK ,
2944 CBQUOTE_CBQUOTE_CWORD_CBQUOTE ,
2945 CENDVAR_CENDVAR_CWORD_CENDVAR ,
2946 CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2947 CWORD_CWORD_CWORD_CWORD ,
2948 CCTL_CCTL_CCTL_CCTL ,
2949};
2950
2951
2952
2953
2954#if USE_SIT_FUNCTION
2955
2956static int
2957SIT(int c, int syntax)
2958{
2959
2960 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2961
2962
2963
2964
2965
2966
2967
2968
2969# if ENABLE_ASH_ALIAS
2970 static const uint8_t syntax_index_table[] ALIGN1 = {
2971 1, 2, 1, 3, 4, 5, 1, 6,
2972 7, 8, 3, 3,3, 1, 1,
2973 3, 1, 3, 3, 9, 3, 10, 1,
2974 11, 3
2975 };
2976# else
2977 static const uint8_t syntax_index_table[] ALIGN1 = {
2978 0, 1, 0, 2, 3, 4, 0, 5,
2979 6, 7, 2, 2,2, 0, 0,
2980 2, 0, 2, 2, 8, 2, 9, 0,
2981 10, 2
2982 };
2983# endif
2984 const char *s;
2985 int indx;
2986
2987 if (c == PEOF)
2988 return CENDFILE;
2989# if ENABLE_ASH_ALIAS
2990 if (c == PEOA)
2991 indx = 0;
2992 else
2993# endif
2994 {
2995
2996
2997 if ((unsigned char)c >= CTL_FIRST
2998 && (unsigned char)c <= CTL_LAST
2999 ) {
3000 return CCTL;
3001 }
3002 s = strchrnul(spec_symbls, c);
3003 if (*s == '\0')
3004 return CWORD;
3005 indx = syntax_index_table[s - spec_symbls];
3006 }
3007 return (S_I_T[indx] >> (syntax*4)) & 0xf;
3008}
3009
3010#else
3011
3012static const uint8_t syntax_index_table[] ALIGN1 = {
3013
3014 CWORD_CWORD_CWORD_CWORD,
3015 CWORD_CWORD_CWORD_CWORD,
3016 CWORD_CWORD_CWORD_CWORD,
3017 CWORD_CWORD_CWORD_CWORD,
3018 CWORD_CWORD_CWORD_CWORD,
3019 CWORD_CWORD_CWORD_CWORD,
3020 CWORD_CWORD_CWORD_CWORD,
3021 CWORD_CWORD_CWORD_CWORD,
3022 CWORD_CWORD_CWORD_CWORD,
3023 CSPCL_CWORD_CWORD_CWORD,
3024 CNL_CNL_CNL_CNL,
3025 CWORD_CWORD_CWORD_CWORD,
3026 CWORD_CWORD_CWORD_CWORD,
3027 CWORD_CWORD_CWORD_CWORD,
3028 CWORD_CWORD_CWORD_CWORD,
3029 CWORD_CWORD_CWORD_CWORD,
3030 CWORD_CWORD_CWORD_CWORD,
3031 CWORD_CWORD_CWORD_CWORD,
3032 CWORD_CWORD_CWORD_CWORD,
3033 CWORD_CWORD_CWORD_CWORD,
3034 CWORD_CWORD_CWORD_CWORD,
3035 CWORD_CWORD_CWORD_CWORD,
3036 CWORD_CWORD_CWORD_CWORD,
3037 CWORD_CWORD_CWORD_CWORD,
3038 CWORD_CWORD_CWORD_CWORD,
3039 CWORD_CWORD_CWORD_CWORD,
3040 CWORD_CWORD_CWORD_CWORD,
3041 CWORD_CWORD_CWORD_CWORD,
3042 CWORD_CWORD_CWORD_CWORD,
3043 CWORD_CWORD_CWORD_CWORD,
3044 CWORD_CWORD_CWORD_CWORD,
3045 CWORD_CWORD_CWORD_CWORD,
3046 CSPCL_CWORD_CWORD_CWORD,
3047 CWORD_CCTL_CCTL_CWORD,
3048 CDQUOTE_CENDQUOTE_CWORD_CWORD,
3049 CWORD_CWORD_CWORD_CWORD,
3050 CVAR_CVAR_CWORD_CVAR,
3051 CWORD_CWORD_CWORD_CWORD,
3052 CSPCL_CWORD_CWORD_CWORD,
3053 CSQUOTE_CWORD_CENDQUOTE_CWORD,
3054 CSPCL_CWORD_CWORD_CLP,
3055 CSPCL_CWORD_CWORD_CRP,
3056 CWORD_CCTL_CCTL_CWORD,
3057 CWORD_CWORD_CWORD_CWORD,
3058 CWORD_CWORD_CWORD_CWORD,
3059 CWORD_CCTL_CCTL_CWORD,
3060 CWORD_CWORD_CWORD_CWORD,
3061
3062 CWORD_CWORD_CWORD_CWORD,
3063 CWORD_CWORD_CWORD_CWORD,
3064 CWORD_CWORD_CWORD_CWORD,
3065 CWORD_CWORD_CWORD_CWORD,
3066 CWORD_CWORD_CWORD_CWORD,
3067 CWORD_CWORD_CWORD_CWORD,
3068 CWORD_CWORD_CWORD_CWORD,
3069 CWORD_CWORD_CWORD_CWORD,
3070 CWORD_CWORD_CWORD_CWORD,
3071 CWORD_CWORD_CWORD_CWORD,
3072 CWORD_CWORD_CWORD_CWORD,
3073 CWORD_CCTL_CCTL_CWORD,
3074 CSPCL_CWORD_CWORD_CWORD,
3075 CSPCL_CWORD_CWORD_CWORD,
3076 CWORD_CCTL_CCTL_CWORD,
3077 CSPCL_CWORD_CWORD_CWORD,
3078 CWORD_CCTL_CCTL_CWORD,
3079 CWORD_CWORD_CWORD_CWORD,
3080 CWORD_CWORD_CWORD_CWORD,
3081 CWORD_CWORD_CWORD_CWORD,
3082 CWORD_CWORD_CWORD_CWORD,
3083 CWORD_CWORD_CWORD_CWORD,
3084 CWORD_CWORD_CWORD_CWORD,
3085 CWORD_CWORD_CWORD_CWORD,
3086 CWORD_CWORD_CWORD_CWORD,
3087 CWORD_CWORD_CWORD_CWORD,
3088 CWORD_CWORD_CWORD_CWORD,
3089 CWORD_CWORD_CWORD_CWORD,
3090 CWORD_CWORD_CWORD_CWORD,
3091 CWORD_CWORD_CWORD_CWORD,
3092 CWORD_CWORD_CWORD_CWORD,
3093 CWORD_CWORD_CWORD_CWORD,
3094 CWORD_CWORD_CWORD_CWORD,
3095 CWORD_CWORD_CWORD_CWORD,
3096 CWORD_CWORD_CWORD_CWORD,
3097 CWORD_CWORD_CWORD_CWORD,
3098 CWORD_CWORD_CWORD_CWORD,
3099 CWORD_CWORD_CWORD_CWORD,
3100 CWORD_CWORD_CWORD_CWORD,
3101 CWORD_CWORD_CWORD_CWORD,
3102 CWORD_CWORD_CWORD_CWORD,
3103 CWORD_CWORD_CWORD_CWORD,
3104 CWORD_CWORD_CWORD_CWORD,
3105 CWORD_CWORD_CWORD_CWORD,
3106 CWORD_CCTL_CCTL_CWORD,
3107 CBACK_CBACK_CCTL_CBACK,
3108 CWORD_CCTL_CCTL_CWORD,
3109 CWORD_CWORD_CWORD_CWORD,
3110 CWORD_CWORD_CWORD_CWORD,
3111 CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3112 CWORD_CWORD_CWORD_CWORD,
3113 CWORD_CWORD_CWORD_CWORD,
3114 CWORD_CWORD_CWORD_CWORD,
3115 CWORD_CWORD_CWORD_CWORD,
3116 CWORD_CWORD_CWORD_CWORD,
3117 CWORD_CWORD_CWORD_CWORD,
3118 CWORD_CWORD_CWORD_CWORD,
3119 CWORD_CWORD_CWORD_CWORD,
3120 CWORD_CWORD_CWORD_CWORD,
3121 CWORD_CWORD_CWORD_CWORD,
3122 CWORD_CWORD_CWORD_CWORD,
3123 CWORD_CWORD_CWORD_CWORD,
3124 CWORD_CWORD_CWORD_CWORD,
3125 CWORD_CWORD_CWORD_CWORD,
3126 CWORD_CWORD_CWORD_CWORD,
3127 CWORD_CWORD_CWORD_CWORD,
3128 CWORD_CWORD_CWORD_CWORD,
3129 CWORD_CWORD_CWORD_CWORD,
3130 CWORD_CWORD_CWORD_CWORD,
3131 CWORD_CWORD_CWORD_CWORD,
3132 CWORD_CWORD_CWORD_CWORD,
3133 CWORD_CWORD_CWORD_CWORD,
3134 CWORD_CWORD_CWORD_CWORD,
3135 CWORD_CWORD_CWORD_CWORD,
3136 CWORD_CWORD_CWORD_CWORD,
3137 CWORD_CWORD_CWORD_CWORD,
3138 CWORD_CWORD_CWORD_CWORD,
3139 CSPCL_CWORD_CWORD_CWORD,
3140 CENDVAR_CENDVAR_CWORD_CENDVAR,
3141 CWORD_CCTL_CCTL_CWORD,
3142 CWORD_CWORD_CWORD_CWORD,
3143 CWORD_CWORD_CWORD_CWORD,
3144 CCTL_CCTL_CCTL_CCTL,
3145 CCTL_CCTL_CCTL_CCTL,
3146 CCTL_CCTL_CCTL_CCTL,
3147 CCTL_CCTL_CCTL_CCTL,
3148 CCTL_CCTL_CCTL_CCTL,
3149 CCTL_CCTL_CCTL_CCTL,
3150 CCTL_CCTL_CCTL_CCTL,
3151 CCTL_CCTL_CCTL_CCTL,
3152 CWORD_CWORD_CWORD_CWORD,
3153 CWORD_CWORD_CWORD_CWORD,
3154 CWORD_CWORD_CWORD_CWORD,
3155 CWORD_CWORD_CWORD_CWORD,
3156 CWORD_CWORD_CWORD_CWORD,
3157 CWORD_CWORD_CWORD_CWORD,
3158 CWORD_CWORD_CWORD_CWORD,
3159 CWORD_CWORD_CWORD_CWORD,
3160 CWORD_CWORD_CWORD_CWORD,
3161 CWORD_CWORD_CWORD_CWORD,
3162 CWORD_CWORD_CWORD_CWORD,
3163 CWORD_CWORD_CWORD_CWORD,
3164 CWORD_CWORD_CWORD_CWORD,
3165 CWORD_CWORD_CWORD_CWORD,
3166 CWORD_CWORD_CWORD_CWORD,
3167 CWORD_CWORD_CWORD_CWORD,
3168 CWORD_CWORD_CWORD_CWORD,
3169 CWORD_CWORD_CWORD_CWORD,
3170 CWORD_CWORD_CWORD_CWORD,
3171 CWORD_CWORD_CWORD_CWORD,
3172 CWORD_CWORD_CWORD_CWORD,
3173 CWORD_CWORD_CWORD_CWORD,
3174 CWORD_CWORD_CWORD_CWORD,
3175 CWORD_CWORD_CWORD_CWORD,
3176 CWORD_CWORD_CWORD_CWORD,
3177 CWORD_CWORD_CWORD_CWORD,
3178 CWORD_CWORD_CWORD_CWORD,
3179 CWORD_CWORD_CWORD_CWORD,
3180 CWORD_CWORD_CWORD_CWORD,
3181 CWORD_CWORD_CWORD_CWORD,
3182 CWORD_CWORD_CWORD_CWORD,
3183 CWORD_CWORD_CWORD_CWORD,
3184 CWORD_CWORD_CWORD_CWORD,
3185 CWORD_CWORD_CWORD_CWORD,
3186 CWORD_CWORD_CWORD_CWORD,
3187 CWORD_CWORD_CWORD_CWORD,
3188 CWORD_CWORD_CWORD_CWORD,
3189 CWORD_CWORD_CWORD_CWORD,
3190 CWORD_CWORD_CWORD_CWORD,
3191 CWORD_CWORD_CWORD_CWORD,
3192 CWORD_CWORD_CWORD_CWORD,
3193 CWORD_CWORD_CWORD_CWORD,
3194 CWORD_CWORD_CWORD_CWORD,
3195 CWORD_CWORD_CWORD_CWORD,
3196 CWORD_CWORD_CWORD_CWORD,
3197 CWORD_CWORD_CWORD_CWORD,
3198 CWORD_CWORD_CWORD_CWORD,
3199 CWORD_CWORD_CWORD_CWORD,
3200 CWORD_CWORD_CWORD_CWORD,
3201 CWORD_CWORD_CWORD_CWORD,
3202 CWORD_CWORD_CWORD_CWORD,
3203 CWORD_CWORD_CWORD_CWORD,
3204 CWORD_CWORD_CWORD_CWORD,
3205 CWORD_CWORD_CWORD_CWORD,
3206 CWORD_CWORD_CWORD_CWORD,
3207 CWORD_CWORD_CWORD_CWORD,
3208 CWORD_CWORD_CWORD_CWORD,
3209 CWORD_CWORD_CWORD_CWORD,
3210 CWORD_CWORD_CWORD_CWORD,
3211 CWORD_CWORD_CWORD_CWORD,
3212 CWORD_CWORD_CWORD_CWORD,
3213 CWORD_CWORD_CWORD_CWORD,
3214 CWORD_CWORD_CWORD_CWORD,
3215 CWORD_CWORD_CWORD_CWORD,
3216 CWORD_CWORD_CWORD_CWORD,
3217 CWORD_CWORD_CWORD_CWORD,
3218 CWORD_CWORD_CWORD_CWORD,
3219 CWORD_CWORD_CWORD_CWORD,
3220 CWORD_CWORD_CWORD_CWORD,
3221 CWORD_CWORD_CWORD_CWORD,
3222 CWORD_CWORD_CWORD_CWORD,
3223 CWORD_CWORD_CWORD_CWORD,
3224 CWORD_CWORD_CWORD_CWORD,
3225 CWORD_CWORD_CWORD_CWORD,
3226 CWORD_CWORD_CWORD_CWORD,
3227 CWORD_CWORD_CWORD_CWORD,
3228 CWORD_CWORD_CWORD_CWORD,
3229 CWORD_CWORD_CWORD_CWORD,
3230 CWORD_CWORD_CWORD_CWORD,
3231 CWORD_CWORD_CWORD_CWORD,
3232 CWORD_CWORD_CWORD_CWORD,
3233 CWORD_CWORD_CWORD_CWORD,
3234 CWORD_CWORD_CWORD_CWORD,
3235 CWORD_CWORD_CWORD_CWORD,
3236 CWORD_CWORD_CWORD_CWORD,
3237 CWORD_CWORD_CWORD_CWORD,
3238 CWORD_CWORD_CWORD_CWORD,
3239 CWORD_CWORD_CWORD_CWORD,
3240 CWORD_CWORD_CWORD_CWORD,
3241 CWORD_CWORD_CWORD_CWORD,
3242 CWORD_CWORD_CWORD_CWORD,
3243 CWORD_CWORD_CWORD_CWORD,
3244 CWORD_CWORD_CWORD_CWORD,
3245 CWORD_CWORD_CWORD_CWORD,
3246 CWORD_CWORD_CWORD_CWORD,
3247 CWORD_CWORD_CWORD_CWORD,
3248 CWORD_CWORD_CWORD_CWORD,
3249 CWORD_CWORD_CWORD_CWORD,
3250 CWORD_CWORD_CWORD_CWORD,
3251 CWORD_CWORD_CWORD_CWORD,
3252 CWORD_CWORD_CWORD_CWORD,
3253 CWORD_CWORD_CWORD_CWORD,
3254 CWORD_CWORD_CWORD_CWORD,
3255 CWORD_CWORD_CWORD_CWORD,
3256 CWORD_CWORD_CWORD_CWORD,
3257 CWORD_CWORD_CWORD_CWORD,
3258 CWORD_CWORD_CWORD_CWORD,
3259 CWORD_CWORD_CWORD_CWORD,
3260 CWORD_CWORD_CWORD_CWORD,
3261 CWORD_CWORD_CWORD_CWORD,
3262 CWORD_CWORD_CWORD_CWORD,
3263 CWORD_CWORD_CWORD_CWORD,
3264 CWORD_CWORD_CWORD_CWORD,
3265 CWORD_CWORD_CWORD_CWORD,
3266 CWORD_CWORD_CWORD_CWORD,
3267 CWORD_CWORD_CWORD_CWORD,
3268 CWORD_CWORD_CWORD_CWORD,
3269 CWORD_CWORD_CWORD_CWORD,
3270 CWORD_CWORD_CWORD_CWORD,
3271 CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3272# if ENABLE_ASH_ALIAS
3273 CSPCL_CIGN_CIGN_CIGN,
3274# endif
3275};
3276
3277#if 1
3278# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3279#else
3280# define SIT(c, syntax) \
3281 ({ \
3282 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3283 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3284 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3285 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3286 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3287 })
3288#endif
3289
3290#endif
3291
3292
3293
3294
3295#if ENABLE_ASH_ALIAS
3296
3297#define ALIASINUSE 1
3298#define ALIASDEAD 2
3299
3300struct alias {
3301 struct alias *next;
3302 char *name;
3303 char *val;
3304 int flag;
3305};
3306
3307
3308static struct alias **atab;
3309#define INIT_G_alias() do { \
3310 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3311} while (0)
3312
3313
3314static struct alias **
3315__lookupalias(const char *name)
3316{
3317 unsigned int hashval;
3318 struct alias **app;
3319 const char *p;
3320 unsigned int ch;
3321
3322 p = name;
3323
3324 ch = (unsigned char)*p;
3325 hashval = ch << 4;
3326 while (ch) {
3327 hashval += ch;
3328 ch = (unsigned char)*++p;
3329 }
3330 app = &atab[hashval % ATABSIZE];
3331
3332 for (; *app; app = &(*app)->next) {
3333 if (strcmp(name, (*app)->name) == 0) {
3334 break;
3335 }
3336 }
3337
3338 return app;
3339}
3340
3341static struct alias *
3342lookupalias(const char *name, int check)
3343{
3344 struct alias *ap = *__lookupalias(name);
3345
3346 if (check && ap && (ap->flag & ALIASINUSE))
3347 return NULL;
3348 return ap;
3349}
3350
3351static struct alias *
3352freealias(struct alias *ap)
3353{
3354 struct alias *next;
3355
3356 if (ap->flag & ALIASINUSE) {
3357 ap->flag |= ALIASDEAD;
3358 return ap;
3359 }
3360
3361 next = ap->next;
3362 free(ap->name);
3363 free(ap->val);
3364 free(ap);
3365 return next;
3366}
3367
3368static void
3369setalias(const char *name, const char *val)
3370{
3371 struct alias *ap, **app;
3372
3373 app = __lookupalias(name);
3374 ap = *app;
3375 INT_OFF;
3376 if (ap) {
3377 if (!(ap->flag & ALIASINUSE)) {
3378 free(ap->val);
3379 }
3380 ap->val = ckstrdup(val);
3381 ap->flag &= ~ALIASDEAD;
3382 } else {
3383
3384 ap = ckzalloc(sizeof(struct alias));
3385 ap->name = ckstrdup(name);
3386 ap->val = ckstrdup(val);
3387
3388
3389 *app = ap;
3390 }
3391 INT_ON;
3392}
3393
3394static int
3395unalias(const char *name)
3396{
3397 struct alias **app;
3398
3399 app = __lookupalias(name);
3400
3401 if (*app) {
3402 INT_OFF;
3403 *app = freealias(*app);
3404 INT_ON;
3405 return 0;
3406 }
3407
3408 return 1;
3409}
3410
3411static void
3412rmaliases(void)
3413{
3414 struct alias *ap, **app;
3415 int i;
3416
3417 INT_OFF;
3418 for (i = 0; i < ATABSIZE; i++) {
3419 app = &atab[i];
3420 for (ap = *app; ap; ap = *app) {
3421 *app = freealias(*app);
3422 if (ap == *app) {
3423 app = &ap->next;
3424 }
3425 }
3426 }
3427 INT_ON;
3428}
3429
3430static void
3431printalias(const struct alias *ap)
3432{
3433 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3434}
3435
3436
3437
3438
3439static int FAST_FUNC
3440aliascmd(int argc UNUSED_PARAM, char **argv)
3441{
3442 char *n, *v;
3443 int ret = 0;
3444 struct alias *ap;
3445
3446 if (!argv[1]) {
3447 int i;
3448
3449 for (i = 0; i < ATABSIZE; i++) {
3450 for (ap = atab[i]; ap; ap = ap->next) {
3451 printalias(ap);
3452 }
3453 }
3454 return 0;
3455 }
3456 while ((n = *++argv) != NULL) {
3457 v = strchr(n+1, '=');
3458 if (v == NULL) {
3459 ap = *__lookupalias(n);
3460 if (ap == NULL) {
3461 fprintf(stderr, "%s: %s not found\n", "alias", n);
3462 ret = 1;
3463 } else
3464 printalias(ap);
3465 } else {
3466 *v++ = '\0';
3467 setalias(n, v);
3468 }
3469 }
3470
3471 return ret;
3472}
3473
3474static int FAST_FUNC
3475unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3476{
3477 int i;
3478
3479 while (nextopt("a") != '\0') {
3480 rmaliases();
3481 return 0;
3482 }
3483 for (i = 0; *argptr; argptr++) {
3484 if (unalias(*argptr)) {
3485 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3486 i = 1;
3487 }
3488 }
3489
3490 return i;
3491}
3492
3493#endif
3494
3495
3496
3497#define FORK_FG 0
3498#define FORK_BG 1
3499#define FORK_NOJOB 2
3500
3501
3502#define SHOW_ONLY_PGID 0x01
3503#define SHOW_PIDS 0x02
3504#define SHOW_CHANGED 0x04
3505#define SHOW_STDERR 0x08
3506
3507
3508
3509
3510
3511
3512
3513struct procstat {
3514 pid_t ps_pid;
3515 int ps_status;
3516 char *ps_cmd;
3517};
3518
3519struct job {
3520 struct procstat ps0;
3521 struct procstat *ps;
3522#if JOBS
3523 int stopstatus;
3524#endif
3525 unsigned nprocs;
3526
3527#define JOBRUNNING 0
3528#define JOBSTOPPED 1
3529#define JOBDONE 2
3530 unsigned
3531 state: 8,
3532#if JOBS
3533 sigint: 1,
3534 jobctl: 1,
3535#endif
3536 waited: 1,
3537 used: 1,
3538 changed: 1;
3539 struct job *prev_job;
3540};
3541
3542static struct job *makejob( int);
3543static int forkshell(struct job *, union node *, int);
3544static int waitforjob(struct job *);
3545
3546#if !JOBS
3547enum { doing_jobctl = 0 };
3548#define setjobctl(on) do {} while (0)
3549#else
3550static smallint doing_jobctl;
3551static void setjobctl(int);
3552#endif
3553
3554
3555
3556
3557static void
3558ignoresig(int signo)
3559{
3560
3561 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3562
3563 signal(signo, SIG_IGN);
3564 }
3565 sigmode[signo - 1] = S_HARD_IGN;
3566}
3567
3568
3569
3570
3571static void
3572signal_handler(int signo)
3573{
3574 if (signo == SIGCHLD) {
3575 got_sigchld = 1;
3576 if (!trap[SIGCHLD])
3577 return;
3578 }
3579
3580 gotsig[signo - 1] = 1;
3581 pending_sig = signo;
3582
3583 if (signo == SIGINT && !trap[SIGINT]) {
3584 if (!suppress_int) {
3585 pending_sig = 0;
3586 raise_interrupt();
3587 }
3588 pending_int = 1;
3589 }
3590}
3591
3592
3593
3594
3595
3596static void
3597setsignal(int signo)
3598{
3599 char *t;
3600 char cur_act, new_act;
3601 struct sigaction act;
3602
3603 t = trap[signo];
3604 new_act = S_DFL;
3605 if (t != NULL) {
3606 new_act = S_CATCH;
3607 if (t[0] == '\0')
3608 new_act = S_IGN;
3609 }
3610
3611 if (rootshell && new_act == S_DFL) {
3612 switch (signo) {
3613 case SIGINT:
3614 if (iflag || minusc || sflag == 0)
3615 new_act = S_CATCH;
3616 break;
3617 case SIGQUIT:
3618#if DEBUG
3619 if (debug)
3620 break;
3621#endif
3622
3623
3624
3625
3626
3627 new_act = S_IGN;
3628 break;
3629 case SIGTERM:
3630 if (iflag)
3631 new_act = S_IGN;
3632 break;
3633#if JOBS
3634 case SIGTSTP:
3635 case SIGTTOU:
3636 if (mflag)
3637 new_act = S_IGN;
3638 break;
3639#endif
3640 }
3641 }
3642
3643
3644
3645
3646
3647
3648
3649 if (signo == SIGCHLD)
3650 new_act = S_CATCH;
3651
3652 t = &sigmode[signo - 1];
3653 cur_act = *t;
3654 if (cur_act == 0) {
3655
3656 if (sigaction(signo, NULL, &act)) {
3657
3658
3659
3660
3661 return;
3662 }
3663 if (act.sa_handler == SIG_IGN) {
3664 cur_act = S_HARD_IGN;
3665 if (mflag
3666 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3667 ) {
3668 cur_act = S_IGN;
3669 }
3670 }
3671 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3672
3673
3674 *t = S_DFL;
3675 return;
3676 }
3677 }
3678 if (cur_act == S_HARD_IGN || cur_act == new_act)
3679 return;
3680
3681 *t = new_act;
3682
3683 act.sa_handler = SIG_DFL;
3684 switch (new_act) {
3685 case S_CATCH:
3686 act.sa_handler = signal_handler;
3687 break;
3688 case S_IGN:
3689 act.sa_handler = SIG_IGN;
3690 break;
3691 }
3692
3693
3694
3695 act.sa_flags = 0;
3696 sigfillset(&act.sa_mask);
3697
3698 sigaction_set(signo, &act);
3699}
3700
3701
3702#define CUR_DELETE 2
3703#define CUR_RUNNING 1
3704#define CUR_STOPPED 0
3705
3706#if JOBS
3707
3708static int initialpgrp;
3709static int ttyfd = -1;
3710#endif
3711
3712static struct job *jobtab;
3713
3714static unsigned njobs;
3715
3716static struct job *curjob;
3717
3718static int jobless;
3719
3720#if 0
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744static struct termios shell_tty_info;
3745static void
3746get_tty_state(void)
3747{
3748 if (rootshell && ttyfd >= 0)
3749 tcgetattr(ttyfd, &shell_tty_info);
3750}
3751static void
3752set_tty_state(void)
3753{
3754
3755 if (ttyfd >= 0)
3756 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3757}
3758static int
3759job_signal_status(struct job *jp)
3760{
3761 int status;
3762 unsigned i;
3763 struct procstat *ps = jp->ps;
3764 for (i = 0; i < jp->nprocs; i++) {
3765 status = ps[i].ps_status;
3766 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3767 return status;
3768 }
3769 return 0;
3770}
3771static void
3772restore_tty_if_stopped_or_signaled(struct job *jp)
3773{
3774
3775 if (rootshell) {
3776 int s = job_signal_status(jp);
3777 if (s)
3778 set_tty_state();
3779 }
3780}
3781#else
3782# define get_tty_state() ((void)0)
3783# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3784#endif
3785
3786static void
3787set_curjob(struct job *jp, unsigned mode)
3788{
3789 struct job *jp1;
3790 struct job **jpp, **curp;
3791
3792
3793 jpp = curp = &curjob;
3794 while (1) {
3795 jp1 = *jpp;
3796 if (jp1 == jp)
3797 break;
3798 jpp = &jp1->prev_job;
3799 }
3800 *jpp = jp1->prev_job;
3801
3802
3803 jpp = curp;
3804 switch (mode) {
3805 default:
3806#if DEBUG
3807 abort();
3808#endif
3809 case CUR_DELETE:
3810
3811 break;
3812 case CUR_RUNNING:
3813
3814
3815
3816 while (1) {
3817 jp1 = *jpp;
3818#if JOBS
3819 if (!jp1 || jp1->state != JOBSTOPPED)
3820#endif
3821 break;
3822 jpp = &jp1->prev_job;
3823 }
3824
3825#if JOBS
3826 case CUR_STOPPED:
3827#endif
3828
3829 jp->prev_job = *jpp;
3830 *jpp = jp;
3831 break;
3832 }
3833}
3834
3835#if JOBS || DEBUG
3836static int
3837jobno(const struct job *jp)
3838{
3839 return jp - jobtab + 1;
3840}
3841#endif
3842
3843
3844
3845
3846#if !JOBS
3847#define getjob(name, getctl) getjob(name)
3848#endif
3849static struct job *
3850getjob(const char *name, int getctl)
3851{
3852 struct job *jp;
3853 struct job *found;
3854 const char *err_msg = "%s: no such job";
3855 unsigned num;
3856 int c;
3857 const char *p;
3858 char *(*match)(const char *, const char *);
3859
3860 jp = curjob;
3861 p = name;
3862 if (!p)
3863 goto currentjob;
3864
3865 if (*p != '%')
3866 goto err;
3867
3868 c = *++p;
3869 if (!c)
3870 goto currentjob;
3871
3872 if (!p[1]) {
3873 if (c == '+' || c == '%') {
3874 currentjob:
3875 err_msg = "No current job";
3876 goto check;
3877 }
3878 if (c == '-') {
3879 if (jp)
3880 jp = jp->prev_job;
3881 err_msg = "No previous job";
3882 check:
3883 if (!jp)
3884 goto err;
3885 goto gotit;
3886 }
3887 }
3888
3889 if (is_number(p)) {
3890 num = atoi(p);
3891 if (num > 0 && num <= njobs) {
3892 jp = jobtab + num - 1;
3893 if (jp->used)
3894 goto gotit;
3895 goto err;
3896 }
3897 }
3898
3899 match = prefix;
3900 if (*p == '?') {
3901 match = strstr;
3902 p++;
3903 }
3904
3905 found = NULL;
3906 while (jp) {
3907 if (match(jp->ps[0].ps_cmd, p)) {
3908 if (found)
3909 goto err;
3910 found = jp;
3911 err_msg = "%s: ambiguous";
3912 }
3913 jp = jp->prev_job;
3914 }
3915 if (!found)
3916 goto err;
3917 jp = found;
3918
3919 gotit:
3920#if JOBS
3921 err_msg = "job %s not created under job control";
3922 if (getctl && jp->jobctl == 0)
3923 goto err;
3924#endif
3925 return jp;
3926 err:
3927 ash_msg_and_raise_error(err_msg, name);
3928}
3929
3930
3931
3932
3933static void
3934freejob(struct job *jp)
3935{
3936 struct procstat *ps;
3937 int i;
3938
3939 INT_OFF;
3940 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3941 if (ps->ps_cmd != nullstr)
3942 free(ps->ps_cmd);
3943 }
3944 if (jp->ps != &jp->ps0)
3945 free(jp->ps);
3946 jp->used = 0;
3947 set_curjob(jp, CUR_DELETE);
3948 INT_ON;
3949}
3950
3951#if JOBS
3952static void
3953xtcsetpgrp(int fd, pid_t pgrp)
3954{
3955 if (tcsetpgrp(fd, pgrp))
3956 ash_msg_and_raise_perror("can't set tty process group");
3957}
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968static void
3969setjobctl(int on)
3970{
3971 int fd;
3972 int pgrp;
3973
3974 if (on == doing_jobctl || rootshell == 0)
3975 return;
3976 if (on) {
3977 int ofd;
3978 ofd = fd = open(_PATH_TTY, O_RDWR);
3979 if (fd < 0) {
3980
3981
3982
3983
3984 fd = 2;
3985 while (!isatty(fd))
3986 if (--fd < 0)
3987 goto out;
3988 }
3989
3990 fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
3991 if (ofd >= 0)
3992 close(ofd);
3993 if (fd < 0)
3994 goto out;
3995 if (F_DUPFD_CLOEXEC == F_DUPFD)
3996 close_on_exec_on(fd);
3997 while (1) {
3998 pgrp = tcgetpgrp(fd);
3999 if (pgrp < 0) {
4000 out:
4001 ash_msg("can't access tty; job control turned off");
4002 mflag = on = 0;
4003 goto close;
4004 }
4005 if (pgrp == getpgrp())
4006 break;
4007 killpg(0, SIGTTIN);
4008 }
4009 initialpgrp = pgrp;
4010
4011 setsignal(SIGTSTP);
4012 setsignal(SIGTTOU);
4013 setsignal(SIGTTIN);
4014 pgrp = rootpid;
4015 setpgid(0, pgrp);
4016 xtcsetpgrp(fd, pgrp);
4017 } else {
4018
4019 fd = ttyfd;
4020 pgrp = initialpgrp;
4021
4022
4023 tcsetpgrp(fd, pgrp);
4024 setpgid(0, pgrp);
4025 setsignal(SIGTSTP);
4026 setsignal(SIGTTOU);
4027 setsignal(SIGTTIN);
4028 close:
4029 if (fd >= 0)
4030 close(fd);
4031 fd = -1;
4032 }
4033 ttyfd = fd;
4034 doing_jobctl = on;
4035}
4036
4037static int FAST_FUNC
4038killcmd(int argc, char **argv)
4039{
4040 if (argv[1] && strcmp(argv[1], "-l") != 0) {
4041 int i = 1;
4042 do {
4043 if (argv[i][0] == '%') {
4044
4045
4046
4047
4048 struct job *jp;
4049 char *dst;
4050 int j, n;
4051
4052 jp = getjob(argv[i], 0);
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065 n = jp->nprocs;
4066 if (jp->jobctl)
4067 n = 1;
4068 dst = alloca(n * sizeof(int)*4);
4069 argv[i] = dst;
4070 for (j = 0; j < n; j++) {
4071 struct procstat *ps = &jp->ps[j];
4072
4073
4074
4075 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4076 continue;
4077
4078
4079
4080
4081
4082 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4083 }
4084 *dst = '\0';
4085 }
4086 } while (argv[++i]);
4087 }
4088 return kill_main(argc, argv);
4089}
4090
4091static void
4092showpipe(struct job *jp )
4093{
4094 struct procstat *ps;
4095 struct procstat *psend;
4096
4097 psend = jp->ps + jp->nprocs;
4098 for (ps = jp->ps + 1; ps < psend; ps++)
4099 printf(" | %s", ps->ps_cmd);
4100 newline_and_flush(stdout);
4101 flush_stdout_stderr();
4102}
4103
4104
4105static int
4106restartjob(struct job *jp, int mode)
4107{
4108 struct procstat *ps;
4109 int i;
4110 int status;
4111 pid_t pgid;
4112
4113 INT_OFF;
4114 if (jp->state == JOBDONE)
4115 goto out;
4116 jp->state = JOBRUNNING;
4117 pgid = jp->ps[0].ps_pid;
4118 if (mode == FORK_FG) {
4119 get_tty_state();
4120 xtcsetpgrp(ttyfd, pgid);
4121 }
4122 killpg(pgid, SIGCONT);
4123 ps = jp->ps;
4124 i = jp->nprocs;
4125 do {
4126 if (WIFSTOPPED(ps->ps_status)) {
4127 ps->ps_status = -1;
4128 }
4129 ps++;
4130 } while (--i);
4131 out:
4132 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4133 INT_ON;
4134 return status;
4135}
4136
4137static int FAST_FUNC
4138fg_bgcmd(int argc UNUSED_PARAM, char **argv)
4139{
4140 struct job *jp;
4141 int mode;
4142 int retval;
4143
4144 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4145 nextopt(nullstr);
4146 argv = argptr;
4147 do {
4148 jp = getjob(*argv, 1);
4149 if (mode == FORK_BG) {
4150 set_curjob(jp, CUR_RUNNING);
4151 printf("[%d] ", jobno(jp));
4152 }
4153 out1str(jp->ps[0].ps_cmd);
4154 showpipe(jp );
4155 retval = restartjob(jp, mode);
4156 } while (*argv && *++argv);
4157 return retval;
4158}
4159#endif
4160
4161static int
4162sprint_status48(char *s, int status, int sigonly)
4163{
4164 int col;
4165 int st;
4166
4167 col = 0;
4168 if (!WIFEXITED(status)) {
4169#if JOBS
4170 if (WIFSTOPPED(status))
4171 st = WSTOPSIG(status);
4172 else
4173#endif
4174 st = WTERMSIG(status);
4175 if (sigonly) {
4176 if (st == SIGINT || st == SIGPIPE)
4177 goto out;
4178#if JOBS
4179 if (WIFSTOPPED(status))
4180 goto out;
4181#endif
4182 }
4183 st &= 0x7f;
4184
4185 col = fmtstr(s, 32, strsignal(st));
4186 if (WCOREDUMP(status)) {
4187 strcpy(s + col, " (core dumped)");
4188 col += sizeof(" (core dumped)")-1;
4189 }
4190 } else if (!sigonly) {
4191 st = WEXITSTATUS(status);
4192 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
4193 }
4194 out:
4195 return col;
4196}
4197
4198static int
4199wait_block_or_sig(int *status)
4200{
4201 int pid;
4202
4203 do {
4204 sigset_t mask;
4205
4206
4207 got_sigchld = 0;
4208
4209 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
4210 if (pid != 0)
4211 break;
4212
4213
4214#if 1
4215 sigfillset(&mask);
4216 sigprocmask(SIG_SETMASK, &mask, &mask);
4217 while (!got_sigchld && !pending_sig)
4218 sigsuspend(&mask);
4219 sigprocmask(SIG_SETMASK, &mask, NULL);
4220#else
4221 while (!got_sigchld && !pending_sig)
4222 pause();
4223#endif
4224
4225
4226 } while (got_sigchld);
4227
4228 return pid;
4229}
4230
4231#define DOWAIT_NONBLOCK 0
4232#define DOWAIT_BLOCK 1
4233#define DOWAIT_BLOCK_OR_SIG 2
4234
4235static int
4236dowait(int block, struct job *job)
4237{
4238 int pid;
4239 int status;
4240 struct job *jp;
4241 struct job *thisjob = NULL;
4242
4243 TRACE(("dowait(0x%x) called\n", block));
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263 INT_OFF;
4264 if (block == DOWAIT_BLOCK_OR_SIG) {
4265 pid = wait_block_or_sig(&status);
4266 } else {
4267 int wait_flags = 0;
4268 if (block == DOWAIT_NONBLOCK)
4269 wait_flags = WNOHANG;
4270
4271 if (doing_jobctl)
4272 wait_flags |= WUNTRACED;
4273
4274 pid = waitpid(-1, &status, wait_flags);
4275 }
4276 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4277 pid, status, errno, strerror(errno)));
4278 if (pid <= 0)
4279 goto out;
4280
4281 thisjob = NULL;
4282 for (jp = curjob; jp; jp = jp->prev_job) {
4283 int jobstate;
4284 struct procstat *ps;
4285 struct procstat *psend;
4286 if (jp->state == JOBDONE)
4287 continue;
4288 jobstate = JOBDONE;
4289 ps = jp->ps;
4290 psend = ps + jp->nprocs;
4291 do {
4292 if (ps->ps_pid == pid) {
4293 TRACE(("Job %d: changing status of proc %d "
4294 "from 0x%x to 0x%x\n",
4295 jobno(jp), pid, ps->ps_status, status));
4296 ps->ps_status = status;
4297 thisjob = jp;
4298 }
4299 if (ps->ps_status == -1)
4300 jobstate = JOBRUNNING;
4301#if JOBS
4302 if (jobstate == JOBRUNNING)
4303 continue;
4304 if (WIFSTOPPED(ps->ps_status)) {
4305 jp->stopstatus = ps->ps_status;
4306 jobstate = JOBSTOPPED;
4307 }
4308#endif
4309 } while (++ps < psend);
4310 if (!thisjob)
4311 continue;
4312
4313
4314
4315 if (jobstate != JOBRUNNING) {
4316
4317
4318
4319 thisjob->changed = 1;
4320 if (thisjob->state != jobstate) {
4321 TRACE(("Job %d: changing state from %d to %d\n",
4322 jobno(thisjob), thisjob->state, jobstate));
4323 thisjob->state = jobstate;
4324#if JOBS
4325 if (jobstate == JOBSTOPPED)
4326 set_curjob(thisjob, CUR_STOPPED);
4327#endif
4328 }
4329 }
4330 goto out;
4331 }
4332
4333#if JOBS
4334 if (!WIFSTOPPED(status))
4335 jobless--;
4336#endif
4337 out:
4338 INT_ON;
4339
4340 if (thisjob && thisjob == job) {
4341 char s[48 + 1];
4342 int len;
4343
4344 len = sprint_status48(s, status, 1);
4345 if (len) {
4346 s[len] = '\n';
4347 s[len + 1] = '\0';
4348 out2str(s);
4349 }
4350 }
4351 return pid;
4352}
4353
4354#if JOBS
4355static void
4356showjob(struct job *jp, int mode)
4357{
4358 struct procstat *ps;
4359 struct procstat *psend;
4360 int col;
4361 int indent_col;
4362 char s[16 + 16 + 48];
4363 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4364
4365 ps = jp->ps;
4366
4367 if (mode & SHOW_ONLY_PGID) {
4368
4369 fprintf(out, "%d\n", ps->ps_pid);
4370 return;
4371 }
4372
4373 col = fmtstr(s, 16, "[%d] ", jobno(jp));
4374 indent_col = col;
4375
4376 if (jp == curjob)
4377 s[col - 3] = '+';
4378 else if (curjob && jp == curjob->prev_job)
4379 s[col - 3] = '-';
4380
4381 if (mode & SHOW_PIDS)
4382 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4383
4384 psend = ps + jp->nprocs;
4385
4386 if (jp->state == JOBRUNNING) {
4387 strcpy(s + col, "Running");
4388 col += sizeof("Running") - 1;
4389 } else {
4390 int status = psend[-1].ps_status;
4391 if (jp->state == JOBSTOPPED)
4392 status = jp->stopstatus;
4393 col += sprint_status48(s + col, status, 0);
4394 }
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405 goto start;
4406 do {
4407
4408 s[0] = '\0';
4409 col = 33;
4410 if (mode & SHOW_PIDS)
4411 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4412 start:
4413 fprintf(out, "%s%*c%s%s",
4414 s,
4415 33 - col >= 0 ? 33 - col : 0, ' ',
4416 ps == jp->ps ? "" : "| ",
4417 ps->ps_cmd
4418 );
4419 } while (++ps != psend);
4420 newline_and_flush(out);
4421
4422 jp->changed = 0;
4423
4424 if (jp->state == JOBDONE) {
4425 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4426 freejob(jp);
4427 }
4428}
4429
4430
4431
4432
4433
4434static void
4435showjobs(int mode)
4436{
4437 struct job *jp;
4438
4439 TRACE(("showjobs(0x%x) called\n", mode));
4440
4441
4442 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
4443 continue;
4444
4445 for (jp = curjob; jp; jp = jp->prev_job) {
4446 if (!(mode & SHOW_CHANGED) || jp->changed) {
4447 showjob(jp, mode);
4448 }
4449 }
4450}
4451
4452static int FAST_FUNC
4453jobscmd(int argc UNUSED_PARAM, char **argv)
4454{
4455 int mode, m;
4456
4457 mode = 0;
4458 while ((m = nextopt("lp")) != '\0') {
4459 if (m == 'l')
4460 mode |= SHOW_PIDS;
4461 else
4462 mode |= SHOW_ONLY_PGID;
4463 }
4464
4465 argv = argptr;
4466 if (*argv) {
4467 do
4468 showjob(getjob(*argv, 0), mode);
4469 while (*++argv);
4470 } else {
4471 showjobs(mode);
4472 }
4473
4474 return 0;
4475}
4476#endif
4477
4478
4479static int
4480getstatus(struct job *job)
4481{
4482 int status;
4483 int retval;
4484 struct procstat *ps;
4485
4486
4487 ps = job->ps + job->nprocs - 1;
4488 status = ps->ps_status;
4489 if (pipefail) {
4490
4491 while (status == 0 && --ps >= job->ps)
4492 status = ps->ps_status;
4493 }
4494
4495 retval = WEXITSTATUS(status);
4496 if (!WIFEXITED(status)) {
4497#if JOBS
4498 retval = WSTOPSIG(status);
4499 if (!WIFSTOPPED(status))
4500#endif
4501 {
4502
4503 retval = WTERMSIG(status);
4504#if JOBS
4505 if (retval == SIGINT)
4506 job->sigint = 1;
4507#endif
4508 }
4509 retval += 128;
4510 }
4511 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4512 jobno(job), job->nprocs, status, retval));
4513 return retval;
4514}
4515
4516static int FAST_FUNC
4517waitcmd(int argc UNUSED_PARAM, char **argv)
4518{
4519 struct job *job;
4520 int retval;
4521 struct job *jp;
4522
4523 nextopt(nullstr);
4524 retval = 0;
4525
4526 argv = argptr;
4527 if (!*argv) {
4528
4529 for (;;) {
4530 jp = curjob;
4531 while (1) {
4532 if (!jp)
4533 goto ret;
4534 if (jp->state == JOBRUNNING)
4535 break;
4536 jp->waited = 1;
4537 jp = jp->prev_job;
4538 }
4539
4540
4541
4542
4543
4544
4545
4546 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4547
4548
4549
4550
4551 if (pending_sig)
4552 goto sigout;
4553 }
4554 }
4555
4556 retval = 127;
4557 do {
4558 if (**argv != '%') {
4559 pid_t pid = number(*argv);
4560 job = curjob;
4561 while (1) {
4562 if (!job)
4563 goto repeat;
4564 if (job->ps[job->nprocs - 1].ps_pid == pid)
4565 break;
4566 job = job->prev_job;
4567 }
4568 } else {
4569 job = getjob(*argv, 0);
4570 }
4571
4572 while (job->state == JOBRUNNING) {
4573 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4574 if (pending_sig)
4575 goto sigout;
4576 }
4577 job->waited = 1;
4578 retval = getstatus(job);
4579 repeat: ;
4580 } while (*++argv);
4581
4582 ret:
4583 return retval;
4584 sigout:
4585 retval = 128 + pending_sig;
4586 return retval;
4587}
4588
4589static struct job *
4590growjobtab(void)
4591{
4592 size_t len;
4593 ptrdiff_t offset;
4594 struct job *jp, *jq;
4595
4596 len = njobs * sizeof(*jp);
4597 jq = jobtab;
4598 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4599
4600 offset = (char *)jp - (char *)jq;
4601 if (offset) {
4602
4603 size_t l = len;
4604
4605 jq = (struct job *)((char *)jq + l);
4606 while (l) {
4607 l -= sizeof(*jp);
4608 jq--;
4609#define joff(p) ((struct job *)((char *)(p) + l))
4610#define jmove(p) (p) = (void *)((char *)(p) + offset)
4611 if (joff(jp)->ps == &jq->ps0)
4612 jmove(joff(jp)->ps);
4613 if (joff(jp)->prev_job)
4614 jmove(joff(jp)->prev_job);
4615 }
4616 if (curjob)
4617 jmove(curjob);
4618#undef joff
4619#undef jmove
4620 }
4621
4622 njobs += 4;
4623 jobtab = jp;
4624 jp = (struct job *)((char *)jp + len);
4625 jq = jp + 3;
4626 do {
4627 jq->used = 0;
4628 } while (--jq >= jp);
4629 return jp;
4630}
4631
4632
4633
4634
4635
4636static struct job *
4637makejob( int nprocs)
4638{
4639 int i;
4640 struct job *jp;
4641
4642 for (i = njobs, jp = jobtab; ; jp++) {
4643 if (--i < 0) {
4644 jp = growjobtab();
4645 break;
4646 }
4647 if (jp->used == 0)
4648 break;
4649 if (jp->state != JOBDONE || !jp->waited)
4650 continue;
4651#if JOBS
4652 if (doing_jobctl)
4653 continue;
4654#endif
4655 freejob(jp);
4656 break;
4657 }
4658 memset(jp, 0, sizeof(*jp));
4659#if JOBS
4660
4661
4662 if (doing_jobctl)
4663 jp->jobctl = 1;
4664#endif
4665 jp->prev_job = curjob;
4666 curjob = jp;
4667 jp->used = 1;
4668 jp->ps = &jp->ps0;
4669 if (nprocs > 1) {
4670 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4671 }
4672 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4673 jobno(jp)));
4674 return jp;
4675}
4676
4677#if JOBS
4678
4679
4680
4681
4682static char *cmdnextc;
4683
4684static void
4685cmdputs(const char *s)
4686{
4687 static const char vstype[VSTYPE + 1][3] = {
4688 "", "}", "-", "+", "?", "=",
4689 "%", "%%", "#", "##"
4690 IF_BASH_SUBSTR(, ":")
4691 IF_BASH_PATTERN_SUBST(, "/", "//")
4692 };
4693
4694 const char *p, *str;
4695 char cc[2];
4696 char *nextc;
4697 unsigned char c;
4698 unsigned char subtype = 0;
4699 int quoted = 0;
4700
4701 cc[1] = '\0';
4702 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4703 p = s;
4704 while ((c = *p++) != '\0') {
4705 str = NULL;
4706 switch (c) {
4707 case CTLESC:
4708 c = *p++;
4709 break;
4710 case CTLVAR:
4711 subtype = *p++;
4712 if ((subtype & VSTYPE) == VSLENGTH)
4713 str = "${#";
4714 else
4715 str = "${";
4716 goto dostr;
4717 case CTLENDVAR:
4718 str = "\"}" + !(quoted & 1);
4719 quoted >>= 1;
4720 subtype = 0;
4721 goto dostr;
4722 case CTLBACKQ:
4723 str = "$(...)";
4724 goto dostr;
4725#if ENABLE_FEATURE_SH_MATH
4726 case CTLARI:
4727 str = "$((";
4728 goto dostr;
4729 case CTLENDARI:
4730 str = "))";
4731 goto dostr;
4732#endif
4733 case CTLQUOTEMARK:
4734 quoted ^= 1;
4735 c = '"';
4736 break;
4737 case '=':
4738 if (subtype == 0)
4739 break;
4740 if ((subtype & VSTYPE) != VSNORMAL)
4741 quoted <<= 1;
4742 str = vstype[subtype & VSTYPE];
4743 if (subtype & VSNUL)
4744 c = ':';
4745 else
4746 goto checkstr;
4747 break;
4748 case '\'':
4749 case '\\':
4750 case '"':
4751 case '$':
4752
4753 cc[0] = c;
4754 str = cc;
4755
4756
4757
4758
4759 c = '\\';
4760 break;
4761 default:
4762 break;
4763 }
4764 USTPUTC(c, nextc);
4765 checkstr:
4766 if (!str)
4767 continue;
4768 dostr:
4769 while ((c = *str++) != '\0') {
4770 USTPUTC(c, nextc);
4771 }
4772 }
4773
4774 if (quoted & 1) {
4775 USTPUTC('"', nextc);
4776 }
4777 *nextc = 0;
4778 cmdnextc = nextc;
4779}
4780
4781
4782static void cmdtxt(union node *n);
4783
4784static void
4785cmdlist(union node *np, int sep)
4786{
4787 for (; np; np = np->narg.next) {
4788 if (!sep)
4789 cmdputs(" ");
4790 cmdtxt(np);
4791 if (sep && np->narg.next)
4792 cmdputs(" ");
4793 }
4794}
4795
4796static void
4797cmdtxt(union node *n)
4798{
4799 union node *np;
4800 struct nodelist *lp;
4801 const char *p;
4802
4803 if (!n)
4804 return;
4805 switch (n->type) {
4806 default:
4807#if DEBUG
4808 abort();
4809#endif
4810 case NPIPE:
4811 lp = n->npipe.cmdlist;
4812 for (;;) {
4813 cmdtxt(lp->n);
4814 lp = lp->next;
4815 if (!lp)
4816 break;
4817 cmdputs(" | ");
4818 }
4819 break;
4820 case NSEMI:
4821 p = "; ";
4822 goto binop;
4823 case NAND:
4824 p = " && ";
4825 goto binop;
4826 case NOR:
4827 p = " || ";
4828 binop:
4829 cmdtxt(n->nbinary.ch1);
4830 cmdputs(p);
4831 n = n->nbinary.ch2;
4832 goto donode;
4833 case NREDIR:
4834 case NBACKGND:
4835 n = n->nredir.n;
4836 goto donode;
4837 case NNOT:
4838 cmdputs("!");
4839 n = n->nnot.com;
4840 donode:
4841 cmdtxt(n);
4842 break;
4843 case NIF:
4844 cmdputs("if ");
4845 cmdtxt(n->nif.test);
4846 cmdputs("; then ");
4847 if (n->nif.elsepart) {
4848 cmdtxt(n->nif.ifpart);
4849 cmdputs("; else ");
4850 n = n->nif.elsepart;
4851 } else {
4852 n = n->nif.ifpart;
4853 }
4854 p = "; fi";
4855 goto dotail;
4856 case NSUBSHELL:
4857 cmdputs("(");
4858 n = n->nredir.n;
4859 p = ")";
4860 goto dotail;
4861 case NWHILE:
4862 p = "while ";
4863 goto until;
4864 case NUNTIL:
4865 p = "until ";
4866 until:
4867 cmdputs(p);
4868 cmdtxt(n->nbinary.ch1);
4869 n = n->nbinary.ch2;
4870 p = "; done";
4871 dodo:
4872 cmdputs("; do ");
4873 dotail:
4874 cmdtxt(n);
4875 goto dotail2;
4876 case NFOR:
4877 cmdputs("for ");
4878 cmdputs(n->nfor.var);
4879 cmdputs(" in ");
4880 cmdlist(n->nfor.args, 1);
4881 n = n->nfor.body;
4882 p = "; done";
4883 goto dodo;
4884 case NDEFUN:
4885 cmdputs(n->ndefun.text);
4886 p = "() { ... }";
4887 goto dotail2;
4888 case NCMD:
4889 cmdlist(n->ncmd.args, 1);
4890 cmdlist(n->ncmd.redirect, 0);
4891 break;
4892 case NARG:
4893 p = n->narg.text;
4894 dotail2:
4895 cmdputs(p);
4896 break;
4897 case NHERE:
4898 case NXHERE:
4899 p = "<<...";
4900 goto dotail2;
4901 case NCASE:
4902 cmdputs("case ");
4903 cmdputs(n->ncase.expr->narg.text);
4904 cmdputs(" in ");
4905 for (np = n->ncase.cases; np; np = np->nclist.next) {
4906 cmdtxt(np->nclist.pattern);
4907 cmdputs(") ");
4908 cmdtxt(np->nclist.body);
4909 cmdputs(";; ");
4910 }
4911 p = "esac";
4912 goto dotail2;
4913 case NTO:
4914 p = ">";
4915 goto redir;
4916 case NCLOBBER:
4917 p = ">|";
4918 goto redir;
4919 case NAPPEND:
4920 p = ">>";
4921 goto redir;
4922#if BASH_REDIR_OUTPUT
4923 case NTO2:
4924#endif
4925 case NTOFD:
4926 p = ">&";
4927 goto redir;
4928 case NFROM:
4929 p = "<";
4930 goto redir;
4931 case NFROMFD:
4932 p = "<&";
4933 goto redir;
4934 case NFROMTO:
4935 p = "<>";
4936 redir:
4937 cmdputs(utoa(n->nfile.fd));
4938 cmdputs(p);
4939 if (n->type == NTOFD || n->type == NFROMFD) {
4940 if (n->ndup.dupfd >= 0)
4941 cmdputs(utoa(n->ndup.dupfd));
4942 else
4943 cmdputs("-");
4944 break;
4945 }
4946 n = n->nfile.fname;
4947 goto donode;
4948 }
4949}
4950
4951static char *
4952commandtext(union node *n)
4953{
4954 char *name;
4955
4956 STARTSTACKSTR(cmdnextc);
4957 cmdtxt(n);
4958 name = stackblock();
4959 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
4960 return ckstrdup(name);
4961}
4962#endif
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983static void
4984clear_traps(void)
4985{
4986 char **tp;
4987
4988 INT_OFF;
4989 for (tp = trap; tp < &trap[NSIG]; tp++) {
4990 if (*tp && **tp) {
4991 if (trap_ptr == trap)
4992 free(*tp);
4993
4994 *tp = NULL;
4995 if ((tp - trap) != 0)
4996 setsignal(tp - trap);
4997 }
4998 }
4999 may_have_traps = 0;
5000 INT_ON;
5001}
5002
5003
5004static void closescript(void);
5005
5006
5007
5008static NOINLINE void
5009forkchild(struct job *jp, union node *n, int mode)
5010{
5011 int oldlvl;
5012
5013 TRACE(("Child shell %d\n", getpid()));
5014 oldlvl = shlvl;
5015 shlvl++;
5016
5017
5018
5019
5020
5021 closescript();
5022
5023 if (mode == FORK_NOJOB
5024 && n && n->type == NCMD
5025
5026 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
5027 && n->ncmd.args->narg.next == NULL
5028
5029 ) {
5030 TRACE(("Trap hack\n"));
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066 trap_ptr = xmemdup(trap, sizeof(trap));
5067
5068 }
5069 clear_traps();
5070#if JOBS
5071
5072 doing_jobctl = 0;
5073 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
5074 pid_t pgrp;
5075
5076 if (jp->nprocs == 0)
5077 pgrp = getpid();
5078 else
5079 pgrp = jp->ps[0].ps_pid;
5080
5081 setpgid(0, pgrp);
5082 if (mode == FORK_FG)
5083 xtcsetpgrp(ttyfd, pgrp);
5084 setsignal(SIGTSTP);
5085 setsignal(SIGTTOU);
5086 } else
5087#endif
5088 if (mode == FORK_BG) {
5089
5090
5091 ignoresig(SIGINT);
5092 ignoresig(SIGQUIT);
5093 if (jp->nprocs == 0) {
5094 close(0);
5095 if (open(bb_dev_null, O_RDONLY) != 0)
5096 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
5097 }
5098 }
5099 if (oldlvl == 0) {
5100 if (iflag) {
5101 setsignal(SIGINT);
5102 setsignal(SIGTERM);
5103 }
5104
5105
5106
5107
5108
5109
5110 setsignal(SIGQUIT);
5111 }
5112#if JOBS
5113 if (n && n->type == NCMD
5114 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
5115 ) {
5116 TRACE(("Job hack\n"));
5117
5118
5119
5120
5121 freejob(curjob);
5122 return;
5123 }
5124#endif
5125 for (jp = curjob; jp; jp = jp->prev_job)
5126 freejob(jp);
5127 jobless = 0;
5128}
5129
5130
5131#if !JOBS
5132#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5133#endif
5134static void
5135forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5136{
5137 TRACE(("In parent shell: child = %d\n", pid));
5138 if (!jp) {
5139
5140 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5141 continue;
5142 jobless++;
5143 return;
5144 }
5145#if JOBS
5146 if (mode != FORK_NOJOB && jp->jobctl) {
5147 int pgrp;
5148
5149 if (jp->nprocs == 0)
5150 pgrp = pid;
5151 else
5152 pgrp = jp->ps[0].ps_pid;
5153
5154 setpgid(pid, pgrp);
5155 }
5156#endif
5157 if (mode == FORK_BG) {
5158 backgndpid = pid;
5159 set_curjob(jp, CUR_RUNNING);
5160 }
5161 if (jp) {
5162 struct procstat *ps = &jp->ps[jp->nprocs++];
5163 ps->ps_pid = pid;
5164 ps->ps_status = -1;
5165 ps->ps_cmd = nullstr;
5166#if JOBS
5167 if (doing_jobctl && n)
5168 ps->ps_cmd = commandtext(n);
5169#endif
5170 }
5171}
5172
5173
5174static int
5175forkshell(struct job *jp, union node *n, int mode)
5176{
5177 int pid;
5178
5179 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5180 pid = fork();
5181 if (pid < 0) {
5182 TRACE(("Fork failed, errno=%d", errno));
5183 if (jp)
5184 freejob(jp);
5185 ash_msg_and_raise_perror("can't fork");
5186 }
5187 if (pid == 0) {
5188 CLEAR_RANDOM_T(&random_gen);
5189 forkchild(jp, n, mode);
5190 } else {
5191 forkparent(jp, n, mode, pid);
5192 }
5193 return pid;
5194}
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216static int
5217waitforjob(struct job *jp)
5218{
5219 int st;
5220
5221 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
5222
5223 INT_OFF;
5224 while (jp->state == JOBRUNNING) {
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255 dowait(DOWAIT_BLOCK, jp);
5256 }
5257 INT_ON;
5258
5259 st = getstatus(jp);
5260#if JOBS
5261 if (jp->jobctl) {
5262 xtcsetpgrp(ttyfd, rootpid);
5263 restore_tty_if_stopped_or_signaled(jp);
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273 if (jp->sigint)
5274 raise(SIGINT);
5275 }
5276 if (jp->state == JOBDONE)
5277#endif
5278 freejob(jp);
5279 return st;
5280}
5281
5282
5283
5284
5285static int
5286stoppedjobs(void)
5287{
5288 struct job *jp;
5289 int retval;
5290
5291 retval = 0;
5292 if (job_warning)
5293 goto out;
5294 jp = curjob;
5295 if (jp && jp->state == JOBSTOPPED) {
5296 out2str("You have stopped jobs.\n");
5297 job_warning = 2;
5298 retval++;
5299 }
5300 out:
5301 return retval;
5302}
5303
5304
5305
5306
5307
5308
5309#undef EMPTY
5310#undef CLOSED
5311#define EMPTY -2
5312#define CLOSED -1
5313
5314
5315
5316
5317
5318
5319
5320static void expandhere(union node *arg, int fd);
5321static int
5322openhere(union node *redir)
5323{
5324 int pip[2];
5325 size_t len = 0;
5326
5327 if (pipe(pip) < 0)
5328 ash_msg_and_raise_perror("can't create pipe");
5329 if (redir->type == NHERE) {
5330 len = strlen(redir->nhere.doc->narg.text);
5331 if (len <= PIPE_BUF) {
5332 full_write(pip[1], redir->nhere.doc->narg.text, len);
5333 goto out;
5334 }
5335 }
5336 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5337
5338 close(pip[0]);
5339 ignoresig(SIGINT);
5340 ignoresig(SIGQUIT);
5341 ignoresig(SIGHUP);
5342 ignoresig(SIGTSTP);
5343 signal(SIGPIPE, SIG_DFL);
5344 if (redir->type == NHERE)
5345 full_write(pip[1], redir->nhere.doc->narg.text, len);
5346 else
5347 expandhere(redir->nhere.doc, pip[1]);
5348 _exit(EXIT_SUCCESS);
5349 }
5350 out:
5351 close(pip[1]);
5352 return pip[0];
5353}
5354
5355static int
5356openredirect(union node *redir)
5357{
5358 struct stat sb;
5359 char *fname;
5360 int f;
5361
5362 switch (redir->nfile.type) {
5363
5364
5365
5366
5367 case NHERE:
5368 case NXHERE:
5369 return openhere(redir);
5370 }
5371
5372
5373
5374
5375 fname = redir->nfile.expfname;
5376
5377 switch (redir->nfile.type) {
5378 default:
5379#if DEBUG
5380 abort();
5381#endif
5382 case NFROM:
5383 f = open(fname, O_RDONLY);
5384 if (f < 0)
5385 goto eopen;
5386 break;
5387 case NFROMTO:
5388 f = open(fname, O_RDWR|O_CREAT, 0666);
5389 if (f < 0)
5390 goto ecreate;
5391 break;
5392 case NTO:
5393#if BASH_REDIR_OUTPUT
5394 case NTO2:
5395#endif
5396
5397 if (Cflag) {
5398 if (stat(fname, &sb) < 0) {
5399 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5400 if (f < 0)
5401 goto ecreate;
5402 } else if (!S_ISREG(sb.st_mode)) {
5403 f = open(fname, O_WRONLY, 0666);
5404 if (f < 0)
5405 goto ecreate;
5406 if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
5407 close(f);
5408 errno = EEXIST;
5409 goto ecreate;
5410 }
5411 } else {
5412 errno = EEXIST;
5413 goto ecreate;
5414 }
5415 break;
5416 }
5417
5418 case NCLOBBER:
5419 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5420 if (f < 0)
5421 goto ecreate;
5422 break;
5423 case NAPPEND:
5424 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5425 if (f < 0)
5426 goto ecreate;
5427 break;
5428 }
5429
5430 return f;
5431 ecreate:
5432 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5433 eopen:
5434 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5435}
5436
5437
5438
5439
5440static int
5441savefd(int from)
5442{
5443 int newfd;
5444 int err;
5445
5446 newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
5447 err = newfd < 0 ? errno : 0;
5448 if (err != EBADF) {
5449 if (err)
5450 ash_msg_and_raise_perror("%d", from);
5451 close(from);
5452 if (F_DUPFD_CLOEXEC == F_DUPFD)
5453 close_on_exec_on(newfd);
5454 }
5455
5456 return newfd;
5457}
5458static int
5459dup2_or_raise(int from, int to)
5460{
5461 int newfd;
5462
5463 newfd = (from != to) ? dup2(from, to) : to;
5464 if (newfd < 0) {
5465
5466 ash_msg_and_raise_perror("%d", from);
5467 }
5468 return newfd;
5469}
5470static int
5471dup_CLOEXEC(int fd, int avoid_fd)
5472{
5473 int newfd;
5474 repeat:
5475 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5476 if (newfd >= 0) {
5477 if (F_DUPFD_CLOEXEC == F_DUPFD)
5478 close_on_exec_on(newfd);
5479 } else {
5480 if (errno == EBUSY)
5481 goto repeat;
5482 if (errno == EINTR)
5483 goto repeat;
5484 }
5485 return newfd;
5486}
5487static int
5488xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5489{
5490 int newfd;
5491 repeat:
5492 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5493 if (newfd < 0) {
5494 if (errno == EBUSY)
5495 goto repeat;
5496 if (errno == EINTR)
5497 goto repeat;
5498
5499 if (errno == EBADF)
5500 return fd;
5501 ash_msg_and_raise_perror("%d", newfd);
5502 }
5503 if (F_DUPFD_CLOEXEC == F_DUPFD)
5504 close_on_exec_on(newfd);
5505 close(fd);
5506 return newfd;
5507}
5508
5509
5510struct squirrel {
5511 int orig_fd;
5512 int moved_to;
5513};
5514struct redirtab {
5515 struct redirtab *next;
5516 int pair_count;
5517 struct squirrel two_fd[];
5518};
5519#define redirlist (G_var.redirlist)
5520
5521static void
5522add_squirrel_closed(struct redirtab *sq, int fd)
5523{
5524 int i;
5525
5526 if (!sq)
5527 return;
5528
5529 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5530
5531 if (fd == sq->two_fd[i].orig_fd) {
5532
5533
5534
5535
5536
5537
5538 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5539 return;
5540 }
5541 }
5542 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5543 sq->two_fd[i].orig_fd = fd;
5544 sq->two_fd[i].moved_to = CLOSED;
5545}
5546
5547static int
5548save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5549{
5550 int i, new_fd;
5551
5552 if (avoid_fd < 9)
5553 avoid_fd = 9;
5554
5555#if JOBS
5556 if (fd == ttyfd) {
5557
5558 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5559 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5560 return 1;
5561 }
5562#endif
5563
5564
5565
5566
5567 if (!sq)
5568 return 0;
5569
5570
5571 if (fd != 0) {
5572 struct parsefile *pf = g_parsefile;
5573 while (pf) {
5574
5575
5576
5577
5578
5579
5580
5581
5582 if (fd == pf->pf_fd) {
5583 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5584 return 1;
5585 }
5586 pf = pf->prev;
5587 }
5588 }
5589
5590
5591
5592
5593 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5594
5595 if (fd == sq->two_fd[i].moved_to) {
5596 new_fd = dup_CLOEXEC(fd, avoid_fd);
5597 sq->two_fd[i].moved_to = new_fd;
5598 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5599 if (new_fd < 0)
5600 xfunc_die();
5601 return 0;
5602 }
5603 if (fd == sq->two_fd[i].orig_fd) {
5604
5605 TRACE(("redirect_fd %d: already moved\n", fd));
5606 return 0;
5607 }
5608 }
5609
5610
5611 new_fd = dup_CLOEXEC(fd, avoid_fd);
5612 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5613 if (new_fd < 0) {
5614 if (errno != EBADF)
5615 xfunc_die();
5616
5617 }
5618 sq->two_fd[i].moved_to = new_fd;
5619 sq->two_fd[i].orig_fd = fd;
5620
5621
5622 if (fd == preverrout_fd)
5623 preverrout_fd = new_fd;
5624
5625 return 0;
5626}
5627
5628static int
5629internally_opened_fd(int fd, struct redirtab *sq)
5630{
5631 int i;
5632#if JOBS
5633 if (fd == ttyfd)
5634 return 1;
5635#endif
5636
5637 if (fd != 0) {
5638 struct parsefile *pf = g_parsefile;
5639 while (pf) {
5640 if (fd == pf->pf_fd)
5641 return 1;
5642 pf = pf->prev;
5643 }
5644 }
5645
5646 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5647 if (fd == sq->two_fd[i].moved_to)
5648 return 1;
5649 }
5650 return 0;
5651}
5652
5653
5654
5655
5656
5657
5658
5659#define REDIR_PUSH 01
5660static void
5661redirect(union node *redir, int flags)
5662{
5663 struct redirtab *sv;
5664
5665 if (!redir)
5666 return;
5667
5668 sv = NULL;
5669 INT_OFF;
5670 if (flags & REDIR_PUSH)
5671 sv = redirlist;
5672 do {
5673 int fd;
5674 int newfd;
5675 int close_fd;
5676 int closed;
5677
5678 fd = redir->nfile.fd;
5679 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5680
5681 newfd = redir->ndup.dupfd;
5682 close_fd = -1;
5683 } else {
5684 newfd = openredirect(redir);
5685 if (fd == newfd) {
5686
5687
5688
5689
5690
5691 add_squirrel_closed(sv, fd);
5692 continue;
5693 }
5694 close_fd = newfd;
5695 }
5696
5697 if (fd == newfd)
5698 continue;
5699
5700
5701
5702
5703
5704 IF_BASH_REDIR_OUTPUT(redirect_more:)
5705
5706 closed = save_fd_on_redirect(fd, newfd, sv);
5707 if (newfd == -1) {
5708
5709 if (!closed) {
5710
5711
5712 close(fd);
5713 }
5714 } else {
5715
5716 if (internally_opened_fd(newfd, sv)) {
5717 errno = EBADF;
5718 ash_msg_and_raise_perror("%d", newfd);
5719 }
5720 dup2_or_raise(newfd, fd);
5721 if (close_fd >= 0)
5722 close(close_fd);
5723#if BASH_REDIR_OUTPUT
5724 if (redir->nfile.type == NTO2 && fd == 1) {
5725
5726 fd = 2;
5727 newfd = 1;
5728 close_fd = -1;
5729 goto redirect_more;
5730 }
5731#endif
5732 }
5733 } while ((redir = redir->nfile.next) != NULL);
5734 INT_ON;
5735
5736
5737#define REDIR_SAVEFD2 0
5738
5739
5740
5741
5742
5743
5744}
5745
5746static int
5747redirectsafe(union node *redir, int flags)
5748{
5749 int err;
5750 volatile int saveint;
5751 struct jmploc *volatile savehandler = exception_handler;
5752 struct jmploc jmploc;
5753
5754 SAVE_INT(saveint);
5755
5756 err = setjmp(jmploc.loc);
5757 if (!err) {
5758 exception_handler = &jmploc;
5759 redirect(redir, flags);
5760 }
5761 exception_handler = savehandler;
5762 if (err && exception_type != EXERROR)
5763 longjmp(exception_handler->loc, 1);
5764 RESTORE_INT(saveint);
5765 return err;
5766}
5767
5768static struct redirtab*
5769pushredir(union node *redir)
5770{
5771 struct redirtab *sv;
5772 int i;
5773
5774 if (!redir)
5775 return redirlist;
5776
5777 i = 0;
5778 do {
5779 i++;
5780#if BASH_REDIR_OUTPUT
5781 if (redir->nfile.type == NTO2)
5782 i++;
5783#endif
5784 redir = redir->nfile.next;
5785 } while (redir);
5786
5787 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5788 sv->pair_count = i;
5789 while (--i >= 0)
5790 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
5791 sv->next = redirlist;
5792 redirlist = sv;
5793 return sv->next;
5794}
5795
5796
5797
5798
5799static void
5800popredir(int drop)
5801{
5802 struct redirtab *rp;
5803 int i;
5804
5805 if (redirlist == NULL)
5806 return;
5807 INT_OFF;
5808 rp = redirlist;
5809 for (i = 0; i < rp->pair_count; i++) {
5810 int fd = rp->two_fd[i].orig_fd;
5811 int copy = rp->two_fd[i].moved_to;
5812 if (copy == CLOSED) {
5813 if (!drop)
5814 close(fd);
5815 continue;
5816 }
5817 if (copy != EMPTY) {
5818 if (!drop) {
5819
5820 dup2_or_raise(copy, fd);
5821 }
5822 close(copy);
5823 }
5824 }
5825 redirlist = rp->next;
5826 free(rp);
5827 INT_ON;
5828}
5829
5830static void
5831unwindredir(struct redirtab *stop)
5832{
5833 while (redirlist != stop)
5834 popredir( 0);
5835}
5836
5837
5838
5839
5840
5841
5842
5843#if ENABLE_FEATURE_SH_MATH
5844static arith_t
5845ash_arith(const char *s)
5846{
5847 arith_state_t math_state;
5848 arith_t result;
5849
5850 math_state.lookupvar = lookupvar;
5851 math_state.setvar = setvar0;
5852
5853
5854 INT_OFF;
5855 result = arith(&math_state, s);
5856 if (math_state.errmsg)
5857 ash_msg_and_raise_error(math_state.errmsg);
5858 INT_ON;
5859
5860 return result;
5861}
5862#endif
5863#if BASH_SUBSTR
5864# if ENABLE_FEATURE_SH_MATH
5865static int substr_atoi(const char *s)
5866{
5867 arith_t t = ash_arith(s);
5868 if (sizeof(t) > sizeof(int)) {
5869
5870
5871
5872 if (t > INT_MAX)
5873 t = INT_MAX;
5874 if (t < INT_MIN)
5875 t = INT_MIN;
5876 }
5877 return t;
5878}
5879# else
5880# define substr_atoi(s) number(s)
5881# endif
5882#endif
5883
5884
5885
5886
5887#define EXP_FULL 0x1
5888#define EXP_TILDE 0x2
5889#define EXP_VARTILDE 0x4
5890#define EXP_REDIR 0x8
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902#define EXP_CASE 0x10
5903#define EXP_VARTILDE2 0x20
5904#define EXP_WORD 0x40
5905#define EXP_QUOTED 0x80
5906
5907
5908
5909#define RMESCAPE_ALLOC 0x1
5910#define RMESCAPE_GLOB 0x2
5911#define RMESCAPE_GROW 0x8
5912#define RMESCAPE_HEAP 0x10
5913
5914
5915#define QUOTES_ESC (EXP_FULL | EXP_CASE)
5916
5917#define QUOTES_KEEPNUL EXP_TILDE
5918
5919
5920
5921
5922
5923struct ifsregion {
5924 struct ifsregion *next;
5925 int begoff;
5926 int endoff;
5927 int nulonly;
5928};
5929
5930struct arglist {
5931 struct strlist *list;
5932 struct strlist **lastp;
5933};
5934
5935
5936static char *expdest;
5937
5938static struct nodelist *argbackq;
5939
5940static struct ifsregion ifsfirst;
5941
5942static struct ifsregion *ifslastp;
5943
5944static struct arglist exparg;
5945
5946
5947
5948
5949
5950static int
5951cvtnum(arith_t num)
5952{
5953 int len;
5954
5955
5956 len = sizeof(arith_t) * 3;
5957
5958 if (sizeof(arith_t) < 4) len += 2;
5959
5960 expdest = makestrspace(len, expdest);
5961 len = fmtstr(expdest, len, ARITH_FMT, num);
5962 STADJUST(len, expdest);
5963 return len;
5964}
5965
5966
5967
5968
5969
5970
5971static void
5972ifsbreakup(char *string, struct arglist *arglist)
5973{
5974 struct ifsregion *ifsp;
5975 struct strlist *sp;
5976 char *start;
5977 char *p;
5978 char *q;
5979 const char *ifs, *realifs;
5980 int ifsspc;
5981 int nulonly;
5982
5983 start = string;
5984 if (ifslastp != NULL) {
5985 ifsspc = 0;
5986 nulonly = 0;
5987 realifs = ifsset() ? ifsval() : defifs;
5988 ifsp = &ifsfirst;
5989 do {
5990 int afternul;
5991
5992 p = string + ifsp->begoff;
5993 afternul = nulonly;
5994 nulonly = ifsp->nulonly;
5995 ifs = nulonly ? nullstr : realifs;
5996 ifsspc = 0;
5997 while (p < string + ifsp->endoff) {
5998 q = p;
5999 if ((unsigned char)*p == CTLESC)
6000 p++;
6001 if (!strchr(ifs, *p)) {
6002 p++;
6003 continue;
6004 }
6005 if (!(afternul || nulonly))
6006 ifsspc = (strchr(defifs, *p) != NULL);
6007
6008 if (q == start && ifsspc) {
6009 p++;
6010 start = p;
6011 continue;
6012 }
6013 *q = '\0';
6014 sp = stzalloc(sizeof(*sp));
6015 sp->text = start;
6016 *arglist->lastp = sp;
6017 arglist->lastp = &sp->next;
6018 p++;
6019 if (!nulonly) {
6020 for (;;) {
6021 if (p >= string + ifsp->endoff) {
6022 break;
6023 }
6024 q = p;
6025 if ((unsigned char)*p == CTLESC)
6026 p++;
6027 if (strchr(ifs, *p) == NULL) {
6028 p = q;
6029 break;
6030 }
6031 if (strchr(defifs, *p) == NULL) {
6032 if (ifsspc) {
6033 p++;
6034 ifsspc = 0;
6035 } else {
6036 p = q;
6037 break;
6038 }
6039 } else
6040 p++;
6041 }
6042 }
6043 start = p;
6044 }
6045 ifsp = ifsp->next;
6046 } while (ifsp != NULL);
6047 if (nulonly)
6048 goto add;
6049 }
6050
6051 if (!*start)
6052 return;
6053
6054 add:
6055 sp = stzalloc(sizeof(*sp));
6056 sp->text = start;
6057 *arglist->lastp = sp;
6058 arglist->lastp = &sp->next;
6059}
6060
6061static void
6062ifsfree(void)
6063{
6064 struct ifsregion *p = ifsfirst.next;
6065
6066 if (!p)
6067 goto out;
6068
6069 INT_OFF;
6070 do {
6071 struct ifsregion *ifsp;
6072 ifsp = p->next;
6073 free(p);
6074 p = ifsp;
6075 } while (p);
6076 ifsfirst.next = NULL;
6077 INT_ON;
6078 out:
6079 ifslastp = NULL;
6080}
6081
6082static size_t
6083esclen(const char *start, const char *p)
6084{
6085 size_t esc = 0;
6086
6087 while (p > start && (unsigned char)*--p == CTLESC) {
6088 esc++;
6089 }
6090 return esc;
6091}
6092
6093
6094
6095
6096#if !BASH_PATTERN_SUBST
6097#define rmescapes(str, flag, slash_position) \
6098 rmescapes(str, flag)
6099#endif
6100static char *
6101rmescapes(char *str, int flag, int *slash_position)
6102{
6103 static const char qchars[] ALIGN1 = {
6104 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
6105
6106 char *p, *q, *r;
6107 unsigned protect_against_glob;
6108 unsigned globbing;
6109
6110 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
6111 if (!p)
6112 return str;
6113
6114 q = p;
6115 r = str;
6116 if (flag & RMESCAPE_ALLOC) {
6117 size_t len = p - str;
6118 size_t fulllen = len + strlen(p) + 1;
6119
6120 if (flag & RMESCAPE_GROW) {
6121 int strloc = str - (char *)stackblock();
6122 r = makestrspace(fulllen, expdest);
6123
6124 str = (char *)stackblock() + strloc;
6125 p = str + len;
6126 } else if (flag & RMESCAPE_HEAP) {
6127 r = ckmalloc(fulllen);
6128 } else {
6129 r = stalloc(fulllen);
6130 }
6131 q = r;
6132 if (len > 0) {
6133 q = (char *)mempcpy(q, str, len);
6134 }
6135 }
6136
6137 globbing = flag & RMESCAPE_GLOB;
6138 protect_against_glob = globbing;
6139 while (*p) {
6140 if ((unsigned char)*p == CTLQUOTEMARK) {
6141
6142
6143 p++;
6144 protect_against_glob = globbing;
6145 continue;
6146 }
6147 if (*p == '\\') {
6148
6149 protect_against_glob = 0;
6150 goto copy;
6151 }
6152 if ((unsigned char)*p == CTLESC) {
6153 p++;
6154#if DEBUG
6155 if (*p == '\0')
6156 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6157#endif
6158 if (protect_against_glob) {
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174 if (*p == '*'
6175 || *p == '?'
6176 || *p == '['
6177 || *p == '\\'
6178 || *p == ']'
6179 || *p == '-'
6180 || *p == '!'
6181
6182 || *p == '^'
6183 ) {
6184 *q++ = '\\';
6185 }
6186 }
6187 }
6188#if BASH_PATTERN_SUBST
6189 else if (slash_position && p == str + *slash_position) {
6190
6191 globbing = 0;
6192 *slash_position = q - r;
6193 slash_position = NULL;
6194 }
6195#endif
6196 protect_against_glob = globbing;
6197 copy:
6198 *q++ = *p++;
6199 }
6200 *q = '\0';
6201 if (flag & RMESCAPE_GROW) {
6202 expdest = r;
6203 STADJUST(q - r + 1, expdest);
6204 }
6205 return r;
6206}
6207#define pmatch(a, b) !fnmatch((a), (b), 0)
6208
6209
6210
6211
6212
6213
6214static char *
6215preglob(const char *pattern, int flag)
6216{
6217 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
6218}
6219
6220
6221
6222
6223static void
6224memtodest(const char *p, size_t len, int syntax, int quotes)
6225{
6226 char *q;
6227
6228 if (!len)
6229 return;
6230
6231 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6232
6233 do {
6234 unsigned char c = *p++;
6235 if (c) {
6236 if (quotes & QUOTES_ESC) {
6237 int n = SIT(c, syntax);
6238 if (n == CCTL
6239 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
6240 && n == CBACK
6241 )
6242 ) {
6243 USTPUTC(CTLESC, q);
6244 }
6245 }
6246 } else if (!(quotes & QUOTES_KEEPNUL))
6247 continue;
6248 USTPUTC(c, q);
6249 } while (--len);
6250
6251 expdest = q;
6252}
6253
6254static size_t
6255strtodest(const char *p, int syntax, int quotes)
6256{
6257 size_t len = strlen(p);
6258 memtodest(p, len, syntax, quotes);
6259 return len;
6260}
6261
6262
6263
6264
6265
6266static void
6267recordregion(int start, int end, int nulonly)
6268{
6269 struct ifsregion *ifsp;
6270
6271 if (ifslastp == NULL) {
6272 ifsp = &ifsfirst;
6273 } else {
6274 INT_OFF;
6275 ifsp = ckzalloc(sizeof(*ifsp));
6276
6277 ifslastp->next = ifsp;
6278 INT_ON;
6279 }
6280 ifslastp = ifsp;
6281 ifslastp->begoff = start;
6282 ifslastp->endoff = end;
6283 ifslastp->nulonly = nulonly;
6284}
6285
6286static void
6287removerecordregions(int endoff)
6288{
6289 if (ifslastp == NULL)
6290 return;
6291
6292 if (ifsfirst.endoff > endoff) {
6293 while (ifsfirst.next) {
6294 struct ifsregion *ifsp;
6295 INT_OFF;
6296 ifsp = ifsfirst.next->next;
6297 free(ifsfirst.next);
6298 ifsfirst.next = ifsp;
6299 INT_ON;
6300 }
6301 if (ifsfirst.begoff > endoff) {
6302 ifslastp = NULL;
6303 } else {
6304 ifslastp = &ifsfirst;
6305 ifsfirst.endoff = endoff;
6306 }
6307 return;
6308 }
6309
6310 ifslastp = &ifsfirst;
6311 while (ifslastp->next && ifslastp->next->begoff < endoff)
6312 ifslastp = ifslastp->next;
6313 while (ifslastp->next) {
6314 struct ifsregion *ifsp;
6315 INT_OFF;
6316 ifsp = ifslastp->next->next;
6317 free(ifslastp->next);
6318 ifslastp->next = ifsp;
6319 INT_ON;
6320 }
6321 if (ifslastp->endoff > endoff)
6322 ifslastp->endoff = endoff;
6323}
6324
6325static char *
6326exptilde(char *startp, char *p, int flags)
6327{
6328 unsigned char c;
6329 char *name;
6330 struct passwd *pw;
6331 const char *home;
6332 int quotes = flags & QUOTES_ESC;
6333
6334 name = p + 1;
6335
6336 while ((c = *++p) != '\0') {
6337 switch (c) {
6338 case CTLESC:
6339 return startp;
6340 case CTLQUOTEMARK:
6341 return startp;
6342 case ':':
6343 if (flags & EXP_VARTILDE)
6344 goto done;
6345 break;
6346 case '/':
6347 case CTLENDVAR:
6348 goto done;
6349 }
6350 }
6351 done:
6352 *p = '\0';
6353 if (*name == '\0') {
6354 home = lookupvar("HOME");
6355 } else {
6356 pw = getpwnam(name);
6357 if (pw == NULL)
6358 goto lose;
6359 home = pw->pw_dir;
6360 }
6361 if (!home || !*home)
6362 goto lose;
6363 *p = c;
6364 strtodest(home, SQSYNTAX, quotes);
6365 return p;
6366 lose:
6367 *p = c;
6368 return startp;
6369}
6370
6371
6372
6373
6374
6375
6376
6377struct backcmd {
6378 int fd;
6379 int nleft;
6380 char *buf;
6381 struct job *jp;
6382};
6383
6384
6385
6386#define EV_EXIT 01
6387#define EV_TESTED 02
6388static int evaltree(union node *, int);
6389
6390
6391
6392
6393
6394
6395static ALWAYS_INLINE NORETURN void
6396evaltreenr(union node *n, int flags)
6397{
6398 evaltree(n, flags);
6399 bb_unreachable(abort());
6400
6401}
6402
6403static void FAST_FUNC
6404evalbackcmd(union node *n, struct backcmd *result)
6405{
6406 int pip[2];
6407 struct job *jp;
6408
6409 result->fd = -1;
6410 result->buf = NULL;
6411 result->nleft = 0;
6412 result->jp = NULL;
6413 if (n == NULL) {
6414 goto out;
6415 }
6416
6417 if (pipe(pip) < 0)
6418 ash_msg_and_raise_perror("can't create pipe");
6419 jp = makejob( 1);
6420 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6421
6422 FORCE_INT_ON;
6423 close(pip[0]);
6424 if (pip[1] != 1) {
6425
6426 dup2_or_raise(pip[1], 1);
6427 close(pip[1]);
6428 }
6429
6430
6431
6432
6433
6434
6435
6436
6437 eflag = 0;
6438 ifsfree();
6439 evaltreenr(n, EV_EXIT);
6440
6441 }
6442
6443 close(pip[1]);
6444 result->fd = pip[0];
6445 result->jp = jp;
6446
6447 out:
6448 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6449 result->fd, result->buf, result->nleft, result->jp));
6450}
6451
6452
6453
6454
6455static void
6456expbackq(union node *cmd, int flag)
6457{
6458 struct backcmd in;
6459 int i;
6460 char buf[128];
6461 char *p;
6462 char *dest;
6463 int startloc;
6464 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6465 struct stackmark smark;
6466
6467 INT_OFF;
6468 startloc = expdest - (char *)stackblock();
6469 pushstackmark(&smark, startloc);
6470 evalbackcmd(cmd, &in);
6471 popstackmark(&smark);
6472
6473 p = in.buf;
6474 i = in.nleft;
6475 if (i == 0)
6476 goto read;
6477 for (;;) {
6478 memtodest(p, i, syntax, flag & QUOTES_ESC);
6479 read:
6480 if (in.fd < 0)
6481 break;
6482 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6483 TRACE(("expbackq: read returns %d\n", i));
6484 if (i <= 0)
6485 break;
6486 p = buf;
6487 }
6488
6489 free(in.buf);
6490 if (in.fd >= 0) {
6491 close(in.fd);
6492 back_exitstatus = waitforjob(in.jp);
6493 }
6494 INT_ON;
6495
6496
6497 dest = expdest;
6498 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6499 STUNPUTC(dest);
6500 expdest = dest;
6501
6502 if (!(flag & EXP_QUOTED))
6503 recordregion(startloc, dest - (char *)stackblock(), 0);
6504 TRACE(("evalbackq: size:%d:'%.*s'\n",
6505 (int)((dest - (char *)stackblock()) - startloc),
6506 (int)((dest - (char *)stackblock()) - startloc),
6507 stackblock() + startloc));
6508}
6509
6510#if ENABLE_FEATURE_SH_MATH
6511
6512
6513
6514
6515static void
6516expari(int flag)
6517{
6518 char *p, *start;
6519 int begoff;
6520 int len;
6521
6522
6523
6524
6525
6526
6527
6528
6529 start = stackblock();
6530 p = expdest - 1;
6531 *p = '\0';
6532 p--;
6533 while (1) {
6534 int esc;
6535
6536 while ((unsigned char)*p != CTLARI) {
6537 p--;
6538#if DEBUG
6539 if (p < start) {
6540 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6541 }
6542#endif
6543 }
6544
6545 esc = esclen(start, p);
6546 if (!(esc % 2)) {
6547 break;
6548 }
6549
6550 p -= esc + 1;
6551 }
6552
6553 begoff = p - start;
6554
6555 removerecordregions(begoff);
6556
6557 expdest = p;
6558
6559 if (flag & QUOTES_ESC)
6560 rmescapes(p + 1, 0, NULL);
6561
6562 len = cvtnum(ash_arith(p + 1));
6563
6564 if (!(flag & EXP_QUOTED))
6565 recordregion(begoff, begoff + len, 0);
6566}
6567#endif
6568
6569
6570static char *evalvar(char *p, int flags);
6571
6572
6573
6574
6575
6576
6577static void
6578argstr(char *p, int flags)
6579{
6580 static const char spclchars[] ALIGN1 = {
6581 '=',
6582 ':',
6583 CTLQUOTEMARK,
6584 CTLENDVAR,
6585 CTLESC,
6586 CTLVAR,
6587 CTLBACKQ,
6588#if ENABLE_FEATURE_SH_MATH
6589 CTLENDARI,
6590#endif
6591 '\0'
6592 };
6593 const char *reject = spclchars;
6594 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6595 int inquotes;
6596 size_t length;
6597 int startloc;
6598
6599 if (!(flags & EXP_VARTILDE)) {
6600 reject += 2;
6601 } else if (flags & EXP_VARTILDE2) {
6602 reject++;
6603 }
6604 inquotes = 0;
6605 length = 0;
6606 if (flags & EXP_TILDE) {
6607 char *q;
6608
6609 flags &= ~EXP_TILDE;
6610 tilde:
6611 q = p;
6612 if (*q == '~')
6613 p = exptilde(p, q, flags);
6614 }
6615 start:
6616 startloc = expdest - (char *)stackblock();
6617 for (;;) {
6618 unsigned char c;
6619
6620 length += strcspn(p + length, reject);
6621 c = p[length];
6622 if (c) {
6623 if (!(c & 0x80)
6624 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6625 ) {
6626
6627 length++;
6628 }
6629 }
6630 if (length > 0) {
6631 int newloc;
6632 expdest = stack_nputstr(p, length, expdest);
6633 newloc = expdest - (char *)stackblock();
6634 if (breakall && !inquotes && newloc > startloc) {
6635 recordregion(startloc, newloc, 0);
6636 }
6637 startloc = newloc;
6638 }
6639 p += length + 1;
6640 length = 0;
6641
6642 switch (c) {
6643 case '\0':
6644 goto breakloop;
6645 case '=':
6646 if (flags & EXP_VARTILDE2) {
6647 p--;
6648 continue;
6649 }
6650 flags |= EXP_VARTILDE2;
6651 reject++;
6652
6653 case ':':
6654
6655
6656
6657
6658 if (*--p == '~') {
6659 goto tilde;
6660 }
6661 continue;
6662 }
6663
6664 switch (c) {
6665 case CTLENDVAR:
6666 goto breakloop;
6667 case CTLQUOTEMARK:
6668
6669 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6670 p = evalvar(p + 1, flags | EXP_QUOTED) + 1;
6671 goto start;
6672 }
6673 inquotes ^= EXP_QUOTED;
6674 addquote:
6675 if (flags & QUOTES_ESC) {
6676 p--;
6677 length++;
6678 startloc++;
6679 }
6680 break;
6681 case CTLESC:
6682 startloc++;
6683 length++;
6684 goto addquote;
6685 case CTLVAR:
6686 TRACE(("argstr: evalvar('%s')\n", p));
6687 p = evalvar(p, flags | inquotes);
6688 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6689 goto start;
6690 case CTLBACKQ:
6691 expbackq(argbackq->n, flags | inquotes);
6692 argbackq = argbackq->next;
6693 goto start;
6694#if ENABLE_FEATURE_SH_MATH
6695 case CTLENDARI:
6696 p--;
6697 expari(flags | inquotes);
6698 goto start;
6699#endif
6700 }
6701 }
6702 breakloop: ;
6703}
6704
6705static char *
6706scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6707 char *pattern, int quotes, int zero)
6708{
6709 char *loc, *loc2;
6710 char c;
6711
6712 loc = startp;
6713 loc2 = rmesc;
6714 do {
6715 int match;
6716 const char *s = loc2;
6717
6718 c = *loc2;
6719 if (zero) {
6720 *loc2 = '\0';
6721 s = rmesc;
6722 }
6723 match = pmatch(pattern, s);
6724
6725 *loc2 = c;
6726 if (match)
6727 return loc;
6728 if (quotes && (unsigned char)*loc == CTLESC)
6729 loc++;
6730 loc++;
6731 loc2++;
6732 } while (c);
6733 return NULL;
6734}
6735
6736static char *
6737scanright(char *startp, char *rmesc, char *rmescend,
6738 char *pattern, int quotes, int match_at_start)
6739{
6740#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6741 int try2optimize = match_at_start;
6742#endif
6743 int esc = 0;
6744 char *loc;
6745 char *loc2;
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755
6756
6757 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6758 int match;
6759 char c = *loc2;
6760 const char *s = loc2;
6761 if (match_at_start) {
6762 *loc2 = '\0';
6763 s = rmesc;
6764 }
6765 match = pmatch(pattern, s);
6766
6767 *loc2 = c;
6768 if (match)
6769 return loc;
6770#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6771 if (try2optimize) {
6772
6773
6774
6775
6776
6777 unsigned plen = strlen(pattern);
6778
6779 if (plen != 0 && pattern[--plen] == '*') {
6780
6781
6782
6783
6784 int slashes = 0;
6785 while (plen != 0 && pattern[--plen] == '\\')
6786 slashes++;
6787 if (!(slashes & 1))
6788 break;
6789 }
6790 try2optimize = 0;
6791 }
6792#endif
6793 loc--;
6794 if (quotes) {
6795 if (--esc < 0) {
6796 esc = esclen(startp, loc);
6797 }
6798 if (esc % 2) {
6799 esc--;
6800 loc--;
6801 }
6802 }
6803 }
6804 return NULL;
6805}
6806
6807static void varunset(const char *, const char *, const char *, int) NORETURN;
6808static void
6809varunset(const char *end, const char *var, const char *umsg, int varflags)
6810{
6811 const char *msg;
6812 const char *tail;
6813
6814 tail = nullstr;
6815 msg = "parameter not set";
6816 if (umsg) {
6817 if ((unsigned char)*end == CTLENDVAR) {
6818 if (varflags & VSNUL)
6819 tail = " or null";
6820 } else {
6821 msg = umsg;
6822 }
6823 }
6824 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6825}
6826
6827static const char *
6828subevalvar(char *p, char *varname, int strloc, int subtype,
6829 int startloc, int varflags, int flag)
6830{
6831 struct nodelist *saveargbackq = argbackq;
6832 int quotes = flag & QUOTES_ESC;
6833 char *startp;
6834 char *loc;
6835 char *rmesc, *rmescend;
6836 char *str;
6837 int amount, resetloc;
6838 int argstr_flags;
6839 IF_BASH_PATTERN_SUBST(int workloc;)
6840 IF_BASH_PATTERN_SUBST(int slash_pos;)
6841 IF_BASH_PATTERN_SUBST(char *repl;)
6842 int zero;
6843 char *(*scan)(char*, char*, char*, char*, int, int);
6844
6845
6846
6847
6848#if BASH_PATTERN_SUBST
6849
6850
6851
6852
6853 repl = NULL;
6854 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6855
6856 repl = p;
6857 for (;;) {
6858
6859 if (*repl == '\0') {
6860 repl = NULL;
6861 break;
6862 }
6863 if (*repl == '/') {
6864 *repl = '\0';
6865 break;
6866 }
6867 if ((unsigned char)*repl == CTLESC && repl[1])
6868 repl++;
6869 repl++;
6870 }
6871 }
6872#endif
6873 argstr_flags = EXP_TILDE;
6874 if (subtype != VSASSIGN
6875 && subtype != VSQUESTION
6876#if BASH_SUBSTR
6877 && subtype != VSSUBSTR
6878#endif
6879 ) {
6880
6881 argstr_flags = EXP_TILDE | EXP_CASE;
6882 }
6883 argstr(p, argstr_flags);
6884
6885#if BASH_PATTERN_SUBST
6886 slash_pos = -1;
6887 if (repl) {
6888 slash_pos = expdest - ((char *)stackblock() + strloc);
6889 STPUTC('/', expdest);
6890
6891 argstr(repl + 1, EXP_TILDE);
6892 *repl = '/';
6893 }
6894#endif
6895 STPUTC('\0', expdest);
6896 argbackq = saveargbackq;
6897 startp = (char *)stackblock() + startloc;
6898
6899
6900 switch (subtype) {
6901 case VSASSIGN:
6902 setvar0(varname, startp);
6903 amount = startp - expdest;
6904 STADJUST(amount, expdest);
6905 return startp;
6906
6907 case VSQUESTION:
6908 varunset(p, varname, startp, varflags);
6909
6910
6911#if BASH_SUBSTR
6912 case VSSUBSTR: {
6913 int pos, len, orig_len;
6914 char *colon;
6915
6916 loc = str = stackblock() + strloc;
6917
6918
6919 colon = strchr(loc, ':');
6920 if (colon) *colon = '\0';
6921 pos = substr_atoi(loc);
6922 if (colon) *colon = ':';
6923
6924
6925 len = str - startp - 1;
6926
6927 if (quotes) {
6928 char *ptr;
6929
6930 for (ptr = startp; ptr < (str - 1); ptr++) {
6931 if ((unsigned char)*ptr == CTLESC) {
6932 len--;
6933 ptr++;
6934 }
6935 }
6936 }
6937 orig_len = len;
6938 if (*loc++ == ':') {
6939
6940 len = substr_atoi(loc);
6941 } else {
6942
6943 len = orig_len;
6944 while (*loc && *loc != ':')
6945 loc++;
6946 if (*loc++ == ':')
6947 len = substr_atoi(loc);
6948 }
6949 if (pos < 0) {
6950
6951 pos = orig_len + pos;
6952 }
6953 if ((unsigned)pos >= orig_len) {
6954
6955
6956
6957
6958 pos = 0;
6959 len = 0;
6960 }
6961 if (len < 0) {
6962
6963 len = (orig_len - pos) + len;
6964 }
6965 if ((unsigned)len > (orig_len - pos))
6966 len = orig_len - pos;
6967
6968 for (str = startp; pos; str++, pos--) {
6969 if (quotes && (unsigned char)*str == CTLESC)
6970 str++;
6971 }
6972 for (loc = startp; len; len--) {
6973 if (quotes && (unsigned char)*str == CTLESC)
6974 *loc++ = *str++;
6975 *loc++ = *str++;
6976 }
6977 *loc = '\0';
6978 amount = loc - expdest;
6979 STADJUST(amount, expdest);
6980 return loc;
6981 }
6982#endif
6983 }
6984
6985 resetloc = expdest - (char *)stackblock();
6986
6987#if BASH_PATTERN_SUBST
6988 repl = NULL;
6989
6990
6991
6992
6993
6994
6995 restart:
6996#endif
6997
6998 amount = expdest - ((char *)stackblock() + resetloc);
6999 STADJUST(-amount, expdest);
7000 startp = (char *)stackblock() + startloc;
7001
7002 rmesc = startp;
7003 rmescend = (char *)stackblock() + strloc;
7004
7005 if (quotes) {
7006
7007 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
7008 if (rmesc != startp) {
7009 rmescend = expdest;
7010 startp = (char *)stackblock() + startloc;
7011 }
7012 }
7013 rmescend--;
7014 str = (char *)stackblock() + strloc;
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024 rmescapes(str, RMESCAPE_GLOB,
7025 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7026 );
7027
7028#if BASH_PATTERN_SUBST
7029 workloc = expdest - (char *)stackblock();
7030 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7031 int len;
7032 char *idx, *end;
7033
7034 if (!repl) {
7035
7036 repl = nullstr;
7037 if (slash_pos >= 0) {
7038 repl = str + slash_pos;
7039 *repl++ = '\0';
7040 }
7041 }
7042
7043
7044
7045 if (str[0] == '\0')
7046 return NULL;
7047
7048 len = 0;
7049 idx = startp;
7050 end = str - 1;
7051 while (idx < end) {
7052 try_to_match:
7053 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
7054
7055 if (!loc) {
7056
7057 char *restart_detect = stackblock();
7058 skip_matching:
7059 STPUTC(*idx, expdest);
7060 if (quotes && (unsigned char)*idx == CTLESC) {
7061 idx++;
7062 len++;
7063 STPUTC(*idx, expdest);
7064 }
7065 if (stackblock() != restart_detect)
7066 goto restart;
7067 idx++;
7068 len++;
7069 rmesc++;
7070
7071 if (idx >= end)
7072 break;
7073 if (str[0] == '*') {
7074
7075
7076
7077 goto skip_matching;
7078 }
7079 goto try_to_match;
7080 }
7081
7082 if (subtype == VSREPLACEALL) {
7083 while (idx < loc) {
7084 if (quotes && (unsigned char)*idx == CTLESC)
7085 idx++;
7086 idx++;
7087 rmesc++;
7088 }
7089 } else {
7090 idx = loc;
7091 }
7092
7093
7094 for (loc = (char*)repl; *loc; loc++) {
7095 char *restart_detect = stackblock();
7096 if (quotes && *loc == '\\') {
7097 STPUTC(CTLESC, expdest);
7098 len++;
7099 }
7100 STPUTC(*loc, expdest);
7101 if (stackblock() != restart_detect)
7102 goto restart;
7103 len++;
7104 }
7105
7106 if (subtype == VSREPLACE) {
7107
7108 while (*idx) {
7109 char *restart_detect = stackblock();
7110 STPUTC(*idx, expdest);
7111 if (stackblock() != restart_detect)
7112 goto restart;
7113 len++;
7114 idx++;
7115 }
7116 break;
7117 }
7118 }
7119
7120
7121
7122
7123 STPUTC('\0', expdest);
7124 startp = (char *)stackblock() + startloc;
7125 memmove(startp, (char *)stackblock() + workloc, len + 1);
7126
7127 amount = expdest - (startp + len);
7128 STADJUST(-amount, expdest);
7129 return startp;
7130 }
7131#endif
7132
7133 subtype -= VSTRIMRIGHT;
7134#if DEBUG
7135 if (subtype < 0 || subtype > 7)
7136 abort();
7137#endif
7138
7139 zero = subtype >> 1;
7140
7141 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7142
7143 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7144 if (loc) {
7145 if (zero) {
7146 memmove(startp, loc, str - loc);
7147 loc = startp + (str - loc) - 1;
7148 }
7149 *loc = '\0';
7150 amount = loc - expdest;
7151 STADJUST(amount, expdest);
7152 }
7153 return loc;
7154}
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164
7165
7166
7167
7168
7169static NOINLINE ssize_t
7170varvalue(char *name, int varflags, int flags, int *quotedp)
7171{
7172 const char *p;
7173 int num;
7174 int i;
7175 ssize_t len = 0;
7176 int sep;
7177 int quoted = *quotedp;
7178 int subtype = varflags & VSTYPE;
7179 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7180 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
7181 int syntax;
7182
7183 sep = (flags & EXP_FULL) << CHAR_BIT;
7184 syntax = quoted ? DQSYNTAX : BASESYNTAX;
7185
7186 switch (*name) {
7187 case '$':
7188 num = rootpid;
7189 goto numvar;
7190 case '?':
7191 num = exitstatus;
7192 goto numvar;
7193 case '#':
7194 num = shellparam.nparam;
7195 goto numvar;
7196 case '!':
7197 num = backgndpid;
7198 if (num == 0)
7199 return -1;
7200 numvar:
7201 len = cvtnum(num);
7202 goto check_1char_name;
7203 case '-':
7204 expdest = makestrspace(NOPTS, expdest);
7205 for (i = NOPTS - 1; i >= 0; i--) {
7206 if (optlist[i] && optletters(i)) {
7207 USTPUTC(optletters(i), expdest);
7208 len++;
7209 }
7210 }
7211 check_1char_name:
7212#if 0
7213
7214 if (name[2] != '\0')
7215 raise_error_syntax("bad substitution");
7216#endif
7217 break;
7218 case '@':
7219 if (quoted && sep)
7220 goto param;
7221
7222 case '*': {
7223 char **ap;
7224 char sepc;
7225
7226 if (quoted)
7227 sep = 0;
7228 sep |= ifsset() ? ifsval()[0] : ' ';
7229 param:
7230 sepc = sep;
7231 *quotedp = !sepc;
7232 ap = shellparam.p;
7233 if (!ap)
7234 return -1;
7235 while ((p = *ap++) != NULL) {
7236 len += strtodest(p, syntax, quotes);
7237
7238 if (*ap && sep) {
7239 len++;
7240 memtodest(&sepc, 1, syntax, quotes);
7241 }
7242 }
7243 break;
7244 }
7245 case '0':
7246 case '1':
7247 case '2':
7248 case '3':
7249 case '4':
7250 case '5':
7251 case '6':
7252 case '7':
7253 case '8':
7254 case '9':
7255 num = atoi(name);
7256 if (num < 0 || num > shellparam.nparam)
7257 return -1;
7258 p = num ? shellparam.p[num - 1] : arg0;
7259 goto value;
7260 default:
7261
7262 p = lookupvar(name);
7263 value:
7264 if (!p)
7265 return -1;
7266
7267 len = strtodest(p, syntax, quotes);
7268#if ENABLE_UNICODE_SUPPORT
7269 if (subtype == VSLENGTH && len > 0) {
7270 reinit_unicode_for_ash();
7271 if (unicode_status == UNICODE_ON) {
7272 STADJUST(-len, expdest);
7273 discard = 0;
7274 len = unicode_strlen(p);
7275 }
7276 }
7277#endif
7278 break;
7279 }
7280
7281 if (discard)
7282 STADJUST(-len, expdest);
7283 return len;
7284}
7285
7286
7287
7288
7289
7290static char *
7291evalvar(char *p, int flag)
7292{
7293 char varflags;
7294 char subtype;
7295 int quoted;
7296 char easy;
7297 char *var;
7298 int patloc;
7299 int startloc;
7300 ssize_t varlen;
7301
7302 varflags = (unsigned char) *p++;
7303 subtype = varflags & VSTYPE;
7304
7305 if (!subtype)
7306 raise_error_syntax("bad substitution");
7307
7308 quoted = flag & EXP_QUOTED;
7309 var = p;
7310 easy = (!quoted || (*var == '@' && shellparam.nparam));
7311 startloc = expdest - (char *)stackblock();
7312 p = strchr(p, '=') + 1;
7313
7314 again:
7315 varlen = varvalue(var, varflags, flag, "ed);
7316 if (varflags & VSNUL)
7317 varlen--;
7318
7319 if (subtype == VSPLUS) {
7320 varlen = -1 - varlen;
7321 goto vsplus;
7322 }
7323
7324 if (subtype == VSMINUS) {
7325 vsplus:
7326 if (varlen < 0) {
7327 argstr(
7328 p,
7329 flag | EXP_TILDE | EXP_WORD
7330 );
7331 goto end;
7332 }
7333 goto record;
7334 }
7335
7336 if (subtype == VSASSIGN || subtype == VSQUESTION) {
7337 if (varlen >= 0)
7338 goto record;
7339
7340 subevalvar(p, var, 0, subtype, startloc, varflags,
7341 flag & ~QUOTES_ESC);
7342 varflags &= ~VSNUL;
7343
7344
7345
7346
7347 removerecordregions(startloc);
7348 goto again;
7349 }
7350
7351 if (varlen < 0 && uflag)
7352 varunset(p, var, 0, 0);
7353
7354 if (subtype == VSLENGTH) {
7355 cvtnum(varlen > 0 ? varlen : 0);
7356 goto record;
7357 }
7358
7359 if (subtype == VSNORMAL) {
7360 record:
7361 if (!easy)
7362 goto end;
7363 recordregion(startloc, expdest - (char *)stackblock(), quoted);
7364 goto end;
7365 }
7366
7367#if DEBUG
7368 switch (subtype) {
7369 case VSTRIMLEFT:
7370 case VSTRIMLEFTMAX:
7371 case VSTRIMRIGHT:
7372 case VSTRIMRIGHTMAX:
7373#if BASH_SUBSTR
7374 case VSSUBSTR:
7375#endif
7376#if BASH_PATTERN_SUBST
7377 case VSREPLACE:
7378 case VSREPLACEALL:
7379#endif
7380 break;
7381 default:
7382 abort();
7383 }
7384#endif
7385
7386 if (varlen >= 0) {
7387
7388
7389
7390
7391 STPUTC('\0', expdest);
7392 patloc = expdest - (char *)stackblock();
7393 if (NULL == subevalvar(p, NULL, patloc, subtype,
7394 startloc, varflags, flag)) {
7395 int amount = expdest - (
7396 (char *)stackblock() + patloc - 1
7397 );
7398 STADJUST(-amount, expdest);
7399 }
7400
7401 removerecordregions(startloc);
7402 goto record;
7403 }
7404
7405 end:
7406 if (subtype != VSNORMAL) {
7407 int nesting = 1;
7408 for (;;) {
7409 unsigned char c = *p++;
7410 if (c == CTLESC)
7411 p++;
7412 else if (c == CTLBACKQ) {
7413 if (varlen >= 0)
7414 argbackq = argbackq->next;
7415 } else if (c == CTLVAR) {
7416 if ((*p++ & VSTYPE) != VSNORMAL)
7417 nesting++;
7418 } else if (c == CTLENDVAR) {
7419 if (--nesting == 0)
7420 break;
7421 }
7422 }
7423 }
7424 return p;
7425}
7426
7427
7428
7429
7430static void
7431addfname(const char *name)
7432{
7433 struct strlist *sp;
7434
7435 sp = stzalloc(sizeof(*sp));
7436 sp->text = sstrdup(name);
7437 *exparg.lastp = sp;
7438 exparg.lastp = &sp->next;
7439}
7440
7441
7442static int
7443hasmeta(const char *p)
7444{
7445 static const char chars[] ALIGN1 = {
7446 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7447 };
7448
7449 for (;;) {
7450 p = strpbrk(p, chars);
7451 if (!p)
7452 break;
7453 switch ((unsigned char)*p) {
7454 case CTLQUOTEMARK:
7455 for (;;) {
7456 p++;
7457 if ((unsigned char)*p == CTLQUOTEMARK)
7458 break;
7459 if ((unsigned char)*p == CTLESC)
7460 p++;
7461 if (*p == '\0')
7462 return 0;
7463 }
7464 break;
7465 case '\\':
7466 case CTLESC:
7467 p++;
7468 if (*p == '\0')
7469 return 0;
7470 break;
7471 case '[':
7472 if (!strchr(p + 1, ']')) {
7473
7474
7475
7476
7477
7478 break;
7479 }
7480
7481 default:
7482
7483
7484 return 1;
7485 }
7486 p++;
7487 }
7488
7489 return 0;
7490}
7491
7492
7493#if !ENABLE_ASH_INTERNAL_GLOB
7494
7495
7496static void
7497addglob(const glob_t *pglob)
7498{
7499 char **p = pglob->gl_pathv;
7500
7501 do {
7502 addfname(*p);
7503 } while (*++p);
7504}
7505static void
7506expandmeta(struct strlist *str )
7507{
7508
7509
7510 while (str) {
7511 char *p;
7512 glob_t pglob;
7513 int i;
7514
7515 if (fflag)
7516 goto nometa;
7517
7518 if (!hasmeta(str->text))
7519 goto nometa;
7520
7521 INT_OFF;
7522 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539 i = glob(p, 0, NULL, &pglob);
7540
7541 if (p != str->text)
7542 free(p);
7543 switch (i) {
7544 case 0:
7545#if 0
7546
7547 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7548 goto nometa2;
7549#endif
7550 addglob(&pglob);
7551 globfree(&pglob);
7552 INT_ON;
7553 break;
7554 case GLOB_NOMATCH:
7555
7556 globfree(&pglob);
7557 INT_ON;
7558 nometa:
7559 *exparg.lastp = str;
7560 rmescapes(str->text, 0, NULL);
7561 exparg.lastp = &str->next;
7562 break;
7563 default:
7564 globfree(&pglob);
7565 INT_ON;
7566 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7567 }
7568 str = str->next;
7569 }
7570}
7571
7572#else
7573
7574
7575
7576
7577
7578typedef struct exp_t {
7579 char *dir;
7580 unsigned dir_max;
7581} exp_t;
7582static void
7583expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7584{
7585#define expdir exp->dir
7586#define expdir_max exp->dir_max
7587 char *enddir = expdir + expdir_len;
7588 char *p;
7589 const char *cp;
7590 char *start;
7591 char *endname;
7592 int metaflag;
7593 struct stat statb;
7594 DIR *dirp;
7595 struct dirent *dp;
7596 int atend;
7597 int matchdot;
7598 int esc;
7599
7600 metaflag = 0;
7601 start = name;
7602 for (p = name; esc = 0, *p; p += esc + 1) {
7603 if (*p == '*' || *p == '?')
7604 metaflag = 1;
7605 else if (*p == '[') {
7606 char *q = p + 1;
7607 if (*q == '!')
7608 q++;
7609 for (;;) {
7610 if (*q == '\\')
7611 q++;
7612 if (*q == '/' || *q == '\0')
7613 break;
7614 if (*++q == ']') {
7615 metaflag = 1;
7616 break;
7617 }
7618 }
7619 } else {
7620 if (*p == '\\')
7621 esc++;
7622 if (p[esc] == '/') {
7623 if (metaflag)
7624 break;
7625 start = p + esc + 1;
7626 }
7627 }
7628 }
7629 if (metaflag == 0) {
7630 if (!expdir_len)
7631 return;
7632 p = name;
7633 do {
7634 if (*p == '\\')
7635 p++;
7636 *enddir++ = *p;
7637 } while (*p++);
7638 if (lstat(expdir, &statb) == 0)
7639 addfname(expdir);
7640 return;
7641 }
7642 endname = p;
7643 if (name < start) {
7644 p = name;
7645 do {
7646 if (*p == '\\')
7647 p++;
7648 *enddir++ = *p++;
7649 } while (p < start);
7650 }
7651 *enddir = '\0';
7652 cp = expdir;
7653 expdir_len = enddir - cp;
7654 if (!expdir_len)
7655 cp = ".";
7656 dirp = opendir(cp);
7657 if (dirp == NULL)
7658 return;
7659 if (*endname == 0) {
7660 atend = 1;
7661 } else {
7662 atend = 0;
7663 *endname = '\0';
7664 endname += esc + 1;
7665 }
7666 name_len -= endname - name;
7667 matchdot = 0;
7668 p = start;
7669 if (*p == '\\')
7670 p++;
7671 if (*p == '.')
7672 matchdot++;
7673 while (!pending_int && (dp = readdir(dirp)) != NULL) {
7674 if (dp->d_name[0] == '.' && !matchdot)
7675 continue;
7676 if (pmatch(start, dp->d_name)) {
7677 if (atend) {
7678 strcpy(enddir, dp->d_name);
7679 addfname(expdir);
7680 } else {
7681 unsigned offset;
7682 unsigned len;
7683
7684 p = stpcpy(enddir, dp->d_name);
7685 *p = '/';
7686
7687 offset = p - expdir + 1;
7688 len = offset + name_len + NAME_MAX;
7689 if (len > expdir_max) {
7690 len += PATH_MAX;
7691 expdir = ckrealloc(expdir, len);
7692 expdir_max = len;
7693 }
7694
7695 expmeta(exp, endname, name_len, offset);
7696 enddir = expdir + expdir_len;
7697 }
7698 }
7699 }
7700 closedir(dirp);
7701 if (!atend)
7702 endname[-esc - 1] = esc ? '\\' : '/';
7703#undef expdir
7704#undef expdir_max
7705}
7706
7707static struct strlist *
7708msort(struct strlist *list, int len)
7709{
7710 struct strlist *p, *q = NULL;
7711 struct strlist **lpp;
7712 int half;
7713 int n;
7714
7715 if (len <= 1)
7716 return list;
7717 half = len >> 1;
7718 p = list;
7719 for (n = half; --n >= 0;) {
7720 q = p;
7721 p = p->next;
7722 }
7723 q->next = NULL;
7724 q = msort(list, half);
7725 p = msort(p, len - half);
7726 lpp = &list;
7727 for (;;) {
7728#if ENABLE_LOCALE_SUPPORT
7729 if (strcoll(p->text, q->text) < 0)
7730#else
7731 if (strcmp(p->text, q->text) < 0)
7732#endif
7733 {
7734 *lpp = p;
7735 lpp = &p->next;
7736 p = *lpp;
7737 if (p == NULL) {
7738 *lpp = q;
7739 break;
7740 }
7741 } else {
7742 *lpp = q;
7743 lpp = &q->next;
7744 q = *lpp;
7745 if (q == NULL) {
7746 *lpp = p;
7747 break;
7748 }
7749 }
7750 }
7751 return list;
7752}
7753
7754
7755
7756
7757
7758
7759static struct strlist *
7760expsort(struct strlist *str)
7761{
7762 int len;
7763 struct strlist *sp;
7764
7765 len = 0;
7766 for (sp = str; sp; sp = sp->next)
7767 len++;
7768 return msort(str, len);
7769}
7770
7771static void
7772expandmeta(struct strlist *str )
7773{
7774
7775
7776 while (str) {
7777 exp_t exp;
7778 struct strlist **savelastp;
7779 struct strlist *sp;
7780 char *p;
7781 unsigned len;
7782
7783 if (fflag)
7784 goto nometa;
7785 if (!hasmeta(str->text))
7786 goto nometa;
7787 savelastp = exparg.lastp;
7788
7789 INT_OFF;
7790 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7791 len = strlen(p);
7792 exp.dir_max = len + PATH_MAX;
7793 exp.dir = ckmalloc(exp.dir_max);
7794
7795 expmeta(&exp, p, len, 0);
7796 free(exp.dir);
7797 if (p != str->text)
7798 free(p);
7799 INT_ON;
7800 if (exparg.lastp == savelastp) {
7801
7802
7803
7804 nometa:
7805 *exparg.lastp = str;
7806 rmescapes(str->text, 0, NULL);
7807 exparg.lastp = &str->next;
7808 } else {
7809 *exparg.lastp = NULL;
7810 *savelastp = sp = expsort(*savelastp);
7811 while (sp->next != NULL)
7812 sp = sp->next;
7813 exparg.lastp = &sp->next;
7814 }
7815 str = str->next;
7816 }
7817}
7818#endif
7819
7820
7821
7822
7823
7824
7825
7826static void
7827expandarg(union node *arg, struct arglist *arglist, int flag)
7828{
7829 struct strlist *sp;
7830 char *p;
7831
7832 argbackq = arg->narg.backquote;
7833 STARTSTACKSTR(expdest);
7834 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7835 argstr(arg->narg.text, flag);
7836 p = _STPUTC('\0', expdest);
7837 expdest = p - 1;
7838 if (arglist == NULL) {
7839
7840 goto out;
7841 }
7842 p = grabstackstr(p);
7843 TRACE(("expandarg: p:'%s'\n", p));
7844 exparg.lastp = &exparg.list;
7845
7846
7847
7848 if (flag & EXP_FULL) {
7849 ifsbreakup(p, &exparg);
7850 *exparg.lastp = NULL;
7851 exparg.lastp = &exparg.list;
7852 expandmeta(exparg.list );
7853 } else {
7854 sp = stzalloc(sizeof(*sp));
7855 sp->text = p;
7856 *exparg.lastp = sp;
7857 exparg.lastp = &sp->next;
7858 }
7859 *exparg.lastp = NULL;
7860 if (exparg.list) {
7861 *arglist->lastp = exparg.list;
7862 arglist->lastp = exparg.lastp;
7863 }
7864
7865 out:
7866 ifsfree();
7867}
7868
7869
7870
7871
7872static void
7873expandhere(union node *arg, int fd)
7874{
7875 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7876 full_write(fd, stackblock(), expdest - (char *)stackblock());
7877}
7878
7879
7880
7881
7882static int
7883patmatch(char *pattern, const char *string)
7884{
7885 char *p = preglob(pattern, 0);
7886 int r = pmatch(p, string);
7887
7888 return r;
7889}
7890
7891
7892
7893
7894static int
7895casematch(union node *pattern, char *val)
7896{
7897 struct stackmark smark;
7898 int result;
7899
7900 setstackmark(&smark);
7901 argbackq = pattern->narg.backquote;
7902 STARTSTACKSTR(expdest);
7903 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
7904 STACKSTRNUL(expdest);
7905 ifsfree();
7906 result = patmatch(stackblock(), val);
7907 popstackmark(&smark);
7908 return result;
7909}
7910
7911
7912
7913
7914struct builtincmd {
7915 const char *name;
7916 int (*builtin)(int, char **) FAST_FUNC;
7917
7918};
7919#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7920
7921
7922#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7923#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
7924
7925struct cmdentry {
7926 smallint cmdtype;
7927 union param {
7928 int index;
7929
7930
7931
7932
7933 const struct builtincmd *cmd;
7934 struct funcnode *func;
7935 } u;
7936};
7937
7938#define CMDUNKNOWN -1
7939#define CMDNORMAL 0
7940#define CMDFUNCTION 1
7941#define CMDBUILTIN 2
7942
7943
7944#define DO_ERR 0x01
7945#define DO_ABS 0x02
7946#define DO_NOFUNC 0x04
7947#define DO_ALTPATH 0x08
7948#define DO_ALTBLTIN 0x20
7949
7950static void find_command(char *, struct cmdentry *, int, const char *);
7951
7952
7953
7954
7955
7956
7957
7958
7959
7960
7961
7962
7963
7964struct tblentry {
7965 struct tblentry *next;
7966 union param param;
7967 smallint cmdtype;
7968 char rehash;
7969 char cmdname[1];
7970};
7971
7972static struct tblentry **cmdtable;
7973#define INIT_G_cmdtable() do { \
7974 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7975} while (0)
7976
7977static int builtinloc = -1;
7978
7979
7980static void
7981tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
7982{
7983#if ENABLE_FEATURE_SH_STANDALONE
7984 if (applet_no >= 0) {
7985 if (APPLET_IS_NOEXEC(applet_no)) {
7986 clearenv();
7987 while (*envp)
7988 putenv(*envp++);
7989 popredir( 1);
7990 run_noexec_applet_and_exit(applet_no, cmd, argv);
7991 }
7992
7993 execve(bb_busybox_exec_path, argv, envp);
7994
7995
7996 }
7997#endif
7998
7999 repeat:
8000#ifdef SYSV
8001 do {
8002 execve(cmd, argv, envp);
8003 } while (errno == EINTR);
8004#else
8005 execve(cmd, argv, envp);
8006#endif
8007 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
8008
8009
8010
8011
8012
8013
8014
8015
8016
8017
8018
8019
8020
8021
8022
8023
8024 argv[0] = (char*) cmd;
8025 cmd = bb_busybox_exec_path;
8026
8027
8028
8029 argv--;
8030 argv[0] = (char*) "ash";
8031 goto repeat;
8032 }
8033}
8034
8035
8036
8037
8038
8039
8040static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8041static void shellexec(char *prog, char **argv, const char *path, int idx)
8042{
8043 char *cmdname;
8044 int e;
8045 char **envp;
8046 int exerrno;
8047 int applet_no = -1;
8048
8049 envp = listvars(VEXPORT, VUNSET, NULL, NULL);
8050 if (strchr(prog, '/') != NULL
8051#if ENABLE_FEATURE_SH_STANDALONE
8052 || (applet_no = find_applet_by_name(prog)) >= 0
8053#endif
8054 ) {
8055 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
8056 if (applet_no >= 0) {
8057
8058
8059
8060
8061 goto try_PATH;
8062 }
8063 e = errno;
8064 } else {
8065 try_PATH:
8066 e = ENOENT;
8067 while ((cmdname = path_advance(&path, prog)) != NULL) {
8068 if (--idx < 0 && pathopt == NULL) {
8069 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
8070 if (errno != ENOENT && errno != ENOTDIR)
8071 e = errno;
8072 }
8073 stunalloc(cmdname);
8074 }
8075 }
8076
8077
8078 switch (e) {
8079 case EACCES:
8080 exerrno = 126;
8081 break;
8082 case ENOENT:
8083 exerrno = 127;
8084 break;
8085 default:
8086 exerrno = 2;
8087 break;
8088 }
8089 exitstatus = exerrno;
8090 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
8091 prog, e, suppress_int));
8092 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
8093
8094}
8095
8096static void
8097printentry(struct tblentry *cmdp)
8098{
8099 int idx;
8100 const char *path;
8101 char *name;
8102
8103 idx = cmdp->param.index;
8104 path = pathval();
8105 do {
8106 name = path_advance(&path, cmdp->cmdname);
8107 stunalloc(name);
8108 } while (--idx >= 0);
8109 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8110}
8111
8112
8113
8114
8115
8116static void
8117clearcmdentry(int firstchange)
8118{
8119 struct tblentry **tblp;
8120 struct tblentry **pp;
8121 struct tblentry *cmdp;
8122
8123 INT_OFF;
8124 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8125 pp = tblp;
8126 while ((cmdp = *pp) != NULL) {
8127 if ((cmdp->cmdtype == CMDNORMAL &&
8128 cmdp->param.index >= firstchange)
8129 || (cmdp->cmdtype == CMDBUILTIN &&
8130 builtinloc >= firstchange)
8131 ) {
8132 *pp = cmdp->next;
8133 free(cmdp);
8134 } else {
8135 pp = &cmdp->next;
8136 }
8137 }
8138 }
8139 INT_ON;
8140}
8141
8142
8143
8144
8145
8146
8147
8148
8149
8150
8151static struct tblentry **lastcmdentry;
8152
8153static struct tblentry *
8154cmdlookup(const char *name, int add)
8155{
8156 unsigned int hashval;
8157 const char *p;
8158 struct tblentry *cmdp;
8159 struct tblentry **pp;
8160
8161 p = name;
8162 hashval = (unsigned char)*p << 4;
8163 while (*p)
8164 hashval += (unsigned char)*p++;
8165 hashval &= 0x7FFF;
8166 pp = &cmdtable[hashval % CMDTABLESIZE];
8167 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8168 if (strcmp(cmdp->cmdname, name) == 0)
8169 break;
8170 pp = &cmdp->next;
8171 }
8172 if (add && cmdp == NULL) {
8173 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8174 + strlen(name)
8175
8176);
8177
8178 cmdp->cmdtype = CMDUNKNOWN;
8179 strcpy(cmdp->cmdname, name);
8180 }
8181 lastcmdentry = pp;
8182 return cmdp;
8183}
8184
8185
8186
8187
8188static void
8189delete_cmd_entry(void)
8190{
8191 struct tblentry *cmdp;
8192
8193 INT_OFF;
8194 cmdp = *lastcmdentry;
8195 *lastcmdentry = cmdp->next;
8196 if (cmdp->cmdtype == CMDFUNCTION)
8197 freefunc(cmdp->param.func);
8198 free(cmdp);
8199 INT_ON;
8200}
8201
8202
8203
8204
8205
8206static void
8207addcmdentry(char *name, struct cmdentry *entry)
8208{
8209 struct tblentry *cmdp;
8210
8211 cmdp = cmdlookup(name, 1);
8212 if (cmdp->cmdtype == CMDFUNCTION) {
8213 freefunc(cmdp->param.func);
8214 }
8215 cmdp->cmdtype = entry->cmdtype;
8216 cmdp->param = entry->u;
8217 cmdp->rehash = 0;
8218}
8219
8220static int FAST_FUNC
8221hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8222{
8223 struct tblentry **pp;
8224 struct tblentry *cmdp;
8225 int c;
8226 struct cmdentry entry;
8227 char *name;
8228
8229 if (nextopt("r") != '\0') {
8230 clearcmdentry(0);
8231 return 0;
8232 }
8233
8234 if (*argptr == NULL) {
8235 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8236 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8237 if (cmdp->cmdtype == CMDNORMAL)
8238 printentry(cmdp);
8239 }
8240 }
8241 return 0;
8242 }
8243
8244 c = 0;
8245 while ((name = *argptr) != NULL) {
8246 cmdp = cmdlookup(name, 0);
8247 if (cmdp != NULL
8248 && (cmdp->cmdtype == CMDNORMAL
8249 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8250 ) {
8251 delete_cmd_entry();
8252 }
8253 find_command(name, &entry, DO_ERR, pathval());
8254 if (entry.cmdtype == CMDUNKNOWN)
8255 c = 1;
8256 argptr++;
8257 }
8258 return c;
8259}
8260
8261
8262
8263
8264
8265static void
8266hashcd(void)
8267{
8268 struct tblentry **pp;
8269 struct tblentry *cmdp;
8270
8271 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8272 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8273 if (cmdp->cmdtype == CMDNORMAL
8274 || (cmdp->cmdtype == CMDBUILTIN
8275 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8276 && builtinloc > 0)
8277 ) {
8278 cmdp->rehash = 1;
8279 }
8280 }
8281 }
8282}
8283
8284
8285
8286
8287
8288
8289
8290static void FAST_FUNC
8291changepath(const char *new)
8292{
8293 const char *old;
8294 int firstchange;
8295 int idx;
8296 int idx_bltin;
8297
8298 old = pathval();
8299 firstchange = 9999;
8300 idx = 0;
8301 idx_bltin = -1;
8302 for (;;) {
8303 if (*old != *new) {
8304 firstchange = idx;
8305 if ((*old == '\0' && *new == ':')
8306 || (*old == ':' && *new == '\0')
8307 ) {
8308 firstchange++;
8309 }
8310 old = new;
8311 }
8312 if (*new == '\0')
8313 break;
8314 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8315 idx_bltin = idx;
8316 if (*new == ':')
8317 idx++;
8318 new++;
8319 old++;
8320 }
8321 if (builtinloc < 0 && idx_bltin >= 0)
8322 builtinloc = idx_bltin;
8323 if (builtinloc >= 0 && idx_bltin < 0)
8324 firstchange = 0;
8325 clearcmdentry(firstchange);
8326 builtinloc = idx_bltin;
8327}
8328enum {
8329 TEOF,
8330 TNL,
8331 TREDIR,
8332 TWORD,
8333 TSEMI,
8334 TBACKGND,
8335 TAND,
8336 TOR,
8337 TPIPE,
8338 TLP,
8339 TRP,
8340 TENDCASE,
8341 TENDBQUOTE,
8342 TNOT,
8343 TCASE,
8344 TDO,
8345 TDONE,
8346 TELIF,
8347 TELSE,
8348 TESAC,
8349 TFI,
8350 TFOR,
8351#if BASH_FUNCTION
8352 TFUNCTION,
8353#endif
8354 TIF,
8355 TIN,
8356 TTHEN,
8357 TUNTIL,
8358 TWHILE,
8359 TBEGIN,
8360 TEND
8361};
8362typedef smallint token_id_t;
8363
8364
8365enum {
8366 tokendlist = 0
8367 | (1u << TEOF)
8368 | (0u << TNL)
8369 | (0u << TREDIR)
8370 | (0u << TWORD)
8371 | (0u << TSEMI)
8372 | (0u << TBACKGND)
8373 | (0u << TAND)
8374 | (0u << TOR)
8375 | (0u << TPIPE)
8376 | (0u << TLP)
8377 | (1u << TRP)
8378 | (1u << TENDCASE)
8379 | (1u << TENDBQUOTE)
8380 | (0u << TNOT)
8381 | (0u << TCASE)
8382 | (1u << TDO)
8383 | (1u << TDONE)
8384 | (1u << TELIF)
8385 | (1u << TELSE)
8386 | (1u << TESAC)
8387 | (1u << TFI)
8388 | (0u << TFOR)
8389#if BASH_FUNCTION
8390 | (0u << TFUNCTION)
8391#endif
8392 | (0u << TIF)
8393 | (0u << TIN)
8394 | (1u << TTHEN)
8395 | (0u << TUNTIL)
8396 | (0u << TWHILE)
8397 | (0u << TBEGIN)
8398 | (1u << TEND)
8399 ,
8400};
8401
8402static const char *const tokname_array[] = {
8403 "end of file",
8404 "newline",
8405 "redirection",
8406 "word",
8407 ";",
8408 "&",
8409 "&&",
8410 "||",
8411 "|",
8412 "(",
8413 ")",
8414 ";;",
8415 "`",
8416#define KWDOFFSET 13
8417
8418 "!",
8419 "case",
8420 "do",
8421 "done",
8422 "elif",
8423 "else",
8424 "esac",
8425 "fi",
8426 "for",
8427#if BASH_FUNCTION
8428 "function",
8429#endif
8430 "if",
8431 "in",
8432 "then",
8433 "until",
8434 "while",
8435 "{",
8436 "}",
8437};
8438
8439
8440static int
8441pstrcmp(const void *a, const void *b)
8442{
8443 return strcmp((char*)a, *(char**)b);
8444}
8445
8446static const char *const *
8447findkwd(const char *s)
8448{
8449 return bsearch(s, tokname_array + KWDOFFSET,
8450 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8451 sizeof(tokname_array[0]), pstrcmp);
8452}
8453
8454
8455
8456
8457static int
8458describe_command(char *command, const char *path, int describe_command_verbose)
8459{
8460 struct cmdentry entry;
8461#if ENABLE_ASH_ALIAS
8462 const struct alias *ap;
8463#endif
8464
8465 path = path ? path : pathval();
8466
8467 if (describe_command_verbose) {
8468 out1str(command);
8469 }
8470
8471
8472 if (findkwd(command)) {
8473 out1str(describe_command_verbose ? " is a shell keyword" : command);
8474 goto out;
8475 }
8476
8477#if ENABLE_ASH_ALIAS
8478
8479 ap = lookupalias(command, 0);
8480 if (ap != NULL) {
8481 if (!describe_command_verbose) {
8482 out1str("alias ");
8483 printalias(ap);
8484 return 0;
8485 }
8486 out1fmt(" is an alias for %s", ap->val);
8487 goto out;
8488 }
8489#endif
8490
8491 find_command(command, &entry, DO_ABS, path);
8492
8493 switch (entry.cmdtype) {
8494 case CMDNORMAL: {
8495 int j = entry.u.index;
8496 char *p;
8497 if (j < 0) {
8498 p = command;
8499 } else {
8500 do {
8501 p = path_advance(&path, command);
8502 stunalloc(p);
8503 } while (--j >= 0);
8504 }
8505 if (describe_command_verbose) {
8506 out1fmt(" is %s", p);
8507 } else {
8508 out1str(p);
8509 }
8510 break;
8511 }
8512
8513 case CMDFUNCTION:
8514 if (describe_command_verbose) {
8515 out1str(" is a shell function");
8516 } else {
8517 out1str(command);
8518 }
8519 break;
8520
8521 case CMDBUILTIN:
8522 if (describe_command_verbose) {
8523 out1fmt(" is a %sshell builtin",
8524 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8525 "special " : nullstr
8526 );
8527 } else {
8528 out1str(command);
8529 }
8530 break;
8531
8532 default:
8533 if (describe_command_verbose) {
8534 out1str(": not found\n");
8535 }
8536 return 127;
8537 }
8538 out:
8539 out1str("\n");
8540 return 0;
8541}
8542
8543static int FAST_FUNC
8544typecmd(int argc UNUSED_PARAM, char **argv)
8545{
8546 int i = 1;
8547 int err = 0;
8548 int verbose = 1;
8549
8550
8551 if (argv[1] && argv[1][0] == '-') {
8552 i++;
8553 verbose = 0;
8554 }
8555 while (argv[i]) {
8556 err |= describe_command(argv[i++], NULL, verbose);
8557 }
8558 return err;
8559}
8560
8561#if ENABLE_ASH_CMDCMD
8562
8563static char **
8564parse_command_args(char **argv, const char **path)
8565{
8566 char *cp, c;
8567
8568 for (;;) {
8569 cp = *++argv;
8570 if (!cp)
8571 return NULL;
8572 if (*cp++ != '-')
8573 break;
8574 c = *cp++;
8575 if (!c)
8576 break;
8577 if (c == '-' && !*cp) {
8578 if (!*++argv)
8579 return NULL;
8580 break;
8581 }
8582 do {
8583 switch (c) {
8584 case 'p':
8585 *path = bb_default_path;
8586 break;
8587 default:
8588
8589 return NULL;
8590 }
8591 c = *cp++;
8592 } while (c);
8593 }
8594 return argv;
8595}
8596
8597static int FAST_FUNC
8598commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8599{
8600 char *cmd;
8601 int c;
8602 enum {
8603 VERIFY_BRIEF = 1,
8604 VERIFY_VERBOSE = 2,
8605 } verify = 0;
8606 const char *path = NULL;
8607
8608
8609
8610
8611
8612 while ((c = nextopt("pvV")) != '\0')
8613 if (c == 'V')
8614 verify |= VERIFY_VERBOSE;
8615 else if (c == 'v')
8616 ;
8617#if DEBUG
8618 else if (c != 'p')
8619 abort();
8620#endif
8621 else
8622 path = bb_default_path;
8623
8624
8625 cmd = *argptr;
8626 if ( cmd)
8627 return describe_command(cmd, path, verify );
8628
8629 return 0;
8630}
8631#endif
8632
8633
8634
8635
8636static void *funcblock;
8637static char *funcstring_end;
8638
8639static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8640 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8641 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8642 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8643 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8644 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8645 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8646 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8647 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8648 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8649 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8650 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8651 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8652 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8653 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8654 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8655 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8656 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8657#if BASH_REDIR_OUTPUT
8658 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
8659#endif
8660 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8661 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8662 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8663 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8664 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8665 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8666 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8667 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8668 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8669};
8670
8671static int calcsize(int funcblocksize, union node *n);
8672
8673static int
8674sizenodelist(int funcblocksize, struct nodelist *lp)
8675{
8676 while (lp) {
8677 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8678 funcblocksize = calcsize(funcblocksize, lp->n);
8679 lp = lp->next;
8680 }
8681 return funcblocksize;
8682}
8683
8684static int
8685calcsize(int funcblocksize, union node *n)
8686{
8687 if (n == NULL)
8688 return funcblocksize;
8689 funcblocksize += nodesize[n->type];
8690 switch (n->type) {
8691 case NCMD:
8692 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8693 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8694 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8695 break;
8696 case NPIPE:
8697 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8698 break;
8699 case NREDIR:
8700 case NBACKGND:
8701 case NSUBSHELL:
8702 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8703 funcblocksize = calcsize(funcblocksize, n->nredir.n);
8704 break;
8705 case NAND:
8706 case NOR:
8707 case NSEMI:
8708 case NWHILE:
8709 case NUNTIL:
8710 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8711 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
8712 break;
8713 case NIF:
8714 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8715 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8716 funcblocksize = calcsize(funcblocksize, n->nif.test);
8717 break;
8718 case NFOR:
8719 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1);
8720 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8721 funcblocksize = calcsize(funcblocksize, n->nfor.args);
8722 break;
8723 case NCASE:
8724 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8725 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
8726 break;
8727 case NCLIST:
8728 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8729 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8730 funcblocksize = calcsize(funcblocksize, n->nclist.next);
8731 break;
8732 case NDEFUN:
8733 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8734 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8735 break;
8736 case NARG:
8737 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
8738 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1);
8739 funcblocksize = calcsize(funcblocksize, n->narg.next);
8740 break;
8741 case NTO:
8742#if BASH_REDIR_OUTPUT
8743 case NTO2:
8744#endif
8745 case NCLOBBER:
8746 case NFROM:
8747 case NFROMTO:
8748 case NAPPEND:
8749 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8750 funcblocksize = calcsize(funcblocksize, n->nfile.next);
8751 break;
8752 case NTOFD:
8753 case NFROMFD:
8754 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8755 funcblocksize = calcsize(funcblocksize, n->ndup.next);
8756 break;
8757 case NHERE:
8758 case NXHERE:
8759 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8760 funcblocksize = calcsize(funcblocksize, n->nhere.next);
8761 break;
8762 case NNOT:
8763 funcblocksize = calcsize(funcblocksize, n->nnot.com);
8764 break;
8765 };
8766 return funcblocksize;
8767}
8768
8769static char *
8770nodeckstrdup(char *s)
8771{
8772 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
8773 return strcpy(funcstring_end, s);
8774}
8775
8776static union node *copynode(union node *);
8777
8778static struct nodelist *
8779copynodelist(struct nodelist *lp)
8780{
8781 struct nodelist *start;
8782 struct nodelist **lpp;
8783
8784 lpp = &start;
8785 while (lp) {
8786 *lpp = funcblock;
8787 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8788 (*lpp)->n = copynode(lp->n);
8789 lp = lp->next;
8790 lpp = &(*lpp)->next;
8791 }
8792 *lpp = NULL;
8793 return start;
8794}
8795
8796static union node *
8797copynode(union node *n)
8798{
8799 union node *new;
8800
8801 if (n == NULL)
8802 return NULL;
8803 new = funcblock;
8804 funcblock = (char *) funcblock + nodesize[n->type];
8805
8806 switch (n->type) {
8807 case NCMD:
8808 new->ncmd.redirect = copynode(n->ncmd.redirect);
8809 new->ncmd.args = copynode(n->ncmd.args);
8810 new->ncmd.assign = copynode(n->ncmd.assign);
8811 new->ncmd.linno = n->ncmd.linno;
8812 break;
8813 case NPIPE:
8814 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8815 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8816 break;
8817 case NREDIR:
8818 case NBACKGND:
8819 case NSUBSHELL:
8820 new->nredir.redirect = copynode(n->nredir.redirect);
8821 new->nredir.n = copynode(n->nredir.n);
8822 new->nredir.linno = n->nredir.linno;
8823 break;
8824 case NAND:
8825 case NOR:
8826 case NSEMI:
8827 case NWHILE:
8828 case NUNTIL:
8829 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8830 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8831 break;
8832 case NIF:
8833 new->nif.elsepart = copynode(n->nif.elsepart);
8834 new->nif.ifpart = copynode(n->nif.ifpart);
8835 new->nif.test = copynode(n->nif.test);
8836 break;
8837 case NFOR:
8838 new->nfor.var = nodeckstrdup(n->nfor.var);
8839 new->nfor.body = copynode(n->nfor.body);
8840 new->nfor.args = copynode(n->nfor.args);
8841 new->nfor.linno = n->nfor.linno;
8842 break;
8843 case NCASE:
8844 new->ncase.cases = copynode(n->ncase.cases);
8845 new->ncase.expr = copynode(n->ncase.expr);
8846 new->ncase.linno = n->ncase.linno;
8847 break;
8848 case NCLIST:
8849 new->nclist.body = copynode(n->nclist.body);
8850 new->nclist.pattern = copynode(n->nclist.pattern);
8851 new->nclist.next = copynode(n->nclist.next);
8852 break;
8853 case NDEFUN:
8854 new->ndefun.body = copynode(n->ndefun.body);
8855 new->ndefun.text = nodeckstrdup(n->ndefun.text);
8856 new->ndefun.linno = n->ndefun.linno;
8857 break;
8858 case NARG:
8859 new->narg.backquote = copynodelist(n->narg.backquote);
8860 new->narg.text = nodeckstrdup(n->narg.text);
8861 new->narg.next = copynode(n->narg.next);
8862 break;
8863 case NTO:
8864#if BASH_REDIR_OUTPUT
8865 case NTO2:
8866#endif
8867 case NCLOBBER:
8868 case NFROM:
8869 case NFROMTO:
8870 case NAPPEND:
8871 new->nfile.fname = copynode(n->nfile.fname);
8872 new->nfile.fd = n->nfile.fd;
8873 new->nfile.next = copynode(n->nfile.next);
8874 break;
8875 case NTOFD:
8876 case NFROMFD:
8877 new->ndup.vname = copynode(n->ndup.vname);
8878 new->ndup.dupfd = n->ndup.dupfd;
8879 new->ndup.fd = n->ndup.fd;
8880 new->ndup.next = copynode(n->ndup.next);
8881 break;
8882 case NHERE:
8883 case NXHERE:
8884 new->nhere.doc = copynode(n->nhere.doc);
8885 new->nhere.fd = n->nhere.fd;
8886 new->nhere.next = copynode(n->nhere.next);
8887 break;
8888 case NNOT:
8889 new->nnot.com = copynode(n->nnot.com);
8890 break;
8891 };
8892 new->type = n->type;
8893 return new;
8894}
8895
8896
8897
8898
8899static struct funcnode *
8900copyfunc(union node *n)
8901{
8902 struct funcnode *f;
8903 size_t blocksize;
8904
8905
8906 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8907 f = ckzalloc(blocksize );
8908 funcblock = (char *) f + offsetof(struct funcnode, n);
8909 funcstring_end = (char *) f + blocksize;
8910 copynode(n);
8911
8912 return f;
8913}
8914
8915
8916
8917
8918static void
8919defun(union node *func)
8920{
8921 struct cmdentry entry;
8922
8923 INT_OFF;
8924 entry.cmdtype = CMDFUNCTION;
8925 entry.u.func = copyfunc(func);
8926 addcmdentry(func->ndefun.text, &entry);
8927 INT_ON;
8928}
8929
8930
8931#define SKIPBREAK (1 << 0)
8932#define SKIPCONT (1 << 1)
8933#define SKIPFUNC (1 << 2)
8934static smallint evalskip;
8935static int skipcount;
8936static int loopnest;
8937static int funcline;
8938
8939
8940static int evalstring(char *s, int flags);
8941
8942
8943
8944
8945
8946
8947
8948
8949static void
8950dotrap(void)
8951{
8952 uint8_t *g;
8953 int sig;
8954 uint8_t last_status;
8955
8956 if (!pending_sig)
8957 return;
8958
8959 last_status = exitstatus;
8960 pending_sig = 0;
8961 barrier();
8962
8963 TRACE(("dotrap entered\n"));
8964 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8965 char *p;
8966
8967 if (!*g)
8968 continue;
8969
8970 if (evalskip) {
8971 pending_sig = sig;
8972 break;
8973 }
8974
8975 p = trap[sig];
8976
8977
8978 if (sig == SIGINT && !p)
8979 continue;
8980
8981 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
8982 *g = 0;
8983 if (!p)
8984 continue;
8985 evalstring(p, 0);
8986 }
8987 exitstatus = last_status;
8988 TRACE(("dotrap returns\n"));
8989}
8990
8991
8992static int evalloop(union node *, int);
8993static int evalfor(union node *, int);
8994static int evalcase(union node *, int);
8995static int evalsubshell(union node *, int);
8996static void expredir(union node *);
8997static int evalpipe(union node *, int);
8998static int evalcommand(union node *, int);
8999static int evalbltin(const struct builtincmd *, int, char **, int);
9000static void prehash(union node *);
9001
9002
9003
9004
9005
9006static int
9007evaltree(union node *n, int flags)
9008{
9009 int checkexit = 0;
9010 int (*evalfn)(union node *, int);
9011 int status = 0;
9012
9013 if (n == NULL) {
9014 TRACE(("evaltree(NULL) called\n"));
9015 goto out;
9016 }
9017 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
9018
9019 dotrap();
9020
9021 switch (n->type) {
9022 default:
9023#if DEBUG
9024 out1fmt("Node type = %d\n", n->type);
9025 fflush_all();
9026 break;
9027#endif
9028 case NNOT:
9029 status = !evaltree(n->nnot.com, EV_TESTED);
9030 goto setstatus;
9031 case NREDIR:
9032 errlinno = lineno = n->nredir.linno;
9033 if (funcline)
9034 lineno -= funcline - 1;
9035 expredir(n->nredir.redirect);
9036 pushredir(n->nredir.redirect);
9037 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9038 if (!status) {
9039 status = evaltree(n->nredir.n, flags & EV_TESTED);
9040 }
9041 if (n->nredir.redirect)
9042 popredir( 0);
9043 goto setstatus;
9044 case NCMD:
9045 evalfn = evalcommand;
9046 checkexit:
9047 if (eflag && !(flags & EV_TESTED))
9048 checkexit = ~0;
9049 goto calleval;
9050 case NFOR:
9051 evalfn = evalfor;
9052 goto calleval;
9053 case NWHILE:
9054 case NUNTIL:
9055 evalfn = evalloop;
9056 goto calleval;
9057 case NSUBSHELL:
9058 case NBACKGND:
9059 evalfn = evalsubshell;
9060 goto checkexit;
9061 case NPIPE:
9062 evalfn = evalpipe;
9063 goto checkexit;
9064 case NCASE:
9065 evalfn = evalcase;
9066 goto calleval;
9067 case NAND:
9068 case NOR:
9069 case NSEMI: {
9070
9071#if NAND + 1 != NOR
9072#error NAND + 1 != NOR
9073#endif
9074#if NOR + 1 != NSEMI
9075#error NOR + 1 != NSEMI
9076#endif
9077 unsigned is_or = n->type - NAND;
9078 status = evaltree(
9079 n->nbinary.ch1,
9080 (flags | ((is_or >> 1) - 1)) & EV_TESTED
9081 );
9082 if ((!status) == is_or || evalskip)
9083 break;
9084 n = n->nbinary.ch2;
9085 evaln:
9086 evalfn = evaltree;
9087 calleval:
9088 status = evalfn(n, flags);
9089 goto setstatus;
9090 }
9091 case NIF:
9092 status = evaltree(n->nif.test, EV_TESTED);
9093 if (evalskip)
9094 break;
9095 if (!status) {
9096 n = n->nif.ifpart;
9097 goto evaln;
9098 }
9099 if (n->nif.elsepart) {
9100 n = n->nif.elsepart;
9101 goto evaln;
9102 }
9103 status = 0;
9104 goto setstatus;
9105 case NDEFUN:
9106 defun(n);
9107
9108
9109
9110
9111 setstatus:
9112 exitstatus = status;
9113 break;
9114 }
9115 out:
9116
9117
9118
9119 dotrap();
9120
9121 if (checkexit & status)
9122 raise_exception(EXEXIT);
9123 if (flags & EV_EXIT)
9124 raise_exception(EXEXIT);
9125
9126 TRACE(("leaving evaltree (no interrupts)\n"));
9127 return exitstatus;
9128}
9129
9130static int
9131skiploop(void)
9132{
9133 int skip = evalskip;
9134
9135 switch (skip) {
9136 case 0:
9137 break;
9138 case SKIPBREAK:
9139 case SKIPCONT:
9140 if (--skipcount <= 0) {
9141 evalskip = 0;
9142 break;
9143 }
9144 skip = SKIPBREAK;
9145 break;
9146 }
9147 return skip;
9148}
9149
9150static int
9151evalloop(union node *n, int flags)
9152{
9153 int skip;
9154 int status;
9155
9156 loopnest++;
9157 status = 0;
9158 flags &= EV_TESTED;
9159 do {
9160 int i;
9161
9162 i = evaltree(n->nbinary.ch1, EV_TESTED);
9163 skip = skiploop();
9164 if (skip == SKIPFUNC)
9165 status = i;
9166 if (skip)
9167 continue;
9168 if (n->type != NWHILE)
9169 i = !i;
9170 if (i != 0)
9171 break;
9172 status = evaltree(n->nbinary.ch2, flags);
9173 skip = skiploop();
9174 } while (!(skip & ~SKIPCONT));
9175 loopnest--;
9176
9177 return status;
9178}
9179
9180static int
9181evalfor(union node *n, int flags)
9182{
9183 struct arglist arglist;
9184 union node *argp;
9185 struct strlist *sp;
9186 struct stackmark smark;
9187 int status = 0;
9188
9189 errlinno = lineno = n->ncase.linno;
9190 if (funcline)
9191 lineno -= funcline - 1;
9192
9193 setstackmark(&smark);
9194 arglist.list = NULL;
9195 arglist.lastp = &arglist.list;
9196 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
9197 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9198 }
9199 *arglist.lastp = NULL;
9200
9201 loopnest++;
9202 flags &= EV_TESTED;
9203 for (sp = arglist.list; sp; sp = sp->next) {
9204 setvar0(n->nfor.var, sp->text);
9205 status = evaltree(n->nfor.body, flags);
9206 if (skiploop() & ~SKIPCONT)
9207 break;
9208 }
9209 loopnest--;
9210 popstackmark(&smark);
9211
9212 return status;
9213}
9214
9215static int
9216evalcase(union node *n, int flags)
9217{
9218 union node *cp;
9219 union node *patp;
9220 struct arglist arglist;
9221 struct stackmark smark;
9222 int status = 0;
9223
9224 errlinno = lineno = n->ncase.linno;
9225 if (funcline)
9226 lineno -= funcline - 1;
9227
9228 setstackmark(&smark);
9229 arglist.list = NULL;
9230 arglist.lastp = &arglist.list;
9231 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
9232 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9233 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
9234 if (casematch(patp, arglist.list->text)) {
9235
9236
9237
9238
9239 if (evalskip == 0 && cp->nclist.body) {
9240 status = evaltree(cp->nclist.body, flags);
9241 }
9242 goto out;
9243 }
9244 }
9245 }
9246 out:
9247 popstackmark(&smark);
9248
9249 return status;
9250}
9251
9252
9253
9254
9255static int
9256evalsubshell(union node *n, int flags)
9257{
9258 struct job *jp;
9259 int backgnd = (n->type == NBACKGND);
9260 int status;
9261
9262 errlinno = lineno = n->nredir.linno;
9263 if (funcline)
9264 lineno -= funcline - 1;
9265
9266 expredir(n->nredir.redirect);
9267 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9268 goto nofork;
9269 INT_OFF;
9270 if (backgnd == FORK_FG)
9271 get_tty_state();
9272 jp = makejob( 1);
9273 if (forkshell(jp, n, backgnd) == 0) {
9274
9275 INT_ON;
9276 flags |= EV_EXIT;
9277 if (backgnd)
9278 flags &= ~EV_TESTED;
9279 nofork:
9280 redirect(n->nredir.redirect, 0);
9281 evaltreenr(n->nredir.n, flags);
9282
9283 }
9284
9285 status = 0;
9286 if (backgnd == FORK_FG)
9287 status = waitforjob(jp);
9288 INT_ON;
9289 return status;
9290}
9291
9292
9293
9294
9295static void fixredir(union node *, const char *, int);
9296static void
9297expredir(union node *n)
9298{
9299 union node *redir;
9300
9301 for (redir = n; redir; redir = redir->nfile.next) {
9302 struct arglist fn;
9303
9304 fn.list = NULL;
9305 fn.lastp = &fn.list;
9306 switch (redir->type) {
9307 case NFROMTO:
9308 case NFROM:
9309 case NTO:
9310#if BASH_REDIR_OUTPUT
9311 case NTO2:
9312#endif
9313 case NCLOBBER:
9314 case NAPPEND:
9315 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
9316 TRACE(("expredir expanded to '%s'\n", fn.list->text));
9317#if BASH_REDIR_OUTPUT
9318 store_expfname:
9319#endif
9320#if 0
9321
9322
9323
9324
9325
9326
9327 if (redir->nfile.expfname)
9328 stunalloc(redir->nfile.expfname);
9329
9330#endif
9331 redir->nfile.expfname = fn.list->text;
9332 break;
9333 case NFROMFD:
9334 case NTOFD:
9335 if (redir->ndup.vname) {
9336 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
9337 if (fn.list == NULL)
9338 ash_msg_and_raise_error("redir error");
9339#if BASH_REDIR_OUTPUT
9340
9341 if (!isdigit_str9(fn.list->text)) {
9342
9343 if (redir->nfile.fd != 1)
9344 ash_msg_and_raise_error("redir error");
9345 redir->type = NTO2;
9346 goto store_expfname;
9347 }
9348#endif
9349 fixredir(redir, fn.list->text, 1);
9350 }
9351 break;
9352 }
9353 }
9354}
9355
9356
9357
9358
9359
9360
9361
9362static int
9363evalpipe(union node *n, int flags)
9364{
9365 struct job *jp;
9366 struct nodelist *lp;
9367 int pipelen;
9368 int prevfd;
9369 int pip[2];
9370 int status = 0;
9371
9372 TRACE(("evalpipe(0x%lx) called\n", (long)n));
9373 pipelen = 0;
9374 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
9375 pipelen++;
9376 flags |= EV_EXIT;
9377 INT_OFF;
9378 if (n->npipe.pipe_backgnd == 0)
9379 get_tty_state();
9380 jp = makejob( pipelen);
9381 prevfd = -1;
9382 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
9383 prehash(lp->n);
9384 pip[1] = -1;
9385 if (lp->next) {
9386 if (pipe(pip) < 0) {
9387 close(prevfd);
9388 ash_msg_and_raise_perror("can't create pipe");
9389 }
9390 }
9391 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9392
9393 INT_ON;
9394 if (pip[1] >= 0) {
9395 close(pip[0]);
9396 }
9397 if (prevfd > 0) {
9398 dup2(prevfd, 0);
9399 close(prevfd);
9400 }
9401 if (pip[1] > 1) {
9402 dup2(pip[1], 1);
9403 close(pip[1]);
9404 }
9405 evaltreenr(lp->n, flags);
9406
9407 }
9408
9409 if (prevfd >= 0)
9410 close(prevfd);
9411 prevfd = pip[0];
9412
9413 if (pip[1] != -1)
9414 close(pip[1]);
9415 }
9416 if (n->npipe.pipe_backgnd == 0) {
9417 status = waitforjob(jp);
9418 TRACE(("evalpipe: job done exit status %d\n", status));
9419 }
9420 INT_ON;
9421
9422 return status;
9423}
9424
9425
9426
9427
9428static void
9429setinteractive(int on)
9430{
9431 static smallint is_interactive;
9432
9433 if (++on == is_interactive)
9434 return;
9435 is_interactive = on;
9436 setsignal(SIGINT);
9437 setsignal(SIGQUIT);
9438 setsignal(SIGTERM);
9439#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9440 if (is_interactive > 1) {
9441
9442 static smallint did_banner;
9443
9444 if (!did_banner) {
9445
9446 out1fmt("\n\n%s %s\n"
9447 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9448 "\n",
9449 bb_banner,
9450 "built-in shell (ash)"
9451 );
9452 did_banner = 1;
9453 }
9454 }
9455#endif
9456}
9457
9458static void
9459optschanged(void)
9460{
9461#if DEBUG
9462 opentrace();
9463#endif
9464 setinteractive(iflag);
9465 setjobctl(mflag);
9466#if ENABLE_FEATURE_EDITING_VI
9467 if (viflag)
9468 line_input_state->flags |= VI_MODE;
9469 else
9470 line_input_state->flags &= ~VI_MODE;
9471#else
9472 viflag = 0;
9473#endif
9474}
9475
9476struct localvar_list {
9477 struct localvar_list *next;
9478 struct localvar *lv;
9479};
9480
9481static struct localvar_list *localvar_stack;
9482
9483
9484
9485
9486
9487static void
9488poplocalvars(int keep)
9489{
9490 struct localvar_list *ll;
9491 struct localvar *lvp, *next;
9492 struct var *vp;
9493
9494 INT_OFF;
9495 ll = localvar_stack;
9496 localvar_stack = ll->next;
9497
9498 next = ll->lv;
9499 free(ll);
9500
9501 while ((lvp = next) != NULL) {
9502 next = lvp->next;
9503 vp = lvp->vp;
9504 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9505 if (keep) {
9506 int bits = VSTRFIXED;
9507
9508 if (lvp->flags != VUNSET) {
9509 if (vp->var_text == lvp->text)
9510 bits |= VTEXTFIXED;
9511 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9512 free((char*)lvp->text);
9513 }
9514
9515 vp->flags &= ~bits;
9516 vp->flags |= (lvp->flags & bits);
9517
9518 if ((vp->flags &
9519 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9520 unsetvar(vp->var_text);
9521 } else if (vp == NULL) {
9522 memcpy(optlist, lvp->text, sizeof(optlist));
9523 free((char*)lvp->text);
9524 optschanged();
9525 } else if (lvp->flags == VUNSET) {
9526 vp->flags &= ~(VSTRFIXED|VREADONLY);
9527 unsetvar(vp->var_text);
9528 } else {
9529 if (vp->var_func)
9530 vp->var_func(var_end(lvp->text));
9531 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9532 free((char*)vp->var_text);
9533 vp->flags = lvp->flags;
9534 vp->var_text = lvp->text;
9535 }
9536 free(lvp);
9537 }
9538 INT_ON;
9539}
9540
9541
9542
9543
9544static struct localvar_list *
9545pushlocalvars(void)
9546{
9547 struct localvar_list *ll;
9548
9549 INT_OFF;
9550 ll = ckzalloc(sizeof(*ll));
9551
9552 ll->next = localvar_stack;
9553 localvar_stack = ll;
9554 INT_ON;
9555
9556 return ll->next;
9557}
9558
9559static void
9560unwindlocalvars(struct localvar_list *stop)
9561{
9562 while (localvar_stack != stop)
9563 poplocalvars(0);
9564}
9565
9566static int
9567evalfun(struct funcnode *func, int argc, char **argv, int flags)
9568{
9569 volatile struct shparam saveparam;
9570 struct jmploc *volatile savehandler;
9571 struct jmploc jmploc;
9572 int e;
9573 int savefuncline;
9574
9575 saveparam = shellparam;
9576 savefuncline = funcline;
9577 savehandler = exception_handler;
9578 e = setjmp(jmploc.loc);
9579 if (e) {
9580 goto funcdone;
9581 }
9582 INT_OFF;
9583 exception_handler = &jmploc;
9584 shellparam.malloced = 0;
9585 func->count++;
9586 funcline = func->n.ndefun.linno;
9587 INT_ON;
9588 shellparam.nparam = argc - 1;
9589 shellparam.p = argv + 1;
9590#if ENABLE_ASH_GETOPTS
9591 shellparam.optind = 1;
9592 shellparam.optoff = -1;
9593#endif
9594 pushlocalvars();
9595 evaltree(func->n.ndefun.body, flags & EV_TESTED);
9596 poplocalvars(0);
9597 funcdone:
9598 INT_OFF;
9599 funcline = savefuncline;
9600 freefunc(func);
9601 freeparam(&shellparam);
9602 shellparam = saveparam;
9603 exception_handler = savehandler;
9604 INT_ON;
9605 evalskip &= ~SKIPFUNC;
9606 return e;
9607}
9608
9609
9610
9611
9612
9613
9614
9615
9616static void
9617mklocal(char *name)
9618{
9619 struct localvar *lvp;
9620 struct var **vpp;
9621 struct var *vp;
9622 char *eq = strchr(name, '=');
9623
9624 INT_OFF;
9625
9626
9627
9628
9629 lvp = localvar_stack->lv;
9630 while (lvp) {
9631 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9632 if (eq)
9633 setvareq(name, 0);
9634
9635
9636
9637 goto ret;
9638 }
9639 lvp = lvp->next;
9640 }
9641
9642 lvp = ckzalloc(sizeof(*lvp));
9643 if (LONE_DASH(name)) {
9644 char *p;
9645 p = ckmalloc(sizeof(optlist));
9646 lvp->text = memcpy(p, optlist, sizeof(optlist));
9647 vp = NULL;
9648 } else {
9649 vpp = hashvar(name);
9650 vp = *findvar(vpp, name);
9651 if (vp == NULL) {
9652
9653 if (eq)
9654 vp = setvareq(name, VSTRFIXED);
9655 else
9656 vp = setvar(name, NULL, VSTRFIXED);
9657 lvp->flags = VUNSET;
9658 } else {
9659 lvp->text = vp->var_text;
9660 lvp->flags = vp->flags;
9661
9662
9663
9664 vp->flags |= VSTRFIXED|VTEXTFIXED;
9665 if (eq)
9666 setvareq(name, 0);
9667 else
9668
9669 setvar0(name, NULL);
9670 }
9671 }
9672 lvp->vp = vp;
9673 lvp->next = localvar_stack->lv;
9674 localvar_stack->lv = lvp;
9675 ret:
9676 INT_ON;
9677}
9678
9679
9680
9681
9682static int FAST_FUNC
9683localcmd(int argc UNUSED_PARAM, char **argv)
9684{
9685 char *name;
9686
9687 if (!localvar_stack)
9688 ash_msg_and_raise_error("not in a function");
9689
9690 argv = argptr;
9691 while ((name = *argv++) != NULL) {
9692 mklocal(name);
9693 }
9694 return 0;
9695}
9696
9697static int FAST_FUNC
9698falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9699{
9700 return 1;
9701}
9702
9703static int FAST_FUNC
9704truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9705{
9706 return 0;
9707}
9708
9709static int FAST_FUNC
9710execcmd(int argc UNUSED_PARAM, char **argv)
9711{
9712 optionarg = NULL;
9713 while (nextopt("a:") != '\0')
9714 ;
9715
9716 argv = argptr;
9717 if (argv[0]) {
9718 char *prog;
9719
9720 iflag = 0;
9721 mflag = 0;
9722 optschanged();
9723
9724
9725
9726
9727
9728
9729 shlvl++;
9730 setsignal(SIGQUIT);
9731
9732
9733
9734
9735 prog = argv[0];
9736 if (optionarg)
9737 argv[0] = optionarg;
9738 shellexec(prog, argv, pathval(), 0);
9739
9740 }
9741 return 0;
9742}
9743
9744
9745
9746
9747static int FAST_FUNC
9748returncmd(int argc UNUSED_PARAM, char **argv)
9749{
9750
9751
9752
9753
9754 evalskip = SKIPFUNC;
9755 return argv[1] ? number(argv[1]) : exitstatus;
9756}
9757
9758
9759static int breakcmd(int, char **) FAST_FUNC;
9760static int dotcmd(int, char **) FAST_FUNC;
9761static int evalcmd(int, char **, int) FAST_FUNC;
9762static int exitcmd(int, char **) FAST_FUNC;
9763static int exportcmd(int, char **) FAST_FUNC;
9764#if ENABLE_ASH_GETOPTS
9765static int getoptscmd(int, char **) FAST_FUNC;
9766#endif
9767#if ENABLE_ASH_HELP
9768static int helpcmd(int, char **) FAST_FUNC;
9769#endif
9770#if MAX_HISTORY
9771static int historycmd(int, char **) FAST_FUNC;
9772#endif
9773#if ENABLE_FEATURE_SH_MATH
9774static int letcmd(int, char **) FAST_FUNC;
9775#endif
9776static int readcmd(int, char **) FAST_FUNC;
9777static int setcmd(int, char **) FAST_FUNC;
9778static int shiftcmd(int, char **) FAST_FUNC;
9779static int timescmd(int, char **) FAST_FUNC;
9780static int trapcmd(int, char **) FAST_FUNC;
9781static int umaskcmd(int, char **) FAST_FUNC;
9782static int unsetcmd(int, char **) FAST_FUNC;
9783static int ulimitcmd(int, char **) FAST_FUNC;
9784
9785#define BUILTIN_NOSPEC "0"
9786#define BUILTIN_SPECIAL "1"
9787#define BUILTIN_REGULAR "2"
9788#define BUILTIN_SPEC_REG "3"
9789#define BUILTIN_ASSIGN "4"
9790#define BUILTIN_SPEC_ASSG "5"
9791#define BUILTIN_REG_ASSG "6"
9792#define BUILTIN_SPEC_REG_ASSG "7"
9793
9794
9795#if ENABLE_ASH_ECHO
9796static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
9797#endif
9798#if ENABLE_ASH_PRINTF
9799static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
9800#endif
9801#if ENABLE_ASH_TEST || BASH_TEST2
9802static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
9803#endif
9804
9805
9806static const struct builtincmd builtintab[] = {
9807 { BUILTIN_SPEC_REG "." , dotcmd },
9808 { BUILTIN_SPEC_REG ":" , truecmd },
9809#if ENABLE_ASH_TEST
9810 { BUILTIN_REGULAR "[" , testcmd },
9811#endif
9812#if BASH_TEST2
9813 { BUILTIN_REGULAR "[[" , testcmd },
9814#endif
9815#if ENABLE_ASH_ALIAS
9816 { BUILTIN_REG_ASSG "alias" , aliascmd },
9817#endif
9818#if JOBS
9819 { BUILTIN_REGULAR "bg" , fg_bgcmd },
9820#endif
9821 { BUILTIN_SPEC_REG "break" , breakcmd },
9822 { BUILTIN_REGULAR "cd" , cdcmd },
9823 { BUILTIN_NOSPEC "chdir" , cdcmd },
9824#if ENABLE_ASH_CMDCMD
9825 { BUILTIN_REGULAR "command" , commandcmd },
9826#endif
9827 { BUILTIN_SPEC_REG "continue", breakcmd },
9828#if ENABLE_ASH_ECHO
9829 { BUILTIN_REGULAR "echo" , echocmd },
9830#endif
9831 { BUILTIN_SPEC_REG "eval" , NULL },
9832 { BUILTIN_SPEC_REG "exec" , execcmd },
9833 { BUILTIN_SPEC_REG "exit" , exitcmd },
9834 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9835 { BUILTIN_REGULAR "false" , falsecmd },
9836#if JOBS
9837 { BUILTIN_REGULAR "fg" , fg_bgcmd },
9838#endif
9839#if ENABLE_ASH_GETOPTS
9840 { BUILTIN_REGULAR "getopts" , getoptscmd },
9841#endif
9842 { BUILTIN_NOSPEC "hash" , hashcmd },
9843#if ENABLE_ASH_HELP
9844 { BUILTIN_NOSPEC "help" , helpcmd },
9845#endif
9846#if MAX_HISTORY
9847 { BUILTIN_NOSPEC "history" , historycmd },
9848#endif
9849#if JOBS
9850 { BUILTIN_REGULAR "jobs" , jobscmd },
9851 { BUILTIN_REGULAR "kill" , killcmd },
9852#endif
9853#if ENABLE_FEATURE_SH_MATH
9854 { BUILTIN_NOSPEC "let" , letcmd },
9855#endif
9856 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
9857#if ENABLE_ASH_PRINTF
9858 { BUILTIN_REGULAR "printf" , printfcmd },
9859#endif
9860 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9861 { BUILTIN_REGULAR "read" , readcmd },
9862 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9863 { BUILTIN_SPEC_REG "return" , returncmd },
9864 { BUILTIN_SPEC_REG "set" , setcmd },
9865 { BUILTIN_SPEC_REG "shift" , shiftcmd },
9866#if BASH_SOURCE
9867 { BUILTIN_SPEC_REG "source" , dotcmd },
9868#endif
9869#if ENABLE_ASH_TEST
9870 { BUILTIN_REGULAR "test" , testcmd },
9871#endif
9872 { BUILTIN_SPEC_REG "times" , timescmd },
9873 { BUILTIN_SPEC_REG "trap" , trapcmd },
9874 { BUILTIN_REGULAR "true" , truecmd },
9875 { BUILTIN_NOSPEC "type" , typecmd },
9876 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9877 { BUILTIN_REGULAR "umask" , umaskcmd },
9878#if ENABLE_ASH_ALIAS
9879 { BUILTIN_REGULAR "unalias" , unaliascmd },
9880#endif
9881 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9882 { BUILTIN_REGULAR "wait" , waitcmd },
9883};
9884
9885
9886#define COMMANDCMD (builtintab + \
9887 2 + \
9888 1 * ENABLE_ASH_TEST + \
9889 1 * BASH_TEST2 + \
9890 1 * ENABLE_ASH_ALIAS + \
9891 1 * ENABLE_ASH_JOB_CONTROL + \
9892 3)
9893#define EVALCMD (COMMANDCMD + \
9894 1 * ENABLE_ASH_CMDCMD + \
9895 1 + \
9896 1 * ENABLE_ASH_ECHO + \
9897 0)
9898#define EXECCMD (EVALCMD + \
9899 1)
9900
9901
9902
9903
9904static int
9905pstrcmp1(const void *a, const void *b)
9906{
9907 return strcmp((char*)a, *(char**)b + 1);
9908}
9909static struct builtincmd *
9910find_builtin(const char *name)
9911{
9912 struct builtincmd *bp;
9913
9914 bp = bsearch(
9915 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9916 pstrcmp1
9917 );
9918 return bp;
9919}
9920
9921
9922
9923
9924static int
9925isassignment(const char *p)
9926{
9927 const char *q = endofname(p);
9928 if (p == q)
9929 return 0;
9930 return *q == '=';
9931}
9932static int FAST_FUNC
9933bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9934{
9935
9936
9937 return back_exitstatus;
9938}
9939static int
9940evalcommand(union node *cmd, int flags)
9941{
9942 static const struct builtincmd null_bltin = {
9943 "\0\0", bltincmd
9944 };
9945 struct localvar_list *localvar_stop;
9946 struct redirtab *redir_stop;
9947 struct stackmark smark;
9948 union node *argp;
9949 struct arglist arglist;
9950 struct arglist varlist;
9951 char **argv;
9952 int argc;
9953 const struct strlist *sp;
9954 struct cmdentry cmdentry;
9955 struct job *jp;
9956 char *lastarg;
9957 const char *path;
9958 int spclbltin;
9959 int status;
9960 char **nargv;
9961 smallint cmd_is_exec;
9962
9963 errlinno = lineno = cmd->ncmd.linno;
9964 if (funcline)
9965 lineno -= funcline - 1;
9966
9967
9968 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9969 setstackmark(&smark);
9970 localvar_stop = pushlocalvars();
9971 back_exitstatus = 0;
9972
9973 cmdentry.cmdtype = CMDBUILTIN;
9974 cmdentry.u.cmd = &null_bltin;
9975 varlist.lastp = &varlist.list;
9976 *varlist.lastp = NULL;
9977 arglist.lastp = &arglist.list;
9978 *arglist.lastp = NULL;
9979
9980 argc = 0;
9981 if (cmd->ncmd.args) {
9982 struct builtincmd *bcmd;
9983 smallint pseudovarflag;
9984
9985 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9986 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9987
9988 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9989 struct strlist **spp;
9990
9991 spp = arglist.lastp;
9992 if (pseudovarflag && isassignment(argp->narg.text))
9993 expandarg(argp, &arglist, EXP_VARTILDE);
9994 else
9995 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9996
9997 for (sp = *spp; sp; sp = sp->next)
9998 argc++;
9999 }
10000 }
10001
10002
10003 nargv = stalloc(sizeof(char *) * (argc + 2));
10004 argv = ++nargv;
10005 for (sp = arglist.list; sp; sp = sp->next) {
10006 TRACE(("evalcommand arg: %s\n", sp->text));
10007 *nargv++ = sp->text;
10008 }
10009 *nargv = NULL;
10010
10011 lastarg = NULL;
10012 if (iflag && funcline == 0 && argc > 0)
10013 lastarg = nargv[-1];
10014
10015 expredir(cmd->ncmd.redirect);
10016 redir_stop = pushredir(cmd->ncmd.redirect);
10017 preverrout_fd = 2;
10018 if (BASH_XTRACEFD && xflag) {
10019
10020
10021
10022 const char *xtracefd = lookupvar("BASH_XTRACEFD");
10023 if (xtracefd && is_number(xtracefd))
10024 preverrout_fd = atoi(xtracefd);
10025
10026 }
10027 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10028
10029 path = vpath.var_text;
10030 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10031 struct strlist **spp;
10032 char *p;
10033
10034 spp = varlist.lastp;
10035 expandarg(argp, &varlist, EXP_VARTILDE);
10036
10037 mklocal((*spp)->text);
10038
10039
10040
10041
10042
10043 p = (*spp)->text;
10044 if (varcmp(p, path) == 0)
10045 path = p;
10046 }
10047
10048
10049 if (xflag) {
10050 const char *pfx = "";
10051
10052 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
10053
10054 sp = varlist.list;
10055 while (sp) {
10056 char *varval = sp->text;
10057 char *eq = strchrnul(varval, '=');
10058 if (*eq)
10059 eq++;
10060 fdprintf(preverrout_fd, "%s%.*s%s",
10061 pfx,
10062 (int)(eq - varval), varval,
10063 maybe_single_quote(eq)
10064 );
10065 sp = sp->next;
10066 pfx = " ";
10067 }
10068
10069 sp = arglist.list;
10070 while (sp) {
10071 fdprintf(preverrout_fd, "%s%s",
10072 pfx,
10073
10074 findkwd(sp->text)
10075 ? single_quote(sp->text)
10076 : maybe_single_quote(sp->text)
10077 );
10078 sp = sp->next;
10079 pfx = " ";
10080 }
10081 safe_write(preverrout_fd, "\n", 1);
10082 }
10083
10084 cmd_is_exec = 0;
10085 spclbltin = -1;
10086
10087
10088 if (argc) {
10089 int cmd_flag = DO_ERR;
10090#if ENABLE_ASH_CMDCMD
10091 const char *oldpath = path + 5;
10092#endif
10093 path += 5;
10094 for (;;) {
10095 find_command(argv[0], &cmdentry, cmd_flag, path);
10096 if (cmdentry.cmdtype == CMDUNKNOWN) {
10097 flush_stdout_stderr();
10098 status = 127;
10099 goto bail;
10100 }
10101
10102
10103 if (cmdentry.cmdtype != CMDBUILTIN)
10104 break;
10105 if (spclbltin < 0)
10106 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10107 if (cmdentry.u.cmd == EXECCMD)
10108 cmd_is_exec = 1;
10109#if ENABLE_ASH_CMDCMD
10110 if (cmdentry.u.cmd == COMMANDCMD) {
10111 path = oldpath;
10112 nargv = parse_command_args(argv, &path);
10113 if (!nargv)
10114 break;
10115
10116
10117
10118 argc -= nargv - argv;
10119 argv = nargv;
10120 cmd_flag |= DO_NOFUNC;
10121 } else
10122#endif
10123 break;
10124 }
10125 }
10126
10127 if (status) {
10128 bail:
10129 exitstatus = status;
10130
10131
10132 if (spclbltin > 0)
10133 raise_exception(EXERROR);
10134
10135 goto out;
10136 }
10137
10138
10139 switch (cmdentry.cmdtype) {
10140 default: {
10141
10142#if ENABLE_FEATURE_SH_STANDALONE \
10143 && ENABLE_FEATURE_SH_NOFORK \
10144 && NUM_APPLETS > 1
10145
10146
10147
10148
10149
10150
10151 int applet_no = (- cmdentry.u.index - 2);
10152 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10153 char **sv_environ;
10154
10155 INT_OFF;
10156 sv_environ = environ;
10157 environ = listvars(VEXPORT, VUNSET, varlist.list, NULL);
10158
10159
10160
10161
10162
10163
10164
10165
10166 status = run_nofork_applet(applet_no, argv);
10167 environ = sv_environ;
10168
10169
10170
10171
10172
10173
10174
10175
10176
10177 INT_ON;
10178 break;
10179 }
10180#endif
10181
10182
10183
10184
10185 if (!(flags & EV_EXIT) || may_have_traps) {
10186
10187 INT_OFF;
10188 get_tty_state();
10189 jp = makejob( 1);
10190 if (forkshell(jp, cmd, FORK_FG) != 0) {
10191
10192 status = waitforjob(jp);
10193 INT_ON;
10194 TRACE(("forked child exited with %d\n", status));
10195 break;
10196 }
10197
10198 FORCE_INT_ON;
10199
10200 }
10201 listsetvar(varlist.list, VEXPORT|VSTACK);
10202 shellexec(argv[0], argv, path, cmdentry.u.index);
10203
10204 }
10205 case CMDBUILTIN:
10206 if (spclbltin > 0 || argc == 0) {
10207 poplocalvars(1);
10208 if (cmd_is_exec && argc > 1)
10209 listsetvar(varlist.list, VEXPORT);
10210 }
10211
10212
10213
10214
10215
10216 dowait(DOWAIT_NONBLOCK, NULL);
10217
10218 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
10219 if (exception_type == EXERROR && spclbltin <= 0) {
10220 FORCE_INT_ON;
10221 goto readstatus;
10222 }
10223 raise:
10224 longjmp(exception_handler->loc, 1);
10225 }
10226 goto readstatus;
10227
10228 case CMDFUNCTION:
10229 poplocalvars(1);
10230
10231 dowait(DOWAIT_NONBLOCK, NULL);
10232 if (evalfun(cmdentry.u.func, argc, argv, flags))
10233 goto raise;
10234 readstatus:
10235 status = exitstatus;
10236 break;
10237 }
10238
10239 out:
10240 if (cmd->ncmd.redirect)
10241 popredir( cmd_is_exec);
10242 unwindredir(redir_stop);
10243 unwindlocalvars(localvar_stop);
10244 if (lastarg) {
10245
10246
10247
10248
10249 setvar0("_", lastarg);
10250 }
10251 popstackmark(&smark);
10252
10253 return status;
10254}
10255
10256static int
10257evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
10258{
10259 char *volatile savecmdname;
10260 struct jmploc *volatile savehandler;
10261 struct jmploc jmploc;
10262 int status;
10263 int i;
10264
10265 savecmdname = commandname;
10266 savehandler = exception_handler;
10267 i = setjmp(jmploc.loc);
10268 if (i)
10269 goto cmddone;
10270 exception_handler = &jmploc;
10271 commandname = argv[0];
10272 argptr = argv + 1;
10273 optptr = NULL;
10274 if (cmd == EVALCMD)
10275 status = evalcmd(argc, argv, flags);
10276 else
10277 status = (*cmd->builtin)(argc, argv);
10278 flush_stdout_stderr();
10279 status |= ferror(stdout);
10280 exitstatus = status;
10281 cmddone:
10282 clearerr(stdout);
10283 commandname = savecmdname;
10284 exception_handler = savehandler;
10285
10286 return i;
10287}
10288
10289static int
10290goodname(const char *p)
10291{
10292 return endofname(p)[0] == '\0';
10293}
10294
10295
10296
10297
10298
10299
10300
10301
10302static void
10303prehash(union node *n)
10304{
10305 struct cmdentry entry;
10306
10307 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10308 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
10309}
10310
10311
10312
10313
10314
10315
10316
10317
10318
10319
10320
10321
10322
10323
10324
10325
10326
10327
10328static int FAST_FUNC
10329breakcmd(int argc UNUSED_PARAM, char **argv)
10330{
10331 int n = argv[1] ? number(argv[1]) : 1;
10332
10333 if (n <= 0)
10334 ash_msg_and_raise_error(msg_illnum, argv[1]);
10335 if (n > loopnest)
10336 n = loopnest;
10337 if (n > 0) {
10338 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
10339 skipcount = n;
10340 }
10341 return 0;
10342}
10343
10344
10345
10346
10347
10348
10349enum {
10350 INPUT_PUSH_FILE = 1,
10351 INPUT_NOFILE_OK = 2,
10352};
10353
10354static smallint checkkwd;
10355
10356#define CHKALIAS 0x1
10357#define CHKKWD 0x2
10358#define CHKNL 0x4
10359#define CHKEOFMARK 0x8
10360
10361
10362
10363
10364
10365#if !ENABLE_ASH_ALIAS
10366#define pushstring(s, ap) pushstring(s)
10367#endif
10368static void
10369pushstring(char *s, struct alias *ap)
10370{
10371 struct strpush *sp;
10372 int len;
10373
10374 len = strlen(s);
10375 INT_OFF;
10376 if (g_parsefile->strpush) {
10377 sp = ckzalloc(sizeof(*sp));
10378 sp->prev = g_parsefile->strpush;
10379 } else {
10380 sp = &(g_parsefile->basestrpush);
10381 }
10382 g_parsefile->strpush = sp;
10383 sp->prev_string = g_parsefile->next_to_pgetc;
10384 sp->prev_left_in_line = g_parsefile->left_in_line;
10385 sp->unget = g_parsefile->unget;
10386 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
10387#if ENABLE_ASH_ALIAS
10388 sp->ap = ap;
10389 if (ap) {
10390 ap->flag |= ALIASINUSE;
10391 sp->string = s;
10392 }
10393#endif
10394 g_parsefile->next_to_pgetc = s;
10395 g_parsefile->left_in_line = len;
10396 g_parsefile->unget = 0;
10397 INT_ON;
10398}
10399
10400static void
10401popstring(void)
10402{
10403 struct strpush *sp = g_parsefile->strpush;
10404
10405 INT_OFF;
10406#if ENABLE_ASH_ALIAS
10407 if (sp->ap) {
10408 if (g_parsefile->next_to_pgetc[-1] == ' '
10409 || g_parsefile->next_to_pgetc[-1] == '\t'
10410 ) {
10411 checkkwd |= CHKALIAS;
10412 }
10413 if (sp->string != sp->ap->val) {
10414 free(sp->string);
10415 }
10416 sp->ap->flag &= ~ALIASINUSE;
10417 if (sp->ap->flag & ALIASDEAD) {
10418 unalias(sp->ap->name);
10419 }
10420 }
10421#endif
10422 g_parsefile->next_to_pgetc = sp->prev_string;
10423 g_parsefile->left_in_line = sp->prev_left_in_line;
10424 g_parsefile->unget = sp->unget;
10425 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
10426 g_parsefile->strpush = sp->prev;
10427 if (sp != &(g_parsefile->basestrpush))
10428 free(sp);
10429 INT_ON;
10430}
10431
10432static int
10433preadfd(void)
10434{
10435 int nr;
10436 char *buf = g_parsefile->buf;
10437
10438 g_parsefile->next_to_pgetc = buf;
10439#if ENABLE_FEATURE_EDITING
10440 retry:
10441 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10442 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10443 else {
10444# if ENABLE_ASH_IDLE_TIMEOUT
10445 int timeout = -1;
10446 if (iflag) {
10447 const char *tmout_var = lookupvar("TMOUT");
10448 if (tmout_var) {
10449 timeout = atoi(tmout_var) * 1000;
10450 if (timeout <= 0)
10451 timeout = -1;
10452 }
10453 }
10454 line_input_state->timeout = timeout;
10455# endif
10456# if ENABLE_FEATURE_TAB_COMPLETION
10457 line_input_state->path_lookup = pathval();
10458# endif
10459 reinit_unicode_for_ash();
10460 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10461 if (nr == 0) {
10462
10463 write(STDOUT_FILENO, "^C", 2);
10464 if (trap[SIGINT]) {
10465 buf[0] = '\n';
10466 buf[1] = '\0';
10467 raise(SIGINT);
10468 return 1;
10469 }
10470 exitstatus = 128 + SIGINT;
10471 bb_putchar('\n');
10472 goto retry;
10473 }
10474 if (nr < 0) {
10475 if (errno == 0) {
10476
10477 nr = 0;
10478 }
10479# if ENABLE_ASH_IDLE_TIMEOUT
10480 else if (errno == EAGAIN && timeout > 0) {
10481 puts("\007timed out waiting for input: auto-logout");
10482 exitshell();
10483 }
10484# endif
10485 }
10486 }
10487#else
10488 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10489#endif
10490
10491#if 0
10492 if (nr < 0) {
10493 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10494 int flags = fcntl(0, F_GETFL);
10495 if (flags >= 0 && (flags & O_NONBLOCK)) {
10496 flags &= ~O_NONBLOCK;
10497 if (fcntl(0, F_SETFL, flags) >= 0) {
10498 out2str("sh: turning off NDELAY mode\n");
10499 goto retry;
10500 }
10501 }
10502 }
10503 }
10504#endif
10505 return nr;
10506}
10507
10508
10509
10510
10511
10512
10513
10514
10515
10516
10517
10518
10519#define pgetc_debug(...) ((void)0)
10520static int pgetc(void);
10521static int
10522preadbuffer(void)
10523{
10524 char *q;
10525 int more;
10526
10527 if (g_parsefile->strpush) {
10528#if ENABLE_ASH_ALIAS
10529 if (g_parsefile->left_in_line == -1
10530 && g_parsefile->strpush->ap
10531 && g_parsefile->next_to_pgetc[-1] != ' '
10532 && g_parsefile->next_to_pgetc[-1] != '\t'
10533 ) {
10534 pgetc_debug("preadbuffer PEOA");
10535 return PEOA;
10536 }
10537#endif
10538 popstring();
10539 return pgetc();
10540 }
10541
10542
10543
10544
10545
10546
10547
10548
10549 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
10550 pgetc_debug("preadbuffer PEOF1");
10551
10552
10553
10554
10555 g_parsefile->next_to_pgetc++;
10556 return PEOF;
10557 }
10558
10559 more = g_parsefile->left_in_buffer;
10560 if (more <= 0) {
10561 flush_stdout_stderr();
10562 again:
10563 more = preadfd();
10564 if (more <= 0) {
10565
10566 g_parsefile->left_in_line = -99;
10567 pgetc_debug("preadbuffer PEOF2");
10568 g_parsefile->next_to_pgetc++;
10569 return PEOF;
10570 }
10571 }
10572
10573
10574
10575
10576
10577
10578 q = g_parsefile->next_to_pgetc;
10579 for (;;) {
10580 char c;
10581
10582 more--;
10583
10584 c = *q;
10585 if (c == '\0') {
10586 memmove(q, q + 1, more);
10587 } else {
10588 q++;
10589 if (c == '\n') {
10590 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10591 break;
10592 }
10593 }
10594
10595 if (more <= 0) {
10596 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10597 if (g_parsefile->left_in_line < 0)
10598 goto again;
10599 break;
10600 }
10601 }
10602 g_parsefile->left_in_buffer = more;
10603
10604 if (vflag) {
10605 char save = *q;
10606 *q = '\0';
10607 out2str(g_parsefile->next_to_pgetc);
10608 *q = save;
10609 }
10610
10611 pgetc_debug("preadbuffer at %d:%p'%s'",
10612 g_parsefile->left_in_line,
10613 g_parsefile->next_to_pgetc,
10614 g_parsefile->next_to_pgetc);
10615 return (unsigned char)*g_parsefile->next_to_pgetc++;
10616}
10617
10618static void
10619nlprompt(void)
10620{
10621 g_parsefile->linno++;
10622 setprompt_if(doprompt, 2);
10623}
10624static void
10625nlnoprompt(void)
10626{
10627 g_parsefile->linno++;
10628 needprompt = doprompt;
10629}
10630
10631static int
10632pgetc(void)
10633{
10634 int c;
10635
10636 pgetc_debug("pgetc at %d:%p'%s'",
10637 g_parsefile->left_in_line,
10638 g_parsefile->next_to_pgetc,
10639 g_parsefile->next_to_pgetc);
10640 if (g_parsefile->unget)
10641 return g_parsefile->lastc[--g_parsefile->unget];
10642
10643 if (--g_parsefile->left_in_line >= 0)
10644 c = (unsigned char)*g_parsefile->next_to_pgetc++;
10645 else
10646 c = preadbuffer();
10647
10648 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10649 g_parsefile->lastc[0] = c;
10650
10651 return c;
10652}
10653
10654#if ENABLE_ASH_ALIAS
10655static int
10656pgetc_without_PEOA(void)
10657{
10658 int c;
10659 do {
10660 pgetc_debug("pgetc at %d:%p'%s'",
10661 g_parsefile->left_in_line,
10662 g_parsefile->next_to_pgetc,
10663 g_parsefile->next_to_pgetc);
10664 c = pgetc();
10665 } while (c == PEOA);
10666 return c;
10667}
10668#else
10669# define pgetc_without_PEOA() pgetc()
10670#endif
10671
10672
10673
10674
10675
10676static void
10677pungetc(void)
10678{
10679 g_parsefile->unget++;
10680}
10681
10682
10683static int
10684pgetc_eatbnl(void)
10685{
10686 int c;
10687
10688 while ((c = pgetc()) == '\\') {
10689 if (pgetc() != '\n') {
10690 pungetc();
10691 break;
10692 }
10693
10694 nlprompt();
10695 }
10696
10697 return c;
10698}
10699
10700struct synstack {
10701 smalluint syntax;
10702 uint8_t innerdq :1;
10703 uint8_t varpushed :1;
10704 uint8_t dblquote :1;
10705 int varnest;
10706 int dqvarnest;
10707 int parenlevel;
10708 struct synstack *prev;
10709 struct synstack *next;
10710};
10711
10712static void
10713synstack_push(struct synstack **stack, struct synstack *next, int syntax)
10714{
10715 memset(next, 0, sizeof(*next));
10716 next->syntax = syntax;
10717 next->next = *stack;
10718 (*stack)->prev = next;
10719 *stack = next;
10720}
10721
10722static ALWAYS_INLINE void
10723synstack_pop(struct synstack **stack)
10724{
10725 *stack = (*stack)->next;
10726}
10727
10728
10729
10730
10731
10732static void
10733pushfile(void)
10734{
10735 struct parsefile *pf;
10736
10737 pf = ckzalloc(sizeof(*pf));
10738 pf->prev = g_parsefile;
10739 pf->pf_fd = -1;
10740
10741
10742
10743 g_parsefile = pf;
10744}
10745
10746static void
10747popfile(void)
10748{
10749 struct parsefile *pf = g_parsefile;
10750
10751 if (pf == &basepf)
10752 return;
10753
10754 INT_OFF;
10755 if (pf->pf_fd >= 0)
10756 close(pf->pf_fd);
10757 free(pf->buf);
10758 while (pf->strpush)
10759 popstring();
10760 g_parsefile = pf->prev;
10761 free(pf);
10762 INT_ON;
10763}
10764
10765
10766
10767
10768static void
10769popallfiles(void)
10770{
10771 while (g_parsefile != &basepf)
10772 popfile();
10773}
10774
10775
10776
10777
10778
10779static void
10780closescript(void)
10781{
10782 popallfiles();
10783 if (g_parsefile->pf_fd > 0) {
10784 close(g_parsefile->pf_fd);
10785 g_parsefile->pf_fd = 0;
10786 }
10787}
10788
10789
10790
10791
10792
10793static void
10794setinputfd(int fd, int push)
10795{
10796 if (push) {
10797 pushfile();
10798 g_parsefile->buf = NULL;
10799 }
10800 g_parsefile->pf_fd = fd;
10801 if (g_parsefile->buf == NULL)
10802 g_parsefile->buf = ckmalloc(IBUFSIZ);
10803 g_parsefile->left_in_buffer = 0;
10804 g_parsefile->left_in_line = 0;
10805 g_parsefile->linno = 1;
10806}
10807
10808
10809
10810
10811
10812static int
10813setinputfile(const char *fname, int flags)
10814{
10815 int fd;
10816
10817 INT_OFF;
10818 fd = open(fname, O_RDONLY | O_CLOEXEC);
10819 if (fd < 0) {
10820 if (flags & INPUT_NOFILE_OK)
10821 goto out;
10822 exitstatus = 127;
10823 ash_msg_and_raise_perror("can't open '%s'", fname);
10824 }
10825 if (fd < 10)
10826 fd = savefd(fd);
10827 else if (O_CLOEXEC == 0)
10828 close_on_exec_on(fd);
10829
10830 setinputfd(fd, flags & INPUT_PUSH_FILE);
10831 out:
10832 INT_ON;
10833 return fd;
10834}
10835
10836
10837
10838
10839static void
10840setinputstring(char *string)
10841{
10842 INT_OFF;
10843 pushfile();
10844 g_parsefile->next_to_pgetc = string;
10845 g_parsefile->left_in_line = strlen(string);
10846 g_parsefile->buf = NULL;
10847 g_parsefile->linno = 1;
10848 INT_ON;
10849}
10850
10851
10852
10853
10854
10855
10856#if ENABLE_ASH_MAIL
10857
10858
10859static unsigned mailtime_hash;
10860
10861static smallint mail_var_path_changed;
10862
10863
10864
10865
10866
10867
10868
10869static void
10870chkmail(void)
10871{
10872 const char *mpath;
10873 char *p;
10874 char *q;
10875 unsigned new_hash;
10876 struct stackmark smark;
10877 struct stat statb;
10878
10879 setstackmark(&smark);
10880 mpath = mpathset() ? mpathval() : mailval();
10881 new_hash = 0;
10882 for (;;) {
10883 p = path_advance(&mpath, nullstr);
10884 if (p == NULL)
10885 break;
10886 if (*p == '\0')
10887 continue;
10888 for (q = p; *q; q++)
10889 continue;
10890#if DEBUG
10891 if (q[-1] != '/')
10892 abort();
10893#endif
10894 q[-1] = '\0';
10895 if (stat(p, &statb) < 0) {
10896 continue;
10897 }
10898
10899 new_hash += (unsigned)statb.st_mtime;
10900 }
10901 if (!mail_var_path_changed && mailtime_hash != new_hash) {
10902 if (mailtime_hash != 0)
10903 out2str("you have mail\n");
10904 mailtime_hash = new_hash;
10905 }
10906 mail_var_path_changed = 0;
10907 popstackmark(&smark);
10908}
10909
10910static void FAST_FUNC
10911changemail(const char *val UNUSED_PARAM)
10912{
10913 mail_var_path_changed = 1;
10914}
10915
10916#endif
10917
10918
10919
10920
10921
10922
10923
10924static void
10925setparam(char **argv)
10926{
10927 char **newparam;
10928 char **ap;
10929 int nparam;
10930
10931 for (nparam = 0; argv[nparam]; nparam++)
10932 continue;
10933 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10934 while (*argv) {
10935 *ap++ = ckstrdup(*argv++);
10936 }
10937 *ap = NULL;
10938 freeparam(&shellparam);
10939 shellparam.malloced = 1;
10940 shellparam.nparam = nparam;
10941 shellparam.p = newparam;
10942#if ENABLE_ASH_GETOPTS
10943 shellparam.optind = 1;
10944 shellparam.optoff = -1;
10945#endif
10946}
10947
10948
10949
10950
10951
10952
10953
10954
10955
10956
10957
10958
10959
10960
10961
10962
10963
10964
10965
10966
10967
10968
10969static int
10970plus_minus_o(char *name, int val)
10971{
10972 int i;
10973
10974 if (name) {
10975 for (i = 0; i < NOPTS; i++) {
10976 if (strcmp(name, optnames(i)) == 0) {
10977 optlist[i] = val;
10978 return 0;
10979 }
10980 }
10981 ash_msg("illegal option %co %s", val ? '-' : '+', name);
10982 return 1;
10983 }
10984 for (i = 0; i < NOPTS; i++) {
10985 if (val) {
10986 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10987 } else {
10988 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10989 }
10990 }
10991 return 0;
10992}
10993static void
10994setoption(int flag, int val)
10995{
10996 int i;
10997
10998 for (i = 0; i < NOPTS; i++) {
10999 if (optletters(i) == flag) {
11000 optlist[i] = val;
11001 return;
11002 }
11003 }
11004 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
11005
11006}
11007static int
11008options(int cmdline, int *login_sh)
11009{
11010 char *p;
11011 int val;
11012 int c;
11013
11014 if (cmdline)
11015 minusc = NULL;
11016 while ((p = *argptr) != NULL) {
11017 c = *p++;
11018 if (c != '-' && c != '+')
11019 break;
11020 argptr++;
11021 val = 0;
11022 if (c == '-') {
11023 val = 1;
11024 if (p[0] == '\0' || LONE_DASH(p)) {
11025 if (!cmdline) {
11026
11027 if (p[0] == '\0')
11028 xflag = vflag = 0;
11029
11030 else if (*argptr == NULL)
11031 setparam(argptr);
11032 }
11033 break;
11034 }
11035 }
11036
11037 while ((c = *p++) != '\0') {
11038
11039 if (c == 'c' && cmdline) {
11040 minusc = p;
11041 } else if (c == 'o') {
11042 if (plus_minus_o(*argptr, val)) {
11043
11044 return 1;
11045 }
11046 if (*argptr)
11047 argptr++;
11048 } else if (cmdline && (c == 'l')) {
11049 if (login_sh)
11050 *login_sh = 1;
11051
11052 } else if (cmdline && val && (c == '-')) {
11053 if (strcmp(p, "login") == 0) {
11054 if (login_sh)
11055 *login_sh = 1;
11056 }
11057 break;
11058 } else {
11059 setoption(c, val);
11060 }
11061 }
11062 }
11063 return 0;
11064}
11065
11066
11067
11068
11069static int FAST_FUNC
11070shiftcmd(int argc UNUSED_PARAM, char **argv)
11071{
11072 int n;
11073 char **ap1, **ap2;
11074
11075 n = 1;
11076 if (argv[1])
11077 n = number(argv[1]);
11078 if (n > shellparam.nparam)
11079 return 1;
11080 INT_OFF;
11081 shellparam.nparam -= n;
11082 for (ap1 = shellparam.p; --n >= 0; ap1++) {
11083 if (shellparam.malloced)
11084 free(*ap1);
11085 }
11086 ap2 = shellparam.p;
11087 while ((*ap2++ = *ap1++) != NULL)
11088 continue;
11089#if ENABLE_ASH_GETOPTS
11090 shellparam.optind = 1;
11091 shellparam.optoff = -1;
11092#endif
11093 INT_ON;
11094 return 0;
11095}
11096
11097
11098
11099
11100
11101
11102
11103
11104static int
11105showvars(const char *sep_prefix, int on, int off)
11106{
11107 const char *sep;
11108 char **ep, **epend;
11109
11110 ep = listvars(on, off, NULL, &epend);
11111 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11112
11113 sep = *sep_prefix ? " " : sep_prefix;
11114
11115 for (; ep < epend; ep++) {
11116 const char *p;
11117 const char *q;
11118
11119 p = endofname(*ep);
11120
11121
11122
11123
11124
11125
11126
11127
11128 q = nullstr;
11129 if (*p == '=')
11130 q = single_quote(++p);
11131 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11132 }
11133 return 0;
11134}
11135
11136
11137
11138
11139static int FAST_FUNC
11140setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11141{
11142 int retval;
11143
11144 if (!argv[1])
11145 return showvars(nullstr, 0, VUNSET);
11146
11147 INT_OFF;
11148 retval = options( 0, NULL);
11149 if (retval == 0) {
11150 optschanged();
11151 if (*argptr != NULL) {
11152 setparam(argptr);
11153 }
11154 }
11155 INT_ON;
11156 return retval;
11157}
11158
11159#if ENABLE_ASH_RANDOM_SUPPORT
11160static void FAST_FUNC
11161change_random(const char *value)
11162{
11163 uint32_t t;
11164
11165 if (value == NULL) {
11166
11167 t = next_random(&random_gen);
11168
11169 setvar(vrandom.var_text, utoa(t), VNOFUNC);
11170 vrandom.flags &= ~VNOFUNC;
11171 } else {
11172
11173 t = strtoul(value, NULL, 10);
11174 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
11175 }
11176}
11177#endif
11178
11179#if ENABLE_ASH_GETOPTS
11180static int
11181getopts(char *optstr, char *optvar, char **optfirst)
11182{
11183 char *p, *q;
11184 char c = '?';
11185 int done = 0;
11186 char sbuf[2];
11187 char **optnext;
11188 int ind = shellparam.optind;
11189 int off = shellparam.optoff;
11190
11191 sbuf[1] = '\0';
11192
11193 shellparam.optind = -1;
11194 optnext = optfirst + ind - 1;
11195
11196 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
11197 p = NULL;
11198 else
11199 p = optnext[-1] + off;
11200 if (p == NULL || *p == '\0') {
11201
11202 p = *optnext;
11203 if (p == NULL || *p != '-' || *++p == '\0') {
11204 atend:
11205 unsetvar("OPTARG");
11206 p = NULL;
11207 done = 1;
11208 goto out;
11209 }
11210 optnext++;
11211 if (LONE_DASH(p))
11212 goto atend;
11213 }
11214
11215 c = *p++;
11216 for (q = optstr; *q != c;) {
11217 if (*q == '\0') {
11218
11219 const char *cp = lookupvar("OPTERR");
11220 if ((cp && LONE_CHAR(cp, '0'))
11221 || (optstr[0] == ':')
11222 ) {
11223 sbuf[0] = c;
11224
11225 setvar0("OPTARG", sbuf);
11226 } else {
11227 fprintf(stderr, "Illegal option -%c\n", c);
11228 unsetvar("OPTARG");
11229 }
11230 c = '?';
11231 goto out;
11232 }
11233 if (*++q == ':')
11234 q++;
11235 }
11236
11237 if (*++q == ':') {
11238 if (*p == '\0' && (p = *optnext) == NULL) {
11239
11240 const char *cp = lookupvar("OPTERR");
11241 if ((cp && LONE_CHAR(cp, '0'))
11242 || (optstr[0] == ':')
11243 ) {
11244 sbuf[0] = c;
11245
11246 setvar0("OPTARG", sbuf);
11247 c = ':';
11248 } else {
11249 fprintf(stderr, "No arg for -%c option\n", c);
11250 unsetvar("OPTARG");
11251 c = '?';
11252 }
11253 goto out;
11254 }
11255
11256 if (p == *optnext)
11257 optnext++;
11258 setvar0("OPTARG", p);
11259 p = NULL;
11260 } else
11261 setvar0("OPTARG", nullstr);
11262 out:
11263 ind = optnext - optfirst + 1;
11264 setvar("OPTIND", itoa(ind), VNOFUNC);
11265 sbuf[0] = c;
11266
11267 setvar0(optvar, sbuf);
11268
11269 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11270 shellparam.optind = ind;
11271
11272 return done;
11273}
11274
11275
11276
11277
11278
11279
11280
11281static int FAST_FUNC
11282getoptscmd(int argc, char **argv)
11283{
11284 char **optbase;
11285
11286 if (argc < 3)
11287 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
11288 if (argc == 3) {
11289 optbase = shellparam.p;
11290 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
11291 shellparam.optind = 1;
11292 shellparam.optoff = -1;
11293 }
11294 } else {
11295 optbase = &argv[3];
11296 if ((unsigned)shellparam.optind > argc - 2) {
11297 shellparam.optind = 1;
11298 shellparam.optoff = -1;
11299 }
11300 }
11301
11302 return getopts(argv[1], argv[2], optbase);
11303}
11304#endif
11305
11306
11307
11308
11309struct heredoc {
11310 struct heredoc *next;
11311 union node *here;
11312 char *eofmark;
11313 smallint striptabs;
11314};
11315
11316static smallint tokpushback;
11317static smallint quoteflag;
11318static token_id_t lasttoken;
11319static struct heredoc *heredoclist;
11320static char *wordtext;
11321static struct nodelist *backquotelist;
11322static union node *redirnode;
11323static struct heredoc *heredoc;
11324
11325static const char *
11326tokname(char *buf, int tok)
11327{
11328 if (tok < TSEMI)
11329 return tokname_array[tok];
11330 sprintf(buf, "\"%s\"", tokname_array[tok]);
11331 return buf;
11332}
11333
11334
11335
11336
11337
11338
11339static void raise_error_unexpected_syntax(int) NORETURN;
11340static void
11341raise_error_unexpected_syntax(int token)
11342{
11343 char msg[64];
11344 char buf[16];
11345 int l;
11346
11347 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
11348 if (token >= 0)
11349 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
11350 raise_error_syntax(msg);
11351
11352}
11353
11354
11355static union node *andor(void);
11356static union node *pipeline(void);
11357static union node *parse_command(void);
11358static void parseheredoc(void);
11359static int peektoken(void);
11360static int readtoken(void);
11361
11362static union node *
11363list(int nlflag)
11364{
11365 union node *n1, *n2, *n3;
11366 int tok;
11367
11368 n1 = NULL;
11369 for (;;) {
11370 switch (peektoken()) {
11371 case TNL:
11372 if (!(nlflag & 1))
11373 break;
11374 parseheredoc();
11375 return n1;
11376
11377 case TEOF:
11378 if (!n1 && (nlflag & 1))
11379 n1 = NODE_EOF;
11380 parseheredoc();
11381 return n1;
11382 }
11383
11384 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11385 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
11386 return n1;
11387 nlflag |= 2;
11388
11389 n2 = andor();
11390 tok = readtoken();
11391 if (tok == TBACKGND) {
11392 if (n2->type == NPIPE) {
11393 n2->npipe.pipe_backgnd = 1;
11394 } else {
11395 if (n2->type != NREDIR) {
11396 n3 = stzalloc(sizeof(struct nredir));
11397 n3->nredir.n = n2;
11398
11399 n2 = n3;
11400 }
11401 n2->type = NBACKGND;
11402 }
11403 }
11404 if (n1 == NULL) {
11405 n1 = n2;
11406 } else {
11407 n3 = stzalloc(sizeof(struct nbinary));
11408 n3->type = NSEMI;
11409 n3->nbinary.ch1 = n1;
11410 n3->nbinary.ch2 = n2;
11411 n1 = n3;
11412 }
11413 switch (tok) {
11414 case TNL:
11415 case TEOF:
11416 tokpushback = 1;
11417
11418 case TBACKGND:
11419 case TSEMI:
11420 break;
11421 default:
11422 if ((nlflag & 1))
11423 raise_error_unexpected_syntax(-1);
11424 tokpushback = 1;
11425 return n1;
11426 }
11427 }
11428}
11429
11430static union node *
11431andor(void)
11432{
11433 union node *n1, *n2, *n3;
11434 int t;
11435
11436 n1 = pipeline();
11437 for (;;) {
11438 t = readtoken();
11439 if (t == TAND) {
11440 t = NAND;
11441 } else if (t == TOR) {
11442 t = NOR;
11443 } else {
11444 tokpushback = 1;
11445 return n1;
11446 }
11447 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11448 n2 = pipeline();
11449 n3 = stzalloc(sizeof(struct nbinary));
11450 n3->type = t;
11451 n3->nbinary.ch1 = n1;
11452 n3->nbinary.ch2 = n2;
11453 n1 = n3;
11454 }
11455}
11456
11457static union node *
11458pipeline(void)
11459{
11460 union node *n1, *n2, *pipenode;
11461 struct nodelist *lp, *prev;
11462 int negate;
11463
11464 negate = 0;
11465 TRACE(("pipeline: entered\n"));
11466 if (readtoken() == TNOT) {
11467 negate = !negate;
11468 checkkwd = CHKKWD | CHKALIAS;
11469 } else
11470 tokpushback = 1;
11471 n1 = parse_command();
11472 if (readtoken() == TPIPE) {
11473 pipenode = stzalloc(sizeof(struct npipe));
11474 pipenode->type = NPIPE;
11475
11476 lp = stzalloc(sizeof(struct nodelist));
11477 pipenode->npipe.cmdlist = lp;
11478 lp->n = n1;
11479 do {
11480 prev = lp;
11481 lp = stzalloc(sizeof(struct nodelist));
11482 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11483 lp->n = parse_command();
11484 prev->next = lp;
11485 } while (readtoken() == TPIPE);
11486 lp->next = NULL;
11487 n1 = pipenode;
11488 }
11489 tokpushback = 1;
11490 if (negate) {
11491 n2 = stzalloc(sizeof(struct nnot));
11492 n2->type = NNOT;
11493 n2->nnot.com = n1;
11494 return n2;
11495 }
11496 return n1;
11497}
11498
11499static union node *
11500makename(void)
11501{
11502 union node *n;
11503
11504 n = stzalloc(sizeof(struct narg));
11505 n->type = NARG;
11506
11507 n->narg.text = wordtext;
11508 n->narg.backquote = backquotelist;
11509 return n;
11510}
11511
11512static void
11513fixredir(union node *n, const char *text, int err)
11514{
11515 int fd;
11516
11517 TRACE(("Fix redir %s %d\n", text, err));
11518 if (!err)
11519 n->ndup.vname = NULL;
11520
11521 fd = bb_strtou(text, NULL, 10);
11522 if (!errno && fd >= 0)
11523 n->ndup.dupfd = fd;
11524 else if (LONE_DASH(text))
11525 n->ndup.dupfd = -1;
11526 else {
11527 if (err)
11528 raise_error_syntax("bad fd number");
11529 n->ndup.vname = makename();
11530 }
11531}
11532
11533static void
11534parsefname(void)
11535{
11536 union node *n = redirnode;
11537
11538 if (n->type == NHERE)
11539 checkkwd = CHKEOFMARK;
11540 if (readtoken() != TWORD)
11541 raise_error_unexpected_syntax(-1);
11542 if (n->type == NHERE) {
11543 struct heredoc *here = heredoc;
11544 struct heredoc *p;
11545
11546 if (quoteflag == 0)
11547 n->type = NXHERE;
11548 TRACE(("Here document %d\n", n->type));
11549 rmescapes(wordtext, 0, NULL);
11550 here->eofmark = wordtext;
11551 here->next = NULL;
11552 if (heredoclist == NULL)
11553 heredoclist = here;
11554 else {
11555 for (p = heredoclist; p->next; p = p->next)
11556 continue;
11557 p->next = here;
11558 }
11559 } else if (n->type == NTOFD || n->type == NFROMFD) {
11560 fixredir(n, wordtext, 0);
11561 } else {
11562 n->nfile.fname = makename();
11563 }
11564}
11565
11566static union node *
11567simplecmd(void)
11568{
11569 union node *args, **app;
11570 union node *n = NULL;
11571 union node *vars, **vpp;
11572 union node **rpp, *redir;
11573 int savecheckkwd;
11574 int savelinno;
11575#if BASH_TEST2
11576 smallint double_brackets_flag = 0;
11577#endif
11578 IF_BASH_FUNCTION(smallint function_flag = 0;)
11579
11580 args = NULL;
11581 app = &args;
11582 vars = NULL;
11583 vpp = &vars;
11584 redir = NULL;
11585 rpp = &redir;
11586
11587 savecheckkwd = CHKALIAS;
11588 savelinno = g_parsefile->linno;
11589 for (;;) {
11590 int t;
11591 checkkwd = savecheckkwd;
11592 t = readtoken();
11593 switch (t) {
11594#if BASH_FUNCTION
11595 case TFUNCTION:
11596 if (peektoken() != TWORD)
11597 raise_error_unexpected_syntax(TWORD);
11598 function_flag = 1;
11599 break;
11600#endif
11601#if BASH_TEST2
11602 case TAND:
11603 case TOR:
11604 if (!double_brackets_flag) {
11605 tokpushback = 1;
11606 goto out;
11607 }
11608 wordtext = (char *) (t == TAND ? "-a" : "-o");
11609#endif
11610 case TWORD:
11611 n = stzalloc(sizeof(struct narg));
11612 n->type = NARG;
11613
11614 n->narg.text = wordtext;
11615#if BASH_TEST2
11616 if (strcmp("[[", wordtext) == 0)
11617 double_brackets_flag = 1;
11618 else if (strcmp("]]", wordtext) == 0)
11619 double_brackets_flag = 0;
11620#endif
11621 n->narg.backquote = backquotelist;
11622 if (savecheckkwd && isassignment(wordtext)) {
11623 *vpp = n;
11624 vpp = &n->narg.next;
11625 } else {
11626 *app = n;
11627 app = &n->narg.next;
11628 savecheckkwd = 0;
11629 }
11630#if BASH_FUNCTION
11631 if (function_flag) {
11632 checkkwd = CHKNL | CHKKWD;
11633 switch (peektoken()) {
11634 case TBEGIN:
11635 case TIF:
11636 case TCASE:
11637 case TUNTIL:
11638 case TWHILE:
11639 case TFOR:
11640 goto do_func;
11641 case TLP:
11642 function_flag = 0;
11643 break;
11644# if BASH_TEST2
11645 case TWORD:
11646 if (strcmp("[[", wordtext) == 0)
11647 goto do_func;
11648
11649# endif
11650 default:
11651 raise_error_unexpected_syntax(-1);
11652 }
11653 }
11654#endif
11655 break;
11656 case TREDIR:
11657 *rpp = n = redirnode;
11658 rpp = &n->nfile.next;
11659 parsefname();
11660 break;
11661 case TLP:
11662 IF_BASH_FUNCTION(do_func:)
11663 if (args && app == &args->narg.next
11664 && !vars && !redir
11665 ) {
11666 struct builtincmd *bcmd;
11667 const char *name;
11668
11669
11670 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
11671 raise_error_unexpected_syntax(TRP);
11672 name = n->narg.text;
11673 if (!goodname(name)
11674 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11675 ) {
11676 raise_error_syntax("bad function name");
11677 }
11678 n->type = NDEFUN;
11679 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11680 n->ndefun.text = n->narg.text;
11681 n->ndefun.linno = g_parsefile->linno;
11682 n->ndefun.body = parse_command();
11683 return n;
11684 }
11685 IF_BASH_FUNCTION(function_flag = 0;)
11686
11687 default:
11688 tokpushback = 1;
11689 goto out;
11690 }
11691 }
11692 out:
11693 *app = NULL;
11694 *vpp = NULL;
11695 *rpp = NULL;
11696 n = stzalloc(sizeof(struct ncmd));
11697 if (NCMD != 0)
11698 n->type = NCMD;
11699 n->ncmd.linno = savelinno;
11700 n->ncmd.args = args;
11701 n->ncmd.assign = vars;
11702 n->ncmd.redirect = redir;
11703 return n;
11704}
11705
11706static union node *
11707parse_command(void)
11708{
11709 union node *n1, *n2;
11710 union node *ap, **app;
11711 union node *cp, **cpp;
11712 union node *redir, **rpp;
11713 union node **rpp2;
11714 int t;
11715 int savelinno;
11716
11717 redir = NULL;
11718 rpp2 = &redir;
11719
11720 savelinno = g_parsefile->linno;
11721
11722 switch (readtoken()) {
11723 default:
11724 raise_error_unexpected_syntax(-1);
11725
11726 case TIF:
11727 n1 = stzalloc(sizeof(struct nif));
11728 n1->type = NIF;
11729 n1->nif.test = list(0);
11730 if (readtoken() != TTHEN)
11731 raise_error_unexpected_syntax(TTHEN);
11732 n1->nif.ifpart = list(0);
11733 n2 = n1;
11734 while (readtoken() == TELIF) {
11735 n2->nif.elsepart = stzalloc(sizeof(struct nif));
11736 n2 = n2->nif.elsepart;
11737 n2->type = NIF;
11738 n2->nif.test = list(0);
11739 if (readtoken() != TTHEN)
11740 raise_error_unexpected_syntax(TTHEN);
11741 n2->nif.ifpart = list(0);
11742 }
11743 if (lasttoken == TELSE)
11744 n2->nif.elsepart = list(0);
11745 else {
11746 n2->nif.elsepart = NULL;
11747 tokpushback = 1;
11748 }
11749 t = TFI;
11750 break;
11751 case TWHILE:
11752 case TUNTIL: {
11753 int got;
11754 n1 = stzalloc(sizeof(struct nbinary));
11755 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
11756 n1->nbinary.ch1 = list(0);
11757 got = readtoken();
11758 if (got != TDO) {
11759 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
11760 got == TWORD ? wordtext : ""));
11761 raise_error_unexpected_syntax(TDO);
11762 }
11763 n1->nbinary.ch2 = list(0);
11764 t = TDONE;
11765 break;
11766 }
11767 case TFOR:
11768 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
11769 raise_error_syntax("bad for loop variable");
11770 n1 = stzalloc(sizeof(struct nfor));
11771 n1->type = NFOR;
11772 n1->nfor.linno = savelinno;
11773 n1->nfor.var = wordtext;
11774 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11775 if (readtoken() == TIN) {
11776 app = ≈
11777 while (readtoken() == TWORD) {
11778 n2 = stzalloc(sizeof(struct narg));
11779 n2->type = NARG;
11780
11781 n2->narg.text = wordtext;
11782 n2->narg.backquote = backquotelist;
11783 *app = n2;
11784 app = &n2->narg.next;
11785 }
11786 *app = NULL;
11787 n1->nfor.args = ap;
11788 if (lasttoken != TNL && lasttoken != TSEMI)
11789 raise_error_unexpected_syntax(-1);
11790 } else {
11791 n2 = stzalloc(sizeof(struct narg));
11792 n2->type = NARG;
11793
11794 n2->narg.text = (char *)dolatstr;
11795
11796 n1->nfor.args = n2;
11797
11798
11799
11800
11801 if (lasttoken != TSEMI)
11802 tokpushback = 1;
11803 }
11804 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11805 if (readtoken() != TDO)
11806 raise_error_unexpected_syntax(TDO);
11807 n1->nfor.body = list(0);
11808 t = TDONE;
11809 break;
11810 case TCASE:
11811 n1 = stzalloc(sizeof(struct ncase));
11812 n1->type = NCASE;
11813 n1->ncase.linno = savelinno;
11814 if (readtoken() != TWORD)
11815 raise_error_unexpected_syntax(TWORD);
11816 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
11817 n2->type = NARG;
11818
11819 n2->narg.text = wordtext;
11820 n2->narg.backquote = backquotelist;
11821 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11822 if (readtoken() != TIN)
11823 raise_error_unexpected_syntax(TIN);
11824 cpp = &n1->ncase.cases;
11825 next_case:
11826 checkkwd = CHKNL | CHKKWD;
11827 t = readtoken();
11828 while (t != TESAC) {
11829 if (lasttoken == TLP)
11830 readtoken();
11831 *cpp = cp = stzalloc(sizeof(struct nclist));
11832 cp->type = NCLIST;
11833 app = &cp->nclist.pattern;
11834 for (;;) {
11835 *app = ap = stzalloc(sizeof(struct narg));
11836 ap->type = NARG;
11837
11838 ap->narg.text = wordtext;
11839 ap->narg.backquote = backquotelist;
11840 if (readtoken() != TPIPE)
11841 break;
11842 app = &ap->narg.next;
11843 readtoken();
11844 }
11845
11846 if (lasttoken != TRP)
11847 raise_error_unexpected_syntax(TRP);
11848 cp->nclist.body = list(2);
11849
11850 cpp = &cp->nclist.next;
11851
11852 checkkwd = CHKNL | CHKKWD;
11853 t = readtoken();
11854 if (t != TESAC) {
11855 if (t != TENDCASE)
11856 raise_error_unexpected_syntax(TENDCASE);
11857 goto next_case;
11858 }
11859 }
11860 *cpp = NULL;
11861 goto redir;
11862 case TLP:
11863 n1 = stzalloc(sizeof(struct nredir));
11864 n1->type = NSUBSHELL;
11865 n1->nredir.linno = savelinno;
11866 n1->nredir.n = list(0);
11867
11868 t = TRP;
11869 break;
11870 case TBEGIN:
11871 n1 = list(0);
11872 t = TEND;
11873 break;
11874 IF_BASH_FUNCTION(case TFUNCTION:)
11875 case TWORD:
11876 case TREDIR:
11877 tokpushback = 1;
11878 return simplecmd();
11879 }
11880
11881 if (readtoken() != t)
11882 raise_error_unexpected_syntax(t);
11883
11884 redir:
11885
11886 checkkwd = CHKKWD | CHKALIAS;
11887 rpp = rpp2;
11888 while (readtoken() == TREDIR) {
11889 *rpp = n2 = redirnode;
11890 rpp = &n2->nfile.next;
11891 parsefname();
11892 }
11893 tokpushback = 1;
11894 *rpp = NULL;
11895 if (redir) {
11896 if (n1->type != NSUBSHELL) {
11897 n2 = stzalloc(sizeof(struct nredir));
11898 n2->type = NREDIR;
11899 n2->nredir.linno = savelinno;
11900 n2->nredir.n = n1;
11901 n1 = n2;
11902 }
11903 n1->nredir.redirect = redir;
11904 }
11905 return n1;
11906}
11907
11908#if BASH_DOLLAR_SQUOTE
11909static int
11910decode_dollar_squote(void)
11911{
11912 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11913 int c, cnt;
11914 char *p;
11915 char buf[4];
11916
11917 c = pgetc();
11918 p = strchr(C_escapes, c);
11919 if (p) {
11920 buf[0] = c;
11921 p = buf;
11922 cnt = 3;
11923 if ((unsigned char)(c - '0') <= 7) {
11924 do {
11925 c = pgetc();
11926 *++p = c;
11927 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11928 pungetc();
11929 } else if (c == 'x') {
11930 do {
11931 c = pgetc();
11932 *++p = c;
11933 } while (isxdigit(c) && --cnt);
11934 pungetc();
11935 if (cnt == 3) {
11936 c = 'x';
11937 goto unrecognized;
11938 }
11939 } else {
11940 p++;
11941 }
11942 *p = '\0';
11943 p = buf;
11944 c = bb_process_escape_sequence((void*)&p);
11945 } else {
11946 if (c != '\'' && c != '"') {
11947 unrecognized:
11948 c |= 0x100;
11949 }
11950 }
11951 return c;
11952}
11953#endif
11954
11955
11956#define FAKEEOFMARK ((char*)(uintptr_t)1)
11957
11958static ALWAYS_INLINE int
11959realeofmark(const char *eofmark)
11960{
11961 return eofmark && eofmark != FAKEEOFMARK;
11962}
11963
11964
11965
11966
11967
11968
11969
11970
11971
11972
11973
11974
11975#define CHECKEND() {goto checkend; checkend_return:;}
11976#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11977#define PARSESUB() {goto parsesub; parsesub_return:;}
11978#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11979#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11980#define PARSEARITH() {goto parsearith; parsearith_return:;}
11981static int
11982readtoken1(int c, int syntax, char *eofmark, int striptabs)
11983{
11984
11985
11986 char *out;
11987 size_t len;
11988 struct nodelist *bqlist;
11989 smallint quotef;
11990 smallint oldstyle;
11991 smallint pssyntax;
11992 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
11993
11994 struct synstack synbase = { };
11995 struct synstack *synstack = &synbase;
11996
11997#if ENABLE_ASH_EXPAND_PRMT
11998 pssyntax = (syntax == PSSYNTAX);
11999 if (pssyntax)
12000 syntax = DQSYNTAX;
12001#else
12002 pssyntax = 0;
12003#endif
12004 synstack->syntax = syntax;
12005
12006 if (syntax == DQSYNTAX)
12007 synstack->dblquote = 1;
12008 quotef = 0;
12009 bqlist = NULL;
12010
12011 STARTSTACKSTR(out);
12012 loop:
12013
12014 CHECKEND();
12015 for (;;) {
12016 CHECKSTRSPACE(4, out);
12017 switch (SIT(c, synstack->syntax)) {
12018 case CNL:
12019 if (synstack->syntax == BASESYNTAX
12020 && !synstack->varnest
12021 ) {
12022 goto endword;
12023 }
12024 USTPUTC(c, out);
12025 nlprompt();
12026 c = pgetc();
12027 goto loop;
12028 case CWORD:
12029 USTPUTC(c, out);
12030 break;
12031 case CCTL:
12032#if BASH_DOLLAR_SQUOTE
12033 if (c == '\\' && bash_dollar_squote) {
12034 c = decode_dollar_squote();
12035 if (c == '\0') {
12036
12037 break;
12038 }
12039 if (c & 0x100) {
12040
12041 c = (unsigned char)c;
12042 if (eofmark == NULL || synstack->dblquote)
12043 USTPUTC(CTLESC, out);
12044 USTPUTC('\\', out);
12045 }
12046 }
12047#endif
12048 if (!eofmark || synstack->dblquote || synstack->varnest)
12049 USTPUTC(CTLESC, out);
12050 USTPUTC(c, out);
12051 break;
12052 case CBACK:
12053 c = pgetc_without_PEOA();
12054 if (c == PEOF) {
12055 USTPUTC(CTLESC, out);
12056 USTPUTC('\\', out);
12057 pungetc();
12058 } else if (c == '\n') {
12059 nlprompt();
12060 } else {
12061 if (pssyntax && c == '$') {
12062 USTPUTC(CTLESC, out);
12063 USTPUTC('\\', out);
12064 }
12065
12066
12067
12068 if (synstack->dblquote
12069 && c != '\\'
12070 && c != '`'
12071 && c != '$'
12072 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12073 && (c != '}' || !synstack->varnest)
12074 ) {
12075 USTPUTC(CTLESC, out);
12076 USTPUTC('\\', out);
12077 }
12078 USTPUTC(CTLESC, out);
12079 USTPUTC(c, out);
12080 quotef = 1;
12081 }
12082 break;
12083 case CSQUOTE:
12084 synstack->syntax = SQSYNTAX;
12085 quotemark:
12086 if (eofmark == NULL) {
12087 USTPUTC(CTLQUOTEMARK, out);
12088 }
12089 break;
12090 case CDQUOTE:
12091 synstack->syntax = DQSYNTAX;
12092 synstack->dblquote = 1;
12093 toggledq:
12094 if (synstack->varnest)
12095 synstack->innerdq ^= 1;
12096 goto quotemark;
12097 case CENDQUOTE:
12098 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
12099 if (eofmark != NULL && synstack->varnest == 0) {
12100 USTPUTC(c, out);
12101 break;
12102 }
12103
12104 if (synstack->dqvarnest == 0) {
12105 synstack->syntax = BASESYNTAX;
12106 synstack->dblquote = 0;
12107 }
12108
12109 quotef = 1;
12110
12111 if (c == '"')
12112 goto toggledq;
12113
12114 goto quotemark;
12115 case CVAR:
12116 PARSESUB();
12117 break;
12118 case CENDVAR:
12119 if (!synstack->innerdq && synstack->varnest > 0) {
12120 if (!--synstack->varnest && synstack->varpushed)
12121 synstack_pop(&synstack);
12122 else if (synstack->dqvarnest > 0)
12123 synstack->dqvarnest--;
12124 c = CTLENDVAR;
12125 }
12126 USTPUTC(c, out);
12127 break;
12128#if ENABLE_FEATURE_SH_MATH
12129 case CLP:
12130 synstack->parenlevel++;
12131 USTPUTC(c, out);
12132 break;
12133 case CRP:
12134 if (synstack->parenlevel > 0) {
12135 synstack->parenlevel--;
12136 } else {
12137 if (pgetc_eatbnl() == ')') {
12138 c = CTLENDARI;
12139 synstack_pop(&synstack);
12140 } else {
12141
12142
12143
12144
12145 pungetc();
12146 }
12147 }
12148 USTPUTC(c, out);
12149 break;
12150#endif
12151 case CBQUOTE:
12152 if (checkkwd & CHKEOFMARK) {
12153 quotef = 1;
12154 USTPUTC('`', out);
12155 break;
12156 }
12157
12158 PARSEBACKQOLD();
12159 break;
12160 case CENDFILE:
12161 goto endword;
12162 case CIGN:
12163 break;
12164 default:
12165 if (synstack->varnest == 0) {
12166#if BASH_REDIR_OUTPUT
12167 if (c == '&') {
12168
12169 if (pgetc() == '>')
12170 c = 0x100 + '>';
12171 pungetc();
12172 }
12173#endif
12174 goto endword;
12175 }
12176 IF_ASH_ALIAS(if (c != PEOA))
12177 USTPUTC(c, out);
12178 }
12179 c = pgetc();
12180 }
12181 endword:
12182
12183#if ENABLE_FEATURE_SH_MATH
12184 if (synstack->syntax == ARISYNTAX)
12185 raise_error_syntax("missing '))'");
12186#endif
12187 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
12188 raise_error_syntax("unterminated quoted string");
12189 if (synstack->varnest != 0) {
12190
12191 raise_error_syntax("missing '}'");
12192 }
12193 USTPUTC('\0', out);
12194 len = out - (char *)stackblock();
12195 out = stackblock();
12196 if (eofmark == NULL) {
12197 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
12198 && quotef == 0
12199 ) {
12200 if (isdigit_str9(out)) {
12201 PARSEREDIR();
12202 lasttoken = TREDIR;
12203 return lasttoken;
12204 }
12205
12206
12207 }
12208 pungetc();
12209 }
12210 quoteflag = quotef;
12211 backquotelist = bqlist;
12212 grabstackblock(len);
12213 wordtext = out;
12214 lasttoken = TWORD;
12215 return lasttoken;
12216
12217
12218
12219
12220
12221
12222
12223checkend: {
12224 if (realeofmark(eofmark)) {
12225 int markloc;
12226 char *p;
12227
12228#if ENABLE_ASH_ALIAS
12229 if (c == PEOA)
12230 c = pgetc_without_PEOA();
12231#endif
12232 if (striptabs) {
12233 while (c == '\t') {
12234 c = pgetc_without_PEOA();
12235 }
12236 }
12237
12238 markloc = out - (char *)stackblock();
12239 for (p = eofmark; STPUTC(c, out), *p; p++) {
12240 if (c != *p)
12241 goto more_heredoc;
12242
12243 c = pgetc_without_PEOA();
12244 }
12245
12246 if (c == '\n' || c == PEOF) {
12247 c = PEOF;
12248 g_parsefile->linno++;
12249 needprompt = doprompt;
12250 } else {
12251 int len_here;
12252
12253 more_heredoc:
12254 p = (char *)stackblock() + markloc + 1;
12255 len_here = out - p;
12256
12257 if (len_here) {
12258 len_here -= (c >= PEOF);
12259 c = p[-1];
12260
12261 if (len_here) {
12262 char *str;
12263
12264 str = alloca(len_here + 1);
12265 *(char *)mempcpy(str, p, len_here) = '\0';
12266
12267 pushstring(str, NULL);
12268 }
12269 }
12270 }
12271
12272 STADJUST((char *)stackblock() + markloc - out, out);
12273 }
12274 goto checkend_return;
12275}
12276
12277
12278
12279
12280
12281
12282parseredir: {
12283
12284 int fd = (*out == '\0' ? -1 : atoi(out));
12285 union node *np;
12286
12287 np = stzalloc(sizeof(struct nfile));
12288 if (c == '>') {
12289 np->nfile.fd = 1;
12290 c = pgetc_eatbnl();
12291 if (c == '>')
12292 np->type = NAPPEND;
12293 else if (c == '|')
12294 np->type = NCLOBBER;
12295 else if (c == '&')
12296 np->type = NTOFD;
12297
12298 else {
12299 np->type = NTO;
12300 pungetc();
12301 }
12302 }
12303#if BASH_REDIR_OUTPUT
12304 else if (c == 0x100 + '>') {
12305 np->nfile.fd = 1;
12306 pgetc();
12307 np->type = NTO2;
12308 }
12309#endif
12310 else {
12311
12312 c = pgetc_eatbnl();
12313 switch (c) {
12314 case '<':
12315 if (sizeof(struct nfile) != sizeof(struct nhere)) {
12316 np = stzalloc(sizeof(struct nhere));
12317
12318 }
12319 np->type = NHERE;
12320 heredoc = stzalloc(sizeof(struct heredoc));
12321 heredoc->here = np;
12322 c = pgetc_eatbnl();
12323 if (c == '-') {
12324 heredoc->striptabs = 1;
12325 } else {
12326
12327 pungetc();
12328 }
12329 break;
12330
12331 case '&':
12332 np->type = NFROMFD;
12333 break;
12334
12335 case '>':
12336 np->type = NFROMTO;
12337 break;
12338
12339 default:
12340 np->type = NFROM;
12341 pungetc();
12342 break;
12343 }
12344 }
12345 if (fd >= 0)
12346 np->nfile.fd = fd;
12347 redirnode = np;
12348 goto parseredir_return;
12349}
12350
12351
12352
12353
12354
12355
12356
12357
12358#define is_special(c) \
12359 (((unsigned)(c) - 33 < 32) \
12360 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
12361parsesub: {
12362 unsigned char subtype;
12363 int typeloc;
12364
12365 c = pgetc_eatbnl();
12366 if ((checkkwd & CHKEOFMARK)
12367 || c > 255
12368 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
12369 ) {
12370#if BASH_DOLLAR_SQUOTE
12371 if (synstack->syntax != DQSYNTAX && c == '\'')
12372 bash_dollar_squote = 1;
12373 else
12374#endif
12375 USTPUTC('$', out);
12376 pungetc();
12377 } else if (c == '(') {
12378
12379 if (pgetc_eatbnl() == '(') {
12380#if ENABLE_FEATURE_SH_MATH
12381 PARSEARITH();
12382#else
12383 raise_error_syntax("support for $((arith)) is disabled");
12384#endif
12385 } else {
12386 pungetc();
12387 PARSEBACKQNEW();
12388 }
12389 } else {
12390
12391 smalluint newsyn = synstack->syntax;
12392
12393 USTPUTC(CTLVAR, out);
12394 typeloc = out - (char *)stackblock();
12395 STADJUST(1, out);
12396 subtype = VSNORMAL;
12397 if (c == '{') {
12398 c = pgetc_eatbnl();
12399 subtype = 0;
12400 }
12401 varname:
12402 if (is_name(c)) {
12403
12404 do {
12405 STPUTC(c, out);
12406 c = pgetc_eatbnl();
12407 } while (is_in_name(c));
12408 } else if (isdigit(c)) {
12409
12410 do {
12411 STPUTC(c, out);
12412 c = pgetc_eatbnl();
12413 } while (isdigit(c));
12414 } else {
12415
12416 int cc = c;
12417
12418 c = pgetc_eatbnl();
12419 if (!subtype && cc == '#') {
12420 subtype = VSLENGTH;
12421 if (c == '_' || isalnum(c))
12422 goto varname;
12423 cc = c;
12424 c = pgetc_eatbnl();
12425 if (cc == '}' || c != '}') {
12426 pungetc();
12427 subtype = 0;
12428 c = cc;
12429 cc = '#';
12430 }
12431 }
12432
12433 if (!is_special(cc)) {
12434 if (subtype == VSLENGTH)
12435 subtype = 0;
12436 goto badsub;
12437 }
12438
12439 USTPUTC(cc, out);
12440 }
12441
12442 if (c != '}' && subtype == VSLENGTH) {
12443
12444 goto badsub;
12445 }
12446
12447 if (subtype == 0) {
12448 static const char types[] ALIGN1 = "}-+?=";
12449
12450
12451 int cc = c;
12452
12453 switch (c) {
12454 case ':':
12455 c = pgetc_eatbnl();
12456#if BASH_SUBSTR
12457
12458
12459
12460
12461 if (!strchr(types, c)) {
12462 subtype = VSSUBSTR;
12463 pungetc();
12464 break;
12465 }
12466#endif
12467 subtype = VSNUL;
12468
12469 default: {
12470 const char *p = strchr(types, c);
12471 if (p == NULL)
12472 break;
12473 subtype |= p - types + VSNORMAL;
12474 break;
12475 }
12476 case '%':
12477 case '#':
12478 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12479 c = pgetc_eatbnl();
12480 if (c == cc)
12481 subtype++;
12482 else
12483 pungetc();
12484
12485 newsyn = BASESYNTAX;
12486 break;
12487#if BASH_PATTERN_SUBST
12488 case '/':
12489
12490
12491
12492
12493 subtype = VSREPLACE;
12494 newsyn = BASESYNTAX;
12495 c = pgetc_eatbnl();
12496 if (c != '/')
12497 goto badsub;
12498 subtype++;
12499 break;
12500#endif
12501 }
12502 } else {
12503 badsub:
12504 pungetc();
12505 }
12506
12507 if (newsyn == ARISYNTAX)
12508 newsyn = DQSYNTAX;
12509
12510 if ((newsyn != synstack->syntax || synstack->innerdq)
12511 && subtype != VSNORMAL
12512 ) {
12513 synstack_push(&synstack,
12514 synstack->prev ?: alloca(sizeof(*synstack)),
12515 newsyn);
12516
12517 synstack->varpushed = 1;
12518 synstack->dblquote = newsyn != BASESYNTAX;
12519 }
12520
12521 ((unsigned char *)stackblock())[typeloc] = subtype;
12522 if (subtype != VSNORMAL) {
12523 synstack->varnest++;
12524 if (synstack->dblquote)
12525 synstack->dqvarnest++;
12526 }
12527 STPUTC('=', out);
12528 }
12529 goto parsesub_return;
12530}
12531
12532
12533
12534
12535
12536
12537
12538parsebackq: {
12539 struct nodelist **nlpp;
12540 union node *n;
12541 char *str;
12542 size_t savelen;
12543 smallint saveprompt = 0;
12544
12545 str = NULL;
12546 savelen = out - (char *)stackblock();
12547 if (savelen > 0) {
12548
12549
12550
12551
12552
12553
12554
12555
12556 str = alloca(savelen);
12557 memcpy(str, stackblock(), savelen);
12558 }
12559
12560 if (oldstyle) {
12561
12562
12563
12564
12565 char *pout;
12566 size_t psavelen;
12567 char *pstr;
12568
12569 STARTSTACKSTR(pout);
12570 for (;;) {
12571 int pc;
12572
12573 setprompt_if(needprompt, 2);
12574 pc = pgetc_eatbnl();
12575 switch (pc) {
12576 case '`':
12577 goto done;
12578
12579 case '\\':
12580 pc = pgetc();
12581 if (pc != '\\' && pc != '`' && pc != '$'
12582 && (!synstack->dblquote || pc != '"')
12583 ) {
12584 STPUTC('\\', pout);
12585 }
12586 if (pc <= 255 ) {
12587 break;
12588 }
12589
12590
12591 case PEOF:
12592 IF_ASH_ALIAS(case PEOA:)
12593 raise_error_syntax("EOF in backquote substitution");
12594
12595 case '\n':
12596 nlnoprompt();
12597 break;
12598
12599 default:
12600 break;
12601 }
12602 STPUTC(pc, pout);
12603 }
12604 done:
12605 STPUTC('\0', pout);
12606 psavelen = pout - (char *)stackblock();
12607 if (psavelen > 0) {
12608 pstr = grabstackstr(pout);
12609 setinputstring(pstr);
12610 }
12611 }
12612 nlpp = &bqlist;
12613 while (*nlpp)
12614 nlpp = &(*nlpp)->next;
12615 *nlpp = stzalloc(sizeof(**nlpp));
12616
12617
12618 if (oldstyle) {
12619 saveprompt = doprompt;
12620 doprompt = 0;
12621 }
12622
12623 n = list(2);
12624
12625 if (oldstyle)
12626 doprompt = saveprompt;
12627 else if (readtoken() != TRP)
12628 raise_error_unexpected_syntax(TRP);
12629
12630 (*nlpp)->n = n;
12631 if (oldstyle) {
12632
12633
12634
12635
12636 popfile();
12637 tokpushback = 0;
12638 }
12639 while (stackblocksize() <= savelen)
12640 growstackblock();
12641 STARTSTACKSTR(out);
12642 if (str) {
12643 memcpy(out, str, savelen);
12644 STADJUST(savelen, out);
12645 }
12646 USTPUTC(CTLBACKQ, out);
12647 if (oldstyle)
12648 goto parsebackq_oldreturn;
12649 goto parsebackq_newreturn;
12650}
12651
12652#if ENABLE_FEATURE_SH_MATH
12653
12654
12655
12656parsearith: {
12657
12658 synstack_push(&synstack,
12659 synstack->prev ?: alloca(sizeof(*synstack)),
12660 ARISYNTAX);
12661 synstack->dblquote = 1;
12662 USTPUTC(CTLARI, out);
12663 goto parsearith_return;
12664}
12665#endif
12666}
12667
12668
12669
12670
12671
12672
12673
12674
12675
12676
12677
12678
12679
12680
12681
12682
12683#define NEW_xxreadtoken
12684#ifdef NEW_xxreadtoken
12685
12686static const char xxreadtoken_chars[7] ALIGN1 = {
12687 '\n', '(', ')',
12688 '&', '|', ';',
12689 0
12690};
12691
12692#define xxreadtoken_singles 3
12693#define xxreadtoken_doubles 3
12694
12695static const char xxreadtoken_tokens[] ALIGN1 = {
12696 TNL, TLP, TRP,
12697 TBACKGND, TPIPE, TSEMI,
12698 TEOF,
12699 TAND, TOR, TENDCASE
12700};
12701
12702static int
12703xxreadtoken(void)
12704{
12705 int c;
12706
12707 if (tokpushback) {
12708 tokpushback = 0;
12709 return lasttoken;
12710 }
12711 setprompt_if(needprompt, 2);
12712 for (;;) {
12713 c = pgetc_eatbnl();
12714 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
12715 continue;
12716
12717 if (c == '#') {
12718 while ((c = pgetc()) != '\n' && c != PEOF)
12719 continue;
12720 pungetc();
12721 } else if (c == '\\') {
12722 break;
12723 } else {
12724 const char *p;
12725
12726 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12727 if (c != PEOF) {
12728 if (c == '\n') {
12729 nlnoprompt();
12730 }
12731
12732 p = strchr(xxreadtoken_chars, c);
12733 if (p == NULL)
12734 break;
12735
12736 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12737 int cc = pgetc_eatbnl();
12738 if (cc == c) {
12739 p += xxreadtoken_doubles + 1;
12740 } else {
12741 pungetc();
12742#if BASH_REDIR_OUTPUT
12743 if (c == '&' && cc == '>')
12744 break;
12745#endif
12746 }
12747 }
12748 }
12749 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12750 return lasttoken;
12751 }
12752 }
12753
12754 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
12755}
12756#else
12757#define RETURN(token) return lasttoken = token
12758static int
12759xxreadtoken(void)
12760{
12761 int c;
12762
12763 if (tokpushback) {
12764 tokpushback = 0;
12765 return lasttoken;
12766 }
12767 setprompt_if(needprompt, 2);
12768 for (;;) {
12769 c = pgetc_eatbnl();
12770 switch (c) {
12771 case ' ': case '\t':
12772 IF_ASH_ALIAS(case PEOA:)
12773 continue;
12774 case '#':
12775 while ((c = pgetc()) != '\n' && c != PEOF)
12776 continue;
12777 pungetc();
12778 continue;
12779 case '\n':
12780 nlnoprompt();
12781 RETURN(TNL);
12782 case PEOF:
12783 RETURN(TEOF);
12784 case '&':
12785 if (pgetc_eatbnl() == '&')
12786 RETURN(TAND);
12787 pungetc();
12788 RETURN(TBACKGND);
12789 case '|':
12790 if (pgetc_eatbnl() == '|')
12791 RETURN(TOR);
12792 pungetc();
12793 RETURN(TPIPE);
12794 case ';':
12795 if (pgetc_eatbnl() == ';')
12796 RETURN(TENDCASE);
12797 pungetc();
12798 RETURN(TSEMI);
12799 case '(':
12800 RETURN(TLP);
12801 case ')':
12802 RETURN(TRP);
12803 }
12804 break;
12805 }
12806 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12807#undef RETURN
12808}
12809#endif
12810
12811static int
12812readtoken(void)
12813{
12814 int t;
12815 int kwd = checkkwd;
12816#if DEBUG
12817 smallint alreadyseen = tokpushback;
12818#endif
12819
12820#if ENABLE_ASH_ALIAS
12821 top:
12822#endif
12823
12824 t = xxreadtoken();
12825
12826
12827
12828
12829 if (kwd & CHKNL) {
12830 while (t == TNL) {
12831 parseheredoc();
12832 t = xxreadtoken();
12833 }
12834 }
12835
12836 if (t != TWORD || quoteflag) {
12837 goto out;
12838 }
12839
12840
12841
12842
12843 if (kwd & CHKKWD) {
12844 const char *const *pp;
12845
12846 pp = findkwd(wordtext);
12847 if (pp) {
12848 lasttoken = t = pp - tokname_array;
12849 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
12850 goto out;
12851 }
12852 }
12853
12854 if (checkkwd & CHKALIAS) {
12855#if ENABLE_ASH_ALIAS
12856 struct alias *ap;
12857 ap = lookupalias(wordtext, 1);
12858 if (ap != NULL) {
12859 if (*ap->val) {
12860 pushstring(ap->val, ap);
12861 }
12862 goto top;
12863 }
12864#endif
12865 }
12866 out:
12867 checkkwd = 0;
12868#if DEBUG
12869 if (!alreadyseen)
12870 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12871 else
12872 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12873#endif
12874 return t;
12875}
12876
12877static int
12878peektoken(void)
12879{
12880 int t;
12881
12882 t = readtoken();
12883 tokpushback = 1;
12884 return t;
12885}
12886
12887
12888
12889
12890
12891static union node *
12892parsecmd(int interact)
12893{
12894 tokpushback = 0;
12895 checkkwd = 0;
12896 heredoclist = 0;
12897 doprompt = interact;
12898 setprompt_if(doprompt, doprompt);
12899 needprompt = 0;
12900 return list(1);
12901}
12902
12903
12904
12905
12906static void
12907parseheredoc(void)
12908{
12909 struct heredoc *here;
12910 union node *n;
12911
12912 here = heredoclist;
12913 heredoclist = NULL;
12914
12915 while (here) {
12916 setprompt_if(needprompt, 2);
12917 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
12918 here->eofmark, here->striptabs);
12919 n = stzalloc(sizeof(struct narg));
12920 n->narg.type = NARG;
12921
12922 n->narg.text = wordtext;
12923 n->narg.backquote = backquotelist;
12924 here->here->nhere.doc = n;
12925 here = here->next;
12926 }
12927}
12928
12929
12930static const char *
12931expandstr(const char *ps, int syntax_type)
12932{
12933 union node n;
12934 int saveprompt;
12935
12936
12937 setinputstring((char *)ps);
12938
12939 saveprompt = doprompt;
12940 doprompt = 0;
12941
12942
12943
12944
12945
12946 {
12947 volatile int saveint;
12948 struct jmploc *volatile savehandler = exception_handler;
12949 struct jmploc jmploc;
12950 SAVE_INT(saveint);
12951 if (setjmp(jmploc.loc) == 0) {
12952 exception_handler = &jmploc;
12953 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
12954 }
12955 exception_handler = savehandler;
12956 RESTORE_INT(saveint);
12957 }
12958
12959 doprompt = saveprompt;
12960
12961 popfile();
12962
12963 n.narg.type = NARG;
12964 n.narg.next = NULL;
12965 n.narg.text = wordtext;
12966 n.narg.backquote = backquotelist;
12967
12968 expandarg(&n, NULL, EXP_QUOTED);
12969 return stackblock();
12970}
12971
12972static inline int
12973parser_eof(void)
12974{
12975 return tokpushback && lasttoken == TEOF;
12976}
12977
12978
12979
12980
12981static int
12982evalstring(char *s, int flags)
12983{
12984 struct jmploc *volatile savehandler;
12985 struct jmploc jmploc;
12986 int ex;
12987
12988 union node *n;
12989 struct stackmark smark;
12990 int status;
12991
12992 s = sstrdup(s);
12993 setinputstring(s);
12994 setstackmark(&smark);
12995
12996 status = 0;
12997
12998
12999
13000
13001
13002
13003
13004 savehandler = exception_handler;
13005 ex = setjmp(jmploc.loc);
13006 if (ex)
13007 goto out;
13008 exception_handler = &jmploc;
13009
13010 while ((n = parsecmd(0)) != NODE_EOF) {
13011 int i;
13012
13013 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
13014 if (n)
13015 status = i;
13016 popstackmark(&smark);
13017 if (evalskip)
13018 break;
13019 }
13020 out:
13021 popstackmark(&smark);
13022 popfile();
13023 stunalloc(s);
13024
13025 exception_handler = savehandler;
13026 if (ex)
13027 longjmp(exception_handler->loc, ex);
13028
13029 return status;
13030}
13031
13032
13033
13034
13035static int FAST_FUNC
13036evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
13037{
13038 char *p;
13039 char *concat;
13040
13041 if (argv[1]) {
13042 p = argv[1];
13043 argv += 2;
13044 if (argv[0]) {
13045 STARTSTACKSTR(concat);
13046 for (;;) {
13047 concat = stack_putstr(p, concat);
13048 p = *argv++;
13049 if (p == NULL)
13050 break;
13051 STPUTC(' ', concat);
13052 }
13053 STPUTC('\0', concat);
13054 p = grabstackstr(concat);
13055 }
13056 return evalstring(p, flags & EV_TESTED);
13057 }
13058 return 0;
13059}
13060
13061
13062
13063
13064
13065
13066static int
13067cmdloop(int top)
13068{
13069 union node *n;
13070 struct stackmark smark;
13071 int inter;
13072 int status = 0;
13073 int numeof = 0;
13074
13075 TRACE(("cmdloop(%d) called\n", top));
13076 for (;;) {
13077 int skip;
13078
13079 setstackmark(&smark);
13080#if JOBS
13081 if (doing_jobctl)
13082 showjobs(SHOW_CHANGED|SHOW_STDERR);
13083#endif
13084 inter = 0;
13085 if (iflag && top) {
13086 inter++;
13087 chkmail();
13088 }
13089 n = parsecmd(inter);
13090#if DEBUG
13091 if (DEBUG > 2 && debug && (n != NODE_EOF))
13092 showtree(n);
13093#endif
13094 if (n == NODE_EOF) {
13095 if (!top || numeof >= 50)
13096 break;
13097 if (!stoppedjobs()) {
13098 if (!Iflag)
13099 break;
13100 out2str("\nUse \"exit\" to leave shell.\n");
13101 }
13102 numeof++;
13103 } else if (nflag == 0) {
13104 int i;
13105
13106
13107 job_warning >>= 1;
13108 numeof = 0;
13109 i = evaltree(n, 0);
13110 if (n)
13111 status = i;
13112 }
13113 popstackmark(&smark);
13114 skip = evalskip;
13115
13116 if (skip) {
13117 evalskip &= ~SKIPFUNC;
13118 break;
13119 }
13120 }
13121 return status;
13122}
13123
13124
13125
13126
13127
13128static char *
13129find_dot_file(char *name)
13130{
13131 char *fullname;
13132 const char *path = pathval();
13133 struct stat statb;
13134
13135
13136 if (strchr(name, '/'))
13137 return name;
13138
13139 while ((fullname = path_advance(&path, name)) != NULL) {
13140 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
13141
13142
13143
13144
13145 return fullname;
13146 }
13147 if (fullname != name)
13148 stunalloc(fullname);
13149 }
13150
13151
13152#if ENABLE_ASH_BASH_SOURCE_CURDIR
13153 return name;
13154#else
13155 ash_msg_and_raise_error("%s: not found", name);
13156
13157#endif
13158}
13159
13160static int FAST_FUNC
13161dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
13162{
13163
13164 int status = 0;
13165 char *fullname;
13166 char **argv;
13167 char *args_need_save;
13168 volatile struct shparam saveparam;
13169
13170
13171
13172
13173
13174
13175 nextopt(nullstr);
13176 argv = argptr;
13177
13178 if (!argv[0]) {
13179
13180 return 2;
13181 }
13182
13183
13184
13185
13186 fullname = find_dot_file(argv[0]);
13187 argv++;
13188 args_need_save = argv[0];
13189 if (args_need_save) {
13190 int argc;
13191 saveparam = shellparam;
13192 shellparam.malloced = 0;
13193 argc = 1;
13194 while (argv[argc])
13195 argc++;
13196 shellparam.nparam = argc;
13197 shellparam.p = argv;
13198 };
13199
13200
13201
13202
13203 setinputfile(fullname, INPUT_PUSH_FILE);
13204 commandname = fullname;
13205 status = cmdloop(0);
13206 popfile();
13207
13208 if (args_need_save) {
13209 freeparam(&shellparam);
13210 shellparam = saveparam;
13211 };
13212
13213 return status;
13214}
13215
13216static int FAST_FUNC
13217exitcmd(int argc UNUSED_PARAM, char **argv)
13218{
13219 if (stoppedjobs())
13220 return 0;
13221 if (argv[1])
13222 exitstatus = number(argv[1]);
13223 raise_exception(EXEXIT);
13224
13225}
13226
13227
13228
13229
13230static void
13231readcmdfile(char *name)
13232{
13233 setinputfile(name, INPUT_PUSH_FILE);
13234 cmdloop(0);
13235 popfile();
13236}
13237
13238
13239
13240
13241
13242
13243
13244
13245static void
13246find_command(char *name, struct cmdentry *entry, int act, const char *path)
13247{
13248 struct tblentry *cmdp;
13249 int idx;
13250 int prev;
13251 char *fullname;
13252 struct stat statb;
13253 int e;
13254 int updatetbl;
13255 struct builtincmd *bcmd;
13256
13257
13258 if (strchr(name, '/') != NULL) {
13259 entry->u.index = -1;
13260 if (act & DO_ABS) {
13261 while (stat(name, &statb) < 0) {
13262#ifdef SYSV
13263 if (errno == EINTR)
13264 continue;
13265#endif
13266 entry->cmdtype = CMDUNKNOWN;
13267 return;
13268 }
13269 }
13270 entry->cmdtype = CMDNORMAL;
13271 return;
13272 }
13273
13274
13275
13276 updatetbl = (path == pathval());
13277 if (!updatetbl) {
13278 act |= DO_ALTPATH;
13279 if (strstr(path, "%builtin") != NULL)
13280 act |= DO_ALTBLTIN;
13281 }
13282
13283
13284 cmdp = cmdlookup(name, 0);
13285 if (cmdp != NULL) {
13286 int bit;
13287
13288 switch (cmdp->cmdtype) {
13289 default:
13290#if DEBUG
13291 abort();
13292#endif
13293 case CMDNORMAL:
13294 bit = DO_ALTPATH;
13295 break;
13296 case CMDFUNCTION:
13297 bit = DO_NOFUNC;
13298 break;
13299 case CMDBUILTIN:
13300 bit = DO_ALTBLTIN;
13301 break;
13302 }
13303 if (act & bit) {
13304 updatetbl = 0;
13305 cmdp = NULL;
13306 } else if (cmdp->rehash == 0)
13307
13308 goto success;
13309 }
13310
13311
13312 bcmd = find_builtin(name);
13313 if (bcmd) {
13314 if (IS_BUILTIN_REGULAR(bcmd))
13315 goto builtin_success;
13316 if (act & DO_ALTPATH) {
13317 if (!(act & DO_ALTBLTIN))
13318 goto builtin_success;
13319 } else if (builtinloc <= 0) {
13320 goto builtin_success;
13321 }
13322 }
13323
13324#if ENABLE_FEATURE_SH_STANDALONE
13325 {
13326 int applet_no = find_applet_by_name(name);
13327 if (applet_no >= 0) {
13328 entry->cmdtype = CMDNORMAL;
13329 entry->u.index = -2 - applet_no;
13330 return;
13331 }
13332 }
13333#endif
13334
13335
13336 prev = -1;
13337 if (cmdp && cmdp->rehash) {
13338 if (cmdp->cmdtype == CMDBUILTIN)
13339 prev = builtinloc;
13340 else
13341 prev = cmdp->param.index;
13342 }
13343
13344 e = ENOENT;
13345 idx = -1;
13346 loop:
13347 while ((fullname = path_advance(&path, name)) != NULL) {
13348 stunalloc(fullname);
13349
13350
13351 idx++;
13352 if (pathopt) {
13353 if (prefix(pathopt, "builtin")) {
13354 if (bcmd)
13355 goto builtin_success;
13356 continue;
13357 }
13358 if ((act & DO_NOFUNC)
13359 || !prefix(pathopt, "func")
13360 ) {
13361 continue;
13362 }
13363 }
13364
13365 if (fullname[0] == '/' && idx <= prev) {
13366 if (idx < prev)
13367 continue;
13368 TRACE(("searchexec \"%s\": no change\n", name));
13369 goto success;
13370 }
13371 while (stat(fullname, &statb) < 0) {
13372#ifdef SYSV
13373 if (errno == EINTR)
13374 continue;
13375#endif
13376 if (errno != ENOENT && errno != ENOTDIR)
13377 e = errno;
13378 goto loop;
13379 }
13380 e = EACCES;
13381 if (!S_ISREG(statb.st_mode))
13382 continue;
13383 if (pathopt) {
13384 stalloc(strlen(fullname) + 1);
13385
13386
13387
13388 readcmdfile(fullname);
13389 cmdp = cmdlookup(name, 0);
13390 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13391 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13392 stunalloc(fullname);
13393 goto success;
13394 }
13395 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13396 if (!updatetbl) {
13397 entry->cmdtype = CMDNORMAL;
13398 entry->u.index = idx;
13399 return;
13400 }
13401 INT_OFF;
13402 cmdp = cmdlookup(name, 1);
13403 cmdp->cmdtype = CMDNORMAL;
13404 cmdp->param.index = idx;
13405 INT_ON;
13406 goto success;
13407 }
13408
13409
13410 if (cmdp && updatetbl)
13411 delete_cmd_entry();
13412 if (act & DO_ERR) {
13413#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13414 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13415 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13416 char *argv[3];
13417 argv[0] = (char*) "command_not_found_handle";
13418 argv[1] = name;
13419 argv[2] = NULL;
13420 evalfun(hookp->param.func, 2, argv, 0);
13421 entry->cmdtype = CMDUNKNOWN;
13422 return;
13423 }
13424#endif
13425 ash_msg("%s: %s", name, errmsg(e, "not found"));
13426 }
13427 entry->cmdtype = CMDUNKNOWN;
13428 return;
13429
13430 builtin_success:
13431 if (!updatetbl) {
13432 entry->cmdtype = CMDBUILTIN;
13433 entry->u.cmd = bcmd;
13434 return;
13435 }
13436 INT_OFF;
13437 cmdp = cmdlookup(name, 1);
13438 cmdp->cmdtype = CMDBUILTIN;
13439 cmdp->param.cmd = bcmd;
13440 INT_ON;
13441 success:
13442 cmdp->rehash = 0;
13443 entry->cmdtype = cmdp->cmdtype;
13444 entry->u = cmdp->param;
13445}
13446
13447
13448
13449
13450
13451static int FAST_FUNC
13452trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13453{
13454 char *action;
13455 char **ap;
13456 int signo, exitcode;
13457
13458 nextopt(nullstr);
13459 ap = argptr;
13460 if (!*ap) {
13461 for (signo = 0; signo < NSIG; signo++) {
13462 char *tr = trap_ptr[signo];
13463 if (tr) {
13464
13465
13466
13467
13468 out1fmt("trap -- %s %s\n",
13469 single_quote(tr),
13470 get_signame(signo));
13471
13472
13473
13474
13475 }
13476 }
13477
13478
13479
13480
13481
13482
13483 return 0;
13484 }
13485
13486
13487
13488
13489
13490 action = NULL;
13491 if (ap[1] && !is_number(ap[0]))
13492 action = *ap++;
13493
13494 exitcode = 0;
13495 while (*ap) {
13496 signo = get_signum(*ap);
13497 if (signo < 0) {
13498
13499 ash_msg("%s: invalid signal specification", *ap);
13500 exitcode = 1;
13501 goto next;
13502 }
13503 INT_OFF;
13504 if (action) {
13505 if (LONE_DASH(action))
13506 action = NULL;
13507 else {
13508 if (action[0])
13509 may_have_traps = 1;
13510 action = ckstrdup(action);
13511 }
13512 }
13513 free(trap[signo]);
13514 trap[signo] = action;
13515 if (signo != 0)
13516 setsignal(signo);
13517 INT_ON;
13518 next:
13519 ap++;
13520 }
13521 return exitcode;
13522}
13523
13524
13525
13526
13527#if ENABLE_ASH_HELP
13528static int FAST_FUNC
13529helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13530{
13531 unsigned col;
13532 unsigned i;
13533
13534 out1fmt(
13535 "Built-in commands:\n"
13536 "------------------\n");
13537 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
13538 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
13539 builtintab[i].name + 1);
13540 if (col > 60) {
13541 out1fmt("\n");
13542 col = 0;
13543 }
13544 }
13545# if ENABLE_FEATURE_SH_STANDALONE
13546 {
13547 const char *a = applet_names;
13548 while (*a) {
13549 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13550 if (col > 60) {
13551 out1fmt("\n");
13552 col = 0;
13553 }
13554 while (*a++ != '\0')
13555 continue;
13556 }
13557 }
13558# endif
13559 newline_and_flush(stdout);
13560 return EXIT_SUCCESS;
13561}
13562#endif
13563
13564#if MAX_HISTORY
13565static int FAST_FUNC
13566historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13567{
13568 show_history(line_input_state);
13569 return EXIT_SUCCESS;
13570}
13571#endif
13572
13573
13574
13575
13576static int FAST_FUNC
13577exportcmd(int argc UNUSED_PARAM, char **argv)
13578{
13579 struct var *vp;
13580 char *name;
13581 const char *p;
13582 char **aptr;
13583 char opt;
13584 int flag;
13585 int flag_off;
13586
13587
13588
13589
13590 flag_off = 0;
13591 while ((opt = nextopt("np")) != '\0') {
13592 if (opt == 'n')
13593 flag_off = VEXPORT;
13594 }
13595 flag = VEXPORT;
13596 if (argv[0][0] == 'r') {
13597 flag = VREADONLY;
13598 flag_off = 0;
13599 }
13600 flag_off = ~flag_off;
13601
13602
13603 {
13604 aptr = argptr;
13605 name = *aptr;
13606 if (name) {
13607 do {
13608 p = strchr(name, '=');
13609 if (p != NULL) {
13610 p++;
13611 } else {
13612 vp = *findvar(hashvar(name), name);
13613 if (vp) {
13614 vp->flags = ((vp->flags | flag) & flag_off);
13615 continue;
13616 }
13617 }
13618 setvar(name, p, (flag & flag_off));
13619 } while ((name = *++aptr) != NULL);
13620 return 0;
13621 }
13622 }
13623
13624
13625
13626
13627 showvars(argv[0], flag, 0);
13628 return 0;
13629}
13630
13631
13632
13633
13634static void
13635unsetfunc(const char *name)
13636{
13637 struct tblentry *cmdp;
13638
13639 cmdp = cmdlookup(name, 0);
13640 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
13641 delete_cmd_entry();
13642}
13643
13644
13645
13646
13647
13648
13649static int FAST_FUNC
13650unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13651{
13652 char **ap;
13653 int i;
13654 int flag = 0;
13655
13656 while ((i = nextopt("vf")) != 0) {
13657 flag = i;
13658 }
13659
13660 for (ap = argptr; *ap; ap++) {
13661 if (flag != 'f') {
13662 unsetvar(*ap);
13663 continue;
13664 }
13665 if (flag != 'v')
13666 unsetfunc(*ap);
13667 }
13668 return 0;
13669}
13670
13671static const unsigned char timescmd_str[] ALIGN1 = {
13672 ' ', offsetof(struct tms, tms_utime),
13673 '\n', offsetof(struct tms, tms_stime),
13674 ' ', offsetof(struct tms, tms_cutime),
13675 '\n', offsetof(struct tms, tms_cstime),
13676 0
13677};
13678static int FAST_FUNC
13679timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13680{
13681 unsigned clk_tck;
13682 const unsigned char *p;
13683 struct tms buf;
13684
13685 clk_tck = bb_clk_tck();
13686
13687 times(&buf);
13688 p = timescmd_str;
13689 do {
13690 unsigned sec, frac;
13691 unsigned long t;
13692 t = *(clock_t *)(((char *) &buf) + p[1]);
13693 sec = t / clk_tck;
13694 frac = t % clk_tck;
13695 out1fmt("%um%u.%03us%c",
13696 sec / 60, sec % 60,
13697 (frac * 1000) / clk_tck,
13698 p[0]);
13699 p += 2;
13700 } while (*p);
13701
13702 return 0;
13703}
13704
13705#if ENABLE_FEATURE_SH_MATH
13706
13707
13708
13709
13710
13711
13712static int FAST_FUNC
13713letcmd(int argc UNUSED_PARAM, char **argv)
13714{
13715 arith_t i;
13716
13717 argv++;
13718 if (!*argv)
13719 ash_msg_and_raise_error("expression expected");
13720 do {
13721 i = ash_arith(*argv);
13722 } while (*++argv);
13723
13724 return !i;
13725}
13726#endif
13727
13728
13729
13730
13731
13732
13733
13734
13735
13736
13737
13738
13739
13740
13741
13742static int FAST_FUNC
13743readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13744{
13745 char *opt_n = NULL;
13746 char *opt_p = NULL;
13747 char *opt_t = NULL;
13748 char *opt_u = NULL;
13749 char *opt_d = NULL;
13750 int read_flags = 0;
13751 const char *r;
13752 int i;
13753
13754 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
13755 switch (i) {
13756 case 'p':
13757 opt_p = optionarg;
13758 break;
13759 case 'n':
13760 opt_n = optionarg;
13761 break;
13762 case 's':
13763 read_flags |= BUILTIN_READ_SILENT;
13764 break;
13765 case 't':
13766 opt_t = optionarg;
13767 break;
13768 case 'r':
13769 read_flags |= BUILTIN_READ_RAW;
13770 break;
13771 case 'u':
13772 opt_u = optionarg;
13773 break;
13774#if BASH_READ_D
13775 case 'd':
13776 opt_d = optionarg;
13777 break;
13778#endif
13779 default:
13780 break;
13781 }
13782 }
13783
13784
13785
13786
13787 again:
13788 INT_OFF;
13789 r = shell_builtin_read(setvar0,
13790 argptr,
13791 bltinlookup("IFS"),
13792 read_flags,
13793 opt_n,
13794 opt_p,
13795 opt_t,
13796 opt_u,
13797 opt_d
13798 );
13799 INT_ON;
13800
13801 if ((uintptr_t)r == 1 && errno == EINTR) {
13802
13803
13804
13805 if (pending_sig == 0)
13806 goto again;
13807 }
13808
13809 if ((uintptr_t)r > 1)
13810 ash_msg_and_raise_error(r);
13811
13812 return (uintptr_t)r;
13813}
13814
13815static int FAST_FUNC
13816umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13817{
13818 static const char permuser[3] ALIGN1 = "ogu";
13819
13820 mode_t mask;
13821 int symbolic_mode = 0;
13822
13823 while (nextopt("S") != '\0') {
13824 symbolic_mode = 1;
13825 }
13826
13827 INT_OFF;
13828 mask = umask(0);
13829 umask(mask);
13830 INT_ON;
13831
13832 if (*argptr == NULL) {
13833 if (symbolic_mode) {
13834 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
13835 char *p = buf;
13836 int i;
13837
13838 i = 2;
13839 for (;;) {
13840 *p++ = ',';
13841 *p++ = permuser[i];
13842 *p++ = '=';
13843
13844 if (!(mask & 0400)) *p++ = 'r';
13845 if (!(mask & 0200)) *p++ = 'w';
13846 if (!(mask & 0100)) *p++ = 'x';
13847 mask <<= 3;
13848 if (--i < 0)
13849 break;
13850 }
13851 *p = '\0';
13852 puts(buf + 1);
13853 } else {
13854 out1fmt("%04o\n", mask);
13855 }
13856 } else {
13857 char *modestr = *argptr;
13858
13859
13860 if (!isdigit(modestr[0]))
13861 mask ^= 0777;
13862 mask = bb_parse_mode(modestr, mask);
13863 if ((unsigned)mask > 0777) {
13864 ash_msg_and_raise_error("illegal mode: %s", modestr);
13865 }
13866 if (!isdigit(modestr[0]))
13867 mask ^= 0777;
13868 umask(mask);
13869 }
13870 return 0;
13871}
13872
13873static int FAST_FUNC
13874ulimitcmd(int argc UNUSED_PARAM, char **argv)
13875{
13876 return shell_builtin_ulimit(argv);
13877}
13878
13879
13880
13881
13882
13883
13884static void
13885exitshell(void)
13886{
13887 struct jmploc loc;
13888 char *p;
13889 int status;
13890
13891#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13892 save_history(line_input_state);
13893#endif
13894 status = exitstatus;
13895 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13896 if (setjmp(loc.loc)) {
13897 if (exception_type == EXEXIT)
13898 status = exitstatus;
13899 goto out;
13900 }
13901 exception_handler = &loc;
13902 p = trap[0];
13903 if (p) {
13904 trap[0] = NULL;
13905 evalskip = 0;
13906 evalstring(p, 0);
13907
13908 }
13909 out:
13910
13911
13912
13913 setjobctl(0);
13914 flush_stdout_stderr();
13915 _exit(status);
13916
13917}
13918
13919
13920static NOINLINE void
13921init(void)
13922{
13923
13924 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
13925 basepf.linno = 1;
13926
13927 sigmode[SIGCHLD - 1] = S_DFL;
13928 setsignal(SIGCHLD);
13929
13930
13931
13932
13933 signal(SIGHUP, SIG_DFL);
13934
13935 {
13936 char **envp;
13937 const char *p;
13938
13939 initvar();
13940 for (envp = environ; envp && *envp; envp++) {
13941
13942
13943
13944
13945
13946
13947
13948
13949
13950
13951
13952 if (strchr(*envp, '=')) {
13953 setvareq(*envp, VEXPORT|VTEXTFIXED);
13954 }
13955 }
13956
13957 setvareq((char*)defoptindvar, VTEXTFIXED);
13958
13959 setvar0("PPID", utoa(getppid()));
13960#if BASH_SHLVL_VAR
13961 p = lookupvar("SHLVL");
13962 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
13963#endif
13964#if BASH_HOSTNAME_VAR
13965 if (!lookupvar("HOSTNAME")) {
13966 struct utsname uts;
13967 uname(&uts);
13968 setvar0("HOSTNAME", uts.nodename);
13969 }
13970#endif
13971 p = lookupvar("PWD");
13972 if (p) {
13973 struct stat st1, st2;
13974 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
13975 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13976 ) {
13977 p = NULL;
13978 }
13979 }
13980 setpwd(p, 0);
13981 }
13982}
13983
13984
13985
13986
13987
13988
13989
13990
13991
13992
13993static int
13994procargs(char **argv)
13995{
13996 int i;
13997 const char *xminusc;
13998 char **xargv;
13999 int login_sh;
14000
14001 xargv = argv;
14002 login_sh = xargv[0] && xargv[0][0] == '-';
14003 arg0 = xargv[0];
14004
14005 xargv++;
14006 for (i = 0; i < NOPTS; i++)
14007 optlist[i] = 2;
14008 argptr = xargv;
14009 if (options( 1, &login_sh)) {
14010
14011 raise_exception(EXERROR);
14012 }
14013 xargv = argptr;
14014 xminusc = minusc;
14015 if (*xargv == NULL) {
14016 if (xminusc)
14017 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14018 sflag = 1;
14019 }
14020 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
14021 iflag = 1;
14022 if (mflag == 2)
14023 mflag = iflag;
14024 for (i = 0; i < NOPTS; i++)
14025 if (optlist[i] == 2)
14026 optlist[i] = 0;
14027#if DEBUG == 2
14028 debug = 1;
14029#endif
14030
14031 if (xminusc) {
14032 minusc = *xargv++;
14033 if (*xargv)
14034 goto setarg0;
14035 } else if (!sflag) {
14036 setinputfile(*xargv, 0);
14037 setarg0:
14038 arg0 = *xargv++;
14039 commandname = arg0;
14040 }
14041
14042 shellparam.p = xargv;
14043#if ENABLE_ASH_GETOPTS
14044 shellparam.optind = 1;
14045 shellparam.optoff = -1;
14046#endif
14047
14048 while (*xargv) {
14049 shellparam.nparam++;
14050 xargv++;
14051 }
14052 optschanged();
14053
14054 return login_sh;
14055}
14056
14057
14058
14059
14060static void
14061read_profile(const char *name)
14062{
14063 name = expandstr(name, DQSYNTAX);
14064 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14065 return;
14066 cmdloop(0);
14067 popfile();
14068}
14069
14070
14071
14072
14073
14074
14075static void
14076reset(void)
14077{
14078
14079 evalskip = 0;
14080 loopnest = 0;
14081
14082
14083 ifsfree();
14084
14085
14086 g_parsefile->left_in_buffer = 0;
14087 g_parsefile->left_in_line = 0;
14088 popallfiles();
14089
14090
14091 unwindredir(NULL);
14092
14093
14094 unwindlocalvars(NULL);
14095}
14096
14097#if PROFILE
14098static short profile_buf[16384];
14099extern int etext();
14100#endif
14101
14102
14103
14104
14105
14106
14107
14108
14109int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14110int ash_main(int argc UNUSED_PARAM, char **argv)
14111{
14112 volatile smallint state;
14113 struct jmploc jmploc;
14114 struct stackmark smark;
14115 int login_sh;
14116
14117
14118 INIT_G_misc();
14119 INIT_G_memstack();
14120 INIT_G_var();
14121#if ENABLE_ASH_ALIAS
14122 INIT_G_alias();
14123#endif
14124 INIT_G_cmdtable();
14125
14126#if PROFILE
14127 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14128#endif
14129
14130#if ENABLE_FEATURE_EDITING
14131 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
14132#endif
14133 state = 0;
14134 if (setjmp(jmploc.loc)) {
14135 smallint e;
14136 smallint s;
14137
14138 reset();
14139
14140 e = exception_type;
14141 s = state;
14142 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
14143 exitshell();
14144 }
14145 if (e == EXINT) {
14146 newline_and_flush(stderr);
14147 }
14148
14149 popstackmark(&smark);
14150 FORCE_INT_ON;
14151 if (s == 1)
14152 goto state1;
14153 if (s == 2)
14154 goto state2;
14155 if (s == 3)
14156 goto state3;
14157 goto state4;
14158 }
14159 exception_handler = &jmploc;
14160 rootpid = getpid();
14161
14162 init();
14163 setstackmark(&smark);
14164 login_sh = procargs(argv);
14165#if DEBUG
14166 TRACE(("Shell args: "));
14167 trace_puts_args(argv);
14168#endif
14169
14170 if (login_sh) {
14171 const char *hp;
14172
14173 state = 1;
14174 read_profile("/etc/profile");
14175 state1:
14176 state = 2;
14177 hp = lookupvar("HOME");
14178 if (hp)
14179 read_profile("$HOME/.profile");
14180 }
14181 state2:
14182 state = 3;
14183 if (
14184#ifndef linux
14185 getuid() == geteuid() && getgid() == getegid() &&
14186#endif
14187 iflag
14188 ) {
14189 const char *shinit = lookupvar("ENV");
14190 if (shinit != NULL && *shinit != '\0')
14191 read_profile(shinit);
14192 }
14193 popstackmark(&smark);
14194 state3:
14195 state = 4;
14196 if (minusc) {
14197
14198
14199
14200
14201
14202
14203
14204 evalstring(minusc, sflag ? 0 : EV_EXIT);
14205 }
14206
14207 if (sflag || minusc == NULL) {
14208#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
14209 if (iflag) {
14210 const char *hp = lookupvar("HISTFILE");
14211 if (!hp) {
14212 hp = lookupvar("HOME");
14213 if (hp) {
14214 INT_OFF;
14215 hp = concat_path_file(hp, ".ash_history");
14216 setvar0("HISTFILE", hp);
14217 free((char*)hp);
14218 INT_ON;
14219 hp = lookupvar("HISTFILE");
14220 }
14221 }
14222 if (hp)
14223 line_input_state->hist_file = hp;
14224# if ENABLE_FEATURE_SH_HISTFILESIZE
14225 hp = lookupvar("HISTFILESIZE");
14226 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14227# endif
14228 }
14229#endif
14230 state4:
14231 cmdloop(1);
14232 }
14233#if PROFILE
14234 monitor(0);
14235#endif
14236#ifdef GPROF
14237 {
14238 extern void _mcleanup(void);
14239 _mcleanup();
14240 }
14241#endif
14242 TRACE(("End of main reached\n"));
14243 exitshell();
14244
14245}
14246
14247
14248
14249
14250
14251
14252
14253
14254
14255
14256
14257
14258
14259
14260
14261
14262
14263
14264
14265
14266
14267
14268
14269
14270
14271
14272
14273
14274
14275
14276
14277
14278
14279