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