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#if BASH_PROCESS_SUBST
10282 redir_stop = redirlist;
10283#endif
10284 file_stop = g_parsefile;
10285 back_exitstatus = 0;
10286
10287 cmdentry.cmdtype = CMDBUILTIN;
10288 cmdentry.u.cmd = &null_bltin;
10289 varlist.lastp = &varlist.list;
10290 *varlist.lastp = NULL;
10291 arglist.lastp = &arglist.list;
10292 *arglist.lastp = NULL;
10293
10294 cmd_flag = 0;
10295 cmd_is_exec = 0;
10296 spclbltin = -1;
10297 vflags = 0;
10298 vlocal = 0;
10299 path = NULL;
10300
10301 argc = 0;
10302 argp = cmd->ncmd.args;
10303 osp = fill_arglist(&arglist, &argp);
10304 if (osp) {
10305 int pseudovarflag = 0;
10306
10307 for (;;) {
10308 find_command(arglist.list->text, &cmdentry,
10309 cmd_flag | DO_REGBLTIN, pathval());
10310
10311 vlocal++;
10312
10313
10314 if (cmdentry.cmdtype != CMDBUILTIN)
10315 break;
10316
10317 pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
10318 if (spclbltin < 0) {
10319 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10320 vlocal = !spclbltin;
10321 }
10322 cmd_is_exec = cmdentry.u.cmd == EXECCMD;
10323#if ENABLE_ASH_CMDCMD
10324 if (cmdentry.u.cmd != COMMANDCMD)
10325 break;
10326
10327 cmd_flag = parse_command_args(&arglist, &argp, &path);
10328 if (!cmd_flag)
10329#endif
10330 break;
10331 }
10332
10333 for (; argp; argp = argp->narg.next)
10334 expandarg(argp, &arglist,
10335 pseudovarflag &&
10336 isassignment(argp->narg.text) ?
10337 EXP_VARTILDE : EXP_FULL | EXP_TILDE);
10338
10339 for (sp = arglist.list; sp; sp = sp->next)
10340 argc++;
10341
10342 if (cmd_is_exec && argc > 1)
10343 vflags = VEXPORT;
10344 }
10345
10346 localvar_stop = pushlocalvars(vlocal);
10347
10348
10349 nargv = stalloc(sizeof(char *) * (argc + 2));
10350 argv = ++nargv;
10351 for (sp = arglist.list; sp; sp = sp->next) {
10352 TRACE(("evalcommand arg: %s\n", sp->text));
10353 *nargv++ = sp->text;
10354 }
10355 *nargv = NULL;
10356
10357 lastarg = NULL;
10358 if (iflag && funcline == 0 && argc > 0)
10359 lastarg = nargv[-1];
10360
10361 expredir(cmd->ncmd.redirect);
10362#if !BASH_PROCESS_SUBST
10363 redir_stop = pushredir(cmd->ncmd.redirect);
10364#else
10365 pushredir(cmd->ncmd.redirect);
10366#endif
10367 preverrout_fd = 2;
10368 if (BASH_XTRACEFD && xflag) {
10369
10370
10371
10372 const char *xtracefd = lookupvar("BASH_XTRACEFD");
10373 if (xtracefd && is_number(xtracefd))
10374 preverrout_fd = atoi(xtracefd);
10375
10376 }
10377 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10378
10379 if (status) {
10380 bail:
10381 exitstatus = status;
10382
10383
10384 if (spclbltin > 0)
10385 raise_exception(EXERROR);
10386
10387 goto out;
10388 }
10389
10390 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10391 struct strlist **spp;
10392
10393 spp = varlist.lastp;
10394 expandarg(argp, &varlist, EXP_VARTILDE);
10395
10396 if (vlocal)
10397 mklocal((*spp)->text, VEXPORT);
10398 else
10399 setvareq((*spp)->text, vflags);
10400 }
10401
10402
10403 if (xflag) {
10404 const char *pfx = "";
10405
10406 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
10407
10408 sp = varlist.list;
10409 while (sp) {
10410 char *varval = sp->text;
10411 char *eq = strchrnul(varval, '=');
10412 if (*eq)
10413 eq++;
10414 fdprintf(preverrout_fd, "%s%.*s%s",
10415 pfx,
10416 (int)(eq - varval), varval,
10417 maybe_single_quote(eq)
10418 );
10419 sp = sp->next;
10420 pfx = " ";
10421 }
10422
10423 sp = arglist.list;
10424 while (sp) {
10425 fdprintf(preverrout_fd, "%s%s",
10426 pfx,
10427
10428 findkwd(sp->text)
10429 ? single_quote(sp->text)
10430 : maybe_single_quote(sp->text)
10431 );
10432 sp = sp->next;
10433 pfx = " ";
10434 }
10435 safe_write(preverrout_fd, "\n", 1);
10436 }
10437
10438
10439 if (cmdentry.cmdtype != CMDBUILTIN
10440 || !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
10441 ) {
10442 path = path ? path : pathval();
10443 find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path);
10444 }
10445
10446 jp = NULL;
10447
10448
10449 switch (cmdentry.cmdtype) {
10450 case CMDUNKNOWN:
10451 status = 127;
10452 flush_stdout_stderr();
10453 goto bail;
10454
10455 default: {
10456
10457#if ENABLE_FEATURE_SH_STANDALONE \
10458 && ENABLE_FEATURE_SH_NOFORK \
10459 && NUM_APPLETS > 1
10460
10461
10462
10463
10464
10465
10466 int applet_no = (- cmdentry.u.index - 2);
10467 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10468 char **sv_environ;
10469
10470 INT_OFF;
10471 sv_environ = environ;
10472 environ = listvars(VEXPORT, VUNSET, varlist.list, NULL);
10473
10474
10475
10476
10477
10478
10479
10480
10481 exitstatus = run_nofork_applet(applet_no, argv);
10482 environ = sv_environ;
10483
10484
10485
10486
10487
10488
10489
10490
10491
10492 INT_ON;
10493 break;
10494 }
10495#endif
10496
10497
10498
10499
10500 if (!(flags & EV_EXIT) || may_have_traps) {
10501
10502 INT_OFF;
10503 get_tty_state();
10504 jp = makejob( 1);
10505 if (forkshell(jp, cmd, FORK_FG) != 0) {
10506
10507 break;
10508 }
10509
10510 FORCE_INT_ON;
10511
10512 }
10513 shellexec(argv[0], argv, path, cmdentry.u.index);
10514
10515 }
10516 case CMDBUILTIN:
10517 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
10518 && !(exception_type == EXERROR && spclbltin <= 0)
10519 ) {
10520 raise:
10521 longjmp(exception_handler->loc, 1);
10522 }
10523 break;
10524
10525 case CMDFUNCTION:
10526 if (evalfun(cmdentry.u.func, argc, argv, flags))
10527 goto raise;
10528 break;
10529 }
10530
10531 status = waitforjob(jp);
10532 if (jp)
10533 TRACE(("forked child exited with %d\n", status));
10534 FORCE_INT_ON;
10535
10536 out:
10537 if (cmd->ncmd.redirect)
10538 popredir( cmd_is_exec);
10539 unwindredir(redir_stop);
10540 unwindfiles(file_stop);
10541 unwindlocalvars(localvar_stop);
10542 if (lastarg) {
10543
10544
10545
10546
10547 setvar0("_", lastarg);
10548 }
10549
10550 return status;
10551}
10552
10553static int
10554evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
10555{
10556 char *volatile savecmdname;
10557 struct jmploc *volatile savehandler;
10558 struct jmploc jmploc;
10559 int status;
10560 int i;
10561
10562 savecmdname = commandname;
10563 savehandler = exception_handler;
10564 i = setjmp(jmploc.loc);
10565 if (i)
10566 goto cmddone;
10567 exception_handler = &jmploc;
10568 commandname = argv[0];
10569 argptr = argv + 1;
10570 optptr = NULL;
10571 if (cmd == EVALCMD)
10572 status = evalcmd(argc, argv, flags);
10573 else
10574 status = (*cmd->builtin)(argc, argv);
10575 flush_stdout_stderr();
10576 status |= ferror(stdout);
10577 exitstatus = status;
10578 cmddone:
10579 clearerr(stdout);
10580 commandname = savecmdname;
10581 exception_handler = savehandler;
10582
10583 return i;
10584}
10585
10586static int
10587goodname(const char *p)
10588{
10589 return endofname(p)[0] == '\0';
10590}
10591
10592
10593
10594
10595
10596
10597
10598
10599static void
10600prehash(union node *n)
10601{
10602 struct cmdentry entry;
10603
10604 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10605 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
10606}
10607
10608
10609
10610
10611
10612
10613
10614
10615
10616
10617
10618
10619
10620
10621
10622
10623
10624
10625static int FAST_FUNC
10626breakcmd(int argc UNUSED_PARAM, char **argv)
10627{
10628 int n = argv[1] ? number(argv[1]) : 1;
10629
10630 if (n <= 0)
10631 ash_msg_and_raise_error(msg_illnum, argv[1]);
10632 if (n > loopnest)
10633 n = loopnest;
10634 if (n > 0) {
10635 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
10636 skipcount = n;
10637 }
10638 return 0;
10639}
10640
10641
10642
10643
10644
10645
10646enum {
10647 INPUT_PUSH_FILE = 1,
10648 INPUT_NOFILE_OK = 2,
10649};
10650
10651static smallint checkkwd;
10652
10653#define CHKALIAS 0x1
10654#define CHKKWD 0x2
10655#define CHKNL 0x4
10656#define CHKEOFMARK 0x8
10657
10658
10659
10660
10661
10662#if !ENABLE_ASH_ALIAS
10663#define pushstring(s, ap) pushstring(s)
10664#endif
10665static void
10666pushstring(char *s, struct alias *ap)
10667{
10668 struct strpush *sp;
10669 int len;
10670
10671 len = strlen(s);
10672 INT_OFF;
10673 if (g_parsefile->strpush) {
10674 sp = ckzalloc(sizeof(*sp));
10675 sp->prev = g_parsefile->strpush;
10676 } else {
10677 sp = &(g_parsefile->basestrpush);
10678 }
10679 g_parsefile->strpush = sp;
10680 sp->prev_string = g_parsefile->next_to_pgetc;
10681 sp->prev_left_in_line = g_parsefile->left_in_line;
10682 sp->unget = g_parsefile->unget;
10683 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
10684#if ENABLE_ASH_ALIAS
10685 sp->ap = ap;
10686 if (ap) {
10687 ap->flag |= ALIASINUSE;
10688 sp->string = s;
10689 }
10690#endif
10691 g_parsefile->next_to_pgetc = s;
10692 g_parsefile->left_in_line = len;
10693 g_parsefile->unget = 0;
10694 INT_ON;
10695}
10696
10697static void
10698popstring(void)
10699{
10700 struct strpush *sp = g_parsefile->strpush;
10701
10702 INT_OFF;
10703#if ENABLE_ASH_ALIAS
10704 if (sp->ap) {
10705 if (g_parsefile->next_to_pgetc[-1] == ' '
10706 || g_parsefile->next_to_pgetc[-1] == '\t'
10707 ) {
10708 checkkwd |= CHKALIAS;
10709 }
10710 if (sp->string != sp->ap->val) {
10711 free(sp->string);
10712 }
10713 sp->ap->flag &= ~ALIASINUSE;
10714 if (sp->ap->flag & ALIASDEAD) {
10715 unalias(sp->ap->name);
10716 }
10717 }
10718#endif
10719 g_parsefile->next_to_pgetc = sp->prev_string;
10720 g_parsefile->left_in_line = sp->prev_left_in_line;
10721 g_parsefile->unget = sp->unget;
10722 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
10723 g_parsefile->strpush = sp->prev;
10724 if (sp != &(g_parsefile->basestrpush))
10725 free(sp);
10726 INT_ON;
10727}
10728
10729static int
10730preadfd(void)
10731{
10732 int nr;
10733 char *buf = g_parsefile->buf;
10734
10735 g_parsefile->next_to_pgetc = buf;
10736#if ENABLE_FEATURE_EDITING
10737
10738 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10739 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10740 else {
10741# if ENABLE_ASH_IDLE_TIMEOUT
10742 int timeout = -1;
10743 const char *tmout_var = lookupvar("TMOUT");
10744 if (tmout_var) {
10745 timeout = atoi(tmout_var) * 1000;
10746 if (timeout <= 0)
10747 timeout = -1;
10748 }
10749 line_input_state->timeout = timeout;
10750# endif
10751# if ENABLE_FEATURE_TAB_COMPLETION
10752 line_input_state->path_lookup = pathval();
10753# endif
10754 reinit_unicode_for_ash();
10755 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10756 if (nr == 0) {
10757
10758 write(STDOUT_FILENO, "^C", 2);
10759 raise(SIGINT);
10760 if (trap[SIGINT]) {
10761 buf[0] = '\n';
10762 buf[1] = '\0';
10763 return 1;
10764 }
10765 exitstatus = 128 + SIGINT;
10766 return -1;
10767 }
10768 if (nr < 0) {
10769 if (errno == 0) {
10770
10771 nr = 0;
10772 }
10773# if ENABLE_ASH_IDLE_TIMEOUT
10774 else if (errno == EAGAIN && timeout > 0) {
10775 puts("\007timed out waiting for input: auto-logout");
10776 exitshell();
10777 }
10778# endif
10779 }
10780 }
10781#else
10782 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10783#endif
10784
10785#if 0
10786 if (nr < 0) {
10787 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10788 int flags = fcntl(0, F_GETFL);
10789 if (flags >= 0 && (flags & O_NONBLOCK)) {
10790 flags &= ~O_NONBLOCK;
10791 if (fcntl(0, F_SETFL, flags) >= 0) {
10792 out2str("sh: turning off NDELAY mode\n");
10793 goto retry;
10794 }
10795 }
10796 }
10797 }
10798#endif
10799 return nr;
10800}
10801
10802
10803
10804
10805
10806
10807
10808
10809
10810
10811
10812
10813#define pgetc_debug(...) ((void)0)
10814static int pgetc(void);
10815static int
10816preadbuffer(void)
10817{
10818 char *q;
10819 int more;
10820
10821 if (g_parsefile->strpush) {
10822#if ENABLE_ASH_ALIAS
10823 if (g_parsefile->left_in_line == -1
10824 && g_parsefile->strpush->ap
10825 && g_parsefile->next_to_pgetc[-1] != ' '
10826 && g_parsefile->next_to_pgetc[-1] != '\t'
10827 ) {
10828 pgetc_debug("preadbuffer PEOA");
10829 return PEOA;
10830 }
10831#endif
10832 popstring();
10833 return pgetc();
10834 }
10835
10836
10837
10838
10839
10840
10841
10842
10843 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
10844 pgetc_debug("preadbuffer PEOF1");
10845
10846
10847
10848
10849 g_parsefile->next_to_pgetc++;
10850 return PEOF;
10851 }
10852
10853 more = g_parsefile->left_in_buffer;
10854 if (more <= 0) {
10855 flush_stdout_stderr();
10856 again:
10857 more = preadfd();
10858 if (more <= 0) {
10859
10860 g_parsefile->left_in_line = -99;
10861 pgetc_debug("preadbuffer PEOF2");
10862 g_parsefile->next_to_pgetc++;
10863 return PEOF;
10864 }
10865 }
10866
10867
10868
10869
10870
10871
10872 q = g_parsefile->next_to_pgetc;
10873 for (;;) {
10874 char c;
10875
10876 more--;
10877
10878 c = *q;
10879 if (c == '\0') {
10880 memmove(q, q + 1, more);
10881 } else {
10882 q++;
10883 if (c == '\n') {
10884 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10885 break;
10886 }
10887 }
10888
10889 if (more <= 0) {
10890 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10891 if (g_parsefile->left_in_line < 0)
10892 goto again;
10893 break;
10894 }
10895 }
10896 g_parsefile->left_in_buffer = more;
10897
10898 if (vflag) {
10899 char save = *q;
10900 *q = '\0';
10901 out2str(g_parsefile->next_to_pgetc);
10902 *q = save;
10903 }
10904
10905 pgetc_debug("preadbuffer at %d:%p'%s'",
10906 g_parsefile->left_in_line,
10907 g_parsefile->next_to_pgetc,
10908 g_parsefile->next_to_pgetc);
10909 return (unsigned char)*g_parsefile->next_to_pgetc++;
10910}
10911
10912static void
10913nlprompt(void)
10914{
10915 g_parsefile->linno++;
10916 setprompt_if(doprompt, 2);
10917}
10918static void
10919nlnoprompt(void)
10920{
10921 g_parsefile->linno++;
10922 needprompt = doprompt;
10923}
10924
10925static int
10926pgetc(void)
10927{
10928 int c;
10929
10930 pgetc_debug("pgetc at %d:%p'%s'",
10931 g_parsefile->left_in_line,
10932 g_parsefile->next_to_pgetc,
10933 g_parsefile->next_to_pgetc);
10934 if (g_parsefile->unget)
10935 return g_parsefile->lastc[--g_parsefile->unget];
10936
10937 if (--g_parsefile->left_in_line >= 0)
10938 c = (unsigned char)*g_parsefile->next_to_pgetc++;
10939 else
10940 c = preadbuffer();
10941
10942 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10943 g_parsefile->lastc[0] = c;
10944
10945 return c;
10946}
10947
10948#if ENABLE_ASH_ALIAS
10949static int
10950pgetc_without_PEOA(void)
10951{
10952 int c;
10953 do {
10954 pgetc_debug("pgetc at %d:%p'%s'",
10955 g_parsefile->left_in_line,
10956 g_parsefile->next_to_pgetc,
10957 g_parsefile->next_to_pgetc);
10958 c = pgetc();
10959 } while (c == PEOA);
10960 return c;
10961}
10962#else
10963# define pgetc_without_PEOA() pgetc()
10964#endif
10965
10966
10967
10968
10969
10970static void
10971pungetc(void)
10972{
10973 g_parsefile->unget++;
10974}
10975
10976
10977static int
10978pgetc_eatbnl(void)
10979{
10980 int c;
10981
10982 while ((c = pgetc()) == '\\') {
10983 if (pgetc() != '\n') {
10984 pungetc();
10985 break;
10986 }
10987
10988 nlprompt();
10989 }
10990
10991 return c;
10992}
10993
10994struct synstack {
10995 smalluint syntax;
10996 uint8_t innerdq :1;
10997 uint8_t varpushed :1;
10998 uint8_t dblquote :1;
10999 int varnest;
11000 int dqvarnest;
11001 int parenlevel;
11002 struct synstack *prev;
11003 struct synstack *next;
11004};
11005
11006static int
11007pgetc_top(struct synstack *stack)
11008{
11009 return stack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl();
11010}
11011
11012static void
11013synstack_push(struct synstack **stack, struct synstack *next, int syntax)
11014{
11015 memset(next, 0, sizeof(*next));
11016 next->syntax = syntax;
11017 next->next = *stack;
11018 (*stack)->prev = next;
11019 *stack = next;
11020}
11021
11022static ALWAYS_INLINE void
11023synstack_pop(struct synstack **stack)
11024{
11025 *stack = (*stack)->next;
11026}
11027
11028
11029
11030
11031
11032static void
11033pushfile(void)
11034{
11035 struct parsefile *pf;
11036
11037 pf = ckzalloc(sizeof(*pf));
11038 pf->prev = g_parsefile;
11039 pf->pf_fd = -1;
11040
11041
11042
11043 g_parsefile = pf;
11044}
11045
11046static void
11047popfile(void)
11048{
11049 struct parsefile *pf = g_parsefile;
11050
11051 if (pf == &basepf)
11052 return;
11053
11054 INT_OFF;
11055 if (pf->pf_fd >= 0)
11056 close(pf->pf_fd);
11057 free(pf->buf);
11058 while (pf->strpush)
11059 popstring();
11060 g_parsefile = pf->prev;
11061 free(pf);
11062 INT_ON;
11063}
11064
11065static void
11066unwindfiles(struct parsefile *stop)
11067{
11068 while (g_parsefile != stop)
11069 popfile();
11070}
11071
11072
11073
11074
11075static void
11076popallfiles(void)
11077{
11078 unwindfiles(&basepf);
11079}
11080
11081
11082
11083
11084
11085static void
11086closescript(void)
11087{
11088 popallfiles();
11089 if (g_parsefile->pf_fd > 0) {
11090 close(g_parsefile->pf_fd);
11091 g_parsefile->pf_fd = 0;
11092 }
11093}
11094
11095
11096
11097
11098
11099static void
11100setinputfd(int fd, int push)
11101{
11102 if (push) {
11103 pushfile();
11104 g_parsefile->buf = NULL;
11105 }
11106 g_parsefile->pf_fd = fd;
11107 if (g_parsefile->buf == NULL)
11108 g_parsefile->buf = ckmalloc(IBUFSIZ);
11109 g_parsefile->left_in_buffer = 0;
11110 g_parsefile->left_in_line = 0;
11111 g_parsefile->linno = 1;
11112}
11113
11114
11115
11116
11117
11118static int
11119setinputfile(const char *fname, int flags)
11120{
11121 int fd;
11122
11123 INT_OFF;
11124 fd = open(fname, O_RDONLY | O_CLOEXEC);
11125 if (fd < 0) {
11126 if (flags & INPUT_NOFILE_OK)
11127 goto out;
11128 exitstatus = 127;
11129 ash_msg_and_raise_perror("can't open '%s'", fname);
11130 }
11131 if (fd < 10)
11132 fd = savefd(fd);
11133 else if (O_CLOEXEC == 0)
11134 close_on_exec_on(fd);
11135
11136 setinputfd(fd, flags & INPUT_PUSH_FILE);
11137 out:
11138 INT_ON;
11139 return fd;
11140}
11141
11142
11143
11144
11145static void
11146setinputstring(char *string)
11147{
11148 INT_OFF;
11149 pushfile();
11150 g_parsefile->next_to_pgetc = string;
11151 g_parsefile->left_in_line = strlen(string);
11152 g_parsefile->buf = NULL;
11153 g_parsefile->linno = 1;
11154 INT_ON;
11155}
11156
11157
11158
11159
11160
11161
11162#if ENABLE_ASH_MAIL
11163
11164
11165static unsigned mailtime_hash;
11166
11167static smallint mail_var_path_changed;
11168
11169
11170
11171
11172
11173
11174
11175static void
11176chkmail(void)
11177{
11178 const char *mpath;
11179 char *p;
11180 char *q;
11181 unsigned new_hash;
11182 struct stackmark smark;
11183 struct stat statb;
11184
11185 setstackmark(&smark);
11186 mpath = mpathset() ? mpathval() : mailval();
11187 new_hash = 0;
11188 for (;;) {
11189 int len;
11190
11191 len = padvance_magic(&mpath, nullstr, 2);
11192 if (!len)
11193 break;
11194 p = stackblock();
11195 break;
11196 if (*p == '\0')
11197 continue;
11198 for (q = p; *q; q++)
11199 continue;
11200#if DEBUG
11201 if (q[-1] != '/')
11202 abort();
11203#endif
11204 q[-1] = '\0';
11205 if (stat(p, &statb) < 0) {
11206 continue;
11207 }
11208
11209 new_hash += (unsigned)statb.st_mtime;
11210 }
11211 if (!mail_var_path_changed && mailtime_hash != new_hash) {
11212 if (mailtime_hash != 0)
11213 out2str("you have mail\n");
11214 mailtime_hash = new_hash;
11215 }
11216 mail_var_path_changed = 0;
11217 popstackmark(&smark);
11218}
11219
11220static void FAST_FUNC
11221changemail(const char *val UNUSED_PARAM)
11222{
11223 mail_var_path_changed = 1;
11224}
11225
11226#endif
11227
11228
11229
11230
11231
11232
11233
11234static void
11235setparam(char **argv)
11236{
11237 char **newparam;
11238 char **ap;
11239 int nparam;
11240
11241 for (nparam = 0; argv[nparam]; nparam++)
11242 continue;
11243 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
11244 while (*argv) {
11245 *ap++ = ckstrdup(*argv++);
11246 }
11247 *ap = NULL;
11248 freeparam(&shellparam);
11249 shellparam.malloced = 1;
11250 shellparam.nparam = nparam;
11251 shellparam.p = newparam;
11252#if ENABLE_ASH_GETOPTS
11253 shellparam.optind = 1;
11254 shellparam.optoff = -1;
11255#endif
11256}
11257
11258
11259
11260
11261
11262
11263
11264
11265
11266
11267
11268
11269
11270
11271
11272
11273
11274
11275
11276
11277
11278
11279static int
11280plus_minus_o(char *name, int val)
11281{
11282 int i;
11283
11284 if (name) {
11285 for (i = 0; i < NOPTS; i++) {
11286 if (strcmp(name, optnames(i)) == 0) {
11287 optlist[i] = val;
11288 return 0;
11289 }
11290 }
11291 ash_msg("illegal option %co %s", val ? '-' : '+', name);
11292 return 1;
11293 }
11294 for (i = 0; i < NOPTS; i++) {
11295 if (optnames(i)[0] == '\0')
11296 continue;
11297 if (val) {
11298 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11299 } else {
11300 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11301 }
11302 }
11303 return 0;
11304}
11305static void
11306setoption(int flag, int val)
11307{
11308 int i;
11309
11310 for (i = 0; i < NOPTS; i++) {
11311 if (optletters(i) == flag && optnames(i)[0] != '\0') {
11312 optlist[i] = val;
11313 return;
11314 }
11315 }
11316 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
11317
11318}
11319
11320
11321
11322static int
11323options(int *login_sh)
11324{
11325 char *p;
11326 int val;
11327 int c;
11328
11329 if (login_sh)
11330 minusc = NULL;
11331 while ((p = *argptr) != NULL) {
11332 c = *p++;
11333 if (c != '-' && c != '+')
11334 break;
11335 argptr++;
11336 val = 0;
11337 if (c == '-') {
11338 val = 1;
11339 if (p[0] == '\0' || LONE_DASH(p)) {
11340 if (!login_sh) {
11341
11342 if (p[0] == '\0')
11343 xflag = vflag = 0;
11344
11345 else if (*argptr == NULL)
11346 setparam(argptr);
11347 }
11348 break;
11349 }
11350 }
11351
11352 while ((c = *p++) != '\0') {
11353 if (login_sh) {
11354
11355 if (c == 'c') {
11356 minusc = p;
11357 cflag = 1;
11358 continue;
11359 }
11360 if (c == 's') {
11361 sflag = 1;
11362 continue;
11363 }
11364 if (c == 'i') {
11365 iflag = 1;
11366 continue;
11367 }
11368 if (c == 'l') {
11369 *login_sh = 1;
11370 continue;
11371 }
11372
11373 if (val && (c == '-')) {
11374 if (strcmp(p, "login") == 0) {
11375 *login_sh = 1;
11376 }
11377 break;
11378 }
11379 }
11380 if (c == 'o') {
11381 if (plus_minus_o(*argptr, val)) {
11382
11383 return 1;
11384 }
11385 if (*argptr)
11386 argptr++;
11387 } else {
11388 setoption(c, val);
11389 }
11390 }
11391 }
11392 return 0;
11393}
11394
11395
11396
11397
11398static int FAST_FUNC
11399shiftcmd(int argc UNUSED_PARAM, char **argv)
11400{
11401 int n;
11402 char **ap1, **ap2;
11403
11404 n = 1;
11405 if (argv[1])
11406 n = number(argv[1]);
11407 if (n > shellparam.nparam)
11408 return 1;
11409 INT_OFF;
11410 shellparam.nparam -= n;
11411 for (ap1 = shellparam.p; --n >= 0; ap1++) {
11412 if (shellparam.malloced)
11413 free(*ap1);
11414 }
11415 ap2 = shellparam.p;
11416 while ((*ap2++ = *ap1++) != NULL)
11417 continue;
11418#if ENABLE_ASH_GETOPTS
11419 shellparam.optind = 1;
11420 shellparam.optoff = -1;
11421#endif
11422 INT_ON;
11423 return 0;
11424}
11425
11426
11427
11428
11429
11430
11431
11432
11433static int
11434showvars(const char *sep_prefix, int on, int off)
11435{
11436 const char *sep;
11437 char **ep, **epend;
11438
11439 ep = listvars(on, off, NULL, &epend);
11440 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11441
11442 sep = *sep_prefix ? " " : sep_prefix;
11443
11444 for (; ep < epend; ep++) {
11445 const char *p;
11446 const char *q;
11447
11448 p = endofname(*ep);
11449
11450
11451
11452
11453
11454
11455
11456
11457 q = nullstr;
11458 if (*p == '=')
11459 q = single_quote(++p);
11460 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11461 }
11462 return 0;
11463}
11464
11465
11466
11467
11468static int FAST_FUNC
11469setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11470{
11471 int retval;
11472
11473 if (!argv[1])
11474 return showvars(nullstr, 0, VUNSET);
11475
11476 INT_OFF;
11477 retval = options( NULL);
11478 if (retval == 0) {
11479 optschanged();
11480 if (*argptr != NULL) {
11481 setparam(argptr);
11482 }
11483 }
11484 INT_ON;
11485 return retval;
11486}
11487
11488#if ENABLE_ASH_RANDOM_SUPPORT
11489static void FAST_FUNC
11490change_random(const char *value)
11491{
11492 uint32_t t;
11493
11494 if (value == NULL) {
11495
11496 t = next_random(&random_gen);
11497
11498 setvar(vrandom.var_text, utoa(t), VNOFUNC);
11499 vrandom.flags &= ~VNOFUNC;
11500 } else {
11501
11502 t = strtoul(value, NULL, 10);
11503 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
11504 }
11505}
11506#endif
11507
11508#if BASH_EPOCH_VARS
11509static void FAST_FUNC
11510change_epoch(struct var *vepoch, const char *fmt)
11511{
11512 struct timeval tv;
11513 char buffer[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
11514
11515 xgettimeofday(&tv);
11516 sprintf(buffer, fmt, (unsigned long long)tv.tv_sec, (unsigned)tv.tv_usec);
11517 setvar(vepoch->var_text, buffer, VNOFUNC);
11518 vepoch->flags &= ~VNOFUNC;
11519}
11520
11521static void FAST_FUNC
11522change_seconds(const char *value UNUSED_PARAM)
11523{
11524 change_epoch(&vepochs, "%llu");
11525}
11526
11527static void FAST_FUNC
11528change_realtime(const char *value UNUSED_PARAM)
11529{
11530 change_epoch(&vepochr, "%llu.%06u");
11531}
11532#endif
11533
11534#if ENABLE_ASH_GETOPTS
11535static int
11536getopts(char *optstr, char *optvar, char **optfirst)
11537{
11538 char *p, *q;
11539 char c = '?';
11540 int done = 0;
11541 char sbuf[2];
11542 char **optnext;
11543 int ind = shellparam.optind;
11544 int off = shellparam.optoff;
11545
11546 sbuf[1] = '\0';
11547
11548 shellparam.optind = -1;
11549 optnext = optfirst + ind - 1;
11550
11551 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
11552 p = NULL;
11553 else
11554 p = optnext[-1] + off;
11555 if (p == NULL || *p == '\0') {
11556
11557 p = *optnext;
11558 if (p == NULL || *p != '-' || *++p == '\0') {
11559 atend:
11560 unsetvar("OPTARG");
11561 p = NULL;
11562 done = 1;
11563 goto out;
11564 }
11565 optnext++;
11566 if (LONE_DASH(p))
11567 goto atend;
11568 }
11569
11570 c = *p++;
11571 for (q = optstr; *q != c;) {
11572 if (*q == '\0') {
11573
11574 const char *cp = lookupvar("OPTERR");
11575 if ((cp && LONE_CHAR(cp, '0'))
11576 || (optstr[0] == ':')
11577 ) {
11578 sbuf[0] = c;
11579
11580 setvar0("OPTARG", sbuf);
11581 } else {
11582 fprintf(stderr, "Illegal option -%c\n", c);
11583 unsetvar("OPTARG");
11584 }
11585 c = '?';
11586 goto out;
11587 }
11588 if (*++q == ':')
11589 q++;
11590 }
11591
11592 if (*++q == ':') {
11593 if (*p == '\0' && (p = *optnext) == NULL) {
11594
11595 const char *cp = lookupvar("OPTERR");
11596 if ((cp && LONE_CHAR(cp, '0'))
11597 || (optstr[0] == ':')
11598 ) {
11599 sbuf[0] = c;
11600
11601 setvar0("OPTARG", sbuf);
11602 c = ':';
11603 } else {
11604 fprintf(stderr, "No arg for -%c option\n", c);
11605 unsetvar("OPTARG");
11606 c = '?';
11607 }
11608 goto out;
11609 }
11610
11611 if (p == *optnext)
11612 optnext++;
11613 setvar0("OPTARG", p);
11614 p = NULL;
11615 } else
11616 setvar0("OPTARG", nullstr);
11617 out:
11618 ind = optnext - optfirst + 1;
11619 setvar("OPTIND", itoa(ind), VNOFUNC);
11620 sbuf[0] = c;
11621
11622 setvar0(optvar, sbuf);
11623
11624 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11625 shellparam.optind = ind;
11626
11627 return done;
11628}
11629
11630
11631
11632
11633
11634
11635
11636static int FAST_FUNC
11637getoptscmd(int argc, char **argv)
11638{
11639 char **optbase;
11640
11641 if (argc < 3)
11642 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
11643 if (argc == 3) {
11644 optbase = shellparam.p;
11645 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
11646 shellparam.optind = 1;
11647 shellparam.optoff = -1;
11648 }
11649 } else {
11650 optbase = &argv[3];
11651 if ((unsigned)shellparam.optind > argc - 2) {
11652 shellparam.optind = 1;
11653 shellparam.optoff = -1;
11654 }
11655 }
11656
11657 return getopts(argv[1], argv[2], optbase);
11658}
11659#endif
11660
11661
11662
11663
11664struct heredoc {
11665 struct heredoc *next;
11666 union node *here;
11667 char *eofmark;
11668 smallint striptabs;
11669};
11670
11671static smallint tokpushback;
11672static smallint quoteflag;
11673static token_id_t lasttoken;
11674static struct heredoc *heredoclist;
11675static char *wordtext;
11676static struct nodelist *backquotelist;
11677static union node *redirnode;
11678static struct heredoc *heredoc;
11679
11680static const char *
11681tokname(char *buf, int tok)
11682{
11683 if (tok < TSEMI)
11684 return tokname_array[tok];
11685 sprintf(buf, "\"%s\"", tokname_array[tok]);
11686 return buf;
11687}
11688
11689
11690
11691
11692
11693
11694static void raise_error_unexpected_syntax(int) NORETURN;
11695static void
11696raise_error_unexpected_syntax(int token)
11697{
11698 char msg[64];
11699 char buf[16];
11700 int l;
11701
11702 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
11703 if (token >= 0)
11704 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
11705 raise_error_syntax(msg);
11706
11707}
11708
11709
11710static union node *andor(void);
11711static union node *pipeline(void);
11712static union node *parse_command(void);
11713static void parseheredoc(void);
11714static int peektoken(void);
11715static int readtoken(void);
11716
11717static union node *
11718list(int nlflag)
11719{
11720 union node *n1, *n2, *n3;
11721 int tok;
11722
11723 n1 = NULL;
11724 for (;;) {
11725 switch (readtoken()) {
11726 case TNL:
11727 if (!(nlflag & 1))
11728 break;
11729 parseheredoc();
11730 return n1;
11731
11732 case TEOF:
11733 if (!n1 && (nlflag & 1))
11734 n1 = NODE_EOF;
11735 parseheredoc();
11736 tokpushback++;
11737 lasttoken = TEOF;
11738 return n1;
11739 }
11740
11741 tokpushback++;
11742 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11743 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
11744 return n1;
11745 nlflag |= 2;
11746
11747 n2 = andor();
11748 tok = readtoken();
11749 if (tok == TBACKGND) {
11750 if (n2->type == NPIPE) {
11751 n2->npipe.pipe_backgnd = 1;
11752 } else {
11753 if (n2->type != NREDIR) {
11754 n3 = stzalloc(sizeof(struct nredir));
11755 n3->nredir.n = n2;
11756
11757 n2 = n3;
11758 }
11759 n2->type = NBACKGND;
11760 }
11761 }
11762 if (n1 == NULL) {
11763 n1 = n2;
11764 } else {
11765 n3 = stzalloc(sizeof(struct nbinary));
11766 n3->type = NSEMI;
11767 n3->nbinary.ch1 = n1;
11768 n3->nbinary.ch2 = n2;
11769 n1 = n3;
11770 }
11771 switch (tok) {
11772 case TNL:
11773 case TEOF:
11774 tokpushback = 1;
11775
11776 case TBACKGND:
11777 case TSEMI:
11778 break;
11779 default:
11780 if ((nlflag & 1))
11781 raise_error_unexpected_syntax(-1);
11782 tokpushback = 1;
11783 return n1;
11784 }
11785 }
11786}
11787
11788static union node *
11789andor(void)
11790{
11791 union node *n1, *n2, *n3;
11792 int t;
11793
11794 n1 = pipeline();
11795 for (;;) {
11796 t = readtoken();
11797 if (t == TAND) {
11798 t = NAND;
11799 } else if (t == TOR) {
11800 t = NOR;
11801 } else {
11802 tokpushback = 1;
11803 return n1;
11804 }
11805 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11806 n2 = pipeline();
11807 n3 = stzalloc(sizeof(struct nbinary));
11808 n3->type = t;
11809 n3->nbinary.ch1 = n1;
11810 n3->nbinary.ch2 = n2;
11811 n1 = n3;
11812 }
11813}
11814
11815static union node *
11816pipeline(void)
11817{
11818 union node *n1, *n2, *pipenode;
11819 struct nodelist *lp, *prev;
11820 int negate;
11821
11822 negate = 0;
11823 TRACE(("pipeline: entered\n"));
11824 if (readtoken() == TNOT) {
11825 negate = !negate;
11826 checkkwd = CHKKWD | CHKALIAS;
11827 } else
11828 tokpushback = 1;
11829 n1 = parse_command();
11830 if (readtoken() == TPIPE) {
11831 pipenode = stzalloc(sizeof(struct npipe));
11832 pipenode->type = NPIPE;
11833
11834 lp = stzalloc(sizeof(struct nodelist));
11835 pipenode->npipe.cmdlist = lp;
11836 lp->n = n1;
11837 do {
11838 prev = lp;
11839 lp = stzalloc(sizeof(struct nodelist));
11840 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11841 lp->n = parse_command();
11842 prev->next = lp;
11843 } while (readtoken() == TPIPE);
11844 lp->next = NULL;
11845 n1 = pipenode;
11846 }
11847 tokpushback = 1;
11848 if (negate) {
11849 n2 = stzalloc(sizeof(struct nnot));
11850 n2->type = NNOT;
11851 n2->nnot.com = n1;
11852 return n2;
11853 }
11854 return n1;
11855}
11856
11857static union node *
11858makename(void)
11859{
11860 union node *n;
11861
11862 n = stzalloc(sizeof(struct narg));
11863 n->type = NARG;
11864
11865 n->narg.text = wordtext;
11866 n->narg.backquote = backquotelist;
11867 return n;
11868}
11869
11870static void
11871fixredir(union node *n, const char *text, int err)
11872{
11873 int fd;
11874
11875 TRACE(("Fix redir %s %d\n", text, err));
11876 if (!err)
11877 n->ndup.vname = NULL;
11878
11879 fd = bb_strtou(text, NULL, 10);
11880 if (!errno && fd >= 0)
11881 n->ndup.dupfd = fd;
11882 else if (LONE_DASH(text))
11883 n->ndup.dupfd = -1;
11884 else {
11885 if (err)
11886 raise_error_syntax("bad fd number");
11887 n->ndup.vname = makename();
11888 }
11889}
11890
11891static void
11892parsefname(void)
11893{
11894 union node *n = redirnode;
11895
11896 if (n->type == NHERE)
11897 checkkwd = CHKEOFMARK;
11898 if (readtoken() != TWORD)
11899 raise_error_unexpected_syntax(-1);
11900 if (n->type == NHERE) {
11901 struct heredoc *here = heredoc;
11902 struct heredoc *p;
11903
11904 if (quoteflag == 0)
11905 n->type = NXHERE;
11906 TRACE(("Here document %d\n", n->type));
11907 rmescapes(wordtext, 0, NULL);
11908 here->eofmark = wordtext;
11909 here->next = NULL;
11910 if (heredoclist == NULL)
11911 heredoclist = here;
11912 else {
11913 for (p = heredoclist; p->next; p = p->next)
11914 continue;
11915 p->next = here;
11916 }
11917 } else if (n->type == NTOFD || n->type == NFROMFD) {
11918 fixredir(n, wordtext, 0);
11919 } else {
11920 n->nfile.fname = makename();
11921 }
11922}
11923
11924static union node *
11925simplecmd(void)
11926{
11927 union node *args, **app;
11928 union node *n = NULL;
11929 union node *vars, **vpp;
11930 union node **rpp, *redir;
11931 int savecheckkwd;
11932 int savelinno;
11933#if BASH_TEST2
11934 smallint double_brackets_flag = 0;
11935#endif
11936 IF_BASH_FUNCTION(smallint function_flag = 0;)
11937
11938 args = NULL;
11939 app = &args;
11940 vars = NULL;
11941 vpp = &vars;
11942 redir = NULL;
11943 rpp = &redir;
11944
11945 savecheckkwd = CHKALIAS;
11946 savelinno = g_parsefile->linno;
11947 for (;;) {
11948 int t;
11949 checkkwd = savecheckkwd;
11950 t = readtoken();
11951 switch (t) {
11952#if BASH_FUNCTION
11953 case TFUNCTION:
11954 if (peektoken() != TWORD)
11955 raise_error_unexpected_syntax(TWORD);
11956 function_flag = 1;
11957 break;
11958#endif
11959#if BASH_TEST2
11960 case TAND:
11961 case TOR:
11962 if (!double_brackets_flag) {
11963 tokpushback = 1;
11964 goto out;
11965 }
11966
11967 wordtext = (char *) (t == TAND ? "&&" : "||");
11968#endif
11969 case TWORD:
11970 n = stzalloc(sizeof(struct narg));
11971 n->type = NARG;
11972
11973 n->narg.text = wordtext;
11974#if BASH_TEST2
11975 if (strcmp("[[", wordtext) == 0)
11976 double_brackets_flag = 1;
11977 else if (strcmp("]]", wordtext) == 0)
11978 double_brackets_flag = 0;
11979#endif
11980 n->narg.backquote = backquotelist;
11981 if (savecheckkwd && isassignment(wordtext)) {
11982 *vpp = n;
11983 vpp = &n->narg.next;
11984 } else {
11985 *app = n;
11986 app = &n->narg.next;
11987 savecheckkwd = 0;
11988 }
11989#if BASH_FUNCTION
11990 if (function_flag) {
11991 checkkwd = CHKNL | CHKKWD;
11992 switch (peektoken()) {
11993 case TBEGIN:
11994 case TIF:
11995 case TCASE:
11996 case TUNTIL:
11997 case TWHILE:
11998 case TFOR:
11999 goto do_func;
12000 case TLP:
12001 function_flag = 0;
12002 break;
12003# if BASH_TEST2
12004 case TWORD:
12005 if (strcmp("[[", wordtext) == 0)
12006 goto do_func;
12007
12008# endif
12009 default:
12010 raise_error_unexpected_syntax(-1);
12011 }
12012 }
12013#endif
12014 break;
12015 case TREDIR:
12016 *rpp = n = redirnode;
12017 rpp = &n->nfile.next;
12018 parsefname();
12019 break;
12020 case TLP:
12021 IF_BASH_FUNCTION(do_func:)
12022 if (args && app == &args->narg.next
12023 && !vars && !redir
12024 ) {
12025 struct builtincmd *bcmd;
12026 const char *name;
12027
12028
12029 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
12030 raise_error_unexpected_syntax(TRP);
12031 name = n->narg.text;
12032 if (!goodname(name)
12033 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
12034 ) {
12035 raise_error_syntax("bad function name");
12036 }
12037 n->type = NDEFUN;
12038 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12039 n->ndefun.text = n->narg.text;
12040 n->ndefun.linno = g_parsefile->linno;
12041 n->ndefun.body = parse_command();
12042 return n;
12043 }
12044 IF_BASH_FUNCTION(function_flag = 0;)
12045
12046 default:
12047 tokpushback = 1;
12048 goto out;
12049 }
12050 }
12051 out:
12052 *app = NULL;
12053 *vpp = NULL;
12054 *rpp = NULL;
12055 n = stzalloc(sizeof(struct ncmd));
12056 if (NCMD != 0)
12057 n->type = NCMD;
12058 n->ncmd.linno = savelinno;
12059 n->ncmd.args = args;
12060 n->ncmd.assign = vars;
12061 n->ncmd.redirect = redir;
12062 return n;
12063}
12064
12065static union node *
12066parse_command(void)
12067{
12068 union node *n1, *n2;
12069 union node *ap, **app;
12070 union node *cp, **cpp;
12071 union node *redir, **rpp;
12072 union node **rpp2;
12073 int t;
12074 int savelinno;
12075
12076 redir = NULL;
12077 rpp2 = &redir;
12078
12079 savelinno = g_parsefile->linno;
12080
12081 switch (readtoken()) {
12082 default:
12083 raise_error_unexpected_syntax(-1);
12084
12085 case TIF:
12086 n1 = stzalloc(sizeof(struct nif));
12087 n1->type = NIF;
12088 n1->nif.test = list(0);
12089 if (readtoken() != TTHEN)
12090 raise_error_unexpected_syntax(TTHEN);
12091 n1->nif.ifpart = list(0);
12092 n2 = n1;
12093 while (readtoken() == TELIF) {
12094 n2->nif.elsepart = stzalloc(sizeof(struct nif));
12095 n2 = n2->nif.elsepart;
12096 n2->type = NIF;
12097 n2->nif.test = list(0);
12098 if (readtoken() != TTHEN)
12099 raise_error_unexpected_syntax(TTHEN);
12100 n2->nif.ifpart = list(0);
12101 }
12102 if (lasttoken == TELSE)
12103 n2->nif.elsepart = list(0);
12104 else {
12105 n2->nif.elsepart = NULL;
12106 tokpushback = 1;
12107 }
12108 t = TFI;
12109 break;
12110 case TWHILE:
12111 case TUNTIL: {
12112 int got;
12113 n1 = stzalloc(sizeof(struct nbinary));
12114 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
12115 n1->nbinary.ch1 = list(0);
12116 got = readtoken();
12117 if (got != TDO) {
12118 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
12119 got == TWORD ? wordtext : ""));
12120 raise_error_unexpected_syntax(TDO);
12121 }
12122 n1->nbinary.ch2 = list(0);
12123 t = TDONE;
12124 break;
12125 }
12126 case TFOR:
12127 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
12128 raise_error_syntax("bad for loop variable");
12129 n1 = stzalloc(sizeof(struct nfor));
12130 n1->type = NFOR;
12131 n1->nfor.linno = savelinno;
12132 n1->nfor.var = wordtext;
12133 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12134 if (readtoken() == TIN) {
12135 app = ≈
12136 while (readtoken() == TWORD) {
12137 n2 = stzalloc(sizeof(struct narg));
12138 n2->type = NARG;
12139
12140 n2->narg.text = wordtext;
12141 n2->narg.backquote = backquotelist;
12142 *app = n2;
12143 app = &n2->narg.next;
12144 }
12145 *app = NULL;
12146 n1->nfor.args = ap;
12147 if (lasttoken != TNL && lasttoken != TSEMI)
12148 raise_error_unexpected_syntax(-1);
12149 } else {
12150 n2 = stzalloc(sizeof(struct narg));
12151 n2->type = NARG;
12152
12153 n2->narg.text = (char *)dolatstr;
12154
12155 n1->nfor.args = n2;
12156
12157
12158
12159
12160 if (lasttoken != TSEMI)
12161 tokpushback = 1;
12162 }
12163 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12164 if (readtoken() != TDO)
12165 raise_error_unexpected_syntax(TDO);
12166 n1->nfor.body = list(0);
12167 t = TDONE;
12168 break;
12169 case TCASE:
12170 n1 = stzalloc(sizeof(struct ncase));
12171 n1->type = NCASE;
12172 n1->ncase.linno = savelinno;
12173 if (readtoken() != TWORD)
12174 raise_error_unexpected_syntax(TWORD);
12175 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
12176 n2->type = NARG;
12177
12178 n2->narg.text = wordtext;
12179 n2->narg.backquote = backquotelist;
12180 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12181 if (readtoken() != TIN)
12182 raise_error_unexpected_syntax(TIN);
12183 cpp = &n1->ncase.cases;
12184 next_case:
12185 checkkwd = CHKNL | CHKKWD;
12186 t = readtoken();
12187 while (t != TESAC) {
12188 if (lasttoken == TLP)
12189 readtoken();
12190 *cpp = cp = stzalloc(sizeof(struct nclist));
12191 cp->type = NCLIST;
12192 app = &cp->nclist.pattern;
12193 for (;;) {
12194 *app = ap = stzalloc(sizeof(struct narg));
12195 ap->type = NARG;
12196
12197 ap->narg.text = wordtext;
12198 ap->narg.backquote = backquotelist;
12199 if (readtoken() != TPIPE)
12200 break;
12201 app = &ap->narg.next;
12202 readtoken();
12203 }
12204
12205 if (lasttoken != TRP)
12206 raise_error_unexpected_syntax(TRP);
12207 cp->nclist.body = list(2);
12208
12209 cpp = &cp->nclist.next;
12210
12211 checkkwd = CHKNL | CHKKWD;
12212 t = readtoken();
12213 if (t != TESAC) {
12214 if (t != TENDCASE)
12215 raise_error_unexpected_syntax(TENDCASE);
12216 goto next_case;
12217 }
12218 }
12219 *cpp = NULL;
12220 goto redir;
12221 case TLP:
12222 n1 = stzalloc(sizeof(struct nredir));
12223 n1->type = NSUBSHELL;
12224 n1->nredir.linno = savelinno;
12225 n1->nredir.n = list(0);
12226
12227 t = TRP;
12228 break;
12229 case TBEGIN:
12230 n1 = list(0);
12231 t = TEND;
12232 break;
12233 IF_BASH_FUNCTION(case TFUNCTION:)
12234 case TWORD:
12235 case TREDIR:
12236 tokpushback = 1;
12237 return simplecmd();
12238 }
12239
12240 if (readtoken() != t)
12241 raise_error_unexpected_syntax(t);
12242
12243 redir:
12244
12245 checkkwd = CHKKWD | CHKALIAS;
12246 rpp = rpp2;
12247 while (readtoken() == TREDIR) {
12248 *rpp = n2 = redirnode;
12249 rpp = &n2->nfile.next;
12250 parsefname();
12251 }
12252 tokpushback = 1;
12253 *rpp = NULL;
12254 if (redir) {
12255 if (n1->type != NSUBSHELL) {
12256 n2 = stzalloc(sizeof(struct nredir));
12257 n2->type = NREDIR;
12258 n2->nredir.linno = savelinno;
12259 n2->nredir.n = n1;
12260 n1 = n2;
12261 }
12262 n1->nredir.redirect = redir;
12263 }
12264 return n1;
12265}
12266
12267#if BASH_DOLLAR_SQUOTE
12268static int
12269decode_dollar_squote(void)
12270{
12271 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
12272 int c, cnt;
12273 char *p;
12274 char buf[4];
12275
12276 c = pgetc();
12277 p = strchr(C_escapes, c);
12278 if (p) {
12279 buf[0] = c;
12280 p = buf;
12281 cnt = 3;
12282 if ((unsigned char)(c - '0') <= 7) {
12283 do {
12284 c = pgetc();
12285 *++p = c;
12286 } while ((unsigned char)(c - '0') <= 7 && --cnt);
12287 pungetc();
12288 } else if (c == 'x') {
12289 do {
12290 c = pgetc();
12291 *++p = c;
12292 } while (isxdigit(c) && --cnt);
12293 pungetc();
12294 if (cnt == 3) {
12295 c = 'x';
12296 goto unrecognized;
12297 }
12298 } else {
12299 p++;
12300 }
12301 *p = '\0';
12302 p = buf;
12303 c = bb_process_escape_sequence((void*)&p);
12304 } else {
12305 if (c != '\'' && c != '"') {
12306 unrecognized:
12307 c |= 0x100;
12308 }
12309 }
12310 return c;
12311}
12312#endif
12313
12314
12315#define FAKEEOFMARK ((char*)(uintptr_t)1)
12316
12317static ALWAYS_INLINE int
12318realeofmark(const char *eofmark)
12319{
12320 return eofmark && eofmark != FAKEEOFMARK;
12321}
12322
12323
12324
12325
12326
12327
12328
12329
12330
12331
12332
12333
12334#define CHECKEND() {goto checkend; checkend_return:;}
12335#define PARSEREDIR() {goto parseredir; parseredir_return:;}
12336#define PARSESUB() {goto parsesub; parsesub_return:;}
12337#define PARSEBACKQOLD() {style = OLD; goto parsebackq; parsebackq_oldreturn:;}
12338#define PARSEBACKQNEW() {style = NEW; goto parsebackq; parsebackq_newreturn:;}
12339#define PARSEPROCSUB() {style = PSUB; goto parsebackq; parsebackq_psreturn:;}
12340#define PARSEARITH() {goto parsearith; parsearith_return:;}
12341static int
12342readtoken1(int c, int syntax, char *eofmark, int striptabs)
12343{
12344
12345
12346 char *out;
12347 size_t len;
12348 struct nodelist *bqlist;
12349 smallint quotef;
12350 smallint style;
12351 enum { OLD, NEW, PSUB };
12352#define oldstyle (style == OLD)
12353 smallint pssyntax;
12354 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
12355
12356 struct synstack synbase = { };
12357 struct synstack *synstack = &synbase;
12358
12359#if ENABLE_ASH_EXPAND_PRMT
12360 pssyntax = (syntax == PSSYNTAX);
12361 if (pssyntax)
12362 syntax = DQSYNTAX;
12363#else
12364 pssyntax = 0;
12365#endif
12366 synstack->syntax = syntax;
12367
12368 if (syntax == DQSYNTAX)
12369 synstack->dblquote = 1;
12370 quotef = 0;
12371 bqlist = NULL;
12372
12373 STARTSTACKSTR(out);
12374 loop:
12375
12376 CHECKEND();
12377 for (;;) {
12378 CHECKSTRSPACE(4, out);
12379 switch (SIT(c, synstack->syntax)) {
12380 case CNL:
12381 if (synstack->syntax == BASESYNTAX
12382 && !synstack->varnest
12383 ) {
12384 goto endword;
12385 }
12386 USTPUTC(c, out);
12387 nlprompt();
12388 c = pgetc_top(synstack);
12389 goto loop;
12390 case CWORD:
12391 USTPUTC(c, out);
12392 break;
12393 case CCTL:
12394#if BASH_DOLLAR_SQUOTE
12395 if (c == '\\' && bash_dollar_squote) {
12396 c = decode_dollar_squote();
12397 if (c == '\0') {
12398
12399 break;
12400 }
12401 if (c & 0x100) {
12402
12403 c = (unsigned char)c;
12404 if (eofmark == NULL || synstack->dblquote)
12405 USTPUTC(CTLESC, out);
12406 USTPUTC('\\', out);
12407 }
12408 }
12409#endif
12410 if (!eofmark || synstack->dblquote || synstack->varnest)
12411 USTPUTC(CTLESC, out);
12412 USTPUTC(c, out);
12413 break;
12414 case CBACK:
12415 c = pgetc_without_PEOA();
12416 if (c == PEOF) {
12417 USTPUTC(CTLESC, out);
12418 USTPUTC('\\', out);
12419 pungetc();
12420 } else {
12421 if (pssyntax && c == '$') {
12422 USTPUTC(CTLESC, out);
12423 USTPUTC('\\', out);
12424 }
12425
12426
12427
12428 if (synstack->dblquote
12429 && c != '\\'
12430 && c != '`'
12431 && c != '$'
12432 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12433 && (c != '}' || !synstack->varnest)
12434 ) {
12435 USTPUTC(CTLESC, out);
12436 USTPUTC('\\', out);
12437 }
12438 USTPUTC(CTLESC, out);
12439 USTPUTC(c, out);
12440 quotef = 1;
12441 }
12442 break;
12443 case CSQUOTE:
12444 synstack->syntax = SQSYNTAX;
12445 quotemark:
12446 if (eofmark == NULL) {
12447 USTPUTC(CTLQUOTEMARK, out);
12448 }
12449 break;
12450 case CDQUOTE:
12451 synstack->syntax = DQSYNTAX;
12452 synstack->dblquote = 1;
12453 toggledq:
12454 if (synstack->varnest)
12455 synstack->innerdq ^= 1;
12456 goto quotemark;
12457 case CENDQUOTE:
12458 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
12459 if (eofmark != NULL && synstack->varnest == 0) {
12460 USTPUTC(c, out);
12461 break;
12462 }
12463
12464 if (synstack->dqvarnest == 0) {
12465 synstack->syntax = BASESYNTAX;
12466 synstack->dblquote = 0;
12467 }
12468
12469 quotef = 1;
12470
12471 if (c == '"')
12472 goto toggledq;
12473
12474 goto quotemark;
12475 case CVAR:
12476 PARSESUB();
12477 break;
12478 case CENDVAR:
12479 if (!synstack->innerdq && synstack->varnest > 0) {
12480 if (!--synstack->varnest && synstack->varpushed)
12481 synstack_pop(&synstack);
12482 else if (synstack->dqvarnest > 0)
12483 synstack->dqvarnest--;
12484 c = CTLENDVAR;
12485 }
12486 USTPUTC(c, out);
12487 break;
12488#if ENABLE_FEATURE_SH_MATH
12489 case CLP:
12490 synstack->parenlevel++;
12491 USTPUTC(c, out);
12492 break;
12493 case CRP:
12494 if (synstack->parenlevel > 0) {
12495 synstack->parenlevel--;
12496 } else {
12497 if (pgetc_eatbnl() == ')') {
12498 c = CTLENDARI;
12499 synstack_pop(&synstack);
12500 } else {
12501
12502
12503
12504
12505 pungetc();
12506 }
12507 }
12508 USTPUTC(c, out);
12509 break;
12510#endif
12511 case CBQUOTE:
12512 if (checkkwd & CHKEOFMARK) {
12513 quotef = 1;
12514 USTPUTC('`', out);
12515 break;
12516 }
12517
12518 PARSEBACKQOLD();
12519 break;
12520 case CENDFILE:
12521 goto endword;
12522 case CIGN:
12523 break;
12524 default:
12525 if (synstack->varnest == 0) {
12526#if BASH_REDIR_OUTPUT
12527 if (c == '&') {
12528
12529 if (pgetc() == '>')
12530 c = 0x100 + '>';
12531 pungetc();
12532 }
12533#endif
12534#if BASH_PROCESS_SUBST
12535 if (c == '<' || c == '>') {
12536 if (pgetc() == '(') {
12537 PARSEPROCSUB();
12538 break;
12539 }
12540 pungetc();
12541 }
12542#endif
12543 goto endword;
12544 }
12545 IF_ASH_ALIAS(if (c != PEOA))
12546 USTPUTC(c, out);
12547 }
12548 c = pgetc_top(synstack);
12549 }
12550 endword:
12551
12552#if ENABLE_FEATURE_SH_MATH
12553 if (synstack->syntax == ARISYNTAX)
12554 raise_error_syntax("missing '))'");
12555#endif
12556 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
12557 raise_error_syntax("unterminated quoted string");
12558 if (synstack->varnest != 0) {
12559
12560 raise_error_syntax("missing '}'");
12561 }
12562 USTPUTC('\0', out);
12563 len = out - (char *)stackblock();
12564 out = stackblock();
12565 if (eofmark == NULL) {
12566 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
12567 && quotef == 0
12568 ) {
12569 if (isdigit_str9(out)) {
12570 PARSEREDIR();
12571 lasttoken = TREDIR;
12572 return lasttoken;
12573 }
12574
12575
12576 }
12577 pungetc();
12578 }
12579 quoteflag = quotef;
12580 backquotelist = bqlist;
12581 grabstackblock(len);
12582 wordtext = out;
12583 lasttoken = TWORD;
12584 return lasttoken;
12585
12586
12587
12588
12589
12590
12591
12592checkend: {
12593 if (realeofmark(eofmark)) {
12594 int markloc;
12595 char *p;
12596
12597#if ENABLE_ASH_ALIAS
12598 if (c == PEOA)
12599 c = pgetc_without_PEOA();
12600#endif
12601 if (striptabs) {
12602 while (c == '\t') {
12603 c = pgetc_without_PEOA();
12604 }
12605 }
12606
12607 markloc = out - (char *)stackblock();
12608 for (p = eofmark; STPUTC(c, out), *p; p++) {
12609 if (c != *p)
12610 goto more_heredoc;
12611
12612
12613
12614
12615
12616
12617
12618 c = pgetc_without_PEOA();
12619 }
12620
12621 if (c == '\n' || c == PEOF) {
12622 c = PEOF;
12623 g_parsefile->linno++;
12624 needprompt = doprompt;
12625 } else {
12626 int len_here;
12627
12628 more_heredoc:
12629 p = (char *)stackblock() + markloc + 1;
12630 len_here = out - p;
12631
12632 if (len_here) {
12633 len_here -= (c >= PEOF);
12634 c = p[-1];
12635
12636 if (len_here) {
12637 char *str;
12638
12639 str = alloca(len_here + 1);
12640 *(char *)mempcpy(str, p, len_here) = '\0';
12641
12642 pushstring(str, NULL);
12643 }
12644 }
12645 }
12646
12647 STADJUST((char *)stackblock() + markloc - out, out);
12648 }
12649 goto checkend_return;
12650}
12651
12652
12653
12654
12655
12656
12657parseredir: {
12658
12659 int fd = (*out == '\0' ? -1 : atoi(out));
12660 union node *np;
12661
12662 np = stzalloc(sizeof(struct nfile));
12663 if (c == '>') {
12664 np->nfile.fd = 1;
12665 c = pgetc_eatbnl();
12666 if (c == '>')
12667 np->type = NAPPEND;
12668 else if (c == '|')
12669 np->type = NCLOBBER;
12670 else if (c == '&')
12671 np->type = NTOFD;
12672
12673 else {
12674 np->type = NTO;
12675 pungetc();
12676 }
12677 }
12678#if BASH_REDIR_OUTPUT
12679 else if (c == 0x100 + '>') {
12680 np->nfile.fd = 1;
12681 pgetc();
12682 np->type = NTO2;
12683 }
12684#endif
12685 else {
12686
12687 c = pgetc_eatbnl();
12688 switch (c) {
12689 case '<':
12690 if (sizeof(struct nfile) != sizeof(struct nhere)) {
12691 np = stzalloc(sizeof(struct nhere));
12692
12693 }
12694 np->type = NHERE;
12695 heredoc = stzalloc(sizeof(struct heredoc));
12696 heredoc->here = np;
12697 c = pgetc_eatbnl();
12698 if (c == '-') {
12699 heredoc->striptabs = 1;
12700 } else {
12701
12702 pungetc();
12703 }
12704 break;
12705
12706 case '&':
12707 np->type = NFROMFD;
12708 break;
12709
12710 case '>':
12711 np->type = NFROMTO;
12712 break;
12713
12714 default:
12715 np->type = NFROM;
12716 pungetc();
12717 break;
12718 }
12719 }
12720 if (fd >= 0)
12721 np->nfile.fd = fd;
12722 redirnode = np;
12723 goto parseredir_return;
12724}
12725
12726
12727
12728
12729
12730
12731
12732
12733#define is_special(c) \
12734 (((unsigned)(c) - 33 < 32) \
12735 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
12736parsesub: {
12737 unsigned char subtype;
12738 int typeloc;
12739
12740 c = pgetc_eatbnl();
12741 if ((checkkwd & CHKEOFMARK)
12742 || c > 255
12743 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
12744 ) {
12745#if BASH_DOLLAR_SQUOTE
12746 if (synstack->syntax != DQSYNTAX && c == '\'')
12747 bash_dollar_squote = 1;
12748 else
12749#endif
12750 USTPUTC('$', out);
12751 pungetc();
12752 } else if (c == '(') {
12753
12754 if (pgetc_eatbnl() == '(') {
12755#if ENABLE_FEATURE_SH_MATH
12756 PARSEARITH();
12757#else
12758 raise_error_syntax("support for $((arith)) is disabled");
12759#endif
12760 } else {
12761 pungetc();
12762 PARSEBACKQNEW();
12763 }
12764 } else {
12765
12766 smalluint newsyn = synstack->syntax;
12767
12768 USTPUTC(CTLVAR, out);
12769 typeloc = out - (char *)stackblock();
12770 STADJUST(1, out);
12771 subtype = VSNORMAL;
12772 if (c == '{') {
12773 c = pgetc_eatbnl();
12774 subtype = 0;
12775 }
12776 varname:
12777 if (is_name(c)) {
12778
12779 do {
12780 STPUTC(c, out);
12781 c = pgetc_eatbnl();
12782 } while (is_in_name(c));
12783 } else if (isdigit(c)) {
12784
12785 do {
12786 STPUTC(c, out);
12787 c = pgetc_eatbnl();
12788 } while ((subtype == 0 || subtype == VSLENGTH) && isdigit(c));
12789 } else if (c != '}') {
12790
12791 int cc = c;
12792
12793 c = pgetc_eatbnl();
12794 if (!subtype && cc == '#') {
12795 subtype = VSLENGTH;
12796 if (c == '_' || isalnum(c))
12797 goto varname;
12798 cc = c;
12799 c = pgetc_eatbnl();
12800 if (cc == '}' || c != '}') {
12801 pungetc();
12802 subtype = 0;
12803 c = cc;
12804 cc = '#';
12805 }
12806 }
12807
12808 if (!is_special(cc)) {
12809 if (subtype == VSLENGTH)
12810 subtype = 0;
12811 goto badsub;
12812 }
12813
12814 USTPUTC(cc, out);
12815 } else
12816 goto badsub;
12817
12818 if (subtype == 0) {
12819 static const char types[] ALIGN1 = "}-+?=";
12820
12821
12822 int cc = c;
12823
12824 switch (c) {
12825 case ':':
12826 c = pgetc_eatbnl();
12827#if BASH_SUBSTR
12828
12829
12830
12831
12832 if (!strchr(types, c)) {
12833 subtype = VSSUBSTR;
12834 pungetc();
12835 break;
12836 }
12837#endif
12838 subtype = VSNUL;
12839
12840 default: {
12841 const char *p = strchr(types, c);
12842 if (p == NULL)
12843 break;
12844 subtype |= p - types + VSNORMAL;
12845 break;
12846 }
12847 case '%':
12848 case '#':
12849 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12850 c = pgetc_eatbnl();
12851 if (c == cc)
12852 subtype++;
12853 else
12854 pungetc();
12855
12856 newsyn = BASESYNTAX;
12857 break;
12858#if BASH_PATTERN_SUBST
12859 case '/':
12860
12861
12862
12863
12864 subtype = VSREPLACE;
12865 newsyn = BASESYNTAX;
12866 c = pgetc_eatbnl();
12867 if (c != '/')
12868 goto badsub;
12869 subtype++;
12870 break;
12871#endif
12872 }
12873 } else {
12874 if (subtype == VSLENGTH && c != '}')
12875 subtype = 0;
12876 badsub:
12877 pungetc();
12878 }
12879
12880 if (newsyn == ARISYNTAX)
12881 newsyn = DQSYNTAX;
12882
12883 if ((newsyn != synstack->syntax || synstack->innerdq)
12884 && subtype != VSNORMAL
12885 ) {
12886 synstack_push(&synstack,
12887 synstack->prev ?: alloca(sizeof(*synstack)),
12888 newsyn);
12889
12890 synstack->varpushed = 1;
12891 synstack->dblquote = newsyn != BASESYNTAX;
12892 }
12893
12894 ((unsigned char *)stackblock())[typeloc] = subtype;
12895 if (subtype != VSNORMAL) {
12896 synstack->varnest++;
12897 if (synstack->dblquote)
12898 synstack->dqvarnest++;
12899 }
12900 STPUTC('=', out);
12901 }
12902 goto parsesub_return;
12903}
12904
12905
12906
12907
12908
12909
12910
12911parsebackq: {
12912 struct nodelist **nlpp;
12913 union node *n;
12914 char *str;
12915 size_t savelen;
12916 struct heredoc *saveheredoclist;
12917 smallint saveprompt = 0;
12918
12919 str = NULL;
12920 savelen = out - (char *)stackblock();
12921 if (savelen > 0) {
12922
12923
12924
12925
12926
12927
12928
12929
12930 str = alloca(savelen);
12931 memcpy(str, stackblock(), savelen);
12932 }
12933
12934 if (oldstyle) {
12935
12936
12937
12938
12939 char *pout;
12940 size_t psavelen;
12941 char *pstr;
12942
12943 STARTSTACKSTR(pout);
12944 for (;;) {
12945 int pc;
12946
12947 setprompt_if(needprompt, 2);
12948 pc = pgetc_eatbnl();
12949 switch (pc) {
12950 case '`':
12951 goto done;
12952
12953 case '\\':
12954 pc = pgetc();
12955 if (pc != '\\' && pc != '`' && pc != '$'
12956 && (!synstack->dblquote || pc != '"')
12957 ) {
12958 STPUTC('\\', pout);
12959 }
12960 if (pc <= 255 ) {
12961 break;
12962 }
12963
12964
12965 case PEOF:
12966 IF_ASH_ALIAS(case PEOA:)
12967 raise_error_syntax("EOF in backquote substitution");
12968
12969 case '\n':
12970 nlnoprompt();
12971 break;
12972
12973 default:
12974 break;
12975 }
12976 STPUTC(pc, pout);
12977 }
12978 done:
12979 STPUTC('\0', pout);
12980 psavelen = pout - (char *)stackblock();
12981 if (psavelen > 0) {
12982 pstr = grabstackstr(pout);
12983 setinputstring(pstr);
12984 }
12985 }
12986 nlpp = &bqlist;
12987 while (*nlpp)
12988 nlpp = &(*nlpp)->next;
12989 *nlpp = stzalloc(sizeof(**nlpp));
12990
12991
12992 saveheredoclist = heredoclist;
12993 heredoclist = NULL;
12994
12995 if (oldstyle) {
12996 saveprompt = doprompt;
12997 doprompt = 0;
12998 }
12999
13000 n = list(2);
13001
13002 if (oldstyle)
13003 doprompt = saveprompt;
13004 else {
13005 if (readtoken() != TRP)
13006 raise_error_unexpected_syntax(TRP);
13007 setinputstring(nullstr);
13008 }
13009
13010 parseheredoc();
13011 heredoclist = saveheredoclist;
13012
13013 (*nlpp)->n = n;
13014
13015 popfile();
13016
13017 if (oldstyle)
13018 tokpushback = 0;
13019 out = growstackto(savelen + 1);
13020 if (str) {
13021 memcpy(out, str, savelen);
13022 STADJUST(savelen, out);
13023 }
13024#if BASH_PROCESS_SUBST
13025 if (style == PSUB)
13026 USTPUTC(c == '<' ? CTLFROMPROC : CTLTOPROC, out);
13027 else
13028#endif
13029 USTPUTC(CTLBACKQ, out);
13030 if (oldstyle)
13031 goto parsebackq_oldreturn;
13032#if BASH_PROCESS_SUBST
13033 else if (style == PSUB)
13034 goto parsebackq_psreturn;
13035#endif
13036 goto parsebackq_newreturn;
13037}
13038
13039#if ENABLE_FEATURE_SH_MATH
13040
13041
13042
13043parsearith: {
13044
13045 synstack_push(&synstack,
13046 synstack->prev ?: alloca(sizeof(*synstack)),
13047 ARISYNTAX);
13048 synstack->dblquote = 1;
13049 USTPUTC(CTLARI, out);
13050 goto parsearith_return;
13051}
13052#endif
13053}
13054
13055
13056
13057
13058
13059
13060
13061
13062
13063
13064
13065
13066
13067
13068
13069
13070#define NEW_xxreadtoken
13071#ifdef NEW_xxreadtoken
13072
13073static const char xxreadtoken_chars[7] ALIGN1 = {
13074 '\n', '(', ')',
13075 '&', '|', ';',
13076 0
13077};
13078
13079#define xxreadtoken_singles 3
13080#define xxreadtoken_doubles 3
13081
13082static const char xxreadtoken_tokens[] ALIGN1 = {
13083 TNL, TLP, TRP,
13084 TBACKGND, TPIPE, TSEMI,
13085 TEOF,
13086 TAND, TOR, TENDCASE
13087};
13088
13089static int
13090xxreadtoken(void)
13091{
13092 int c;
13093
13094 if (tokpushback) {
13095 tokpushback = 0;
13096 return lasttoken;
13097 }
13098 setprompt_if(needprompt, 2);
13099 for (;;) {
13100 c = pgetc_eatbnl();
13101 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
13102 continue;
13103
13104 if (c == '#') {
13105 while ((c = pgetc()) != '\n' && c != PEOF)
13106 continue;
13107 pungetc();
13108 } else if (c == '\\') {
13109 break;
13110 } else {
13111 const char *p;
13112
13113 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
13114 if (c != PEOF) {
13115 if (c == '\n') {
13116 nlnoprompt();
13117 }
13118
13119 p = strchr(xxreadtoken_chars, c);
13120 if (p == NULL)
13121 break;
13122
13123 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
13124 int cc = pgetc_eatbnl();
13125 if (cc == c) {
13126 p += xxreadtoken_doubles + 1;
13127 } else {
13128 pungetc();
13129#if BASH_REDIR_OUTPUT
13130 if (c == '&' && cc == '>')
13131 break;
13132#endif
13133 }
13134 }
13135 }
13136 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
13137 return lasttoken;
13138 }
13139 }
13140
13141 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
13142}
13143#else
13144#define RETURN(token) return lasttoken = token
13145static int
13146xxreadtoken(void)
13147{
13148 int c;
13149
13150 if (tokpushback) {
13151 tokpushback = 0;
13152 return lasttoken;
13153 }
13154 setprompt_if(needprompt, 2);
13155 for (;;) {
13156 c = pgetc_eatbnl();
13157 switch (c) {
13158 case ' ': case '\t':
13159 IF_ASH_ALIAS(case PEOA:)
13160 continue;
13161 case '#':
13162 while ((c = pgetc()) != '\n' && c != PEOF)
13163 continue;
13164 pungetc();
13165 continue;
13166 case '\n':
13167 nlnoprompt();
13168 RETURN(TNL);
13169 case PEOF:
13170 RETURN(TEOF);
13171 case '&':
13172 if (pgetc_eatbnl() == '&')
13173 RETURN(TAND);
13174 pungetc();
13175 RETURN(TBACKGND);
13176 case '|':
13177 if (pgetc_eatbnl() == '|')
13178 RETURN(TOR);
13179 pungetc();
13180 RETURN(TPIPE);
13181 case ';':
13182 if (pgetc_eatbnl() == ';')
13183 RETURN(TENDCASE);
13184 pungetc();
13185 RETURN(TSEMI);
13186 case '(':
13187 RETURN(TLP);
13188 case ')':
13189 RETURN(TRP);
13190 }
13191 break;
13192 }
13193 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
13194#undef RETURN
13195}
13196#endif
13197
13198static int
13199readtoken(void)
13200{
13201 int t;
13202 int kwd = checkkwd;
13203#if DEBUG
13204 smallint alreadyseen = tokpushback;
13205#endif
13206
13207#if ENABLE_ASH_ALIAS
13208 top:
13209#endif
13210
13211 t = xxreadtoken();
13212
13213
13214
13215
13216 if (kwd & CHKNL) {
13217 while (t == TNL) {
13218 parseheredoc();
13219 t = xxreadtoken();
13220 }
13221 }
13222
13223 if (t != TWORD || quoteflag) {
13224 goto out;
13225 }
13226
13227
13228
13229
13230 if (kwd & CHKKWD) {
13231 const char *const *pp;
13232
13233 pp = findkwd(wordtext);
13234 if (pp) {
13235 lasttoken = t = pp - tokname_array;
13236 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
13237 goto out;
13238 }
13239 }
13240
13241 if (checkkwd & CHKALIAS) {
13242#if ENABLE_ASH_ALIAS
13243 struct alias *ap;
13244 ap = lookupalias(wordtext, 1);
13245 if (ap != NULL) {
13246 if (*ap->val) {
13247 pushstring(ap->val, ap);
13248 }
13249 goto top;
13250 }
13251#endif
13252 }
13253 out:
13254 checkkwd = 0;
13255#if DEBUG
13256 if (!alreadyseen)
13257 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13258 else
13259 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13260#endif
13261 return t;
13262}
13263
13264static int
13265peektoken(void)
13266{
13267 int t;
13268
13269 t = readtoken();
13270 tokpushback = 1;
13271 return t;
13272}
13273
13274
13275
13276
13277
13278static union node *
13279parsecmd(int interact)
13280{
13281 tokpushback = 0;
13282 checkkwd = 0;
13283 heredoclist = 0;
13284 doprompt = interact;
13285 setprompt_if(doprompt, doprompt);
13286 needprompt = 0;
13287 return list(1);
13288}
13289
13290
13291
13292
13293static void
13294parseheredoc(void)
13295{
13296 struct heredoc *here;
13297 union node *n;
13298
13299 here = heredoclist;
13300 heredoclist = NULL;
13301
13302 while (here) {
13303 tokpushback = 0;
13304 setprompt_if(needprompt, 2);
13305 if (here->here->type == NHERE)
13306 readtoken1(pgetc(), SQSYNTAX, here->eofmark, here->striptabs);
13307 else
13308 readtoken1(pgetc_eatbnl(), DQSYNTAX, here->eofmark, here->striptabs);
13309 n = stzalloc(sizeof(struct narg));
13310 n->narg.type = NARG;
13311
13312 n->narg.text = wordtext;
13313 n->narg.backquote = backquotelist;
13314 here->here->nhere.doc = n;
13315 here = here->next;
13316 }
13317}
13318
13319
13320static const char *
13321expandstr(const char *ps, int syntax_type)
13322{
13323 union node n;
13324 int saveprompt;
13325 struct parsefile *file_stop = g_parsefile;
13326 volatile int saveint;
13327 struct jmploc *volatile savehandler = exception_handler;
13328 struct jmploc jmploc;
13329 const char *volatile result;
13330 int err;
13331
13332
13333 setinputstring((char *)ps);
13334
13335 saveprompt = doprompt;
13336 doprompt = 0;
13337 result = ps;
13338
13339 SAVE_INT(saveint);
13340 err = setjmp(jmploc.loc);
13341 if (err)
13342 goto out;
13343
13344
13345
13346
13347
13348 exception_handler = &jmploc;
13349 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
13350
13351 n.narg.type = NARG;
13352 n.narg.next = NULL;
13353 n.narg.text = wordtext;
13354 n.narg.backquote = backquotelist;
13355
13356
13357
13358
13359 expandarg(&n, NULL, EXP_QUOTED);
13360 result = stackblock();
13361
13362out:
13363 exception_handler = savehandler;
13364 if (err && exception_type != EXERROR)
13365 longjmp(exception_handler->loc, 1);
13366 RESTORE_INT(saveint);
13367
13368 doprompt = saveprompt;
13369
13370 unwindfiles(file_stop);
13371
13372 return result;
13373}
13374
13375static inline int
13376parser_eof(void)
13377{
13378 return tokpushback && lasttoken == TEOF;
13379}
13380
13381
13382
13383
13384static int
13385evalstring(char *s, int flags)
13386{
13387 struct jmploc *volatile savehandler;
13388 struct jmploc jmploc;
13389 int ex;
13390
13391 union node *n;
13392 struct stackmark smark;
13393 int status;
13394
13395 s = sstrdup(s);
13396 setinputstring(s);
13397 setstackmark(&smark);
13398
13399 status = 0;
13400
13401
13402
13403
13404
13405
13406
13407 savehandler = exception_handler;
13408 ex = setjmp(jmploc.loc);
13409 if (ex)
13410 goto out;
13411 exception_handler = &jmploc;
13412
13413 while ((n = parsecmd(0)) != NODE_EOF) {
13414 int i;
13415
13416 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
13417 if (n)
13418 status = i;
13419 popstackmark(&smark);
13420 if (evalskip)
13421 break;
13422 }
13423 out:
13424 popstackmark(&smark);
13425 popfile();
13426 stunalloc(s);
13427
13428 exception_handler = savehandler;
13429 if (ex)
13430 longjmp(exception_handler->loc, ex);
13431
13432 return status;
13433}
13434
13435
13436
13437
13438static int FAST_FUNC
13439evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
13440{
13441 char *p;
13442 char *concat;
13443
13444 if (argv[1]) {
13445 p = argv[1];
13446 argv += 2;
13447 if (argv[0]) {
13448 STARTSTACKSTR(concat);
13449 for (;;) {
13450 concat = stack_putstr(p, concat);
13451 p = *argv++;
13452 if (p == NULL)
13453 break;
13454 STPUTC(' ', concat);
13455 }
13456 STPUTC('\0', concat);
13457 p = grabstackstr(concat);
13458 }
13459 return evalstring(p, flags & EV_TESTED);
13460 }
13461 return 0;
13462}
13463
13464
13465
13466
13467
13468
13469static int
13470cmdloop(int top)
13471{
13472 union node *n;
13473 struct stackmark smark;
13474 int inter;
13475 int status = 0;
13476 int numeof = 0;
13477
13478 TRACE(("cmdloop(%d) called\n", top));
13479 for (;;) {
13480 int skip;
13481
13482 setstackmark(&smark);
13483#if JOBS
13484 if (doing_jobctl)
13485 showjobs(SHOW_CHANGED|SHOW_STDERR);
13486#endif
13487 inter = 0;
13488 if (iflag && top) {
13489 inter++;
13490 chkmail();
13491 }
13492 n = parsecmd(inter);
13493#if DEBUG
13494 if (DEBUG > 2 && debug && (n != NODE_EOF))
13495 showtree(n);
13496#endif
13497 if (n == NODE_EOF) {
13498 if (!top || numeof >= 50)
13499 break;
13500 if (!stoppedjobs()) {
13501 if (!Iflag) {
13502 if (iflag) {
13503 newline_and_flush(stderr);
13504 }
13505 break;
13506 }
13507 out2str("\nUse \"exit\" to leave shell.\n");
13508 }
13509 numeof++;
13510 } else if (nflag == 0) {
13511 int i;
13512
13513
13514 job_warning >>= 1;
13515 numeof = 0;
13516 i = evaltree(n, 0);
13517 if (n)
13518 status = i;
13519 }
13520 popstackmark(&smark);
13521 skip = evalskip;
13522
13523 if (skip) {
13524 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
13525 break;
13526 }
13527 }
13528 return status;
13529}
13530
13531
13532
13533
13534
13535static char *
13536find_dot_file(char *basename)
13537{
13538 char *fullname;
13539 const char *path = pathval();
13540 struct stat statb;
13541 int len;
13542
13543
13544 if (strchr(basename, '/'))
13545 return basename;
13546
13547 while ((len = padvance(&path, basename)) >= 0) {
13548 fullname = stackblock();
13549 if ((!pathopt || *pathopt == 'f')
13550 && !stat(fullname, &statb) && S_ISREG(statb.st_mode)
13551 ) {
13552
13553 return stalloc(len);
13554 }
13555 }
13556
13557
13558#if ENABLE_ASH_BASH_SOURCE_CURDIR
13559 return basename;
13560#else
13561 ash_msg_and_raise_error("%s: not found", basename);
13562
13563#endif
13564}
13565
13566static int FAST_FUNC
13567dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
13568{
13569
13570 int status = 0;
13571 char *fullname;
13572 char **argv;
13573 char *args_need_save;
13574 volatile struct shparam saveparam;
13575
13576
13577
13578
13579
13580
13581 nextopt(nullstr);
13582 argv = argptr;
13583
13584 if (!argv[0]) {
13585
13586 return 2;
13587 }
13588
13589
13590
13591
13592 fullname = find_dot_file(argv[0]);
13593 argv++;
13594 args_need_save = argv[0];
13595 if (args_need_save) {
13596 int argc;
13597 saveparam = shellparam;
13598 shellparam.malloced = 0;
13599 argc = 1;
13600 while (argv[argc])
13601 argc++;
13602 shellparam.nparam = argc;
13603 shellparam.p = argv;
13604 };
13605
13606
13607
13608
13609 setinputfile(fullname, INPUT_PUSH_FILE);
13610 commandname = fullname;
13611 status = cmdloop(0);
13612 popfile();
13613
13614 if (args_need_save) {
13615 freeparam(&shellparam);
13616 shellparam = saveparam;
13617 };
13618
13619 return status;
13620}
13621
13622static int FAST_FUNC
13623exitcmd(int argc UNUSED_PARAM, char **argv)
13624{
13625 if (stoppedjobs())
13626 return 0;
13627
13628 if (argv[1])
13629 savestatus = number(argv[1]);
13630
13631 raise_exception(EXEXIT);
13632
13633}
13634
13635
13636
13637
13638static void
13639readcmdfile(char *name)
13640{
13641 setinputfile(name, INPUT_PUSH_FILE);
13642 cmdloop(0);
13643 popfile();
13644}
13645
13646
13647
13648
13649
13650
13651
13652
13653static void
13654find_command(char *name, struct cmdentry *entry, int act, const char *path)
13655{
13656 struct tblentry *cmdp;
13657 int idx;
13658 int prev;
13659 char *fullname;
13660 struct stat statb;
13661 int e;
13662 int updatetbl;
13663 struct builtincmd *bcmd;
13664 int len;
13665
13666
13667 if (strchr(name, '/') != NULL) {
13668 entry->u.index = -1;
13669 if (act & DO_ABS) {
13670 while (stat(name, &statb) < 0) {
13671#ifdef SYSV
13672 if (errno == EINTR)
13673 continue;
13674#endif
13675 entry->cmdtype = CMDUNKNOWN;
13676 return;
13677 }
13678 }
13679 entry->cmdtype = CMDNORMAL;
13680 return;
13681 }
13682
13683
13684
13685 updatetbl = (path == pathval());
13686 if (!updatetbl)
13687 act |= DO_ALTPATH;
13688
13689
13690 cmdp = cmdlookup(name, 0);
13691 if (cmdp != NULL) {
13692 int bit;
13693
13694 switch (cmdp->cmdtype) {
13695 default:
13696#if DEBUG
13697 abort();
13698#endif
13699 case CMDNORMAL:
13700 bit = DO_ALTPATH | DO_REGBLTIN;
13701 break;
13702 case CMDFUNCTION:
13703 bit = DO_NOFUNC;
13704 break;
13705 case CMDBUILTIN:
13706 bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
13707 break;
13708 }
13709 if (act & bit) {
13710 if (act & bit & DO_REGBLTIN)
13711 goto fail;
13712
13713 updatetbl = 0;
13714 cmdp = NULL;
13715 } else if (cmdp->rehash == 0)
13716
13717 goto success;
13718 }
13719
13720
13721 bcmd = find_builtin(name);
13722 if (bcmd) {
13723 if (IS_BUILTIN_REGULAR(bcmd))
13724 goto builtin_success;
13725 if (act & DO_ALTPATH)
13726 goto builtin_success;
13727 if (builtinloc <= 0)
13728 goto builtin_success;
13729 }
13730
13731 if (act & DO_REGBLTIN)
13732 goto fail;
13733
13734#if ENABLE_FEATURE_SH_STANDALONE
13735 {
13736 int applet_no = find_applet_by_name(name);
13737 if (applet_no >= 0) {
13738 entry->cmdtype = CMDNORMAL;
13739 entry->u.index = -2 - applet_no;
13740 return;
13741 }
13742 }
13743#endif
13744
13745
13746 prev = -1;
13747 if (cmdp && cmdp->rehash) {
13748 if (cmdp->cmdtype == CMDBUILTIN)
13749 prev = builtinloc;
13750 else
13751 prev = cmdp->param.index;
13752 }
13753
13754 e = ENOENT;
13755 idx = -1;
13756 loop:
13757 while ((len = padvance(&path, name)) >= 0) {
13758 const char *lpathopt = pathopt;
13759
13760 fullname = stackblock();
13761 idx++;
13762 if (lpathopt) {
13763 if (*lpathopt == 'b') {
13764 if (bcmd)
13765 goto builtin_success;
13766 continue;
13767 } else if (!(act & DO_NOFUNC)) {
13768
13769 } else {
13770
13771 continue;
13772 }
13773 }
13774
13775 if (fullname[0] == '/' && idx <= prev) {
13776 if (idx < prev)
13777 continue;
13778 TRACE(("searchexec \"%s\": no change\n", name));
13779 goto success;
13780 }
13781 while (stat(fullname, &statb) < 0) {
13782#ifdef SYSV
13783 if (errno == EINTR)
13784 continue;
13785#endif
13786 if (errno != ENOENT && errno != ENOTDIR)
13787 e = errno;
13788 goto loop;
13789 }
13790 e = EACCES;
13791 if (!S_ISREG(statb.st_mode))
13792 continue;
13793 if (lpathopt) {
13794 stalloc(len);
13795
13796
13797
13798 readcmdfile(fullname);
13799 cmdp = cmdlookup(name, 0);
13800 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13801 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13802 stunalloc(fullname);
13803 goto success;
13804 }
13805 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13806 if (!updatetbl) {
13807 entry->cmdtype = CMDNORMAL;
13808 entry->u.index = idx;
13809 return;
13810 }
13811 INT_OFF;
13812 cmdp = cmdlookup(name, 1);
13813 cmdp->cmdtype = CMDNORMAL;
13814 cmdp->param.index = idx;
13815 INT_ON;
13816 goto success;
13817 }
13818
13819
13820 if (cmdp && updatetbl)
13821 delete_cmd_entry();
13822 if (act & DO_ERR) {
13823#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13824 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13825 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13826 char *argv[3];
13827 argv[0] = (char*) "command_not_found_handle";
13828 argv[1] = name;
13829 argv[2] = NULL;
13830 evalfun(hookp->param.func, 2, argv, 0);
13831 entry->cmdtype = CMDUNKNOWN;
13832 return;
13833 }
13834#endif
13835 ash_msg("%s: %s", name, errmsg(e, "not found"));
13836 }
13837 fail:
13838 entry->cmdtype = CMDUNKNOWN;
13839 return;
13840
13841 builtin_success:
13842 if (!updatetbl) {
13843 entry->cmdtype = CMDBUILTIN;
13844 entry->u.cmd = bcmd;
13845 return;
13846 }
13847 INT_OFF;
13848 cmdp = cmdlookup(name, 1);
13849 cmdp->cmdtype = CMDBUILTIN;
13850 cmdp->param.cmd = bcmd;
13851 INT_ON;
13852 success:
13853 cmdp->rehash = 0;
13854 entry->cmdtype = cmdp->cmdtype;
13855 entry->u = cmdp->param;
13856}
13857
13858
13859
13860
13861
13862static int FAST_FUNC
13863trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13864{
13865 char *action;
13866 char **ap;
13867 int signo, exitcode;
13868
13869 nextopt(nullstr);
13870 ap = argptr;
13871 if (!*ap) {
13872 for (signo = 0; signo < NSIG; signo++) {
13873 char *tr = trap_ptr[signo];
13874 if (tr) {
13875
13876
13877
13878
13879 out1fmt("trap -- %s %s\n",
13880 single_quote(tr),
13881 get_signame(signo));
13882
13883
13884
13885
13886 }
13887 }
13888
13889
13890
13891
13892
13893
13894 return 0;
13895 }
13896
13897
13898
13899
13900
13901 action = NULL;
13902 if (ap[1] && !is_number(ap[0]))
13903 action = *ap++;
13904
13905 exitcode = 0;
13906 while (*ap) {
13907 signo = get_signum(*ap);
13908 if (signo < 0) {
13909
13910 ash_msg("%s: invalid signal specification", *ap);
13911 exitcode = 1;
13912 goto next;
13913 }
13914 INT_OFF;
13915 if (action) {
13916 if (LONE_DASH(action))
13917 action = NULL;
13918 else {
13919 if (action[0])
13920 may_have_traps = 1;
13921 action = ckstrdup(action);
13922 }
13923 }
13924 free(trap[signo]);
13925 trap[signo] = action;
13926 if (signo != 0)
13927 setsignal(signo);
13928 INT_ON;
13929 next:
13930 ap++;
13931 }
13932 return exitcode;
13933}
13934
13935
13936
13937
13938#if ENABLE_ASH_HELP
13939static int FAST_FUNC
13940helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13941{
13942 unsigned col;
13943 unsigned i;
13944
13945 out1fmt(
13946 "Built-in commands:\n"
13947 "------------------\n");
13948 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
13949 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
13950 builtintab[i].name + 1);
13951 if (col > 60) {
13952 out1fmt("\n");
13953 col = 0;
13954 }
13955 }
13956# if ENABLE_FEATURE_SH_STANDALONE
13957 {
13958 const char *a = applet_names;
13959 while (*a) {
13960 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13961 if (col > 60) {
13962 out1fmt("\n");
13963 col = 0;
13964 }
13965 while (*a++ != '\0')
13966 continue;
13967 }
13968 }
13969# endif
13970 newline_and_flush(stdout);
13971 return EXIT_SUCCESS;
13972}
13973#endif
13974
13975#if MAX_HISTORY
13976static int FAST_FUNC
13977historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13978{
13979 show_history(line_input_state);
13980 return EXIT_SUCCESS;
13981}
13982#endif
13983
13984
13985
13986
13987static int FAST_FUNC
13988exportcmd(int argc UNUSED_PARAM, char **argv)
13989{
13990 struct var *vp;
13991 char *name;
13992 const char *p;
13993 char **aptr;
13994 char opt;
13995 int flag;
13996 int flag_off;
13997
13998
13999
14000
14001 flag_off = 0;
14002 while ((opt = nextopt("np")) != '\0') {
14003 if (opt == 'n')
14004 flag_off = VEXPORT;
14005 }
14006 flag = VEXPORT;
14007 if (argv[0][0] == 'r') {
14008 flag = VREADONLY;
14009 flag_off = 0;
14010 }
14011 flag_off = ~flag_off;
14012
14013
14014 {
14015 aptr = argptr;
14016 name = *aptr;
14017 if (name) {
14018 do {
14019 p = strchr(name, '=');
14020 if (p != NULL) {
14021 p++;
14022 } else {
14023 vp = *findvar(hashvar(name), name);
14024 if (vp) {
14025 vp->flags = ((vp->flags | flag) & flag_off);
14026 continue;
14027 }
14028 }
14029 setvar(name, p, (flag & flag_off));
14030 } while ((name = *++aptr) != NULL);
14031 return 0;
14032 }
14033 }
14034
14035
14036
14037
14038 showvars(argv[0], flag, 0);
14039 return 0;
14040}
14041
14042
14043
14044
14045static void
14046unsetfunc(const char *name)
14047{
14048 struct tblentry *cmdp;
14049
14050 cmdp = cmdlookup(name, 0);
14051 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
14052 delete_cmd_entry();
14053}
14054
14055
14056
14057
14058
14059
14060static int FAST_FUNC
14061unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14062{
14063 char **ap;
14064 int i;
14065 int flag = 0;
14066
14067 while ((i = nextopt("vf")) != 0) {
14068 flag = i;
14069 }
14070
14071 for (ap = argptr; *ap; ap++) {
14072 if (flag != 'f') {
14073 unsetvar(*ap);
14074 continue;
14075 }
14076 if (flag != 'v')
14077 unsetfunc(*ap);
14078 }
14079 return 0;
14080}
14081
14082static const unsigned char timescmd_str[] ALIGN1 = {
14083 ' ', offsetof(struct tms, tms_utime),
14084 '\n', offsetof(struct tms, tms_stime),
14085 ' ', offsetof(struct tms, tms_cutime),
14086 '\n', offsetof(struct tms, tms_cstime),
14087 0
14088};
14089static int FAST_FUNC
14090timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14091{
14092 unsigned clk_tck;
14093 const unsigned char *p;
14094 struct tms buf;
14095
14096 clk_tck = bb_clk_tck();
14097
14098 times(&buf);
14099 p = timescmd_str;
14100 do {
14101 unsigned sec, frac;
14102 unsigned long t;
14103 t = *(clock_t *)(((char *) &buf) + p[1]);
14104 sec = t / clk_tck;
14105 frac = t % clk_tck;
14106 out1fmt("%um%u.%03us%c",
14107 sec / 60, sec % 60,
14108 (frac * 1000) / clk_tck,
14109 p[0]);
14110 p += 2;
14111 } while (*p);
14112
14113 return 0;
14114}
14115
14116#if ENABLE_FEATURE_SH_MATH
14117
14118
14119
14120
14121
14122
14123static int FAST_FUNC
14124letcmd(int argc UNUSED_PARAM, char **argv)
14125{
14126 arith_t i;
14127
14128 argv++;
14129 if (!*argv)
14130 ash_msg_and_raise_error("expression expected");
14131 do {
14132 i = ash_arith(*argv);
14133 } while (*++argv);
14134
14135 return !i;
14136}
14137#endif
14138
14139
14140
14141
14142
14143
14144
14145
14146
14147
14148
14149
14150
14151
14152
14153static int FAST_FUNC
14154readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14155{
14156 struct builtin_read_params params;
14157 const char *r;
14158 int i;
14159
14160 memset(¶ms, 0, sizeof(params));
14161
14162 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
14163 switch (i) {
14164 case 'p':
14165 params.opt_p = optionarg;
14166 break;
14167 case 'n':
14168 params.opt_n = optionarg;
14169 break;
14170 case 's':
14171 params.read_flags |= BUILTIN_READ_SILENT;
14172 break;
14173 case 't':
14174 params.opt_t = optionarg;
14175 break;
14176 case 'r':
14177 params.read_flags |= BUILTIN_READ_RAW;
14178 break;
14179 case 'u':
14180 params.opt_u = optionarg;
14181 break;
14182#if BASH_READ_D
14183 case 'd':
14184 params.opt_d = optionarg;
14185 break;
14186#endif
14187 default:
14188 break;
14189 }
14190 }
14191
14192 if (!ENABLE_ASH_BASH_COMPAT && !argptr) {
14193 bb_simple_error_msg("read: need variable name");
14194 return 1;
14195 }
14196 params.argv = argptr;
14197 params.setvar = setvar0;
14198 params.ifs = bltinlookup("IFS");
14199
14200
14201
14202
14203 again:
14204 INT_OFF;
14205 r = shell_builtin_read(¶ms);
14206 INT_ON;
14207
14208 if ((uintptr_t)r == 1 && errno == EINTR) {
14209
14210
14211
14212 if (pending_sig == 0)
14213 goto again;
14214 }
14215
14216 if ((uintptr_t)r > 1)
14217 ash_msg_and_raise_error(r);
14218
14219 return (uintptr_t)r;
14220}
14221
14222static int FAST_FUNC
14223umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14224{
14225 static const char permuser[3] ALIGN1 = "ogu";
14226
14227 mode_t mask;
14228 int symbolic_mode = 0;
14229
14230 while (nextopt("S") != '\0') {
14231 symbolic_mode = 1;
14232 }
14233
14234 INT_OFF;
14235 mask = umask(0);
14236 umask(mask);
14237 INT_ON;
14238
14239 if (*argptr == NULL) {
14240 if (symbolic_mode) {
14241 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
14242 char *p = buf;
14243 int i;
14244
14245 i = 2;
14246 for (;;) {
14247 *p++ = ',';
14248 *p++ = permuser[i];
14249 *p++ = '=';
14250
14251 if (!(mask & 0400)) *p++ = 'r';
14252 if (!(mask & 0200)) *p++ = 'w';
14253 if (!(mask & 0100)) *p++ = 'x';
14254 mask <<= 3;
14255 if (--i < 0)
14256 break;
14257 }
14258 *p = '\0';
14259 puts(buf + 1);
14260 } else {
14261 out1fmt("%04o\n", mask);
14262 }
14263 } else {
14264 char *modestr = *argptr;
14265
14266
14267 if (!isdigit(modestr[0]))
14268 mask ^= 0777;
14269 mask = bb_parse_mode(modestr, mask);
14270 if ((unsigned)mask > 0777) {
14271 ash_msg_and_raise_error("illegal mode: %s", modestr);
14272 }
14273 if (!isdigit(modestr[0]))
14274 mask ^= 0777;
14275 umask(mask);
14276 }
14277 return 0;
14278}
14279
14280static int FAST_FUNC
14281ulimitcmd(int argc UNUSED_PARAM, char **argv)
14282{
14283 return shell_builtin_ulimit(argv);
14284}
14285
14286
14287
14288
14289
14290
14291
14292
14293static void
14294exitreset(void)
14295{
14296
14297 if (savestatus >= 0) {
14298 if (exception_type == EXEXIT || evalskip == SKIPFUNCDEF)
14299 exitstatus = savestatus;
14300 savestatus = -1;
14301 }
14302 evalskip = 0;
14303 loopnest = 0;
14304
14305
14306 ifsfree();
14307
14308
14309 unwindredir(NULL);
14310}
14311
14312
14313
14314
14315
14316
14317static void
14318reset(void)
14319{
14320
14321 g_parsefile->left_in_buffer = 0;
14322 g_parsefile->left_in_line = 0;
14323 g_parsefile->unget = 0;
14324 popallfiles();
14325
14326
14327 unwindlocalvars(NULL);
14328}
14329
14330
14331
14332
14333static void
14334exitshell(void)
14335{
14336 struct jmploc loc;
14337 char *p;
14338
14339#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
14340 save_history(line_input_state);
14341#endif
14342 savestatus = exitstatus;
14343 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
14344 if (setjmp(loc.loc))
14345 goto out;
14346 exception_handler = &loc;
14347 p = trap[0];
14348 if (p) {
14349 trap[0] = NULL;
14350 evalskip = 0;
14351 evalstring(p, 0);
14352 evalskip = SKIPFUNCDEF;
14353
14354 }
14355 out:
14356 exitreset();
14357
14358
14359
14360 setjobctl(0);
14361 flush_stdout_stderr();
14362 _exit(exitstatus);
14363
14364}
14365
14366
14367static NOINLINE void
14368init(void)
14369{
14370
14371 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
14372 basepf.linno = 1;
14373
14374 sigmode[SIGCHLD - 1] = S_DFL;
14375 setsignal(SIGCHLD);
14376
14377 {
14378 char **envp;
14379 const char *p;
14380
14381 initvar();
14382 for (envp = environ; envp && *envp; envp++) {
14383
14384
14385
14386
14387
14388
14389
14390
14391
14392
14393
14394 if (strchr(*envp, '=')) {
14395 setvareq(*envp, VEXPORT|VTEXTFIXED);
14396 }
14397 }
14398
14399 setvareq((char*)defifsvar, VTEXTFIXED);
14400 setvareq((char*)defoptindvar, VTEXTFIXED);
14401
14402 setvar0("PPID", utoa(getppid()));
14403#if BASH_SHLVL_VAR
14404 p = lookupvar("SHLVL");
14405 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
14406#endif
14407#if BASH_HOSTNAME_VAR
14408 if (!lookupvar("HOSTNAME")) {
14409 struct utsname uts;
14410 uname(&uts);
14411 setvar0("HOSTNAME", uts.nodename);
14412 }
14413#endif
14414 p = lookupvar("PWD");
14415 if (p) {
14416 struct stat st1, st2;
14417 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
14418 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14419 ) {
14420 p = NULL;
14421 }
14422 }
14423 setpwd(p, 0);
14424 }
14425}
14426
14427
14428
14429
14430
14431
14432
14433
14434
14435
14436
14437static int
14438procargs(char **argv)
14439{
14440 int i;
14441 const char *xminusc;
14442 char **xargv;
14443 int login_sh;
14444
14445 xargv = argv;
14446 login_sh = xargv[0] && xargv[0][0] == '-';
14447#if NUM_SCRIPTS > 0
14448 if (minusc)
14449 goto setarg0;
14450#endif
14451 arg0 = xargv[0];
14452
14453 xargv++;
14454 argptr = xargv;
14455 for (i = 0; i < NOPTS; i++)
14456 optlist[i] = 2;
14457 if (options(&login_sh)) {
14458
14459 raise_exception(EXERROR);
14460 }
14461 xargv = argptr;
14462 xminusc = minusc;
14463 if (*xargv == NULL) {
14464 if (xminusc)
14465 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14466 sflag = 1;
14467 }
14468 if (iflag == 2
14469 && sflag == 1
14470 && !minusc
14471 && isatty(0) && isatty(1)
14472 ) {
14473 iflag = 1;
14474 }
14475 if (mflag == 2)
14476 mflag = iflag;
14477
14478 for (i = 0; i < NOPTS; i++)
14479 optlist[i] &= 1;
14480#if DEBUG == 2
14481 debug = 1;
14482#endif
14483
14484 if (xminusc) {
14485 minusc = *xargv++;
14486 if (*xargv)
14487 goto setarg0;
14488 } else if (!sflag) {
14489 setinputfile(*xargv, 0);
14490 setarg0:
14491 arg0 = *xargv++;
14492 commandname = arg0;
14493 }
14494
14495 shellparam.p = xargv;
14496#if ENABLE_ASH_GETOPTS
14497 shellparam.optind = 1;
14498 shellparam.optoff = -1;
14499#endif
14500
14501 while (*xargv) {
14502 shellparam.nparam++;
14503 xargv++;
14504 }
14505
14506
14507
14508
14509
14510
14511
14512
14513 if (iflag)
14514 signal(SIGHUP, SIG_DFL);
14515
14516 optschanged();
14517
14518 return login_sh;
14519}
14520
14521
14522
14523
14524static void
14525read_profile(const char *name)
14526{
14527 name = expandstr(name, DQSYNTAX);
14528 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14529 return;
14530 cmdloop(0);
14531 popfile();
14532}
14533
14534#if PROFILE
14535static short profile_buf[16384];
14536extern int etext();
14537#endif
14538
14539
14540
14541
14542
14543
14544
14545
14546int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14547#if NUM_SCRIPTS > 0
14548int ash_main(int argc, char **argv)
14549#else
14550int ash_main(int argc UNUSED_PARAM, char **argv)
14551#endif
14552
14553{
14554 volatile smallint state;
14555 struct jmploc jmploc;
14556 struct stackmark smark;
14557 int login_sh;
14558
14559
14560 INIT_G_misc();
14561 INIT_G_memstack();
14562 INIT_G_var();
14563#if ENABLE_ASH_ALIAS
14564 INIT_G_alias();
14565#endif
14566 INIT_G_cmdtable();
14567
14568#if PROFILE
14569 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14570#endif
14571
14572 state = 0;
14573 if (setjmp(jmploc.loc)) {
14574 smallint e;
14575 smallint s;
14576
14577 exitreset();
14578
14579 e = exception_type;
14580 s = state;
14581 if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
14582 exitshell();
14583 }
14584
14585 reset();
14586
14587 if (e == EXINT) {
14588 newline_and_flush(stderr);
14589 }
14590
14591 popstackmark(&smark);
14592 FORCE_INT_ON;
14593 if (s == 1)
14594 goto state1;
14595 if (s == 2)
14596 goto state2;
14597 if (s == 3)
14598 goto state3;
14599 goto state4;
14600 }
14601 exception_handler = &jmploc;
14602 rootpid = getpid();
14603
14604 init();
14605 setstackmark(&smark);
14606
14607#if NUM_SCRIPTS > 0
14608 if (argc < 0)
14609
14610 minusc = get_script_content(-argc - 1);
14611#endif
14612 login_sh = procargs(argv);
14613#if DEBUG
14614 TRACE(("Shell args: "));
14615 trace_puts_args(argv);
14616#endif
14617
14618 if (login_sh) {
14619 const char *hp;
14620
14621 state = 1;
14622 read_profile("/etc/profile");
14623 state1:
14624 state = 2;
14625 hp = lookupvar("HOME");
14626 if (hp)
14627 read_profile("$HOME/.profile");
14628 }
14629 state2:
14630 state = 3;
14631 if (
14632#ifndef linux
14633 getuid() == geteuid() && getgid() == getegid() &&
14634#endif
14635 iflag
14636 ) {
14637 const char *shinit = lookupvar("ENV");
14638 if (shinit != NULL && *shinit != '\0')
14639 read_profile(shinit);
14640 }
14641 popstackmark(&smark);
14642 state3:
14643 state = 4;
14644 if (minusc) {
14645
14646
14647
14648
14649
14650
14651
14652
14653
14654
14655
14656
14657
14658
14659 evalstring(minusc, EV_EXIT);
14660 }
14661
14662 if (sflag || minusc == NULL) {
14663#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
14664 if (line_input_state) {
14665 const char *hp = lookupvar("HISTFILE");
14666 if (!hp) {
14667 hp = lookupvar("HOME");
14668 if (hp) {
14669 INT_OFF;
14670 hp = concat_path_file(hp, ".ash_history");
14671 setvar0("HISTFILE", hp);
14672 free((char*)hp);
14673 INT_ON;
14674 hp = lookupvar("HISTFILE");
14675 }
14676 }
14677 if (hp)
14678 line_input_state->hist_file = xstrdup(hp);
14679# if ENABLE_FEATURE_SH_HISTFILESIZE
14680 hp = lookupvar("HISTFILESIZE");
14681 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14682# endif
14683 }
14684#endif
14685 state4:
14686 cmdloop(1);
14687 }
14688#if PROFILE
14689 monitor(0);
14690#endif
14691#ifdef GPROF
14692 {
14693 extern void _mcleanup(void);
14694 _mcleanup();
14695 }
14696#endif
14697 TRACE(("End of main reached\n"));
14698 exitshell();
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
14731
14732
14733
14734