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