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