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