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