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