ash: dont allow e.g. exec <&10 to attach to stript's fd!
[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];
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 = 0, q = gotsig; i < NSIG - 1; i++, q++) {
7850                 if (!*q)
7851                         continue;
7852                 *q = '\0';
7853
7854                 p = trap[i + 1];
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         int checkexit = 0;
7885         void (*evalfn)(union node *, int);
7886         unsigned isor;
7887         int status;
7888         if (n == NULL) {
7889                 TRACE(("evaltree(NULL) called\n"));
7890                 goto out;
7891         }
7892         TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7893                         getpid(), n, n->type, flags));
7894         switch (n->type) {
7895         default:
7896 #if DEBUG
7897                 out1fmt("Node type = %d\n", n->type);
7898                 fflush(stdout);
7899                 break;
7900 #endif
7901         case NNOT:
7902                 evaltree(n->nnot.com, EV_TESTED);
7903                 status = !exitstatus;
7904                 goto setstatus;
7905         case NREDIR:
7906                 expredir(n->nredir.redirect);
7907                 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7908                 if (!status) {
7909                         evaltree(n->nredir.n, flags & EV_TESTED);
7910                         status = exitstatus;
7911                 }
7912                 popredir(0);
7913                 goto setstatus;
7914         case NCMD:
7915                 evalfn = evalcommand;
7916  checkexit:
7917                 if (eflag && !(flags & EV_TESTED))
7918                         checkexit = ~0;
7919                 goto calleval;
7920         case NFOR:
7921                 evalfn = evalfor;
7922                 goto calleval;
7923         case NWHILE:
7924         case NUNTIL:
7925                 evalfn = evalloop;
7926                 goto calleval;
7927         case NSUBSHELL:
7928         case NBACKGND:
7929                 evalfn = evalsubshell;
7930                 goto calleval;
7931         case NPIPE:
7932                 evalfn = evalpipe;
7933                 goto checkexit;
7934         case NCASE:
7935                 evalfn = evalcase;
7936                 goto calleval;
7937         case NAND:
7938         case NOR:
7939         case NSEMI:
7940 #if NAND + 1 != NOR
7941 #error NAND + 1 != NOR
7942 #endif
7943 #if NOR + 1 != NSEMI
7944 #error NOR + 1 != NSEMI
7945 #endif
7946                 isor = n->type - NAND;
7947                 evaltree(
7948                         n->nbinary.ch1,
7949                         (flags | ((isor >> 1) - 1)) & EV_TESTED
7950                 );
7951                 if (!exitstatus == isor)
7952                         break;
7953                 if (!evalskip) {
7954                         n = n->nbinary.ch2;
7955  evaln:
7956                         evalfn = evaltree;
7957  calleval:
7958                         evalfn(n, flags);
7959                         break;
7960                 }
7961                 break;
7962         case NIF:
7963                 evaltree(n->nif.test, EV_TESTED);
7964                 if (evalskip)
7965                         break;
7966                 if (exitstatus == 0) {
7967                         n = n->nif.ifpart;
7968                         goto evaln;
7969                 } else if (n->nif.elsepart) {
7970                         n = n->nif.elsepart;
7971                         goto evaln;
7972                 }
7973                 goto success;
7974         case NDEFUN:
7975                 defun(n->narg.text, n->narg.next);
7976  success:
7977                 status = 0;
7978  setstatus:
7979                 exitstatus = status;
7980                 break;
7981         }
7982  out:
7983         if ((checkexit & exitstatus))
7984                 evalskip |= SKIPEVAL;
7985         else if (pendingsig && dotrap())
7986                 goto exexit;
7987
7988         if (flags & EV_EXIT) {
7989  exexit:
7990                 raise_exception(EXEXIT);
7991         }
7992 }
7993
7994 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
7995 static
7996 #endif
7997 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
7998
7999 static void
8000 evalloop(union node *n, int flags)
8001 {
8002         int status;
8003
8004         loopnest++;
8005         status = 0;
8006         flags &= EV_TESTED;
8007         for (;;) {
8008                 int i;
8009
8010                 evaltree(n->nbinary.ch1, EV_TESTED);
8011                 if (evalskip) {
8012  skipping:
8013                         if (evalskip == SKIPCONT && --skipcount <= 0) {
8014                                 evalskip = 0;
8015                                 continue;
8016                         }
8017                         if (evalskip == SKIPBREAK && --skipcount <= 0)
8018                                 evalskip = 0;
8019                         break;
8020                 }
8021                 i = exitstatus;
8022                 if (n->type != NWHILE)
8023                         i = !i;
8024                 if (i != 0)
8025                         break;
8026                 evaltree(n->nbinary.ch2, flags);
8027                 status = exitstatus;
8028                 if (evalskip)
8029                         goto skipping;
8030         }
8031         loopnest--;
8032         exitstatus = status;
8033 }
8034
8035 static void
8036 evalfor(union node *n, int flags)
8037 {
8038         struct arglist arglist;
8039         union node *argp;
8040         struct strlist *sp;
8041         struct stackmark smark;
8042
8043         setstackmark(&smark);
8044         arglist.list = NULL;
8045         arglist.lastp = &arglist.list;
8046         for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8047                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8048                 /* XXX */
8049                 if (evalskip)
8050                         goto out;
8051         }
8052         *arglist.lastp = NULL;
8053
8054         exitstatus = 0;
8055         loopnest++;
8056         flags &= EV_TESTED;
8057         for (sp = arglist.list; sp; sp = sp->next) {
8058                 setvar(n->nfor.var, sp->text, 0);
8059                 evaltree(n->nfor.body, flags);
8060                 if (evalskip) {
8061                         if (evalskip == SKIPCONT && --skipcount <= 0) {
8062                                 evalskip = 0;
8063                                 continue;
8064                         }
8065                         if (evalskip == SKIPBREAK && --skipcount <= 0)
8066                                 evalskip = 0;
8067                         break;
8068                 }
8069         }
8070         loopnest--;
8071  out:
8072         popstackmark(&smark);
8073 }
8074
8075 static void
8076 evalcase(union node *n, int flags)
8077 {
8078         union node *cp;
8079         union node *patp;
8080         struct arglist arglist;
8081         struct stackmark smark;
8082
8083         setstackmark(&smark);
8084         arglist.list = NULL;
8085         arglist.lastp = &arglist.list;
8086         expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8087         exitstatus = 0;
8088         for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8089                 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8090                         if (casematch(patp, arglist.list->text)) {
8091                                 if (evalskip == 0) {
8092                                         evaltree(cp->nclist.body, flags);
8093                                 }
8094                                 goto out;
8095                         }
8096                 }
8097         }
8098  out:
8099         popstackmark(&smark);
8100 }
8101
8102 /*
8103  * Kick off a subshell to evaluate a tree.
8104  */
8105 static void
8106 evalsubshell(union node *n, int flags)
8107 {
8108         struct job *jp;
8109         int backgnd = (n->type == NBACKGND);
8110         int status;
8111
8112         expredir(n->nredir.redirect);
8113         if (!backgnd && flags & EV_EXIT && !trap[0])
8114                 goto nofork;
8115         INT_OFF;
8116         jp = makejob(/*n,*/ 1);
8117         if (forkshell(jp, n, backgnd) == 0) {
8118                 INT_ON;
8119                 flags |= EV_EXIT;
8120                 if (backgnd)
8121                         flags &=~ EV_TESTED;
8122  nofork:
8123                 redirect(n->nredir.redirect, 0);
8124                 evaltreenr(n->nredir.n, flags);
8125                 /* never returns */
8126         }
8127         status = 0;
8128         if (!backgnd)
8129                 status = waitforjob(jp);
8130         exitstatus = status;
8131         INT_ON;
8132 }
8133
8134 /*
8135  * Compute the names of the files in a redirection list.
8136  */
8137 static void fixredir(union node *, const char *, int);
8138 static void
8139 expredir(union node *n)
8140 {
8141         union node *redir;
8142
8143         for (redir = n; redir; redir = redir->nfile.next) {
8144                 struct arglist fn;
8145
8146                 fn.list = NULL;
8147                 fn.lastp = &fn.list;
8148                 switch (redir->type) {
8149                 case NFROMTO:
8150                 case NFROM:
8151                 case NTO:
8152                 case NCLOBBER:
8153                 case NAPPEND:
8154                         expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8155                         redir->nfile.expfname = fn.list->text;
8156                         break;
8157                 case NFROMFD:
8158                 case NTOFD:
8159                         if (redir->ndup.vname) {
8160                                 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8161                                 if (fn.list == NULL)
8162                                         ash_msg_and_raise_error("redir error");
8163                                 fixredir(redir, fn.list->text, 1);
8164                         }
8165                         break;
8166                 }
8167         }
8168 }
8169
8170 /*
8171  * Evaluate a pipeline.  All the processes in the pipeline are children
8172  * of the process creating the pipeline.  (This differs from some versions
8173  * of the shell, which make the last process in a pipeline the parent
8174  * of all the rest.)
8175  */
8176 static void
8177 evalpipe(union node *n, int flags)
8178 {
8179         struct job *jp;
8180         struct nodelist *lp;
8181         int pipelen;
8182         int prevfd;
8183         int pip[2];
8184
8185         TRACE(("evalpipe(0x%lx) called\n", (long)n));
8186         pipelen = 0;
8187         for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8188                 pipelen++;
8189         flags |= EV_EXIT;
8190         INT_OFF;
8191         jp = makejob(/*n,*/ pipelen);
8192         prevfd = -1;
8193         for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8194                 prehash(lp->n);
8195                 pip[1] = -1;
8196                 if (lp->next) {
8197                         if (pipe(pip) < 0) {
8198                                 close(prevfd);
8199                                 ash_msg_and_raise_error("pipe call failed");
8200                         }
8201                 }
8202                 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8203                         INT_ON;
8204                         if (pip[1] >= 0) {
8205                                 close(pip[0]);
8206                         }
8207                         if (prevfd > 0) {
8208                                 dup2(prevfd, 0);
8209                                 close(prevfd);
8210                         }
8211                         if (pip[1] > 1) {
8212                                 dup2(pip[1], 1);
8213                                 close(pip[1]);
8214                         }
8215                         evaltreenr(lp->n, flags);
8216                         /* never returns */
8217                 }
8218                 if (prevfd >= 0)
8219                         close(prevfd);
8220                 prevfd = pip[0];
8221                 close(pip[1]);
8222         }
8223         if (n->npipe.pipe_backgnd == 0) {
8224                 exitstatus = waitforjob(jp);
8225                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
8226         }
8227         INT_ON;
8228 }
8229
8230 /*
8231  * Controls whether the shell is interactive or not.
8232  */
8233 static void
8234 setinteractive(int on)
8235 {
8236         static smallint is_interactive;
8237
8238         if (++on == is_interactive)
8239                 return;
8240         is_interactive = on;
8241         setsignal(SIGINT);
8242         setsignal(SIGQUIT);
8243         setsignal(SIGTERM);
8244 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8245         if (is_interactive > 1) {
8246                 /* Looks like they want an interactive shell */
8247                 static smallint did_banner;
8248
8249                 if (!did_banner) {
8250                         out1fmt(
8251                                 "\n\n"
8252                                 "%s built-in shell (ash)\n"
8253                                 "Enter 'help' for a list of built-in commands."
8254                                 "\n\n",
8255                                 bb_banner);
8256                         did_banner = 1;
8257                 }
8258         }
8259 #endif
8260 }
8261
8262 static void
8263 optschanged(void)
8264 {
8265 #if DEBUG
8266         opentrace();
8267 #endif
8268         setinteractive(iflag);
8269         setjobctl(mflag);
8270 #if ENABLE_FEATURE_EDITING_VI
8271         if (viflag)
8272                 line_input_state->flags |= VI_MODE;
8273         else
8274                 line_input_state->flags &= ~VI_MODE;
8275 #else
8276         viflag = 0; /* forcibly keep the option off */
8277 #endif
8278 }
8279
8280 static struct localvar *localvars;
8281
8282 /*
8283  * Called after a function returns.
8284  * Interrupts must be off.
8285  */
8286 static void
8287 poplocalvars(void)
8288 {
8289         struct localvar *lvp;
8290         struct var *vp;
8291
8292         while ((lvp = localvars) != NULL) {
8293                 localvars = lvp->next;
8294                 vp = lvp->vp;
8295                 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8296                 if (vp == NULL) {       /* $- saved */
8297                         memcpy(optlist, lvp->text, sizeof(optlist));
8298                         free((char*)lvp->text);
8299                         optschanged();
8300                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8301                         unsetvar(vp->text);
8302                 } else {
8303                         if (vp->func)
8304                                 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8305                         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8306                                 free((char*)vp->text);
8307                         vp->flags = lvp->flags;
8308                         vp->text = lvp->text;
8309                 }
8310                 free(lvp);
8311         }
8312 }
8313
8314 static int
8315 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8316 {
8317         volatile struct shparam saveparam;
8318         struct localvar *volatile savelocalvars;
8319         struct jmploc *volatile savehandler;
8320         struct jmploc jmploc;
8321         int e;
8322
8323         saveparam = shellparam;
8324         savelocalvars = localvars;
8325         e = setjmp(jmploc.loc);
8326         if (e) {
8327                 goto funcdone;
8328         }
8329         INT_OFF;
8330         savehandler = exception_handler;
8331         exception_handler = &jmploc;
8332         localvars = NULL;
8333         shellparam.malloced = 0;
8334         func->count++;
8335         funcnest++;
8336         INT_ON;
8337         shellparam.nparam = argc - 1;
8338         shellparam.p = argv + 1;
8339 #if ENABLE_ASH_GETOPTS
8340         shellparam.optind = 1;
8341         shellparam.optoff = -1;
8342 #endif
8343         evaltree(&func->n, flags & EV_TESTED);
8344  funcdone:
8345         INT_OFF;
8346         funcnest--;
8347         freefunc(func);
8348         poplocalvars();
8349         localvars = savelocalvars;
8350         freeparam(&shellparam);
8351         shellparam = saveparam;
8352         exception_handler = savehandler;
8353         INT_ON;
8354         evalskip &= ~SKIPFUNC;
8355         return e;
8356 }
8357
8358 #if ENABLE_ASH_CMDCMD
8359 static char **
8360 parse_command_args(char **argv, const char **path)
8361 {
8362         char *cp, c;
8363
8364         for (;;) {
8365                 cp = *++argv;
8366                 if (!cp)
8367                         return 0;
8368                 if (*cp++ != '-')
8369                         break;
8370                 c = *cp++;
8371                 if (!c)
8372                         break;
8373                 if (c == '-' && !*cp) {
8374                         argv++;
8375                         break;
8376                 }
8377                 do {
8378                         switch (c) {
8379                         case 'p':
8380                                 *path = bb_default_path;
8381                                 break;
8382                         default:
8383                                 /* run 'typecmd' for other options */
8384                                 return 0;
8385                         }
8386                         c = *cp++;
8387                 } while (c);
8388         }
8389         return argv;
8390 }
8391 #endif
8392
8393 /*
8394  * Make a variable a local variable.  When a variable is made local, it's
8395  * value and flags are saved in a localvar structure.  The saved values
8396  * will be restored when the shell function returns.  We handle the name
8397  * "-" as a special case.
8398  */
8399 static void
8400 mklocal(char *name)
8401 {
8402         struct localvar *lvp;
8403         struct var **vpp;
8404         struct var *vp;
8405
8406         INT_OFF;
8407         lvp = ckzalloc(sizeof(struct localvar));
8408         if (LONE_DASH(name)) {
8409                 char *p;
8410                 p = ckmalloc(sizeof(optlist));
8411                 lvp->text = memcpy(p, optlist, sizeof(optlist));
8412                 vp = NULL;
8413         } else {
8414                 char *eq;
8415
8416                 vpp = hashvar(name);
8417                 vp = *findvar(vpp, name);
8418                 eq = strchr(name, '=');
8419                 if (vp == NULL) {
8420                         if (eq)
8421                                 setvareq(name, VSTRFIXED);
8422                         else
8423                                 setvar(name, NULL, VSTRFIXED);
8424                         vp = *vpp;      /* the new variable */
8425                         lvp->flags = VUNSET;
8426                 } else {
8427                         lvp->text = vp->text;
8428                         lvp->flags = vp->flags;
8429                         vp->flags |= VSTRFIXED|VTEXTFIXED;
8430                         if (eq)
8431                                 setvareq(name, 0);
8432                 }
8433         }
8434         lvp->vp = vp;
8435         lvp->next = localvars;
8436         localvars = lvp;
8437         INT_ON;
8438 }
8439
8440 /*
8441  * The "local" command.
8442  */
8443 static int
8444 localcmd(int argc UNUSED_PARAM, char **argv)
8445 {
8446         char *name;
8447
8448         argv = argptr;
8449         while ((name = *argv++) != NULL) {
8450                 mklocal(name);
8451         }
8452         return 0;
8453 }
8454
8455 static int
8456 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8457 {
8458         return 1;
8459 }
8460
8461 static int
8462 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8463 {
8464         return 0;
8465 }
8466
8467 static int
8468 execcmd(int argc UNUSED_PARAM, char **argv)
8469 {
8470         if (argv[1]) {
8471                 iflag = 0;              /* exit on error */
8472                 mflag = 0;
8473                 optschanged();
8474                 shellexec(argv + 1, pathval(), 0);
8475         }
8476         return 0;
8477 }
8478
8479 /*
8480  * The return command.
8481  */
8482 static int
8483 returncmd(int argc UNUSED_PARAM, char **argv)
8484 {
8485         /*
8486          * If called outside a function, do what ksh does;
8487          * skip the rest of the file.
8488          */
8489         evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8490         return argv[1] ? number(argv[1]) : exitstatus;
8491 }
8492
8493 /* Forward declarations for builtintab[] */
8494 static int breakcmd(int, char **);
8495 static int dotcmd(int, char **);
8496 static int evalcmd(int, char **);
8497 static int exitcmd(int, char **);
8498 static int exportcmd(int, char **);
8499 #if ENABLE_ASH_GETOPTS
8500 static int getoptscmd(int, char **);
8501 #endif
8502 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8503 static int helpcmd(int, char **);
8504 #endif
8505 #if ENABLE_ASH_MATH_SUPPORT
8506 static int letcmd(int, char **);
8507 #endif
8508 static int readcmd(int, char **);
8509 static int setcmd(int, char **);
8510 static int shiftcmd(int, char **);
8511 static int timescmd(int, char **);
8512 static int trapcmd(int, char **);
8513 static int umaskcmd(int, char **);
8514 static int unsetcmd(int, char **);
8515 static int ulimitcmd(int, char **);
8516
8517 #define BUILTIN_NOSPEC          "0"
8518 #define BUILTIN_SPECIAL         "1"
8519 #define BUILTIN_REGULAR         "2"
8520 #define BUILTIN_SPEC_REG        "3"
8521 #define BUILTIN_ASSIGN          "4"
8522 #define BUILTIN_SPEC_ASSG       "5"
8523 #define BUILTIN_REG_ASSG        "6"
8524 #define BUILTIN_SPEC_REG_ASSG   "7"
8525
8526 /* We do not handle [[ expr ]] bashism bash-compatibly,
8527  * we make it a synonym of [ expr ].
8528  * Basically, word splitting and pathname expansion should NOT be performed
8529  * Examples:
8530  * no word splitting:     a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8531  * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8532  * Additional operators:
8533  * || and && should work as -o and -a
8534  * =~ regexp match
8535  * Apart from the above, [[ expr ]] should work as [ expr ]
8536  */
8537
8538 #define echocmd   echo_main
8539 #define printfcmd printf_main
8540 #define testcmd   test_main
8541
8542 /* Keep these in proper order since it is searched via bsearch() */
8543 static const struct builtincmd builtintab[] = {
8544         { BUILTIN_SPEC_REG      ".", dotcmd },
8545         { BUILTIN_SPEC_REG      ":", truecmd },
8546 #if ENABLE_ASH_BUILTIN_TEST
8547         { BUILTIN_REGULAR       "[", testcmd },
8548 #if ENABLE_ASH_BASH_COMPAT
8549         { BUILTIN_REGULAR       "[[", testcmd },
8550 #endif
8551 #endif
8552 #if ENABLE_ASH_ALIAS
8553         { BUILTIN_REG_ASSG      "alias", aliascmd },
8554 #endif
8555 #if JOBS
8556         { BUILTIN_REGULAR       "bg", fg_bgcmd },
8557 #endif
8558         { BUILTIN_SPEC_REG      "break", breakcmd },
8559         { BUILTIN_REGULAR       "cd", cdcmd },
8560         { BUILTIN_NOSPEC        "chdir", cdcmd },
8561 #if ENABLE_ASH_CMDCMD
8562         { BUILTIN_REGULAR       "command", commandcmd },
8563 #endif
8564         { BUILTIN_SPEC_REG      "continue", breakcmd },
8565 #if ENABLE_ASH_BUILTIN_ECHO
8566         { BUILTIN_REGULAR       "echo", echocmd },
8567 #endif
8568         { BUILTIN_SPEC_REG      "eval", evalcmd },
8569         { BUILTIN_SPEC_REG      "exec", execcmd },
8570         { BUILTIN_SPEC_REG      "exit", exitcmd },
8571         { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8572         { BUILTIN_REGULAR       "false", falsecmd },
8573 #if JOBS
8574         { BUILTIN_REGULAR       "fg", fg_bgcmd },
8575 #endif
8576 #if ENABLE_ASH_GETOPTS
8577         { BUILTIN_REGULAR       "getopts", getoptscmd },
8578 #endif
8579         { BUILTIN_NOSPEC        "hash", hashcmd },
8580 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8581         { BUILTIN_NOSPEC        "help", helpcmd },
8582 #endif
8583 #if JOBS
8584         { BUILTIN_REGULAR       "jobs", jobscmd },
8585         { BUILTIN_REGULAR       "kill", killcmd },
8586 #endif
8587 #if ENABLE_ASH_MATH_SUPPORT
8588         { BUILTIN_NOSPEC        "let", letcmd },
8589 #endif
8590         { BUILTIN_ASSIGN        "local", localcmd },
8591 #if ENABLE_ASH_BUILTIN_PRINTF
8592         { BUILTIN_REGULAR       "printf", printfcmd },
8593 #endif
8594         { BUILTIN_NOSPEC        "pwd", pwdcmd },
8595         { BUILTIN_REGULAR       "read", readcmd },
8596         { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8597         { BUILTIN_SPEC_REG      "return", returncmd },
8598         { BUILTIN_SPEC_REG      "set", setcmd },
8599         { BUILTIN_SPEC_REG      "shift", shiftcmd },
8600         { BUILTIN_SPEC_REG      "source", dotcmd },
8601 #if ENABLE_ASH_BUILTIN_TEST
8602         { BUILTIN_REGULAR       "test", testcmd },
8603 #endif
8604         { BUILTIN_SPEC_REG      "times", timescmd },
8605         { BUILTIN_SPEC_REG      "trap", trapcmd },
8606         { BUILTIN_REGULAR       "true", truecmd },
8607         { BUILTIN_NOSPEC        "type", typecmd },
8608         { BUILTIN_NOSPEC        "ulimit", ulimitcmd },
8609         { BUILTIN_REGULAR       "umask", umaskcmd },
8610 #if ENABLE_ASH_ALIAS
8611         { BUILTIN_REGULAR       "unalias", unaliascmd },
8612 #endif
8613         { BUILTIN_SPEC_REG      "unset", unsetcmd },
8614         { BUILTIN_REGULAR       "wait", waitcmd },
8615 };
8616
8617 /* Should match the above table! */
8618 #define COMMANDCMD (builtintab + \
8619         2 + \
8620         1 * ENABLE_ASH_BUILTIN_TEST + \
8621         1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8622         1 * ENABLE_ASH_ALIAS + \
8623         1 * ENABLE_ASH_JOB_CONTROL + \
8624         3)
8625 #define EXECCMD (builtintab + \
8626         2 + \
8627         1 * ENABLE_ASH_BUILTIN_TEST + \
8628         1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8629         1 * ENABLE_ASH_ALIAS + \
8630         1 * ENABLE_ASH_JOB_CONTROL + \
8631         3 + \
8632         1 * ENABLE_ASH_CMDCMD + \
8633         1 + \
8634         ENABLE_ASH_BUILTIN_ECHO + \
8635         1)
8636
8637 /*
8638  * Search the table of builtin commands.
8639  */
8640 static struct builtincmd *
8641 find_builtin(const char *name)
8642 {
8643         struct builtincmd *bp;
8644
8645         bp = bsearch(
8646                 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8647                 pstrcmp
8648         );
8649         return bp;
8650 }
8651
8652 /*
8653  * Execute a simple command.
8654  */
8655 static int
8656 isassignment(const char *p)
8657 {
8658         const char *q = endofname(p);
8659         if (p == q)
8660                 return 0;
8661         return *q == '=';
8662 }
8663 static int
8664 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8665 {
8666         /* Preserve exitstatus of a previous possible redirection
8667          * as POSIX mandates */
8668         return back_exitstatus;
8669 }
8670 static void
8671 evalcommand(union node *cmd, int flags)
8672 {
8673         static const struct builtincmd null_bltin = {
8674                 "\0\0", bltincmd /* why three NULs? */
8675         };
8676         struct stackmark smark;
8677         union node *argp;
8678         struct arglist arglist;
8679         struct arglist varlist;
8680         char **argv;
8681         int argc;
8682         const struct strlist *sp;
8683         struct cmdentry cmdentry;
8684         struct job *jp;
8685         char *lastarg;
8686         const char *path;
8687         int spclbltin;
8688         int cmd_is_exec;
8689         int status;
8690         char **nargv;
8691         struct builtincmd *bcmd;
8692         int pseudovarflag = 0;
8693
8694         /* First expand the arguments. */
8695         TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8696         setstackmark(&smark);
8697         back_exitstatus = 0;
8698
8699         cmdentry.cmdtype = CMDBUILTIN;
8700         cmdentry.u.cmd = &null_bltin;
8701         varlist.lastp = &varlist.list;
8702         *varlist.lastp = NULL;
8703         arglist.lastp = &arglist.list;
8704         *arglist.lastp = NULL;
8705
8706         argc = 0;
8707         if (cmd->ncmd.args) {
8708                 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8709                 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8710         }
8711
8712         for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8713                 struct strlist **spp;
8714
8715                 spp = arglist.lastp;
8716                 if (pseudovarflag && isassignment(argp->narg.text))
8717                         expandarg(argp, &arglist, EXP_VARTILDE);
8718                 else
8719                         expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8720
8721                 for (sp = *spp; sp; sp = sp->next)
8722                         argc++;
8723         }
8724
8725         argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8726         for (sp = arglist.list; sp; sp = sp->next) {
8727                 TRACE(("evalcommand arg: %s\n", sp->text));
8728                 *nargv++ = sp->text;
8729         }
8730         *nargv = NULL;
8731
8732         lastarg = NULL;
8733         if (iflag && funcnest == 0 && argc > 0)
8734                 lastarg = nargv[-1];
8735
8736         preverrout_fd = 2;
8737         expredir(cmd->ncmd.redirect);
8738         status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8739
8740         path = vpath.text;
8741         for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8742                 struct strlist **spp;
8743                 char *p;
8744
8745                 spp = varlist.lastp;
8746                 expandarg(argp, &varlist, EXP_VARTILDE);
8747
8748                 /*
8749                  * Modify the command lookup path, if a PATH= assignment
8750                  * is present
8751                  */
8752                 p = (*spp)->text;
8753                 if (varequal(p, path))
8754                         path = p;
8755         }
8756
8757         /* Print the command if xflag is set. */
8758         if (xflag) {
8759                 int n;
8760                 const char *p = " %s";
8761
8762                 p++;
8763                 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8764
8765                 sp = varlist.list;
8766                 for (n = 0; n < 2; n++) {
8767                         while (sp) {
8768                                 fdprintf(preverrout_fd, p, sp->text);
8769                                 sp = sp->next;
8770                                 if (*p == '%') {
8771                                         p--;
8772                                 }
8773                         }
8774                         sp = arglist.list;
8775                 }
8776                 safe_write(preverrout_fd, "\n", 1);
8777         }
8778
8779         cmd_is_exec = 0;
8780         spclbltin = -1;
8781
8782         /* Now locate the command. */
8783         if (argc) {
8784                 const char *oldpath;
8785                 int cmd_flag = DO_ERR;
8786
8787                 path += 5;
8788                 oldpath = path;
8789                 for (;;) {
8790                         find_command(argv[0], &cmdentry, cmd_flag, path);
8791                         if (cmdentry.cmdtype == CMDUNKNOWN) {
8792                                 flush_stderr();
8793                                 status = 127;
8794                                 goto bail;
8795                         }
8796
8797                         /* implement bltin and command here */
8798                         if (cmdentry.cmdtype != CMDBUILTIN)
8799                                 break;
8800                         if (spclbltin < 0)
8801                                 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8802                         if (cmdentry.u.cmd == EXECCMD)
8803                                 cmd_is_exec++;
8804 #if ENABLE_ASH_CMDCMD
8805                         if (cmdentry.u.cmd == COMMANDCMD) {
8806                                 path = oldpath;
8807                                 nargv = parse_command_args(argv, &path);
8808                                 if (!nargv)
8809                                         break;
8810                                 argc -= nargv - argv;
8811                                 argv = nargv;
8812                                 cmd_flag |= DO_NOFUNC;
8813                         } else
8814 #endif
8815                                 break;
8816                 }
8817         }
8818
8819         if (status) {
8820                 /* We have a redirection error. */
8821                 if (spclbltin > 0)
8822                         raise_exception(EXERROR);
8823  bail:
8824                 exitstatus = status;
8825                 goto out;
8826         }
8827
8828         /* Execute the command. */
8829         switch (cmdentry.cmdtype) {
8830         default:
8831 #if ENABLE_FEATURE_SH_NOFORK
8832         {
8833                 /* find_command() encodes applet_no as (-2 - applet_no) */
8834                 int applet_no = (- cmdentry.u.index - 2);
8835                 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
8836                         listsetvar(varlist.list, VEXPORT|VSTACK);
8837                         /* run <applet>_main() */
8838                         exitstatus = run_nofork_applet(applet_no, argv);
8839                         break;
8840                 }
8841         }
8842 #endif
8843
8844                 /* Fork off a child process if necessary. */
8845                 if (!(flags & EV_EXIT) || trap[0]) {
8846                         INT_OFF;
8847                         jp = makejob(/*cmd,*/ 1);
8848                         if (forkshell(jp, cmd, FORK_FG) != 0) {
8849                                 exitstatus = waitforjob(jp);
8850                                 INT_ON;
8851                                 break;
8852                         }
8853                         FORCE_INT_ON;
8854                 }
8855                 listsetvar(varlist.list, VEXPORT|VSTACK);
8856                 shellexec(argv, path, cmdentry.u.index);
8857                 /* NOTREACHED */
8858
8859         case CMDBUILTIN:
8860                 cmdenviron = varlist.list;
8861                 if (cmdenviron) {
8862                         struct strlist *list = cmdenviron;
8863                         int i = VNOSET;
8864                         if (spclbltin > 0 || argc == 0) {
8865                                 i = 0;
8866                                 if (cmd_is_exec && argc > 1)
8867                                         i = VEXPORT;
8868                         }
8869                         listsetvar(list, i);
8870                 }
8871                 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8872                         int exit_status;
8873                         int i = exception;
8874                         if (i == EXEXIT)
8875                                 goto raise;
8876                         exit_status = 2;
8877                         if (i == EXINT)
8878                                 exit_status = 128 + SIGINT;
8879                         if (i == EXSIG)
8880                                 exit_status = 128 + pendingsig;
8881                         exitstatus = exit_status;
8882                         if (i == EXINT || spclbltin > 0) {
8883  raise:
8884                                 longjmp(exception_handler->loc, 1);
8885                         }
8886                         FORCE_INT_ON;
8887                 }
8888                 break;
8889
8890         case CMDFUNCTION:
8891                 listsetvar(varlist.list, 0);
8892                 if (evalfun(cmdentry.u.func, argc, argv, flags))
8893                         goto raise;
8894                 break;
8895         }
8896
8897  out:
8898         popredir(cmd_is_exec);
8899         if (lastarg) {
8900                 /* dsl: I think this is intended to be used to support
8901                  * '_' in 'vi' command mode during line editing...
8902                  * However I implemented that within libedit itself.
8903                  */
8904                 setvar("_", lastarg, 0);
8905         }
8906         popstackmark(&smark);
8907 }
8908
8909 static int
8910 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8911 {
8912         char *volatile savecmdname;
8913         struct jmploc *volatile savehandler;
8914         struct jmploc jmploc;
8915         int i;
8916
8917         savecmdname = commandname;
8918         i = setjmp(jmploc.loc);
8919         if (i)
8920                 goto cmddone;
8921         savehandler = exception_handler;
8922         exception_handler = &jmploc;
8923         commandname = argv[0];
8924         argptr = argv + 1;
8925         optptr = NULL;                  /* initialize nextopt */
8926         exitstatus = (*cmd->builtin)(argc, argv);
8927         flush_stdout_stderr();
8928  cmddone:
8929         exitstatus |= ferror(stdout);
8930         clearerr(stdout);
8931         commandname = savecmdname;
8932 //      exsig = 0;
8933         exception_handler = savehandler;
8934
8935         return i;
8936 }
8937
8938 static int
8939 goodname(const char *p)
8940 {
8941         return !*endofname(p);
8942 }
8943
8944
8945 /*
8946  * Search for a command.  This is called before we fork so that the
8947  * location of the command will be available in the parent as well as
8948  * the child.  The check for "goodname" is an overly conservative
8949  * check that the name will not be subject to expansion.
8950  */
8951 static void
8952 prehash(union node *n)
8953 {
8954         struct cmdentry entry;
8955
8956         if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
8957                 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
8958 }
8959
8960
8961 /* ============ Builtin commands
8962  *
8963  * Builtin commands whose functions are closely tied to evaluation
8964  * are implemented here.
8965  */
8966
8967 /*
8968  * Handle break and continue commands.  Break, continue, and return are
8969  * all handled by setting the evalskip flag.  The evaluation routines
8970  * above all check this flag, and if it is set they start skipping
8971  * commands rather than executing them.  The variable skipcount is
8972  * the number of loops to break/continue, or the number of function
8973  * levels to return.  (The latter is always 1.)  It should probably
8974  * be an error to break out of more loops than exist, but it isn't
8975  * in the standard shell so we don't make it one here.
8976  */
8977 static int
8978 breakcmd(int argc UNUSED_PARAM, char **argv)
8979 {
8980         int n = argv[1] ? number(argv[1]) : 1;
8981
8982         if (n <= 0)
8983                 ash_msg_and_raise_error(illnum, argv[1]);
8984         if (n > loopnest)
8985                 n = loopnest;
8986         if (n > 0) {
8987                 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
8988                 skipcount = n;
8989         }
8990         return 0;
8991 }
8992
8993
8994 /* ============ input.c
8995  *
8996  * This implements the input routines used by the parser.
8997  */
8998
8999 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
9000
9001 enum {
9002         INPUT_PUSH_FILE = 1,
9003         INPUT_NOFILE_OK = 2,
9004 };
9005
9006 static int plinno = 1;                  /* input line number */
9007 /* number of characters left in input buffer */
9008 static int parsenleft;                  /* copy of parsefile->nleft */
9009 static int parselleft;                  /* copy of parsefile->lleft */
9010 /* next character in input buffer */
9011 static char *parsenextc;                /* copy of parsefile->nextc */
9012
9013 static smallint checkkwd;
9014 /* values of checkkwd variable */
9015 #define CHKALIAS        0x1
9016 #define CHKKWD          0x2
9017 #define CHKNL           0x4
9018
9019 static void
9020 popstring(void)
9021 {
9022         struct strpush *sp = g_parsefile->strpush;
9023
9024         INT_OFF;
9025 #if ENABLE_ASH_ALIAS
9026         if (sp->ap) {
9027                 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
9028                         checkkwd |= CHKALIAS;
9029                 }
9030                 if (sp->string != sp->ap->val) {
9031                         free(sp->string);
9032                 }
9033                 sp->ap->flag &= ~ALIASINUSE;
9034                 if (sp->ap->flag & ALIASDEAD) {
9035                         unalias(sp->ap->name);
9036                 }
9037         }
9038 #endif
9039         parsenextc = sp->prevstring;
9040         parsenleft = sp->prevnleft;
9041 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
9042         g_parsefile->strpush = sp->prev;
9043         if (sp != &(g_parsefile->basestrpush))
9044                 free(sp);
9045         INT_ON;
9046 }
9047
9048 static int
9049 preadfd(void)
9050 {
9051         int nr;
9052         char *buf = g_parsefile->buf;
9053         parsenextc = buf;
9054
9055 #if ENABLE_FEATURE_EDITING
9056  retry:
9057         if (!iflag || g_parsefile->fd)
9058                 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9059         else {
9060 #if ENABLE_FEATURE_TAB_COMPLETION
9061                 line_input_state->path_lookup = pathval();
9062 #endif
9063                 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
9064                 if (nr == 0) {
9065                         /* Ctrl+C pressed */
9066                         if (trap[SIGINT]) {
9067                                 buf[0] = '\n';
9068                                 buf[1] = '\0';
9069                                 raise(SIGINT);
9070                                 return 1;
9071                         }
9072                         goto retry;
9073                 }
9074                 if (nr < 0 && errno == 0) {
9075                         /* Ctrl+D pressed */
9076                         nr = 0;
9077                 }
9078         }
9079 #else
9080         nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9081 #endif
9082
9083 #if 0
9084 /* nonblock_safe_read() handles this problem */
9085         if (nr < 0) {
9086                 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9087                         int flags = fcntl(0, F_GETFL);
9088                         if (flags >= 0 && (flags & O_NONBLOCK)) {
9089                                 flags &= ~O_NONBLOCK;
9090                                 if (fcntl(0, F_SETFL, flags) >= 0) {
9091                                         out2str("sh: turning off NDELAY mode\n");
9092                                         goto retry;
9093                                 }
9094                         }
9095                 }
9096         }
9097 #endif
9098         return nr;
9099 }
9100
9101 /*
9102  * Refill the input buffer and return the next input character:
9103  *
9104  * 1) If a string was pushed back on the input, pop it;
9105  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
9106  *    from a string so we can't refill the buffer, return EOF.
9107  * 3) If the is more stuff in this buffer, use it else call read to fill it.
9108  * 4) Process input up to the next newline, deleting nul characters.
9109  */
9110 static int
9111 preadbuffer(void)
9112 {
9113         char *q;
9114         int more;
9115         char savec;
9116
9117         while (g_parsefile->strpush) {
9118 #if ENABLE_ASH_ALIAS
9119                 if (parsenleft == -1 && g_parsefile->strpush->ap &&
9120                         parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
9121                         return PEOA;
9122                 }
9123 #endif
9124                 popstring();
9125                 if (--parsenleft >= 0)
9126                         return signed_char2int(*parsenextc++);
9127         }
9128         if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL)
9129                 return PEOF;
9130         flush_stdout_stderr();
9131
9132         more = parselleft;
9133         if (more <= 0) {
9134  again:
9135                 more = preadfd();
9136                 if (more <= 0) {
9137                         parselleft = parsenleft = EOF_NLEFT;
9138                         return PEOF;
9139                 }
9140         }
9141
9142         q = parsenextc;
9143
9144         /* delete nul characters */
9145         for (;;) {
9146                 int c;
9147
9148                 more--;
9149                 c = *q;
9150
9151                 if (!c)
9152                         memmove(q, q + 1, more);
9153                 else {
9154                         q++;
9155                         if (c == '\n') {
9156                                 parsenleft = q - parsenextc - 1;
9157                                 break;
9158                         }
9159                 }
9160
9161                 if (more <= 0) {
9162                         parsenleft = q - parsenextc - 1;
9163                         if (parsenleft < 0)
9164                                 goto again;
9165                         break;
9166                 }
9167         }
9168         parselleft = more;
9169
9170         savec = *q;
9171         *q = '\0';
9172
9173         if (vflag) {
9174                 out2str(parsenextc);
9175         }
9176
9177         *q = savec;
9178
9179         return signed_char2int(*parsenextc++);
9180 }
9181
9182 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
9183 static int
9184 pgetc(void)
9185 {
9186         return pgetc_as_macro();
9187 }
9188
9189 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9190 #define pgetc_macro() pgetc()
9191 #else
9192 #define pgetc_macro() pgetc_as_macro()
9193 #endif
9194
9195 /*
9196  * Same as pgetc(), but ignores PEOA.
9197  */
9198 #if ENABLE_ASH_ALIAS
9199 static int
9200 pgetc2(void)
9201 {
9202         int c;
9203
9204         do {
9205                 c = pgetc_macro();
9206         } while (c == PEOA);
9207         return c;
9208 }
9209 #else
9210 static int
9211 pgetc2(void)
9212 {
9213         return pgetc_macro();
9214 }
9215 #endif
9216
9217 /*
9218  * Read a line from the script.
9219  */
9220 static char *
9221 pfgets(char *line, int len)
9222 {
9223         char *p = line;
9224         int nleft = len;
9225         int c;
9226
9227         while (--nleft > 0) {
9228                 c = pgetc2();
9229                 if (c == PEOF) {
9230                         if (p == line)
9231                                 return NULL;
9232                         break;
9233                 }
9234                 *p++ = c;
9235                 if (c == '\n')
9236                         break;
9237         }
9238         *p = '\0';
9239         return line;
9240 }
9241
9242 /*
9243  * Undo the last call to pgetc.  Only one character may be pushed back.
9244  * PEOF may be pushed back.
9245  */
9246 static void
9247 pungetc(void)
9248 {
9249         parsenleft++;
9250         parsenextc--;
9251 }
9252
9253 /*
9254  * Push a string back onto the input at this current parsefile level.
9255  * We handle aliases this way.
9256  */
9257 #if !ENABLE_ASH_ALIAS
9258 #define pushstring(s, ap) pushstring(s)
9259 #endif
9260 static void
9261 pushstring(char *s, struct alias *ap)
9262 {
9263         struct strpush *sp;
9264         size_t len;
9265
9266         len = strlen(s);
9267         INT_OFF;
9268 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
9269         if (g_parsefile->strpush) {
9270                 sp = ckzalloc(sizeof(struct strpush));
9271                 sp->prev = g_parsefile->strpush;
9272                 g_parsefile->strpush = sp;
9273         } else
9274                 sp = g_parsefile->strpush = &(g_parsefile->basestrpush);
9275         sp->prevstring = parsenextc;
9276         sp->prevnleft = parsenleft;
9277 #if ENABLE_ASH_ALIAS
9278         sp->ap = ap;
9279         if (ap) {
9280                 ap->flag |= ALIASINUSE;
9281                 sp->string = s;
9282         }
9283 #endif
9284         parsenextc = s;
9285         parsenleft = len;
9286         INT_ON;
9287 }
9288
9289 /*
9290  * To handle the "." command, a stack of input files is used.  Pushfile
9291  * adds a new entry to the stack and popfile restores the previous level.
9292  */
9293 static void
9294 pushfile(void)
9295 {
9296         struct parsefile *pf;
9297
9298         g_parsefile->nleft = parsenleft;
9299         g_parsefile->lleft = parselleft;
9300         g_parsefile->nextc = parsenextc;
9301         g_parsefile->linno = plinno;
9302         pf = ckzalloc(sizeof(*pf));
9303         pf->prev = g_parsefile;
9304         pf->fd = -1;
9305         /*pf->strpush = NULL; - ckzalloc did it */
9306         /*pf->basestrpush.prev = NULL;*/
9307         g_parsefile = pf;
9308 }
9309
9310 static void
9311 popfile(void)
9312 {
9313         struct parsefile *pf = g_parsefile;
9314
9315         INT_OFF;
9316         if (pf->fd >= 0)
9317                 close(pf->fd);
9318         free(pf->buf);
9319         while (pf->strpush)
9320                 popstring();
9321         g_parsefile = pf->prev;
9322         free(pf);
9323         parsenleft = g_parsefile->nleft;
9324         parselleft = g_parsefile->lleft;
9325         parsenextc = g_parsefile->nextc;
9326         plinno = g_parsefile->linno;
9327         INT_ON;
9328 }
9329
9330 /*
9331  * Return to top level.
9332  */
9333 static void
9334 popallfiles(void)
9335 {
9336         while (g_parsefile != &basepf)
9337                 popfile();
9338 }
9339
9340 /*
9341  * Close the file(s) that the shell is reading commands from.  Called
9342  * after a fork is done.
9343  */
9344 static void
9345 closescript(void)
9346 {
9347         popallfiles();
9348         if (g_parsefile->fd > 0) {
9349                 close(g_parsefile->fd);
9350                 g_parsefile->fd = 0;
9351         }
9352 }
9353
9354 /*
9355  * Like setinputfile, but takes an open file descriptor.  Call this with
9356  * interrupts off.
9357  */
9358 static void
9359 setinputfd(int fd, int push)
9360 {
9361         close_on_exec_on(fd);
9362         if (push) {
9363                 pushfile();
9364                 g_parsefile->buf = 0;
9365         }
9366         g_parsefile->fd = fd;
9367         if (g_parsefile->buf == NULL)
9368                 g_parsefile->buf = ckmalloc(IBUFSIZ);
9369         parselleft = parsenleft = 0;
9370         plinno = 1;
9371 }
9372
9373 /*
9374  * Set the input to take input from a file.  If push is set, push the
9375  * old input onto the stack first.
9376  */
9377 static int
9378 setinputfile(const char *fname, int flags)
9379 {
9380         int fd;
9381         int fd2;
9382
9383         INT_OFF;
9384         fd = open(fname, O_RDONLY);
9385         if (fd < 0) {
9386                 if (flags & INPUT_NOFILE_OK)
9387                         goto out;
9388                 ash_msg_and_raise_error("can't open %s", fname);
9389         }
9390         if (fd < 10) {
9391                 fd2 = copyfd(fd, 10);
9392                 close(fd);
9393                 if (fd2 < 0)
9394                         ash_msg_and_raise_error("out of file descriptors");
9395                 fd = fd2;
9396         }
9397         setinputfd(fd, flags & INPUT_PUSH_FILE);
9398  out:
9399         INT_ON;
9400         return fd;
9401 }
9402
9403 /*
9404  * Like setinputfile, but takes input from a string.
9405  */
9406 static void
9407 setinputstring(char *string)
9408 {
9409         INT_OFF;
9410         pushfile();
9411         parsenextc = string;
9412         parsenleft = strlen(string);
9413         g_parsefile->buf = NULL;
9414         plinno = 1;
9415         INT_ON;
9416 }
9417
9418
9419 /* ============ mail.c
9420  *
9421  * Routines to check for mail.
9422  */
9423
9424 #if ENABLE_ASH_MAIL
9425
9426 #define MAXMBOXES 10
9427
9428 /* times of mailboxes */
9429 static time_t mailtime[MAXMBOXES];
9430 /* Set if MAIL or MAILPATH is changed. */
9431 static smallint mail_var_path_changed;
9432
9433 /*
9434  * Print appropriate message(s) if mail has arrived.
9435  * If mail_var_path_changed is set,
9436  * then the value of MAIL has mail_var_path_changed,
9437  * so we just update the values.
9438  */
9439 static void
9440 chkmail(void)
9441 {
9442         const char *mpath;
9443         char *p;
9444         char *q;
9445         time_t *mtp;
9446         struct stackmark smark;
9447         struct stat statb;
9448
9449         setstackmark(&smark);
9450         mpath = mpathset() ? mpathval() : mailval();
9451         for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9452                 p = padvance(&mpath, nullstr);
9453                 if (p == NULL)
9454                         break;
9455                 if (*p == '\0')
9456                         continue;
9457                 for (q = p; *q; q++)
9458                         continue;
9459 #if DEBUG
9460                 if (q[-1] != '/')
9461                         abort();
9462 #endif
9463                 q[-1] = '\0';                   /* delete trailing '/' */
9464                 if (stat(p, &statb) < 0) {
9465                         *mtp = 0;
9466                         continue;
9467                 }
9468                 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9469                         fprintf(
9470                                 stderr, snlfmt,
9471                                 pathopt ? pathopt : "you have mail"
9472                         );
9473                 }
9474                 *mtp = statb.st_mtime;
9475         }
9476         mail_var_path_changed = 0;
9477         popstackmark(&smark);
9478 }
9479
9480 static void
9481 changemail(const char *val UNUSED_PARAM)
9482 {
9483         mail_var_path_changed = 1;
9484 }
9485
9486 #endif /* ASH_MAIL */
9487
9488
9489 /* ============ ??? */
9490
9491 /*
9492  * Set the shell parameters.
9493  */
9494 static void
9495 setparam(char **argv)
9496 {
9497         char **newparam;
9498         char **ap;
9499         int nparam;
9500
9501         for (nparam = 0; argv[nparam]; nparam++)
9502                 continue;
9503         ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9504         while (*argv) {
9505                 *ap++ = ckstrdup(*argv++);
9506         }
9507         *ap = NULL;
9508         freeparam(&shellparam);
9509         shellparam.malloced = 1;
9510         shellparam.nparam = nparam;
9511         shellparam.p = newparam;
9512 #if ENABLE_ASH_GETOPTS
9513         shellparam.optind = 1;
9514         shellparam.optoff = -1;
9515 #endif
9516 }
9517
9518 /*
9519  * Process shell options.  The global variable argptr contains a pointer
9520  * to the argument list; we advance it past the options.
9521  *
9522  * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9523  * For a non-interactive shell, an error condition encountered
9524  * by a special built-in ... shall cause the shell to write a diagnostic message
9525  * to standard error and exit as shown in the following table:
9526  * Error                                           Special Built-In
9527  * ...
9528  * Utility syntax error (option or operand error)  Shall exit
9529  * ...
9530  * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9531  * we see that bash does not do that (set "finishes" with error code 1 instead,
9532  * and shell continues), and people rely on this behavior!
9533  * Testcase:
9534  * set -o barfoo 2>/dev/null
9535  * echo $?
9536  *
9537  * Oh well. Let's mimic that.
9538  */
9539 static int
9540 plus_minus_o(char *name, int val)
9541 {
9542         int i;
9543
9544         if (name) {
9545                 for (i = 0; i < NOPTS; i++) {
9546                         if (strcmp(name, optnames(i)) == 0) {
9547                                 optlist[i] = val;
9548                                 return 0;
9549                         }
9550                 }
9551                 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9552                 return 1;
9553         }
9554         for (i = 0; i < NOPTS; i++) {
9555                 if (val) {
9556                         out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9557                 } else {
9558                         out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9559                 }
9560         }
9561         return 0;
9562 }
9563 static void
9564 setoption(int flag, int val)
9565 {
9566         int i;
9567
9568         for (i = 0; i < NOPTS; i++) {
9569                 if (optletters(i) == flag) {
9570                         optlist[i] = val;
9571                         return;
9572                 }
9573         }
9574         ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9575         /* NOTREACHED */
9576 }
9577 static int
9578 options(int cmdline)
9579 {
9580         char *p;
9581         int val;
9582         int c;
9583
9584         if (cmdline)
9585                 minusc = NULL;
9586         while ((p = *argptr) != NULL) {
9587                 c = *p++;
9588                 if (c != '-' && c != '+')
9589                         break;
9590                 argptr++;
9591                 val = 0; /* val = 0 if c == '+' */
9592                 if (c == '-') {
9593                         val = 1;
9594                         if (p[0] == '\0' || LONE_DASH(p)) {
9595                                 if (!cmdline) {
9596                                         /* "-" means turn off -x and -v */
9597                                         if (p[0] == '\0')
9598                                                 xflag = vflag = 0;
9599                                         /* "--" means reset params */
9600                                         else if (*argptr == NULL)
9601                                                 setparam(argptr);
9602                                 }
9603                                 break;    /* "-" or  "--" terminates options */
9604                         }
9605                 }
9606                 /* first char was + or - */
9607                 while ((c = *p++) != '\0') {
9608                         /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9609                         if (c == 'c' && cmdline) {
9610                                 minusc = p;     /* command is after shell args */
9611                         } else if (c == 'o') {
9612                                 if (plus_minus_o(*argptr, val)) {
9613                                         /* it already printed err message */
9614                                         return 1; /* error */
9615                                 }
9616                                 if (*argptr)
9617                                         argptr++;
9618                         } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9619                                 isloginsh = 1;
9620                         /* bash does not accept +-login, we also won't */
9621                         } else if (cmdline && val && (c == '-')) { /* long options */
9622                                 if (strcmp(p, "login") == 0)
9623                                         isloginsh = 1;
9624                                 break;
9625                         } else {
9626                                 setoption(c, val);
9627                         }
9628                 }
9629         }
9630         return 0;
9631 }
9632
9633 /*
9634  * The shift builtin command.
9635  */
9636 static int
9637 shiftcmd(int argc UNUSED_PARAM, char **argv)
9638 {
9639         int n;
9640         char **ap1, **ap2;
9641
9642         n = 1;
9643         if (argv[1])
9644                 n = number(argv[1]);
9645         if (n > shellparam.nparam)
9646                 n = shellparam.nparam;
9647         INT_OFF;
9648         shellparam.nparam -= n;
9649         for (ap1 = shellparam.p; --n >= 0; ap1++) {
9650                 if (shellparam.malloced)
9651                         free(*ap1);
9652         }
9653         ap2 = shellparam.p;
9654         while ((*ap2++ = *ap1++) != NULL)
9655                 continue;
9656 #if ENABLE_ASH_GETOPTS
9657         shellparam.optind = 1;
9658         shellparam.optoff = -1;
9659 #endif
9660         INT_ON;
9661         return 0;
9662 }
9663
9664 /*
9665  * POSIX requires that 'set' (but not export or readonly) output the
9666  * variables in lexicographic order - by the locale's collating order (sigh).
9667  * Maybe we could keep them in an ordered balanced binary tree
9668  * instead of hashed lists.
9669  * For now just roll 'em through qsort for printing...
9670  */
9671 static int
9672 showvars(const char *sep_prefix, int on, int off)
9673 {
9674         const char *sep;
9675         char **ep, **epend;
9676
9677         ep = listvars(on, off, &epend);
9678         qsort(ep, epend - ep, sizeof(char *), vpcmp);
9679
9680         sep = *sep_prefix ? " " : sep_prefix;
9681
9682         for (; ep < epend; ep++) {
9683                 const char *p;
9684                 const char *q;
9685
9686                 p = strchrnul(*ep, '=');
9687                 q = nullstr;
9688                 if (*p)
9689                         q = single_quote(++p);
9690                 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9691         }
9692         return 0;
9693 }
9694
9695 /*
9696  * The set command builtin.
9697  */
9698 static int
9699 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9700 {
9701         int retval;
9702
9703         if (!argv[1])
9704                 return showvars(nullstr, 0, VUNSET);
9705         INT_OFF;
9706         retval = 1;
9707         if (!options(0)) { /* if no parse error... */
9708                 retval = 0;
9709                 optschanged();
9710                 if (*argptr != NULL) {
9711                         setparam(argptr);
9712                 }
9713         }
9714         INT_ON;
9715         return retval;
9716 }
9717
9718 #if ENABLE_ASH_RANDOM_SUPPORT
9719 static void
9720 change_random(const char *value)
9721 {
9722         /* Galois LFSR parameter */
9723         /* Taps at 32 31 29 1: */
9724         enum { MASK = 0x8000000b };
9725         /* Another example - taps at 32 31 30 10: */
9726         /* MASK = 0x00400007 */
9727
9728         if (value == NULL) {
9729                 /* "get", generate */
9730                 uint32_t t;
9731
9732                 /* LCG has period of 2^32 and alternating lowest bit */
9733                 random_LCG = 1664525 * random_LCG + 1013904223;
9734                 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9735                 t = (random_galois_LFSR << 1);
9736                 if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
9737                         t ^= MASK;
9738                 random_galois_LFSR = t;
9739                 /* Both are weak, combining them gives better randomness
9740                  * and ~2^64 period. & 0x7fff is probably bash compat
9741                  * for $RANDOM range. Combining with subtraction is
9742                  * just for fun. + and ^ would work equally well. */
9743                 t = (t - random_LCG) & 0x7fff;
9744                 /* set without recursion */
9745                 setvar(vrandom.text, utoa(t), VNOFUNC);
9746                 vrandom.flags &= ~VNOFUNC;
9747         } else {
9748                 /* set/reset */
9749                 random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);
9750         }
9751 }
9752 #endif
9753
9754 #if ENABLE_ASH_GETOPTS
9755 static int
9756 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9757 {
9758         char *p, *q;
9759         char c = '?';
9760         int done = 0;
9761         int err = 0;
9762         char s[12];
9763         char **optnext;
9764
9765         if (*param_optind < 1)
9766                 return 1;
9767         optnext = optfirst + *param_optind - 1;
9768
9769         if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
9770                 p = NULL;
9771         else
9772                 p = optnext[-1] + *optoff;
9773         if (p == NULL || *p == '\0') {
9774                 /* Current word is done, advance */
9775                 p = *optnext;
9776                 if (p == NULL || *p != '-' || *++p == '\0') {
9777  atend:
9778                         p = NULL;
9779                         done = 1;
9780                         goto out;
9781                 }
9782                 optnext++;
9783                 if (LONE_DASH(p))        /* check for "--" */
9784                         goto atend;
9785         }
9786
9787         c = *p++;
9788         for (q = optstr; *q != c;) {
9789                 if (*q == '\0') {
9790                         if (optstr[0] == ':') {
9791                                 s[0] = c;
9792                                 s[1] = '\0';
9793                                 err |= setvarsafe("OPTARG", s, 0);
9794                         } else {
9795                                 fprintf(stderr, "Illegal option -%c\n", c);
9796                                 unsetvar("OPTARG");
9797                         }
9798                         c = '?';
9799                         goto out;
9800                 }
9801                 if (*++q == ':')
9802                         q++;
9803         }
9804
9805         if (*++q == ':') {
9806                 if (*p == '\0' && (p = *optnext) == NULL) {
9807                         if (optstr[0] == ':') {
9808                                 s[0] = c;
9809                                 s[1] = '\0';
9810                                 err |= setvarsafe("OPTARG", s, 0);
9811                                 c = ':';
9812                         } else {
9813                                 fprintf(stderr, "No arg for -%c option\n", c);
9814                                 unsetvar("OPTARG");
9815                                 c = '?';
9816                         }
9817                         goto out;
9818                 }
9819
9820                 if (p == *optnext)
9821                         optnext++;
9822                 err |= setvarsafe("OPTARG", p, 0);
9823                 p = NULL;
9824         } else
9825                 err |= setvarsafe("OPTARG", nullstr, 0);
9826  out:
9827         *optoff = p ? p - *(optnext - 1) : -1;
9828         *param_optind = optnext - optfirst + 1;
9829         fmtstr(s, sizeof(s), "%d", *param_optind);
9830         err |= setvarsafe("OPTIND", s, VNOFUNC);
9831         s[0] = c;
9832         s[1] = '\0';
9833         err |= setvarsafe(optvar, s, 0);
9834         if (err) {
9835                 *param_optind = 1;
9836                 *optoff = -1;
9837                 flush_stdout_stderr();
9838                 raise_exception(EXERROR);
9839         }
9840         return done;
9841 }
9842
9843 /*
9844  * The getopts builtin.  Shellparam.optnext points to the next argument
9845  * to be processed.  Shellparam.optptr points to the next character to
9846  * be processed in the current argument.  If shellparam.optnext is NULL,
9847  * then it's the first time getopts has been called.
9848  */
9849 static int
9850 getoptscmd(int argc, char **argv)
9851 {
9852         char **optbase;
9853
9854         if (argc < 3)
9855                 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9856         if (argc == 3) {
9857                 optbase = shellparam.p;
9858                 if (shellparam.optind > shellparam.nparam + 1) {
9859                         shellparam.optind = 1;
9860                         shellparam.optoff = -1;
9861                 }
9862         } else {
9863                 optbase = &argv[3];
9864                 if (shellparam.optind > argc - 2) {
9865                         shellparam.optind = 1;
9866                         shellparam.optoff = -1;
9867                 }
9868         }
9869
9870         return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9871                         &shellparam.optoff);
9872 }
9873 #endif /* ASH_GETOPTS */
9874
9875
9876 /* ============ Shell parser */
9877
9878 struct heredoc {
9879         struct heredoc *next;   /* next here document in list */
9880         union node *here;       /* redirection node */
9881         char *eofmark;          /* string indicating end of input */
9882         smallint striptabs;     /* if set, strip leading tabs */
9883 };
9884
9885 static smallint tokpushback;           /* last token pushed back */
9886 static smallint parsebackquote;        /* nonzero if we are inside backquotes */
9887 static smallint quoteflag;             /* set if (part of) last token was quoted */
9888 static token_id_t lasttoken;           /* last token read (integer id Txxx) */
9889 static struct heredoc *heredoclist;    /* list of here documents to read */
9890 static char *wordtext;                 /* text of last word returned by readtoken */
9891 static struct nodelist *backquotelist;
9892 static union node *redirnode;
9893 static struct heredoc *heredoc;
9894 /*
9895  * NEOF is returned by parsecmd when it encounters an end of file.  It
9896  * must be distinct from NULL, so we use the address of a variable that
9897  * happens to be handy.
9898  */
9899 #define NEOF ((union node *)&tokpushback)
9900
9901 static void raise_error_syntax(const char *) NORETURN;
9902 static void
9903 raise_error_syntax(const char *msg)
9904 {
9905         ash_msg_and_raise_error("syntax error: %s", msg);
9906         /* NOTREACHED */
9907 }
9908
9909 /*
9910  * Called when an unexpected token is read during the parse.  The argument
9911  * is the token that is expected, or -1 if more than one type of token can
9912  * occur at this point.
9913  */
9914 static void raise_error_unexpected_syntax(int) NORETURN;
9915 static void
9916 raise_error_unexpected_syntax(int token)
9917 {
9918         char msg[64];
9919         int l;
9920
9921         l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9922         if (token >= 0)
9923                 sprintf(msg + l, " (expecting %s)", tokname(token));
9924         raise_error_syntax(msg);
9925         /* NOTREACHED */
9926 }
9927
9928 #define EOFMARKLEN 79
9929
9930 /* parsing is heavily cross-recursive, need these forward decls */
9931 static union node *andor(void);
9932 static union node *pipeline(void);
9933 static union node *parse_command(void);
9934 static void parseheredoc(void);
9935 static char peektoken(void);
9936 static int readtoken(void);
9937
9938 static union node *
9939 list(int nlflag)
9940 {
9941         union node *n1, *n2, *n3;
9942         int tok;
9943
9944         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9945         if (nlflag == 2 && peektoken())
9946                 return NULL;
9947         n1 = NULL;
9948         for (;;) {
9949                 n2 = andor();
9950                 tok = readtoken();
9951                 if (tok == TBACKGND) {
9952                         if (n2->type == NPIPE) {
9953                                 n2->npipe.pipe_backgnd = 1;
9954                         } else {
9955                                 if (n2->type != NREDIR) {
9956                                         n3 = stzalloc(sizeof(struct nredir));
9957                                         n3->nredir.n = n2;
9958                                         /*n3->nredir.redirect = NULL; - stzalloc did it */
9959                                         n2 = n3;
9960                                 }
9961                                 n2->type = NBACKGND;
9962                         }
9963                 }
9964                 if (n1 == NULL) {
9965                         n1 = n2;
9966                 } else {
9967                         n3 = stzalloc(sizeof(struct nbinary));
9968                         n3->type = NSEMI;
9969                         n3->nbinary.ch1 = n1;
9970                         n3->nbinary.ch2 = n2;
9971                         n1 = n3;
9972                 }
9973                 switch (tok) {
9974                 case TBACKGND:
9975                 case TSEMI:
9976                         tok = readtoken();
9977                         /* fall through */
9978                 case TNL:
9979                         if (tok == TNL) {
9980                                 parseheredoc();
9981                                 if (nlflag == 1)
9982                                         return n1;
9983                         } else {
9984                                 tokpushback = 1;
9985                         }
9986                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9987                         if (peektoken())
9988                                 return n1;
9989                         break;
9990                 case TEOF:
9991                         if (heredoclist)
9992                                 parseheredoc();
9993                         else
9994                                 pungetc();              /* push back EOF on input */
9995                         return n1;
9996                 default:
9997                         if (nlflag == 1)
9998                                 raise_error_unexpected_syntax(-1);
9999                         tokpushback = 1;
10000                         return n1;
10001                 }
10002         }
10003 }
10004
10005 static union node *
10006 andor(void)
10007 {
10008         union node *n1, *n2, *n3;
10009         int t;
10010
10011         n1 = pipeline();
10012         for (;;) {
10013                 t = readtoken();
10014                 if (t == TAND) {
10015                         t = NAND;
10016                 } else if (t == TOR) {
10017                         t = NOR;
10018                 } else {
10019                         tokpushback = 1;
10020                         return n1;
10021                 }
10022                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10023                 n2 = pipeline();
10024                 n3 = stzalloc(sizeof(struct nbinary));
10025                 n3->type = t;
10026                 n3->nbinary.ch1 = n1;
10027                 n3->nbinary.ch2 = n2;
10028                 n1 = n3;
10029         }
10030 }
10031
10032 static union node *
10033 pipeline(void)
10034 {
10035         union node *n1, *n2, *pipenode;
10036         struct nodelist *lp, *prev;
10037         int negate;
10038
10039         negate = 0;
10040         TRACE(("pipeline: entered\n"));
10041         if (readtoken() == TNOT) {
10042                 negate = !negate;
10043                 checkkwd = CHKKWD | CHKALIAS;
10044         } else
10045                 tokpushback = 1;
10046         n1 = parse_command();
10047         if (readtoken() == TPIPE) {
10048                 pipenode = stzalloc(sizeof(struct npipe));
10049                 pipenode->type = NPIPE;
10050                 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10051                 lp = stzalloc(sizeof(struct nodelist));
10052                 pipenode->npipe.cmdlist = lp;
10053                 lp->n = n1;
10054                 do {
10055                         prev = lp;
10056                         lp = stzalloc(sizeof(struct nodelist));
10057                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
10058                         lp->n = parse_command();
10059                         prev->next = lp;
10060                 } while (readtoken() == TPIPE);
10061                 lp->next = NULL;
10062                 n1 = pipenode;
10063         }
10064         tokpushback = 1;
10065         if (negate) {
10066                 n2 = stzalloc(sizeof(struct nnot));
10067                 n2->type = NNOT;
10068                 n2->nnot.com = n1;
10069                 return n2;
10070         }
10071         return n1;
10072 }
10073
10074 static union node *
10075 makename(void)
10076 {
10077         union node *n;
10078
10079         n = stzalloc(sizeof(struct narg));
10080         n->type = NARG;
10081         /*n->narg.next = NULL; - stzalloc did it */
10082         n->narg.text = wordtext;
10083         n->narg.backquote = backquotelist;
10084         return n;
10085 }
10086
10087 static void
10088 fixredir(union node *n, const char *text, int err)
10089 {
10090         int fd;
10091
10092         TRACE(("Fix redir %s %d\n", text, err));
10093         if (!err)
10094                 n->ndup.vname = NULL;
10095
10096         fd = bb_strtou(text, NULL, 10);
10097         if (!errno && fd >= 0)
10098                 n->ndup.dupfd = fd;
10099         else if (LONE_DASH(text))
10100                 n->ndup.dupfd = -1;
10101         else {
10102                 if (err)
10103                         raise_error_syntax("Bad fd number");
10104                 n->ndup.vname = makename();
10105         }
10106 }
10107
10108 /*
10109  * Returns true if the text contains nothing to expand (no dollar signs
10110  * or backquotes).
10111  */
10112 static int
10113 noexpand(char *text)
10114 {
10115         char *p;
10116         char c;
10117
10118         p = text;
10119         while ((c = *p++) != '\0') {
10120                 if (c == CTLQUOTEMARK)
10121                         continue;
10122                 if (c == CTLESC)
10123                         p++;
10124                 else if (SIT(c, BASESYNTAX) == CCTL)
10125                         return 0;
10126         }
10127         return 1;
10128 }
10129
10130 static void
10131 parsefname(void)
10132 {
10133         union node *n = redirnode;
10134
10135         if (readtoken() != TWORD)
10136                 raise_error_unexpected_syntax(-1);
10137         if (n->type == NHERE) {
10138                 struct heredoc *here = heredoc;
10139                 struct heredoc *p;
10140                 int i;
10141
10142                 if (quoteflag == 0)
10143                         n->type = NXHERE;
10144                 TRACE(("Here document %d\n", n->type));
10145                 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10146                         raise_error_syntax("Illegal eof marker for << redirection");
10147                 rmescapes(wordtext);
10148                 here->eofmark = wordtext;
10149                 here->next = NULL;
10150                 if (heredoclist == NULL)
10151                         heredoclist = here;
10152                 else {
10153                         for (p = heredoclist; p->next; p = p->next)
10154                                 continue;
10155                         p->next = here;
10156                 }
10157         } else if (n->type == NTOFD || n->type == NFROMFD) {
10158                 fixredir(n, wordtext, 0);
10159         } else {
10160                 n->nfile.fname = makename();
10161         }
10162 }
10163
10164 static union node *
10165 simplecmd(void)
10166 {
10167         union node *args, **app;
10168         union node *n = NULL;
10169         union node *vars, **vpp;
10170         union node **rpp, *redir;
10171         int savecheckkwd;
10172 #if ENABLE_ASH_BASH_COMPAT
10173         smallint double_brackets_flag = 0;
10174 #endif
10175
10176         args = NULL;
10177         app = &args;
10178         vars = NULL;
10179         vpp = &vars;
10180         redir = NULL;
10181         rpp = &redir;
10182
10183         savecheckkwd = CHKALIAS;
10184         for (;;) {
10185                 int t;
10186                 checkkwd = savecheckkwd;
10187                 t = readtoken();
10188                 switch (t) {
10189 #if ENABLE_ASH_BASH_COMPAT
10190                 case TAND: /* "&&" */
10191                 case TOR: /* "||" */
10192                         if (!double_brackets_flag) {
10193                                 tokpushback = 1;
10194                                 goto out;
10195                         }
10196                         wordtext = (char *) (t == TAND ? "-a" : "-o");
10197 #endif
10198                 case TWORD:
10199                         n = stzalloc(sizeof(struct narg));
10200                         n->type = NARG;
10201                         /*n->narg.next = NULL; - stzalloc did it */
10202                         n->narg.text = wordtext;
10203 #if ENABLE_ASH_BASH_COMPAT
10204                         if (strcmp("[[", wordtext) == 0)
10205                                 double_brackets_flag = 1;
10206                         else if (strcmp("]]", wordtext) == 0)
10207                                 double_brackets_flag = 0;
10208 #endif
10209                         n->narg.backquote = backquotelist;
10210                         if (savecheckkwd && isassignment(wordtext)) {
10211                                 *vpp = n;
10212                                 vpp = &n->narg.next;
10213                         } else {
10214                                 *app = n;
10215                                 app = &n->narg.next;
10216                                 savecheckkwd = 0;
10217                         }
10218                         break;
10219                 case TREDIR:
10220                         *rpp = n = redirnode;
10221                         rpp = &n->nfile.next;
10222                         parsefname();   /* read name of redirection file */
10223                         break;
10224                 case TLP:
10225                         if (args && app == &args->narg.next
10226                          && !vars && !redir
10227                         ) {
10228                                 struct builtincmd *bcmd;
10229                                 const char *name;
10230
10231                                 /* We have a function */
10232                                 if (readtoken() != TRP)
10233                                         raise_error_unexpected_syntax(TRP);
10234                                 name = n->narg.text;
10235                                 if (!goodname(name)
10236                                  || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10237                                 ) {
10238                                         raise_error_syntax("Bad function name");
10239                                 }
10240                                 n->type = NDEFUN;
10241                                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10242                                 n->narg.next = parse_command();
10243                                 return n;
10244                         }
10245                         /* fall through */
10246                 default:
10247                         tokpushback = 1;
10248                         goto out;
10249                 }
10250         }
10251  out:
10252         *app = NULL;
10253         *vpp = NULL;
10254         *rpp = NULL;
10255         n = stzalloc(sizeof(struct ncmd));
10256         n->type = NCMD;
10257         n->ncmd.args = args;
10258         n->ncmd.assign = vars;
10259         n->ncmd.redirect = redir;
10260         return n;
10261 }
10262
10263 static union node *
10264 parse_command(void)
10265 {
10266         union node *n1, *n2;
10267         union node *ap, **app;
10268         union node *cp, **cpp;
10269         union node *redir, **rpp;
10270         union node **rpp2;
10271         int t;
10272
10273         redir = NULL;
10274         rpp2 = &redir;
10275
10276         switch (readtoken()) {
10277         default:
10278                 raise_error_unexpected_syntax(-1);
10279                 /* NOTREACHED */
10280         case TIF:
10281                 n1 = stzalloc(sizeof(struct nif));
10282                 n1->type = NIF;
10283                 n1->nif.test = list(0);
10284                 if (readtoken() != TTHEN)
10285                         raise_error_unexpected_syntax(TTHEN);
10286                 n1->nif.ifpart = list(0);
10287                 n2 = n1;
10288                 while (readtoken() == TELIF) {
10289                         n2->nif.elsepart = stzalloc(sizeof(struct nif));
10290                         n2 = n2->nif.elsepart;
10291                         n2->type = NIF;
10292                         n2->nif.test = list(0);
10293                         if (readtoken() != TTHEN)
10294                                 raise_error_unexpected_syntax(TTHEN);
10295                         n2->nif.ifpart = list(0);
10296                 }
10297                 if (lasttoken == TELSE)
10298                         n2->nif.elsepart = list(0);
10299                 else {
10300                         n2->nif.elsepart = NULL;
10301                         tokpushback = 1;
10302                 }
10303                 t = TFI;
10304                 break;
10305         case TWHILE:
10306         case TUNTIL: {
10307                 int got;
10308                 n1 = stzalloc(sizeof(struct nbinary));
10309                 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10310                 n1->nbinary.ch1 = list(0);
10311                 got = readtoken();
10312                 if (got != TDO) {
10313                         TRACE(("expecting DO got %s %s\n", tokname(got),
10314                                         got == TWORD ? wordtext : ""));
10315                         raise_error_unexpected_syntax(TDO);
10316                 }
10317                 n1->nbinary.ch2 = list(0);
10318                 t = TDONE;
10319                 break;
10320         }
10321         case TFOR:
10322                 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10323                         raise_error_syntax("Bad for loop variable");
10324                 n1 = stzalloc(sizeof(struct nfor));
10325                 n1->type = NFOR;
10326                 n1->nfor.var = wordtext;
10327                 checkkwd = CHKKWD | CHKALIAS;
10328                 if (readtoken() == TIN) {
10329                         app = &ap;
10330                         while (readtoken() == TWORD) {
10331                                 n2 = stzalloc(sizeof(struct narg));
10332                                 n2->type = NARG;
10333                                 /*n2->narg.next = NULL; - stzalloc did it */
10334                                 n2->narg.text = wordtext;
10335                                 n2->narg.backquote = backquotelist;
10336                                 *app = n2;
10337                                 app = &n2->narg.next;
10338                         }
10339                         *app = NULL;
10340                         n1->nfor.args = ap;
10341                         if (lasttoken != TNL && lasttoken != TSEMI)
10342                                 raise_error_unexpected_syntax(-1);
10343                 } else {
10344                         n2 = stzalloc(sizeof(struct narg));
10345                         n2->type = NARG;
10346                         /*n2->narg.next = NULL; - stzalloc did it */
10347                         n2->narg.text = (char *)dolatstr;
10348                         /*n2->narg.backquote = NULL;*/
10349                         n1->nfor.args = n2;
10350                         /*
10351                          * Newline or semicolon here is optional (but note
10352                          * that the original Bourne shell only allowed NL).
10353                          */
10354                         if (lasttoken != TNL && lasttoken != TSEMI)
10355                                 tokpushback = 1;
10356                 }
10357                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10358                 if (readtoken() != TDO)
10359                         raise_error_unexpected_syntax(TDO);
10360                 n1->nfor.body = list(0);
10361                 t = TDONE;
10362                 break;
10363         case TCASE:
10364                 n1 = stzalloc(sizeof(struct ncase));
10365                 n1->type = NCASE;
10366                 if (readtoken() != TWORD)
10367                         raise_error_unexpected_syntax(TWORD);
10368                 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10369                 n2->type = NARG;
10370                 /*n2->narg.next = NULL; - stzalloc did it */
10371                 n2->narg.text = wordtext;
10372                 n2->narg.backquote = backquotelist;
10373                 do {
10374                         checkkwd = CHKKWD | CHKALIAS;
10375                 } while (readtoken() == TNL);
10376                 if (lasttoken != TIN)
10377                         raise_error_unexpected_syntax(TIN);
10378                 cpp = &n1->ncase.cases;
10379  next_case:
10380                 checkkwd = CHKNL | CHKKWD;
10381                 t = readtoken();
10382                 while (t != TESAC) {
10383                         if (lasttoken == TLP)
10384                                 readtoken();
10385                         *cpp = cp = stzalloc(sizeof(struct nclist));
10386                         cp->type = NCLIST;
10387                         app = &cp->nclist.pattern;
10388                         for (;;) {
10389                                 *app = ap = stzalloc(sizeof(struct narg));
10390                                 ap->type = NARG;
10391                                 /*ap->narg.next = NULL; - stzalloc did it */
10392                                 ap->narg.text = wordtext;
10393                                 ap->narg.backquote = backquotelist;
10394                                 if (readtoken() != TPIPE)
10395                                         break;
10396                                 app = &ap->narg.next;
10397                                 readtoken();
10398                         }
10399                         //ap->narg.next = NULL;
10400                         if (lasttoken != TRP)
10401                                 raise_error_unexpected_syntax(TRP);
10402                         cp->nclist.body = list(2);
10403
10404                         cpp = &cp->nclist.next;
10405
10406                         checkkwd = CHKNL | CHKKWD;
10407                         t = readtoken();
10408                         if (t != TESAC) {
10409                                 if (t != TENDCASE)
10410                                         raise_error_unexpected_syntax(TENDCASE);
10411                                 goto next_case;
10412                         }
10413                 }
10414                 *cpp = NULL;
10415                 goto redir;
10416         case TLP:
10417                 n1 = stzalloc(sizeof(struct nredir));
10418                 n1->type = NSUBSHELL;
10419                 n1->nredir.n = list(0);
10420                 /*n1->nredir.redirect = NULL; - stzalloc did it */
10421                 t = TRP;
10422                 break;
10423         case TBEGIN:
10424                 n1 = list(0);
10425                 t = TEND;
10426                 break;
10427         case TWORD:
10428         case TREDIR:
10429                 tokpushback = 1;
10430                 return simplecmd();
10431         }
10432
10433         if (readtoken() != t)
10434                 raise_error_unexpected_syntax(t);
10435
10436  redir:
10437         /* Now check for redirection which may follow command */
10438         checkkwd = CHKKWD | CHKALIAS;
10439         rpp = rpp2;
10440         while (readtoken() == TREDIR) {
10441                 *rpp = n2 = redirnode;
10442                 rpp = &n2->nfile.next;
10443                 parsefname();
10444         }
10445         tokpushback = 1;
10446         *rpp = NULL;
10447         if (redir) {
10448                 if (n1->type != NSUBSHELL) {
10449                         n2 = stzalloc(sizeof(struct nredir));
10450                         n2->type = NREDIR;
10451                         n2->nredir.n = n1;
10452                         n1 = n2;
10453                 }
10454                 n1->nredir.redirect = redir;
10455         }
10456         return n1;
10457 }
10458
10459 #if ENABLE_ASH_BASH_COMPAT
10460 static int decode_dollar_squote(void)
10461 {
10462         static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10463         int c, cnt;
10464         char *p;
10465         char buf[4];
10466
10467         c = pgetc();
10468         p = strchr(C_escapes, c);
10469         if (p) {
10470                 buf[0] = c;
10471                 p = buf;
10472                 cnt = 3;
10473                 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10474                         do {
10475                                 c = pgetc();
10476                                 *++p = c;
10477                         } while ((unsigned char)(c - '0') <= 7 && --cnt);
10478                         pungetc();
10479                 } else if (c == 'x') { /* \xHH */
10480                         do {
10481                                 c = pgetc();
10482                                 *++p = c;
10483                         } while (isxdigit(c) && --cnt);
10484                         pungetc();
10485                         if (cnt == 3) { /* \x but next char is "bad" */
10486                                 c = 'x';
10487                                 goto unrecognized;
10488                         }
10489                 } else { /* simple seq like \\ or \t */
10490                         p++;
10491                 }
10492                 *p = '\0';
10493                 p = buf;
10494                 c = bb_process_escape_sequence((void*)&p);
10495         } else { /* unrecognized "\z": print both chars unless ' or " */
10496                 if (c != '\'' && c != '"') {
10497  unrecognized:
10498                         c |= 0x100; /* "please encode \, then me" */
10499                 }
10500         }
10501         return c;
10502 }
10503 #endif
10504
10505 /*
10506  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10507  * is not NULL, read a here document.  In the latter case, eofmark is the
10508  * word which marks the end of the document and striptabs is true if
10509  * leading tabs should be stripped from the document.  The argument firstc
10510  * is the first character of the input token or document.
10511  *
10512  * Because C does not have internal subroutines, I have simulated them
10513  * using goto's to implement the subroutine linkage.  The following macros
10514  * will run code that appears at the end of readtoken1.
10515  */
10516 #define CHECKEND()      {goto checkend; checkend_return:;}
10517 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10518 #define PARSESUB()      {goto parsesub; parsesub_return:;}
10519 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10520 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10521 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
10522 static int
10523 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10524 {
10525         /* NB: syntax parameter fits into smallint */
10526         int c = firstc;
10527         char *out;
10528         int len;
10529         char line[EOFMARKLEN + 1];
10530         struct nodelist *bqlist;
10531         smallint quotef;
10532         smallint dblquote;
10533         smallint oldstyle;
10534         smallint prevsyntax; /* syntax before arithmetic */
10535 #if ENABLE_ASH_EXPAND_PRMT
10536         smallint pssyntax;   /* we are expanding a prompt string */
10537 #endif
10538         int varnest;         /* levels of variables expansion */
10539         int arinest;         /* levels of arithmetic expansion */
10540         int parenlevel;      /* levels of parens in arithmetic */
10541         int dqvarnest;       /* levels of variables expansion within double quotes */
10542
10543         USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10544
10545 #if __GNUC__
10546         /* Avoid longjmp clobbering */
10547         (void) &out;
10548         (void) &quotef;
10549         (void) &dblquote;
10550         (void) &varnest;
10551         (void) &arinest;
10552         (void) &parenlevel;
10553         (void) &dqvarnest;
10554         (void) &oldstyle;
10555         (void) &prevsyntax;
10556         (void) &syntax;
10557 #endif
10558         startlinno = plinno;
10559         bqlist = NULL;
10560         quotef = 0;
10561         oldstyle = 0;
10562         prevsyntax = 0;
10563 #if ENABLE_ASH_EXPAND_PRMT
10564         pssyntax = (syntax == PSSYNTAX);
10565         if (pssyntax)
10566                 syntax = DQSYNTAX;
10567 #endif
10568         dblquote = (syntax == DQSYNTAX);
10569         varnest = 0;
10570         arinest = 0;
10571         parenlevel = 0;
10572         dqvarnest = 0;
10573
10574         STARTSTACKSTR(out);
10575         loop: { /* for each line, until end of word */
10576                 CHECKEND();     /* set c to PEOF if at end of here document */
10577                 for (;;) {      /* until end of line or end of word */
10578                         CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
10579                         switch (SIT(c, syntax)) {
10580                         case CNL:       /* '\n' */
10581                                 if (syntax == BASESYNTAX)
10582                                         goto endword;   /* exit outer loop */
10583                                 USTPUTC(c, out);
10584                                 plinno++;
10585                                 if (doprompt)
10586                                         setprompt(2);
10587                                 c = pgetc();
10588                                 goto loop;              /* continue outer loop */
10589                         case CWORD:
10590                                 USTPUTC(c, out);
10591                                 break;
10592                         case CCTL:
10593                                 if (eofmark == NULL || dblquote)
10594                                         USTPUTC(CTLESC, out);
10595 #if ENABLE_ASH_BASH_COMPAT
10596                                 if (c == '\\' && bash_dollar_squote) {
10597                                         c = decode_dollar_squote();
10598                                         if (c & 0x100) {
10599                                                 USTPUTC('\\', out);
10600                                                 c = (unsigned char)c;
10601                                         }
10602                                 }
10603 #endif
10604                                 USTPUTC(c, out);
10605                                 break;
10606                         case CBACK:     /* backslash */
10607                                 c = pgetc2();
10608                                 if (c == PEOF) {
10609                                         USTPUTC(CTLESC, out);
10610                                         USTPUTC('\\', out);
10611                                         pungetc();
10612                                 } else if (c == '\n') {
10613                                         if (doprompt)
10614                                                 setprompt(2);
10615                                 } else {
10616 #if ENABLE_ASH_EXPAND_PRMT
10617                                         if (c == '$' && pssyntax) {
10618                                                 USTPUTC(CTLESC, out);
10619                                                 USTPUTC('\\', out);
10620                                         }
10621 #endif
10622                                         if (dblquote && c != '\\'
10623                                          && c != '`' && c != '$'
10624                                          && (c != '"' || eofmark != NULL)
10625                                         ) {
10626                                                 USTPUTC(CTLESC, out);
10627                                                 USTPUTC('\\', out);
10628                                         }
10629                                         if (SIT(c, SQSYNTAX) == CCTL)
10630                                                 USTPUTC(CTLESC, out);
10631                                         USTPUTC(c, out);
10632                                         quotef = 1;
10633                                 }
10634                                 break;
10635                         case CSQUOTE:
10636                                 syntax = SQSYNTAX;
10637  quotemark:
10638                                 if (eofmark == NULL) {
10639                                         USTPUTC(CTLQUOTEMARK, out);
10640                                 }
10641                                 break;
10642                         case CDQUOTE:
10643                                 syntax = DQSYNTAX;
10644                                 dblquote = 1;
10645                                 goto quotemark;
10646                         case CENDQUOTE:
10647                                 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10648                                 if (eofmark != NULL && arinest == 0
10649                                  && varnest == 0
10650                                 ) {
10651                                         USTPUTC(c, out);
10652                                 } else {
10653                                         if (dqvarnest == 0) {
10654                                                 syntax = BASESYNTAX;
10655                                                 dblquote = 0;
10656                                         }
10657                                         quotef = 1;
10658                                         goto quotemark;
10659                                 }
10660                                 break;
10661                         case CVAR:      /* '$' */
10662                                 PARSESUB();             /* parse substitution */
10663                                 break;
10664                         case CENDVAR:   /* '}' */
10665                                 if (varnest > 0) {
10666                                         varnest--;
10667                                         if (dqvarnest > 0) {
10668                                                 dqvarnest--;
10669                                         }
10670                                         USTPUTC(CTLENDVAR, out);
10671                                 } else {
10672                                         USTPUTC(c, out);
10673                                 }
10674                                 break;
10675 #if ENABLE_ASH_MATH_SUPPORT
10676                         case CLP:       /* '(' in arithmetic */
10677                                 parenlevel++;
10678                                 USTPUTC(c, out);
10679                                 break;
10680                         case CRP:       /* ')' in arithmetic */
10681                                 if (parenlevel > 0) {
10682                                         USTPUTC(c, out);
10683                                         --parenlevel;
10684                                 } else {
10685                                         if (pgetc() == ')') {
10686                                                 if (--arinest == 0) {
10687                                                         USTPUTC(CTLENDARI, out);
10688                                                         syntax = prevsyntax;
10689                                                         dblquote = (syntax == DQSYNTAX);
10690                                                 } else
10691                                                         USTPUTC(')', out);
10692                                         } else {
10693                                                 /*
10694                                                  * unbalanced parens
10695                                                  *  (don't 2nd guess - no error)
10696                                                  */
10697                                                 pungetc();
10698                                                 USTPUTC(')', out);
10699                                         }
10700                                 }
10701                                 break;
10702 #endif
10703                         case CBQUOTE:   /* '`' */
10704                                 PARSEBACKQOLD();
10705                                 break;
10706                         case CENDFILE:
10707                                 goto endword;           /* exit outer loop */
10708                         case CIGN:
10709                                 break;
10710                         default:
10711                                 if (varnest == 0)
10712                                         goto endword;   /* exit outer loop */
10713 #if ENABLE_ASH_ALIAS
10714                                 if (c != PEOA)
10715 #endif
10716                                         USTPUTC(c, out);
10717
10718                         }
10719                         c = pgetc_macro();
10720                 } /* for (;;) */
10721         }
10722  endword:
10723 #if ENABLE_ASH_MATH_SUPPORT
10724         if (syntax == ARISYNTAX)
10725                 raise_error_syntax("Missing '))'");
10726 #endif
10727         if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10728                 raise_error_syntax("Unterminated quoted string");
10729         if (varnest != 0) {
10730                 startlinno = plinno;
10731                 /* { */
10732                 raise_error_syntax("Missing '}'");
10733         }
10734         USTPUTC('\0', out);
10735         len = out - (char *)stackblock();
10736         out = stackblock();
10737         if (eofmark == NULL) {
10738                 if ((c == '>' || c == '<') && quotef == 0) {
10739                         int maxlen = 9 + 1; /* max 9 digit fd#: 999999999 */
10740                         char *np = out;
10741                         while (--maxlen && isdigit(*np))
10742                                 np++;
10743                         if (*np == '\0') {
10744                                 PARSEREDIR(); /* passed as params: out, c */
10745                                 lasttoken = TREDIR;
10746                                 return lasttoken;
10747                         }
10748                         /* else: non-number X seen, interpret it
10749                          * as "NNNX>file" = "NNNX >file" */
10750                 }
10751                 pungetc();
10752         }
10753         quoteflag = quotef;
10754         backquotelist = bqlist;
10755         grabstackblock(len);
10756         wordtext = out;
10757         lasttoken = TWORD;
10758         return lasttoken;
10759 /* end of readtoken routine */
10760
10761 /*
10762  * Check to see whether we are at the end of the here document.  When this
10763  * is called, c is set to the first character of the next input line.  If
10764  * we are at the end of the here document, this routine sets the c to PEOF.
10765  */
10766 checkend: {
10767         if (eofmark) {
10768 #if ENABLE_ASH_ALIAS
10769                 if (c == PEOA) {
10770                         c = pgetc2();
10771                 }
10772 #endif
10773                 if (striptabs) {
10774                         while (c == '\t') {
10775                                 c = pgetc2();
10776                         }
10777                 }
10778                 if (c == *eofmark) {
10779                         if (pfgets(line, sizeof(line)) != NULL) {
10780                                 char *p, *q;
10781
10782                                 p = line;
10783                                 for (q = eofmark + 1; *q && *p == *q; p++, q++)
10784                                         continue;
10785                                 if (*p == '\n' && *q == '\0') {
10786                                         c = PEOF;
10787                                         plinno++;
10788                                         needprompt = doprompt;
10789                                 } else {
10790                                         pushstring(line, NULL);
10791                                 }
10792                         }
10793                 }
10794         }
10795         goto checkend_return;
10796 }
10797
10798 /*
10799  * Parse a redirection operator.  The variable "out" points to a string
10800  * specifying the fd to be redirected.  The variable "c" contains the
10801  * first character of the redirection operator.
10802  */
10803 parseredir: {
10804         /* out is already checked to be a valid number or "" */
10805         int fd = (*out == '\0' ? -1 : atoi(out));
10806         union node *np;
10807
10808         np = stzalloc(sizeof(struct nfile));
10809         if (c == '>') {
10810                 np->nfile.fd = 1;
10811                 c = pgetc();
10812                 if (c == '>')
10813                         np->type = NAPPEND;
10814                 else if (c == '|')
10815                         np->type = NCLOBBER;
10816                 else if (c == '&')
10817                         np->type = NTOFD;
10818                 else {
10819                         np->type = NTO;
10820                         pungetc();
10821                 }
10822         } else {        /* c == '<' */
10823                 /*np->nfile.fd = 0; - stzalloc did it */
10824                 c = pgetc();
10825                 switch (c) {
10826                 case '<':
10827                         if (sizeof(struct nfile) != sizeof(struct nhere)) {
10828                                 np = stzalloc(sizeof(struct nhere));
10829                                 /*np->nfile.fd = 0; - stzalloc did it */
10830                         }
10831                         np->type = NHERE;
10832                         heredoc = stzalloc(sizeof(struct heredoc));
10833                         heredoc->here = np;
10834                         c = pgetc();
10835                         if (c == '-') {
10836                                 heredoc->striptabs = 1;
10837                         } else {
10838                                 /*heredoc->striptabs = 0; - stzalloc did it */
10839                                 pungetc();
10840                         }
10841                         break;
10842
10843                 case '&':
10844                         np->type = NFROMFD;
10845                         break;
10846
10847                 case '>':
10848                         np->type = NFROMTO;
10849                         break;
10850
10851                 default:
10852                         np->type = NFROM;
10853                         pungetc();
10854                         break;
10855                 }
10856         }
10857         if (fd >= 0)
10858                 np->nfile.fd = fd;
10859         redirnode = np;
10860         goto parseredir_return;
10861 }
10862
10863 /*
10864  * Parse a substitution.  At this point, we have read the dollar sign
10865  * and nothing else.
10866  */
10867
10868 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10869  * (assuming ascii char codes, as the original implementation did) */
10870 #define is_special(c) \
10871         (((unsigned)(c) - 33 < 32) \
10872                         && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
10873 parsesub: {
10874         int subtype;
10875         int typeloc;
10876         int flags;
10877         char *p;
10878         static const char types[] ALIGN1 = "}-+?=";
10879
10880         c = pgetc();
10881         if (c <= PEOA_OR_PEOF
10882          || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10883         ) {
10884 #if ENABLE_ASH_BASH_COMPAT
10885                 if (c == '\'')
10886                         bash_dollar_squote = 1;
10887                 else
10888 #endif
10889                         USTPUTC('$', out);
10890                 pungetc();
10891         } else if (c == '(') {  /* $(command) or $((arith)) */
10892                 if (pgetc() == '(') {
10893 #if ENABLE_ASH_MATH_SUPPORT
10894                         PARSEARITH();
10895 #else
10896                         raise_error_syntax("you disabled math support for $((arith)) syntax");
10897 #endif
10898                 } else {
10899                         pungetc();
10900                         PARSEBACKQNEW();
10901                 }
10902         } else {
10903                 USTPUTC(CTLVAR, out);
10904                 typeloc = out - (char *)stackblock();
10905                 USTPUTC(VSNORMAL, out);
10906                 subtype = VSNORMAL;
10907                 if (c == '{') {
10908                         c = pgetc();
10909                         if (c == '#') {
10910                                 c = pgetc();
10911                                 if (c == '}')
10912                                         c = '#';
10913                                 else
10914                                         subtype = VSLENGTH;
10915                         } else
10916                                 subtype = 0;
10917                 }
10918                 if (c > PEOA_OR_PEOF && is_name(c)) {
10919                         do {
10920                                 STPUTC(c, out);
10921                                 c = pgetc();
10922                         } while (c > PEOA_OR_PEOF && is_in_name(c));
10923                 } else if (isdigit(c)) {
10924                         do {
10925                                 STPUTC(c, out);
10926                                 c = pgetc();
10927                         } while (isdigit(c));
10928                 } else if (is_special(c)) {
10929                         USTPUTC(c, out);
10930                         c = pgetc();
10931                 } else
10932  badsub:                raise_error_syntax("Bad substitution");
10933
10934                 STPUTC('=', out);
10935                 flags = 0;
10936                 if (subtype == 0) {
10937                         switch (c) {
10938                         case ':':
10939                                 c = pgetc();
10940 #if ENABLE_ASH_BASH_COMPAT
10941                                 if (c == ':' || c == '$' || isdigit(c)) {
10942                                         pungetc();
10943                                         subtype = VSSUBSTR;
10944                                         break;
10945                                 }
10946 #endif
10947                                 flags = VSNUL;
10948                                 /*FALLTHROUGH*/
10949                         default:
10950                                 p = strchr(types, c);
10951                                 if (p == NULL)
10952                                         goto badsub;
10953                                 subtype = p - types + VSNORMAL;
10954                                 break;
10955                         case '%':
10956                         case '#': {
10957                                 int cc = c;
10958                                 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
10959                                 c = pgetc();
10960                                 if (c == cc)
10961                                         subtype++;
10962                                 else
10963                                         pungetc();
10964                                 break;
10965                         }
10966 #if ENABLE_ASH_BASH_COMPAT
10967                         case '/':
10968                                 subtype = VSREPLACE;
10969                                 c = pgetc();
10970                                 if (c == '/')
10971                                         subtype++; /* VSREPLACEALL */
10972                                 else
10973                                         pungetc();
10974                                 break;
10975 #endif
10976                         }
10977                 } else {
10978                         pungetc();
10979                 }
10980                 if (dblquote || arinest)
10981                         flags |= VSQUOTE;
10982                 *((char *)stackblock() + typeloc) = subtype | flags;
10983                 if (subtype != VSNORMAL) {
10984                         varnest++;
10985                         if (dblquote || arinest) {
10986                                 dqvarnest++;
10987                         }
10988                 }
10989         }
10990         goto parsesub_return;
10991 }
10992
10993 /*
10994  * Called to parse command substitutions.  Newstyle is set if the command
10995  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10996  * list of commands (passed by reference), and savelen is the number of
10997  * characters on the top of the stack which must be preserved.
10998  */
10999 parsebackq: {
11000         struct nodelist **nlpp;
11001         smallint savepbq;
11002         union node *n;
11003         char *volatile str;
11004         struct jmploc jmploc;
11005         struct jmploc *volatile savehandler;
11006         size_t savelen;
11007         smallint saveprompt = 0;
11008
11009 #ifdef __GNUC__
11010         (void) &saveprompt;
11011 #endif
11012         savepbq = parsebackquote;
11013         if (setjmp(jmploc.loc)) {
11014                 free(str);
11015                 parsebackquote = 0;
11016                 exception_handler = savehandler;
11017                 longjmp(exception_handler->loc, 1);
11018         }
11019         INT_OFF;
11020         str = NULL;
11021         savelen = out - (char *)stackblock();
11022         if (savelen > 0) {
11023                 str = ckmalloc(savelen);
11024                 memcpy(str, stackblock(), savelen);
11025         }
11026         savehandler = exception_handler;
11027         exception_handler = &jmploc;
11028         INT_ON;
11029         if (oldstyle) {
11030                 /* We must read until the closing backquote, giving special
11031                    treatment to some slashes, and then push the string and
11032                    reread it as input, interpreting it normally.  */
11033                 char *pout;
11034                 int pc;
11035                 size_t psavelen;
11036                 char *pstr;
11037
11038
11039                 STARTSTACKSTR(pout);
11040                 for (;;) {
11041                         if (needprompt) {
11042                                 setprompt(2);
11043                         }
11044                         pc = pgetc();
11045                         switch (pc) {
11046                         case '`':
11047                                 goto done;
11048
11049                         case '\\':
11050                                 pc = pgetc();
11051                                 if (pc == '\n') {
11052                                         plinno++;
11053                                         if (doprompt)
11054                                                 setprompt(2);
11055                                         /*
11056                                          * If eating a newline, avoid putting
11057                                          * the newline into the new character
11058                                          * stream (via the STPUTC after the
11059                                          * switch).
11060                                          */
11061                                         continue;
11062                                 }
11063                                 if (pc != '\\' && pc != '`' && pc != '$'
11064                                  && (!dblquote || pc != '"'))
11065                                         STPUTC('\\', pout);
11066                                 if (pc > PEOA_OR_PEOF) {
11067                                         break;
11068                                 }
11069                                 /* fall through */
11070
11071                         case PEOF:
11072 #if ENABLE_ASH_ALIAS
11073                         case PEOA:
11074 #endif
11075                                 startlinno = plinno;
11076                                 raise_error_syntax("EOF in backquote substitution");
11077
11078                         case '\n':
11079                                 plinno++;
11080                                 needprompt = doprompt;
11081                                 break;
11082
11083                         default:
11084                                 break;
11085                         }
11086                         STPUTC(pc, pout);
11087                 }
11088  done:
11089                 STPUTC('\0', pout);
11090                 psavelen = pout - (char *)stackblock();
11091                 if (psavelen > 0) {
11092                         pstr = grabstackstr(pout);
11093                         setinputstring(pstr);
11094                 }
11095         }
11096         nlpp = &bqlist;
11097         while (*nlpp)
11098                 nlpp = &(*nlpp)->next;
11099         *nlpp = stzalloc(sizeof(**nlpp));
11100         /* (*nlpp)->next = NULL; - stzalloc did it */
11101         parsebackquote = oldstyle;
11102
11103         if (oldstyle) {
11104                 saveprompt = doprompt;
11105                 doprompt = 0;
11106         }
11107
11108         n = list(2);
11109
11110         if (oldstyle)
11111                 doprompt = saveprompt;
11112         else if (readtoken() != TRP)
11113                 raise_error_unexpected_syntax(TRP);
11114
11115         (*nlpp)->n = n;
11116         if (oldstyle) {
11117                 /*
11118                  * Start reading from old file again, ignoring any pushed back
11119                  * tokens left from the backquote parsing
11120                  */
11121                 popfile();
11122                 tokpushback = 0;
11123         }
11124         while (stackblocksize() <= savelen)
11125                 growstackblock();
11126         STARTSTACKSTR(out);
11127         if (str) {
11128                 memcpy(out, str, savelen);
11129                 STADJUST(savelen, out);
11130                 INT_OFF;
11131                 free(str);
11132                 str = NULL;
11133                 INT_ON;
11134         }
11135         parsebackquote = savepbq;
11136         exception_handler = savehandler;
11137         if (arinest || dblquote)
11138                 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11139         else
11140                 USTPUTC(CTLBACKQ, out);
11141         if (oldstyle)
11142                 goto parsebackq_oldreturn;
11143         goto parsebackq_newreturn;
11144 }
11145
11146 #if ENABLE_ASH_MATH_SUPPORT
11147 /*
11148  * Parse an arithmetic expansion (indicate start of one and set state)
11149  */
11150 parsearith: {
11151         if (++arinest == 1) {
11152                 prevsyntax = syntax;
11153                 syntax = ARISYNTAX;
11154                 USTPUTC(CTLARI, out);
11155                 if (dblquote)
11156                         USTPUTC('"', out);
11157                 else
11158                         USTPUTC(' ', out);
11159         } else {
11160                 /*
11161                  * we collapse embedded arithmetic expansion to
11162                  * parenthesis, which should be equivalent
11163                  */
11164                 USTPUTC('(', out);
11165         }
11166         goto parsearith_return;
11167 }
11168 #endif
11169
11170 } /* end of readtoken */
11171
11172 /*
11173  * Read the next input token.
11174  * If the token is a word, we set backquotelist to the list of cmds in
11175  *      backquotes.  We set quoteflag to true if any part of the word was
11176  *      quoted.
11177  * If the token is TREDIR, then we set redirnode to a structure containing
11178  *      the redirection.
11179  * In all cases, the variable startlinno is set to the number of the line
11180  *      on which the token starts.
11181  *
11182  * [Change comment:  here documents and internal procedures]
11183  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
11184  *  word parsing code into a separate routine.  In this case, readtoken
11185  *  doesn't need to have any internal procedures, but parseword does.
11186  *  We could also make parseoperator in essence the main routine, and
11187  *  have parseword (readtoken1?) handle both words and redirection.]
11188  */
11189 #define NEW_xxreadtoken
11190 #ifdef NEW_xxreadtoken
11191 /* singles must be first! */
11192 static const char xxreadtoken_chars[7] ALIGN1 = {
11193         '\n', '(', ')', '&', '|', ';', 0
11194 };
11195
11196 static const char xxreadtoken_tokens[] ALIGN1 = {
11197         TNL, TLP, TRP,          /* only single occurrence allowed */
11198         TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11199         TEOF,                   /* corresponds to trailing nul */
11200         TAND, TOR, TENDCASE     /* if double occurrence */
11201 };
11202
11203 #define xxreadtoken_doubles \
11204         (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
11205 #define xxreadtoken_singles \
11206         (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
11207
11208 static int
11209 xxreadtoken(void)
11210 {
11211         int c;
11212
11213         if (tokpushback) {
11214                 tokpushback = 0;
11215                 return lasttoken;
11216         }
11217         if (needprompt) {
11218                 setprompt(2);
11219         }
11220         startlinno = plinno;
11221         for (;;) {                      /* until token or start of word found */
11222                 c = pgetc_macro();
11223
11224                 if ((c != ' ') && (c != '\t')
11225 #if ENABLE_ASH_ALIAS
11226                  && (c != PEOA)
11227 #endif
11228                 ) {
11229                         if (c == '#') {
11230                                 while ((c = pgetc()) != '\n' && c != PEOF)
11231                                         continue;
11232                                 pungetc();
11233                         } else if (c == '\\') {
11234                                 if (pgetc() != '\n') {
11235                                         pungetc();
11236                                         goto READTOKEN1;
11237                                 }
11238                                 startlinno = ++plinno;
11239                                 if (doprompt)
11240                                         setprompt(2);
11241                         } else {
11242                                 const char *p
11243                                         = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11244
11245                                 if (c != PEOF) {
11246                                         if (c == '\n') {
11247                                                 plinno++;
11248                                                 needprompt = doprompt;
11249                                         }
11250
11251                                         p = strchr(xxreadtoken_chars, c);
11252                                         if (p == NULL) {
11253  READTOKEN1:
11254                                                 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11255                                         }
11256
11257                                         if ((size_t)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11258                                                 if (pgetc() == *p) {    /* double occurrence? */
11259                                                         p += xxreadtoken_doubles + 1;
11260                                                 } else {
11261                                                         pungetc();
11262                                                 }
11263                                         }
11264                                 }
11265                                 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11266                                 return lasttoken;
11267                         }
11268                 }
11269         } /* for */
11270 }
11271 #else
11272 #define RETURN(token)   return lasttoken = token
11273 static int
11274 xxreadtoken(void)
11275 {
11276         int c;
11277
11278         if (tokpushback) {
11279                 tokpushback = 0;
11280                 return lasttoken;
11281         }
11282         if (needprompt) {
11283                 setprompt(2);
11284         }
11285         startlinno = plinno;
11286         for (;;) {      /* until token or start of word found */
11287                 c = pgetc_macro();
11288                 switch (c) {
11289                 case ' ': case '\t':
11290 #if ENABLE_ASH_ALIAS
11291                 case PEOA:
11292 #endif
11293                         continue;
11294                 case '#':
11295                         while ((c = pgetc()) != '\n' && c != PEOF)
11296                                 continue;
11297                         pungetc();
11298                         continue;
11299                 case '\\':
11300                         if (pgetc() == '\n') {
11301                                 startlinno = ++plinno;
11302                                 if (doprompt)
11303                                         setprompt(2);
11304                                 continue;
11305                         }
11306                         pungetc();
11307                         goto breakloop;
11308                 case '\n':
11309                         plinno++;
11310                         needprompt = doprompt;
11311                         RETURN(TNL);
11312                 case PEOF:
11313                         RETURN(TEOF);
11314                 case '&':
11315                         if (pgetc() == '&')
11316                                 RETURN(TAND);
11317                         pungetc();
11318                         RETURN(TBACKGND);
11319                 case '|':
11320                         if (pgetc() == '|')
11321                                 RETURN(TOR);
11322                         pungetc();
11323                         RETURN(TPIPE);
11324                 case ';':
11325                         if (pgetc() == ';')
11326                                 RETURN(TENDCASE);
11327                         pungetc();
11328                         RETURN(TSEMI);
11329                 case '(':
11330                         RETURN(TLP);
11331                 case ')':
11332                         RETURN(TRP);
11333                 default:
11334                         goto breakloop;
11335                 }
11336         }
11337  breakloop:
11338         return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11339 #undef RETURN
11340 }
11341 #endif /* NEW_xxreadtoken */
11342
11343 static int
11344 readtoken(void)
11345 {
11346         int t;
11347 #if DEBUG
11348         smallint alreadyseen = tokpushback;
11349 #endif
11350
11351 #if ENABLE_ASH_ALIAS
11352  top:
11353 #endif
11354
11355         t = xxreadtoken();
11356
11357         /*
11358          * eat newlines
11359          */
11360         if (checkkwd & CHKNL) {
11361                 while (t == TNL) {
11362                         parseheredoc();
11363                         t = xxreadtoken();
11364                 }
11365         }
11366
11367         if (t != TWORD || quoteflag) {
11368                 goto out;
11369         }
11370
11371         /*
11372          * check for keywords
11373          */
11374         if (checkkwd & CHKKWD) {
11375                 const char *const *pp;
11376
11377                 pp = findkwd(wordtext);
11378                 if (pp) {
11379                         lasttoken = t = pp - tokname_array;
11380                         TRACE(("keyword %s recognized\n", tokname(t)));
11381                         goto out;
11382                 }
11383         }
11384
11385         if (checkkwd & CHKALIAS) {
11386 #if ENABLE_ASH_ALIAS
11387                 struct alias *ap;
11388                 ap = lookupalias(wordtext, 1);
11389                 if (ap != NULL) {
11390                         if (*ap->val) {
11391                                 pushstring(ap->val, ap);
11392                         }
11393                         goto top;
11394                 }
11395 #endif
11396         }
11397  out:
11398         checkkwd = 0;
11399 #if DEBUG
11400         if (!alreadyseen)
11401                 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11402         else
11403                 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11404 #endif
11405         return t;
11406 }
11407
11408 static char
11409 peektoken(void)
11410 {
11411         int t;
11412
11413         t = readtoken();
11414         tokpushback = 1;
11415         return tokname_array[t][0];
11416 }
11417
11418 /*
11419  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
11420  * valid parse tree indicating a blank line.)
11421  */
11422 static union node *
11423 parsecmd(int interact)
11424 {
11425         int t;
11426
11427         tokpushback = 0;
11428         doprompt = interact;
11429         if (doprompt)
11430                 setprompt(doprompt);
11431         needprompt = 0;
11432         t = readtoken();
11433         if (t == TEOF)
11434                 return NEOF;
11435         if (t == TNL)
11436                 return NULL;
11437         tokpushback = 1;
11438         return list(1);
11439 }
11440
11441 /*
11442  * Input any here documents.
11443  */
11444 static void
11445 parseheredoc(void)
11446 {
11447         struct heredoc *here;
11448         union node *n;
11449
11450         here = heredoclist;
11451         heredoclist = NULL;
11452
11453         while (here) {
11454                 if (needprompt) {
11455                         setprompt(2);
11456                 }
11457                 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11458                                 here->eofmark, here->striptabs);
11459                 n = stzalloc(sizeof(struct narg));
11460                 n->narg.type = NARG;
11461                 /*n->narg.next = NULL; - stzalloc did it */
11462                 n->narg.text = wordtext;
11463                 n->narg.backquote = backquotelist;
11464                 here->here->nhere.doc = n;
11465                 here = here->next;
11466         }
11467 }
11468
11469
11470 /*
11471  * called by editline -- any expansions to the prompt should be added here.
11472  */
11473 #if ENABLE_ASH_EXPAND_PRMT
11474 static const char *
11475 expandstr(const char *ps)
11476 {
11477         union node n;
11478
11479         /* XXX Fix (char *) cast. */
11480         setinputstring((char *)ps);
11481         readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11482         popfile();
11483
11484         n.narg.type = NARG;
11485         n.narg.next = NULL;
11486         n.narg.text = wordtext;
11487         n.narg.backquote = backquotelist;
11488
11489         expandarg(&n, NULL, 0);
11490         return stackblock();
11491 }
11492 #endif
11493
11494 /*
11495  * Execute a command or commands contained in a string.
11496  */
11497 static int
11498 evalstring(char *s, int mask)
11499 {
11500         union node *n;
11501         struct stackmark smark;
11502         int skip;
11503
11504         setinputstring(s);
11505         setstackmark(&smark);
11506
11507         skip = 0;
11508         while ((n = parsecmd(0)) != NEOF) {
11509                 evaltree(n, 0);
11510                 popstackmark(&smark);
11511                 skip = evalskip;
11512                 if (skip)
11513                         break;
11514         }
11515         popfile();
11516
11517         skip &= mask;
11518         evalskip = skip;
11519         return skip;
11520 }
11521
11522 /*
11523  * The eval command.
11524  */
11525 static int
11526 evalcmd(int argc UNUSED_PARAM, char **argv)
11527 {
11528         char *p;
11529         char *concat;
11530
11531         if (argv[1]) {
11532                 p = argv[1];
11533                 argv += 2;
11534                 if (argv[0]) {
11535                         STARTSTACKSTR(concat);
11536                         for (;;) {
11537                                 concat = stack_putstr(p, concat);
11538                                 p = *argv++;
11539                                 if (p == NULL)
11540                                         break;
11541                                 STPUTC(' ', concat);
11542                         }
11543                         STPUTC('\0', concat);
11544                         p = grabstackstr(concat);
11545                 }
11546                 evalstring(p, ~SKIPEVAL);
11547
11548         }
11549         return exitstatus;
11550 }
11551
11552 /*
11553  * Read and execute commands.  "Top" is nonzero for the top level command
11554  * loop; it turns on prompting if the shell is interactive.
11555  */
11556 static int
11557 cmdloop(int top)
11558 {
11559         union node *n;
11560         struct stackmark smark;
11561         int inter;
11562         int numeof = 0;
11563
11564         TRACE(("cmdloop(%d) called\n", top));
11565         for (;;) {
11566                 int skip;
11567
11568                 setstackmark(&smark);
11569 #if JOBS
11570                 if (doing_jobctl)
11571                         showjobs(stderr, SHOW_CHANGED);
11572 #endif
11573                 inter = 0;
11574                 if (iflag && top) {
11575                         inter++;
11576 #if ENABLE_ASH_MAIL
11577                         chkmail();
11578 #endif
11579                 }
11580                 n = parsecmd(inter);
11581                 /* showtree(n); DEBUG */
11582                 if (n == NEOF) {
11583                         if (!top || numeof >= 50)
11584                                 break;
11585                         if (!stoppedjobs()) {
11586                                 if (!Iflag)
11587                                         break;
11588                                 out2str("\nUse \"exit\" to leave shell.\n");
11589                         }
11590                         numeof++;
11591                 } else if (nflag == 0) {
11592                         /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11593                         job_warning >>= 1;
11594                         numeof = 0;
11595                         evaltree(n, 0);
11596                 }
11597                 popstackmark(&smark);
11598                 skip = evalskip;
11599
11600                 if (skip) {
11601                         evalskip = 0;
11602                         return skip & SKIPEVAL;
11603                 }
11604         }
11605         return 0;
11606 }
11607
11608 /*
11609  * Take commands from a file.  To be compatible we should do a path
11610  * search for the file, which is necessary to find sub-commands.
11611  */
11612 static char *
11613 find_dot_file(char *name)
11614 {
11615         char *fullname;
11616         const char *path = pathval();
11617         struct stat statb;
11618
11619         /* don't try this for absolute or relative paths */
11620         if (strchr(name, '/'))
11621                 return name;
11622
11623         while ((fullname = padvance(&path, name)) != NULL) {
11624                 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11625                         /*
11626                          * Don't bother freeing here, since it will
11627                          * be freed by the caller.
11628                          */
11629                         return fullname;
11630                 }
11631                 stunalloc(fullname);
11632         }
11633
11634         /* not found in the PATH */
11635         ash_msg_and_raise_error("%s: not found", name);
11636         /* NOTREACHED */
11637 }
11638
11639 static int
11640 dotcmd(int argc, char **argv)
11641 {
11642         struct strlist *sp;
11643         volatile struct shparam saveparam;
11644         int status = 0;
11645
11646         for (sp = cmdenviron; sp; sp = sp->next)
11647                 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11648
11649         if (argv[1]) {        /* That's what SVR2 does */
11650                 char *fullname = find_dot_file(argv[1]);
11651                 argv += 2;
11652                 argc -= 2;
11653                 if (argc) { /* argc > 0, argv[0] != NULL */
11654                         saveparam = shellparam;
11655                         shellparam.malloced = 0;
11656                         shellparam.nparam = argc;
11657                         shellparam.p = argv;
11658                 };
11659
11660                 setinputfile(fullname, INPUT_PUSH_FILE);
11661                 commandname = fullname;
11662                 cmdloop(0);
11663                 popfile();
11664
11665                 if (argc) {
11666                         freeparam(&shellparam);
11667                         shellparam = saveparam;
11668                 };
11669                 status = exitstatus;
11670         }
11671         return status;
11672 }
11673
11674 static int
11675 exitcmd(int argc UNUSED_PARAM, char **argv)
11676 {
11677         if (stoppedjobs())
11678                 return 0;
11679         if (argv[1])
11680                 exitstatus = number(argv[1]);
11681         raise_exception(EXEXIT);
11682         /* NOTREACHED */
11683 }
11684
11685 /*
11686  * Read a file containing shell functions.
11687  */
11688 static void
11689 readcmdfile(char *name)
11690 {
11691         setinputfile(name, INPUT_PUSH_FILE);
11692         cmdloop(0);
11693         popfile();
11694 }
11695
11696
11697 /* ============ find_command inplementation */
11698
11699 /*
11700  * Resolve a command name.  If you change this routine, you may have to
11701  * change the shellexec routine as well.
11702  */
11703 static void
11704 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11705 {
11706         struct tblentry *cmdp;
11707         int idx;
11708         int prev;
11709         char *fullname;
11710         struct stat statb;
11711         int e;
11712         int updatetbl;
11713         struct builtincmd *bcmd;
11714
11715         /* If name contains a slash, don't use PATH or hash table */
11716         if (strchr(name, '/') != NULL) {
11717                 entry->u.index = -1;
11718                 if (act & DO_ABS) {
11719                         while (stat(name, &statb) < 0) {
11720 #ifdef SYSV
11721                                 if (errno == EINTR)
11722                                         continue;
11723 #endif
11724                                 entry->cmdtype = CMDUNKNOWN;
11725                                 return;
11726                         }
11727                 }
11728                 entry->cmdtype = CMDNORMAL;
11729                 return;
11730         }
11731
11732 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11733
11734         updatetbl = (path == pathval());
11735         if (!updatetbl) {
11736                 act |= DO_ALTPATH;
11737                 if (strstr(path, "%builtin") != NULL)
11738                         act |= DO_ALTBLTIN;
11739         }
11740
11741         /* If name is in the table, check answer will be ok */
11742         cmdp = cmdlookup(name, 0);
11743         if (cmdp != NULL) {
11744                 int bit;
11745
11746                 switch (cmdp->cmdtype) {
11747                 default:
11748 #if DEBUG
11749                         abort();
11750 #endif
11751                 case CMDNORMAL:
11752                         bit = DO_ALTPATH;
11753                         break;
11754                 case CMDFUNCTION:
11755                         bit = DO_NOFUNC;
11756                         break;
11757                 case CMDBUILTIN:
11758                         bit = DO_ALTBLTIN;
11759                         break;
11760                 }
11761                 if (act & bit) {
11762                         updatetbl = 0;
11763                         cmdp = NULL;
11764                 } else if (cmdp->rehash == 0)
11765                         /* if not invalidated by cd, we're done */
11766                         goto success;
11767         }
11768
11769         /* If %builtin not in path, check for builtin next */
11770         bcmd = find_builtin(name);
11771         if (bcmd) {
11772                 if (IS_BUILTIN_REGULAR(bcmd))
11773                         goto builtin_success;
11774                 if (act & DO_ALTPATH) {
11775                         if (!(act & DO_ALTBLTIN))
11776                                 goto builtin_success;
11777                 } else if (builtinloc <= 0) {
11778                         goto builtin_success;
11779                 }
11780         }
11781
11782 #if ENABLE_FEATURE_SH_STANDALONE
11783         {
11784                 int applet_no = find_applet_by_name(name);
11785                 if (applet_no >= 0) {
11786                         entry->cmdtype = CMDNORMAL;
11787                         entry->u.index = -2 - applet_no;
11788                         return;
11789                 }
11790         }
11791 #endif
11792
11793         /* We have to search path. */
11794         prev = -1;              /* where to start */
11795         if (cmdp && cmdp->rehash) {     /* doing a rehash */
11796                 if (cmdp->cmdtype == CMDBUILTIN)
11797                         prev = builtinloc;
11798                 else
11799                         prev = cmdp->param.index;
11800         }
11801
11802         e = ENOENT;
11803         idx = -1;
11804  loop:
11805         while ((fullname = padvance(&path, name)) != NULL) {
11806                 stunalloc(fullname);
11807                 /* NB: code below will still use fullname
11808                  * despite it being "unallocated" */
11809                 idx++;
11810                 if (pathopt) {
11811                         if (prefix(pathopt, "builtin")) {
11812                                 if (bcmd)
11813                                         goto builtin_success;
11814                                 continue;
11815                         }
11816                         if ((act & DO_NOFUNC)
11817                          || !prefix(pathopt, "func")
11818                         ) {     /* ignore unimplemented options */
11819                                 continue;
11820                         }
11821                 }
11822                 /* if rehash, don't redo absolute path names */
11823                 if (fullname[0] == '/' && idx <= prev) {
11824                         if (idx < prev)
11825                                 continue;
11826                         TRACE(("searchexec \"%s\": no change\n", name));
11827                         goto success;
11828                 }
11829                 while (stat(fullname, &statb) < 0) {
11830 #ifdef SYSV
11831                         if (errno == EINTR)
11832                                 continue;
11833 #endif
11834                         if (errno != ENOENT && errno != ENOTDIR)
11835                                 e = errno;
11836                         goto loop;
11837                 }
11838                 e = EACCES;     /* if we fail, this will be the error */
11839                 if (!S_ISREG(statb.st_mode))
11840                         continue;
11841                 if (pathopt) {          /* this is a %func directory */
11842                         stalloc(strlen(fullname) + 1);
11843                         /* NB: stalloc will return space pointed by fullname
11844                          * (because we don't have any intervening allocations
11845                          * between stunalloc above and this stalloc) */
11846                         readcmdfile(fullname);
11847                         cmdp = cmdlookup(name, 0);
11848                         if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11849                                 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11850                         stunalloc(fullname);
11851                         goto success;
11852                 }
11853                 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11854                 if (!updatetbl) {
11855                         entry->cmdtype = CMDNORMAL;
11856                         entry->u.index = idx;
11857                         return;
11858                 }
11859                 INT_OFF;
11860                 cmdp = cmdlookup(name, 1);
11861                 cmdp->cmdtype = CMDNORMAL;
11862                 cmdp->param.index = idx;
11863                 INT_ON;
11864                 goto success;
11865         }
11866
11867         /* We failed.  If there was an entry for this command, delete it */
11868         if (cmdp && updatetbl)
11869                 delete_cmd_entry();
11870         if (act & DO_ERR)
11871                 ash_msg("%s: %s", name, errmsg(e, "not found"));
11872         entry->cmdtype = CMDUNKNOWN;
11873         return;
11874
11875  builtin_success:
11876         if (!updatetbl) {
11877                 entry->cmdtype = CMDBUILTIN;
11878                 entry->u.cmd = bcmd;
11879                 return;
11880         }
11881         INT_OFF;
11882         cmdp = cmdlookup(name, 1);
11883         cmdp->cmdtype = CMDBUILTIN;
11884         cmdp->param.cmd = bcmd;
11885         INT_ON;
11886  success:
11887         cmdp->rehash = 0;
11888         entry->cmdtype = cmdp->cmdtype;
11889         entry->u = cmdp->param;
11890 }
11891
11892
11893 /* ============ trap.c */
11894
11895 /*
11896  * The trap builtin.
11897  */
11898 static int
11899 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11900 {
11901         char *action;
11902         char **ap;
11903         int signo;
11904
11905         nextopt(nullstr);
11906         ap = argptr;
11907         if (!*ap) {
11908                 for (signo = 0; signo < NSIG; signo++) {
11909                         if (trap[signo] != NULL) {
11910                                 const char *sn;
11911
11912                                 sn = get_signame(signo);
11913                                 out1fmt("trap -- %s %s\n",
11914                                         single_quote(trap[signo]), sn);
11915                         }
11916                 }
11917                 return 0;
11918         }
11919         if (!ap[1])
11920                 action = NULL;
11921         else
11922                 action = *ap++;
11923         while (*ap) {
11924                 signo = get_signum(*ap);
11925                 if (signo < 0)
11926                         ash_msg_and_raise_error("%s: bad trap", *ap);
11927                 INT_OFF;
11928                 if (action) {
11929                         if (LONE_DASH(action))
11930                                 action = NULL;
11931                         else
11932                                 action = ckstrdup(action);
11933                 }
11934                 free(trap[signo]);
11935                 trap[signo] = action;
11936                 if (signo != 0)
11937                         setsignal(signo);
11938                 INT_ON;
11939                 ap++;
11940         }
11941         return 0;
11942 }
11943
11944
11945 /* ============ Builtins */
11946
11947 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11948 /*
11949  * Lists available builtins
11950  */
11951 static int
11952 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11953 {
11954         unsigned col;
11955         unsigned i;
11956
11957         out1fmt("\nBuilt-in commands:\n-------------------\n");
11958         for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
11959                 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11960                                         builtintab[i].name + 1);
11961                 if (col > 60) {
11962                         out1fmt("\n");
11963                         col = 0;
11964                 }
11965         }
11966 #if ENABLE_FEATURE_SH_STANDALONE
11967         {
11968                 const char *a = applet_names;
11969                 while (*a) {
11970                         col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
11971                         if (col > 60) {
11972                                 out1fmt("\n");
11973                                 col = 0;
11974                         }
11975                         a += strlen(a) + 1;
11976                 }
11977         }
11978 #endif
11979         out1fmt("\n\n");
11980         return EXIT_SUCCESS;
11981 }
11982 #endif /* FEATURE_SH_EXTRA_QUIET */
11983
11984 /*
11985  * The export and readonly commands.
11986  */
11987 static int
11988 exportcmd(int argc UNUSED_PARAM, char **argv)
11989 {
11990         struct var *vp;
11991         char *name;
11992         const char *p;
11993         char **aptr;
11994         int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11995
11996         if (nextopt("p") != 'p') {
11997                 aptr = argptr;
11998                 name = *aptr;
11999                 if (name) {
12000                         do {
12001                                 p = strchr(name, '=');
12002                                 if (p != NULL) {
12003                                         p++;
12004                                 } else {
12005                                         vp = *findvar(hashvar(name), name);
12006                                         if (vp) {
12007                                                 vp->flags |= flag;
12008                                                 continue;
12009                                         }
12010                                 }
12011                                 setvar(name, p, flag);
12012                         } while ((name = *++aptr) != NULL);
12013                         return 0;
12014                 }
12015         }
12016         showvars(argv[0], flag, 0);
12017         return 0;
12018 }
12019
12020 /*
12021  * Delete a function if it exists.
12022  */
12023 static void
12024 unsetfunc(const char *name)
12025 {
12026         struct tblentry *cmdp;
12027
12028         cmdp = cmdlookup(name, 0);
12029         if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
12030                 delete_cmd_entry();
12031 }
12032
12033 /*
12034  * The unset builtin command.  We unset the function before we unset the
12035  * variable to allow a function to be unset when there is a readonly variable
12036  * with the same name.
12037  */
12038 static int
12039 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12040 {
12041         char **ap;
12042         int i;
12043         int flag = 0;
12044         int ret = 0;
12045
12046         while ((i = nextopt("vf")) != '\0') {
12047                 flag = i;
12048         }
12049
12050         for (ap = argptr; *ap; ap++) {
12051                 if (flag != 'f') {
12052                         i = unsetvar(*ap);
12053                         ret |= i;
12054                         if (!(i & 2))
12055                                 continue;
12056                 }
12057                 if (flag != 'v')
12058                         unsetfunc(*ap);
12059         }
12060         return ret & 1;
12061 }
12062
12063
12064 /*      setmode.c      */
12065
12066 #include <sys/times.h>
12067
12068 static const unsigned char timescmd_str[] ALIGN1 = {
12069         ' ',  offsetof(struct tms, tms_utime),
12070         '\n', offsetof(struct tms, tms_stime),
12071         ' ',  offsetof(struct tms, tms_cutime),
12072         '\n', offsetof(struct tms, tms_cstime),
12073         0
12074 };
12075
12076 static int
12077 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12078 {
12079         long clk_tck, s, t;
12080         const unsigned char *p;
12081         struct tms buf;
12082
12083         clk_tck = sysconf(_SC_CLK_TCK);
12084         times(&buf);
12085
12086         p = timescmd_str;
12087         do {
12088                 t = *(clock_t *)(((char *) &buf) + p[1]);
12089                 s = t / clk_tck;
12090                 out1fmt("%ldm%ld.%.3lds%c",
12091                         s/60, s%60,
12092                         ((t - s * clk_tck) * 1000) / clk_tck,
12093                         p[0]);
12094         } while (*(p += 2));
12095
12096         return 0;
12097 }
12098
12099 #if ENABLE_ASH_MATH_SUPPORT
12100 static arith_t
12101 dash_arith(const char *s)
12102 {
12103         arith_t result;
12104         int errcode = 0;
12105
12106         INT_OFF;
12107         result = arith(s, &errcode);
12108         if (errcode < 0) {
12109                 if (errcode == -3)
12110                         ash_msg_and_raise_error("exponent less than 0");
12111                 if (errcode == -2)
12112                         ash_msg_and_raise_error("divide by zero");
12113                 if (errcode == -5)
12114                         ash_msg_and_raise_error("expression recursion loop detected");
12115                 raise_error_syntax(s);
12116         }
12117         INT_ON;
12118
12119         return result;
12120 }
12121
12122 /*
12123  *  The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12124  *  Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12125  *
12126  *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12127  */
12128 static int
12129 letcmd(int argc UNUSED_PARAM, char **argv)
12130 {
12131         arith_t i;
12132
12133         argv++;
12134         if (!*argv)
12135                 ash_msg_and_raise_error("expression expected");
12136         do {
12137                 i = dash_arith(*argv);
12138         } while (*++argv);
12139
12140         return !i;
12141 }
12142 #endif /* ASH_MATH_SUPPORT */
12143
12144
12145 /* ============ miscbltin.c
12146  *
12147  * Miscellaneous builtins.
12148  */
12149
12150 #undef rflag
12151
12152 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12153 typedef enum __rlimit_resource rlim_t;
12154 #endif
12155
12156 /*
12157  * The read builtin. Options:
12158  *      -r              Do not interpret '\' specially
12159  *      -s              Turn off echo (tty only)
12160  *      -n NCHARS       Read NCHARS max
12161  *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
12162  *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
12163  *      -u FD           Read from given FD instead of fd 0
12164  * This uses unbuffered input, which may be avoidable in some cases.
12165  * TODO: bash also has:
12166  *      -a ARRAY        Read into array[0],[1],etc
12167  *      -d DELIM        End on DELIM char, not newline
12168  *      -e              Use line editing (tty only)
12169  */
12170 static int
12171 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12172 {
12173         static const char *const arg_REPLY[] = { "REPLY", NULL };
12174
12175         char **ap;
12176         int backslash;
12177         char c;
12178         int rflag;
12179         char *prompt;
12180         const char *ifs;
12181         char *p;
12182         int startword;
12183         int status;
12184         int i;
12185         int fd = 0;
12186 #if ENABLE_ASH_READ_NCHARS
12187         int nchars = 0; /* if != 0, -n is in effect */
12188         int silent = 0;
12189         struct termios tty, old_tty;
12190 #endif
12191 #if ENABLE_ASH_READ_TIMEOUT
12192         unsigned end_ms = 0;
12193         unsigned timeout = 0;
12194 #endif
12195
12196         rflag = 0;
12197         prompt = NULL;
12198         while ((i = nextopt("p:u:r"
12199                 USE_ASH_READ_TIMEOUT("t:")
12200                 USE_ASH_READ_NCHARS("n:s")
12201         )) != '\0') {
12202                 switch (i) {
12203                 case 'p':
12204                         prompt = optionarg;
12205                         break;
12206 #if ENABLE_ASH_READ_NCHARS
12207                 case 'n':
12208                         nchars = bb_strtou(optionarg, NULL, 10);
12209                         if (nchars < 0 || errno)
12210                                 ash_msg_and_raise_error("invalid count");
12211                         /* nchars == 0: off (bash 3.2 does this too) */
12212                         break;
12213                 case 's':
12214                         silent = 1;
12215                         break;
12216 #endif
12217 #if ENABLE_ASH_READ_TIMEOUT
12218                 case 't':
12219                         timeout = bb_strtou(optionarg, NULL, 10);
12220                         if (errno || timeout > UINT_MAX / 2048)
12221                                 ash_msg_and_raise_error("invalid timeout");
12222                         timeout *= 1000;
12223 #if 0 /* even bash have no -t N.NNN support */
12224                         ts.tv_sec = bb_strtou(optionarg, &p, 10);
12225                         ts.tv_usec = 0;
12226                         /* EINVAL means number is ok, but not terminated by NUL */
12227                         if (*p == '.' && errno == EINVAL) {
12228                                 char *p2;
12229                                 if (*++p) {
12230                                         int scale;
12231                                         ts.tv_usec = bb_strtou(p, &p2, 10);
12232                                         if (errno)
12233                                                 ash_msg_and_raise_error("invalid timeout");
12234                                         scale = p2 - p;
12235                                         /* normalize to usec */
12236                                         if (scale > 6)
12237                                                 ash_msg_and_raise_error("invalid timeout");
12238                                         while (scale++ < 6)
12239                                                 ts.tv_usec *= 10;
12240                                 }
12241                         } else if (ts.tv_sec < 0 || errno) {
12242                                 ash_msg_and_raise_error("invalid timeout");
12243                         }
12244                         if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12245                                 ash_msg_and_raise_error("invalid timeout");
12246                         }
12247 #endif /* if 0 */
12248                         break;
12249 #endif
12250                 case 'r':
12251                         rflag = 1;
12252                         break;
12253                 case 'u':
12254                         fd = bb_strtou(optionarg, NULL, 10);
12255                         if (fd < 0 || errno)
12256                                 ash_msg_and_raise_error("invalid file descriptor");
12257                         break;
12258                 default:
12259                         break;
12260                 }
12261         }
12262         if (prompt && isatty(fd)) {
12263                 out2str(prompt);
12264         }
12265         ap = argptr;
12266         if (*ap == NULL)
12267                 ap = (char**)arg_REPLY;
12268         ifs = bltinlookup("IFS");
12269         if (ifs == NULL)
12270                 ifs = defifs;
12271 #if ENABLE_ASH_READ_NCHARS
12272         tcgetattr(fd, &tty);
12273         old_tty = tty;
12274         if (nchars || silent) {
12275                 if (nchars) {
12276                         tty.c_lflag &= ~ICANON;
12277                         tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12278                 }
12279                 if (silent) {
12280                         tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12281                 }
12282                 /* if tcgetattr failed, tcsetattr will fail too.
12283                  * Ignoring, it's harmless. */
12284                 tcsetattr(fd, TCSANOW, &tty);
12285         }
12286 #endif
12287
12288         status = 0;
12289         startword = 1;
12290         backslash = 0;
12291 #if ENABLE_ASH_READ_TIMEOUT
12292         if (timeout) /* NB: ensuring end_ms is nonzero */
12293                 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12294 #endif
12295         STARTSTACKSTR(p);
12296         do {
12297 #if ENABLE_ASH_READ_TIMEOUT
12298                 if (end_ms) {
12299                         struct pollfd pfd[1];
12300                         pfd[0].fd = fd;
12301                         pfd[0].events = POLLIN;
12302                         timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12303                         if ((int)timeout <= 0 /* already late? */
12304                          || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12305                         ) { /* timed out! */
12306 #if ENABLE_ASH_READ_NCHARS
12307                                 tcsetattr(fd, TCSANOW, &old_tty);
12308 #endif
12309                                 return 1;
12310                         }
12311                 }
12312 #endif
12313                 if (nonblock_safe_read(fd, &c, 1) != 1) {
12314                         status = 1;
12315                         break;
12316                 }
12317                 if (c == '\0')
12318                         continue;
12319                 if (backslash) {
12320                         backslash = 0;
12321                         if (c != '\n')
12322                                 goto put;
12323                         continue;
12324                 }
12325                 if (!rflag && c == '\\') {
12326                         backslash++;
12327                         continue;
12328                 }
12329                 if (c == '\n')
12330                         break;
12331                 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12332                         continue;
12333                 }
12334                 startword = 0;
12335                 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12336                         STACKSTRNUL(p);
12337                         setvar(*ap, stackblock(), 0);
12338                         ap++;
12339                         startword = 1;
12340                         STARTSTACKSTR(p);
12341                 } else {
12342  put:
12343                         STPUTC(c, p);
12344                 }
12345         }
12346 /* end of do {} while: */
12347 #if ENABLE_ASH_READ_NCHARS
12348         while (--nchars);
12349 #else
12350         while (1);
12351 #endif
12352
12353 #if ENABLE_ASH_READ_NCHARS
12354         tcsetattr(fd, TCSANOW, &old_tty);
12355 #endif
12356
12357         STACKSTRNUL(p);
12358         /* Remove trailing blanks */
12359         while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12360                 *p = '\0';
12361         setvar(*ap, stackblock(), 0);
12362         while (*++ap != NULL)
12363                 setvar(*ap, nullstr, 0);
12364         return status;
12365 }
12366
12367 static int
12368 umaskcmd(int argc UNUSED_PARAM, char **argv)
12369 {
12370         static const char permuser[3] ALIGN1 = "ugo";
12371         static const char permmode[3] ALIGN1 = "rwx";
12372         static const short permmask[] ALIGN2 = {
12373                 S_IRUSR, S_IWUSR, S_IXUSR,
12374                 S_IRGRP, S_IWGRP, S_IXGRP,
12375                 S_IROTH, S_IWOTH, S_IXOTH
12376         };
12377
12378         char *ap;
12379         mode_t mask;
12380         int i;
12381         int symbolic_mode = 0;
12382
12383         while (nextopt("S") != '\0') {
12384                 symbolic_mode = 1;
12385         }
12386
12387         INT_OFF;
12388         mask = umask(0);
12389         umask(mask);
12390         INT_ON;
12391
12392         ap = *argptr;
12393         if (ap == NULL) {
12394                 if (symbolic_mode) {
12395                         char buf[18];
12396                         char *p = buf;
12397
12398                         for (i = 0; i < 3; i++) {
12399                                 int j;
12400
12401                                 *p++ = permuser[i];
12402                                 *p++ = '=';
12403                                 for (j = 0; j < 3; j++) {
12404                                         if ((mask & permmask[3 * i + j]) == 0) {
12405                                                 *p++ = permmode[j];
12406                                         }
12407                                 }
12408                                 *p++ = ',';
12409                         }
12410                         *--p = 0;
12411                         puts(buf);
12412                 } else {
12413                         out1fmt("%.4o\n", mask);
12414                 }
12415         } else {
12416                 if (isdigit((unsigned char) *ap)) {
12417                         mask = 0;
12418                         do {
12419                                 if (*ap >= '8' || *ap < '0')
12420                                         ash_msg_and_raise_error(illnum, argv[1]);
12421                                 mask = (mask << 3) + (*ap - '0');
12422                         } while (*++ap != '\0');
12423                         umask(mask);
12424                 } else {
12425                         mask = ~mask & 0777;
12426                         if (!bb_parse_mode(ap, &mask)) {
12427                                 ash_msg_and_raise_error("illegal mode: %s", ap);
12428                         }
12429                         umask(~mask & 0777);
12430                 }
12431         }
12432         return 0;
12433 }
12434
12435 /*
12436  * ulimit builtin
12437  *
12438  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12439  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12440  * ash by J.T. Conklin.
12441  *
12442  * Public domain.
12443  */
12444
12445 struct limits {
12446         uint8_t cmd;          /* RLIMIT_xxx fit into it */
12447         uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12448         char    option;
12449 };
12450
12451 static const struct limits limits_tbl[] = {
12452 #ifdef RLIMIT_CPU
12453         { RLIMIT_CPU,        0, 't' },
12454 #endif
12455 #ifdef RLIMIT_FSIZE
12456         { RLIMIT_FSIZE,      9, 'f' },
12457 #endif
12458 #ifdef RLIMIT_DATA
12459         { RLIMIT_DATA,      10, 'd' },
12460 #endif
12461 #ifdef RLIMIT_STACK
12462         { RLIMIT_STACK,     10, 's' },
12463 #endif
12464 #ifdef RLIMIT_CORE
12465         { RLIMIT_CORE,       9, 'c' },
12466 #endif
12467 #ifdef RLIMIT_RSS
12468         { RLIMIT_RSS,       10, 'm' },
12469 #endif
12470 #ifdef RLIMIT_MEMLOCK
12471         { RLIMIT_MEMLOCK,   10, 'l' },
12472 #endif
12473 #ifdef RLIMIT_NPROC
12474         { RLIMIT_NPROC,      0, 'p' },
12475 #endif
12476 #ifdef RLIMIT_NOFILE
12477         { RLIMIT_NOFILE,     0, 'n' },
12478 #endif
12479 #ifdef RLIMIT_AS
12480         { RLIMIT_AS,        10, 'v' },
12481 #endif
12482 #ifdef RLIMIT_LOCKS
12483         { RLIMIT_LOCKS,      0, 'w' },
12484 #endif
12485 };
12486 static const char limits_name[] =
12487 #ifdef RLIMIT_CPU
12488         "time(seconds)" "\0"
12489 #endif
12490 #ifdef RLIMIT_FSIZE
12491         "file(blocks)" "\0"
12492 #endif
12493 #ifdef RLIMIT_DATA
12494         "data(kb)" "\0"
12495 #endif
12496 #ifdef RLIMIT_STACK
12497         "stack(kb)" "\0"
12498 #endif
12499 #ifdef RLIMIT_CORE
12500         "coredump(blocks)" "\0"
12501 #endif
12502 #ifdef RLIMIT_RSS
12503         "memory(kb)" "\0"
12504 #endif
12505 #ifdef RLIMIT_MEMLOCK
12506         "locked memory(kb)" "\0"
12507 #endif
12508 #ifdef RLIMIT_NPROC
12509         "process" "\0"
12510 #endif
12511 #ifdef RLIMIT_NOFILE
12512         "nofiles" "\0"
12513 #endif
12514 #ifdef RLIMIT_AS
12515         "vmemory(kb)" "\0"
12516 #endif
12517 #ifdef RLIMIT_LOCKS
12518         "locks" "\0"
12519 #endif
12520 ;
12521
12522 enum limtype { SOFT = 0x1, HARD = 0x2 };
12523
12524 static void
12525 printlim(enum limtype how, const struct rlimit *limit,
12526                         const struct limits *l)
12527 {
12528         rlim_t val;
12529
12530         val = limit->rlim_max;
12531         if (how & SOFT)
12532                 val = limit->rlim_cur;
12533
12534         if (val == RLIM_INFINITY)
12535                 out1fmt("unlimited\n");
12536         else {
12537                 val >>= l->factor_shift;
12538                 out1fmt("%lld\n", (long long) val);
12539         }
12540 }
12541
12542 static int
12543 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12544 {
12545         int c;
12546         rlim_t val = 0;
12547         enum limtype how = SOFT | HARD;
12548         const struct limits *l;
12549         int set, all = 0;
12550         int optc, what;
12551         struct rlimit limit;
12552
12553         what = 'f';
12554         while ((optc = nextopt("HSa"
12555 #ifdef RLIMIT_CPU
12556                                 "t"
12557 #endif
12558 #ifdef RLIMIT_FSIZE
12559                                 "f"
12560 #endif
12561 #ifdef RLIMIT_DATA
12562                                 "d"
12563 #endif
12564 #ifdef RLIMIT_STACK
12565                                 "s"
12566 #endif
12567 #ifdef RLIMIT_CORE
12568                                 "c"
12569 #endif
12570 #ifdef RLIMIT_RSS
12571                                 "m"
12572 #endif
12573 #ifdef RLIMIT_MEMLOCK
12574                                 "l"
12575 #endif
12576 #ifdef RLIMIT_NPROC
12577                                 "p"
12578 #endif
12579 #ifdef RLIMIT_NOFILE
12580                                 "n"
12581 #endif
12582 #ifdef RLIMIT_AS
12583                                 "v"
12584 #endif
12585 #ifdef RLIMIT_LOCKS
12586                                 "w"
12587 #endif
12588                                         )) != '\0')
12589                 switch (optc) {
12590                 case 'H':
12591                         how = HARD;
12592                         break;
12593                 case 'S':
12594                         how = SOFT;
12595                         break;
12596                 case 'a':
12597                         all = 1;
12598                         break;
12599                 default:
12600                         what = optc;
12601                 }
12602
12603         for (l = limits_tbl; l->option != what; l++)
12604                 continue;
12605
12606         set = *argptr ? 1 : 0;
12607         if (set) {
12608                 char *p = *argptr;
12609
12610                 if (all || argptr[1])
12611                         ash_msg_and_raise_error("too many arguments");
12612                 if (strncmp(p, "unlimited\n", 9) == 0)
12613                         val = RLIM_INFINITY;
12614                 else {
12615                         val = (rlim_t) 0;
12616
12617                         while ((c = *p++) >= '0' && c <= '9') {
12618                                 val = (val * 10) + (long)(c - '0');
12619                                 // val is actually 'unsigned long int' and can't get < 0
12620                                 if (val < (rlim_t) 0)
12621                                         break;
12622                         }
12623                         if (c)
12624                                 ash_msg_and_raise_error("bad number");
12625                         val <<= l->factor_shift;
12626                 }
12627         }
12628         if (all) {
12629                 const char *lname = limits_name;
12630                 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12631                         getrlimit(l->cmd, &limit);
12632                         out1fmt("%-20s ", lname);
12633                         lname += strlen(lname) + 1;
12634                         printlim(how, &limit, l);
12635                 }
12636                 return 0;
12637         }
12638
12639         getrlimit(l->cmd, &limit);
12640         if (set) {
12641                 if (how & HARD)
12642                         limit.rlim_max = val;
12643                 if (how & SOFT)
12644                         limit.rlim_cur = val;
12645                 if (setrlimit(l->cmd, &limit) < 0)
12646                         ash_msg_and_raise_error("error setting limit (%m)");
12647         } else {
12648                 printlim(how, &limit, l);
12649         }
12650         return 0;
12651 }
12652
12653
12654 /* ============ Math support */
12655
12656 #if ENABLE_ASH_MATH_SUPPORT
12657
12658 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12659
12660    Permission is hereby granted, free of charge, to any person obtaining
12661    a copy of this software and associated documentation files (the
12662    "Software"), to deal in the Software without restriction, including
12663    without limitation the rights to use, copy, modify, merge, publish,
12664    distribute, sublicense, and/or sell copies of the Software, and to
12665    permit persons to whom the Software is furnished to do so, subject to
12666    the following conditions:
12667
12668    The above copyright notice and this permission notice shall be
12669    included in all copies or substantial portions of the Software.
12670
12671    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12672    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12673    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12674    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12675    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12676    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12677    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12678 */
12679
12680 /* This is my infix parser/evaluator. It is optimized for size, intended
12681  * as a replacement for yacc-based parsers. However, it may well be faster
12682  * than a comparable parser written in yacc. The supported operators are
12683  * listed in #defines below. Parens, order of operations, and error handling
12684  * are supported. This code is thread safe. The exact expression format should
12685  * be that which POSIX specifies for shells. */
12686
12687 /* The code uses a simple two-stack algorithm. See
12688  * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12689  * for a detailed explanation of the infix-to-postfix algorithm on which
12690  * this is based (this code differs in that it applies operators immediately
12691  * to the stack instead of adding them to a queue to end up with an
12692  * expression). */
12693
12694 /* To use the routine, call it with an expression string and error return
12695  * pointer */
12696
12697 /*
12698  * Aug 24, 2001              Manuel Novoa III
12699  *
12700  * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12701  *
12702  * 1) In arith_apply():
12703  *    a) Cached values of *numptr and &(numptr[-1]).
12704  *    b) Removed redundant test for zero denominator.
12705  *
12706  * 2) In arith():
12707  *    a) Eliminated redundant code for processing operator tokens by moving
12708  *       to a table-based implementation.  Also folded handling of parens
12709  *       into the table.
12710  *    b) Combined all 3 loops which called arith_apply to reduce generated
12711  *       code size at the cost of speed.
12712  *
12713  * 3) The following expressions were treated as valid by the original code:
12714  *       1()  ,    0!  ,    1 ( *3 )   .
12715  *    These bugs have been fixed by internally enclosing the expression in
12716  *    parens and then checking that all binary ops and right parens are
12717  *    preceded by a valid expression (NUM_TOKEN).
12718  *
12719  * Note: It may be desirable to replace Aaron's test for whitespace with
12720  * ctype's isspace() if it is used by another busybox applet or if additional
12721  * whitespace chars should be considered.  Look below the "#include"s for a
12722  * precompiler test.
12723  */
12724
12725 /*
12726  * Aug 26, 2001              Manuel Novoa III
12727  *
12728  * Return 0 for null expressions.  Pointed out by Vladimir Oleynik.
12729  *
12730  * Merge in Aaron's comments previously posted to the busybox list,
12731  * modified slightly to take account of my changes to the code.
12732  *
12733  */
12734
12735 /*
12736  *  (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12737  *
12738  * - allow access to variable,
12739  *   used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12740  * - realize assign syntax (VAR=expr, +=, *= etc)
12741  * - realize exponentiation (** operator)
12742  * - realize comma separated - expr, expr
12743  * - realise ++expr --expr expr++ expr--
12744  * - realise expr ? expr : expr (but, second expr calculate always)
12745  * - allow hexadecimal and octal numbers
12746  * - was restored loses XOR operator
12747  * - remove one goto label, added three ;-)
12748  * - protect $((num num)) as true zero expr (Manuel`s error)
12749  * - always use special isspace(), see comment from bash ;-)
12750  */
12751
12752 #define arith_isspace(arithval) \
12753         (arithval == ' ' || arithval == '\n' || arithval == '\t')
12754
12755 typedef unsigned char operator;
12756
12757 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12758  * precedence, and 3 high bits are an ID unique across operators of that
12759  * precedence. The ID portion is so that multiple operators can have the
12760  * same precedence, ensuring that the leftmost one is evaluated first.
12761  * Consider * and /. */
12762
12763 #define tok_decl(prec,id) (((id)<<5)|(prec))
12764 #define PREC(op) ((op) & 0x1F)
12765
12766 #define TOK_LPAREN tok_decl(0,0)
12767
12768 #define TOK_COMMA tok_decl(1,0)
12769
12770 #define TOK_ASSIGN tok_decl(2,0)
12771 #define TOK_AND_ASSIGN tok_decl(2,1)
12772 #define TOK_OR_ASSIGN tok_decl(2,2)
12773 #define TOK_XOR_ASSIGN tok_decl(2,3)
12774 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12775 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12776 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12777 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12778
12779 #define TOK_MUL_ASSIGN tok_decl(3,0)
12780 #define TOK_DIV_ASSIGN tok_decl(3,1)
12781 #define TOK_REM_ASSIGN tok_decl(3,2)
12782
12783 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12784 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12785
12786 /* conditional is right associativity too */
12787 #define TOK_CONDITIONAL tok_decl(4,0)
12788 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12789
12790 #define TOK_OR tok_decl(5,0)
12791
12792 #define TOK_AND tok_decl(6,0)
12793
12794 #define TOK_BOR tok_decl(7,0)
12795
12796 #define TOK_BXOR tok_decl(8,0)
12797
12798 #define TOK_BAND tok_decl(9,0)
12799
12800 #define TOK_EQ tok_decl(10,0)
12801 #define TOK_NE tok_decl(10,1)
12802
12803 #define TOK_LT tok_decl(11,0)
12804 #define TOK_GT tok_decl(11,1)
12805 #define TOK_GE tok_decl(11,2)
12806 #define TOK_LE tok_decl(11,3)
12807
12808 #define TOK_LSHIFT tok_decl(12,0)
12809 #define TOK_RSHIFT tok_decl(12,1)
12810
12811 #define TOK_ADD tok_decl(13,0)
12812 #define TOK_SUB tok_decl(13,1)
12813
12814 #define TOK_MUL tok_decl(14,0)
12815 #define TOK_DIV tok_decl(14,1)
12816 #define TOK_REM tok_decl(14,2)
12817
12818 /* exponent is right associativity */
12819 #define TOK_EXPONENT tok_decl(15,1)
12820
12821 /* For now unary operators. */
12822 #define UNARYPREC 16
12823 #define TOK_BNOT tok_decl(UNARYPREC,0)
12824 #define TOK_NOT tok_decl(UNARYPREC,1)
12825
12826 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12827 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12828
12829 #define PREC_PRE (UNARYPREC+2)
12830
12831 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12832 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12833
12834 #define PREC_POST (UNARYPREC+3)
12835
12836 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12837 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12838
12839 #define SPEC_PREC (UNARYPREC+4)
12840
12841 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12842 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12843
12844 #define NUMPTR (*numstackptr)
12845
12846 static int
12847 tok_have_assign(operator op)
12848 {
12849         operator prec = PREC(op);
12850
12851         convert_prec_is_assing(prec);
12852         return (prec == PREC(TOK_ASSIGN) ||
12853                         prec == PREC_PRE || prec == PREC_POST);
12854 }
12855
12856 static int
12857 is_right_associativity(operator prec)
12858 {
12859         return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12860                 || prec == PREC(TOK_CONDITIONAL));
12861 }
12862
12863 typedef struct {
12864         arith_t val;
12865         arith_t contidional_second_val;
12866         char contidional_second_val_initialized;
12867         char *var;      /* if NULL then is regular number,
12868                            else is variable name */
12869 } v_n_t;
12870
12871 typedef struct chk_var_recursive_looped_t {
12872         const char *var;
12873         struct chk_var_recursive_looped_t *next;
12874 } chk_var_recursive_looped_t;
12875
12876 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12877
12878 static int
12879 arith_lookup_val(v_n_t *t)
12880 {
12881         if (t->var) {
12882                 const char * p = lookupvar(t->var);
12883
12884                 if (p) {
12885                         int errcode;
12886
12887                         /* recursive try as expression */
12888                         chk_var_recursive_looped_t *cur;
12889                         chk_var_recursive_looped_t cur_save;
12890
12891                         for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12892                                 if (strcmp(cur->var, t->var) == 0) {
12893                                         /* expression recursion loop detected */
12894                                         return -5;
12895                                 }
12896                         }
12897                         /* save current lookuped var name */
12898                         cur = prev_chk_var_recursive;
12899                         cur_save.var = t->var;
12900                         cur_save.next = cur;
12901                         prev_chk_var_recursive = &cur_save;
12902
12903                         t->val = arith (p, &errcode);
12904                         /* restore previous ptr after recursiving */
12905                         prev_chk_var_recursive = cur;
12906                         return errcode;
12907                 }
12908                 /* allow undefined var as 0 */
12909                 t->val = 0;
12910         }
12911         return 0;
12912 }
12913
12914 /* "applying" a token means performing it on the top elements on the integer
12915  * stack. For a unary operator it will only change the top element, but a
12916  * binary operator will pop two arguments and push a result */
12917 static int
12918 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
12919 {
12920         v_n_t *numptr_m1;
12921         arith_t numptr_val, rez;
12922         int ret_arith_lookup_val;
12923
12924         /* There is no operator that can work without arguments */
12925         if (NUMPTR == numstack) goto err;
12926         numptr_m1 = NUMPTR - 1;
12927
12928         /* check operand is var with noninteger value */
12929         ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12930         if (ret_arith_lookup_val)
12931                 return ret_arith_lookup_val;
12932
12933         rez = numptr_m1->val;
12934         if (op == TOK_UMINUS)
12935                 rez *= -1;
12936         else if (op == TOK_NOT)
12937                 rez = !rez;
12938         else if (op == TOK_BNOT)
12939                 rez = ~rez;
12940         else if (op == TOK_POST_INC || op == TOK_PRE_INC)
12941                 rez++;
12942         else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
12943                 rez--;
12944         else if (op != TOK_UPLUS) {
12945                 /* Binary operators */
12946
12947                 /* check and binary operators need two arguments */
12948                 if (numptr_m1 == numstack) goto err;
12949
12950                 /* ... and they pop one */
12951                 --NUMPTR;
12952                 numptr_val = rez;
12953                 if (op == TOK_CONDITIONAL) {
12954                         if (!numptr_m1->contidional_second_val_initialized) {
12955                                 /* protect $((expr1 ? expr2)) without ": expr" */
12956                                 goto err;
12957                         }
12958                         rez = numptr_m1->contidional_second_val;
12959                 } else if (numptr_m1->contidional_second_val_initialized) {
12960                         /* protect $((expr1 : expr2)) without "expr ? " */
12961                         goto err;
12962                 }
12963                 numptr_m1 = NUMPTR - 1;
12964                 if (op != TOK_ASSIGN) {
12965                         /* check operand is var with noninteger value for not '=' */
12966                         ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12967                         if (ret_arith_lookup_val)
12968                                 return ret_arith_lookup_val;
12969                 }
12970                 if (op == TOK_CONDITIONAL) {
12971                         numptr_m1->contidional_second_val = rez;
12972                 }
12973                 rez = numptr_m1->val;
12974                 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
12975                         rez |= numptr_val;
12976                 else if (op == TOK_OR)
12977                         rez = numptr_val || rez;
12978                 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
12979                         rez &= numptr_val;
12980                 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
12981                         rez ^= numptr_val;
12982                 else if (op == TOK_AND)
12983                         rez = rez && numptr_val;
12984                 else if (op == TOK_EQ)
12985                         rez = (rez == numptr_val);
12986                 else if (op == TOK_NE)
12987                         rez = (rez != numptr_val);
12988                 else if (op == TOK_GE)
12989                         rez = (rez >= numptr_val);
12990                 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
12991                         rez >>= numptr_val;
12992                 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
12993                         rez <<= numptr_val;
12994                 else if (op == TOK_GT)
12995                         rez = (rez > numptr_val);
12996                 else if (op == TOK_LT)
12997                         rez = (rez < numptr_val);
12998                 else if (op == TOK_LE)
12999                         rez = (rez <= numptr_val);
13000                 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13001                         rez *= numptr_val;
13002                 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13003                         rez += numptr_val;
13004                 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13005                         rez -= numptr_val;
13006                 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13007                         rez = numptr_val;
13008                 else if (op == TOK_CONDITIONAL_SEP) {
13009                         if (numptr_m1 == numstack) {
13010                                 /* protect $((expr : expr)) without "expr ? " */
13011                                 goto err;
13012                         }
13013                         numptr_m1->contidional_second_val_initialized = op;
13014                         numptr_m1->contidional_second_val = numptr_val;
13015                 } else if (op == TOK_CONDITIONAL) {
13016                         rez = rez ?
13017                                 numptr_val : numptr_m1->contidional_second_val;
13018                 } else if (op == TOK_EXPONENT) {
13019                         if (numptr_val < 0)
13020                                 return -3;      /* exponent less than 0 */
13021                         else {
13022                                 arith_t c = 1;
13023
13024                                 if (numptr_val)
13025                                         while (numptr_val--)
13026                                                 c *= rez;
13027                                 rez = c;
13028                         }
13029                 } else if (numptr_val==0)          /* zero divisor check */
13030                         return -2;
13031                 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13032                         rez /= numptr_val;
13033                 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13034                         rez %= numptr_val;
13035         }
13036         if (tok_have_assign(op)) {
13037                 char buf[sizeof(arith_t_type)*3 + 2];
13038
13039                 if (numptr_m1->var == NULL) {
13040                         /* Hmm, 1=2 ? */
13041                         goto err;
13042                 }
13043                 /* save to shell variable */
13044 #if ENABLE_ASH_MATH_SUPPORT_64
13045                 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
13046 #else
13047                 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
13048 #endif
13049                 setvar(numptr_m1->var, buf, 0);
13050                 /* after saving, make previous value for v++ or v-- */
13051                 if (op == TOK_POST_INC)
13052                         rez--;
13053                 else if (op == TOK_POST_DEC)
13054                         rez++;
13055         }
13056         numptr_m1->val = rez;
13057         /* protect geting var value, is number now */
13058         numptr_m1->var = NULL;
13059         return 0;
13060  err:
13061         return -1;
13062 }
13063
13064 /* longest must be first */
13065 static const char op_tokens[] ALIGN1 = {
13066         '<','<','=',0, TOK_LSHIFT_ASSIGN,
13067         '>','>','=',0, TOK_RSHIFT_ASSIGN,
13068         '<','<',    0, TOK_LSHIFT,
13069         '>','>',    0, TOK_RSHIFT,
13070         '|','|',    0, TOK_OR,
13071         '&','&',    0, TOK_AND,
13072         '!','=',    0, TOK_NE,
13073         '<','=',    0, TOK_LE,
13074         '>','=',    0, TOK_GE,
13075         '=','=',    0, TOK_EQ,
13076         '|','=',    0, TOK_OR_ASSIGN,
13077         '&','=',    0, TOK_AND_ASSIGN,
13078         '*','=',    0, TOK_MUL_ASSIGN,
13079         '/','=',    0, TOK_DIV_ASSIGN,
13080         '%','=',    0, TOK_REM_ASSIGN,
13081         '+','=',    0, TOK_PLUS_ASSIGN,
13082         '-','=',    0, TOK_MINUS_ASSIGN,
13083         '-','-',    0, TOK_POST_DEC,
13084         '^','=',    0, TOK_XOR_ASSIGN,
13085         '+','+',    0, TOK_POST_INC,
13086         '*','*',    0, TOK_EXPONENT,
13087         '!',        0, TOK_NOT,
13088         '<',        0, TOK_LT,
13089         '>',        0, TOK_GT,
13090         '=',        0, TOK_ASSIGN,
13091         '|',        0, TOK_BOR,
13092         '&',        0, TOK_BAND,
13093         '*',        0, TOK_MUL,
13094         '/',        0, TOK_DIV,
13095         '%',        0, TOK_REM,
13096         '+',        0, TOK_ADD,
13097         '-',        0, TOK_SUB,
13098         '^',        0, TOK_BXOR,
13099         /* uniq */
13100         '~',        0, TOK_BNOT,
13101         ',',        0, TOK_COMMA,
13102         '?',        0, TOK_CONDITIONAL,
13103         ':',        0, TOK_CONDITIONAL_SEP,
13104         ')',        0, TOK_RPAREN,
13105         '(',        0, TOK_LPAREN,
13106         0
13107 };
13108 /* ptr to ")" */
13109 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
13110
13111 static arith_t
13112 arith(const char *expr, int *perrcode)
13113 {
13114         char arithval; /* Current character under analysis */
13115         operator lasttok, op;
13116         operator prec;
13117         operator *stack, *stackptr;
13118         const char *p = endexpression;
13119         int errcode;
13120         v_n_t *numstack, *numstackptr;
13121         unsigned datasizes = strlen(expr) + 2;
13122
13123         /* Stack of integers */
13124         /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13125          * in any given correct or incorrect expression is left as an exercise to
13126          * the reader. */
13127         numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
13128         /* Stack of operator tokens */
13129         stackptr = stack = alloca(datasizes * sizeof(stack[0]));
13130
13131         *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
13132         *perrcode = errcode = 0;
13133
13134         while (1) {
13135                 arithval = *expr;
13136                 if (arithval == 0) {
13137                         if (p == endexpression) {
13138                                 /* Null expression. */
13139                                 return 0;
13140                         }
13141
13142                         /* This is only reached after all tokens have been extracted from the
13143                          * input stream. If there are still tokens on the operator stack, they
13144                          * are to be applied in order. At the end, there should be a final
13145                          * result on the integer stack */
13146
13147                         if (expr != endexpression + 1) {
13148                                 /* If we haven't done so already, */
13149                                 /* append a closing right paren */
13150                                 expr = endexpression;
13151                                 /* and let the loop process it. */
13152                                 continue;
13153                         }
13154                         /* At this point, we're done with the expression. */
13155                         if (numstackptr != numstack+1) {
13156                                 /* ... but if there isn't, it's bad */
13157  err:
13158                                 *perrcode = -1;
13159                                 return *perrcode;
13160                         }
13161                         if (numstack->var) {
13162                                 /* expression is $((var)) only, lookup now */
13163                                 errcode = arith_lookup_val(numstack);
13164                         }
13165  ret:
13166                         *perrcode = errcode;
13167                         return numstack->val;
13168                 }
13169
13170                 /* Continue processing the expression. */
13171                 if (arith_isspace(arithval)) {
13172                         /* Skip whitespace */
13173                         goto prologue;
13174                 }
13175                 p = endofname(expr);
13176                 if (p != expr) {
13177                         size_t var_name_size = (p-expr) + 1;  /* trailing zero */
13178
13179                         numstackptr->var = alloca(var_name_size);
13180                         safe_strncpy(numstackptr->var, expr, var_name_size);
13181                         expr = p;
13182  num:
13183                         numstackptr->contidional_second_val_initialized = 0;
13184                         numstackptr++;
13185                         lasttok = TOK_NUM;
13186                         continue;
13187                 }
13188                 if (isdigit(arithval)) {
13189                         numstackptr->var = NULL;
13190 #if ENABLE_ASH_MATH_SUPPORT_64
13191                         numstackptr->val = strtoll(expr, (char **) &expr, 0);
13192 #else
13193                         numstackptr->val = strtol(expr, (char **) &expr, 0);
13194 #endif
13195                         goto num;
13196                 }
13197                 for (p = op_tokens; ; p++) {
13198                         const char *o;
13199
13200                         if (*p == 0) {
13201                                 /* strange operator not found */
13202                                 goto err;
13203                         }
13204                         for (o = expr; *p && *o == *p; p++)
13205                                 o++;
13206                         if (!*p) {
13207                                 /* found */
13208                                 expr = o - 1;
13209                                 break;
13210                         }
13211                         /* skip tail uncompared token */
13212                         while (*p)
13213                                 p++;
13214                         /* skip zero delim */
13215                         p++;
13216                 }
13217                 op = p[1];
13218
13219                 /* post grammar: a++ reduce to num */
13220                 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13221                         lasttok = TOK_NUM;
13222
13223                 /* Plus and minus are binary (not unary) _only_ if the last
13224                  * token was as number, or a right paren (which pretends to be
13225                  * a number, since it evaluates to one). Think about it.
13226                  * It makes sense. */
13227                 if (lasttok != TOK_NUM) {
13228                         switch (op) {
13229                         case TOK_ADD:
13230                                 op = TOK_UPLUS;
13231                                 break;
13232                         case TOK_SUB:
13233                                 op = TOK_UMINUS;
13234                                 break;
13235                         case TOK_POST_INC:
13236                                 op = TOK_PRE_INC;
13237                                 break;
13238                         case TOK_POST_DEC:
13239                                 op = TOK_PRE_DEC;
13240                                 break;
13241                         }
13242                 }
13243                 /* We don't want a unary operator to cause recursive descent on the
13244                  * stack, because there can be many in a row and it could cause an
13245                  * operator to be evaluated before its argument is pushed onto the
13246                  * integer stack. */
13247                 /* But for binary operators, "apply" everything on the operator
13248                  * stack until we find an operator with a lesser priority than the
13249                  * one we have just extracted. */
13250                 /* Left paren is given the lowest priority so it will never be
13251                  * "applied" in this way.
13252                  * if associativity is right and priority eq, applied also skip
13253                  */
13254                 prec = PREC(op);
13255                 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13256                         /* not left paren or unary */
13257                         if (lasttok != TOK_NUM) {
13258                                 /* binary op must be preceded by a num */
13259                                 goto err;
13260                         }
13261                         while (stackptr != stack) {
13262                                 if (op == TOK_RPAREN) {
13263                                         /* The algorithm employed here is simple: while we don't
13264                                          * hit an open paren nor the bottom of the stack, pop
13265                                          * tokens and apply them */
13266                                         if (stackptr[-1] == TOK_LPAREN) {
13267                                                 --stackptr;
13268                                                 /* Any operator directly after a */
13269                                                 lasttok = TOK_NUM;
13270                                                 /* close paren should consider itself binary */
13271                                                 goto prologue;
13272                                         }
13273                                 } else {
13274                                         operator prev_prec = PREC(stackptr[-1]);
13275
13276                                         convert_prec_is_assing(prec);
13277                                         convert_prec_is_assing(prev_prec);
13278                                         if (prev_prec < prec)
13279                                                 break;
13280                                         /* check right assoc */
13281                                         if (prev_prec == prec && is_right_associativity(prec))
13282                                                 break;
13283                                 }
13284                                 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13285                                 if (errcode) goto ret;
13286                         }
13287                         if (op == TOK_RPAREN) {
13288                                 goto err;
13289                         }
13290                 }
13291
13292                 /* Push this operator to the stack and remember it. */
13293                 *stackptr++ = lasttok = op;
13294  prologue:
13295                 ++expr;
13296         } /* while */
13297 }
13298 #endif /* ASH_MATH_SUPPORT */
13299
13300
13301 /* ============ main() and helpers */
13302
13303 /*
13304  * Called to exit the shell.
13305  */
13306 static void exitshell(void) NORETURN;
13307 static void
13308 exitshell(void)
13309 {
13310         struct jmploc loc;
13311         char *p;
13312         int status;
13313
13314         status = exitstatus;
13315         TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13316         if (setjmp(loc.loc)) {
13317                 if (exception == EXEXIT)
13318 /* dash bug: it just does _exit(exitstatus) here
13319  * but we have to do setjobctl(0) first!
13320  * (bug is still not fixed in dash-0.5.3 - if you run dash
13321  * under Midnight Commander, on exit from dash MC is backgrounded) */
13322                         status = exitstatus;
13323                 goto out;
13324         }
13325         exception_handler = &loc;
13326         p = trap[0];
13327         if (p) {
13328                 trap[0] = NULL;
13329                 evalstring(p, 0);
13330         }
13331         flush_stdout_stderr();
13332  out:
13333         setjobctl(0);
13334         _exit(status);
13335         /* NOTREACHED */
13336 }
13337
13338 static void
13339 init(void)
13340 {
13341         /* from input.c: */
13342         basepf.nextc = basepf.buf = basebuf;
13343
13344         /* from trap.c: */
13345         signal(SIGCHLD, SIG_DFL);
13346
13347         /* from var.c: */
13348         {
13349                 char **envp;
13350                 char ppid[sizeof(int)*3 + 1];
13351                 const char *p;
13352                 struct stat st1, st2;
13353
13354                 initvar();
13355                 for (envp = environ; envp && *envp; envp++) {
13356                         if (strchr(*envp, '=')) {
13357                                 setvareq(*envp, VEXPORT|VTEXTFIXED);
13358                         }
13359                 }
13360
13361                 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13362                 setvar("PPID", ppid, 0);
13363
13364                 p = lookupvar("PWD");
13365                 if (p)
13366                         if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13367                          || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13368                                 p = '\0';
13369                 setpwd(p, 0);
13370         }
13371 }
13372
13373 /*
13374  * Process the shell command line arguments.
13375  */
13376 static void
13377 procargs(char **argv)
13378 {
13379         int i;
13380         const char *xminusc;
13381         char **xargv;
13382
13383         xargv = argv;
13384         arg0 = xargv[0];
13385         /* if (xargv[0]) - mmm, this is always true! */
13386                 xargv++;
13387         for (i = 0; i < NOPTS; i++)
13388                 optlist[i] = 2;
13389         argptr = xargv;
13390         if (options(1)) {
13391                 /* it already printed err message */
13392                 raise_exception(EXERROR);
13393         }
13394         xargv = argptr;
13395         xminusc = minusc;
13396         if (*xargv == NULL) {
13397                 if (xminusc)
13398                         ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13399                 sflag = 1;
13400         }
13401         if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13402                 iflag = 1;
13403         if (mflag == 2)
13404                 mflag = iflag;
13405         for (i = 0; i < NOPTS; i++)
13406                 if (optlist[i] == 2)
13407                         optlist[i] = 0;
13408 #if DEBUG == 2
13409         debug = 1;
13410 #endif
13411         /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13412         if (xminusc) {
13413                 minusc = *xargv++;
13414                 if (*xargv)
13415                         goto setarg0;
13416         } else if (!sflag) {
13417                 setinputfile(*xargv, 0);
13418  setarg0:
13419                 arg0 = *xargv++;
13420                 commandname = arg0;
13421         }
13422
13423         shellparam.p = xargv;
13424 #if ENABLE_ASH_GETOPTS
13425         shellparam.optind = 1;
13426         shellparam.optoff = -1;
13427 #endif
13428         /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13429         while (*xargv) {
13430                 shellparam.nparam++;
13431                 xargv++;
13432         }
13433         optschanged();
13434 }
13435
13436 /*
13437  * Read /etc/profile or .profile.
13438  */
13439 static void
13440 read_profile(const char *name)
13441 {
13442         int skip;
13443
13444         if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13445                 return;
13446         skip = cmdloop(0);
13447         popfile();
13448         if (skip)
13449                 exitshell();
13450 }
13451
13452 /*
13453  * This routine is called when an error or an interrupt occurs in an
13454  * interactive shell and control is returned to the main command loop.
13455  */
13456 static void
13457 reset(void)
13458 {
13459         /* from eval.c: */
13460         evalskip = 0;
13461         loopnest = 0;
13462         /* from input.c: */
13463         parselleft = parsenleft = 0;      /* clear input buffer */
13464         popallfiles();
13465         /* from parser.c: */
13466         tokpushback = 0;
13467         checkkwd = 0;
13468         /* from redir.c: */
13469         clearredir(0);
13470 }
13471
13472 #if PROFILE
13473 static short profile_buf[16384];
13474 extern int etext();
13475 #endif
13476
13477 /*
13478  * Main routine.  We initialize things, parse the arguments, execute
13479  * profiles if we're a login shell, and then call cmdloop to execute
13480  * commands.  The setjmp call sets up the location to jump to when an
13481  * exception occurs.  When an exception occurs the variable "state"
13482  * is used to figure out how far we had gotten.
13483  */
13484 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13485 int ash_main(int argc UNUSED_PARAM, char **argv)
13486 {
13487         char *shinit;
13488         volatile int state;
13489         struct jmploc jmploc;
13490         struct stackmark smark;
13491
13492         /* Initialize global data */
13493         INIT_G_misc();
13494         INIT_G_memstack();
13495         INIT_G_var();
13496 #if ENABLE_ASH_ALIAS
13497         INIT_G_alias();
13498 #endif
13499         INIT_G_cmdtable();
13500
13501 #if PROFILE
13502         monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13503 #endif
13504
13505 #if ENABLE_FEATURE_EDITING
13506         line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13507 #endif
13508         state = 0;
13509         if (setjmp(jmploc.loc)) {
13510                 int e;
13511                 int s;
13512
13513                 reset();
13514
13515                 e = exception;
13516                 if (e == EXERROR)
13517                         exitstatus = 2;
13518                 s = state;
13519                 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13520                         exitshell();
13521
13522                 if (e == EXINT) {
13523                         outcslow('\n', stderr);
13524                 }
13525                 popstackmark(&smark);
13526                 FORCE_INT_ON; /* enable interrupts */
13527                 if (s == 1)
13528                         goto state1;
13529                 if (s == 2)
13530                         goto state2;
13531                 if (s == 3)
13532                         goto state3;
13533                 goto state4;
13534         }
13535         exception_handler = &jmploc;
13536 #if DEBUG
13537         opentrace();
13538         trace_puts("Shell args: ");
13539         trace_puts_args(argv);
13540 #endif
13541         rootpid = getpid();
13542
13543 #if ENABLE_ASH_RANDOM_SUPPORT
13544         /* Can use monotonic_ns() for better randomness but for now it is
13545          * not used anywhere else in busybox... so avoid bloat */
13546         random_galois_LFSR = random_LCG = rootpid + monotonic_us();
13547 #endif
13548         init();
13549         setstackmark(&smark);
13550         procargs(argv);
13551
13552 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13553         if (iflag) {
13554                 const char *hp = lookupvar("HISTFILE");
13555
13556                 if (hp == NULL) {
13557                         hp = lookupvar("HOME");
13558                         if (hp != NULL) {
13559                                 char *defhp = concat_path_file(hp, ".ash_history");
13560                                 setvar("HISTFILE", defhp, 0);
13561                                 free(defhp);
13562                         }
13563                 }
13564         }
13565 #endif
13566         if (argv[0] && argv[0][0] == '-')
13567                 isloginsh = 1;
13568         if (isloginsh) {
13569                 state = 1;
13570                 read_profile("/etc/profile");
13571  state1:
13572                 state = 2;
13573                 read_profile(".profile");
13574         }
13575  state2:
13576         state = 3;
13577         if (
13578 #ifndef linux
13579          getuid() == geteuid() && getgid() == getegid() &&
13580 #endif
13581          iflag
13582         ) {
13583                 shinit = lookupvar("ENV");
13584                 if (shinit != NULL && *shinit != '\0') {
13585                         read_profile(shinit);
13586                 }
13587         }
13588  state3:
13589         state = 4;
13590         if (minusc)
13591                 evalstring(minusc, 0);
13592
13593         if (sflag || minusc == NULL) {
13594 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13595                 if (iflag) {
13596                         const char *hp = lookupvar("HISTFILE");
13597
13598                         if (hp != NULL)
13599                                 line_input_state->hist_file = hp;
13600                 }
13601 #endif
13602  state4: /* XXX ??? - why isn't this before the "if" statement */
13603                 cmdloop(1);
13604         }
13605 #if PROFILE
13606         monitor(0);
13607 #endif
13608 #ifdef GPROF
13609         {
13610                 extern void _mcleanup(void);
13611                 _mcleanup();
13612         }
13613 #endif
13614         exitshell();
13615         /* NOTREACHED */
13616 }
13617
13618 #if DEBUG
13619 const char *applet_name = "debug stuff usage";
13620 int main(int argc, char **argv)
13621 {
13622         return ash_main(argc, argv);
13623 }
13624 #endif
13625
13626
13627 /*-
13628  * Copyright (c) 1989, 1991, 1993, 1994
13629  *      The Regents of the University of California.  All rights reserved.
13630  *
13631  * This code is derived from software contributed to Berkeley by
13632  * Kenneth Almquist.
13633  *
13634  * Redistribution and use in source and binary forms, with or without
13635  * modification, are permitted provided that the following conditions
13636  * are met:
13637  * 1. Redistributions of source code must retain the above copyright
13638  *    notice, this list of conditions and the following disclaimer.
13639  * 2. Redistributions in binary form must reproduce the above copyright
13640  *    notice, this list of conditions and the following disclaimer in the
13641  *    documentation and/or other materials provided with the distribution.
13642  * 3. Neither the name of the University nor the names of its contributors
13643  *    may be used to endorse or promote products derived from this software
13644  *    without specific prior written permission.
13645  *
13646  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13647  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13648  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13649  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13650  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13651  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13652  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13653  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13654  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13655  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13656  * SUCH DAMAGE.
13657  */