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