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