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