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