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