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