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