1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172#define DEBUG 0
173
174#define DEBUG_TIME 0
175#define DEBUG_PID 1
176#define DEBUG_SIG 1
177#define DEBUG_INTONOFF 0
178
179#define PROFILE 0
180
181#define JOBS ENABLE_ASH_JOB_CONTROL
182
183#include <fnmatch.h>
184#include <sys/times.h>
185#include <sys/utsname.h>
186#include "busybox.h"
187#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
188# include "embedded_scripts.h"
189#else
190# define NUM_SCRIPTS 0
191#endif
192
193
194
195
196#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
197#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
198
199#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
200#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
201
202#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
203#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
204#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
205#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
206#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
207#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
223#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
224#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
225#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
226#define BASH_EPOCH_VARS ENABLE_ASH_BASH_COMPAT
227#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
228#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
229#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
230#define IF_BASH_READ_D IF_ASH_BASH_COMPAT
231#define BASH_WAIT_N ENABLE_ASH_BASH_COMPAT
232
233#if HAVE_DEV_FD
234# define BASH_PROCESS_SUBST ENABLE_ASH_BASH_COMPAT
235# define IF_BASH_PROCESS_SUBST IF_ASH_BASH_COMPAT
236#else
237# define BASH_PROCESS_SUBST 0
238# define IF_BASH_PROCESS_SUBST(...)
239#endif
240
241#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
242
243# undef ENABLE_ASH_INTERNAL_GLOB
244# define ENABLE_ASH_INTERNAL_GLOB 1
245#endif
246
247#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
248# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
249# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
250# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
251# error glob() should unbackslash them and match. uClibc does not unbackslash,
252# error fails to match dirname, subsequently not expanding <pattern> in it.
253
254
255
256#endif
257
258#if !ENABLE_ASH_INTERNAL_GLOB
259# include <glob.h>
260#endif
261
262#include "unicode.h"
263#include "shell_common.h"
264#if ENABLE_FEATURE_SH_MATH
265# include "math.h"
266#else
267typedef long arith_t;
268# define ARITH_FMT "%ld"
269#endif
270#if ENABLE_ASH_RANDOM_SUPPORT
271# include "random.h"
272#else
273# define CLEAR_RANDOM_T(rnd) ((void)0)
274#endif
275
276#include "NUM_APPLETS.h"
277#if NUM_APPLETS == 1
278
279# undef CONFIG_FEATURE_SH_STANDALONE
280# undef ENABLE_FEATURE_SH_STANDALONE
281# undef IF_FEATURE_SH_STANDALONE
282# undef IF_NOT_FEATURE_SH_STANDALONE
283# define ENABLE_FEATURE_SH_STANDALONE 0
284# define IF_FEATURE_SH_STANDALONE(...)
285# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
286#endif
287
288#ifndef F_DUPFD_CLOEXEC
289# define F_DUPFD_CLOEXEC F_DUPFD
290#endif
291#ifndef O_CLOEXEC
292# define O_CLOEXEC 0
293#endif
294#ifndef PIPE_BUF
295# define PIPE_BUF 4096
296#endif
297
298#ifndef unlikely
299# define unlikely(cond) (cond)
300#endif
301
302#if !BB_MMU
303# error "Do not even bother, ash will not run on NOMMU machine"
304#endif
305
306
307
308#define VTABSIZE 39
309#define ATABSIZE 39
310#define CMDTABLESIZE 31
311
312
313
314
315
316static const char *const optletters_optnames[] = {
317 "e" "errexit",
318 "f" "noglob",
319
320
321 "I" "ignoreeof",
322
323
324
325
326
327
328 "i" "",
329
330 "m" "monitor",
331 "n" "noexec",
332
333 "s" "",
334 "c" "",
335 "x" "xtrace",
336 "v" "verbose",
337 "C" "noclobber",
338 "a" "allexport",
339 "b" "notify",
340 "u" "nounset",
341 "E" "errtrace",
342 "\0" "vi"
343#if BASH_PIPEFAIL
344 ,"\0" "pipefail"
345#endif
346#if DEBUG
347 ,"\0" "nolog"
348 ,"\0" "debug"
349#endif
350};
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366#define optletters(n) optletters_optnames[n][0]
367#define optnames(n) (optletters_optnames[n] + 1)
368
369enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
370
371
372
373
374#define msg_illnum "Illegal number: %s"
375
376
377
378
379
380
381
382
383
384
385struct jmploc {
386 jmp_buf loc;
387};
388
389struct globals_misc {
390 uint8_t exitstatus;
391 uint8_t back_exitstatus;
392 smallint job_warning;
393 smallint inps4;
394 int savestatus;
395 int rootpid;
396
397 int shlvl;
398#define rootshell (!shlvl)
399 int errlinno;
400
401 char *minusc;
402
403 char *curdir;
404 char *physdir;
405
406 char *arg0;
407
408 struct jmploc *exception_handler;
409
410 volatile int suppress_int;
411 volatile smallint pending_int;
412 volatile smallint got_sigchld;
413 volatile smallint pending_sig;
414 smallint exception_type;
415#define EXINT 0
416#define EXERROR 1
417#define EXEND 3
418#define EXEXIT 4
419
420 char nullstr[1];
421
422 char optlist[NOPTS];
423#define eflag optlist[0]
424#define fflag optlist[1]
425#define Iflag optlist[2]
426#define iflag optlist[3]
427#define mflag optlist[4]
428#define nflag optlist[5]
429#define sflag optlist[6]
430#define cflag optlist[7]
431#define xflag optlist[8]
432#define vflag optlist[9]
433#define Cflag optlist[10]
434#define aflag optlist[11]
435#define bflag optlist[12]
436#define uflag optlist[13]
437#define Eflag optlist[14]
438#define viflag optlist[15]
439#if BASH_PIPEFAIL
440# define pipefail optlist[16]
441#else
442# define pipefail 0
443#endif
444#if DEBUG
445# define nolog optlist[16 + BASH_PIPEFAIL]
446# define debug optlist[17 + BASH_PIPEFAIL]
447#endif
448
449
450
451
452
453
454
455 char sigmode[NSIG - 1];
456#define S_DFL 1
457#define S_CATCH 2
458#define S_IGN 3
459#define S_HARD_IGN 4
460
461
462 uint8_t gotsig[NSIG - 1];
463 uint8_t may_have_traps;
464 char *trap[NSIG + 1];
465
466#define NTRAP_ERR NSIG
467#define NTRAP_LAST NSIG
468
469 char **trap_ptr;
470
471
472#if ENABLE_ASH_RANDOM_SUPPORT
473 random_t random_gen;
474#endif
475 pid_t backgndpid;
476};
477extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
478#define G_misc (*ash_ptr_to_globals_misc)
479#define exitstatus (G_misc.exitstatus )
480#define back_exitstatus (G_misc.back_exitstatus )
481#define job_warning (G_misc.job_warning)
482#define inps4 (G_misc.inps4 )
483#define savestatus (G_misc.savestatus )
484#define rootpid (G_misc.rootpid )
485#define shlvl (G_misc.shlvl )
486#define errlinno (G_misc.errlinno )
487#define minusc (G_misc.minusc )
488#define curdir (G_misc.curdir )
489#define physdir (G_misc.physdir )
490#define arg0 (G_misc.arg0 )
491#define exception_handler (G_misc.exception_handler)
492#define exception_type (G_misc.exception_type )
493#define suppress_int (G_misc.suppress_int )
494#define pending_int (G_misc.pending_int )
495#define got_sigchld (G_misc.got_sigchld )
496#define pending_sig (G_misc.pending_sig )
497#define nullstr (G_misc.nullstr )
498#define optlist (G_misc.optlist )
499#define sigmode (G_misc.sigmode )
500#define gotsig (G_misc.gotsig )
501#define may_have_traps (G_misc.may_have_traps )
502#define trap (G_misc.trap )
503#define trap_ptr (G_misc.trap_ptr )
504#define random_gen (G_misc.random_gen )
505#define backgndpid (G_misc.backgndpid )
506#define INIT_G_misc() do { \
507 XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \
508 savestatus = -1; \
509 curdir = nullstr; \
510 physdir = nullstr; \
511 trap_ptr = trap; \
512} while (0)
513
514
515
516#if DEBUG
517static void trace_printf(const char *fmt, ...);
518static void trace_vprintf(const char *fmt, va_list va);
519# define TRACE(param) trace_printf param
520# define TRACEV(param) trace_vprintf param
521# define close(fd) do { \
522 int dfd = (fd); \
523 if (close(dfd) < 0) \
524 bb_error_msg("bug on %d: closing %d(0x%x)", \
525 __LINE__, dfd, dfd); \
526} while (0)
527#else
528# define TRACE(param)
529# define TRACEV(param)
530#endif
531
532
533
534#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
535#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
536
537static int
538isdigit_str9(const char *str)
539{
540 int maxlen = 9 + 1;
541 while (--maxlen && isdigit(*str))
542 str++;
543 return (*str == '\0');
544}
545
546static const char *
547var_end(const char *var)
548{
549 while (*var)
550 if (*var++ == '=')
551 break;
552 return var;
553}
554
555
556
557
558
559
560
561struct strlist {
562 struct strlist *next;
563 char *text;
564};
565
566struct alias;
567
568struct strpush {
569 struct strpush *prev;
570 char *prev_string;
571 int prev_left_in_line;
572#if ENABLE_ASH_ALIAS
573 struct alias *ap;
574#endif
575 char *string;
576
577
578 struct strpush *spfree;
579
580
581 int lastc[2];
582
583
584 int unget;
585};
586
587
588
589
590
591struct parsefile {
592 struct parsefile *prev;
593 int linno;
594 int pf_fd;
595 int left_in_line;
596 int left_in_buffer;
597 char *next_to_pgetc;
598 char *buf;
599 struct strpush *strpush;
600 struct strpush basestrpush;
601
602
603 struct strpush *spfree;
604
605
606 int lastc[2];
607
608
609 int unget;
610};
611
612static struct parsefile basepf;
613static struct parsefile *g_parsefile = &basepf;
614static char *commandname;
615
616
617
618
619static void exitshell(void) NORETURN;
620
621
622
623
624
625
626
627#if DEBUG_INTONOFF
628# define INT_OFF do { \
629 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
630 suppress_int++; \
631 barrier(); \
632} while (0)
633#else
634# define INT_OFF do { \
635 suppress_int++; \
636 barrier(); \
637} while (0)
638#endif
639
640
641
642
643
644
645static void raise_exception(int) NORETURN;
646static void
647raise_exception(int e)
648{
649#if DEBUG
650 if (exception_handler == NULL)
651 abort();
652#endif
653 INT_OFF;
654 exception_type = e;
655 longjmp(exception_handler->loc, 1);
656}
657#if DEBUG
658#define raise_exception(e) do { \
659 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
660 raise_exception(e); \
661} while (0)
662#endif
663
664
665
666
667
668
669
670
671static void raise_interrupt(void) NORETURN;
672static void
673raise_interrupt(void)
674{
675 pending_int = 0;
676
677
678 sigprocmask_allsigs(SIG_UNBLOCK);
679
680
681 if (!(rootshell && iflag)) {
682
683 signal(SIGINT, SIG_DFL);
684 raise(SIGINT);
685 }
686
687 exitstatus = SIGINT + 128;
688 raise_exception(EXINT);
689
690}
691#if DEBUG
692#define raise_interrupt() do { \
693 TRACE(("raising interrupt on line %d\n", __LINE__)); \
694 raise_interrupt(); \
695} while (0)
696#endif
697
698static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
699int_on(void)
700{
701 barrier();
702 if (--suppress_int == 0 && pending_int) {
703 raise_interrupt();
704 }
705}
706#if DEBUG_INTONOFF
707# define INT_ON do { \
708 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
709 int_on(); \
710} while (0)
711#else
712# define INT_ON int_on()
713#endif
714static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
715force_int_on(void)
716{
717 barrier();
718 suppress_int = 0;
719 if (pending_int)
720 raise_interrupt();
721}
722#define FORCE_INT_ON force_int_on()
723
724#define SAVE_INT(v) ((v) = suppress_int)
725
726#define RESTORE_INT(v) do { \
727 barrier(); \
728 suppress_int = (v); \
729 if (suppress_int == 0 && pending_int) \
730 raise_interrupt(); \
731} while (0)
732
733
734
735
736static void
737outstr(const char *p, FILE *file)
738{
739 INT_OFF;
740 fputs(p, file);
741 INT_ON;
742}
743
744static void
745flush_stdout_stderr(void)
746{
747 INT_OFF;
748 fflush_all();
749 INT_ON;
750}
751
752
753static void
754newline_and_flush(FILE *dest)
755{
756 INT_OFF;
757 putc('\n', dest);
758 fflush(dest);
759 INT_ON;
760}
761
762static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
763static int
764out1fmt(const char *fmt, ...)
765{
766 va_list ap;
767 int r;
768
769 INT_OFF;
770 va_start(ap, fmt);
771 r = vprintf(fmt, ap);
772 va_end(ap);
773 INT_ON;
774 return r;
775}
776
777static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
778static int
779fmtstr(char *outbuf, size_t length, const char *fmt, ...)
780{
781 va_list ap;
782 int ret;
783
784 INT_OFF;
785 va_start(ap, fmt);
786 ret = vsnprintf(outbuf, length, fmt, ap);
787 va_end(ap);
788 INT_ON;
789 return ret > (int)length ? length : ret;
790}
791
792static void
793out1str(const char *p)
794{
795 outstr(p, stdout);
796}
797
798static void
799out2str(const char *p)
800{
801 outstr(p, stderr);
802 flush_stdout_stderr();
803}
804
805
806
807
808
809#define CTL_FIRST CTLESC
810#define CTLESC ((unsigned char)'\201')
811#define CTLVAR ((unsigned char)'\202')
812#define CTLENDVAR ((unsigned char)'\203')
813#define CTLBACKQ ((unsigned char)'\204')
814#define CTLARI ((unsigned char)'\206')
815#define CTLENDARI ((unsigned char)'\207')
816#define CTLQUOTEMARK ((unsigned char)'\210')
817#define CTL_LAST CTLQUOTEMARK
818#if BASH_PROCESS_SUBST
819# define CTLTOPROC ((unsigned char)'\211')
820# define CTLFROMPROC ((unsigned char)'\212')
821# undef CTL_LAST
822# define CTL_LAST CTLFROMPROC
823#endif
824
825
826#define VSTYPE 0x0f
827#define VSNUL 0x10
828
829
830#define VSNORMAL 0x1
831#define VSMINUS 0x2
832#define VSPLUS 0x3
833#define VSQUESTION 0x4
834#define VSASSIGN 0x5
835#define VSTRIMRIGHT 0x6
836#define VSTRIMRIGHTMAX 0x7
837#define VSTRIMLEFT 0x8
838#define VSTRIMLEFTMAX 0x9
839#define VSLENGTH 0xa
840#if BASH_SUBSTR
841#define VSSUBSTR 0xc
842#endif
843#if BASH_PATTERN_SUBST
844#define VSREPLACE 0xd
845#define VSREPLACEALL 0xe
846#endif
847
848static const char dolatstr[] ALIGN1 = {
849 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
850};
851#define DOLATSTRLEN 6
852
853#define NCMD 0
854#define NPIPE 1
855#define NREDIR 2
856#define NBACKGND 3
857#define NSUBSHELL 4
858#define NAND 5
859#define NOR 6
860#define NSEMI 7
861#define NIF 8
862#define NWHILE 9
863#define NUNTIL 10
864#define NFOR 11
865#define NCASE 12
866#define NCLIST 13
867#define NDEFUN 14
868#define NARG 15
869#define NTO 16
870#if BASH_REDIR_OUTPUT
871#define NTO2 17
872#endif
873#define NCLOBBER 18
874#define NFROM 19
875#define NFROMTO 20
876#define NAPPEND 21
877#define NTOFD 22
878#define NFROMFD 23
879#define NHERE 24
880#define NXHERE 25
881#define NNOT 26
882#define N_NUMBER 27
883
884union node;
885
886struct ncmd {
887 smallint type;
888 int linno;
889 union node *assign;
890 union node *args;
891 union node *redirect;
892};
893
894struct npipe {
895 smallint type;
896 smallint pipe_backgnd;
897 struct nodelist *cmdlist;
898};
899
900struct nredir {
901 smallint type;
902 int linno;
903 union node *n;
904 union node *redirect;
905};
906
907struct nbinary {
908 smallint type;
909 union node *ch1;
910 union node *ch2;
911};
912
913struct nif {
914 smallint type;
915 union node *test;
916 union node *ifpart;
917 union node *elsepart;
918};
919
920struct nfor {
921 smallint type;
922 int linno;
923 union node *args;
924 union node *body;
925 char *var;
926};
927
928struct ncase {
929 smallint type;
930 int linno;
931 union node *expr;
932 union node *cases;
933};
934
935struct nclist {
936 smallint type;
937 union node *next;
938 union node *pattern;
939 union node *body;
940};
941
942struct ndefun {
943 smallint type;
944 int linno;
945 char *text;
946 union node *body;
947};
948
949struct narg {
950 smallint type;
951 union node *next;
952 char *text;
953 struct nodelist *backquote;
954};
955
956
957
958
959
960struct nfile {
961 smallint type;
962 union node *next;
963 int fd;
964 int _unused_dupfd;
965 union node *fname;
966 char *expfname;
967};
968
969struct ndup {
970 smallint type;
971 union node *next;
972 int fd;
973 int dupfd;
974 union node *vname;
975 char *_unused_expfname;
976};
977
978struct nhere {
979 smallint type;
980 union node *next;
981 int fd;
982 union node *doc;
983};
984
985struct nnot {
986 smallint type;
987 union node *com;
988};
989
990union node {
991 smallint type;
992 struct ncmd ncmd;
993 struct npipe npipe;
994 struct nredir nredir;
995 struct nbinary nbinary;
996 struct nif nif;
997 struct nfor nfor;
998 struct ncase ncase;
999 struct nclist nclist;
1000 struct ndefun ndefun;
1001 struct narg narg;
1002 struct nfile nfile;
1003 struct ndup ndup;
1004 struct nhere nhere;
1005 struct nnot nnot;
1006};
1007
1008
1009
1010
1011
1012#define NODE_EOF ((union node *) -1L)
1013
1014struct nodelist {
1015 struct nodelist *next;
1016 union node *n;
1017};
1018
1019struct funcnode {
1020 int count;
1021 union node n;
1022};
1023
1024
1025
1026
1027static void
1028freefunc(struct funcnode *f)
1029{
1030 if (f && --f->count < 0)
1031 free(f);
1032}
1033
1034
1035
1036
1037#if DEBUG
1038
1039static FILE *tracefile;
1040
1041static void
1042trace_printf(const char *fmt, ...)
1043{
1044 va_list va;
1045
1046 if (debug != 1)
1047 return;
1048 if (DEBUG_TIME)
1049 fprintf(tracefile, "%u ", (int) time(NULL));
1050 if (DEBUG_PID)
1051 fprintf(tracefile, "[%u] ", (int) getpid());
1052 if (DEBUG_SIG)
1053 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
1054 va_start(va, fmt);
1055 vfprintf(tracefile, fmt, va);
1056 va_end(va);
1057}
1058
1059static void
1060trace_vprintf(const char *fmt, va_list va)
1061{
1062 if (debug != 1)
1063 return;
1064 vfprintf(tracefile, fmt, va);
1065 fprintf(tracefile, "\n");
1066}
1067
1068static void
1069trace_puts(const char *s)
1070{
1071 if (debug != 1)
1072 return;
1073 fputs(s, tracefile);
1074}
1075
1076static void
1077trace_puts_quoted(char *s)
1078{
1079 char *p;
1080 char c;
1081
1082 if (debug != 1)
1083 return;
1084 putc('"', tracefile);
1085 for (p = s; *p; p++) {
1086 switch ((unsigned char)*p) {
1087 case '\n': c = 'n'; goto backslash;
1088 case '\t': c = 't'; goto backslash;
1089 case '\r': c = 'r'; goto backslash;
1090 case '\"': c = '\"'; goto backslash;
1091 case '\\': c = '\\'; goto backslash;
1092 case CTLESC: c = 'e'; goto backslash;
1093 case CTLVAR: c = 'v'; goto backslash;
1094 case CTLBACKQ: c = 'q'; goto backslash;
1095#if BASH_PROCESS_SUBST
1096 case CTLTOPROC: c = 'p'; goto backslash;
1097 case CTLFROMPROC: c = 'P'; goto backslash;
1098#endif
1099 backslash:
1100 putc('\\', tracefile);
1101 putc(c, tracefile);
1102 break;
1103 default:
1104 if (*p >= ' ' && *p <= '~')
1105 putc(*p, tracefile);
1106 else {
1107 putc('\\', tracefile);
1108 putc((*p >> 6) & 03, tracefile);
1109 putc((*p >> 3) & 07, tracefile);
1110 putc(*p & 07, tracefile);
1111 }
1112 break;
1113 }
1114 }
1115 putc('"', tracefile);
1116}
1117
1118static void
1119trace_puts_args(char **ap)
1120{
1121 if (debug != 1)
1122 return;
1123 if (!*ap)
1124 return;
1125 while (1) {
1126 trace_puts_quoted(*ap);
1127 if (!*++ap) {
1128 putc('\n', tracefile);
1129 break;
1130 }
1131 putc(' ', tracefile);
1132 }
1133}
1134
1135static void
1136opentrace(void)
1137{
1138 char s[100];
1139#ifdef O_APPEND
1140 int flags;
1141#endif
1142
1143 if (debug != 1) {
1144 if (tracefile)
1145 fflush(tracefile);
1146
1147 return;
1148 }
1149 strcpy(s, "./trace");
1150 if (tracefile) {
1151 if (!freopen(s, "a", tracefile)) {
1152 fprintf(stderr, "Can't re-open %s\n", s);
1153 debug = 0;
1154 return;
1155 }
1156 } else {
1157 tracefile = fopen(s, "a");
1158 if (tracefile == NULL) {
1159 fprintf(stderr, "Can't open %s\n", s);
1160 debug = 0;
1161 return;
1162 }
1163 }
1164#ifdef O_APPEND
1165 flags = fcntl(fileno(tracefile), F_GETFL);
1166 if (flags >= 0)
1167 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1168#endif
1169 setlinebuf(tracefile);
1170 fputs("\nTracing started.\n", tracefile);
1171}
1172
1173static void
1174indent(int amount, char *pfx, FILE *fp)
1175{
1176 int i;
1177
1178 for (i = 0; i < amount; i++) {
1179 if (pfx && i == amount - 1)
1180 fputs(pfx, fp);
1181 putc('\t', fp);
1182 }
1183}
1184
1185
1186static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1187
1188static void
1189sharg(union node *arg, FILE *fp)
1190{
1191 char *p;
1192 struct nodelist *bqlist;
1193 unsigned char subtype;
1194
1195 if (arg->type != NARG) {
1196 out1fmt("<node type %d>\n", arg->type);
1197 abort();
1198 }
1199 bqlist = arg->narg.backquote;
1200 for (p = arg->narg.text; *p; p++) {
1201 switch ((unsigned char)*p) {
1202 case CTLESC:
1203 p++;
1204 putc(*p, fp);
1205 break;
1206 case CTLVAR:
1207 putc('$', fp);
1208 putc('{', fp);
1209 subtype = *++p;
1210 if (subtype == VSLENGTH)
1211 putc('#', fp);
1212
1213 while (*p != '=') {
1214 putc(*p, fp);
1215 p++;
1216 }
1217
1218 if (subtype & VSNUL)
1219 putc(':', fp);
1220
1221 switch (subtype & VSTYPE) {
1222 case VSNORMAL:
1223 putc('}', fp);
1224 break;
1225 case VSMINUS:
1226 putc('-', fp);
1227 break;
1228 case VSPLUS:
1229 putc('+', fp);
1230 break;
1231 case VSQUESTION:
1232 putc('?', fp);
1233 break;
1234 case VSASSIGN:
1235 putc('=', fp);
1236 break;
1237 case VSTRIMLEFT:
1238 putc('#', fp);
1239 break;
1240 case VSTRIMLEFTMAX:
1241 putc('#', fp);
1242 putc('#', fp);
1243 break;
1244 case VSTRIMRIGHT:
1245 putc('%', fp);
1246 break;
1247 case VSTRIMRIGHTMAX:
1248 putc('%', fp);
1249 putc('%', fp);
1250 break;
1251 case VSLENGTH:
1252 break;
1253 default:
1254 out1fmt("<subtype %d>", subtype);
1255 }
1256 break;
1257 case CTLENDVAR:
1258 putc('}', fp);
1259 break;
1260#if BASH_PROCESS_SUBST
1261 case CTLTOPROC:
1262 putc('>', fp);
1263 goto backq;
1264 case CTLFROMPROC:
1265 putc('<', fp);
1266 goto backq;
1267#endif
1268 case CTLBACKQ:
1269 putc('$', fp);
1270 IF_BASH_PROCESS_SUBST(backq:)
1271 putc('(', fp);
1272 shtree(bqlist->n, -1, NULL, fp);
1273 putc(')', fp);
1274 break;
1275 default:
1276 putc(*p, fp);
1277 break;
1278 }
1279 }
1280}
1281
1282static void
1283shcmd(union node *cmd, FILE *fp)
1284{
1285 union node *np;
1286 int first;
1287 const char *s;
1288 int dftfd;
1289
1290 first = 1;
1291 for (np = cmd->ncmd.args; np; np = np->narg.next) {
1292 if (!first)
1293 putc(' ', fp);
1294 sharg(np, fp);
1295 first = 0;
1296 }
1297 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1298 if (!first)
1299 putc(' ', fp);
1300 dftfd = 0;
1301 switch (np->nfile.type) {
1302 case NTO: s = ">>"+1; dftfd = 1; break;
1303 case NCLOBBER: s = ">|"; dftfd = 1; break;
1304 case NAPPEND: s = ">>"; dftfd = 1; break;
1305#if BASH_REDIR_OUTPUT
1306 case NTO2:
1307#endif
1308 case NTOFD: s = ">&"; dftfd = 1; break;
1309 case NFROM: s = "<"; break;
1310 case NFROMFD: s = "<&"; break;
1311 case NFROMTO: s = "<>"; break;
1312 default: s = "*error*"; break;
1313 }
1314 if (np->nfile.fd != dftfd)
1315 fprintf(fp, "%d", np->nfile.fd);
1316 fputs(s, fp);
1317 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1318 fprintf(fp, "%d", np->ndup.dupfd);
1319 } else {
1320 sharg(np->nfile.fname, fp);
1321 }
1322 first = 0;
1323 }
1324}
1325
1326static void
1327shtree(union node *n, int ind, char *pfx, FILE *fp)
1328{
1329 struct nodelist *lp;
1330 const char *s;
1331
1332 if (n == NULL)
1333 return;
1334
1335 indent(ind, pfx, fp);
1336
1337 if (n == NODE_EOF) {
1338 fputs("<EOF>", fp);
1339 return;
1340 }
1341
1342 switch (n->type) {
1343 case NSEMI:
1344 s = "; ";
1345 goto binop;
1346 case NAND:
1347 s = " && ";
1348 goto binop;
1349 case NOR:
1350 s = " || ";
1351 binop:
1352 shtree(n->nbinary.ch1, ind, NULL, fp);
1353
1354 fputs(s, fp);
1355 shtree(n->nbinary.ch2, ind, NULL, fp);
1356 break;
1357 case NCMD:
1358 shcmd(n, fp);
1359 if (ind >= 0)
1360 putc('\n', fp);
1361 break;
1362 case NPIPE:
1363 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1364 shtree(lp->n, 0, NULL, fp);
1365 if (lp->next)
1366 fputs(" | ", fp);
1367 }
1368 if (n->npipe.pipe_backgnd)
1369 fputs(" &", fp);
1370 if (ind >= 0)
1371 putc('\n', fp);
1372 break;
1373 default:
1374 fprintf(fp, "<node type %d>", n->type);
1375 if (ind >= 0)
1376 putc('\n', fp);
1377 break;
1378 }
1379}
1380
1381static void
1382showtree(union node *n)
1383{
1384 trace_puts("showtree called\n");
1385 shtree(n, 1, NULL, stderr);
1386}
1387
1388#endif
1389
1390
1391
1392
1393static void
1394ash_vmsg(const char *msg, va_list ap)
1395{
1396 fprintf(stderr, "%s: ", arg0);
1397 if (commandname) {
1398 if (strcmp(arg0, commandname))
1399 fprintf(stderr, "%s: ", commandname);
1400 if (!iflag || g_parsefile->pf_fd > 0)
1401 fprintf(stderr, "line %d: ", errlinno);
1402 }
1403 vfprintf(stderr, msg, ap);
1404 newline_and_flush(stderr);
1405}
1406
1407
1408
1409
1410
1411
1412static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1413static void
1414ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1415{
1416#if DEBUG
1417 if (msg) {
1418 TRACE(("ash_vmsg_and_raise(%d):", cond));
1419 TRACEV((msg, ap));
1420 } else
1421 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1422 if (msg)
1423#endif
1424 ash_vmsg(msg, ap);
1425
1426 flush_stdout_stderr();
1427 raise_exception(cond);
1428
1429}
1430
1431static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1432static void
1433ash_msg_and_raise_error(const char *msg, ...)
1434{
1435 va_list ap;
1436
1437 exitstatus = 2;
1438
1439 va_start(ap, msg);
1440 ash_vmsg_and_raise(EXERROR, msg, ap);
1441
1442 va_end(ap);
1443}
1444
1445
1446
1447
1448#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
1449
1450static void raise_error_syntax(const char *) NORETURN;
1451static void
1452raise_error_syntax(const char *msg)
1453{
1454 errlinno = g_parsefile->linno;
1455 ash_msg_and_raise_error("syntax error: %s", msg);
1456
1457}
1458
1459static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1460static void
1461ash_msg_and_raise(int cond, const char *msg, ...)
1462{
1463 va_list ap;
1464
1465 va_start(ap, msg);
1466 ash_vmsg_and_raise(cond, msg, ap);
1467
1468 va_end(ap);
1469}
1470
1471
1472
1473
1474static void
1475ash_msg(const char *fmt, ...)
1476{
1477 va_list ap;
1478
1479 va_start(ap, fmt);
1480 ash_vmsg(fmt, ap);
1481 va_end(ap);
1482}
1483
1484
1485
1486
1487
1488
1489static const char *
1490errmsg(int e, const char *em)
1491{
1492 if (e == ENOENT || e == ENOTDIR) {
1493 return em;
1494 }
1495 return strerror(e);
1496}
1497
1498
1499
1500
1501#if 0
1502
1503
1504
1505
1506
1507static void *
1508ckrealloc(void * p, size_t nbytes)
1509{
1510 p = realloc(p, nbytes);
1511 if (!p)
1512 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1513 return p;
1514}
1515
1516static void *
1517ckmalloc(size_t nbytes)
1518{
1519 return ckrealloc(NULL, nbytes);
1520}
1521
1522static void *
1523ckzalloc(size_t nbytes)
1524{
1525 return memset(ckmalloc(nbytes), 0, nbytes);
1526}
1527
1528static char *
1529ckstrdup(const char *s)
1530{
1531 char *p = strdup(s);
1532 if (!p)
1533 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1534 return p;
1535}
1536#else
1537
1538# define ckrealloc xrealloc
1539# define ckmalloc xmalloc
1540# define ckzalloc xzalloc
1541# define ckstrdup xstrdup
1542#endif
1543
1544
1545
1546
1547
1548#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1549enum {
1550
1551
1552
1553 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1554
1555 MINSIZE = SHELL_ALIGN(504),
1556};
1557
1558struct stack_block {
1559 struct stack_block *prev;
1560 char space[MINSIZE];
1561};
1562
1563struct stackmark {
1564 struct stack_block *stackp;
1565 char *stacknxt;
1566 size_t stacknleft;
1567};
1568
1569
1570struct globals_memstack {
1571 struct stack_block *g_stackp;
1572 char *g_stacknxt;
1573 char *sstrend;
1574 size_t g_stacknleft;
1575 struct stack_block stackbase;
1576};
1577extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1578#define G_memstack (*ash_ptr_to_globals_memstack)
1579#define g_stackp (G_memstack.g_stackp )
1580#define g_stacknxt (G_memstack.g_stacknxt )
1581#define sstrend (G_memstack.sstrend )
1582#define g_stacknleft (G_memstack.g_stacknleft)
1583#define stackbase (G_memstack.stackbase )
1584#define INIT_G_memstack() do { \
1585 XZALLOC_CONST_PTR(&ash_ptr_to_globals_memstack, sizeof(G_memstack)); \
1586 g_stackp = &stackbase; \
1587 g_stacknxt = stackbase.space; \
1588 g_stacknleft = MINSIZE; \
1589 sstrend = stackbase.space + MINSIZE; \
1590} while (0)
1591
1592
1593#define stackblock() ((void *)g_stacknxt)
1594#define stackblocksize() g_stacknleft
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604static void *
1605stalloc(size_t nbytes)
1606{
1607 char *p;
1608 size_t aligned;
1609
1610 aligned = SHELL_ALIGN(nbytes);
1611 if (aligned > g_stacknleft) {
1612 size_t len;
1613 size_t blocksize;
1614 struct stack_block *sp;
1615
1616 blocksize = aligned;
1617 if (blocksize < MINSIZE)
1618 blocksize = MINSIZE;
1619 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1620 if (len < blocksize)
1621 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1622 INT_OFF;
1623 sp = ckmalloc(len);
1624 sp->prev = g_stackp;
1625 g_stacknxt = sp->space;
1626 g_stacknleft = blocksize;
1627 sstrend = g_stacknxt + blocksize;
1628 g_stackp = sp;
1629 INT_ON;
1630 }
1631 p = g_stacknxt;
1632 g_stacknxt += aligned;
1633 g_stacknleft -= aligned;
1634 return p;
1635}
1636
1637static void *
1638stzalloc(size_t nbytes)
1639{
1640 return memset(stalloc(nbytes), 0, nbytes);
1641}
1642
1643static void
1644stunalloc(void *p)
1645{
1646#if DEBUG
1647 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1648 write(STDERR_FILENO, "stunalloc\n", 10);
1649 abort();
1650 }
1651#endif
1652 g_stacknleft += g_stacknxt - (char *)p;
1653 g_stacknxt = p;
1654}
1655
1656
1657
1658
1659static char *
1660sstrdup(const char *p)
1661{
1662 size_t len = strlen(p) + 1;
1663 return memcpy(stalloc(len), p, len);
1664}
1665
1666static ALWAYS_INLINE void
1667grabstackblock(size_t len)
1668{
1669 stalloc(len);
1670}
1671
1672static void
1673pushstackmark(struct stackmark *mark, size_t len)
1674{
1675 mark->stackp = g_stackp;
1676 mark->stacknxt = g_stacknxt;
1677 mark->stacknleft = g_stacknleft;
1678 grabstackblock(len);
1679}
1680
1681static void
1682setstackmark(struct stackmark *mark)
1683{
1684 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1685}
1686
1687static void
1688popstackmark(struct stackmark *mark)
1689{
1690 struct stack_block *sp;
1691
1692 if (!mark->stackp)
1693 return;
1694
1695 INT_OFF;
1696 while (g_stackp != mark->stackp) {
1697 sp = g_stackp;
1698 g_stackp = sp->prev;
1699 free(sp);
1700 }
1701 g_stacknxt = mark->stacknxt;
1702 g_stacknleft = mark->stacknleft;
1703 sstrend = mark->stacknxt + mark->stacknleft;
1704 INT_ON;
1705}
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716static void
1717growstackblock(size_t min)
1718{
1719 size_t newlen;
1720
1721 newlen = g_stacknleft * 2;
1722 if (newlen < g_stacknleft)
1723 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1724 min = SHELL_ALIGN(min | 128);
1725 if (newlen < min)
1726 newlen += min;
1727
1728 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1729 struct stack_block *sp;
1730 struct stack_block *prevstackp;
1731 size_t grosslen;
1732
1733 INT_OFF;
1734 sp = g_stackp;
1735 prevstackp = sp->prev;
1736 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1737 sp = ckrealloc(sp, grosslen);
1738 sp->prev = prevstackp;
1739 g_stackp = sp;
1740 g_stacknxt = sp->space;
1741 g_stacknleft = newlen;
1742 sstrend = sp->space + newlen;
1743 INT_ON;
1744 } else {
1745 char *oldspace = g_stacknxt;
1746 size_t oldlen = g_stacknleft;
1747 char *p = stalloc(newlen);
1748
1749
1750 g_stacknxt = memcpy(p, oldspace, oldlen);
1751 g_stacknleft += newlen;
1752 }
1753}
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772static void *
1773growstackstr(void)
1774{
1775 size_t len = stackblocksize();
1776 growstackblock(0);
1777 return (char *)stackblock() + len;
1778}
1779
1780static char *
1781growstackto(size_t len)
1782{
1783 if (stackblocksize() < len)
1784 growstackblock(len);
1785 return stackblock();
1786}
1787
1788
1789
1790
1791static char *
1792makestrspace(size_t newlen, char *p)
1793{
1794 size_t len = p - g_stacknxt;
1795
1796 return growstackto(len + newlen) + len;
1797}
1798
1799static char *
1800stnputs(const char *s, size_t n, char *p)
1801{
1802 p = makestrspace(n, p);
1803 p = (char *)mempcpy(p, s, n);
1804 return p;
1805}
1806
1807static char *
1808stack_putstr(const char *s, char *p)
1809{
1810 return stnputs(s, strlen(s), p);
1811}
1812
1813static char *
1814_STPUTC(int c, char *p)
1815{
1816 if (p == sstrend)
1817 p = growstackstr();
1818 *p++ = c;
1819 return p;
1820}
1821
1822#define STARTSTACKSTR(p) ((p) = stackblock())
1823#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1824#define CHECKSTRSPACE(n, p) do { \
1825 char *q = (p); \
1826 size_t l = (n); \
1827 size_t m = sstrend - q; \
1828 if (l > m) \
1829 (p) = makestrspace(l, q); \
1830} while (0)
1831#define USTPUTC(c, p) (*(p)++ = (c))
1832#define STACKSTRNUL(p) do { \
1833 if ((p) == sstrend) \
1834 (p) = growstackstr(); \
1835 *(p) = '\0'; \
1836} while (0)
1837#define STUNPUTC(p) (--(p))
1838#define STTOPC(p) ((p)[-1])
1839#define STADJUST(amount, p) ((p) += (amount))
1840
1841#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1842#define ungrabstackstr(s, p) stunalloc(s)
1843#define stackstrend() ((void *)sstrend)
1844
1845
1846
1847
1848
1849
1850
1851static char *
1852prefix(const char *string, const char *pfx)
1853{
1854 while (*pfx) {
1855 if (*pfx++ != *string++)
1856 return NULL;
1857 }
1858 return (char *) string;
1859}
1860
1861
1862
1863
1864static int
1865is_number(const char *p)
1866{
1867 do {
1868 if (!isdigit(*p))
1869 return 0;
1870 } while (*++p != '\0');
1871 return 1;
1872}
1873
1874
1875
1876
1877
1878static int
1879number(const char *s)
1880{
1881 if (!is_number(s))
1882 ash_msg_and_raise_error(msg_illnum, s);
1883 return atoi(s);
1884}
1885
1886
1887
1888
1889
1890static char *
1891single_quote(const char *s)
1892{
1893 char *p;
1894
1895 STARTSTACKSTR(p);
1896
1897 do {
1898 char *q;
1899 size_t len;
1900
1901 len = strchrnul(s, '\'') - s;
1902
1903 q = p = makestrspace(len + 3, p);
1904
1905 *q++ = '\'';
1906 q = (char *)mempcpy(q, s, len);
1907 *q++ = '\'';
1908 s += len;
1909
1910 STADJUST(q - p, p);
1911
1912 if (*s != '\'')
1913 break;
1914 len = 0;
1915 do len++; while (*++s == '\'');
1916
1917 q = p = makestrspace(len + 3, p);
1918
1919 *q++ = '"';
1920 q = (char *)mempcpy(q, s - len, len);
1921 *q++ = '"';
1922
1923 STADJUST(q - p, p);
1924 } while (*s);
1925
1926 USTPUTC('\0', p);
1927
1928 return stackblock();
1929}
1930
1931
1932
1933
1934
1935
1936static const char *
1937maybe_single_quote(const char *s)
1938{
1939 const char *p = s;
1940
1941 while (*p) {
1942
1943
1944 if (*p < '+')
1945 goto need_quoting;
1946
1947 if (*p >= ';' && *p <= '?')
1948 goto need_quoting;
1949
1950 if (*p == '`')
1951 goto need_quoting;
1952 if (*p == '[')
1953 goto need_quoting;
1954 if (*p == '\\')
1955 goto need_quoting;
1956
1957 if (*p > 'z')
1958 goto need_quoting;
1959
1960
1961 p++;
1962 }
1963 return s;
1964
1965 need_quoting:
1966 return single_quote(s);
1967}
1968
1969
1970
1971
1972static char **argptr;
1973static char *optionarg;
1974static char *optptr;
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986static int
1987nextopt(const char *optstring)
1988{
1989 char *p;
1990 const char *q;
1991 char c;
1992
1993 p = optptr;
1994 if (p == NULL || *p == '\0') {
1995
1996 p = *argptr;
1997 if (p == NULL)
1998 return '\0';
1999 if (*p != '-')
2000 return '\0';
2001 if (*++p == '\0')
2002 return '\0';
2003 argptr++;
2004 if (LONE_DASH(p))
2005 return '\0';
2006
2007 }
2008
2009 c = *p++;
2010 for (q = optstring; *q != c;) {
2011 if (*q == '\0')
2012 ash_msg_and_raise_error("illegal option -%c", c);
2013 if (*++q == ':')
2014 q++;
2015 }
2016 if (*++q == ':') {
2017 if (*p == '\0') {
2018 p = *argptr++;
2019 if (p == NULL)
2020 ash_msg_and_raise_error("no arg for -%c option", c);
2021 }
2022 optionarg = p;
2023 p = NULL;
2024 }
2025 optptr = p;
2026 return c;
2027}
2028
2029
2030
2031
2032struct shparam {
2033 int nparam;
2034#if ENABLE_ASH_GETOPTS
2035 int optind;
2036 int optoff;
2037#endif
2038 unsigned char malloced;
2039 char **p;
2040};
2041
2042
2043
2044
2045static void
2046freeparam(volatile struct shparam *param)
2047{
2048 if (param->malloced) {
2049 char **ap, **ap1;
2050 ap = ap1 = param->p;
2051 while (*ap)
2052 free(*ap++);
2053 free(ap1);
2054 }
2055}
2056
2057#if ENABLE_ASH_GETOPTS
2058static void FAST_FUNC getoptsreset(const char *value);
2059#endif
2060
2061struct var {
2062 struct var *next;
2063 int flags;
2064 const char *var_text;
2065 void (*var_func)(const char *) FAST_FUNC;
2066
2067};
2068
2069struct localvar {
2070 struct localvar *next;
2071 struct var *vp;
2072 int flags;
2073 const char *text;
2074};
2075
2076
2077#define VEXPORT 0x01
2078#define VREADONLY 0x02
2079#define VSTRFIXED 0x04
2080#define VTEXTFIXED 0x08
2081#define VSTACK 0x10
2082#define VUNSET 0x20
2083#define VNOFUNC 0x40
2084#define VNOSET 0x80
2085#define VNOSAVE 0x100
2086#if ENABLE_ASH_RANDOM_SUPPORT
2087# define VDYNAMIC 0x200
2088#else
2089# define VDYNAMIC 0
2090#endif
2091
2092
2093
2094#if ENABLE_LOCALE_SUPPORT
2095static void FAST_FUNC
2096change_lc_all(const char *value)
2097{
2098 if (value && *value != '\0')
2099 setlocale(LC_ALL, value);
2100}
2101static void FAST_FUNC
2102change_lc_ctype(const char *value)
2103{
2104 if (value && *value != '\0')
2105 setlocale(LC_CTYPE, value);
2106}
2107#endif
2108#if ENABLE_ASH_MAIL
2109static void chkmail(void);
2110static void changemail(const char *var_value) FAST_FUNC;
2111#else
2112# define chkmail() ((void)0)
2113#endif
2114static void changepath(const char *) FAST_FUNC;
2115#if ENABLE_ASH_RANDOM_SUPPORT
2116static void change_random(const char *) FAST_FUNC;
2117#endif
2118#if BASH_EPOCH_VARS
2119static void change_seconds(const char *) FAST_FUNC;
2120static void change_realtime(const char *) FAST_FUNC;
2121#endif
2122
2123static const struct {
2124 int flags;
2125 const char *var_text;
2126 void (*var_func)(const char *) FAST_FUNC;
2127} varinit_data[] ALIGN_PTR = {
2128
2129
2130
2131
2132 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
2133#if ENABLE_ASH_MAIL
2134 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2135 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
2136#endif
2137 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2138 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2139 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2140 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
2141#if ENABLE_ASH_GETOPTS
2142 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
2143#endif
2144 { VSTRFIXED|VTEXTFIXED , NULL , NULL },
2145 { VSTRFIXED|VTEXTFIXED , NULL , NULL },
2146#if ENABLE_ASH_RANDOM_SUPPORT
2147 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2148#endif
2149#if BASH_EPOCH_VARS
2150 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHSECONDS", change_seconds },
2151 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHREALTIME", change_realtime },
2152#endif
2153#if ENABLE_LOCALE_SUPPORT
2154 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2155 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
2156#endif
2157#if ENABLE_FEATURE_EDITING_SAVEHISTORY
2158 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
2159#endif
2160};
2161
2162struct redirtab;
2163
2164struct globals_var {
2165 struct shparam shellparam;
2166 struct redirtab *redirlist;
2167 int preverrout_fd;
2168 struct var *vartab[VTABSIZE];
2169 struct var varinit[ARRAY_SIZE(varinit_data)];
2170 int lineno;
2171 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2172 char funcnamevar[sizeof("FUNCNAME=") + 64];
2173 char *funcname;
2174 unsigned trap_depth;
2175 bool in_trap_ERR;
2176};
2177extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2178#define G_var (*ash_ptr_to_globals_var)
2179#define shellparam (G_var.shellparam )
2180
2181#define preverrout_fd (G_var.preverrout_fd)
2182#define vartab (G_var.vartab )
2183#define varinit (G_var.varinit )
2184#define lineno (G_var.lineno )
2185#define linenovar (G_var.linenovar )
2186#define funcnamevar (G_var.funcnamevar )
2187#define funcname (G_var.funcname )
2188#define trap_depth (G_var.trap_depth )
2189#define in_trap_ERR (G_var.in_trap_ERR )
2190#define vifs varinit[0]
2191#if ENABLE_ASH_MAIL
2192# define vmail varinit[1]
2193# define vmpath varinit[2]
2194#endif
2195#define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
2196#define vpath varinit[VAR_OFFSET1 + 1]
2197#define vps1 varinit[VAR_OFFSET1 + 2]
2198#define vps2 varinit[VAR_OFFSET1 + 3]
2199#define vps4 varinit[VAR_OFFSET1 + 4]
2200#if ENABLE_ASH_GETOPTS
2201# define voptind varinit[VAR_OFFSET1 + 5]
2202#endif
2203#define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
2204#define vlineno varinit[VAR_OFFSET2 + 5]
2205#define vfuncname varinit[VAR_OFFSET2 + 6]
2206#if ENABLE_ASH_RANDOM_SUPPORT
2207# define vrandom varinit[VAR_OFFSET2 + 7]
2208#endif
2209#define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
2210#if BASH_EPOCH_VARS
2211# define vepochs varinit[VAR_OFFSET3 + 7]
2212# define vepochr varinit[VAR_OFFSET3 + 8]
2213#endif
2214#define INIT_G_var() do { \
2215 unsigned i; \
2216 XZALLOC_CONST_PTR(&ash_ptr_to_globals_var, sizeof(G_var)); \
2217 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2218 varinit[i].flags = varinit_data[i].flags; \
2219 varinit[i].var_text = varinit_data[i].var_text; \
2220 varinit[i].var_func = varinit_data[i].var_func; \
2221 } \
2222 strcpy(linenovar, "LINENO="); \
2223 vlineno.var_text = linenovar; \
2224 strcpy(funcnamevar, "FUNCNAME="); \
2225 vfuncname.var_text = funcnamevar; \
2226} while (0)
2227
2228
2229
2230
2231
2232
2233#define ifsval() (vifs.var_text + 4)
2234#define ifsset() ((vifs.flags & VUNSET) == 0)
2235#if ENABLE_ASH_MAIL
2236# define mailval() (vmail.var_text + 5)
2237# define mpathval() (vmpath.var_text + 9)
2238# define mpathset() ((vmpath.flags & VUNSET) == 0)
2239#endif
2240#define pathval() (vpath.var_text + 5)
2241#define ps1val() (vps1.var_text + 4)
2242#define ps2val() (vps2.var_text + 4)
2243#define ps4val() (vps4.var_text + 4)
2244#if ENABLE_ASH_GETOPTS
2245# define optindval() (voptind.var_text + 7)
2246#endif
2247
2248#if ENABLE_ASH_GETOPTS
2249static void FAST_FUNC
2250getoptsreset(const char *value)
2251{
2252 shellparam.optind = 1;
2253 if (is_number(value))
2254 shellparam.optind = number(value) ?: 1;
2255 shellparam.optoff = -1;
2256}
2257#endif
2258
2259
2260
2261
2262
2263
2264static int
2265varcmp(const char *p, const char *q)
2266{
2267 int c, d;
2268
2269 while ((c = *p) == (d = *q)) {
2270 if (c == '\0' || c == '=')
2271 goto out;
2272 p++;
2273 q++;
2274 }
2275 if (c == '=')
2276 c = '\0';
2277 if (d == '=')
2278 d = '\0';
2279 out:
2280 return c - d;
2281}
2282
2283
2284
2285
2286static struct var **
2287hashvar(const char *p)
2288{
2289 unsigned hashval;
2290
2291 hashval = ((unsigned char) *p) << 4;
2292 while (*p && *p != '=')
2293 hashval += (unsigned char) *p++;
2294 return &vartab[hashval % VTABSIZE];
2295}
2296
2297static int
2298vpcmp(const void *a, const void *b)
2299{
2300 return varcmp(*(const char **)a, *(const char **)b);
2301}
2302
2303
2304
2305
2306static void
2307initvar(void)
2308{
2309 struct var *vp;
2310 struct var *end;
2311 struct var **vpp;
2312
2313
2314
2315
2316#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2317 vps1.var_text = "PS1=\\w \\$ ";
2318#else
2319 if (!geteuid())
2320 vps1.var_text = "PS1=# ";
2321#endif
2322 vp = varinit;
2323 end = vp + ARRAY_SIZE(varinit);
2324 do {
2325 vpp = hashvar(vp->var_text);
2326 vp->next = *vpp;
2327 *vpp = vp;
2328 } while (++vp < end);
2329}
2330
2331static struct var **
2332findvar(struct var **vpp, const char *name)
2333{
2334 for (; *vpp; vpp = &(*vpp)->next) {
2335 if (varcmp((*vpp)->var_text, name) == 0) {
2336 break;
2337 }
2338 }
2339 return vpp;
2340}
2341
2342
2343
2344
2345static const char* FAST_FUNC
2346lookupvar(const char *name)
2347{
2348 struct var *v;
2349
2350 v = *findvar(hashvar(name), name);
2351 if (v) {
2352#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2353
2354
2355
2356
2357
2358
2359 if (v->flags & VDYNAMIC)
2360 v->var_func(NULL);
2361#endif
2362 if (!(v->flags & VUNSET)) {
2363 if (v->var_text == linenovar) {
2364 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2365 } else
2366 if (v->var_text == funcnamevar) {
2367 safe_strncpy(funcnamevar+9, funcname ? funcname : "", sizeof(funcnamevar)-9);
2368 }
2369 return var_end(v->var_text);
2370 }
2371 }
2372 return NULL;
2373}
2374
2375#if ENABLE_UNICODE_SUPPORT
2376static void
2377reinit_unicode_for_ash(void)
2378{
2379
2380
2381
2382
2383 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2384 || ENABLE_UNICODE_USING_LOCALE
2385 ) {
2386 const char *s = lookupvar("LC_ALL");
2387 if (!s) s = lookupvar("LC_CTYPE");
2388 if (!s) s = lookupvar("LANG");
2389 reinit_unicode(s);
2390 }
2391}
2392#else
2393# define reinit_unicode_for_ash() ((void)0)
2394#endif
2395
2396
2397
2398
2399static ALWAYS_INLINE const char *
2400bltinlookup(const char *name)
2401{
2402 return lookupvar(name);
2403}
2404
2405
2406
2407
2408
2409
2410
2411
2412static struct var *
2413setvareq(char *s, int flags)
2414{
2415 struct var *vp, **vpp;
2416
2417 vpp = hashvar(s);
2418 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2419 vpp = findvar(vpp, s);
2420 vp = *vpp;
2421 if (vp) {
2422 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2423 const char *n;
2424
2425 if (flags & VNOSAVE)
2426 free(s);
2427 n = vp->var_text;
2428 exitstatus = 1;
2429 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2430 }
2431
2432 if (flags & VNOSET)
2433 goto out;
2434
2435 if (vp->var_func && !(flags & VNOFUNC))
2436 vp->var_func(var_end(s));
2437
2438 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2439 free((char*)vp->var_text);
2440
2441 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2442 *vpp = vp->next;
2443 free(vp);
2444 out_free:
2445 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2446 free(s);
2447 goto out;
2448 }
2449
2450 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2451#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2452 if (flags & VUNSET)
2453 flags &= ~VDYNAMIC;
2454#endif
2455 } else {
2456
2457 if (flags & VNOSET)
2458 goto out;
2459 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2460 goto out_free;
2461 vp = ckzalloc(sizeof(*vp));
2462 vp->next = *vpp;
2463
2464 *vpp = vp;
2465 }
2466 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2467 s = ckstrdup(s);
2468 vp->var_text = s;
2469 vp->flags = flags;
2470
2471 out:
2472 return vp;
2473}
2474
2475
2476
2477
2478
2479static struct var *
2480setvar(const char *name, const char *val, int flags)
2481{
2482 const char *q;
2483 char *p;
2484 char *nameeq;
2485 size_t namelen;
2486 size_t vallen;
2487 struct var *vp;
2488
2489 q = endofname(name);
2490 p = strchrnul(q, '=');
2491 namelen = p - name;
2492 if (!namelen || p != q)
2493 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2494 vallen = 0;
2495 if (val == NULL) {
2496 flags |= VUNSET;
2497 } else {
2498 vallen = strlen(val);
2499 }
2500
2501 INT_OFF;
2502 nameeq = ckzalloc(namelen + vallen + 2);
2503 p = mempcpy(nameeq, name, namelen);
2504 if (val) {
2505 *p++ = '=';
2506 memcpy(p, val, vallen);
2507 }
2508 vp = setvareq(nameeq, flags | VNOSAVE);
2509 INT_ON;
2510
2511 return vp;
2512}
2513
2514static void FAST_FUNC
2515setvar0(const char *name, const char *val)
2516{
2517 setvar(name, val, 0);
2518}
2519
2520
2521
2522
2523static void
2524unsetvar(const char *s)
2525{
2526 setvar(s, NULL, 0);
2527}
2528
2529
2530
2531
2532#if !ENABLE_FEATURE_SH_NOFORK
2533# define listvars(on, off, lp, end) listvars(on, off, end)
2534#endif
2535static char **
2536listvars(int on, int off, struct strlist *lp, char ***end)
2537{
2538 struct var **vpp;
2539 struct var *vp;
2540 char **ep;
2541 int mask;
2542
2543 STARTSTACKSTR(ep);
2544 vpp = vartab;
2545 mask = on | off;
2546 do {
2547 for (vp = *vpp; vp; vp = vp->next) {
2548 if ((vp->flags & mask) == on) {
2549#if ENABLE_FEATURE_SH_NOFORK
2550
2551
2552
2553
2554
2555
2556
2557 struct strlist *lp1 = lp;
2558 while (lp1) {
2559 if (strcmp(lp1->text, vp->var_text) == 0)
2560 goto skip;
2561 lp1 = lp1->next;
2562 }
2563#endif
2564 if (ep == stackstrend())
2565 ep = growstackstr();
2566 *ep++ = (char*)vp->var_text;
2567#if ENABLE_FEATURE_SH_NOFORK
2568 skip: ;
2569#endif
2570 }
2571 }
2572 } while (++vpp < vartab + VTABSIZE);
2573
2574#if ENABLE_FEATURE_SH_NOFORK
2575 while (lp) {
2576 if (ep == stackstrend())
2577 ep = growstackstr();
2578 *ep++ = lp->text;
2579 lp = lp->next;
2580 }
2581#endif
2582
2583 if (ep == stackstrend())
2584 ep = growstackstr();
2585 if (end)
2586 *end = ep;
2587 *ep++ = NULL;
2588 return grabstackstr(ep);
2589}
2590
2591
2592
2593static const char *
2594legal_pathopt(const char *opt, const char *term, int magic)
2595{
2596 switch (magic) {
2597 case 0:
2598 opt = NULL;
2599 break;
2600
2601 case 1:
2602 opt = prefix(opt, "builtin") ?: prefix(opt, "func");
2603 break;
2604
2605 default:
2606 opt += strcspn(opt, term);
2607 break;
2608 }
2609
2610 if (opt && *opt == '%')
2611 opt++;
2612
2613 return opt;
2614}
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629static const char *pathopt;
2630
2631static int
2632padvance_magic(const char **path, const char *name, int magic)
2633{
2634 const char *term = "%:";
2635 const char *lpathopt;
2636 const char *p;
2637 char *q;
2638 const char *start;
2639 size_t qlen;
2640 size_t len;
2641
2642 if (*path == NULL)
2643 return -1;
2644
2645 lpathopt = NULL;
2646 start = *path;
2647
2648 if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) {
2649 lpathopt = start + 1;
2650 start = p;
2651 term = ":";
2652 }
2653
2654 len = strcspn(start, term);
2655 p = start + len;
2656
2657 if (*p == '%') {
2658 size_t extra = strchrnul(p, ':') - p;
2659
2660 if (legal_pathopt(p + 1, term, magic))
2661 lpathopt = p + 1;
2662 else
2663 len += extra;
2664
2665 p += extra;
2666 }
2667
2668 pathopt = lpathopt;
2669 *path = *p == ':' ? p + 1 : NULL;
2670
2671
2672 qlen = len + strlen(name) + 2;
2673 q = growstackto(qlen);
2674
2675 if (len) {
2676 q = mempcpy(q, start, len);
2677 *q++ = '/';
2678 }
2679 strcpy(q, name);
2680
2681 return qlen;
2682}
2683
2684static int
2685padvance(const char **path, const char *name)
2686{
2687 return padvance_magic(path, name, 1);
2688}
2689
2690
2691
2692
2693static smallint doprompt;
2694static smallint needprompt;
2695
2696#if ENABLE_FEATURE_EDITING
2697static line_input_t *line_input_state;
2698static const char *cmdedit_prompt;
2699static void
2700putprompt(const char *s)
2701{
2702 if (ENABLE_ASH_EXPAND_PRMT) {
2703 free((char*)cmdedit_prompt);
2704 cmdedit_prompt = ckstrdup(s);
2705 return;
2706 }
2707 cmdedit_prompt = s;
2708}
2709#else
2710static void
2711putprompt(const char *s)
2712{
2713 out2str(s);
2714}
2715#endif
2716
2717
2718static const char *expandstr(const char *ps, int syntax_type);
2719
2720#define BASESYNTAX 0
2721#define DQSYNTAX 1
2722#define SQSYNTAX 2
2723#define ARISYNTAX 3
2724#if ENABLE_ASH_EXPAND_PRMT
2725# define PSSYNTAX 4
2726#endif
2727
2728
2729
2730
2731
2732static void
2733setprompt_if(smallint do_set, int whichprompt)
2734{
2735 const char *prompt;
2736 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2737
2738 if (!do_set)
2739 return;
2740
2741 needprompt = 0;
2742
2743 switch (whichprompt) {
2744 case 1:
2745 prompt = ps1val();
2746 break;
2747 case 2:
2748 prompt = ps2val();
2749 break;
2750 default:
2751 prompt = nullstr;
2752 }
2753#if ENABLE_ASH_EXPAND_PRMT
2754 pushstackmark(&smark, stackblocksize());
2755 putprompt(expandstr(prompt, PSSYNTAX));
2756 popstackmark(&smark);
2757#else
2758 putprompt(prompt);
2759#endif
2760}
2761
2762
2763
2764
2765#define CD_PHYSICAL 1
2766#define CD_PRINT 2
2767
2768static int
2769cdopt(void)
2770{
2771 int flags = 0;
2772 int i, j;
2773
2774 j = 'L';
2775 while ((i = nextopt("LP")) != '\0') {
2776 if (i != j) {
2777 flags ^= CD_PHYSICAL;
2778 j = i;
2779 }
2780 }
2781
2782 return flags;
2783}
2784
2785
2786
2787
2788
2789static const char *
2790updatepwd(const char *dir)
2791{
2792 char *new;
2793 char *p;
2794 char *cdcomppath;
2795 const char *lim;
2796
2797 cdcomppath = sstrdup(dir);
2798 STARTSTACKSTR(new);
2799 if (*dir != '/') {
2800 if (curdir == nullstr)
2801 return 0;
2802 new = stack_putstr(curdir, new);
2803 }
2804 new = makestrspace(strlen(dir) + 2, new);
2805 lim = (char *)stackblock() + 1;
2806 if (*dir != '/') {
2807 if (new[-1] != '/')
2808 USTPUTC('/', new);
2809 if (new > lim && *lim == '/')
2810 lim++;
2811 } else {
2812 USTPUTC('/', new);
2813 cdcomppath++;
2814 if (dir[1] == '/' && dir[2] != '/') {
2815 USTPUTC('/', new);
2816 cdcomppath++;
2817 lim++;
2818 }
2819 }
2820 p = strtok_r(cdcomppath, "/", &cdcomppath);
2821 while (p) {
2822 switch (*p) {
2823 case '.':
2824 if (p[1] == '.' && p[2] == '\0') {
2825 while (new > lim) {
2826 STUNPUTC(new);
2827 if (new[-1] == '/')
2828 break;
2829 }
2830 break;
2831 }
2832 if (p[1] == '\0')
2833 break;
2834
2835 default:
2836 new = stack_putstr(p, new);
2837 USTPUTC('/', new);
2838 }
2839 p = strtok_r(NULL, "/", &cdcomppath);
2840 }
2841 if (new > lim)
2842 STUNPUTC(new);
2843 *new = 0;
2844 return stackblock();
2845}
2846
2847
2848
2849
2850
2851static char *
2852getpwd(void)
2853{
2854 char *dir = getcwd(NULL, 0);
2855 return dir ? dir : nullstr;
2856}
2857
2858static void
2859setpwd(const char *val, int setold)
2860{
2861 char *oldcur, *dir;
2862
2863 oldcur = dir = curdir;
2864
2865 if (setold) {
2866 setvar("OLDPWD", oldcur, VEXPORT);
2867 }
2868 INT_OFF;
2869 if (physdir != nullstr) {
2870 if (physdir != oldcur)
2871 free(physdir);
2872 physdir = nullstr;
2873 }
2874 if (oldcur == val || !val) {
2875 char *s = getpwd();
2876 physdir = s;
2877 if (!val)
2878 dir = s;
2879 } else
2880 dir = ckstrdup(val);
2881 if (oldcur != dir && oldcur != nullstr) {
2882 free(oldcur);
2883 }
2884 curdir = dir;
2885 INT_ON;
2886 setvar("PWD", dir, VEXPORT);
2887}
2888
2889static void hashcd(void);
2890
2891
2892
2893
2894
2895static int
2896docd(const char *dest, int flags)
2897{
2898 const char *dir = NULL;
2899 int err;
2900
2901 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2902
2903 INT_OFF;
2904 if (!(flags & CD_PHYSICAL)) {
2905 dir = updatepwd(dest);
2906 if (dir)
2907 dest = dir;
2908 }
2909 err = chdir(dest);
2910 if (err)
2911 goto out;
2912 setpwd(dir, 1);
2913 hashcd();
2914 out:
2915 INT_ON;
2916 return err;
2917}
2918
2919static int FAST_FUNC
2920cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2921{
2922 const char *dest;
2923 const char *path;
2924 const char *p;
2925 char c;
2926 struct stat statb;
2927 int flags;
2928 int len;
2929
2930 flags = cdopt();
2931 dest = *argptr;
2932 if (!dest)
2933 dest = bltinlookup("HOME");
2934 else if (LONE_DASH(dest)) {
2935 dest = bltinlookup("OLDPWD");
2936 flags |= CD_PRINT;
2937 }
2938 if (!dest)
2939 dest = nullstr;
2940 if (*dest == '/')
2941 goto step6;
2942 if (*dest == '.') {
2943 c = dest[1];
2944 dotdot:
2945 switch (c) {
2946 case '\0':
2947 case '/':
2948 goto step6;
2949 case '.':
2950 c = dest[2];
2951 if (c != '.')
2952 goto dotdot;
2953 }
2954 }
2955 if (!*dest)
2956 dest = ".";
2957 path = bltinlookup("CDPATH");
2958 while (p = path, (len = padvance(&path, dest)) >= 0) {
2959 c = *p;
2960 p = stalloc(len);
2961
2962 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2963 if (c && c != ':')
2964 flags |= CD_PRINT;
2965 docd:
2966 if (!docd(p, flags))
2967 goto out;
2968 goto err;
2969 }
2970 }
2971
2972 step6:
2973 p = dest;
2974 goto docd;
2975
2976 err:
2977 ash_msg_and_raise_perror("can't cd to %s", dest);
2978
2979 out:
2980 if (flags & CD_PRINT)
2981 out1fmt("%s\n", curdir);
2982 return 0;
2983}
2984
2985static int FAST_FUNC
2986pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2987{
2988 int flags;
2989 const char *dir = curdir;
2990
2991 flags = cdopt();
2992 if (flags) {
2993 if (physdir == nullstr)
2994 setpwd(dir, 0);
2995 dir = physdir;
2996 }
2997 out1fmt("%s\n", dir);
2998 return 0;
2999}
3000
3001
3002
3003
3004
3005#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
3006
3007
3008#define CWORD 0
3009#define CNL 1
3010#define CBACK 2
3011#define CSQUOTE 3
3012#define CDQUOTE 4
3013#define CENDQUOTE 5
3014#define CBQUOTE 6
3015#define CVAR 7
3016#define CENDVAR 8
3017#define CLP 9
3018#define CRP 10
3019#define CENDFILE 11
3020#define CCTL 12
3021#define CSPCL 13
3022
3023#define PEOF 256
3024
3025#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
3026
3027#if ENABLE_FEATURE_SH_MATH
3028# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
3029#else
3030# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
3031#endif
3032static const uint16_t S_I_T[] ALIGN2 = {
3033 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ),
3034 SIT_ITEM(CNL , CNL , CNL , CNL ),
3035 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ),
3036 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ),
3037 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ),
3038 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD),
3039 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ),
3040 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ),
3041 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ),
3042 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE),
3043 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR),
3044#if !USE_SIT_FUNCTION
3045 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),
3046 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ),
3047 SIT_ITEM(CCTL , CCTL , CCTL , CCTL )
3048#endif
3049#undef SIT_ITEM
3050};
3051
3052enum {
3053 CSPCL_CWORD_CWORD_CWORD ,
3054 CNL_CNL_CNL_CNL ,
3055 CWORD_CCTL_CCTL_CWORD ,
3056 CDQUOTE_CENDQUOTE_CWORD_CWORD ,
3057 CVAR_CVAR_CWORD_CVAR ,
3058 CSQUOTE_CWORD_CENDQUOTE_CWORD ,
3059 CSPCL_CWORD_CWORD_CLP ,
3060 CSPCL_CWORD_CWORD_CRP ,
3061 CBACK_CBACK_CCTL_CBACK ,
3062 CBQUOTE_CBQUOTE_CWORD_CBQUOTE ,
3063 CENDVAR_CENDVAR_CWORD_CENDVAR ,
3064 CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3065 CWORD_CWORD_CWORD_CWORD ,
3066 CCTL_CCTL_CCTL_CCTL ,
3067};
3068
3069
3070
3071
3072#if USE_SIT_FUNCTION
3073
3074static int
3075SIT(int c, int syntax)
3076{
3077
3078 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
3079
3080
3081
3082
3083
3084
3085
3086
3087 static const uint8_t syntax_index_table[] ALIGN1 = {
3088 0, 1, 0, 2, 3, 4, 0, 5,
3089 6, 7, 2, 2,2, 0, 0,
3090 2, 0, 2, 2, 8, 2, 9, 0,
3091 10, 2
3092 };
3093 const char *s;
3094 int indx;
3095
3096 if (c == PEOF)
3097 return CENDFILE;
3098
3099
3100 if ((unsigned char)c >= CTL_FIRST
3101 && (unsigned char)c <= CTL_LAST
3102 ) {
3103 return CCTL;
3104 }
3105 s = strchrnul(spec_symbls, c);
3106 if (*s == '\0')
3107 return CWORD;
3108 indx = syntax_index_table[s - spec_symbls];
3109 return (S_I_T[indx] >> (syntax*4)) & 0xf;
3110}
3111
3112#else
3113
3114static const uint8_t syntax_index_table[] ALIGN1 = {
3115
3116 CWORD_CWORD_CWORD_CWORD,
3117 CWORD_CWORD_CWORD_CWORD,
3118 CWORD_CWORD_CWORD_CWORD,
3119 CWORD_CWORD_CWORD_CWORD,
3120 CWORD_CWORD_CWORD_CWORD,
3121 CWORD_CWORD_CWORD_CWORD,
3122 CWORD_CWORD_CWORD_CWORD,
3123 CWORD_CWORD_CWORD_CWORD,
3124 CWORD_CWORD_CWORD_CWORD,
3125 CSPCL_CWORD_CWORD_CWORD,
3126 CNL_CNL_CNL_CNL,
3127 CWORD_CWORD_CWORD_CWORD,
3128 CWORD_CWORD_CWORD_CWORD,
3129 CWORD_CWORD_CWORD_CWORD,
3130 CWORD_CWORD_CWORD_CWORD,
3131 CWORD_CWORD_CWORD_CWORD,
3132 CWORD_CWORD_CWORD_CWORD,
3133 CWORD_CWORD_CWORD_CWORD,
3134 CWORD_CWORD_CWORD_CWORD,
3135 CWORD_CWORD_CWORD_CWORD,
3136 CWORD_CWORD_CWORD_CWORD,
3137 CWORD_CWORD_CWORD_CWORD,
3138 CWORD_CWORD_CWORD_CWORD,
3139 CWORD_CWORD_CWORD_CWORD,
3140 CWORD_CWORD_CWORD_CWORD,
3141 CWORD_CWORD_CWORD_CWORD,
3142 CWORD_CWORD_CWORD_CWORD,
3143 CWORD_CWORD_CWORD_CWORD,
3144 CWORD_CWORD_CWORD_CWORD,
3145 CWORD_CWORD_CWORD_CWORD,
3146 CWORD_CWORD_CWORD_CWORD,
3147 CWORD_CWORD_CWORD_CWORD,
3148 CSPCL_CWORD_CWORD_CWORD,
3149 CWORD_CCTL_CCTL_CWORD,
3150 CDQUOTE_CENDQUOTE_CWORD_CWORD,
3151 CWORD_CWORD_CWORD_CWORD,
3152 CVAR_CVAR_CWORD_CVAR,
3153 CWORD_CWORD_CWORD_CWORD,
3154 CSPCL_CWORD_CWORD_CWORD,
3155 CSQUOTE_CWORD_CENDQUOTE_CWORD,
3156 CSPCL_CWORD_CWORD_CLP,
3157 CSPCL_CWORD_CWORD_CRP,
3158 CWORD_CCTL_CCTL_CWORD,
3159 CWORD_CWORD_CWORD_CWORD,
3160 CWORD_CWORD_CWORD_CWORD,
3161 CWORD_CCTL_CCTL_CWORD,
3162 CWORD_CWORD_CWORD_CWORD,
3163
3164 CWORD_CWORD_CWORD_CWORD,
3165 CWORD_CWORD_CWORD_CWORD,
3166 CWORD_CWORD_CWORD_CWORD,
3167 CWORD_CWORD_CWORD_CWORD,
3168 CWORD_CWORD_CWORD_CWORD,
3169 CWORD_CWORD_CWORD_CWORD,
3170 CWORD_CWORD_CWORD_CWORD,
3171 CWORD_CWORD_CWORD_CWORD,
3172 CWORD_CWORD_CWORD_CWORD,
3173 CWORD_CWORD_CWORD_CWORD,
3174 CWORD_CWORD_CWORD_CWORD,
3175 CWORD_CCTL_CCTL_CWORD,
3176 CSPCL_CWORD_CWORD_CWORD,
3177 CSPCL_CWORD_CWORD_CWORD,
3178 CWORD_CCTL_CCTL_CWORD,
3179 CSPCL_CWORD_CWORD_CWORD,
3180 CWORD_CCTL_CCTL_CWORD,
3181 CWORD_CWORD_CWORD_CWORD,
3182 CWORD_CWORD_CWORD_CWORD,
3183 CWORD_CWORD_CWORD_CWORD,
3184 CWORD_CWORD_CWORD_CWORD,
3185 CWORD_CWORD_CWORD_CWORD,
3186 CWORD_CWORD_CWORD_CWORD,
3187 CWORD_CWORD_CWORD_CWORD,
3188 CWORD_CWORD_CWORD_CWORD,
3189 CWORD_CWORD_CWORD_CWORD,
3190 CWORD_CWORD_CWORD_CWORD,
3191 CWORD_CWORD_CWORD_CWORD,
3192 CWORD_CWORD_CWORD_CWORD,
3193 CWORD_CWORD_CWORD_CWORD,
3194 CWORD_CWORD_CWORD_CWORD,
3195 CWORD_CWORD_CWORD_CWORD,
3196 CWORD_CWORD_CWORD_CWORD,
3197 CWORD_CWORD_CWORD_CWORD,
3198 CWORD_CWORD_CWORD_CWORD,
3199 CWORD_CWORD_CWORD_CWORD,
3200 CWORD_CWORD_CWORD_CWORD,
3201 CWORD_CWORD_CWORD_CWORD,
3202 CWORD_CWORD_CWORD_CWORD,
3203 CWORD_CWORD_CWORD_CWORD,
3204 CWORD_CWORD_CWORD_CWORD,
3205 CWORD_CWORD_CWORD_CWORD,
3206 CWORD_CWORD_CWORD_CWORD,
3207 CWORD_CWORD_CWORD_CWORD,
3208 CWORD_CCTL_CCTL_CWORD,
3209 CBACK_CBACK_CCTL_CBACK,
3210 CWORD_CCTL_CCTL_CWORD,
3211 CWORD_CWORD_CWORD_CWORD,
3212 CWORD_CWORD_CWORD_CWORD,
3213 CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3214 CWORD_CWORD_CWORD_CWORD,
3215 CWORD_CWORD_CWORD_CWORD,
3216 CWORD_CWORD_CWORD_CWORD,
3217 CWORD_CWORD_CWORD_CWORD,
3218 CWORD_CWORD_CWORD_CWORD,
3219 CWORD_CWORD_CWORD_CWORD,
3220 CWORD_CWORD_CWORD_CWORD,
3221 CWORD_CWORD_CWORD_CWORD,
3222 CWORD_CWORD_CWORD_CWORD,
3223 CWORD_CWORD_CWORD_CWORD,
3224 CWORD_CWORD_CWORD_CWORD,
3225 CWORD_CWORD_CWORD_CWORD,
3226 CWORD_CWORD_CWORD_CWORD,
3227 CWORD_CWORD_CWORD_CWORD,
3228 CWORD_CWORD_CWORD_CWORD,
3229 CWORD_CWORD_CWORD_CWORD,
3230 CWORD_CWORD_CWORD_CWORD,
3231 CWORD_CWORD_CWORD_CWORD,
3232 CWORD_CWORD_CWORD_CWORD,
3233 CWORD_CWORD_CWORD_CWORD,
3234 CWORD_CWORD_CWORD_CWORD,
3235 CWORD_CWORD_CWORD_CWORD,
3236 CWORD_CWORD_CWORD_CWORD,
3237 CWORD_CWORD_CWORD_CWORD,
3238 CWORD_CWORD_CWORD_CWORD,
3239 CWORD_CWORD_CWORD_CWORD,
3240 CWORD_CWORD_CWORD_CWORD,
3241 CSPCL_CWORD_CWORD_CWORD,
3242 CENDVAR_CENDVAR_CWORD_CENDVAR,
3243 CWORD_CCTL_CCTL_CWORD,
3244 CWORD_CWORD_CWORD_CWORD,
3245 CWORD_CWORD_CWORD_CWORD,
3246 CCTL_CCTL_CCTL_CCTL,
3247 CCTL_CCTL_CCTL_CCTL,
3248 CCTL_CCTL_CCTL_CCTL,
3249 CCTL_CCTL_CCTL_CCTL,
3250 CCTL_CCTL_CCTL_CCTL,
3251 CCTL_CCTL_CCTL_CCTL,
3252 CCTL_CCTL_CCTL_CCTL,
3253 CCTL_CCTL_CCTL_CCTL,
3254#if BASH_PROCESS_SUBST
3255 CCTL_CCTL_CCTL_CCTL,
3256 CCTL_CCTL_CCTL_CCTL,
3257#else
3258 CWORD_CWORD_CWORD_CWORD,
3259 CWORD_CWORD_CWORD_CWORD,
3260#endif
3261 CWORD_CWORD_CWORD_CWORD,
3262 CWORD_CWORD_CWORD_CWORD,
3263 CWORD_CWORD_CWORD_CWORD,
3264 CWORD_CWORD_CWORD_CWORD,
3265 CWORD_CWORD_CWORD_CWORD,
3266 CWORD_CWORD_CWORD_CWORD,
3267 CWORD_CWORD_CWORD_CWORD,
3268 CWORD_CWORD_CWORD_CWORD,
3269 CWORD_CWORD_CWORD_CWORD,
3270 CWORD_CWORD_CWORD_CWORD,
3271 CWORD_CWORD_CWORD_CWORD,
3272 CWORD_CWORD_CWORD_CWORD,
3273 CWORD_CWORD_CWORD_CWORD,
3274 CWORD_CWORD_CWORD_CWORD,
3275 CWORD_CWORD_CWORD_CWORD,
3276 CWORD_CWORD_CWORD_CWORD,
3277 CWORD_CWORD_CWORD_CWORD,
3278 CWORD_CWORD_CWORD_CWORD,
3279 CWORD_CWORD_CWORD_CWORD,
3280 CWORD_CWORD_CWORD_CWORD,
3281 CWORD_CWORD_CWORD_CWORD,
3282 CWORD_CWORD_CWORD_CWORD,
3283 CWORD_CWORD_CWORD_CWORD,
3284 CWORD_CWORD_CWORD_CWORD,
3285 CWORD_CWORD_CWORD_CWORD,
3286 CWORD_CWORD_CWORD_CWORD,
3287 CWORD_CWORD_CWORD_CWORD,
3288 CWORD_CWORD_CWORD_CWORD,
3289 CWORD_CWORD_CWORD_CWORD,
3290 CWORD_CWORD_CWORD_CWORD,
3291 CWORD_CWORD_CWORD_CWORD,
3292 CWORD_CWORD_CWORD_CWORD,
3293 CWORD_CWORD_CWORD_CWORD,
3294 CWORD_CWORD_CWORD_CWORD,
3295 CWORD_CWORD_CWORD_CWORD,
3296 CWORD_CWORD_CWORD_CWORD,
3297 CWORD_CWORD_CWORD_CWORD,
3298 CWORD_CWORD_CWORD_CWORD,
3299 CWORD_CWORD_CWORD_CWORD,
3300 CWORD_CWORD_CWORD_CWORD,
3301 CWORD_CWORD_CWORD_CWORD,
3302 CWORD_CWORD_CWORD_CWORD,
3303 CWORD_CWORD_CWORD_CWORD,
3304 CWORD_CWORD_CWORD_CWORD,
3305 CWORD_CWORD_CWORD_CWORD,
3306 CWORD_CWORD_CWORD_CWORD,
3307 CWORD_CWORD_CWORD_CWORD,
3308 CWORD_CWORD_CWORD_CWORD,
3309 CWORD_CWORD_CWORD_CWORD,
3310 CWORD_CWORD_CWORD_CWORD,
3311 CWORD_CWORD_CWORD_CWORD,
3312 CWORD_CWORD_CWORD_CWORD,
3313 CWORD_CWORD_CWORD_CWORD,
3314 CWORD_CWORD_CWORD_CWORD,
3315 CWORD_CWORD_CWORD_CWORD,
3316 CWORD_CWORD_CWORD_CWORD,
3317 CWORD_CWORD_CWORD_CWORD,
3318 CWORD_CWORD_CWORD_CWORD,
3319 CWORD_CWORD_CWORD_CWORD,
3320 CWORD_CWORD_CWORD_CWORD,
3321 CWORD_CWORD_CWORD_CWORD,
3322 CWORD_CWORD_CWORD_CWORD,
3323 CWORD_CWORD_CWORD_CWORD,
3324 CWORD_CWORD_CWORD_CWORD,
3325 CWORD_CWORD_CWORD_CWORD,
3326 CWORD_CWORD_CWORD_CWORD,
3327 CWORD_CWORD_CWORD_CWORD,
3328 CWORD_CWORD_CWORD_CWORD,
3329 CWORD_CWORD_CWORD_CWORD,
3330 CWORD_CWORD_CWORD_CWORD,
3331 CWORD_CWORD_CWORD_CWORD,
3332 CWORD_CWORD_CWORD_CWORD,
3333 CWORD_CWORD_CWORD_CWORD,
3334 CWORD_CWORD_CWORD_CWORD,
3335 CWORD_CWORD_CWORD_CWORD,
3336 CWORD_CWORD_CWORD_CWORD,
3337 CWORD_CWORD_CWORD_CWORD,
3338 CWORD_CWORD_CWORD_CWORD,
3339 CWORD_CWORD_CWORD_CWORD,
3340 CWORD_CWORD_CWORD_CWORD,
3341 CWORD_CWORD_CWORD_CWORD,
3342 CWORD_CWORD_CWORD_CWORD,
3343 CWORD_CWORD_CWORD_CWORD,
3344 CWORD_CWORD_CWORD_CWORD,
3345 CWORD_CWORD_CWORD_CWORD,
3346 CWORD_CWORD_CWORD_CWORD,
3347 CWORD_CWORD_CWORD_CWORD,
3348 CWORD_CWORD_CWORD_CWORD,
3349 CWORD_CWORD_CWORD_CWORD,
3350 CWORD_CWORD_CWORD_CWORD,
3351 CWORD_CWORD_CWORD_CWORD,
3352 CWORD_CWORD_CWORD_CWORD,
3353 CWORD_CWORD_CWORD_CWORD,
3354 CWORD_CWORD_CWORD_CWORD,
3355 CWORD_CWORD_CWORD_CWORD,
3356 CWORD_CWORD_CWORD_CWORD,
3357 CWORD_CWORD_CWORD_CWORD,
3358 CWORD_CWORD_CWORD_CWORD,
3359 CWORD_CWORD_CWORD_CWORD,
3360 CWORD_CWORD_CWORD_CWORD,
3361 CWORD_CWORD_CWORD_CWORD,
3362 CWORD_CWORD_CWORD_CWORD,
3363 CWORD_CWORD_CWORD_CWORD,
3364 CWORD_CWORD_CWORD_CWORD,
3365 CWORD_CWORD_CWORD_CWORD,
3366 CWORD_CWORD_CWORD_CWORD,
3367 CWORD_CWORD_CWORD_CWORD,
3368 CWORD_CWORD_CWORD_CWORD,
3369 CWORD_CWORD_CWORD_CWORD,
3370 CWORD_CWORD_CWORD_CWORD,
3371 CWORD_CWORD_CWORD_CWORD,
3372 CWORD_CWORD_CWORD_CWORD,
3373 CWORD_CWORD_CWORD_CWORD,
3374 CWORD_CWORD_CWORD_CWORD,
3375 CWORD_CWORD_CWORD_CWORD,
3376 CWORD_CWORD_CWORD_CWORD,
3377 CWORD_CWORD_CWORD_CWORD,
3378 CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3379};
3380
3381#if 1
3382# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3383#else
3384# define SIT(c, syntax) \
3385 ({ \
3386 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3387 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3388 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3389 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3390 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3391 })
3392#endif
3393
3394#endif
3395
3396
3397
3398
3399#if ENABLE_ASH_ALIAS
3400
3401#define ALIASINUSE 1
3402#define ALIASDEAD 2
3403
3404struct alias {
3405 struct alias *next;
3406 char *name;
3407 char *val;
3408 int flag;
3409};
3410
3411
3412static struct alias **atab;
3413#define INIT_G_alias() do { \
3414 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3415} while (0)
3416
3417
3418static struct alias **
3419__lookupalias(const char *name)
3420{
3421 unsigned int hashval;
3422 struct alias **app;
3423 const char *p;
3424 unsigned int ch;
3425
3426 p = name;
3427
3428 ch = (unsigned char)*p;
3429 hashval = ch << 4;
3430 while (ch) {
3431 hashval += ch;
3432 ch = (unsigned char)*++p;
3433 }
3434 app = &atab[hashval % ATABSIZE];
3435
3436 for (; *app; app = &(*app)->next) {
3437 if (strcmp(name, (*app)->name) == 0) {
3438 break;
3439 }
3440 }
3441
3442 return app;
3443}
3444
3445static struct alias *
3446lookupalias(const char *name, int check)
3447{
3448 struct alias *ap = *__lookupalias(name);
3449
3450 if (check && ap && (ap->flag & ALIASINUSE))
3451 return NULL;
3452 return ap;
3453}
3454
3455static struct alias *
3456freealias(struct alias *ap)
3457{
3458 struct alias *next;
3459
3460 if (ap->flag & ALIASINUSE) {
3461 ap->flag |= ALIASDEAD;
3462 return ap;
3463 }
3464
3465 next = ap->next;
3466 free(ap->name);
3467 free(ap->val);
3468 free(ap);
3469 return next;
3470}
3471
3472static void
3473setalias(const char *name, const char *val)
3474{
3475 struct alias *ap, **app;
3476
3477 app = __lookupalias(name);
3478 ap = *app;
3479 INT_OFF;
3480 if (ap) {
3481 if (!(ap->flag & ALIASINUSE)) {
3482 free(ap->val);
3483 }
3484 ap->val = ckstrdup(val);
3485 ap->flag &= ~ALIASDEAD;
3486 } else {
3487
3488 ap = ckzalloc(sizeof(struct alias));
3489 ap->name = ckstrdup(name);
3490 ap->val = ckstrdup(val);
3491
3492
3493 *app = ap;
3494 }
3495 INT_ON;
3496}
3497
3498static int
3499unalias(const char *name)
3500{
3501 struct alias **app;
3502
3503 app = __lookupalias(name);
3504
3505 if (*app) {
3506 INT_OFF;
3507 *app = freealias(*app);
3508 INT_ON;
3509 return 0;
3510 }
3511
3512 return 1;
3513}
3514
3515static void
3516rmaliases(void)
3517{
3518 struct alias *ap, **app;
3519 int i;
3520
3521 INT_OFF;
3522 for (i = 0; i < ATABSIZE; i++) {
3523 app = &atab[i];
3524 for (ap = *app; ap; ap = *app) {
3525 *app = freealias(*app);
3526 if (ap == *app) {
3527 app = &ap->next;
3528 }
3529 }
3530 }
3531 INT_ON;
3532}
3533
3534static void
3535printalias(const struct alias *ap)
3536{
3537 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3538}
3539
3540
3541
3542
3543static int FAST_FUNC
3544aliascmd(int argc UNUSED_PARAM, char **argv)
3545{
3546 char *n, *v;
3547 int ret = 0;
3548 struct alias *ap;
3549
3550 if (!argv[1]) {
3551 int i;
3552
3553 for (i = 0; i < ATABSIZE; i++) {
3554 for (ap = atab[i]; ap; ap = ap->next) {
3555 printalias(ap);
3556 }
3557 }
3558 return 0;
3559 }
3560 while ((n = *++argv) != NULL) {
3561 v = strchr(n+1, '=');
3562 if (v == NULL) {
3563 ap = *__lookupalias(n);
3564 if (ap == NULL) {
3565 fprintf(stderr, "%s: %s not found\n", "alias", n);
3566 ret = 1;
3567 } else
3568 printalias(ap);
3569 } else {
3570 *v++ = '\0';
3571 setalias(n, v);
3572 }
3573 }
3574
3575 return ret;
3576}
3577
3578static int FAST_FUNC
3579unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3580{
3581 int i;
3582
3583 while (nextopt("a") != '\0') {
3584 rmaliases();
3585 return 0;
3586 }
3587 for (i = 0; *argptr; argptr++) {
3588 if (unalias(*argptr)) {
3589 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3590 i = 1;
3591 }
3592 }
3593
3594 return i;
3595}
3596
3597#endif
3598
3599
3600
3601#define FORK_FG 0
3602#define FORK_BG 1
3603#define FORK_NOJOB 2
3604
3605
3606#define SHOW_ONLY_PGID 0x01
3607#define SHOW_PIDS 0x02
3608#define SHOW_CHANGED 0x04
3609#define SHOW_STDERR 0x08
3610
3611
3612
3613
3614
3615
3616
3617struct procstat {
3618 pid_t ps_pid;
3619 int ps_status;
3620 char *ps_cmd;
3621};
3622
3623struct job {
3624 struct procstat ps0;
3625 struct procstat *ps;
3626#if JOBS
3627 int stopstatus;
3628#endif
3629 unsigned nprocs;
3630
3631#define JOBRUNNING 0
3632#define JOBSTOPPED 1
3633#define JOBDONE 2
3634 unsigned
3635 state: 8,
3636#if JOBS
3637 sigint: 1,
3638 jobctl: 1,
3639#endif
3640 waited: 1,
3641 used: 1,
3642 changed: 1;
3643 struct job *prev_job;
3644};
3645
3646static struct job *makejob( int);
3647static int forkshell(struct job *, union node *, int);
3648static int waitforjob(struct job *);
3649
3650#if !JOBS
3651enum { doing_jobctl = 0 };
3652#define setjobctl(on) do {} while (0)
3653#else
3654static smallint doing_jobctl;
3655static void setjobctl(int);
3656#endif
3657
3658
3659
3660
3661static void
3662ignoresig(int signo)
3663{
3664
3665 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3666
3667 signal(signo, SIG_IGN);
3668 }
3669 sigmode[signo - 1] = S_HARD_IGN;
3670}
3671
3672
3673
3674
3675static void
3676signal_handler(int signo)
3677{
3678 if (signo == SIGCHLD) {
3679 got_sigchld = 1;
3680 if (!trap[SIGCHLD])
3681 return;
3682 }
3683
3684 gotsig[signo - 1] = 1;
3685 pending_sig = signo;
3686
3687 if (signo == SIGINT && !trap[SIGINT]) {
3688 if (!suppress_int) {
3689 pending_sig = 0;
3690 raise_interrupt();
3691 }
3692 pending_int = 1;
3693 }
3694}
3695
3696
3697
3698
3699
3700static void
3701setsignal(int signo)
3702{
3703 char *t;
3704 char cur_act, new_act;
3705 struct sigaction act;
3706
3707 t = trap[signo];
3708 new_act = S_DFL;
3709 if (t != NULL) {
3710 new_act = S_CATCH;
3711 if (t[0] == '\0')
3712 new_act = S_IGN;
3713 }
3714
3715 if (rootshell && new_act == S_DFL) {
3716 switch (signo) {
3717 case SIGINT:
3718 if (iflag || minusc || sflag == 0)
3719 new_act = S_CATCH;
3720 break;
3721 case SIGQUIT:
3722#if DEBUG
3723 if (debug)
3724 break;
3725#endif
3726
3727
3728
3729
3730
3731 new_act = S_IGN;
3732 break;
3733 case SIGTERM:
3734 if (iflag)
3735 new_act = S_IGN;
3736 break;
3737#if JOBS
3738 case SIGTSTP:
3739 case SIGTTOU:
3740 if (mflag)
3741 new_act = S_IGN;
3742 break;
3743#endif
3744 }
3745 }
3746
3747
3748
3749
3750
3751
3752
3753 if (signo == SIGCHLD)
3754 new_act = S_CATCH;
3755
3756 t = &sigmode[signo - 1];
3757 cur_act = *t;
3758 if (cur_act == 0) {
3759
3760 if (sigaction(signo, NULL, &act)) {
3761
3762
3763
3764
3765 return;
3766 }
3767 if (act.sa_handler == SIG_IGN) {
3768 cur_act = S_HARD_IGN;
3769 if (mflag
3770 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3771 ) {
3772 cur_act = S_IGN;
3773 }
3774 }
3775 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3776
3777
3778 *t = S_DFL;
3779 return;
3780 }
3781 }
3782 if (cur_act == S_HARD_IGN || cur_act == new_act)
3783 return;
3784
3785 *t = new_act;
3786
3787 act.sa_handler = SIG_DFL;
3788 switch (new_act) {
3789 case S_CATCH:
3790 act.sa_handler = signal_handler;
3791 break;
3792 case S_IGN:
3793 act.sa_handler = SIG_IGN;
3794 break;
3795 }
3796
3797
3798
3799 act.sa_flags = 0;
3800 sigfillset(&act.sa_mask);
3801
3802 sigaction_set(signo, &act);
3803}
3804
3805
3806#define CUR_DELETE 2
3807#define CUR_RUNNING 1
3808#define CUR_STOPPED 0
3809
3810#if JOBS
3811
3812static int initialpgrp;
3813static int ttyfd = -1;
3814#endif
3815
3816static struct job *jobtab;
3817
3818static unsigned njobs;
3819
3820static struct job *curjob;
3821
3822#if 0
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846static struct termios shell_tty_info;
3847static void
3848get_tty_state(void)
3849{
3850 if (rootshell && ttyfd >= 0)
3851 tcgetattr(ttyfd, &shell_tty_info);
3852}
3853static void
3854set_tty_state(void)
3855{
3856
3857 if (ttyfd >= 0)
3858 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3859}
3860static int
3861job_signal_status(struct job *jp)
3862{
3863 int status;
3864 unsigned i;
3865 struct procstat *ps = jp->ps;
3866 for (i = 0; i < jp->nprocs; i++) {
3867 status = ps[i].ps_status;
3868 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3869 return status;
3870 }
3871 return 0;
3872}
3873static void
3874restore_tty_if_stopped_or_signaled(struct job *jp)
3875{
3876
3877 if (rootshell) {
3878 int s = job_signal_status(jp);
3879 if (s)
3880 set_tty_state();
3881 }
3882}
3883#else
3884# define get_tty_state() ((void)0)
3885# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3886#endif
3887
3888static void
3889set_curjob(struct job *jp, unsigned mode)
3890{
3891 struct job *jp1;
3892 struct job **jpp, **curp;
3893
3894
3895 jpp = curp = &curjob;
3896 while (1) {
3897 jp1 = *jpp;
3898 if (jp1 == jp)
3899 break;
3900 jpp = &jp1->prev_job;
3901 }
3902 *jpp = jp1->prev_job;
3903
3904
3905 jpp = curp;
3906 switch (mode) {
3907 default:
3908#if DEBUG
3909 abort();
3910#endif
3911 case CUR_DELETE:
3912
3913 break;
3914 case CUR_RUNNING:
3915
3916
3917
3918 while (1) {
3919 jp1 = *jpp;
3920#if JOBS
3921 if (!jp1 || jp1->state != JOBSTOPPED)
3922#endif
3923 break;
3924 jpp = &jp1->prev_job;
3925 }
3926
3927#if JOBS
3928 case CUR_STOPPED:
3929#endif
3930
3931 jp->prev_job = *jpp;
3932 *jpp = jp;
3933 break;
3934 }
3935}
3936
3937#if JOBS || DEBUG
3938static int
3939jobno(const struct job *jp)
3940{
3941 return jp - jobtab + 1;
3942}
3943#endif
3944
3945
3946
3947
3948#if !JOBS
3949#define getjob(name, getctl) getjob(name)
3950#endif
3951static struct job *
3952getjob(const char *name, int getctl)
3953{
3954 struct job *jp;
3955 struct job *found;
3956 const char *err_msg = "%s: no such job";
3957 unsigned num;
3958 int c;
3959 const char *p;
3960 char *(*match)(const char *, const char *);
3961
3962 jp = curjob;
3963 p = name;
3964 if (!p)
3965 goto currentjob;
3966
3967 if (*p != '%')
3968 goto err;
3969
3970 c = *++p;
3971 if (!c)
3972 goto currentjob;
3973
3974 if (!p[1]) {
3975 if (c == '+' || c == '%') {
3976 currentjob:
3977 err_msg = "No current job";
3978 goto check;
3979 }
3980 if (c == '-') {
3981 if (jp)
3982 jp = jp->prev_job;
3983 err_msg = "No previous job";
3984 check:
3985 if (!jp)
3986 goto err;
3987 goto gotit;
3988 }
3989 }
3990
3991 if (is_number(p)) {
3992 num = atoi(p);
3993 if (num > 0 && num <= njobs) {
3994 jp = jobtab + num - 1;
3995 if (jp->used)
3996 goto gotit;
3997 goto err;
3998 }
3999 }
4000
4001 match = prefix;
4002 if (*p == '?') {
4003 match = strstr;
4004 p++;
4005 }
4006
4007 found = NULL;
4008 while (jp) {
4009 if (match(jp->ps[0].ps_cmd, p)) {
4010 if (found)
4011 goto err;
4012 found = jp;
4013 err_msg = "%s: ambiguous";
4014 }
4015 jp = jp->prev_job;
4016 }
4017 if (!found)
4018 goto err;
4019 jp = found;
4020
4021 gotit:
4022#if JOBS
4023 err_msg = "job %s not created under job control";
4024 if (getctl && jp->jobctl == 0)
4025 goto err;
4026#endif
4027 return jp;
4028 err:
4029 ash_msg_and_raise_error(err_msg, name);
4030}
4031
4032
4033
4034
4035static void
4036freejob(struct job *jp)
4037{
4038 struct procstat *ps;
4039 int i;
4040
4041 INT_OFF;
4042 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
4043 if (ps->ps_cmd != nullstr)
4044 free(ps->ps_cmd);
4045 }
4046 if (jp->ps != &jp->ps0)
4047 free(jp->ps);
4048 jp->used = 0;
4049 set_curjob(jp, CUR_DELETE);
4050 INT_ON;
4051}
4052
4053#if JOBS
4054static void
4055xtcsetpgrp(int fd, pid_t pgrp)
4056{
4057 if (tcsetpgrp(fd, pgrp))
4058 ash_msg_and_raise_perror("can't set tty process group");
4059}
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070static void
4071setjobctl(int on)
4072{
4073 int fd;
4074 int pgrp;
4075
4076 if (on == doing_jobctl || rootshell == 0)
4077 return;
4078 if (on) {
4079 int ofd;
4080 ofd = fd = open(_PATH_TTY, O_RDWR);
4081 if (fd < 0) {
4082
4083
4084
4085
4086 fd = 2;
4087 while (!isatty(fd))
4088 if (--fd < 0)
4089 goto out;
4090 }
4091
4092 fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
4093 if (ofd >= 0)
4094 close(ofd);
4095 if (fd < 0)
4096 goto out;
4097 if (F_DUPFD_CLOEXEC == F_DUPFD)
4098 close_on_exec_on(fd);
4099 while (1) {
4100 pgrp = tcgetpgrp(fd);
4101 if (pgrp < 0) {
4102 out:
4103 ash_msg("can't access tty; job control turned off");
4104 mflag = on = 0;
4105 goto close;
4106 }
4107 if (pgrp == getpgrp())
4108 break;
4109 killpg(0, SIGTTIN);
4110 }
4111 initialpgrp = pgrp;
4112
4113 setsignal(SIGTSTP);
4114 setsignal(SIGTTOU);
4115 setsignal(SIGTTIN);
4116 pgrp = rootpid;
4117 setpgid(0, pgrp);
4118 xtcsetpgrp(fd, pgrp);
4119 } else {
4120
4121 fd = ttyfd;
4122 pgrp = initialpgrp;
4123
4124
4125 tcsetpgrp(fd, pgrp);
4126 setpgid(0, pgrp);
4127 setsignal(SIGTSTP);
4128 setsignal(SIGTTOU);
4129 setsignal(SIGTTIN);
4130 close:
4131 if (fd >= 0)
4132 close(fd);
4133 fd = -1;
4134 }
4135 ttyfd = fd;
4136 doing_jobctl = on;
4137}
4138
4139static int FAST_FUNC
4140killcmd(int argc, char **argv)
4141{
4142 if (argv[1] && strcmp(argv[1], "-l") != 0) {
4143 int i = 1;
4144 do {
4145 if (argv[i][0] == '%') {
4146
4147
4148
4149
4150 struct job *jp;
4151 char *dst;
4152 int j, n;
4153
4154 jp = getjob(argv[i], 0);
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167 n = jp->nprocs;
4168 if (jp->jobctl)
4169 n = 1;
4170 dst = alloca(n * sizeof(int)*4);
4171 argv[i] = dst;
4172 for (j = 0; j < n; j++) {
4173 struct procstat *ps = &jp->ps[j];
4174
4175
4176
4177 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4178 continue;
4179
4180
4181
4182
4183
4184 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4185 }
4186 *dst = '\0';
4187 }
4188 } while (argv[++i]);
4189 }
4190 return kill_main(argc, argv);
4191}
4192
4193static void
4194showpipe(struct job *jp )
4195{
4196 struct procstat *ps;
4197 struct procstat *psend;
4198
4199 psend = jp->ps + jp->nprocs;
4200 for (ps = jp->ps + 1; ps < psend; ps++)
4201 printf(" | %s", ps->ps_cmd);
4202 newline_and_flush(stdout);
4203 flush_stdout_stderr();
4204}
4205
4206
4207static int
4208restartjob(struct job *jp, int mode)
4209{
4210 struct procstat *ps;
4211 int i;
4212 int status;
4213 pid_t pgid;
4214
4215 INT_OFF;
4216 if (jp->state == JOBDONE)
4217 goto out;
4218 jp->state = JOBRUNNING;
4219 pgid = jp->ps[0].ps_pid;
4220 if (mode == FORK_FG) {
4221 get_tty_state();
4222 xtcsetpgrp(ttyfd, pgid);
4223 }
4224 killpg(pgid, SIGCONT);
4225 ps = jp->ps;
4226 i = jp->nprocs;
4227 do {
4228 if (WIFSTOPPED(ps->ps_status)) {
4229 ps->ps_status = -1;
4230 }
4231 ps++;
4232 } while (--i);
4233 out:
4234 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4235 INT_ON;
4236 return status;
4237}
4238
4239static int FAST_FUNC
4240fg_bgcmd(int argc UNUSED_PARAM, char **argv)
4241{
4242 struct job *jp;
4243 int mode;
4244 int retval;
4245
4246 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4247 nextopt(nullstr);
4248 argv = argptr;
4249 do {
4250 jp = getjob(*argv, 1);
4251 if (mode == FORK_BG) {
4252 set_curjob(jp, CUR_RUNNING);
4253 printf("[%d] ", jobno(jp));
4254 }
4255 out1str(jp->ps[0].ps_cmd);
4256 showpipe(jp );
4257 retval = restartjob(jp, mode);
4258 } while (*argv && *++argv);
4259 return retval;
4260}
4261#endif
4262
4263static int
4264sprint_status48(char *os, int status, int sigonly)
4265{
4266 char *s = os;
4267 int st;
4268
4269 if (!WIFEXITED(status)) {
4270#if JOBS
4271 if (WIFSTOPPED(status))
4272 st = WSTOPSIG(status);
4273 else
4274#endif
4275 st = WTERMSIG(status);
4276 if (sigonly) {
4277 if (st == SIGINT || st == SIGPIPE)
4278 goto out;
4279#if JOBS
4280 if (WIFSTOPPED(status))
4281 goto out;
4282#endif
4283 }
4284 st &= 0x7f;
4285 s = stpncpy(s, strsignal(st), 32);
4286 if (WCOREDUMP(status)) {
4287 s = stpcpy(s, " (core dumped)");
4288 }
4289 } else if (!sigonly) {
4290 st = WEXITSTATUS(status);
4291 s += fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
4292 }
4293 out:
4294 return s - os;
4295}
4296
4297#define DOWAIT_NONBLOCK 0
4298#define DOWAIT_BLOCK 1
4299#define DOWAIT_BLOCK_OR_SIG 2
4300#if BASH_WAIT_N
4301# define DOWAIT_JOBSTATUS 0x10
4302#endif
4303
4304static int
4305waitproc(int block, int *status)
4306{
4307 sigset_t oldmask;
4308 int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
4309 int err;
4310
4311#if JOBS
4312 if (doing_jobctl)
4313 flags |= WUNTRACED;
4314#endif
4315
4316 do {
4317 got_sigchld = 0;
4318 do
4319 err = waitpid(-1, status, flags);
4320 while (err < 0 && errno == EINTR);
4321
4322 if (err || (err = -!block))
4323 break;
4324
4325 sigfillset(&oldmask);
4326 sigprocmask2(SIG_SETMASK, &oldmask);
4327 while (!got_sigchld && !pending_sig)
4328 sigsuspend(&oldmask);
4329 sigprocmask(SIG_SETMASK, &oldmask, NULL);
4330
4331
4332
4333
4334 } while (got_sigchld);
4335
4336 return err;
4337}
4338
4339static int
4340waitone(int block, struct job *job)
4341{
4342 int pid;
4343 int status;
4344 struct job *jp;
4345 struct job *thisjob = NULL;
4346#if BASH_WAIT_N
4347 bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
4348 block = (block & ~DOWAIT_JOBSTATUS);
4349#endif
4350
4351 TRACE(("dowait(0x%x) called\n", block));
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371 INT_OFF;
4372 pid = waitproc(block, &status);
4373 TRACE(("wait returns pid %d, status=%d\n", pid, status));
4374 if (pid <= 0)
4375 goto out;
4376
4377 for (jp = curjob; jp; jp = jp->prev_job) {
4378 int jobstate;
4379 struct procstat *ps;
4380 struct procstat *psend;
4381 if (jp->state == JOBDONE)
4382 continue;
4383 jobstate = JOBDONE;
4384 ps = jp->ps;
4385 psend = ps + jp->nprocs;
4386 do {
4387 if (ps->ps_pid == pid) {
4388 TRACE(("Job %d: changing status of proc %d "
4389 "from 0x%x to 0x%x\n",
4390 jobno(jp), pid, ps->ps_status, status));
4391 ps->ps_status = status;
4392 thisjob = jp;
4393 }
4394 if (ps->ps_status == -1)
4395 jobstate = JOBRUNNING;
4396#if JOBS
4397 if (jobstate == JOBRUNNING)
4398 continue;
4399 if (WIFSTOPPED(ps->ps_status)) {
4400 jp->stopstatus = ps->ps_status;
4401 jobstate = JOBSTOPPED;
4402 }
4403#endif
4404 } while (++ps < psend);
4405 if (!thisjob)
4406 continue;
4407
4408
4409
4410 if (jobstate != JOBRUNNING) {
4411
4412
4413
4414 thisjob->changed = 1;
4415 if (thisjob->state != jobstate) {
4416 TRACE(("Job %d: changing state from %d to %d\n",
4417 jobno(thisjob), thisjob->state, jobstate));
4418 thisjob->state = jobstate;
4419#if JOBS
4420 if (jobstate == JOBSTOPPED)
4421 set_curjob(thisjob, CUR_STOPPED);
4422#endif
4423 }
4424 }
4425 goto out;
4426 }
4427
4428 out:
4429 INT_ON;
4430
4431#if BASH_WAIT_N
4432 if (want_jobexitstatus) {
4433 pid = -1;
4434 if (thisjob && thisjob->state == JOBDONE)
4435 pid = thisjob->ps[thisjob->nprocs - 1].ps_status;
4436 }
4437#endif
4438 if (thisjob && thisjob == job) {
4439 char s[48 + 1];
4440 int len;
4441
4442 len = sprint_status48(s, status, 1);
4443 if (len) {
4444 s[len] = '\n';
4445 s[len + 1] = '\0';
4446 out2str(s);
4447 }
4448 }
4449 return pid;
4450}
4451
4452static int
4453dowait(int block, struct job *jp)
4454{
4455 smallint gotchld = *(volatile smallint *)&got_sigchld;
4456 int rpid;
4457 int pid;
4458
4459 if (jp && jp->state != JOBRUNNING)
4460 block = DOWAIT_NONBLOCK;
4461
4462 if (block == DOWAIT_NONBLOCK && !gotchld)
4463 return 1;
4464
4465 rpid = 1;
4466
4467 do {
4468 pid = waitone(block, jp);
4469 rpid &= !!pid;
4470
4471 if (!pid || (jp && jp->state != JOBRUNNING))
4472 block = DOWAIT_NONBLOCK;
4473 } while (pid >= 0);
4474
4475 return rpid;
4476}
4477
4478#if JOBS
4479static void
4480showjob(struct job *jp, int mode)
4481{
4482 struct procstat *ps;
4483 struct procstat *psend;
4484 int col;
4485 int indent_col;
4486 char s[16 + 16 + 48];
4487 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4488
4489 ps = jp->ps;
4490
4491 if (mode & SHOW_ONLY_PGID) {
4492
4493 fprintf(out, "%d\n", ps->ps_pid);
4494 return;
4495 }
4496
4497 col = fmtstr(s, 16, "[%d] ", jobno(jp));
4498 indent_col = col;
4499
4500 if (jp == curjob)
4501 s[col - 3] = '+';
4502 else if (curjob && jp == curjob->prev_job)
4503 s[col - 3] = '-';
4504
4505 if (mode & SHOW_PIDS)
4506 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4507
4508 psend = ps + jp->nprocs;
4509
4510 if (jp->state == JOBRUNNING) {
4511 strcpy(s + col, "Running");
4512 col += sizeof("Running") - 1;
4513 } else {
4514 int status = psend[-1].ps_status;
4515 if (jp->state == JOBSTOPPED)
4516 status = jp->stopstatus;
4517 col += sprint_status48(s + col, status, 0);
4518 }
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529 goto start;
4530 do {
4531
4532 s[0] = '\0';
4533 col = 33;
4534 if (mode & SHOW_PIDS)
4535 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4536 start:
4537 fprintf(out, "%s%*c%s%s",
4538 s,
4539 33 - col >= 0 ? 33 - col : 0, ' ',
4540 ps == jp->ps ? "" : "| ",
4541 ps->ps_cmd
4542 );
4543 } while (++ps != psend);
4544 newline_and_flush(out);
4545
4546 jp->changed = 0;
4547
4548 if (jp->state == JOBDONE) {
4549 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4550 freejob(jp);
4551 }
4552}
4553
4554
4555
4556
4557
4558static void
4559showjobs(int mode)
4560{
4561 struct job *jp;
4562
4563 TRACE(("showjobs(0x%x) called\n", mode));
4564
4565
4566 dowait(DOWAIT_NONBLOCK, NULL);
4567
4568 for (jp = curjob; jp; jp = jp->prev_job) {
4569 if (!(mode & SHOW_CHANGED) || jp->changed) {
4570 showjob(jp, mode);
4571 }
4572 }
4573}
4574
4575static int FAST_FUNC
4576jobscmd(int argc UNUSED_PARAM, char **argv)
4577{
4578 int mode, m;
4579
4580 mode = 0;
4581 while ((m = nextopt("lp")) != '\0') {
4582 if (m == 'l')
4583 mode |= SHOW_PIDS;
4584 else
4585 mode |= SHOW_ONLY_PGID;
4586 }
4587
4588 argv = argptr;
4589 if (*argv) {
4590 do
4591 showjob(getjob(*argv, 0), mode);
4592 while (*++argv);
4593 } else {
4594 showjobs(mode);
4595 }
4596
4597 return 0;
4598}
4599#endif
4600
4601
4602static int
4603getstatus(struct job *job)
4604{
4605 int status;
4606 int retval;
4607 struct procstat *ps;
4608
4609
4610 ps = job->ps + job->nprocs - 1;
4611 status = ps->ps_status;
4612 if (pipefail) {
4613
4614 while (status == 0 && --ps >= job->ps)
4615 status = ps->ps_status;
4616 }
4617
4618 retval = WEXITSTATUS(status);
4619 if (!WIFEXITED(status)) {
4620#if JOBS
4621 retval = WSTOPSIG(status);
4622 if (!WIFSTOPPED(status))
4623#endif
4624 {
4625
4626 retval = WTERMSIG(status);
4627#if JOBS
4628 if (retval == SIGINT)
4629 job->sigint = 1;
4630#endif
4631 }
4632 retval |= 128;
4633 }
4634 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4635 jobno(job), job->nprocs, status, retval));
4636 return retval;
4637}
4638
4639static int FAST_FUNC
4640waitcmd(int argc UNUSED_PARAM, char **argv)
4641{
4642 struct job *job;
4643 int retval;
4644 struct job *jp;
4645#if BASH_WAIT_N
4646 int status;
4647 char one = nextopt("n");
4648#else
4649 nextopt(nullstr);
4650#endif
4651 retval = 0;
4652
4653 argv = argptr;
4654 if (!argv[0]) {
4655
4656 for (;;) {
4657 jp = curjob;
4658#if BASH_WAIT_N
4659 if (one && !jp)
4660
4661 retval = 127;
4662#endif
4663 while (1) {
4664 if (!jp)
4665 goto ret;
4666 if (jp->state == JOBRUNNING)
4667 break;
4668 jp->waited = 1;
4669 jp = jp->prev_job;
4670 }
4671
4672
4673
4674
4675
4676
4677
4678#if BASH_WAIT_N
4679 status = dowait(DOWAIT_BLOCK_OR_SIG | DOWAIT_JOBSTATUS, NULL);
4680#else
4681 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4682#endif
4683
4684
4685
4686
4687 if (pending_sig)
4688 goto sigout;
4689#if BASH_WAIT_N
4690 if (one) {
4691
4692
4693
4694
4695 if (status != -1 && !WIFSTOPPED(status)) {
4696 retval = WEXITSTATUS(status);
4697 if (WIFSIGNALED(status))
4698 retval = 128 | WTERMSIG(status);
4699 goto ret;
4700 }
4701 }
4702#endif
4703 }
4704 }
4705
4706 retval = 127;
4707 do {
4708 if (**argv != '%') {
4709 pid_t pid = number(*argv);
4710 job = curjob;
4711 while (1) {
4712 if (!job)
4713 goto repeat;
4714 if (job->ps[job->nprocs - 1].ps_pid == pid)
4715 break;
4716 job = job->prev_job;
4717 }
4718 } else {
4719 job = getjob(*argv, 0);
4720 }
4721
4722 dowait(DOWAIT_BLOCK_OR_SIG, job);
4723 if (pending_sig)
4724 goto sigout;
4725 job->waited = 1;
4726 retval = getstatus(job);
4727 repeat: ;
4728 } while (*++argv);
4729
4730 ret:
4731 return retval;
4732 sigout:
4733 retval = 128 | pending_sig;
4734 return retval;
4735}
4736
4737static struct job *
4738growjobtab(void)
4739{
4740 size_t len;
4741 ptrdiff_t offset;
4742 struct job *jp, *jq;
4743
4744 len = njobs * sizeof(*jp);
4745 jq = jobtab;
4746 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4747
4748 offset = (char *)jp - (char *)jq;
4749 if (offset) {
4750
4751 size_t l = len;
4752
4753 jq = (struct job *)((char *)jq + l);
4754 while (l) {
4755 l -= sizeof(*jp);
4756 jq--;
4757#define joff(p) ((struct job *)((char *)(p) + l))
4758#define jmove(p) (p) = (void *)((char *)(p) + offset)
4759 if (joff(jp)->ps == &jq->ps0)
4760 jmove(joff(jp)->ps);
4761 if (joff(jp)->prev_job)
4762 jmove(joff(jp)->prev_job);
4763 }
4764 if (curjob)
4765 jmove(curjob);
4766#undef joff
4767#undef jmove
4768 }
4769
4770 njobs += 4;
4771 jobtab = jp;
4772 jp = (struct job *)((char *)jp + len);
4773 jq = jp + 3;
4774 do {
4775 jq->used = 0;
4776 } while (--jq >= jp);
4777 return jp;
4778}
4779
4780
4781
4782
4783
4784static struct job *
4785makejob( int nprocs)
4786{
4787 int i;
4788 struct job *jp;
4789
4790 for (i = njobs, jp = jobtab; ; jp++) {
4791 if (--i < 0) {
4792 jp = growjobtab();
4793 break;
4794 }
4795 if (jp->used == 0)
4796 break;
4797 if (jp->state != JOBDONE || !jp->waited)
4798 continue;
4799#if JOBS
4800 if (doing_jobctl)
4801 continue;
4802#endif
4803 freejob(jp);
4804 break;
4805 }
4806 memset(jp, 0, sizeof(*jp));
4807#if JOBS
4808
4809
4810 if (doing_jobctl)
4811 jp->jobctl = 1;
4812#endif
4813 jp->prev_job = curjob;
4814 curjob = jp;
4815 jp->used = 1;
4816 jp->ps = &jp->ps0;
4817 if (nprocs > 1) {
4818 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4819 }
4820 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4821 jobno(jp)));
4822 return jp;
4823}
4824
4825#if JOBS
4826
4827
4828
4829
4830static char *cmdnextc;
4831
4832static void
4833cmdputs(const char *s)
4834{
4835 static const char vstype[VSTYPE + 1][3] ALIGN1 = {
4836 "", "}", "-", "+", "?", "=",
4837 "%", "%%", "#", "##"
4838 IF_BASH_SUBSTR(, ":")
4839 IF_BASH_PATTERN_SUBST(, "/", "//")
4840 };
4841
4842 const char *p, *str;
4843 char cc[2];
4844 char *nextc;
4845 unsigned char c;
4846 unsigned char subtype = 0;
4847 int quoted = 0;
4848
4849 cc[1] = '\0';
4850 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4851 p = s;
4852 while ((c = *p++) != '\0') {
4853 str = NULL;
4854 switch (c) {
4855 case CTLESC:
4856 c = *p++;
4857 break;
4858 case CTLVAR:
4859 subtype = *p++;
4860 if ((subtype & VSTYPE) == VSLENGTH)
4861 str = "${#";
4862 else
4863 str = "${";
4864 goto dostr;
4865 case CTLENDVAR:
4866 str = "\"}";
4867 str += !(quoted & 1);
4868 quoted >>= 1;
4869 subtype = 0;
4870 goto dostr;
4871#if BASH_PROCESS_SUBST
4872 case CTLBACKQ:
4873 c = '$';
4874 str = "(...)";
4875 break;
4876 case CTLTOPROC:
4877 c = '>';
4878 str = "(...)";
4879 break;
4880 case CTLFROMPROC:
4881 c = '<';
4882 str = "(...)";
4883 break;
4884#else
4885 case CTLBACKQ:
4886 str = "$(...)";
4887 goto dostr;
4888#endif
4889#if ENABLE_FEATURE_SH_MATH
4890 case CTLARI:
4891 str = "$((";
4892 goto dostr;
4893 case CTLENDARI:
4894 str = "))";
4895 goto dostr;
4896#endif
4897 case CTLQUOTEMARK:
4898 quoted ^= 1;
4899 c = '"';
4900 break;
4901 case '=':
4902 if (subtype == 0)
4903 break;
4904 if ((subtype & VSTYPE) != VSNORMAL)
4905 quoted <<= 1;
4906 str = vstype[subtype & VSTYPE];
4907 if (subtype & VSNUL)
4908 c = ':';
4909 else
4910 goto checkstr;
4911 break;
4912 case '\'':
4913 case '\\':
4914 case '"':
4915 case '$':
4916
4917 cc[0] = c;
4918 str = cc;
4919
4920
4921
4922
4923 c = '\\';
4924 break;
4925 default:
4926 break;
4927 }
4928 USTPUTC(c, nextc);
4929 checkstr:
4930 if (!str)
4931 continue;
4932 dostr:
4933 while ((c = *str++) != '\0') {
4934 USTPUTC(c, nextc);
4935 }
4936 }
4937
4938 if (quoted & 1) {
4939 USTPUTC('"', nextc);
4940 }
4941 *nextc = 0;
4942 cmdnextc = nextc;
4943}
4944
4945
4946static void cmdtxt(union node *n);
4947
4948static void
4949cmdlist(union node *np, int sep)
4950{
4951 for (; np; np = np->narg.next) {
4952 if (!sep)
4953 cmdputs(" ");
4954 cmdtxt(np);
4955 if (sep && np->narg.next)
4956 cmdputs(" ");
4957 }
4958}
4959
4960static void
4961cmdtxt(union node *n)
4962{
4963 union node *np;
4964 struct nodelist *lp;
4965 const char *p;
4966
4967 if (!n)
4968 return;
4969 switch (n->type) {
4970 default:
4971#if DEBUG
4972 abort();
4973#endif
4974 case NPIPE:
4975 lp = n->npipe.cmdlist;
4976 for (;;) {
4977 cmdtxt(lp->n);
4978 lp = lp->next;
4979 if (!lp)
4980 break;
4981 cmdputs(" | ");
4982 }
4983 break;
4984 case NSEMI:
4985 p = "; ";
4986 goto binop;
4987 case NAND:
4988 p = " && ";
4989 goto binop;
4990 case NOR:
4991 p = " || ";
4992 binop:
4993 cmdtxt(n->nbinary.ch1);
4994 cmdputs(p);
4995 n = n->nbinary.ch2;
4996 goto donode;
4997 case NREDIR:
4998 case NBACKGND:
4999 n = n->nredir.n;
5000 goto donode;
5001 case NNOT:
5002 cmdputs("!");
5003 n = n->nnot.com;
5004 donode:
5005 cmdtxt(n);
5006 break;
5007 case NIF:
5008 cmdputs("if ");
5009 cmdtxt(n->nif.test);
5010 cmdputs("; then ");
5011 if (n->nif.elsepart) {
5012 cmdtxt(n->nif.ifpart);
5013 cmdputs("; else ");
5014 n = n->nif.elsepart;
5015 } else {
5016 n = n->nif.ifpart;
5017 }
5018 p = "; fi";
5019 goto dotail;
5020 case NSUBSHELL:
5021 cmdputs("(");
5022 n = n->nredir.n;
5023 p = ")";
5024 goto dotail;
5025 case NWHILE:
5026 p = "while ";
5027 goto until;
5028 case NUNTIL:
5029 p = "until ";
5030 until:
5031 cmdputs(p);
5032 cmdtxt(n->nbinary.ch1);
5033 n = n->nbinary.ch2;
5034 p = "; done";
5035 dodo:
5036 cmdputs("; do ");
5037 dotail:
5038 cmdtxt(n);
5039 goto dotail2;
5040 case NFOR:
5041 cmdputs("for ");
5042 cmdputs(n->nfor.var);
5043 cmdputs(" in ");
5044 cmdlist(n->nfor.args, 1);
5045 n = n->nfor.body;
5046 p = "; done";
5047 goto dodo;
5048 case NDEFUN:
5049 cmdputs(n->ndefun.text);
5050 p = "() { ... }";
5051 goto dotail2;
5052 case NCMD:
5053 cmdlist(n->ncmd.args, 1);
5054 cmdlist(n->ncmd.redirect, 0);
5055 break;
5056 case NARG:
5057 p = n->narg.text;
5058 dotail2:
5059 cmdputs(p);
5060 break;
5061 case NHERE:
5062 case NXHERE:
5063 p = "<<...";
5064 goto dotail2;
5065 case NCASE:
5066 cmdputs("case ");
5067 cmdputs(n->ncase.expr->narg.text);
5068 cmdputs(" in ");
5069 for (np = n->ncase.cases; np; np = np->nclist.next) {
5070 cmdtxt(np->nclist.pattern);
5071 cmdputs(") ");
5072 cmdtxt(np->nclist.body);
5073 cmdputs(";; ");
5074 }
5075 p = "esac";
5076 goto dotail2;
5077 case NTO:
5078 p = ">";
5079 goto redir;
5080 case NCLOBBER:
5081 p = ">|";
5082 goto redir;
5083 case NAPPEND:
5084 p = ">>";
5085 goto redir;
5086#if BASH_REDIR_OUTPUT
5087 case NTO2:
5088#endif
5089 case NTOFD:
5090 p = ">&";
5091 goto redir;
5092 case NFROM:
5093 p = "<";
5094 goto redir;
5095 case NFROMFD:
5096 p = "<&";
5097 goto redir;
5098 case NFROMTO:
5099 p = "<>";
5100 redir:
5101 cmdputs(utoa(n->nfile.fd));
5102 cmdputs(p);
5103 if (n->type == NTOFD || n->type == NFROMFD) {
5104 if (n->ndup.dupfd >= 0)
5105 cmdputs(utoa(n->ndup.dupfd));
5106 else
5107 cmdputs("-");
5108 break;
5109 }
5110 n = n->nfile.fname;
5111 goto donode;
5112 }
5113}
5114
5115static char *
5116commandtext(union node *n)
5117{
5118 char *name;
5119
5120 STARTSTACKSTR(cmdnextc);
5121 cmdtxt(n);
5122 name = stackblock();
5123 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
5124 return ckstrdup(name);
5125}
5126#endif
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147static void
5148clear_traps(void)
5149{
5150 char **tp;
5151
5152 INT_OFF;
5153 for (tp = trap; tp <= &trap[NTRAP_LAST]; tp++) {
5154 if (*tp && **tp) {
5155 if (trap_ptr == trap)
5156 free(*tp);
5157
5158 *tp = NULL;
5159 if ((tp - trap) != 0 && (tp - trap) < NSIG)
5160 setsignal(tp - trap);
5161 }
5162 }
5163 may_have_traps = 0;
5164 INT_ON;
5165}
5166
5167
5168static void closescript(void);
5169
5170
5171
5172static NOINLINE void
5173forkchild(struct job *jp, union node *n, int mode)
5174{
5175 int oldlvl;
5176
5177 TRACE(("Child shell %d\n", getpid()));
5178 oldlvl = shlvl;
5179 shlvl++;
5180
5181
5182
5183
5184
5185 closescript();
5186
5187 if (mode == FORK_NOJOB
5188 && n && n->type == NCMD
5189
5190 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
5191 && n->ncmd.args->narg.next == NULL
5192
5193 ) {
5194 TRACE(("Trap hack\n"));
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230 trap_ptr = xmemdup(trap, sizeof(trap));
5231
5232 }
5233 clear_traps();
5234#if JOBS
5235
5236 doing_jobctl = 0;
5237 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
5238 pid_t pgrp;
5239
5240 if (jp->nprocs == 0)
5241 pgrp = getpid();
5242 else
5243 pgrp = jp->ps[0].ps_pid;
5244
5245 setpgid(0, pgrp);
5246 if (mode == FORK_FG)
5247 xtcsetpgrp(ttyfd, pgrp);
5248 setsignal(SIGTSTP);
5249 setsignal(SIGTTOU);
5250 } else
5251#endif
5252 if (mode == FORK_BG) {
5253
5254
5255 ignoresig(SIGINT);
5256 ignoresig(SIGQUIT);
5257 if (jp->nprocs == 0) {
5258 close(0);
5259 if (open(bb_dev_null, O_RDONLY) != 0)
5260 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
5261 }
5262 }
5263 if (oldlvl == 0) {
5264 if (iflag) {
5265 setsignal(SIGINT);
5266 setsignal(SIGTERM);
5267 }
5268
5269
5270
5271
5272
5273
5274 setsignal(SIGQUIT);
5275 }
5276#if JOBS
5277 if (n && n->type == NCMD
5278 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
5279 ) {
5280 TRACE(("Job hack\n"));
5281
5282
5283
5284
5285 freejob(curjob);
5286 return;
5287 }
5288#endif
5289 for (jp = curjob; jp; jp = jp->prev_job)
5290 freejob(jp);
5291}
5292
5293
5294#if !JOBS
5295#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5296#endif
5297static void
5298forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5299{
5300 TRACE(("In parent shell: child = %d\n", pid));
5301 if (!jp)
5302 return;
5303#if JOBS
5304 if (mode != FORK_NOJOB && jp->jobctl) {
5305 int pgrp;
5306
5307 if (jp->nprocs == 0)
5308 pgrp = pid;
5309 else
5310 pgrp = jp->ps[0].ps_pid;
5311
5312 setpgid(pid, pgrp);
5313 }
5314#endif
5315 if (mode == FORK_BG) {
5316 backgndpid = pid;
5317 set_curjob(jp, CUR_RUNNING);
5318 }
5319 if (jp) {
5320 struct procstat *ps = &jp->ps[jp->nprocs++];
5321 ps->ps_pid = pid;
5322 ps->ps_status = -1;
5323 ps->ps_cmd = nullstr;
5324#if JOBS
5325 if (doing_jobctl && n)
5326 ps->ps_cmd = commandtext(n);
5327#endif
5328 }
5329}
5330
5331
5332static int
5333forkshell(struct job *jp, union node *n, int mode)
5334{
5335 int pid;
5336
5337 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5338 pid = fork();
5339 if (pid < 0) {
5340 TRACE(("Fork failed, errno=%d", errno));
5341 if (jp)
5342 freejob(jp);
5343 ash_msg_and_raise_perror("can't fork");
5344 }
5345 if (pid == 0) {
5346 CLEAR_RANDOM_T(&random_gen);
5347 forkchild(jp, n, mode);
5348 } else {
5349 forkparent(jp, n, mode, pid);
5350 }
5351 return pid;
5352}
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374static int
5375waitforjob(struct job *jp)
5376{
5377 int st;
5378
5379 TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411 dowait(jp ? DOWAIT_BLOCK : DOWAIT_NONBLOCK, jp);
5412 if (!jp)
5413 return exitstatus;
5414
5415 st = getstatus(jp);
5416#if JOBS
5417 if (jp->jobctl) {
5418 xtcsetpgrp(ttyfd, rootpid);
5419 restore_tty_if_stopped_or_signaled(jp);
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429 if (jp->sigint)
5430 raise(SIGINT);
5431 }
5432 if (jp->state == JOBDONE)
5433#endif
5434 freejob(jp);
5435 return st;
5436}
5437
5438
5439
5440
5441static int
5442stoppedjobs(void)
5443{
5444 struct job *jp;
5445 int retval;
5446
5447 retval = 0;
5448 if (!iflag || job_warning)
5449 goto out;
5450 jp = curjob;
5451 if (jp && jp->state == JOBSTOPPED) {
5452 out2str("You have stopped jobs.\n");
5453 job_warning = 2;
5454 retval++;
5455 }
5456 out:
5457 return retval;
5458}
5459
5460
5461
5462
5463
5464
5465#undef EMPTY
5466#undef CLOSED
5467#define EMPTY -2
5468#define CLOSED -1
5469
5470
5471
5472
5473
5474
5475
5476static void expandhere(union node *arg);
5477static int
5478openhere(union node *redir)
5479{
5480 char *p;
5481 int pip[2];
5482 size_t len = 0;
5483
5484 if (pipe(pip) < 0)
5485 ash_msg_and_raise_perror("can't create pipe");
5486
5487 p = redir->nhere.doc->narg.text;
5488 if (redir->type == NXHERE) {
5489 expandhere(redir->nhere.doc);
5490 p = stackblock();
5491 }
5492
5493 len = strlen(p);
5494 if (len <= PIPE_BUF) {
5495 xwrite(pip[1], p, len);
5496 goto out;
5497 }
5498
5499 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5500
5501 close(pip[0]);
5502 ignoresig(SIGINT);
5503 ignoresig(SIGQUIT);
5504 ignoresig(SIGHUP);
5505 ignoresig(SIGTSTP);
5506 signal(SIGPIPE, SIG_DFL);
5507 xwrite(pip[1], p, len);
5508 _exit(EXIT_SUCCESS);
5509 }
5510 out:
5511 close(pip[1]);
5512 return pip[0];
5513}
5514
5515static int
5516openredirect(union node *redir)
5517{
5518 struct stat sb;
5519 char *fname;
5520 int f;
5521
5522 switch (redir->nfile.type) {
5523
5524
5525
5526
5527 case NHERE:
5528 case NXHERE:
5529 return openhere(redir);
5530 }
5531
5532
5533
5534
5535 fname = redir->nfile.expfname;
5536
5537 switch (redir->nfile.type) {
5538 default:
5539#if DEBUG
5540 abort();
5541#endif
5542 case NFROM:
5543 f = open(fname, O_RDONLY);
5544 if (f < 0)
5545 goto eopen;
5546 break;
5547 case NFROMTO:
5548 f = open(fname, O_RDWR|O_CREAT, 0666);
5549 if (f < 0)
5550 goto ecreate;
5551 break;
5552 case NTO:
5553#if BASH_REDIR_OUTPUT
5554 case NTO2:
5555#endif
5556
5557 if (Cflag) {
5558 if (stat(fname, &sb) < 0) {
5559 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5560 if (f < 0)
5561 goto ecreate;
5562 } else if (!S_ISREG(sb.st_mode)) {
5563 f = open(fname, O_WRONLY, 0666);
5564 if (f < 0)
5565 goto ecreate;
5566 if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
5567 close(f);
5568 errno = EEXIST;
5569 goto ecreate;
5570 }
5571 } else {
5572 errno = EEXIST;
5573 goto ecreate;
5574 }
5575 break;
5576 }
5577
5578 case NCLOBBER:
5579 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5580 if (f < 0)
5581 goto ecreate;
5582 break;
5583 case NAPPEND:
5584 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5585 if (f < 0)
5586 goto ecreate;
5587 break;
5588 }
5589
5590 return f;
5591 ecreate:
5592 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5593 eopen:
5594 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5595}
5596
5597
5598
5599
5600static int
5601savefd(int from)
5602{
5603 int newfd;
5604 int err;
5605
5606 newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
5607 err = newfd < 0 ? errno : 0;
5608 if (err != EBADF) {
5609 if (err)
5610 ash_msg_and_raise_perror("%d", from);
5611 close(from);
5612 if (F_DUPFD_CLOEXEC == F_DUPFD)
5613 close_on_exec_on(newfd);
5614 }
5615
5616 return newfd;
5617}
5618static int
5619dup2_or_raise(int from, int to)
5620{
5621 int newfd;
5622
5623 newfd = (from != to) ? dup2(from, to) : to;
5624 if (newfd < 0) {
5625
5626 ash_msg_and_raise_perror("%d", from);
5627 }
5628 return newfd;
5629}
5630static int
5631dup_CLOEXEC(int fd, int avoid_fd)
5632{
5633 int newfd;
5634 repeat:
5635 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5636 if (newfd >= 0) {
5637 if (F_DUPFD_CLOEXEC == F_DUPFD)
5638 close_on_exec_on(newfd);
5639 } else {
5640 if (errno == EBUSY)
5641 goto repeat;
5642 if (errno == EINTR)
5643 goto repeat;
5644 }
5645 return newfd;
5646}
5647static int
5648xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5649{
5650 int newfd;
5651 repeat:
5652 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5653 if (newfd < 0) {
5654 if (errno == EBUSY)
5655 goto repeat;
5656 if (errno == EINTR)
5657 goto repeat;
5658
5659 if (errno == EBADF)
5660 return fd;
5661 ash_msg_and_raise_perror("%d", newfd);
5662 }
5663 if (F_DUPFD_CLOEXEC == F_DUPFD)
5664 close_on_exec_on(newfd);
5665 close(fd);
5666 return newfd;
5667}
5668
5669
5670struct squirrel {
5671 int orig_fd;
5672 int moved_to;
5673};
5674struct redirtab {
5675 struct redirtab *next;
5676 int pair_count;
5677 struct squirrel two_fd[];
5678};
5679#define redirlist (G_var.redirlist)
5680
5681static void
5682add_squirrel_closed(struct redirtab *sq, int fd)
5683{
5684 int i;
5685
5686 if (!sq)
5687 return;
5688
5689 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5690
5691 if (fd == sq->two_fd[i].orig_fd) {
5692
5693
5694
5695
5696
5697
5698 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5699 return;
5700 }
5701 }
5702 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5703 sq->two_fd[i].orig_fd = fd;
5704 sq->two_fd[i].moved_to = CLOSED;
5705}
5706
5707static int
5708save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5709{
5710 int i, new_fd;
5711
5712 if (avoid_fd < 9)
5713 avoid_fd = 9;
5714
5715#if JOBS
5716 if (fd == ttyfd) {
5717
5718 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5719 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5720 return 1;
5721 }
5722#endif
5723
5724
5725
5726
5727 if (!sq)
5728 return 0;
5729
5730
5731 if (fd != 0) {
5732 struct parsefile *pf = g_parsefile;
5733 while (pf) {
5734
5735
5736
5737
5738
5739
5740
5741
5742 if (fd == pf->pf_fd) {
5743 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5744 return 1;
5745 }
5746 pf = pf->prev;
5747 }
5748 }
5749
5750
5751
5752
5753 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5754
5755 if (fd == sq->two_fd[i].moved_to) {
5756 new_fd = dup_CLOEXEC(fd, avoid_fd);
5757 sq->two_fd[i].moved_to = new_fd;
5758 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5759 if (new_fd < 0)
5760 xfunc_die();
5761 return 0;
5762 }
5763 if (fd == sq->two_fd[i].orig_fd) {
5764
5765 TRACE(("redirect_fd %d: already moved\n", fd));
5766 return 0;
5767 }
5768 }
5769
5770
5771 new_fd = dup_CLOEXEC(fd, avoid_fd);
5772 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5773 if (new_fd < 0) {
5774 if (errno != EBADF)
5775 xfunc_die();
5776
5777 }
5778 sq->two_fd[i].moved_to = new_fd;
5779 sq->two_fd[i].orig_fd = fd;
5780
5781
5782 if (fd == preverrout_fd)
5783 preverrout_fd = new_fd;
5784
5785 return 0;
5786}
5787
5788static int
5789internally_opened_fd(int fd, struct redirtab *sq)
5790{
5791 int i;
5792#if JOBS
5793 if (fd == ttyfd)
5794 return 1;
5795#endif
5796
5797 if (fd != 0) {
5798 struct parsefile *pf = g_parsefile;
5799 while (pf) {
5800 if (fd == pf->pf_fd)
5801 return 1;
5802 pf = pf->prev;
5803 }
5804 }
5805
5806 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5807 if (fd == sq->two_fd[i].moved_to)
5808 return 1;
5809 }
5810 return 0;
5811}
5812
5813
5814
5815
5816
5817
5818
5819#define REDIR_PUSH 01
5820static void
5821redirect(union node *redir, int flags)
5822{
5823 struct redirtab *sv;
5824
5825 if (!redir)
5826 return;
5827
5828 sv = NULL;
5829 INT_OFF;
5830 if (flags & REDIR_PUSH)
5831 sv = redirlist;
5832 do {
5833 int fd;
5834 int newfd;
5835 int close_fd;
5836 int closed;
5837
5838 fd = redir->nfile.fd;
5839 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5840
5841 newfd = redir->ndup.dupfd;
5842 close_fd = -1;
5843 } else {
5844 newfd = openredirect(redir);
5845 if (fd == newfd) {
5846
5847
5848
5849
5850
5851 add_squirrel_closed(sv, fd);
5852 continue;
5853 }
5854 close_fd = newfd;
5855 }
5856
5857 if (fd == newfd)
5858 continue;
5859
5860
5861
5862
5863
5864 IF_BASH_REDIR_OUTPUT(redirect_more:)
5865
5866 closed = save_fd_on_redirect(fd, newfd, sv);
5867 if (newfd == -1) {
5868
5869 if (!closed) {
5870
5871
5872 close(fd);
5873 }
5874 } else {
5875
5876 if (internally_opened_fd(newfd, sv)) {
5877 errno = EBADF;
5878 ash_msg_and_raise_perror("%d", newfd);
5879 }
5880 dup2_or_raise(newfd, fd);
5881 if (close_fd >= 0)
5882 close(close_fd);
5883#if BASH_REDIR_OUTPUT
5884 if (redir->nfile.type == NTO2 && fd == 1) {
5885
5886 fd = 2;
5887 newfd = 1;
5888 close_fd = -1;
5889 goto redirect_more;
5890 }
5891#endif
5892 }
5893 } while ((redir = redir->nfile.next) != NULL);
5894 INT_ON;
5895
5896
5897#define REDIR_SAVEFD2 0
5898
5899
5900
5901
5902
5903
5904}
5905
5906static int
5907redirectsafe(union node *redir, int flags)
5908{
5909 int err;
5910 volatile int saveint;
5911 struct jmploc *volatile savehandler = exception_handler;
5912 struct jmploc jmploc;
5913
5914 SAVE_INT(saveint);
5915
5916 err = setjmp(jmploc.loc);
5917 if (!err) {
5918 exception_handler = &jmploc;
5919 redirect(redir, flags);
5920 }
5921 exception_handler = savehandler;
5922 if (err && exception_type != EXERROR)
5923 longjmp(exception_handler->loc, 1);
5924 RESTORE_INT(saveint);
5925 return err;
5926}
5927
5928#if BASH_PROCESS_SUBST
5929static void
5930pushfd(int fd)
5931{
5932 struct redirtab *sv;
5933
5934 sv = ckzalloc(sizeof(*sv) + sizeof(sv->two_fd[0]));
5935 sv->pair_count = 1;
5936 sv->two_fd[0].orig_fd = fd;
5937 sv->two_fd[0].moved_to = CLOSED;
5938 sv->next = redirlist;
5939 redirlist = sv;
5940}
5941#endif
5942
5943static struct redirtab*
5944pushredir(union node *redir)
5945{
5946 struct redirtab *sv;
5947 int i;
5948
5949 if (!redir)
5950 return redirlist;
5951
5952 i = 0;
5953 do {
5954 i++;
5955#if BASH_REDIR_OUTPUT
5956 if (redir->nfile.type == NTO2)
5957 i++;
5958#endif
5959 redir = redir->nfile.next;
5960 } while (redir);
5961
5962 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5963 sv->pair_count = i;
5964 while (--i >= 0)
5965 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
5966 sv->next = redirlist;
5967 redirlist = sv;
5968 return sv->next;
5969}
5970
5971
5972
5973
5974static void
5975popredir(int drop)
5976{
5977 struct redirtab *rp;
5978 int i;
5979
5980 if (redirlist == NULL)
5981 return;
5982 INT_OFF;
5983 rp = redirlist;
5984 for (i = 0; i < rp->pair_count; i++) {
5985 int fd = rp->two_fd[i].orig_fd;
5986 int copy = rp->two_fd[i].moved_to;
5987 if (copy == CLOSED) {
5988 if (!drop)
5989 close(fd);
5990 continue;
5991 }
5992 if (copy != EMPTY) {
5993 if (!drop) {
5994
5995 dup2_or_raise(copy, fd);
5996 }
5997 close(copy);
5998 }
5999 }
6000 redirlist = rp->next;
6001 free(rp);
6002 INT_ON;
6003}
6004
6005static void
6006unwindredir(struct redirtab *stop)
6007{
6008 while (redirlist != stop)
6009 popredir( 0);
6010}
6011
6012
6013
6014
6015
6016
6017
6018#if ENABLE_FEATURE_SH_MATH
6019static arith_t
6020ash_arith(const char *s)
6021{
6022 arith_state_t math_state;
6023 arith_t result;
6024
6025 math_state.lookupvar = lookupvar;
6026 math_state.setvar = setvar0;
6027
6028
6029 INT_OFF;
6030 result = arith(&math_state, s);
6031 if (math_state.errmsg)
6032 ash_msg_and_raise_error(math_state.errmsg);
6033 INT_ON;
6034
6035 return result;
6036}
6037#endif
6038#if BASH_SUBSTR
6039# if ENABLE_FEATURE_SH_MATH
6040static int substr_atoi(const char *s)
6041{
6042 arith_t t = ash_arith(s);
6043 if (sizeof(t) > sizeof(int)) {
6044
6045
6046
6047 if (t > INT_MAX)
6048 t = INT_MAX;
6049 if (t < INT_MIN)
6050 t = INT_MIN;
6051 }
6052 return t;
6053}
6054# else
6055# define substr_atoi(s) number(s)
6056# endif
6057#endif
6058
6059
6060
6061
6062#define EXP_FULL 0x1
6063#define EXP_TILDE 0x2
6064#define EXP_VARTILDE 0x4
6065#define EXP_REDIR 0x8
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077#define EXP_CASE 0x10
6078#define EXP_VARTILDE2 0x20
6079#define EXP_WORD 0x40
6080#define EXP_QUOTED 0x100
6081#define EXP_KEEPNUL 0x200
6082#define EXP_DISCARD 0x400
6083
6084
6085
6086
6087#define RMESCAPE_ALLOC 0x1
6088#define RMESCAPE_GLOB 0x2
6089#define RMESCAPE_GROW 0x8
6090#define RMESCAPE_HEAP 0x10
6091
6092
6093#define QUOTES_ESC (EXP_FULL | EXP_CASE)
6094
6095
6096
6097
6098
6099struct ifsregion {
6100 struct ifsregion *next;
6101 int begoff;
6102 int endoff;
6103 int nulonly;
6104};
6105
6106struct arglist {
6107 struct strlist *list;
6108 struct strlist **lastp;
6109};
6110
6111
6112static char *expdest;
6113
6114static struct nodelist *argbackq;
6115
6116static struct ifsregion ifsfirst;
6117
6118static struct ifsregion *ifslastp;
6119
6120static struct arglist exparg;
6121
6122
6123
6124
6125
6126
6127static void
6128ifsbreakup(char *string, struct arglist *arglist)
6129{
6130 struct ifsregion *ifsp;
6131 struct strlist *sp;
6132 char *start;
6133 char *p;
6134 char *q;
6135 const char *ifs, *realifs;
6136 int ifsspc;
6137 int nulonly;
6138
6139 start = string;
6140 if (ifslastp != NULL) {
6141 ifsspc = 0;
6142 nulonly = 0;
6143 realifs = ifsset() ? ifsval() : defifs;
6144 ifsp = &ifsfirst;
6145 do {
6146 int afternul;
6147
6148 p = string + ifsp->begoff;
6149 afternul = nulonly;
6150 nulonly = ifsp->nulonly;
6151 ifs = nulonly ? nullstr : realifs;
6152 ifsspc = 0;
6153 while (p < string + ifsp->endoff) {
6154 q = p;
6155 if ((unsigned char)*p == CTLESC)
6156 p++;
6157 if (!strchr(ifs, *p)) {
6158 p++;
6159 continue;
6160 }
6161 if (!(afternul || nulonly))
6162 ifsspc = (strchr(defifs, *p) != NULL);
6163
6164 if (q == start && ifsspc) {
6165 p++;
6166 start = p;
6167 continue;
6168 }
6169 *q = '\0';
6170 sp = stzalloc(sizeof(*sp));
6171 sp->text = start;
6172 *arglist->lastp = sp;
6173 arglist->lastp = &sp->next;
6174 p++;
6175 if (!nulonly) {
6176 for (;;) {
6177 if (p >= string + ifsp->endoff) {
6178 break;
6179 }
6180 q = p;
6181 if ((unsigned char)*p == CTLESC)
6182 p++;
6183 if (strchr(ifs, *p) == NULL) {
6184 p = q;
6185 break;
6186 }
6187 if (strchr(defifs, *p) == NULL) {
6188 if (ifsspc) {
6189 p++;
6190 ifsspc = 0;
6191 } else {
6192 p = q;
6193 break;
6194 }
6195 } else
6196 p++;
6197 }
6198 }
6199 start = p;
6200 }
6201 ifsp = ifsp->next;
6202 } while (ifsp != NULL);
6203 if (nulonly)
6204 goto add;
6205 }
6206
6207 if (!*start)
6208 return;
6209
6210 add:
6211 sp = stzalloc(sizeof(*sp));
6212 sp->text = start;
6213 *arglist->lastp = sp;
6214 arglist->lastp = &sp->next;
6215}
6216
6217static void
6218ifsfree(void)
6219{
6220 struct ifsregion *p = ifsfirst.next;
6221
6222 if (!p)
6223 goto out;
6224
6225 INT_OFF;
6226 do {
6227 struct ifsregion *ifsp;
6228 ifsp = p->next;
6229 free(p);
6230 p = ifsp;
6231 } while (p);
6232 ifsfirst.next = NULL;
6233 INT_ON;
6234 out:
6235 ifslastp = NULL;
6236}
6237
6238static size_t
6239esclen(const char *start, const char *p)
6240{
6241 size_t esc = 0;
6242
6243 while (p > start && (unsigned char)*--p == CTLESC) {
6244 esc++;
6245 }
6246 return esc;
6247}
6248
6249
6250
6251
6252#if !BASH_PATTERN_SUBST
6253#define rmescapes(str, flag, slash_position) \
6254 rmescapes(str, flag)
6255#endif
6256static char *
6257rmescapes(char *str, int flag, int *slash_position)
6258{
6259 static const char qchars[] ALIGN1 = {
6260 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
6261
6262 char *p, *q, *r;
6263 unsigned protect_against_glob;
6264 unsigned globbing;
6265
6266 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
6267 if (!p)
6268 return str;
6269
6270 q = p;
6271 r = str;
6272 if (flag & RMESCAPE_ALLOC) {
6273 size_t len = p - str;
6274 size_t fulllen = len + strlen(p) + 1;
6275
6276 if (flag & RMESCAPE_GROW) {
6277 int strloc = str - (char *)stackblock();
6278 r = makestrspace(fulllen, expdest);
6279
6280 str = (char *)stackblock() + strloc;
6281 p = str + len;
6282 } else if (flag & RMESCAPE_HEAP) {
6283 r = ckmalloc(fulllen);
6284 } else {
6285 r = stalloc(fulllen);
6286 }
6287 q = r;
6288 if (len > 0) {
6289 q = (char *)mempcpy(q, str, len);
6290 }
6291 }
6292
6293 globbing = flag & RMESCAPE_GLOB;
6294 protect_against_glob = globbing;
6295 while (*p) {
6296 if ((unsigned char)*p == CTLQUOTEMARK) {
6297
6298
6299 p++;
6300 protect_against_glob = globbing;
6301 continue;
6302 }
6303 if (*p == '\\') {
6304
6305 protect_against_glob = 0;
6306 goto copy;
6307 }
6308 if ((unsigned char)*p == CTLESC) {
6309 p++;
6310#if DEBUG
6311 if (*p == '\0')
6312 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6313#endif
6314 if (protect_against_glob) {
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330 if (*p == '*'
6331 || *p == '?'
6332 || *p == '['
6333 || *p == '\\'
6334 || *p == ']'
6335 || *p == '-'
6336 || *p == '!'
6337
6338 || *p == '^'
6339 ) {
6340 *q++ = '\\';
6341 }
6342 }
6343 }
6344#if BASH_PATTERN_SUBST
6345 else if (slash_position && p == str + *slash_position) {
6346
6347 globbing = 0;
6348 *slash_position = q - r;
6349 slash_position = NULL;
6350 }
6351#endif
6352 protect_against_glob = globbing;
6353 copy:
6354 *q++ = *p++;
6355 }
6356 *q = '\0';
6357 if (flag & RMESCAPE_GROW) {
6358 expdest = r;
6359 STADJUST(q - r + 1, expdest);
6360 }
6361 return r;
6362}
6363#define pmatch(a, b) !fnmatch((a), (b), 0)
6364
6365
6366
6367
6368
6369
6370static char *
6371preglob(const char *pattern, int flag)
6372{
6373 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
6374}
6375
6376
6377
6378
6379static size_t
6380memtodest(const char *p, size_t len, int flags)
6381{
6382 int syntax = flags & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6383 char *q;
6384 char *s;
6385
6386 if (!len)
6387 return 0;
6388
6389 q = makestrspace(len * 2, expdest);
6390 s = q;
6391
6392 do {
6393 unsigned char c = *p++;
6394 if (c) {
6395 if (flags & QUOTES_ESC) {
6396 int n = SIT(c, syntax);
6397 if (n == CCTL
6398 || ((flags & EXP_QUOTED) && n == CBACK)
6399 ) {
6400 USTPUTC(CTLESC, q);
6401 }
6402 }
6403 } else if (!(flags & EXP_KEEPNUL))
6404 continue;
6405 USTPUTC(c, q);
6406 } while (--len);
6407
6408 expdest = q;
6409 return q - s;
6410}
6411
6412static size_t
6413strtodest(const char *p, int flags)
6414{
6415 size_t len = strlen(p);
6416 memtodest(p, len, flags);
6417 return len;
6418}
6419
6420
6421
6422
6423
6424static int
6425cvtnum(arith_t num, int flags)
6426{
6427
6428
6429 int len = (sizeof(arith_t) >= 4) ? sizeof(arith_t) * 3 : sizeof(arith_t) * 3 + 2;
6430 char buf[len];
6431
6432 len = fmtstr(buf, len, ARITH_FMT, num);
6433 return memtodest(buf, len, flags);
6434}
6435
6436
6437
6438
6439
6440static void
6441recordregion(int start, int end, int nulonly)
6442{
6443 struct ifsregion *ifsp;
6444
6445 if (ifslastp == NULL) {
6446