ash: fix bad interaction between ash -c '....&' and bash compat
[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 #if ENABLE_ASH_BASH_COMPAT
7579         [NTO2     ] = SHELL_ALIGN(sizeof(struct nfile)),
7580 #endif
7581         [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
7582         [NFROM    ] = SHELL_ALIGN(sizeof(struct nfile)),
7583         [NFROMTO  ] = SHELL_ALIGN(sizeof(struct nfile)),
7584         [NAPPEND  ] = SHELL_ALIGN(sizeof(struct nfile)),
7585         [NTOFD    ] = SHELL_ALIGN(sizeof(struct ndup)),
7586         [NFROMFD  ] = SHELL_ALIGN(sizeof(struct ndup)),
7587         [NHERE    ] = SHELL_ALIGN(sizeof(struct nhere)),
7588         [NXHERE   ] = SHELL_ALIGN(sizeof(struct nhere)),
7589         [NNOT     ] = SHELL_ALIGN(sizeof(struct nnot)),
7590 };
7591
7592 static void calcsize(union node *n);
7593
7594 static void
7595 sizenodelist(struct nodelist *lp)
7596 {
7597         while (lp) {
7598                 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7599                 calcsize(lp->n);
7600                 lp = lp->next;
7601         }
7602 }
7603
7604 static void
7605 calcsize(union node *n)
7606 {
7607         if (n == NULL)
7608                 return;
7609         funcblocksize += nodesize[n->type];
7610         switch (n->type) {
7611         case NCMD:
7612                 calcsize(n->ncmd.redirect);
7613                 calcsize(n->ncmd.args);
7614                 calcsize(n->ncmd.assign);
7615                 break;
7616         case NPIPE:
7617                 sizenodelist(n->npipe.cmdlist);
7618                 break;
7619         case NREDIR:
7620         case NBACKGND:
7621         case NSUBSHELL:
7622                 calcsize(n->nredir.redirect);
7623                 calcsize(n->nredir.n);
7624                 break;
7625         case NAND:
7626         case NOR:
7627         case NSEMI:
7628         case NWHILE:
7629         case NUNTIL:
7630                 calcsize(n->nbinary.ch2);
7631                 calcsize(n->nbinary.ch1);
7632                 break;
7633         case NIF:
7634                 calcsize(n->nif.elsepart);
7635                 calcsize(n->nif.ifpart);
7636                 calcsize(n->nif.test);
7637                 break;
7638         case NFOR:
7639                 funcstringsize += strlen(n->nfor.var) + 1;
7640                 calcsize(n->nfor.body);
7641                 calcsize(n->nfor.args);
7642                 break;
7643         case NCASE:
7644                 calcsize(n->ncase.cases);
7645                 calcsize(n->ncase.expr);
7646                 break;
7647         case NCLIST:
7648                 calcsize(n->nclist.body);
7649                 calcsize(n->nclist.pattern);
7650                 calcsize(n->nclist.next);
7651                 break;
7652         case NDEFUN:
7653         case NARG:
7654                 sizenodelist(n->narg.backquote);
7655                 funcstringsize += strlen(n->narg.text) + 1;
7656                 calcsize(n->narg.next);
7657                 break;
7658         case NTO:
7659 #if ENABLE_ASH_BASH_COMPAT
7660         case NTO2:
7661 #endif
7662         case NCLOBBER:
7663         case NFROM:
7664         case NFROMTO:
7665         case NAPPEND:
7666                 calcsize(n->nfile.fname);
7667                 calcsize(n->nfile.next);
7668                 break;
7669         case NTOFD:
7670         case NFROMFD:
7671                 calcsize(n->ndup.vname);
7672                 calcsize(n->ndup.next);
7673         break;
7674         case NHERE:
7675         case NXHERE:
7676                 calcsize(n->nhere.doc);
7677                 calcsize(n->nhere.next);
7678                 break;
7679         case NNOT:
7680                 calcsize(n->nnot.com);
7681                 break;
7682         };
7683 }
7684
7685 static char *
7686 nodeckstrdup(char *s)
7687 {
7688         char *rtn = funcstring;
7689
7690         strcpy(funcstring, s);
7691         funcstring += strlen(s) + 1;
7692         return rtn;
7693 }
7694
7695 static union node *copynode(union node *);
7696
7697 static struct nodelist *
7698 copynodelist(struct nodelist *lp)
7699 {
7700         struct nodelist *start;
7701         struct nodelist **lpp;
7702
7703         lpp = &start;
7704         while (lp) {
7705                 *lpp = funcblock;
7706                 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7707                 (*lpp)->n = copynode(lp->n);
7708                 lp = lp->next;
7709                 lpp = &(*lpp)->next;
7710         }
7711         *lpp = NULL;
7712         return start;
7713 }
7714
7715 static union node *
7716 copynode(union node *n)
7717 {
7718         union node *new;
7719
7720         if (n == NULL)
7721                 return NULL;
7722         new = funcblock;
7723         funcblock = (char *) funcblock + nodesize[n->type];
7724
7725         switch (n->type) {
7726         case NCMD:
7727                 new->ncmd.redirect = copynode(n->ncmd.redirect);
7728                 new->ncmd.args = copynode(n->ncmd.args);
7729                 new->ncmd.assign = copynode(n->ncmd.assign);
7730                 break;
7731         case NPIPE:
7732                 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7733                 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
7734                 break;
7735         case NREDIR:
7736         case NBACKGND:
7737         case NSUBSHELL:
7738                 new->nredir.redirect = copynode(n->nredir.redirect);
7739                 new->nredir.n = copynode(n->nredir.n);
7740                 break;
7741         case NAND:
7742         case NOR:
7743         case NSEMI:
7744         case NWHILE:
7745         case NUNTIL:
7746                 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7747                 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7748                 break;
7749         case NIF:
7750                 new->nif.elsepart = copynode(n->nif.elsepart);
7751                 new->nif.ifpart = copynode(n->nif.ifpart);
7752                 new->nif.test = copynode(n->nif.test);
7753                 break;
7754         case NFOR:
7755                 new->nfor.var = nodeckstrdup(n->nfor.var);
7756                 new->nfor.body = copynode(n->nfor.body);
7757                 new->nfor.args = copynode(n->nfor.args);
7758                 break;
7759         case NCASE:
7760                 new->ncase.cases = copynode(n->ncase.cases);
7761                 new->ncase.expr = copynode(n->ncase.expr);
7762                 break;
7763         case NCLIST:
7764                 new->nclist.body = copynode(n->nclist.body);
7765                 new->nclist.pattern = copynode(n->nclist.pattern);
7766                 new->nclist.next = copynode(n->nclist.next);
7767                 break;
7768         case NDEFUN:
7769         case NARG:
7770                 new->narg.backquote = copynodelist(n->narg.backquote);
7771                 new->narg.text = nodeckstrdup(n->narg.text);
7772                 new->narg.next = copynode(n->narg.next);
7773                 break;
7774         case NTO:
7775 #if ENABLE_ASH_BASH_COMPAT
7776         case NTO2:
7777 #endif
7778         case NCLOBBER:
7779         case NFROM:
7780         case NFROMTO:
7781         case NAPPEND:
7782                 new->nfile.fname = copynode(n->nfile.fname);
7783                 new->nfile.fd = n->nfile.fd;
7784                 new->nfile.next = copynode(n->nfile.next);
7785                 break;
7786         case NTOFD:
7787         case NFROMFD:
7788                 new->ndup.vname = copynode(n->ndup.vname);
7789                 new->ndup.dupfd = n->ndup.dupfd;
7790                 new->ndup.fd = n->ndup.fd;
7791                 new->ndup.next = copynode(n->ndup.next);
7792                 break;
7793         case NHERE:
7794         case NXHERE:
7795                 new->nhere.doc = copynode(n->nhere.doc);
7796                 new->nhere.fd = n->nhere.fd;
7797                 new->nhere.next = copynode(n->nhere.next);
7798                 break;
7799         case NNOT:
7800                 new->nnot.com = copynode(n->nnot.com);
7801                 break;
7802         };
7803         new->type = n->type;
7804         return new;
7805 }
7806
7807 /*
7808  * Make a copy of a parse tree.
7809  */
7810 static struct funcnode *
7811 copyfunc(union node *n)
7812 {
7813         struct funcnode *f;
7814         size_t blocksize;
7815
7816         funcblocksize = offsetof(struct funcnode, n);
7817         funcstringsize = 0;
7818         calcsize(n);
7819         blocksize = funcblocksize;
7820         f = ckmalloc(blocksize + funcstringsize);
7821         funcblock = (char *) f + offsetof(struct funcnode, n);
7822         funcstring = (char *) f + blocksize;
7823         copynode(n);
7824         f->count = 0;
7825         return f;
7826 }
7827
7828 /*
7829  * Define a shell function.
7830  */
7831 static void
7832 defun(char *name, union node *func)
7833 {
7834         struct cmdentry entry;
7835
7836         INT_OFF;
7837         entry.cmdtype = CMDFUNCTION;
7838         entry.u.func = copyfunc(func);
7839         addcmdentry(name, &entry);
7840         INT_ON;
7841 }
7842
7843 static int evalskip;            /* set if we are skipping commands */
7844 /* reasons for skipping commands (see comment on breakcmd routine) */
7845 #define SKIPBREAK      (1 << 0)
7846 #define SKIPCONT       (1 << 1)
7847 #define SKIPFUNC       (1 << 2)
7848 #define SKIPFILE       (1 << 3)
7849 #define SKIPEVAL       (1 << 4)
7850 static int skipcount;           /* number of levels to skip */
7851 static int funcnest;            /* depth of function calls */
7852 static int loopnest;            /* current loop nesting level */
7853
7854 /* forward decl way out to parsing code - dotrap needs it */
7855 static int evalstring(char *s, int mask);
7856
7857 /*
7858  * Called to execute a trap.  Perhaps we should avoid entering new trap
7859  * handlers while we are executing a trap handler.
7860  */
7861 static int
7862 dotrap(void)
7863 {
7864         char *p;
7865         char *q;
7866         int i;
7867         int savestatus;
7868         int skip;
7869
7870         savestatus = exitstatus;
7871         pendingsig = 0;
7872         xbarrier();
7873
7874         for (i = 1, q = gotsig; i < NSIG; i++, q++) {
7875                 if (!*q)
7876                         continue;
7877                 *q = '\0';
7878
7879                 p = trap[i];
7880                 if (!p)
7881                         continue;
7882                 skip = evalstring(p, SKIPEVAL);
7883                 exitstatus = savestatus;
7884                 if (skip)
7885                         return skip;
7886         }
7887
7888         return 0;
7889 }
7890
7891 /* forward declarations - evaluation is fairly recursive business... */
7892 static void evalloop(union node *, int);
7893 static void evalfor(union node *, int);
7894 static void evalcase(union node *, int);
7895 static void evalsubshell(union node *, int);
7896 static void expredir(union node *);
7897 static void evalpipe(union node *, int);
7898 static void evalcommand(union node *, int);
7899 static int evalbltin(const struct builtincmd *, int, char **);
7900 static void prehash(union node *);
7901
7902 /*
7903  * Evaluate a parse tree.  The value is left in the global variable
7904  * exitstatus.
7905  */
7906 static void
7907 evaltree(union node *n, int flags)
7908 {
7909
7910         struct jmploc *volatile savehandler = exception_handler;
7911         struct jmploc jmploc;
7912         int checkexit = 0;
7913         void (*evalfn)(union node *, int);
7914         int status;
7915
7916         if (n == NULL) {
7917                 TRACE(("evaltree(NULL) called\n"));
7918                 goto out1;
7919         }
7920         TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7921                         getpid(), n, n->type, flags));
7922
7923         exception_handler = &jmploc;
7924         {
7925                 int err = setjmp(jmploc.loc);
7926                 if (err) {
7927                         /* if it was a signal, check for trap handlers */
7928                         if (exception == EXSIG)
7929                                 goto out;
7930                         /* continue on the way out */
7931                         exception_handler = savehandler;
7932                         longjmp(exception_handler->loc, err);
7933                 }
7934         }
7935
7936         switch (n->type) {
7937         default:
7938 #if DEBUG
7939                 out1fmt("Node type = %d\n", n->type);
7940                 fflush(stdout);
7941                 break;
7942 #endif
7943         case NNOT:
7944                 evaltree(n->nnot.com, EV_TESTED);
7945                 status = !exitstatus;
7946                 goto setstatus;
7947         case NREDIR:
7948                 expredir(n->nredir.redirect);
7949                 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7950                 if (!status) {
7951                         evaltree(n->nredir.n, flags & EV_TESTED);
7952                         status = exitstatus;
7953                 }
7954                 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
7955                 goto setstatus;
7956         case NCMD:
7957                 evalfn = evalcommand;
7958  checkexit:
7959                 if (eflag && !(flags & EV_TESTED))
7960                         checkexit = ~0;
7961                 goto calleval;
7962         case NFOR:
7963                 evalfn = evalfor;
7964                 goto calleval;
7965         case NWHILE:
7966         case NUNTIL:
7967                 evalfn = evalloop;
7968                 goto calleval;
7969         case NSUBSHELL:
7970         case NBACKGND:
7971                 evalfn = evalsubshell;
7972                 goto calleval;
7973         case NPIPE:
7974                 evalfn = evalpipe;
7975                 goto checkexit;
7976         case NCASE:
7977                 evalfn = evalcase;
7978                 goto calleval;
7979         case NAND:
7980         case NOR:
7981         case NSEMI: {
7982
7983 #if NAND + 1 != NOR
7984 #error NAND + 1 != NOR
7985 #endif
7986 #if NOR + 1 != NSEMI
7987 #error NOR + 1 != NSEMI
7988 #endif
7989                 unsigned is_or = n->type - NAND;
7990                 evaltree(
7991                         n->nbinary.ch1,
7992                         (flags | ((is_or >> 1) - 1)) & EV_TESTED
7993                 );
7994                 if (!exitstatus == is_or)
7995                         break;
7996                 if (!evalskip) {
7997                         n = n->nbinary.ch2;
7998  evaln:
7999                         evalfn = evaltree;
8000  calleval:
8001                         evalfn(n, flags);
8002                         break;
8003                 }
8004                 break;
8005         }
8006         case NIF:
8007                 evaltree(n->nif.test, EV_TESTED);
8008                 if (evalskip)
8009                         break;
8010                 if (exitstatus == 0) {
8011                         n = n->nif.ifpart;
8012                         goto evaln;
8013                 } else if (n->nif.elsepart) {
8014                         n = n->nif.elsepart;
8015                         goto evaln;
8016                 }
8017                 goto success;
8018         case NDEFUN:
8019                 defun(n->narg.text, n->narg.next);
8020  success:
8021                 status = 0;
8022  setstatus:
8023                 exitstatus = status;
8024                 break;
8025         }
8026
8027  out:
8028         exception_handler = savehandler;
8029  out1:
8030         if (checkexit & exitstatus)
8031                 evalskip |= SKIPEVAL;
8032         else if (pendingsig && dotrap())
8033                 goto exexit;
8034
8035         if (flags & EV_EXIT) {
8036  exexit:
8037                 raise_exception(EXEXIT);
8038         }
8039 }
8040
8041 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8042 static
8043 #endif
8044 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8045
8046 static void
8047 evalloop(union node *n, int flags)
8048 {
8049         int status;
8050
8051         loopnest++;
8052         status = 0;
8053         flags &= EV_TESTED;
8054         for (;;) {
8055                 int i;
8056
8057                 evaltree(n->nbinary.ch1, EV_TESTED);
8058                 if (evalskip) {
8059  skipping:
8060                         if (evalskip == SKIPCONT && --skipcount <= 0) {
8061                                 evalskip = 0;
8062                                 continue;
8063                         }
8064                         if (evalskip == SKIPBREAK && --skipcount <= 0)
8065                                 evalskip = 0;
8066                         break;
8067                 }
8068                 i = exitstatus;
8069                 if (n->type != NWHILE)
8070                         i = !i;
8071                 if (i != 0)
8072                         break;
8073                 evaltree(n->nbinary.ch2, flags);
8074                 status = exitstatus;
8075                 if (evalskip)
8076                         goto skipping;
8077         }
8078         loopnest--;
8079         exitstatus = status;
8080 }
8081
8082 static void
8083 evalfor(union node *n, int flags)
8084 {
8085         struct arglist arglist;
8086         union node *argp;
8087         struct strlist *sp;
8088         struct stackmark smark;
8089
8090         setstackmark(&smark);
8091         arglist.list = NULL;
8092         arglist.lastp = &arglist.list;
8093         for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8094                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8095                 /* XXX */
8096                 if (evalskip)
8097                         goto out;
8098         }
8099         *arglist.lastp = NULL;
8100
8101         exitstatus = 0;
8102         loopnest++;
8103         flags &= EV_TESTED;
8104         for (sp = arglist.list; sp; sp = sp->next) {
8105                 setvar(n->nfor.var, sp->text, 0);
8106                 evaltree(n->nfor.body, flags);
8107                 if (evalskip) {
8108                         if (evalskip == SKIPCONT && --skipcount <= 0) {
8109                                 evalskip = 0;
8110                                 continue;
8111                         }
8112                         if (evalskip == SKIPBREAK && --skipcount <= 0)
8113                                 evalskip = 0;
8114                         break;
8115                 }
8116         }
8117         loopnest--;
8118  out:
8119         popstackmark(&smark);
8120 }
8121
8122 static void
8123 evalcase(union node *n, int flags)
8124 {
8125         union node *cp;
8126         union node *patp;
8127         struct arglist arglist;
8128         struct stackmark smark;
8129
8130         setstackmark(&smark);
8131         arglist.list = NULL;
8132         arglist.lastp = &arglist.list;
8133         expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8134         exitstatus = 0;
8135         for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8136                 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8137                         if (casematch(patp, arglist.list->text)) {
8138                                 if (evalskip == 0) {
8139                                         evaltree(cp->nclist.body, flags);
8140                                 }
8141                                 goto out;
8142                         }
8143                 }
8144         }
8145  out:
8146         popstackmark(&smark);
8147 }
8148
8149 /*
8150  * Kick off a subshell to evaluate a tree.
8151  */
8152 static void
8153 evalsubshell(union node *n, int flags)
8154 {
8155         struct job *jp;
8156         int backgnd = (n->type == NBACKGND);
8157         int status;
8158
8159         expredir(n->nredir.redirect);
8160         if (!backgnd && flags & EV_EXIT && !trap[0])
8161                 goto nofork;
8162         INT_OFF;
8163         jp = makejob(/*n,*/ 1);
8164         if (forkshell(jp, n, backgnd) == 0) {
8165                 INT_ON;
8166                 flags |= EV_EXIT;
8167                 if (backgnd)
8168                         flags &=~ EV_TESTED;
8169  nofork:
8170                 redirect(n->nredir.redirect, 0);
8171                 evaltreenr(n->nredir.n, flags);
8172                 /* never returns */
8173         }
8174         status = 0;
8175         if (!backgnd)
8176                 status = waitforjob(jp);
8177         exitstatus = status;
8178         INT_ON;
8179 }
8180
8181 /*
8182  * Compute the names of the files in a redirection list.
8183  */
8184 static void fixredir(union node *, const char *, int);
8185 static void
8186 expredir(union node *n)
8187 {
8188         union node *redir;
8189
8190         for (redir = n; redir; redir = redir->nfile.next) {
8191                 struct arglist fn;
8192
8193                 fn.list = NULL;
8194                 fn.lastp = &fn.list;
8195                 switch (redir->type) {
8196                 case NFROMTO:
8197                 case NFROM:
8198                 case NTO:
8199 #if ENABLE_ASH_BASH_COMPAT
8200                 case NTO2:
8201 #endif
8202                 case NCLOBBER:
8203                 case NAPPEND:
8204                         expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8205 #if ENABLE_ASH_BASH_COMPAT
8206  store_expfname:
8207 #endif
8208                         redir->nfile.expfname = fn.list->text;
8209                         break;
8210                 case NFROMFD:
8211                 case NTOFD: /* >& */
8212                         if (redir->ndup.vname) {
8213                                 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8214                                 if (fn.list == NULL)
8215                                         ash_msg_and_raise_error("redir error");
8216 #if ENABLE_ASH_BASH_COMPAT
8217 //FIXME: we used expandarg with different args!
8218                                 if (!isdigit_str9(fn.list->text)) {
8219                                         /* >&file, not >&fd */
8220                                         if (redir->nfile.fd != 1) /* 123>&file - BAD */
8221                                                 ash_msg_and_raise_error("redir error");
8222                                         redir->type = NTO2;
8223                                         goto store_expfname;
8224                                 }
8225 #endif
8226                                 fixredir(redir, fn.list->text, 1);
8227                         }
8228                         break;
8229                 }
8230         }
8231 }
8232
8233 /*
8234  * Evaluate a pipeline.  All the processes in the pipeline are children
8235  * of the process creating the pipeline.  (This differs from some versions
8236  * of the shell, which make the last process in a pipeline the parent
8237  * of all the rest.)
8238  */
8239 static void
8240 evalpipe(union node *n, int flags)
8241 {
8242         struct job *jp;
8243         struct nodelist *lp;
8244         int pipelen;
8245         int prevfd;
8246         int pip[2];
8247
8248         TRACE(("evalpipe(0x%lx) called\n", (long)n));
8249         pipelen = 0;
8250         for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8251                 pipelen++;
8252         flags |= EV_EXIT;
8253         INT_OFF;
8254         jp = makejob(/*n,*/ pipelen);
8255         prevfd = -1;
8256         for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8257                 prehash(lp->n);
8258                 pip[1] = -1;
8259                 if (lp->next) {
8260                         if (pipe(pip) < 0) {
8261                                 close(prevfd);
8262                                 ash_msg_and_raise_error("pipe call failed");
8263                         }
8264                 }
8265                 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8266                         INT_ON;
8267                         if (pip[1] >= 0) {
8268                                 close(pip[0]);
8269                         }
8270                         if (prevfd > 0) {
8271                                 dup2(prevfd, 0);
8272                                 close(prevfd);
8273                         }
8274                         if (pip[1] > 1) {
8275                                 dup2(pip[1], 1);
8276                                 close(pip[1]);
8277                         }
8278                         evaltreenr(lp->n, flags);
8279                         /* never returns */
8280                 }
8281                 if (prevfd >= 0)
8282                         close(prevfd);
8283                 prevfd = pip[0];
8284                 close(pip[1]);
8285         }
8286         if (n->npipe.pipe_backgnd == 0) {
8287                 exitstatus = waitforjob(jp);
8288                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
8289         }
8290         INT_ON;
8291 }
8292
8293 /*
8294  * Controls whether the shell is interactive or not.
8295  */
8296 static void
8297 setinteractive(int on)
8298 {
8299         static smallint is_interactive;
8300
8301         if (++on == is_interactive)
8302                 return;
8303         is_interactive = on;
8304         setsignal(SIGINT);
8305         setsignal(SIGQUIT);
8306         setsignal(SIGTERM);
8307 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8308         if (is_interactive > 1) {
8309                 /* Looks like they want an interactive shell */
8310                 static smallint did_banner;
8311
8312                 if (!did_banner) {
8313                         out1fmt(
8314                                 "\n\n"
8315                                 "%s built-in shell (ash)\n"
8316                                 "Enter 'help' for a list of built-in commands."
8317                                 "\n\n",
8318                                 bb_banner);
8319                         did_banner = 1;
8320                 }
8321         }
8322 #endif
8323 }
8324
8325 static void
8326 optschanged(void)
8327 {
8328 #if DEBUG
8329         opentrace();
8330 #endif
8331         setinteractive(iflag);
8332         setjobctl(mflag);
8333 #if ENABLE_FEATURE_EDITING_VI
8334         if (viflag)
8335                 line_input_state->flags |= VI_MODE;
8336         else
8337                 line_input_state->flags &= ~VI_MODE;
8338 #else
8339         viflag = 0; /* forcibly keep the option off */
8340 #endif
8341 }
8342
8343 static struct localvar *localvars;
8344
8345 /*
8346  * Called after a function returns.
8347  * Interrupts must be off.
8348  */
8349 static void
8350 poplocalvars(void)
8351 {
8352         struct localvar *lvp;
8353         struct var *vp;
8354
8355         while ((lvp = localvars) != NULL) {
8356                 localvars = lvp->next;
8357                 vp = lvp->vp;
8358                 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8359                 if (vp == NULL) {       /* $- saved */
8360                         memcpy(optlist, lvp->text, sizeof(optlist));
8361                         free((char*)lvp->text);
8362                         optschanged();
8363                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8364                         unsetvar(vp->text);
8365                 } else {
8366                         if (vp->func)
8367                                 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8368                         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8369                                 free((char*)vp->text);
8370                         vp->flags = lvp->flags;
8371                         vp->text = lvp->text;
8372                 }
8373                 free(lvp);
8374         }
8375 }
8376
8377 static int
8378 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8379 {
8380         volatile struct shparam saveparam;
8381         struct localvar *volatile savelocalvars;
8382         struct jmploc *volatile savehandler;
8383         struct jmploc jmploc;
8384         int e;
8385
8386         saveparam = shellparam;
8387         savelocalvars = localvars;
8388         e = setjmp(jmploc.loc);
8389         if (e) {
8390                 goto funcdone;
8391         }
8392         INT_OFF;
8393         savehandler = exception_handler;
8394         exception_handler = &jmploc;
8395         localvars = NULL;
8396         shellparam.malloced = 0;
8397         func->count++;
8398         funcnest++;
8399         INT_ON;
8400         shellparam.nparam = argc - 1;
8401         shellparam.p = argv + 1;
8402 #if ENABLE_ASH_GETOPTS
8403         shellparam.optind = 1;
8404         shellparam.optoff = -1;
8405 #endif
8406         evaltree(&func->n, flags & EV_TESTED);
8407  funcdone:
8408         INT_OFF;
8409         funcnest--;
8410         freefunc(func);
8411         poplocalvars();
8412         localvars = savelocalvars;
8413         freeparam(&shellparam);
8414         shellparam = saveparam;
8415         exception_handler = savehandler;
8416         INT_ON;
8417         evalskip &= ~SKIPFUNC;
8418         return e;
8419 }
8420
8421 #if ENABLE_ASH_CMDCMD
8422 static char **
8423 parse_command_args(char **argv, const char **path)
8424 {
8425         char *cp, c;
8426
8427         for (;;) {
8428                 cp = *++argv;
8429                 if (!cp)
8430                         return 0;
8431                 if (*cp++ != '-')
8432                         break;
8433                 c = *cp++;
8434                 if (!c)
8435                         break;
8436                 if (c == '-' && !*cp) {
8437                         argv++;
8438                         break;
8439                 }
8440                 do {
8441                         switch (c) {
8442                         case 'p':
8443                                 *path = bb_default_path;
8444                                 break;
8445                         default:
8446                                 /* run 'typecmd' for other options */
8447                                 return 0;
8448                         }
8449                         c = *cp++;
8450                 } while (c);
8451         }
8452         return argv;
8453 }
8454 #endif
8455
8456 /*
8457  * Make a variable a local variable.  When a variable is made local, it's
8458  * value and flags are saved in a localvar structure.  The saved values
8459  * will be restored when the shell function returns.  We handle the name
8460  * "-" as a special case.
8461  */
8462 static void
8463 mklocal(char *name)
8464 {
8465         struct localvar *lvp;
8466         struct var **vpp;
8467         struct var *vp;
8468
8469         INT_OFF;
8470         lvp = ckzalloc(sizeof(struct localvar));
8471         if (LONE_DASH(name)) {
8472                 char *p;
8473                 p = ckmalloc(sizeof(optlist));
8474                 lvp->text = memcpy(p, optlist, sizeof(optlist));
8475                 vp = NULL;
8476         } else {
8477                 char *eq;
8478
8479                 vpp = hashvar(name);
8480                 vp = *findvar(vpp, name);
8481                 eq = strchr(name, '=');
8482                 if (vp == NULL) {
8483                         if (eq)
8484                                 setvareq(name, VSTRFIXED);
8485                         else
8486                                 setvar(name, NULL, VSTRFIXED);
8487                         vp = *vpp;      /* the new variable */
8488                         lvp->flags = VUNSET;
8489                 } else {
8490                         lvp->text = vp->text;
8491                         lvp->flags = vp->flags;
8492                         vp->flags |= VSTRFIXED|VTEXTFIXED;
8493                         if (eq)
8494                                 setvareq(name, 0);
8495                 }
8496         }
8497         lvp->vp = vp;
8498         lvp->next = localvars;
8499         localvars = lvp;
8500         INT_ON;
8501 }
8502
8503 /*
8504  * The "local" command.
8505  */
8506 static int
8507 localcmd(int argc UNUSED_PARAM, char **argv)
8508 {
8509         char *name;
8510
8511         argv = argptr;
8512         while ((name = *argv++) != NULL) {
8513                 mklocal(name);
8514         }
8515         return 0;
8516 }
8517
8518 static int
8519 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8520 {
8521         return 1;
8522 }
8523
8524 static int
8525 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8526 {
8527         return 0;
8528 }
8529
8530 static int
8531 execcmd(int argc UNUSED_PARAM, char **argv)
8532 {
8533         if (argv[1]) {
8534                 iflag = 0;              /* exit on error */
8535                 mflag = 0;
8536                 optschanged();
8537                 shellexec(argv + 1, pathval(), 0);
8538         }
8539         return 0;
8540 }
8541
8542 /*
8543  * The return command.
8544  */
8545 static int
8546 returncmd(int argc UNUSED_PARAM, char **argv)
8547 {
8548         /*
8549          * If called outside a function, do what ksh does;
8550          * skip the rest of the file.
8551          */
8552         evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8553         return argv[1] ? number(argv[1]) : exitstatus;
8554 }
8555
8556 /* Forward declarations for builtintab[] */
8557 static int breakcmd(int, char **);
8558 static int dotcmd(int, char **);
8559 static int evalcmd(int, char **);
8560 static int exitcmd(int, char **);
8561 static int exportcmd(int, char **);
8562 #if ENABLE_ASH_GETOPTS
8563 static int getoptscmd(int, char **);
8564 #endif
8565 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8566 static int helpcmd(int, char **);
8567 #endif
8568 #if ENABLE_ASH_MATH_SUPPORT
8569 static int letcmd(int, char **);
8570 #endif
8571 static int readcmd(int, char **);
8572 static int setcmd(int, char **);
8573 static int shiftcmd(int, char **);
8574 static int timescmd(int, char **);
8575 static int trapcmd(int, char **);
8576 static int umaskcmd(int, char **);
8577 static int unsetcmd(int, char **);
8578 static int ulimitcmd(int, char **);
8579
8580 #define BUILTIN_NOSPEC          "0"
8581 #define BUILTIN_SPECIAL         "1"
8582 #define BUILTIN_REGULAR         "2"
8583 #define BUILTIN_SPEC_REG        "3"
8584 #define BUILTIN_ASSIGN          "4"
8585 #define BUILTIN_SPEC_ASSG       "5"
8586 #define BUILTIN_REG_ASSG        "6"
8587 #define BUILTIN_SPEC_REG_ASSG   "7"
8588
8589 /* We do not handle [[ expr ]] bashism bash-compatibly,
8590  * we make it a synonym of [ expr ].
8591  * Basically, word splitting and pathname expansion should NOT be performed
8592  * Examples:
8593  * no word splitting:     a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8594  * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8595  * Additional operators:
8596  * || and && should work as -o and -a
8597  * =~ regexp match
8598  * Apart from the above, [[ expr ]] should work as [ expr ]
8599  */
8600
8601 #define echocmd   echo_main
8602 #define printfcmd printf_main
8603 #define testcmd   test_main
8604
8605 /* Keep these in proper order since it is searched via bsearch() */
8606 static const struct builtincmd builtintab[] = {
8607         { BUILTIN_SPEC_REG      ".", dotcmd },
8608         { BUILTIN_SPEC_REG      ":", truecmd },
8609 #if ENABLE_ASH_BUILTIN_TEST
8610         { BUILTIN_REGULAR       "[", testcmd },
8611 #if ENABLE_ASH_BASH_COMPAT
8612         { BUILTIN_REGULAR       "[[", testcmd },
8613 #endif
8614 #endif
8615 #if ENABLE_ASH_ALIAS
8616         { BUILTIN_REG_ASSG      "alias", aliascmd },
8617 #endif
8618 #if JOBS
8619         { BUILTIN_REGULAR       "bg", fg_bgcmd },
8620 #endif
8621         { BUILTIN_SPEC_REG      "break", breakcmd },
8622         { BUILTIN_REGULAR       "cd", cdcmd },
8623         { BUILTIN_NOSPEC        "chdir", cdcmd },
8624 #if ENABLE_ASH_CMDCMD
8625         { BUILTIN_REGULAR       "command", commandcmd },
8626 #endif
8627         { BUILTIN_SPEC_REG      "continue", breakcmd },
8628 #if ENABLE_ASH_BUILTIN_ECHO
8629         { BUILTIN_REGULAR       "echo", echocmd },
8630 #endif
8631         { BUILTIN_SPEC_REG      "eval", evalcmd },
8632         { BUILTIN_SPEC_REG      "exec", execcmd },
8633         { BUILTIN_SPEC_REG      "exit", exitcmd },
8634         { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8635         { BUILTIN_REGULAR       "false", falsecmd },
8636 #if JOBS
8637         { BUILTIN_REGULAR       "fg", fg_bgcmd },
8638 #endif
8639 #if ENABLE_ASH_GETOPTS
8640         { BUILTIN_REGULAR       "getopts", getoptscmd },
8641 #endif
8642         { BUILTIN_NOSPEC        "hash", hashcmd },
8643 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8644         { BUILTIN_NOSPEC        "help", helpcmd },
8645 #endif
8646 #if JOBS
8647         { BUILTIN_REGULAR       "jobs", jobscmd },
8648         { BUILTIN_REGULAR       "kill", killcmd },
8649 #endif
8650 #if ENABLE_ASH_MATH_SUPPORT
8651         { BUILTIN_NOSPEC        "let", letcmd },
8652 #endif
8653         { BUILTIN_ASSIGN        "local", localcmd },
8654 #if ENABLE_ASH_BUILTIN_PRINTF
8655         { BUILTIN_REGULAR       "printf", printfcmd },
8656 #endif
8657         { BUILTIN_NOSPEC        "pwd", pwdcmd },
8658         { BUILTIN_REGULAR       "read", readcmd },
8659         { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8660         { BUILTIN_SPEC_REG      "return", returncmd },
8661         { BUILTIN_SPEC_REG      "set", setcmd },
8662         { BUILTIN_SPEC_REG      "shift", shiftcmd },
8663         { BUILTIN_SPEC_REG      "source", dotcmd },
8664 #if ENABLE_ASH_BUILTIN_TEST
8665         { BUILTIN_REGULAR       "test", testcmd },
8666 #endif
8667         { BUILTIN_SPEC_REG      "times", timescmd },
8668         { BUILTIN_SPEC_REG      "trap", trapcmd },
8669         { BUILTIN_REGULAR       "true", truecmd },
8670         { BUILTIN_NOSPEC        "type", typecmd },
8671         { BUILTIN_NOSPEC        "ulimit", ulimitcmd },
8672         { BUILTIN_REGULAR       "umask", umaskcmd },
8673 #if ENABLE_ASH_ALIAS
8674         { BUILTIN_REGULAR       "unalias", unaliascmd },
8675 #endif
8676         { BUILTIN_SPEC_REG      "unset", unsetcmd },
8677         { BUILTIN_REGULAR       "wait", waitcmd },
8678 };
8679
8680 /* Should match the above table! */
8681 #define COMMANDCMD (builtintab + \
8682         2 + \
8683         1 * ENABLE_ASH_BUILTIN_TEST + \
8684         1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8685         1 * ENABLE_ASH_ALIAS + \
8686         1 * ENABLE_ASH_JOB_CONTROL + \
8687         3)
8688 #define EXECCMD (builtintab + \
8689         2 + \
8690         1 * ENABLE_ASH_BUILTIN_TEST + \
8691         1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8692         1 * ENABLE_ASH_ALIAS + \
8693         1 * ENABLE_ASH_JOB_CONTROL + \
8694         3 + \
8695         1 * ENABLE_ASH_CMDCMD + \
8696         1 + \
8697         ENABLE_ASH_BUILTIN_ECHO + \
8698         1)
8699
8700 /*
8701  * Search the table of builtin commands.
8702  */
8703 static struct builtincmd *
8704 find_builtin(const char *name)
8705 {
8706         struct builtincmd *bp;
8707
8708         bp = bsearch(
8709                 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8710                 pstrcmp
8711         );
8712         return bp;
8713 }
8714
8715 /*
8716  * Execute a simple command.
8717  */
8718 static int
8719 isassignment(const char *p)
8720 {
8721         const char *q = endofname(p);
8722         if (p == q)
8723                 return 0;
8724         return *q == '=';
8725 }
8726 static int
8727 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8728 {
8729         /* Preserve exitstatus of a previous possible redirection
8730          * as POSIX mandates */
8731         return back_exitstatus;
8732 }
8733 static void
8734 evalcommand(union node *cmd, int flags)
8735 {
8736         static const struct builtincmd null_bltin = {
8737                 "\0\0", bltincmd /* why three NULs? */
8738         };
8739         struct stackmark smark;
8740         union node *argp;
8741         struct arglist arglist;
8742         struct arglist varlist;
8743         char **argv;
8744         int argc;
8745         const struct strlist *sp;
8746         struct cmdentry cmdentry;
8747         struct job *jp;
8748         char *lastarg;
8749         const char *path;
8750         int spclbltin;
8751         int status;
8752         char **nargv;
8753         struct builtincmd *bcmd;
8754         smallint cmd_is_exec;
8755         smallint pseudovarflag = 0;
8756
8757         /* First expand the arguments. */
8758         TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8759         setstackmark(&smark);
8760         back_exitstatus = 0;
8761
8762         cmdentry.cmdtype = CMDBUILTIN;
8763         cmdentry.u.cmd = &null_bltin;
8764         varlist.lastp = &varlist.list;
8765         *varlist.lastp = NULL;
8766         arglist.lastp = &arglist.list;
8767         *arglist.lastp = NULL;
8768
8769         argc = 0;
8770         if (cmd->ncmd.args) {
8771                 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8772                 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8773         }
8774
8775         for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8776                 struct strlist **spp;
8777
8778                 spp = arglist.lastp;
8779                 if (pseudovarflag && isassignment(argp->narg.text))
8780                         expandarg(argp, &arglist, EXP_VARTILDE);
8781                 else
8782                         expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8783
8784                 for (sp = *spp; sp; sp = sp->next)
8785                         argc++;
8786         }
8787
8788         argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8789         for (sp = arglist.list; sp; sp = sp->next) {
8790                 TRACE(("evalcommand arg: %s\n", sp->text));
8791                 *nargv++ = sp->text;
8792         }
8793         *nargv = NULL;
8794
8795         lastarg = NULL;
8796         if (iflag && funcnest == 0 && argc > 0)
8797                 lastarg = nargv[-1];
8798
8799         preverrout_fd = 2;
8800         expredir(cmd->ncmd.redirect);
8801         status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8802
8803         path = vpath.text;
8804         for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8805                 struct strlist **spp;
8806                 char *p;
8807
8808                 spp = varlist.lastp;
8809                 expandarg(argp, &varlist, EXP_VARTILDE);
8810
8811                 /*
8812                  * Modify the command lookup path, if a PATH= assignment
8813                  * is present
8814                  */
8815                 p = (*spp)->text;
8816                 if (varequal(p, path))
8817                         path = p;
8818         }
8819
8820         /* Print the command if xflag is set. */
8821         if (xflag) {
8822                 int n;
8823                 const char *p = " %s";
8824
8825                 p++;
8826                 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8827
8828                 sp = varlist.list;
8829                 for (n = 0; n < 2; n++) {
8830                         while (sp) {
8831                                 fdprintf(preverrout_fd, p, sp->text);
8832                                 sp = sp->next;
8833                                 if (*p == '%') {
8834                                         p--;
8835                                 }
8836                         }
8837                         sp = arglist.list;
8838                 }
8839                 safe_write(preverrout_fd, "\n", 1);
8840         }
8841
8842         cmd_is_exec = 0;
8843         spclbltin = -1;
8844
8845         /* Now locate the command. */
8846         if (argc) {
8847                 const char *oldpath;
8848                 int cmd_flag = DO_ERR;
8849
8850                 path += 5;
8851                 oldpath = path;
8852                 for (;;) {
8853                         find_command(argv[0], &cmdentry, cmd_flag, path);
8854                         if (cmdentry.cmdtype == CMDUNKNOWN) {
8855                                 flush_stderr();
8856                                 status = 127;
8857                                 goto bail;
8858                         }
8859
8860                         /* implement bltin and command here */
8861                         if (cmdentry.cmdtype != CMDBUILTIN)
8862                                 break;
8863                         if (spclbltin < 0)
8864                                 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8865                         if (cmdentry.u.cmd == EXECCMD)
8866                                 cmd_is_exec = 1;
8867 #if ENABLE_ASH_CMDCMD
8868                         if (cmdentry.u.cmd == COMMANDCMD) {
8869                                 path = oldpath;
8870                                 nargv = parse_command_args(argv, &path);
8871                                 if (!nargv)
8872                                         break;
8873                                 argc -= nargv - argv;
8874                                 argv = nargv;
8875                                 cmd_flag |= DO_NOFUNC;
8876                         } else
8877 #endif
8878                                 break;
8879                 }
8880         }
8881
8882         if (status) {
8883                 /* We have a redirection error. */
8884                 if (spclbltin > 0)
8885                         raise_exception(EXERROR);
8886  bail:
8887                 exitstatus = status;
8888                 goto out;
8889         }
8890
8891         /* Execute the command. */
8892         switch (cmdentry.cmdtype) {
8893         default:
8894
8895 #if ENABLE_FEATURE_SH_NOFORK
8896 /* Hmmm... shouldn't it happen somewhere in forkshell() instead?
8897  * Why "fork off a child process if necessary" doesn't apply to NOFORK? */
8898         {
8899                 /* find_command() encodes applet_no as (-2 - applet_no) */
8900                 int applet_no = (- cmdentry.u.index - 2);
8901                 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
8902                         listsetvar(varlist.list, VEXPORT|VSTACK);
8903                         /* run <applet>_main() */
8904                         exitstatus = run_nofork_applet(applet_no, argv);
8905                         break;
8906                 }
8907         }
8908 #endif
8909                 /* Fork off a child process if necessary. */
8910                 if (!(flags & EV_EXIT) || trap[0]) {
8911                         INT_OFF;
8912                         jp = makejob(/*cmd,*/ 1);
8913                         if (forkshell(jp, cmd, FORK_FG) != 0) {
8914                                 exitstatus = waitforjob(jp);
8915                                 INT_ON;
8916                                 break;
8917                         }
8918                         FORCE_INT_ON;
8919                 }
8920                 listsetvar(varlist.list, VEXPORT|VSTACK);
8921                 shellexec(argv, path, cmdentry.u.index);
8922                 /* NOTREACHED */
8923
8924         case CMDBUILTIN:
8925                 cmdenviron = varlist.list;
8926                 if (cmdenviron) {
8927                         struct strlist *list = cmdenviron;
8928                         int i = VNOSET;
8929                         if (spclbltin > 0 || argc == 0) {
8930                                 i = 0;
8931                                 if (cmd_is_exec && argc > 1)
8932                                         i = VEXPORT;
8933                         }
8934                         listsetvar(list, i);
8935                 }
8936                 /* Tight loop with builtins only:
8937                  * "while kill -0 $child; do true; done"
8938                  * will never exit even if $child died, unless we do this
8939                  * to reap the zombie and make kill detect that it's gone: */
8940                 dowait(DOWAIT_NONBLOCK, NULL);
8941
8942                 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8943                         int exit_status;
8944                         int i = exception;
8945                         if (i == EXEXIT)
8946                                 goto raise;
8947                         exit_status = 2;
8948                         if (i == EXINT)
8949                                 exit_status = 128 + SIGINT;
8950                         if (i == EXSIG)
8951                                 exit_status = 128 + pendingsig;
8952                         exitstatus = exit_status;
8953                         if (i == EXINT || spclbltin > 0) {
8954  raise:
8955                                 longjmp(exception_handler->loc, 1);
8956                         }
8957                         FORCE_INT_ON;
8958                 }
8959                 break;
8960
8961         case CMDFUNCTION:
8962                 listsetvar(varlist.list, 0);
8963                 /* See above for the rationale */
8964                 dowait(DOWAIT_NONBLOCK, NULL);
8965                 if (evalfun(cmdentry.u.func, argc, argv, flags))
8966                         goto raise;
8967                 break;
8968         }
8969
8970  out:
8971         popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
8972         if (lastarg) {
8973                 /* dsl: I think this is intended to be used to support
8974                  * '_' in 'vi' command mode during line editing...
8975                  * However I implemented that within libedit itself.
8976                  */
8977                 setvar("_", lastarg, 0);
8978         }
8979         popstackmark(&smark);
8980 }
8981
8982 static int
8983 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8984 {
8985         char *volatile savecmdname;
8986         struct jmploc *volatile savehandler;
8987         struct jmploc jmploc;
8988         int i;
8989
8990         savecmdname = commandname;
8991         i = setjmp(jmploc.loc);
8992         if (i)
8993                 goto cmddone;
8994         savehandler = exception_handler;
8995         exception_handler = &jmploc;
8996         commandname = argv[0];
8997         argptr = argv + 1;
8998         optptr = NULL;                  /* initialize nextopt */
8999         exitstatus = (*cmd->builtin)(argc, argv);
9000         flush_stdout_stderr();
9001  cmddone:
9002         exitstatus |= ferror(stdout);
9003         clearerr(stdout);
9004         commandname = savecmdname;
9005 //      exsig = 0;
9006         exception_handler = savehandler;
9007
9008         return i;
9009 }
9010
9011 static int
9012 goodname(const char *p)
9013 {
9014         return !*endofname(p);
9015 }
9016
9017
9018 /*
9019  * Search for a command.  This is called before we fork so that the
9020  * location of the command will be available in the parent as well as
9021  * the child.  The check for "goodname" is an overly conservative
9022  * check that the name will not be subject to expansion.
9023  */
9024 static void
9025 prehash(union node *n)
9026 {
9027         struct cmdentry entry;
9028
9029         if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9030                 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9031 }
9032
9033
9034 /* ============ Builtin commands
9035  *
9036  * Builtin commands whose functions are closely tied to evaluation
9037  * are implemented here.
9038  */
9039
9040 /*
9041  * Handle break and continue commands.  Break, continue, and return are
9042  * all handled by setting the evalskip flag.  The evaluation routines
9043  * above all check this flag, and if it is set they start skipping
9044  * commands rather than executing them.  The variable skipcount is
9045  * the number of loops to break/continue, or the number of function
9046  * levels to return.  (The latter is always 1.)  It should probably
9047  * be an error to break out of more loops than exist, but it isn't
9048  * in the standard shell so we don't make it one here.
9049  */
9050 static int
9051 breakcmd(int argc UNUSED_PARAM, char **argv)
9052 {
9053         int n = argv[1] ? number(argv[1]) : 1;
9054
9055         if (n <= 0)
9056                 ash_msg_and_raise_error(illnum, argv[1]);
9057         if (n > loopnest)
9058                 n = loopnest;
9059         if (n > 0) {
9060                 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9061                 skipcount = n;
9062         }
9063         return 0;
9064 }
9065
9066
9067 /* ============ input.c
9068  *
9069  * This implements the input routines used by the parser.
9070  */
9071
9072 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
9073
9074 enum {
9075         INPUT_PUSH_FILE = 1,
9076         INPUT_NOFILE_OK = 2,
9077 };
9078
9079 static int plinno = 1;                  /* input line number */
9080 /* number of characters left in input buffer */
9081 static int parsenleft;                  /* copy of parsefile->nleft */
9082 static int parselleft;                  /* copy of parsefile->lleft */
9083 /* next character in input buffer */
9084 static char *parsenextc;                /* copy of parsefile->nextc */
9085
9086 static smallint checkkwd;
9087 /* values of checkkwd variable */
9088 #define CHKALIAS        0x1
9089 #define CHKKWD          0x2
9090 #define CHKNL           0x4
9091
9092 static void
9093 popstring(void)
9094 {
9095         struct strpush *sp = g_parsefile->strpush;
9096
9097         INT_OFF;
9098 #if ENABLE_ASH_ALIAS
9099         if (sp->ap) {
9100                 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
9101                         checkkwd |= CHKALIAS;
9102                 }
9103                 if (sp->string != sp->ap->val) {
9104                         free(sp->string);
9105                 }
9106                 sp->ap->flag &= ~ALIASINUSE;
9107                 if (sp->ap->flag & ALIASDEAD) {
9108                         unalias(sp->ap->name);
9109                 }
9110         }
9111 #endif
9112         parsenextc = sp->prevstring;
9113         parsenleft = sp->prevnleft;
9114 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
9115         g_parsefile->strpush = sp->prev;
9116         if (sp != &(g_parsefile->basestrpush))
9117                 free(sp);
9118         INT_ON;
9119 }
9120
9121 static int
9122 preadfd(void)
9123 {
9124         int nr;
9125         char *buf = g_parsefile->buf;
9126         parsenextc = buf;
9127
9128 #if ENABLE_FEATURE_EDITING
9129  retry:
9130         if (!iflag || g_parsefile->fd)
9131                 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9132         else {
9133 #if ENABLE_FEATURE_TAB_COMPLETION
9134                 line_input_state->path_lookup = pathval();
9135 #endif
9136                 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
9137                 if (nr == 0) {
9138                         /* Ctrl+C pressed */
9139                         if (trap[SIGINT]) {
9140                                 buf[0] = '\n';
9141                                 buf[1] = '\0';
9142                                 raise(SIGINT);
9143                                 return 1;
9144                         }
9145                         goto retry;
9146                 }
9147                 if (nr < 0 && errno == 0) {
9148                         /* Ctrl+D pressed */
9149                         nr = 0;
9150                 }
9151         }
9152 #else
9153         nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9154 #endif
9155
9156 #if 0
9157 /* nonblock_safe_read() handles this problem */
9158         if (nr < 0) {
9159                 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9160                         int flags = fcntl(0, F_GETFL);
9161                         if (flags >= 0 && (flags & O_NONBLOCK)) {
9162                                 flags &= ~O_NONBLOCK;
9163                                 if (fcntl(0, F_SETFL, flags) >= 0) {
9164                                         out2str("sh: turning off NDELAY mode\n");
9165                                         goto retry;
9166                                 }
9167                         }
9168                 }
9169         }
9170 #endif
9171         return nr;
9172 }
9173
9174 /*
9175  * Refill the input buffer and return the next input character:
9176  *
9177  * 1) If a string was pushed back on the input, pop it;
9178  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
9179  *    from a string so we can't refill the buffer, return EOF.
9180  * 3) If the is more stuff in this buffer, use it else call read to fill it.
9181  * 4) Process input up to the next newline, deleting nul characters.
9182  */
9183 static int
9184 preadbuffer(void)
9185 {
9186         char *q;
9187         int more;
9188         char savec;
9189
9190         while (g_parsefile->strpush) {
9191 #if ENABLE_ASH_ALIAS
9192                 if (parsenleft == -1 && g_parsefile->strpush->ap
9193                  && parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
9194                 ) {
9195                         return PEOA;
9196                 }
9197 #endif
9198                 popstring();
9199                 if (--parsenleft >= 0)
9200                         return signed_char2int(*parsenextc++);
9201         }
9202         if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL)
9203                 return PEOF;
9204         flush_stdout_stderr();
9205
9206         more = parselleft;
9207         if (more <= 0) {
9208  again:
9209                 more = preadfd();
9210                 if (more <= 0) {
9211                         parselleft = parsenleft = EOF_NLEFT;
9212                         return PEOF;
9213                 }
9214         }
9215
9216         q = parsenextc;
9217
9218         /* delete nul characters */
9219         for (;;) {
9220                 int c;
9221
9222                 more--;
9223                 c = *q;
9224
9225                 if (!c)
9226                         memmove(q, q + 1, more);
9227                 else {
9228                         q++;
9229                         if (c == '\n') {
9230                                 parsenleft = q - parsenextc - 1;
9231                                 break;
9232                         }
9233                 }
9234
9235                 if (more <= 0) {
9236                         parsenleft = q - parsenextc - 1;
9237                         if (parsenleft < 0)
9238                                 goto again;
9239                         break;
9240                 }
9241         }
9242         parselleft = more;
9243
9244         savec = *q;
9245         *q = '\0';
9246
9247         if (vflag) {
9248                 out2str(parsenextc);
9249         }
9250
9251         *q = savec;
9252
9253         return signed_char2int(*parsenextc++);
9254 }
9255
9256 #define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer())
9257 static int
9258 pgetc(void)
9259 {
9260         return pgetc_as_macro();
9261 }
9262
9263 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9264 #define pgetc_fast() pgetc()
9265 #else
9266 #define pgetc_fast() pgetc_as_macro()
9267 #endif
9268
9269 /*
9270  * Same as pgetc(), but ignores PEOA.
9271  */
9272 #if ENABLE_ASH_ALIAS
9273 static int
9274 pgetc2(void)
9275 {
9276         int c;
9277         do {
9278                 c = pgetc_fast();
9279         } while (c == PEOA);
9280         return c;
9281 }
9282 #else
9283 #define pgetc2() pgetc()
9284 #endif
9285
9286 /*
9287  * Read a line from the script.
9288  */
9289 static char *
9290 pfgets(char *line, int len)
9291 {
9292         char *p = line;
9293         int nleft = len;
9294         int c;
9295
9296         while (--nleft > 0) {
9297                 c = pgetc2();
9298                 if (c == PEOF) {
9299                         if (p == line)
9300                                 return NULL;
9301                         break;
9302                 }
9303                 *p++ = c;
9304                 if (c == '\n')
9305                         break;
9306         }
9307         *p = '\0';
9308         return line;
9309 }
9310
9311 /*
9312  * Undo the last call to pgetc.  Only one character may be pushed back.
9313  * PEOF may be pushed back.
9314  */
9315 static void
9316 pungetc(void)
9317 {
9318         /* check is needed for ash -c 'echo 5&' + BASH_COMPAT to work */
9319         if (parsenleft < 0)
9320                 return;
9321         parsenleft++;
9322         parsenextc--;
9323 }
9324
9325 /*
9326  * Push a string back onto the input at this current parsefile level.
9327  * We handle aliases this way.
9328  */
9329 #if !ENABLE_ASH_ALIAS
9330 #define pushstring(s, ap) pushstring(s)
9331 #endif
9332 static void
9333 pushstring(char *s, struct alias *ap)
9334 {
9335         struct strpush *sp;
9336         size_t len;
9337
9338         len = strlen(s);
9339         INT_OFF;
9340         if (g_parsefile->strpush) {
9341                 sp = ckzalloc(sizeof(struct strpush));
9342                 sp->prev = g_parsefile->strpush;
9343                 g_parsefile->strpush = sp;
9344         } else
9345                 sp = g_parsefile->strpush = &(g_parsefile->basestrpush);
9346         sp->prevstring = parsenextc;
9347         sp->prevnleft = parsenleft;
9348 #if ENABLE_ASH_ALIAS
9349         sp->ap = ap;
9350         if (ap) {
9351                 ap->flag |= ALIASINUSE;
9352                 sp->string = s;
9353         }
9354 #endif
9355         parsenextc = s;
9356         parsenleft = len;
9357         INT_ON;
9358 }
9359
9360 /*
9361  * To handle the "." command, a stack of input files is used.  Pushfile
9362  * adds a new entry to the stack and popfile restores the previous level.
9363  */
9364 static void
9365 pushfile(void)
9366 {
9367         struct parsefile *pf;
9368
9369         g_parsefile->nleft = parsenleft;
9370         g_parsefile->lleft = parselleft;
9371         g_parsefile->nextc = parsenextc;
9372         g_parsefile->linno = plinno;
9373         pf = ckzalloc(sizeof(*pf));
9374         pf->prev = g_parsefile;
9375         pf->fd = -1;
9376         /*pf->strpush = NULL; - ckzalloc did it */
9377         /*pf->basestrpush.prev = NULL;*/
9378         g_parsefile = pf;
9379 }
9380
9381 static void
9382 popfile(void)
9383 {
9384         struct parsefile *pf = g_parsefile;
9385
9386         INT_OFF;
9387         if (pf->fd >= 0)
9388                 close(pf->fd);
9389         free(pf->buf);
9390         while (pf->strpush)
9391                 popstring();
9392         g_parsefile = pf->prev;
9393         free(pf);
9394         parsenleft = g_parsefile->nleft;
9395         parselleft = g_parsefile->lleft;
9396         parsenextc = g_parsefile->nextc;
9397         plinno = g_parsefile->linno;
9398         INT_ON;
9399 }
9400
9401 /*
9402  * Return to top level.
9403  */
9404 static void
9405 popallfiles(void)
9406 {
9407         while (g_parsefile != &basepf)
9408                 popfile();
9409 }
9410
9411 /*
9412  * Close the file(s) that the shell is reading commands from.  Called
9413  * after a fork is done.
9414  */
9415 static void
9416 closescript(void)
9417 {
9418         popallfiles();
9419         if (g_parsefile->fd > 0) {
9420                 close(g_parsefile->fd);
9421                 g_parsefile->fd = 0;
9422         }
9423 }
9424
9425 /*
9426  * Like setinputfile, but takes an open file descriptor.  Call this with
9427  * interrupts off.
9428  */
9429 static void
9430 setinputfd(int fd, int push)
9431 {
9432         close_on_exec_on(fd);
9433         if (push) {
9434                 pushfile();
9435                 g_parsefile->buf = 0;
9436         }
9437         g_parsefile->fd = fd;
9438         if (g_parsefile->buf == NULL)
9439                 g_parsefile->buf = ckmalloc(IBUFSIZ);
9440         parselleft = parsenleft = 0;
9441         plinno = 1;
9442 }
9443
9444 /*
9445  * Set the input to take input from a file.  If push is set, push the
9446  * old input onto the stack first.
9447  */
9448 static int
9449 setinputfile(const char *fname, int flags)
9450 {
9451         int fd;
9452         int fd2;
9453
9454         INT_OFF;
9455         fd = open(fname, O_RDONLY);
9456         if (fd < 0) {
9457                 if (flags & INPUT_NOFILE_OK)
9458                         goto out;
9459                 ash_msg_and_raise_error("can't open %s", fname);
9460         }
9461         if (fd < 10) {
9462                 fd2 = copyfd(fd, 10);
9463                 close(fd);
9464                 if (fd2 < 0)
9465                         ash_msg_and_raise_error("out of file descriptors");
9466                 fd = fd2;
9467         }
9468         setinputfd(fd, flags & INPUT_PUSH_FILE);
9469  out:
9470         INT_ON;
9471         return fd;
9472 }
9473
9474 /*
9475  * Like setinputfile, but takes input from a string.
9476  */
9477 static void
9478 setinputstring(char *string)
9479 {
9480         INT_OFF;
9481         pushfile();
9482         parsenextc = string;
9483         parsenleft = strlen(string);
9484         g_parsefile->buf = NULL;
9485         plinno = 1;
9486         INT_ON;
9487 }
9488
9489
9490 /* ============ mail.c
9491  *
9492  * Routines to check for mail.
9493  */
9494
9495 #if ENABLE_ASH_MAIL
9496
9497 #define MAXMBOXES 10
9498
9499 /* times of mailboxes */
9500 static time_t mailtime[MAXMBOXES];
9501 /* Set if MAIL or MAILPATH is changed. */
9502 static smallint mail_var_path_changed;
9503
9504 /*
9505  * Print appropriate message(s) if mail has arrived.
9506  * If mail_var_path_changed is set,
9507  * then the value of MAIL has mail_var_path_changed,
9508  * so we just update the values.
9509  */
9510 static void
9511 chkmail(void)
9512 {
9513         const char *mpath;
9514         char *p;
9515         char *q;
9516         time_t *mtp;
9517         struct stackmark smark;
9518         struct stat statb;
9519
9520         setstackmark(&smark);
9521         mpath = mpathset() ? mpathval() : mailval();
9522         for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9523                 p = padvance(&mpath, nullstr);
9524                 if (p == NULL)
9525                         break;
9526                 if (*p == '\0')
9527                         continue;
9528                 for (q = p; *q; q++)
9529                         continue;
9530 #if DEBUG
9531                 if (q[-1] != '/')
9532                         abort();
9533 #endif
9534                 q[-1] = '\0';                   /* delete trailing '/' */
9535                 if (stat(p, &statb) < 0) {
9536                         *mtp = 0;
9537                         continue;
9538                 }
9539                 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9540                         fprintf(
9541                                 stderr, snlfmt,
9542                                 pathopt ? pathopt : "you have mail"
9543                         );
9544                 }
9545                 *mtp = statb.st_mtime;
9546         }
9547         mail_var_path_changed = 0;
9548         popstackmark(&smark);
9549 }
9550
9551 static void
9552 changemail(const char *val UNUSED_PARAM)
9553 {
9554         mail_var_path_changed = 1;
9555 }
9556
9557 #endif /* ASH_MAIL */
9558
9559
9560 /* ============ ??? */
9561
9562 /*
9563  * Set the shell parameters.
9564  */
9565 static void
9566 setparam(char **argv)
9567 {
9568         char **newparam;
9569         char **ap;
9570         int nparam;
9571
9572         for (nparam = 0; argv[nparam]; nparam++)
9573                 continue;
9574         ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9575         while (*argv) {
9576                 *ap++ = ckstrdup(*argv++);
9577         }
9578         *ap = NULL;
9579         freeparam(&shellparam);
9580         shellparam.malloced = 1;
9581         shellparam.nparam = nparam;
9582         shellparam.p = newparam;
9583 #if ENABLE_ASH_GETOPTS
9584         shellparam.optind = 1;
9585         shellparam.optoff = -1;
9586 #endif
9587 }
9588
9589 /*
9590  * Process shell options.  The global variable argptr contains a pointer
9591  * to the argument list; we advance it past the options.
9592  *
9593  * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9594  * For a non-interactive shell, an error condition encountered
9595  * by a special built-in ... shall cause the shell to write a diagnostic message
9596  * to standard error and exit as shown in the following table:
9597  * Error                                           Special Built-In
9598  * ...
9599  * Utility syntax error (option or operand error)  Shall exit
9600  * ...
9601  * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9602  * we see that bash does not do that (set "finishes" with error code 1 instead,
9603  * and shell continues), and people rely on this behavior!
9604  * Testcase:
9605  * set -o barfoo 2>/dev/null
9606  * echo $?
9607  *
9608  * Oh well. Let's mimic that.
9609  */
9610 static int
9611 plus_minus_o(char *name, int val)
9612 {
9613         int i;
9614
9615         if (name) {
9616                 for (i = 0; i < NOPTS; i++) {
9617                         if (strcmp(name, optnames(i)) == 0) {
9618                                 optlist[i] = val;
9619                                 return 0;
9620                         }
9621                 }
9622                 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9623                 return 1;
9624         }
9625         for (i = 0; i < NOPTS; i++) {
9626                 if (val) {
9627                         out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9628                 } else {
9629                         out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9630                 }
9631         }
9632         return 0;
9633 }
9634 static void
9635 setoption(int flag, int val)
9636 {
9637         int i;
9638
9639         for (i = 0; i < NOPTS; i++) {
9640                 if (optletters(i) == flag) {
9641                         optlist[i] = val;
9642                         return;
9643                 }
9644         }
9645         ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9646         /* NOTREACHED */
9647 }
9648 static int
9649 options(int cmdline)
9650 {
9651         char *p;
9652         int val;
9653         int c;
9654
9655         if (cmdline)
9656                 minusc = NULL;
9657         while ((p = *argptr) != NULL) {
9658                 c = *p++;
9659                 if (c != '-' && c != '+')
9660                         break;
9661                 argptr++;
9662                 val = 0; /* val = 0 if c == '+' */
9663                 if (c == '-') {
9664                         val = 1;
9665                         if (p[0] == '\0' || LONE_DASH(p)) {
9666                                 if (!cmdline) {
9667                                         /* "-" means turn off -x and -v */
9668                                         if (p[0] == '\0')
9669                                                 xflag = vflag = 0;
9670                                         /* "--" means reset params */
9671                                         else if (*argptr == NULL)
9672                                                 setparam(argptr);
9673                                 }
9674                                 break;    /* "-" or  "--" terminates options */
9675                         }
9676                 }
9677                 /* first char was + or - */
9678                 while ((c = *p++) != '\0') {
9679                         /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9680                         if (c == 'c' && cmdline) {
9681                                 minusc = p;     /* command is after shell args */
9682                         } else if (c == 'o') {
9683                                 if (plus_minus_o(*argptr, val)) {
9684                                         /* it already printed err message */
9685                                         return 1; /* error */
9686                                 }
9687                                 if (*argptr)
9688                                         argptr++;
9689                         } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9690                                 isloginsh = 1;
9691                         /* bash does not accept +-login, we also won't */
9692                         } else if (cmdline && val && (c == '-')) { /* long options */
9693                                 if (strcmp(p, "login") == 0)
9694                                         isloginsh = 1;
9695                                 break;
9696                         } else {
9697                                 setoption(c, val);
9698                         }
9699                 }
9700         }
9701         return 0;
9702 }
9703
9704 /*
9705  * The shift builtin command.
9706  */
9707 static int
9708 shiftcmd(int argc UNUSED_PARAM, char **argv)
9709 {
9710         int n;
9711         char **ap1, **ap2;
9712
9713         n = 1;
9714         if (argv[1])
9715                 n = number(argv[1]);
9716         if (n > shellparam.nparam)
9717                 n = 0; /* bash compat, was = shellparam.nparam; */
9718         INT_OFF;
9719         shellparam.nparam -= n;
9720         for (ap1 = shellparam.p; --n >= 0; ap1++) {
9721                 if (shellparam.malloced)
9722                         free(*ap1);
9723         }
9724         ap2 = shellparam.p;
9725         while ((*ap2++ = *ap1++) != NULL)
9726                 continue;
9727 #if ENABLE_ASH_GETOPTS
9728         shellparam.optind = 1;
9729         shellparam.optoff = -1;
9730 #endif
9731         INT_ON;
9732         return 0;
9733 }
9734
9735 /*
9736  * POSIX requires that 'set' (but not export or readonly) output the
9737  * variables in lexicographic order - by the locale's collating order (sigh).
9738  * Maybe we could keep them in an ordered balanced binary tree
9739  * instead of hashed lists.
9740  * For now just roll 'em through qsort for printing...
9741  */
9742 static int
9743 showvars(const char *sep_prefix, int on, int off)
9744 {
9745         const char *sep;
9746         char **ep, **epend;
9747
9748         ep = listvars(on, off, &epend);
9749         qsort(ep, epend - ep, sizeof(char *), vpcmp);
9750
9751         sep = *sep_prefix ? " " : sep_prefix;
9752
9753         for (; ep < epend; ep++) {
9754                 const char *p;
9755                 const char *q;
9756
9757                 p = strchrnul(*ep, '=');
9758                 q = nullstr;
9759                 if (*p)
9760                         q = single_quote(++p);
9761                 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9762         }
9763         return 0;
9764 }
9765
9766 /*
9767  * The set command builtin.
9768  */
9769 static int
9770 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9771 {
9772         int retval;
9773
9774         if (!argv[1])
9775                 return showvars(nullstr, 0, VUNSET);
9776         INT_OFF;
9777         retval = 1;
9778         if (!options(0)) { /* if no parse error... */
9779                 retval = 0;
9780                 optschanged();
9781                 if (*argptr != NULL) {
9782                         setparam(argptr);
9783                 }
9784         }
9785         INT_ON;
9786         return retval;
9787 }
9788
9789 #if ENABLE_ASH_RANDOM_SUPPORT
9790 static void
9791 change_random(const char *value)
9792 {
9793         /* Galois LFSR parameter */
9794         /* Taps at 32 31 29 1: */
9795         enum { MASK = 0x8000000b };
9796         /* Another example - taps at 32 31 30 10: */
9797         /* MASK = 0x00400007 */
9798
9799         if (value == NULL) {
9800                 /* "get", generate */
9801                 uint32_t t;
9802
9803                 /* LCG has period of 2^32 and alternating lowest bit */
9804                 random_LCG = 1664525 * random_LCG + 1013904223;
9805                 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9806                 t = (random_galois_LFSR << 1);
9807                 if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
9808                         t ^= MASK;
9809                 random_galois_LFSR = t;
9810                 /* Both are weak, combining them gives better randomness
9811                  * and ~2^64 period. & 0x7fff is probably bash compat
9812                  * for $RANDOM range. Combining with subtraction is
9813                  * just for fun. + and ^ would work equally well. */
9814                 t = (t - random_LCG) & 0x7fff;
9815                 /* set without recursion */
9816                 setvar(vrandom.text, utoa(t), VNOFUNC);
9817                 vrandom.flags &= ~VNOFUNC;
9818         } else {
9819                 /* set/reset */
9820                 random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);
9821         }
9822 }
9823 #endif
9824
9825 #if ENABLE_ASH_GETOPTS
9826 static int
9827 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9828 {
9829         char *p, *q;
9830         char c = '?';
9831         int done = 0;
9832         int err = 0;
9833         char s[12];
9834         char **optnext;
9835
9836         if (*param_optind < 1)
9837                 return 1;
9838         optnext = optfirst + *param_optind - 1;
9839
9840         if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
9841                 p = NULL;
9842         else
9843                 p = optnext[-1] + *optoff;
9844         if (p == NULL || *p == '\0') {
9845                 /* Current word is done, advance */
9846                 p = *optnext;
9847                 if (p == NULL || *p != '-' || *++p == '\0') {
9848  atend:
9849                         p = NULL;
9850                         done = 1;
9851                         goto out;
9852                 }
9853                 optnext++;
9854                 if (LONE_DASH(p))        /* check for "--" */
9855                         goto atend;
9856         }
9857
9858         c = *p++;
9859         for (q = optstr; *q != c;) {
9860                 if (*q == '\0') {
9861                         if (optstr[0] == ':') {
9862                                 s[0] = c;
9863                                 s[1] = '\0';
9864                                 err |= setvarsafe("OPTARG", s, 0);
9865                         } else {
9866                                 fprintf(stderr, "Illegal option -%c\n", c);
9867                                 unsetvar("OPTARG");
9868                         }
9869                         c = '?';
9870                         goto out;
9871                 }
9872                 if (*++q == ':')
9873                         q++;
9874         }
9875
9876         if (*++q == ':') {
9877                 if (*p == '\0' && (p = *optnext) == NULL) {
9878                         if (optstr[0] == ':') {
9879                                 s[0] = c;
9880                                 s[1] = '\0';
9881                                 err |= setvarsafe("OPTARG", s, 0);
9882                                 c = ':';
9883                         } else {
9884                                 fprintf(stderr, "No arg for -%c option\n", c);
9885                                 unsetvar("OPTARG");
9886                                 c = '?';
9887                         }
9888                         goto out;
9889                 }
9890
9891                 if (p == *optnext)
9892                         optnext++;
9893                 err |= setvarsafe("OPTARG", p, 0);
9894                 p = NULL;
9895         } else
9896                 err |= setvarsafe("OPTARG", nullstr, 0);
9897  out:
9898         *optoff = p ? p - *(optnext - 1) : -1;
9899         *param_optind = optnext - optfirst + 1;
9900         fmtstr(s, sizeof(s), "%d", *param_optind);
9901         err |= setvarsafe("OPTIND", s, VNOFUNC);
9902         s[0] = c;
9903         s[1] = '\0';
9904         err |= setvarsafe(optvar, s, 0);
9905         if (err) {
9906                 *param_optind = 1;
9907                 *optoff = -1;
9908                 flush_stdout_stderr();
9909                 raise_exception(EXERROR);
9910         }
9911         return done;
9912 }
9913
9914 /*
9915  * The getopts builtin.  Shellparam.optnext points to the next argument
9916  * to be processed.  Shellparam.optptr points to the next character to
9917  * be processed in the current argument.  If shellparam.optnext is NULL,
9918  * then it's the first time getopts has been called.
9919  */
9920 static int
9921 getoptscmd(int argc, char **argv)
9922 {
9923         char **optbase;
9924
9925         if (argc < 3)
9926                 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9927         if (argc == 3) {
9928                 optbase = shellparam.p;
9929                 if (shellparam.optind > shellparam.nparam + 1) {
9930                         shellparam.optind = 1;
9931                         shellparam.optoff = -1;
9932                 }
9933         } else {
9934                 optbase = &argv[3];
9935                 if (shellparam.optind > argc - 2) {
9936                         shellparam.optind = 1;
9937                         shellparam.optoff = -1;
9938                 }
9939         }
9940
9941         return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9942                         &shellparam.optoff);
9943 }
9944 #endif /* ASH_GETOPTS */
9945
9946
9947 /* ============ Shell parser */
9948
9949 struct heredoc {
9950         struct heredoc *next;   /* next here document in list */
9951         union node *here;       /* redirection node */
9952         char *eofmark;          /* string indicating end of input */
9953         smallint striptabs;     /* if set, strip leading tabs */
9954 };
9955
9956 static smallint tokpushback;           /* last token pushed back */
9957 static smallint parsebackquote;        /* nonzero if we are inside backquotes */
9958 static smallint quoteflag;             /* set if (part of) last token was quoted */
9959 static token_id_t lasttoken;           /* last token read (integer id Txxx) */
9960 static struct heredoc *heredoclist;    /* list of here documents to read */
9961 static char *wordtext;                 /* text of last word returned by readtoken */
9962 static struct nodelist *backquotelist;
9963 static union node *redirnode;
9964 static struct heredoc *heredoc;
9965 /*
9966  * NEOF is returned by parsecmd when it encounters an end of file.  It
9967  * must be distinct from NULL, so we use the address of a variable that
9968  * happens to be handy.
9969  */
9970 #define NEOF ((union node *)&tokpushback)
9971
9972 static void raise_error_syntax(const char *) NORETURN;
9973 static void
9974 raise_error_syntax(const char *msg)
9975 {
9976         ash_msg_and_raise_error("syntax error: %s", msg);
9977         /* NOTREACHED */
9978 }
9979
9980 /*
9981  * Called when an unexpected token is read during the parse.  The argument
9982  * is the token that is expected, or -1 if more than one type of token can
9983  * occur at this point.
9984  */
9985 static void raise_error_unexpected_syntax(int) NORETURN;
9986 static void
9987 raise_error_unexpected_syntax(int token)
9988 {
9989         char msg[64];
9990         int l;
9991
9992         l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9993         if (token >= 0)
9994                 sprintf(msg + l, " (expecting %s)", tokname(token));
9995         raise_error_syntax(msg);
9996         /* NOTREACHED */
9997 }
9998
9999 #define EOFMARKLEN 79
10000
10001 /* parsing is heavily cross-recursive, need these forward decls */
10002 static union node *andor(void);
10003 static union node *pipeline(void);
10004 static union node *parse_command(void);
10005 static void parseheredoc(void);
10006 static char peektoken(void);
10007 static int readtoken(void);
10008
10009 static union node *
10010 list(int nlflag)
10011 {
10012         union node *n1, *n2, *n3;
10013         int tok;
10014
10015         checkkwd = CHKNL | CHKKWD | CHKALIAS;
10016         if (nlflag == 2 && peektoken())
10017                 return NULL;
10018         n1 = NULL;
10019         for (;;) {
10020                 n2 = andor();
10021                 tok = readtoken();
10022                 if (tok == TBACKGND) {
10023                         if (n2->type == NPIPE) {
10024                                 n2->npipe.pipe_backgnd = 1;
10025                         } else {
10026                                 if (n2->type != NREDIR) {
10027                                         n3 = stzalloc(sizeof(struct nredir));
10028                                         n3->nredir.n = n2;
10029                                         /*n3->nredir.redirect = NULL; - stzalloc did it */
10030                                         n2 = n3;
10031                                 }
10032                                 n2->type = NBACKGND;
10033                         }
10034                 }
10035                 if (n1 == NULL) {
10036                         n1 = n2;
10037                 } else {
10038                         n3 = stzalloc(sizeof(struct nbinary));
10039                         n3->type = NSEMI;
10040                         n3->nbinary.ch1 = n1;
10041                         n3->nbinary.ch2 = n2;
10042                         n1 = n3;
10043                 }
10044                 switch (tok) {
10045                 case TBACKGND:
10046                 case TSEMI:
10047                         tok = readtoken();
10048                         /* fall through */
10049                 case TNL:
10050                         if (tok == TNL) {
10051                                 parseheredoc();
10052                                 if (nlflag == 1)
10053                                         return n1;
10054                         } else {
10055                                 tokpushback = 1;
10056                         }
10057                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
10058                         if (peektoken())
10059                                 return n1;
10060                         break;
10061                 case TEOF:
10062                         if (heredoclist)
10063                                 parseheredoc();
10064                         else
10065                                 pungetc();              /* push back EOF on input */
10066                         return n1;
10067                 default:
10068                         if (nlflag == 1)
10069                                 raise_error_unexpected_syntax(-1);
10070                         tokpushback = 1;
10071                         return n1;
10072                 }
10073         }
10074 }
10075
10076 static union node *
10077 andor(void)
10078 {
10079         union node *n1, *n2, *n3;
10080         int t;
10081
10082         n1 = pipeline();
10083         for (;;) {
10084                 t = readtoken();
10085                 if (t == TAND) {
10086                         t = NAND;
10087                 } else if (t == TOR) {
10088                         t = NOR;
10089                 } else {
10090                         tokpushback = 1;
10091                         return n1;
10092                 }
10093                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10094                 n2 = pipeline();
10095                 n3 = stzalloc(sizeof(struct nbinary));
10096                 n3->type = t;
10097                 n3->nbinary.ch1 = n1;
10098                 n3->nbinary.ch2 = n2;
10099                 n1 = n3;
10100         }
10101 }
10102
10103 static union node *
10104 pipeline(void)
10105 {
10106         union node *n1, *n2, *pipenode;
10107         struct nodelist *lp, *prev;
10108         int negate;
10109
10110         negate = 0;
10111         TRACE(("pipeline: entered\n"));
10112         if (readtoken() == TNOT) {
10113                 negate = !negate;
10114                 checkkwd = CHKKWD | CHKALIAS;
10115         } else
10116                 tokpushback = 1;
10117         n1 = parse_command();
10118         if (readtoken() == TPIPE) {
10119                 pipenode = stzalloc(sizeof(struct npipe));
10120                 pipenode->type = NPIPE;
10121                 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10122                 lp = stzalloc(sizeof(struct nodelist));
10123                 pipenode->npipe.cmdlist = lp;
10124                 lp->n = n1;
10125                 do {
10126                         prev = lp;
10127                         lp = stzalloc(sizeof(struct nodelist));
10128                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
10129                         lp->n = parse_command();
10130                         prev->next = lp;
10131                 } while (readtoken() == TPIPE);
10132                 lp->next = NULL;
10133                 n1 = pipenode;
10134         }
10135         tokpushback = 1;
10136         if (negate) {
10137                 n2 = stzalloc(sizeof(struct nnot));
10138                 n2->type = NNOT;
10139                 n2->nnot.com = n1;
10140                 return n2;
10141         }
10142         return n1;
10143 }
10144
10145 static union node *
10146 makename(void)
10147 {
10148         union node *n;
10149
10150         n = stzalloc(sizeof(struct narg));
10151         n->type = NARG;
10152         /*n->narg.next = NULL; - stzalloc did it */
10153         n->narg.text = wordtext;
10154         n->narg.backquote = backquotelist;
10155         return n;
10156 }
10157
10158 static void
10159 fixredir(union node *n, const char *text, int err)
10160 {
10161         int fd;
10162
10163         TRACE(("Fix redir %s %d\n", text, err));
10164         if (!err)
10165                 n->ndup.vname = NULL;
10166
10167         fd = bb_strtou(text, NULL, 10);
10168         if (!errno && fd >= 0)
10169                 n->ndup.dupfd = fd;
10170         else if (LONE_DASH(text))
10171                 n->ndup.dupfd = -1;
10172         else {
10173                 if (err)
10174                         raise_error_syntax("bad fd number");
10175                 n->ndup.vname = makename();
10176         }
10177 }
10178
10179 /*
10180  * Returns true if the text contains nothing to expand (no dollar signs
10181  * or backquotes).
10182  */
10183 static int
10184 noexpand(char *text)
10185 {
10186         char *p;
10187         char c;
10188
10189         p = text;
10190         while ((c = *p++) != '\0') {
10191                 if (c == CTLQUOTEMARK)
10192                         continue;
10193                 if (c == CTLESC)
10194                         p++;
10195                 else if (SIT(c, BASESYNTAX) == CCTL)
10196                         return 0;
10197         }
10198         return 1;
10199 }
10200
10201 static void
10202 parsefname(void)
10203 {
10204         union node *n = redirnode;
10205
10206         if (readtoken() != TWORD)
10207                 raise_error_unexpected_syntax(-1);
10208         if (n->type == NHERE) {
10209                 struct heredoc *here = heredoc;
10210                 struct heredoc *p;
10211                 int i;
10212
10213                 if (quoteflag == 0)
10214                         n->type = NXHERE;
10215                 TRACE(("Here document %d\n", n->type));
10216                 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10217                         raise_error_syntax("illegal eof marker for << redirection");
10218                 rmescapes(wordtext);
10219                 here->eofmark = wordtext;
10220                 here->next = NULL;
10221                 if (heredoclist == NULL)
10222                         heredoclist = here;
10223                 else {
10224                         for (p = heredoclist; p->next; p = p->next)
10225                                 continue;
10226                         p->next = here;
10227                 }
10228         } else if (n->type == NTOFD || n->type == NFROMFD) {
10229                 fixredir(n, wordtext, 0);
10230         } else {
10231                 n->nfile.fname = makename();
10232         }
10233 }
10234
10235 static union node *
10236 simplecmd(void)
10237 {
10238         union node *args, **app;
10239         union node *n = NULL;
10240         union node *vars, **vpp;
10241         union node **rpp, *redir;
10242         int savecheckkwd;
10243 #if ENABLE_ASH_BASH_COMPAT
10244         smallint double_brackets_flag = 0;
10245 #endif
10246
10247         args = NULL;
10248         app = &args;
10249         vars = NULL;
10250         vpp = &vars;
10251         redir = NULL;
10252         rpp = &redir;
10253
10254         savecheckkwd = CHKALIAS;
10255         for (;;) {
10256                 int t;
10257                 checkkwd = savecheckkwd;
10258                 t = readtoken();
10259                 switch (t) {
10260 #if ENABLE_ASH_BASH_COMPAT
10261                 case TAND: /* "&&" */
10262                 case TOR: /* "||" */
10263                         if (!double_brackets_flag) {
10264                                 tokpushback = 1;
10265                                 goto out;
10266                         }
10267                         wordtext = (char *) (t == TAND ? "-a" : "-o");
10268 #endif
10269                 case TWORD:
10270                         n = stzalloc(sizeof(struct narg));
10271                         n->type = NARG;
10272                         /*n->narg.next = NULL; - stzalloc did it */
10273                         n->narg.text = wordtext;
10274 #if ENABLE_ASH_BASH_COMPAT
10275                         if (strcmp("[[", wordtext) == 0)
10276                                 double_brackets_flag = 1;
10277                         else if (strcmp("]]", wordtext) == 0)
10278                                 double_brackets_flag = 0;
10279 #endif
10280                         n->narg.backquote = backquotelist;
10281                         if (savecheckkwd && isassignment(wordtext)) {
10282                                 *vpp = n;
10283                                 vpp = &n->narg.next;
10284                         } else {
10285                                 *app = n;
10286                                 app = &n->narg.next;
10287                                 savecheckkwd = 0;
10288                         }
10289                         break;
10290                 case TREDIR:
10291                         *rpp = n = redirnode;
10292                         rpp = &n->nfile.next;
10293                         parsefname();   /* read name of redirection file */
10294                         break;
10295                 case TLP:
10296                         if (args && app == &args->narg.next
10297                          && !vars && !redir
10298                         ) {
10299                                 struct builtincmd *bcmd;
10300                                 const char *name;
10301
10302                                 /* We have a function */
10303                                 if (readtoken() != TRP)
10304                                         raise_error_unexpected_syntax(TRP);
10305                                 name = n->narg.text;
10306                                 if (!goodname(name)
10307                                  || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10308                                 ) {
10309                                         raise_error_syntax("bad function name");
10310                                 }
10311                                 n->type = NDEFUN;
10312                                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10313                                 n->narg.next = parse_command();
10314                                 return n;
10315                         }
10316                         /* fall through */
10317                 default:
10318                         tokpushback = 1;
10319                         goto out;
10320                 }
10321         }
10322  out:
10323         *app = NULL;
10324         *vpp = NULL;
10325         *rpp = NULL;
10326         n = stzalloc(sizeof(struct ncmd));
10327         n->type = NCMD;
10328         n->ncmd.args = args;
10329         n->ncmd.assign = vars;
10330         n->ncmd.redirect = redir;
10331         return n;
10332 }
10333
10334 static union node *
10335 parse_command(void)
10336 {
10337         union node *n1, *n2;
10338         union node *ap, **app;
10339         union node *cp, **cpp;
10340         union node *redir, **rpp;
10341         union node **rpp2;
10342         int t;
10343
10344         redir = NULL;
10345         rpp2 = &redir;
10346
10347         switch (readtoken()) {
10348         default:
10349                 raise_error_unexpected_syntax(-1);
10350                 /* NOTREACHED */
10351         case TIF:
10352                 n1 = stzalloc(sizeof(struct nif));
10353                 n1->type = NIF;
10354                 n1->nif.test = list(0);
10355                 if (readtoken() != TTHEN)
10356                         raise_error_unexpected_syntax(TTHEN);
10357                 n1->nif.ifpart = list(0);
10358                 n2 = n1;
10359                 while (readtoken() == TELIF) {
10360                         n2->nif.elsepart = stzalloc(sizeof(struct nif));
10361                         n2 = n2->nif.elsepart;
10362                         n2->type = NIF;
10363                         n2->nif.test = list(0);
10364                         if (readtoken() != TTHEN)
10365                                 raise_error_unexpected_syntax(TTHEN);
10366                         n2->nif.ifpart = list(0);
10367                 }
10368                 if (lasttoken == TELSE)
10369                         n2->nif.elsepart = list(0);
10370                 else {
10371                         n2->nif.elsepart = NULL;
10372                         tokpushback = 1;
10373                 }
10374                 t = TFI;
10375                 break;
10376         case TWHILE:
10377         case TUNTIL: {
10378                 int got;
10379                 n1 = stzalloc(sizeof(struct nbinary));
10380                 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10381                 n1->nbinary.ch1 = list(0);
10382                 got = readtoken();
10383                 if (got != TDO) {
10384                         TRACE(("expecting DO got %s %s\n", tokname(got),
10385                                         got == TWORD ? wordtext : ""));
10386                         raise_error_unexpected_syntax(TDO);
10387                 }
10388                 n1->nbinary.ch2 = list(0);
10389                 t = TDONE;
10390                 break;
10391         }
10392         case TFOR:
10393                 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10394                         raise_error_syntax("bad for loop variable");
10395                 n1 = stzalloc(sizeof(struct nfor));
10396                 n1->type = NFOR;
10397                 n1->nfor.var = wordtext;
10398                 checkkwd = CHKKWD | CHKALIAS;
10399                 if (readtoken() == TIN) {
10400                         app = &ap;
10401                         while (readtoken() == TWORD) {
10402                                 n2 = stzalloc(sizeof(struct narg));
10403                                 n2->type = NARG;
10404                                 /*n2->narg.next = NULL; - stzalloc did it */
10405                                 n2->narg.text = wordtext;
10406                                 n2->narg.backquote = backquotelist;
10407                                 *app = n2;
10408                                 app = &n2->narg.next;
10409                         }
10410                         *app = NULL;
10411                         n1->nfor.args = ap;
10412                         if (lasttoken != TNL && lasttoken != TSEMI)
10413                                 raise_error_unexpected_syntax(-1);
10414                 } else {
10415                         n2 = stzalloc(sizeof(struct narg));
10416                         n2->type = NARG;
10417                         /*n2->narg.next = NULL; - stzalloc did it */
10418                         n2->narg.text = (char *)dolatstr;
10419                         /*n2->narg.backquote = NULL;*/
10420                         n1->nfor.args = n2;
10421                         /*
10422                          * Newline or semicolon here is optional (but note
10423                          * that the original Bourne shell only allowed NL).
10424                          */
10425                         if (lasttoken != TNL && lasttoken != TSEMI)
10426                                 tokpushback = 1;
10427                 }
10428                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10429                 if (readtoken() != TDO)
10430                         raise_error_unexpected_syntax(TDO);
10431                 n1->nfor.body = list(0);
10432                 t = TDONE;
10433                 break;
10434         case TCASE:
10435                 n1 = stzalloc(sizeof(struct ncase));
10436                 n1->type = NCASE;
10437                 if (readtoken() != TWORD)
10438                         raise_error_unexpected_syntax(TWORD);
10439                 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10440                 n2->type = NARG;
10441                 /*n2->narg.next = NULL; - stzalloc did it */
10442                 n2->narg.text = wordtext;
10443                 n2->narg.backquote = backquotelist;
10444                 do {
10445                         checkkwd = CHKKWD | CHKALIAS;
10446                 } while (readtoken() == TNL);
10447                 if (lasttoken != TIN)
10448                         raise_error_unexpected_syntax(TIN);
10449                 cpp = &n1->ncase.cases;
10450  next_case:
10451                 checkkwd = CHKNL | CHKKWD;
10452                 t = readtoken();
10453                 while (t != TESAC) {
10454                         if (lasttoken == TLP)
10455                                 readtoken();
10456                         *cpp = cp = stzalloc(sizeof(struct nclist));
10457                         cp->type = NCLIST;
10458                         app = &cp->nclist.pattern;
10459                         for (;;) {
10460                                 *app = ap = stzalloc(sizeof(struct narg));
10461                                 ap->type = NARG;
10462                                 /*ap->narg.next = NULL; - stzalloc did it */
10463                                 ap->narg.text = wordtext;
10464                                 ap->narg.backquote = backquotelist;
10465                                 if (readtoken() != TPIPE)
10466                                         break;
10467                                 app = &ap->narg.next;
10468                                 readtoken();
10469                         }
10470                         //ap->narg.next = NULL;
10471                         if (lasttoken != TRP)
10472                                 raise_error_unexpected_syntax(TRP);
10473                         cp->nclist.body = list(2);
10474
10475                         cpp = &cp->nclist.next;
10476
10477                         checkkwd = CHKNL | CHKKWD;
10478                         t = readtoken();
10479                         if (t != TESAC) {
10480                                 if (t != TENDCASE)
10481                                         raise_error_unexpected_syntax(TENDCASE);
10482                                 goto next_case;
10483                         }
10484                 }
10485                 *cpp = NULL;
10486                 goto redir;
10487         case TLP:
10488                 n1 = stzalloc(sizeof(struct nredir));
10489                 n1->type = NSUBSHELL;
10490                 n1->nredir.n = list(0);
10491                 /*n1->nredir.redirect = NULL; - stzalloc did it */
10492                 t = TRP;
10493                 break;
10494         case TBEGIN:
10495                 n1 = list(0);
10496                 t = TEND;
10497                 break;
10498         case TWORD:
10499         case TREDIR:
10500                 tokpushback = 1;
10501                 return simplecmd();
10502         }
10503
10504         if (readtoken() != t)
10505                 raise_error_unexpected_syntax(t);
10506
10507  redir:
10508         /* Now check for redirection which may follow command */
10509         checkkwd = CHKKWD | CHKALIAS;
10510         rpp = rpp2;
10511         while (readtoken() == TREDIR) {
10512                 *rpp = n2 = redirnode;
10513                 rpp = &n2->nfile.next;
10514                 parsefname();
10515         }
10516         tokpushback = 1;
10517         *rpp = NULL;
10518         if (redir) {
10519                 if (n1->type != NSUBSHELL) {
10520                         n2 = stzalloc(sizeof(struct nredir));
10521                         n2->type = NREDIR;
10522                         n2->nredir.n = n1;
10523                         n1 = n2;
10524                 }
10525                 n1->nredir.redirect = redir;
10526         }
10527         return n1;
10528 }
10529
10530 #if ENABLE_ASH_BASH_COMPAT
10531 static int decode_dollar_squote(void)
10532 {
10533         static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10534         int c, cnt;
10535         char *p;
10536         char buf[4];
10537
10538         c = pgetc();
10539         p = strchr(C_escapes, c);
10540         if (p) {
10541                 buf[0] = c;
10542                 p = buf;
10543                 cnt = 3;
10544                 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10545                         do {
10546                                 c = pgetc();
10547                                 *++p = c;
10548                         } while ((unsigned char)(c - '0') <= 7 && --cnt);
10549                         pungetc();
10550                 } else if (c == 'x') { /* \xHH */
10551                         do {
10552                                 c = pgetc();
10553                                 *++p = c;
10554                         } while (isxdigit(c) && --cnt);
10555                         pungetc();
10556                         if (cnt == 3) { /* \x but next char is "bad" */
10557                                 c = 'x';
10558                                 goto unrecognized;
10559                         }
10560                 } else { /* simple seq like \\ or \t */
10561                         p++;
10562                 }
10563                 *p = '\0';
10564                 p = buf;
10565                 c = bb_process_escape_sequence((void*)&p);
10566         } else { /* unrecognized "\z": print both chars unless ' or " */
10567                 if (c != '\'' && c != '"') {
10568  unrecognized:
10569                         c |= 0x100; /* "please encode \, then me" */
10570                 }
10571         }
10572         return c;
10573 }
10574 #endif
10575
10576 /*
10577  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10578  * is not NULL, read a here document.  In the latter case, eofmark is the
10579  * word which marks the end of the document and striptabs is true if
10580  * leading tabs should be stripped from the document.  The argument firstc
10581  * is the first character of the input token or document.
10582  *
10583  * Because C does not have internal subroutines, I have simulated them
10584  * using goto's to implement the subroutine linkage.  The following macros
10585  * will run code that appears at the end of readtoken1.
10586  */
10587 #define CHECKEND()      {goto checkend; checkend_return:;}
10588 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10589 #define PARSESUB()      {goto parsesub; parsesub_return:;}
10590 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10591 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10592 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
10593 static int
10594 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10595 {
10596         /* NB: syntax parameter fits into smallint */
10597         int c = firstc;
10598         char *out;
10599         int len;
10600         char line[EOFMARKLEN + 1];
10601         struct nodelist *bqlist;
10602         smallint quotef;
10603         smallint dblquote;
10604         smallint oldstyle;
10605         smallint prevsyntax; /* syntax before arithmetic */
10606 #if ENABLE_ASH_EXPAND_PRMT
10607         smallint pssyntax;   /* we are expanding a prompt string */
10608 #endif
10609         int varnest;         /* levels of variables expansion */
10610         int arinest;         /* levels of arithmetic expansion */
10611         int parenlevel;      /* levels of parens in arithmetic */
10612         int dqvarnest;       /* levels of variables expansion within double quotes */
10613
10614         USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10615
10616 #if __GNUC__
10617         /* Avoid longjmp clobbering */
10618         (void) &out;
10619         (void) &quotef;
10620         (void) &dblquote;
10621         (void) &varnest;
10622         (void) &arinest;
10623         (void) &parenlevel;
10624         (void) &dqvarnest;
10625         (void) &oldstyle;
10626         (void) &prevsyntax;
10627         (void) &syntax;
10628 #endif
10629         startlinno = plinno;
10630         bqlist = NULL;
10631         quotef = 0;
10632         oldstyle = 0;
10633         prevsyntax = 0;
10634 #if ENABLE_ASH_EXPAND_PRMT
10635         pssyntax = (syntax == PSSYNTAX);
10636         if (pssyntax)
10637                 syntax = DQSYNTAX;
10638 #endif
10639         dblquote = (syntax == DQSYNTAX);
10640         varnest = 0;
10641         arinest = 0;
10642         parenlevel = 0;
10643         dqvarnest = 0;
10644
10645         STARTSTACKSTR(out);
10646  loop:
10647         /* For each line, until end of word */
10648         {
10649                 CHECKEND();     /* set c to PEOF if at end of here document */
10650                 for (;;) {      /* until end of line or end of word */
10651                         CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
10652                         switch (SIT(c, syntax)) {
10653                         case CNL:       /* '\n' */
10654                                 if (syntax == BASESYNTAX)
10655                                         goto endword;   /* exit outer loop */
10656                                 USTPUTC(c, out);
10657                                 plinno++;
10658                                 if (doprompt)
10659                                         setprompt(2);
10660                                 c = pgetc();
10661                                 goto loop;              /* continue outer loop */
10662                         case CWORD:
10663                                 USTPUTC(c, out);
10664                                 break;
10665                         case CCTL:
10666                                 if (eofmark == NULL || dblquote)
10667                                         USTPUTC(CTLESC, out);
10668 #if ENABLE_ASH_BASH_COMPAT
10669                                 if (c == '\\' && bash_dollar_squote) {
10670                                         c = decode_dollar_squote();
10671                                         if (c & 0x100) {
10672                                                 USTPUTC('\\', out);
10673                                                 c = (unsigned char)c;
10674                                         }
10675                                 }
10676 #endif
10677                                 USTPUTC(c, out);
10678                                 break;
10679                         case CBACK:     /* backslash */
10680                                 c = pgetc2();
10681                                 if (c == PEOF) {
10682                                         USTPUTC(CTLESC, out);
10683                                         USTPUTC('\\', out);
10684                                         pungetc();
10685                                 } else if (c == '\n') {
10686                                         if (doprompt)
10687                                                 setprompt(2);
10688                                 } else {
10689 #if ENABLE_ASH_EXPAND_PRMT
10690                                         if (c == '$' && pssyntax) {
10691                                                 USTPUTC(CTLESC, out);
10692                                                 USTPUTC('\\', out);
10693                                         }
10694 #endif
10695                                         if (dblquote && c != '\\'
10696                                          && c != '`' && c != '$'
10697                                          && (c != '"' || eofmark != NULL)
10698                                         ) {
10699                                                 USTPUTC(CTLESC, out);
10700                                                 USTPUTC('\\', out);
10701                                         }
10702                                         if (SIT(c, SQSYNTAX) == CCTL)
10703                                                 USTPUTC(CTLESC, out);
10704                                         USTPUTC(c, out);
10705                                         quotef = 1;
10706                                 }
10707                                 break;
10708                         case CSQUOTE:
10709                                 syntax = SQSYNTAX;
10710  quotemark:
10711                                 if (eofmark == NULL) {
10712                                         USTPUTC(CTLQUOTEMARK, out);
10713                                 }
10714                                 break;
10715                         case CDQUOTE:
10716                                 syntax = DQSYNTAX;
10717                                 dblquote = 1;
10718                                 goto quotemark;
10719                         case CENDQUOTE:
10720                                 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10721                                 if (eofmark != NULL && arinest == 0
10722                                  && varnest == 0
10723                                 ) {
10724                                         USTPUTC(c, out);
10725                                 } else {
10726                                         if (dqvarnest == 0) {
10727                                                 syntax = BASESYNTAX;
10728                                                 dblquote = 0;
10729                                         }
10730                                         quotef = 1;
10731                                         goto quotemark;
10732                                 }
10733                                 break;
10734                         case CVAR:      /* '$' */
10735                                 PARSESUB();             /* parse substitution */
10736                                 break;
10737                         case CENDVAR:   /* '}' */
10738                                 if (varnest > 0) {
10739                                         varnest--;
10740                                         if (dqvarnest > 0) {
10741                                                 dqvarnest--;
10742                                         }
10743                                         USTPUTC(CTLENDVAR, out);
10744                                 } else {
10745                                         USTPUTC(c, out);
10746                                 }
10747                                 break;
10748 #if ENABLE_ASH_MATH_SUPPORT
10749                         case CLP:       /* '(' in arithmetic */
10750                                 parenlevel++;
10751                                 USTPUTC(c, out);
10752                                 break;
10753                         case CRP:       /* ')' in arithmetic */
10754                                 if (parenlevel > 0) {
10755                                         USTPUTC(c, out);
10756                                         --parenlevel;
10757                                 } else {
10758                                         if (pgetc() == ')') {
10759                                                 if (--arinest == 0) {
10760                                                         USTPUTC(CTLENDARI, out);
10761                                                         syntax = prevsyntax;
10762                                                         dblquote = (syntax == DQSYNTAX);
10763                                                 } else
10764                                                         USTPUTC(')', out);
10765                                         } else {
10766                                                 /*
10767                                                  * unbalanced parens
10768                                                  *  (don't 2nd guess - no error)
10769                                                  */
10770                                                 pungetc();
10771                                                 USTPUTC(')', out);
10772                                         }
10773                                 }
10774                                 break;
10775 #endif
10776                         case CBQUOTE:   /* '`' */
10777                                 PARSEBACKQOLD();
10778                                 break;
10779                         case CENDFILE:
10780                                 goto endword;           /* exit outer loop */
10781                         case CIGN:
10782                                 break;
10783                         default:
10784                                 if (varnest == 0) {
10785 #if ENABLE_ASH_BASH_COMPAT
10786                                         if (c == '&') {
10787                                                 if (pgetc() == '>')
10788                                                         c = 0x100 + '>'; /* flag &> */
10789                                                 pungetc();
10790                                         }
10791 #endif
10792                                         goto endword;   /* exit outer loop */
10793                                 }
10794 #if ENABLE_ASH_ALIAS
10795                                 if (c != PEOA)
10796 #endif
10797                                         USTPUTC(c, out);
10798
10799                         }
10800                         c = pgetc_fast();
10801                 } /* for (;;) */
10802         }
10803  endword:
10804 #if ENABLE_ASH_MATH_SUPPORT
10805         if (syntax == ARISYNTAX)
10806                 raise_error_syntax("missing '))'");
10807 #endif
10808         if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10809                 raise_error_syntax("unterminated quoted string");
10810         if (varnest != 0) {
10811                 startlinno = plinno;
10812                 /* { */
10813                 raise_error_syntax("missing '}'");
10814         }
10815         USTPUTC('\0', out);
10816         len = out - (char *)stackblock();
10817         out = stackblock();
10818         if (eofmark == NULL) {
10819                 if ((c == '>' || c == '<' USE_ASH_BASH_COMPAT( || c == 0x100 + '>'))
10820                  && quotef == 0
10821                 ) {
10822                         if (isdigit_str9(out)) {
10823                                 PARSEREDIR(); /* passed as params: out, c */
10824                                 lasttoken = TREDIR;
10825                                 return lasttoken;
10826                         }
10827                         /* else: non-number X seen, interpret it
10828                          * as "NNNX>file" = "NNNX >file" */
10829                 }
10830                 pungetc();
10831         }
10832         quoteflag = quotef;
10833         backquotelist = bqlist;
10834         grabstackblock(len);
10835         wordtext = out;
10836         lasttoken = TWORD;
10837         return lasttoken;
10838 /* end of readtoken routine */
10839
10840 /*
10841  * Check to see whether we are at the end of the here document.  When this
10842  * is called, c is set to the first character of the next input line.  If
10843  * we are at the end of the here document, this routine sets the c to PEOF.
10844  */
10845 checkend: {
10846         if (eofmark) {
10847 #if ENABLE_ASH_ALIAS
10848                 if (c == PEOA) {
10849                         c = pgetc2();
10850                 }
10851 #endif
10852                 if (striptabs) {
10853                         while (c == '\t') {
10854                                 c = pgetc2();
10855                         }
10856                 }
10857                 if (c == *eofmark) {
10858                         if (pfgets(line, sizeof(line)) != NULL) {
10859                                 char *p, *q;
10860
10861                                 p = line;
10862                                 for (q = eofmark + 1; *q && *p == *q; p++, q++)
10863                                         continue;
10864                                 if (*p == '\n' && *q == '\0') {
10865                                         c = PEOF;
10866                                         plinno++;
10867                                         needprompt = doprompt;
10868                                 } else {
10869                                         pushstring(line, NULL);
10870                                 }
10871                         }
10872                 }
10873         }
10874         goto checkend_return;
10875 }
10876
10877 /*
10878  * Parse a redirection operator.  The variable "out" points to a string
10879  * specifying the fd to be redirected.  The variable "c" contains the
10880  * first character of the redirection operator.
10881  */
10882 parseredir: {
10883         /* out is already checked to be a valid number or "" */
10884         int fd = (*out == '\0' ? -1 : atoi(out));
10885         union node *np;
10886
10887         np = stzalloc(sizeof(struct nfile));
10888         if (c == '>') {
10889                 np->nfile.fd = 1;
10890                 c = pgetc();
10891                 if (c == '>')
10892                         np->type = NAPPEND;
10893                 else if (c == '|')
10894                         np->type = NCLOBBER;
10895                 else if (c == '&')
10896                         np->type = NTOFD;
10897                         /* it also can be NTO2 (>&file), but we can't figure it out yet */
10898                 else {
10899                         np->type = NTO;
10900                         pungetc();
10901                 }
10902         }
10903 #if ENABLE_ASH_BASH_COMPAT
10904         else if (c == 0x100 + '>') { /* this flags &> redirection */
10905                 np->nfile.fd = 1;
10906                 pgetc(); /* this is '>', no need to check */
10907                 np->type = NTO2;
10908         }
10909 #endif
10910         else { /* c == '<' */
10911                 /*np->nfile.fd = 0; - stzalloc did it */
10912                 c = pgetc();
10913                 switch (c) {
10914                 case '<':
10915                         if (sizeof(struct nfile) != sizeof(struct nhere)) {
10916                                 np = stzalloc(sizeof(struct nhere));
10917                                 /*np->nfile.fd = 0; - stzalloc did it */
10918                         }
10919                         np->type = NHERE;
10920                         heredoc = stzalloc(sizeof(struct heredoc));
10921                         heredoc->here = np;
10922                         c = pgetc();
10923                         if (c == '-') {
10924                                 heredoc->striptabs = 1;
10925                         } else {
10926                                 /*heredoc->striptabs = 0; - stzalloc did it */
10927                                 pungetc();
10928                         }
10929                         break;
10930
10931                 case '&':
10932                         np->type = NFROMFD;
10933                         break;
10934
10935                 case '>':
10936                         np->type = NFROMTO;
10937                         break;
10938
10939                 default:
10940                         np->type = NFROM;
10941                         pungetc();
10942                         break;
10943                 }
10944         }
10945         if (fd >= 0)
10946                 np->nfile.fd = fd;
10947         redirnode = np;
10948         goto parseredir_return;
10949 }
10950
10951 /*
10952  * Parse a substitution.  At this point, we have read the dollar sign
10953  * and nothing else.
10954  */
10955
10956 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10957  * (assuming ascii char codes, as the original implementation did) */
10958 #define is_special(c) \
10959         (((unsigned)(c) - 33 < 32) \
10960                         && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
10961 parsesub: {
10962         int subtype;
10963         int typeloc;
10964         int flags;
10965         char *p;
10966         static const char types[] ALIGN1 = "}-+?=";
10967
10968         c = pgetc();
10969         if (c <= PEOA_OR_PEOF
10970          || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10971         ) {
10972 #if ENABLE_ASH_BASH_COMPAT
10973                 if (c == '\'')
10974                         bash_dollar_squote = 1;
10975                 else
10976 #endif
10977                         USTPUTC('$', out);
10978                 pungetc();
10979         } else if (c == '(') {  /* $(command) or $((arith)) */
10980                 if (pgetc() == '(') {
10981 #if ENABLE_ASH_MATH_SUPPORT
10982                         PARSEARITH();
10983 #else
10984                         raise_error_syntax("you disabled math support for $((arith)) syntax");
10985 #endif
10986                 } else {
10987                         pungetc();
10988                         PARSEBACKQNEW();
10989                 }
10990         } else {
10991                 USTPUTC(CTLVAR, out);
10992                 typeloc = out - (char *)stackblock();
10993                 USTPUTC(VSNORMAL, out);
10994                 subtype = VSNORMAL;
10995                 if (c == '{') {
10996                         c = pgetc();
10997                         if (c == '#') {
10998                                 c = pgetc();
10999                                 if (c == '}')
11000                                         c = '#';
11001                                 else
11002                                         subtype = VSLENGTH;
11003                         } else
11004                                 subtype = 0;
11005                 }
11006                 if (c > PEOA_OR_PEOF && is_name(c)) {
11007                         do {
11008                                 STPUTC(c, out);
11009                                 c = pgetc();
11010                         } while (c > PEOA_OR_PEOF && is_in_name(c));
11011                 } else if (isdigit(c)) {
11012                         do {
11013                                 STPUTC(c, out);
11014                                 c = pgetc();
11015                         } while (isdigit(c));
11016                 } else if (is_special(c)) {
11017                         USTPUTC(c, out);
11018                         c = pgetc();
11019                 } else {
11020  badsub:
11021                         raise_error_syntax("bad substitution");
11022                 }
11023
11024                 STPUTC('=', out);
11025                 flags = 0;
11026                 if (subtype == 0) {
11027                         switch (c) {
11028                         case ':':
11029                                 c = pgetc();
11030 #if ENABLE_ASH_BASH_COMPAT
11031                                 if (c == ':' || c == '$' || isdigit(c)) {
11032                                         pungetc();
11033                                         subtype = VSSUBSTR;
11034                                         break;
11035                                 }
11036 #endif
11037                                 flags = VSNUL;
11038                                 /*FALLTHROUGH*/
11039                         default:
11040                                 p = strchr(types, c);
11041                                 if (p == NULL)
11042                                         goto badsub;
11043                                 subtype = p - types + VSNORMAL;
11044                                 break;
11045                         case '%':
11046                         case '#': {
11047                                 int cc = c;
11048                                 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
11049                                 c = pgetc();
11050                                 if (c == cc)
11051                                         subtype++;
11052                                 else
11053                                         pungetc();
11054                                 break;
11055                         }
11056 #if ENABLE_ASH_BASH_COMPAT
11057                         case '/':
11058                                 subtype = VSREPLACE;
11059                                 c = pgetc();
11060                                 if (c == '/')
11061                                         subtype++; /* VSREPLACEALL */
11062                                 else
11063                                         pungetc();
11064                                 break;
11065 #endif
11066                         }
11067                 } else {
11068                         pungetc();
11069                 }
11070                 if (dblquote || arinest)
11071                         flags |= VSQUOTE;
11072                 *((char *)stackblock() + typeloc) = subtype | flags;
11073                 if (subtype != VSNORMAL) {
11074                         varnest++;
11075                         if (dblquote || arinest) {
11076                                 dqvarnest++;
11077                         }
11078                 }
11079         }
11080         goto parsesub_return;
11081 }
11082
11083 /*
11084  * Called to parse command substitutions.  Newstyle is set if the command
11085  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11086  * list of commands (passed by reference), and savelen is the number of
11087  * characters on the top of the stack which must be preserved.
11088  */
11089 parsebackq: {
11090         struct nodelist **nlpp;
11091         smallint savepbq;
11092         union node *n;
11093         char *volatile str;
11094         struct jmploc jmploc;
11095         struct jmploc *volatile savehandler;
11096         size_t savelen;
11097         smallint saveprompt = 0;
11098
11099 #ifdef __GNUC__
11100         (void) &saveprompt;
11101 #endif
11102         savepbq = parsebackquote;
11103         if (setjmp(jmploc.loc)) {
11104                 free(str);
11105                 parsebackquote = 0;
11106                 exception_handler = savehandler;
11107                 longjmp(exception_handler->loc, 1);
11108         }
11109         INT_OFF;
11110         str = NULL;
11111         savelen = out - (char *)stackblock();
11112         if (savelen > 0) {
11113                 str = ckmalloc(savelen);
11114                 memcpy(str, stackblock(), savelen);
11115         }
11116         savehandler = exception_handler;
11117         exception_handler = &jmploc;
11118         INT_ON;
11119         if (oldstyle) {
11120                 /* We must read until the closing backquote, giving special
11121                    treatment to some slashes, and then push the string and
11122                    reread it as input, interpreting it normally.  */
11123                 char *pout;
11124                 int pc;
11125                 size_t psavelen;
11126                 char *pstr;
11127
11128
11129                 STARTSTACKSTR(pout);
11130                 for (;;) {
11131                         if (needprompt) {
11132                                 setprompt(2);
11133                         }
11134                         pc = pgetc();
11135                         switch (pc) {
11136                         case '`':
11137                                 goto done;
11138
11139                         case '\\':
11140                                 pc = pgetc();
11141                                 if (pc == '\n') {
11142                                         plinno++;
11143                                         if (doprompt)
11144                                                 setprompt(2);
11145                                         /*
11146                                          * If eating a newline, avoid putting
11147                                          * the newline into the new character
11148                                          * stream (via the STPUTC after the
11149                                          * switch).
11150                                          */
11151                                         continue;
11152                                 }
11153                                 if (pc != '\\' && pc != '`' && pc != '$'
11154                                  && (!dblquote || pc != '"'))
11155                                         STPUTC('\\', pout);
11156                                 if (pc > PEOA_OR_PEOF) {
11157                                         break;
11158                                 }
11159                                 /* fall through */
11160
11161                         case PEOF:
11162 #if ENABLE_ASH_ALIAS
11163                         case PEOA:
11164 #endif
11165                                 startlinno = plinno;
11166                                 raise_error_syntax("EOF in backquote substitution");
11167
11168                         case '\n':
11169                                 plinno++;
11170                                 needprompt = doprompt;
11171                                 break;
11172
11173                         default:
11174                                 break;
11175                         }
11176                         STPUTC(pc, pout);
11177                 }
11178  done:
11179                 STPUTC('\0', pout);
11180                 psavelen = pout - (char *)stackblock();
11181                 if (psavelen > 0) {
11182                         pstr = grabstackstr(pout);
11183                         setinputstring(pstr);
11184                 }
11185         }
11186         nlpp = &bqlist;
11187         while (*nlpp)
11188                 nlpp = &(*nlpp)->next;
11189         *nlpp = stzalloc(sizeof(**nlpp));
11190         /* (*nlpp)->next = NULL; - stzalloc did it */
11191         parsebackquote = oldstyle;
11192
11193         if (oldstyle) {
11194                 saveprompt = doprompt;
11195                 doprompt = 0;
11196         }
11197
11198         n = list(2);
11199
11200         if (oldstyle)
11201                 doprompt = saveprompt;
11202         else if (readtoken() != TRP)
11203                 raise_error_unexpected_syntax(TRP);
11204
11205         (*nlpp)->n = n;
11206         if (oldstyle) {
11207                 /*
11208                  * Start reading from old file again, ignoring any pushed back
11209                  * tokens left from the backquote parsing
11210                  */
11211                 popfile();
11212                 tokpushback = 0;
11213         }
11214         while (stackblocksize() <= savelen)
11215                 growstackblock();
11216         STARTSTACKSTR(out);
11217         if (str) {
11218                 memcpy(out, str, savelen);
11219                 STADJUST(savelen, out);
11220                 INT_OFF;
11221                 free(str);
11222                 str = NULL;
11223                 INT_ON;
11224         }
11225         parsebackquote = savepbq;
11226         exception_handler = savehandler;
11227         if (arinest || dblquote)
11228                 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11229         else
11230                 USTPUTC(CTLBACKQ, out);
11231         if (oldstyle)
11232                 goto parsebackq_oldreturn;
11233         goto parsebackq_newreturn;
11234 }
11235
11236 #if ENABLE_ASH_MATH_SUPPORT
11237 /*
11238  * Parse an arithmetic expansion (indicate start of one and set state)
11239  */
11240 parsearith: {
11241         if (++arinest == 1) {
11242                 prevsyntax = syntax;
11243                 syntax = ARISYNTAX;
11244                 USTPUTC(CTLARI, out);
11245                 if (dblquote)
11246                         USTPUTC('"', out);
11247                 else
11248                         USTPUTC(' ', out);
11249         } else {
11250                 /*
11251                  * we collapse embedded arithmetic expansion to
11252                  * parenthesis, which should be equivalent
11253                  */
11254                 USTPUTC('(', out);
11255         }
11256         goto parsearith_return;
11257 }
11258 #endif
11259
11260 } /* end of readtoken */
11261
11262 /*
11263  * Read the next input token.
11264  * If the token is a word, we set backquotelist to the list of cmds in
11265  *      backquotes.  We set quoteflag to true if any part of the word was
11266  *      quoted.
11267  * If the token is TREDIR, then we set redirnode to a structure containing
11268  *      the redirection.
11269  * In all cases, the variable startlinno is set to the number of the line
11270  *      on which the token starts.
11271  *
11272  * [Change comment:  here documents and internal procedures]
11273  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
11274  *  word parsing code into a separate routine.  In this case, readtoken
11275  *  doesn't need to have any internal procedures, but parseword does.
11276  *  We could also make parseoperator in essence the main routine, and
11277  *  have parseword (readtoken1?) handle both words and redirection.]
11278  */
11279 #define NEW_xxreadtoken
11280 #ifdef NEW_xxreadtoken
11281 /* singles must be first! */
11282 static const char xxreadtoken_chars[7] ALIGN1 = {
11283         '\n', '(', ')', /* singles */
11284         '&', '|', ';',  /* doubles */
11285         0
11286 };
11287
11288 #define xxreadtoken_singles 3
11289 #define xxreadtoken_doubles 3
11290
11291 static const char xxreadtoken_tokens[] ALIGN1 = {
11292         TNL, TLP, TRP,          /* only single occurrence allowed */
11293         TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11294         TEOF,                   /* corresponds to trailing nul */
11295         TAND, TOR, TENDCASE     /* if double occurrence */
11296 };
11297
11298 static int
11299 xxreadtoken(void)
11300 {
11301         int c;
11302
11303         if (tokpushback) {
11304                 tokpushback = 0;
11305                 return lasttoken;
11306         }
11307         if (needprompt) {
11308                 setprompt(2);
11309         }
11310         startlinno = plinno;
11311         for (;;) {                      /* until token or start of word found */
11312                 c = pgetc_fast();
11313                 if (c == ' ' || c == '\t' USE_ASH_ALIAS( || c == PEOA))
11314                         continue;
11315
11316                 if (c == '#') {
11317                         while ((c = pgetc()) != '\n' && c != PEOF)
11318                                 continue;
11319                         pungetc();
11320                 } else if (c == '\\') {
11321                         if (pgetc() != '\n') {
11322                                 pungetc();
11323                                 break; /* return readtoken1(...) */
11324                         }
11325                         startlinno = ++plinno;
11326                         if (doprompt)
11327                                 setprompt(2);
11328                 } else {
11329                         const char *p;
11330
11331                         p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11332                         if (c != PEOF) {
11333                                 if (c == '\n') {
11334                                         plinno++;
11335                                         needprompt = doprompt;
11336                                 }
11337
11338                                 p = strchr(xxreadtoken_chars, c);
11339                                 if (p == NULL)
11340                                         break; /* return readtoken1(...) */
11341
11342                                 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11343                                         int cc = pgetc();
11344                                         if (cc == c) {    /* double occurrence? */
11345                                                 p += xxreadtoken_doubles + 1;
11346                                         } else {
11347                                                 pungetc();
11348 #if ENABLE_ASH_BASH_COMPAT
11349                                                 if (c == '&' && cc == '>') /* &> */
11350                                                         break; /* return readtoken1(...) */
11351 #endif
11352                                         }
11353                                 }
11354                         }
11355                         lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11356                         return lasttoken;
11357                 }
11358         } /* for (;;) */
11359
11360         return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11361 }
11362 #else /* old xxreadtoken */
11363 #define RETURN(token)   return lasttoken = token
11364 static int
11365 xxreadtoken(void)
11366 {
11367         int c;
11368
11369         if (tokpushback) {
11370                 tokpushback = 0;
11371                 return lasttoken;
11372         }
11373         if (needprompt) {
11374                 setprompt(2);
11375         }
11376         startlinno = plinno;
11377         for (;;) {      /* until token or start of word found */
11378                 c = pgetc_fast();
11379                 switch (c) {
11380                 case ' ': case '\t':
11381 #if ENABLE_ASH_ALIAS
11382                 case PEOA:
11383 #endif
11384                         continue;
11385                 case '#':
11386                         while ((c = pgetc()) != '\n' && c != PEOF)
11387                                 continue;
11388                         pungetc();
11389                         continue;
11390                 case '\\':
11391                         if (pgetc() == '\n') {
11392                                 startlinno = ++plinno;
11393                                 if (doprompt)
11394                                         setprompt(2);
11395                                 continue;
11396                         }
11397                         pungetc();
11398                         goto breakloop;
11399                 case '\n':
11400                         plinno++;
11401                         needprompt = doprompt;
11402                         RETURN(TNL);
11403                 case PEOF:
11404                         RETURN(TEOF);
11405                 case '&':
11406                         if (pgetc() == '&')
11407                                 RETURN(TAND);
11408                         pungetc();
11409                         RETURN(TBACKGND);
11410                 case '|':
11411                         if (pgetc() == '|')
11412                                 RETURN(TOR);
11413                         pungetc();
11414                         RETURN(TPIPE);
11415                 case ';':
11416                         if (pgetc() == ';')
11417                                 RETURN(TENDCASE);
11418                         pungetc();
11419                         RETURN(TSEMI);
11420                 case '(':
11421                         RETURN(TLP);
11422                 case ')':
11423                         RETURN(TRP);
11424                 default:
11425                         goto breakloop;
11426                 }
11427         }
11428  breakloop:
11429         return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11430 #undef RETURN
11431 }
11432 #endif /* old xxreadtoken */
11433
11434 static int
11435 readtoken(void)
11436 {
11437         int t;
11438 #if DEBUG
11439         smallint alreadyseen = tokpushback;
11440 #endif
11441
11442 #if ENABLE_ASH_ALIAS
11443  top:
11444 #endif
11445
11446         t = xxreadtoken();
11447
11448         /*
11449          * eat newlines
11450          */
11451         if (checkkwd & CHKNL) {
11452                 while (t == TNL) {
11453                         parseheredoc();
11454                         t = xxreadtoken();
11455                 }
11456         }
11457
11458         if (t != TWORD || quoteflag) {
11459                 goto out;
11460         }
11461
11462         /*
11463          * check for keywords
11464          */
11465         if (checkkwd & CHKKWD) {
11466                 const char *const *pp;
11467
11468                 pp = findkwd(wordtext);
11469                 if (pp) {
11470                         lasttoken = t = pp - tokname_array;
11471                         TRACE(("keyword %s recognized\n", tokname(t)));
11472                         goto out;
11473                 }
11474         }
11475
11476         if (checkkwd & CHKALIAS) {
11477 #if ENABLE_ASH_ALIAS
11478                 struct alias *ap;
11479                 ap = lookupalias(wordtext, 1);
11480                 if (ap != NULL) {
11481                         if (*ap->val) {
11482                                 pushstring(ap->val, ap);
11483                         }
11484                         goto top;
11485                 }
11486 #endif
11487         }
11488  out:
11489         checkkwd = 0;
11490 #if DEBUG
11491         if (!alreadyseen)
11492                 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11493         else
11494                 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11495 #endif
11496         return t;
11497 }
11498
11499 static char
11500 peektoken(void)
11501 {
11502         int t;
11503
11504         t = readtoken();
11505         tokpushback = 1;
11506         return tokname_array[t][0];
11507 }
11508
11509 /*
11510  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
11511  * valid parse tree indicating a blank line.)
11512  */
11513 static union node *
11514 parsecmd(int interact)
11515 {
11516         int t;
11517
11518         tokpushback = 0;
11519         doprompt = interact;
11520         if (doprompt)
11521                 setprompt(doprompt);
11522         needprompt = 0;
11523         t = readtoken();
11524         if (t == TEOF)
11525                 return NEOF;
11526         if (t == TNL)
11527                 return NULL;
11528         tokpushback = 1;
11529         return list(1);
11530 }
11531
11532 /*
11533  * Input any here documents.
11534  */
11535 static void
11536 parseheredoc(void)
11537 {
11538         struct heredoc *here;
11539         union node *n;
11540
11541         here = heredoclist;
11542         heredoclist = NULL;
11543
11544         while (here) {
11545                 if (needprompt) {
11546                         setprompt(2);
11547                 }
11548                 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11549                                 here->eofmark, here->striptabs);
11550                 n = stzalloc(sizeof(struct narg));
11551                 n->narg.type = NARG;
11552                 /*n->narg.next = NULL; - stzalloc did it */
11553                 n->narg.text = wordtext;
11554                 n->narg.backquote = backquotelist;
11555                 here->here->nhere.doc = n;
11556                 here = here->next;
11557         }
11558 }
11559
11560
11561 /*
11562  * called by editline -- any expansions to the prompt should be added here.
11563  */
11564 #if ENABLE_ASH_EXPAND_PRMT
11565 static const char *
11566 expandstr(const char *ps)
11567 {
11568         union node n;
11569
11570         /* XXX Fix (char *) cast. */
11571         setinputstring((char *)ps);
11572         readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11573         popfile();
11574
11575         n.narg.type = NARG;
11576         n.narg.next = NULL;
11577         n.narg.text = wordtext;
11578         n.narg.backquote = backquotelist;
11579
11580         expandarg(&n, NULL, 0);
11581         return stackblock();
11582 }
11583 #endif
11584
11585 /*
11586  * Execute a command or commands contained in a string.
11587  */
11588 static int
11589 evalstring(char *s, int mask)
11590 {
11591         union node *n;
11592         struct stackmark smark;
11593         int skip;
11594
11595         setinputstring(s);
11596         setstackmark(&smark);
11597
11598         skip = 0;
11599         while ((n = parsecmd(0)) != NEOF) {
11600                 evaltree(n, 0);
11601                 popstackmark(&smark);
11602                 skip = evalskip;
11603                 if (skip)
11604                         break;
11605         }
11606         popfile();
11607
11608         skip &= mask;
11609         evalskip = skip;
11610         return skip;
11611 }
11612
11613 /*
11614  * The eval command.
11615  */
11616 static int
11617 evalcmd(int argc UNUSED_PARAM, char **argv)
11618 {
11619         char *p;
11620         char *concat;
11621
11622         if (argv[1]) {
11623                 p = argv[1];
11624                 argv += 2;
11625                 if (argv[0]) {
11626                         STARTSTACKSTR(concat);
11627                         for (;;) {
11628                                 concat = stack_putstr(p, concat);
11629                                 p = *argv++;
11630                                 if (p == NULL)
11631                                         break;
11632                                 STPUTC(' ', concat);
11633                         }
11634                         STPUTC('\0', concat);
11635                         p = grabstackstr(concat);
11636                 }
11637                 evalstring(p, ~SKIPEVAL);
11638
11639         }
11640         return exitstatus;
11641 }
11642
11643 /*
11644  * Read and execute commands.  "Top" is nonzero for the top level command
11645  * loop; it turns on prompting if the shell is interactive.
11646  */
11647 static int
11648 cmdloop(int top)
11649 {
11650         union node *n;
11651         struct stackmark smark;
11652         int inter;
11653         int numeof = 0;
11654
11655         TRACE(("cmdloop(%d) called\n", top));
11656         for (;;) {
11657                 int skip;
11658
11659                 setstackmark(&smark);
11660 #if JOBS
11661                 if (doing_jobctl)
11662                         showjobs(stderr, SHOW_CHANGED);
11663 #endif
11664                 inter = 0;
11665                 if (iflag && top) {
11666                         inter++;
11667 #if ENABLE_ASH_MAIL
11668                         chkmail();
11669 #endif
11670                 }
11671                 n = parsecmd(inter);
11672                 /* showtree(n); DEBUG */
11673                 if (n == NEOF) {
11674                         if (!top || numeof >= 50)
11675                                 break;
11676                         if (!stoppedjobs()) {
11677                                 if (!Iflag)
11678                                         break;
11679                                 out2str("\nUse \"exit\" to leave shell.\n");
11680                         }
11681                         numeof++;
11682                 } else if (nflag == 0) {
11683                         /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11684                         job_warning >>= 1;
11685                         numeof = 0;
11686                         evaltree(n, 0);
11687                 }
11688                 popstackmark(&smark);
11689                 skip = evalskip;
11690
11691                 if (skip) {
11692                         evalskip = 0;
11693                         return skip & SKIPEVAL;
11694                 }
11695         }
11696         return 0;
11697 }
11698
11699 /*
11700  * Take commands from a file.  To be compatible we should do a path
11701  * search for the file, which is necessary to find sub-commands.
11702  */
11703 static char *
11704 find_dot_file(char *name)
11705 {
11706         char *fullname;
11707         const char *path = pathval();
11708         struct stat statb;
11709
11710         /* don't try this for absolute or relative paths */
11711         if (strchr(name, '/'))
11712                 return name;
11713
11714         while ((fullname = padvance(&path, name)) != NULL) {
11715                 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11716                         /*
11717                          * Don't bother freeing here, since it will
11718                          * be freed by the caller.
11719                          */
11720                         return fullname;
11721                 }
11722                 stunalloc(fullname);
11723         }
11724
11725         /* not found in the PATH */
11726         ash_msg_and_raise_error("%s: not found", name);
11727         /* NOTREACHED */
11728 }
11729
11730 static int
11731 dotcmd(int argc, char **argv)
11732 {
11733         struct strlist *sp;
11734         volatile struct shparam saveparam;
11735         int status = 0;
11736
11737         for (sp = cmdenviron; sp; sp = sp->next)
11738                 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11739
11740         if (argv[1]) {        /* That's what SVR2 does */
11741                 char *fullname = find_dot_file(argv[1]);
11742                 argv += 2;
11743                 argc -= 2;
11744                 if (argc) { /* argc > 0, argv[0] != NULL */
11745                         saveparam = shellparam;
11746                         shellparam.malloced = 0;
11747                         shellparam.nparam = argc;
11748                         shellparam.p = argv;
11749                 };
11750
11751                 setinputfile(fullname, INPUT_PUSH_FILE);
11752                 commandname = fullname;
11753                 cmdloop(0);
11754                 popfile();
11755
11756                 if (argc) {
11757                         freeparam(&shellparam);
11758                         shellparam = saveparam;
11759                 };
11760                 status = exitstatus;
11761         }
11762         return status;
11763 }
11764
11765 static int
11766 exitcmd(int argc UNUSED_PARAM, char **argv)
11767 {
11768         if (stoppedjobs())
11769                 return 0;
11770         if (argv[1])
11771                 exitstatus = number(argv[1]);
11772         raise_exception(EXEXIT);
11773         /* NOTREACHED */
11774 }
11775
11776 /*
11777  * Read a file containing shell functions.
11778  */
11779 static void
11780 readcmdfile(char *name)
11781 {
11782         setinputfile(name, INPUT_PUSH_FILE);
11783         cmdloop(0);
11784         popfile();
11785 }
11786
11787
11788 /* ============ find_command inplementation */
11789
11790 /*
11791  * Resolve a command name.  If you change this routine, you may have to
11792  * change the shellexec routine as well.
11793  */
11794 static void
11795 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11796 {
11797         struct tblentry *cmdp;
11798         int idx;
11799         int prev;
11800         char *fullname;
11801         struct stat statb;
11802         int e;
11803         int updatetbl;
11804         struct builtincmd *bcmd;
11805
11806         /* If name contains a slash, don't use PATH or hash table */
11807         if (strchr(name, '/') != NULL) {
11808                 entry->u.index = -1;
11809                 if (act & DO_ABS) {
11810                         while (stat(name, &statb) < 0) {
11811 #ifdef SYSV
11812                                 if (errno == EINTR)
11813                                         continue;
11814 #endif
11815                                 entry->cmdtype = CMDUNKNOWN;
11816                                 return;
11817                         }
11818                 }
11819                 entry->cmdtype = CMDNORMAL;
11820                 return;
11821         }
11822
11823 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11824
11825         updatetbl = (path == pathval());
11826         if (!updatetbl) {
11827                 act |= DO_ALTPATH;
11828                 if (strstr(path, "%builtin") != NULL)
11829                         act |= DO_ALTBLTIN;
11830         }
11831
11832         /* If name is in the table, check answer will be ok */
11833         cmdp = cmdlookup(name, 0);
11834         if (cmdp != NULL) {
11835                 int bit;
11836
11837                 switch (cmdp->cmdtype) {
11838                 default:
11839 #if DEBUG
11840                         abort();
11841 #endif
11842                 case CMDNORMAL:
11843                         bit = DO_ALTPATH;
11844                         break;
11845                 case CMDFUNCTION:
11846                         bit = DO_NOFUNC;
11847                         break;
11848                 case CMDBUILTIN:
11849                         bit = DO_ALTBLTIN;
11850                         break;
11851                 }
11852                 if (act & bit) {
11853                         updatetbl = 0;
11854                         cmdp = NULL;
11855                 } else if (cmdp->rehash == 0)
11856                         /* if not invalidated by cd, we're done */
11857                         goto success;
11858         }
11859
11860         /* If %builtin not in path, check for builtin next */
11861         bcmd = find_builtin(name);
11862         if (bcmd) {
11863                 if (IS_BUILTIN_REGULAR(bcmd))
11864                         goto builtin_success;
11865                 if (act & DO_ALTPATH) {
11866                         if (!(act & DO_ALTBLTIN))
11867                                 goto builtin_success;
11868                 } else if (builtinloc <= 0) {
11869                         goto builtin_success;
11870                 }
11871         }
11872
11873 #if ENABLE_FEATURE_SH_STANDALONE
11874         {
11875                 int applet_no = find_applet_by_name(name);
11876                 if (applet_no >= 0) {
11877                         entry->cmdtype = CMDNORMAL;
11878                         entry->u.index = -2 - applet_no;
11879                         return;
11880                 }
11881         }
11882 #endif
11883
11884         /* We have to search path. */
11885         prev = -1;              /* where to start */
11886         if (cmdp && cmdp->rehash) {     /* doing a rehash */
11887                 if (cmdp->cmdtype == CMDBUILTIN)
11888                         prev = builtinloc;
11889                 else
11890                         prev = cmdp->param.index;
11891         }
11892
11893         e = ENOENT;
11894         idx = -1;
11895  loop:
11896         while ((fullname = padvance(&path, name)) != NULL) {
11897                 stunalloc(fullname);
11898                 /* NB: code below will still use fullname
11899                  * despite it being "unallocated" */
11900                 idx++;
11901                 if (pathopt) {
11902                         if (prefix(pathopt, "builtin")) {
11903                                 if (bcmd)
11904                                         goto builtin_success;
11905                                 continue;
11906                         }
11907                         if ((act & DO_NOFUNC)
11908                          || !prefix(pathopt, "func")
11909                         ) {     /* ignore unimplemented options */
11910                                 continue;
11911                         }
11912                 }
11913                 /* if rehash, don't redo absolute path names */
11914                 if (fullname[0] == '/' && idx <= prev) {
11915                         if (idx < prev)
11916                                 continue;
11917                         TRACE(("searchexec \"%s\": no change\n", name));
11918                         goto success;
11919                 }
11920                 while (stat(fullname, &statb) < 0) {
11921 #ifdef SYSV
11922                         if (errno == EINTR)
11923                                 continue;
11924 #endif
11925                         if (errno != ENOENT && errno != ENOTDIR)
11926                                 e = errno;
11927                         goto loop;
11928                 }
11929                 e = EACCES;     /* if we fail, this will be the error */
11930                 if (!S_ISREG(statb.st_mode))
11931                         continue;
11932                 if (pathopt) {          /* this is a %func directory */
11933                         stalloc(strlen(fullname) + 1);
11934                         /* NB: stalloc will return space pointed by fullname
11935                          * (because we don't have any intervening allocations
11936                          * between stunalloc above and this stalloc) */
11937                         readcmdfile(fullname);
11938                         cmdp = cmdlookup(name, 0);
11939                         if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11940                                 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11941                         stunalloc(fullname);
11942                         goto success;
11943                 }
11944                 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11945                 if (!updatetbl) {
11946                         entry->cmdtype = CMDNORMAL;
11947                         entry->u.index = idx;
11948                         return;
11949                 }
11950                 INT_OFF;
11951                 cmdp = cmdlookup(name, 1);
11952                 cmdp->cmdtype = CMDNORMAL;
11953                 cmdp->param.index = idx;
11954                 INT_ON;
11955                 goto success;
11956         }
11957
11958         /* We failed.  If there was an entry for this command, delete it */
11959         if (cmdp && updatetbl)
11960                 delete_cmd_entry();
11961         if (act & DO_ERR)
11962                 ash_msg("%s: %s", name, errmsg(e, "not found"));
11963         entry->cmdtype = CMDUNKNOWN;
11964         return;
11965
11966  builtin_success:
11967         if (!updatetbl) {
11968                 entry->cmdtype = CMDBUILTIN;
11969                 entry->u.cmd = bcmd;
11970                 return;
11971         }
11972         INT_OFF;
11973         cmdp = cmdlookup(name, 1);
11974         cmdp->cmdtype = CMDBUILTIN;
11975         cmdp->param.cmd = bcmd;
11976         INT_ON;
11977  success:
11978         cmdp->rehash = 0;
11979         entry->cmdtype = cmdp->cmdtype;
11980         entry->u = cmdp->param;
11981 }
11982
11983
11984 /* ============ trap.c */
11985
11986 /*
11987  * The trap builtin.
11988  */
11989 static int
11990 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11991 {
11992         char *action;
11993         char **ap;
11994         int signo;
11995
11996         nextopt(nullstr);
11997         ap = argptr;
11998         if (!*ap) {
11999                 for (signo = 0; signo < NSIG; signo++) {
12000                         if (trap[signo] != NULL) {
12001                                 out1fmt("trap -- %s %s\n",
12002                                                 single_quote(trap[signo]),
12003                                                 get_signame(signo));
12004                         }
12005                 }
12006                 return 0;
12007         }
12008         action = NULL;
12009         if (ap[1])
12010                 action = *ap++;
12011         while (*ap) {
12012                 signo = get_signum(*ap);
12013                 if (signo < 0)
12014                         ash_msg_and_raise_error("%s: bad trap", *ap);
12015                 INT_OFF;
12016                 if (action) {
12017                         if (LONE_DASH(action))
12018                                 action = NULL;
12019                         else
12020                                 action = ckstrdup(action);
12021                 }
12022                 free(trap[signo]);
12023                 trap[signo] = action;
12024                 if (signo != 0)
12025                         setsignal(signo);
12026                 INT_ON;
12027                 ap++;
12028         }
12029         return 0;
12030 }
12031
12032
12033 /* ============ Builtins */
12034
12035 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12036 /*
12037  * Lists available builtins
12038  */
12039 static int
12040 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12041 {
12042         unsigned col;
12043         unsigned i;
12044
12045         out1fmt("\nBuilt-in commands:\n-------------------\n");
12046         for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12047                 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12048                                         builtintab[i].name + 1);
12049                 if (col > 60) {
12050                         out1fmt("\n");
12051                         col = 0;
12052                 }
12053         }
12054 #if ENABLE_FEATURE_SH_STANDALONE
12055         {
12056                 const char *a = applet_names;
12057                 while (*a) {
12058                         col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12059                         if (col > 60) {
12060                                 out1fmt("\n");
12061                                 col = 0;
12062                         }
12063                         a += strlen(a) + 1;
12064                 }
12065         }
12066 #endif
12067         out1fmt("\n\n");
12068         return EXIT_SUCCESS;
12069 }
12070 #endif /* FEATURE_SH_EXTRA_QUIET */
12071
12072 /*
12073  * The export and readonly commands.
12074  */
12075 static int
12076 exportcmd(int argc UNUSED_PARAM, char **argv)
12077 {
12078         struct var *vp;
12079         char *name;
12080         const char *p;
12081         char **aptr;
12082         int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
12083
12084         if (nextopt("p") != 'p') {
12085                 aptr = argptr;
12086                 name = *aptr;
12087                 if (name) {
12088                         do {
12089                                 p = strchr(name, '=');
12090                                 if (p != NULL) {
12091                                         p++;
12092                                 } else {
12093                                         vp = *findvar(hashvar(name), name);
12094                                         if (vp) {
12095                                                 vp->flags |= flag;
12096                                                 continue;
12097                                         }
12098                                 }
12099                                 setvar(name, p, flag);
12100                         } while ((name = *++aptr) != NULL);
12101                         return 0;
12102                 }
12103         }
12104         showvars(argv[0], flag, 0);
12105         return 0;
12106 }
12107
12108 /*
12109  * Delete a function if it exists.
12110  */
12111 static void
12112 unsetfunc(const char *name)
12113 {
12114         struct tblentry *cmdp;
12115
12116         cmdp = cmdlookup(name, 0);
12117         if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
12118                 delete_cmd_entry();
12119 }
12120
12121 /*
12122  * The unset builtin command.  We unset the function before we unset the
12123  * variable to allow a function to be unset when there is a readonly variable
12124  * with the same name.
12125  */
12126 static int
12127 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12128 {
12129         char **ap;
12130         int i;
12131         int flag = 0;
12132         int ret = 0;
12133
12134         while ((i = nextopt("vf")) != '\0') {
12135                 flag = i;
12136         }
12137
12138         for (ap = argptr; *ap; ap++) {
12139                 if (flag != 'f') {
12140                         i = unsetvar(*ap);
12141                         ret |= i;
12142                         if (!(i & 2))
12143                                 continue;
12144                 }
12145                 if (flag != 'v')
12146                         unsetfunc(*ap);
12147         }
12148         return ret & 1;
12149 }
12150
12151
12152 /*      setmode.c      */
12153
12154 #include <sys/times.h>
12155
12156 static const unsigned char timescmd_str[] ALIGN1 = {
12157         ' ',  offsetof(struct tms, tms_utime),
12158         '\n', offsetof(struct tms, tms_stime),
12159         ' ',  offsetof(struct tms, tms_cutime),
12160         '\n', offsetof(struct tms, tms_cstime),
12161         0
12162 };
12163
12164 static int
12165 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12166 {
12167         long clk_tck, s, t;
12168         const unsigned char *p;
12169         struct tms buf;
12170
12171         clk_tck = sysconf(_SC_CLK_TCK);
12172         times(&buf);
12173
12174         p = timescmd_str;
12175         do {
12176                 t = *(clock_t *)(((char *) &buf) + p[1]);
12177                 s = t / clk_tck;
12178                 out1fmt("%ldm%ld.%.3lds%c",
12179                         s/60, s%60,
12180                         ((t - s * clk_tck) * 1000) / clk_tck,
12181                         p[0]);
12182         } while (*(p += 2));
12183
12184         return 0;
12185 }
12186
12187 #if ENABLE_ASH_MATH_SUPPORT
12188 static arith_t
12189 dash_arith(const char *s)
12190 {
12191         arith_t result;
12192         int errcode = 0;
12193
12194         INT_OFF;
12195         result = arith(s, &errcode);
12196         if (errcode < 0) {
12197                 if (errcode == -3)
12198                         ash_msg_and_raise_error("exponent less than 0");
12199                 if (errcode == -2)
12200                         ash_msg_and_raise_error("divide by zero");
12201                 if (errcode == -5)
12202                         ash_msg_and_raise_error("expression recursion loop detected");
12203                 raise_error_syntax(s);
12204         }
12205         INT_ON;
12206
12207         return result;
12208 }
12209
12210 /*
12211  *  The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12212  *  Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12213  *
12214  *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12215  */
12216 static int
12217 letcmd(int argc UNUSED_PARAM, char **argv)
12218 {
12219         arith_t i;
12220
12221         argv++;
12222         if (!*argv)
12223                 ash_msg_and_raise_error("expression expected");
12224         do {
12225                 i = dash_arith(*argv);
12226         } while (*++argv);
12227
12228         return !i;
12229 }
12230 #endif /* ASH_MATH_SUPPORT */
12231
12232
12233 /* ============ miscbltin.c
12234  *
12235  * Miscellaneous builtins.
12236  */
12237
12238 #undef rflag
12239
12240 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12241 typedef enum __rlimit_resource rlim_t;
12242 #endif
12243
12244 /*
12245  * The read builtin. Options:
12246  *      -r              Do not interpret '\' specially
12247  *      -s              Turn off echo (tty only)
12248  *      -n NCHARS       Read NCHARS max
12249  *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
12250  *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
12251  *      -u FD           Read from given FD instead of fd 0
12252  * This uses unbuffered input, which may be avoidable in some cases.
12253  * TODO: bash also has:
12254  *      -a ARRAY        Read into array[0],[1],etc
12255  *      -d DELIM        End on DELIM char, not newline
12256  *      -e              Use line editing (tty only)
12257  */
12258 static int
12259 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12260 {
12261         static const char *const arg_REPLY[] = { "REPLY", NULL };
12262
12263         char **ap;
12264         int backslash;
12265         char c;
12266         int rflag;
12267         char *prompt;
12268         const char *ifs;
12269         char *p;
12270         int startword;
12271         int status;
12272         int i;
12273         int fd = 0;
12274 #if ENABLE_ASH_READ_NCHARS
12275         int nchars = 0; /* if != 0, -n is in effect */
12276         int silent = 0;
12277         struct termios tty, old_tty;
12278 #endif
12279 #if ENABLE_ASH_READ_TIMEOUT
12280         unsigned end_ms = 0;
12281         unsigned timeout = 0;
12282 #endif
12283
12284         rflag = 0;
12285         prompt = NULL;
12286         while ((i = nextopt("p:u:r"
12287                 USE_ASH_READ_TIMEOUT("t:")
12288                 USE_ASH_READ_NCHARS("n:s")
12289         )) != '\0') {
12290                 switch (i) {
12291                 case 'p':
12292                         prompt = optionarg;
12293                         break;
12294 #if ENABLE_ASH_READ_NCHARS
12295                 case 'n':
12296                         nchars = bb_strtou(optionarg, NULL, 10);
12297                         if (nchars < 0 || errno)
12298                                 ash_msg_and_raise_error("invalid count");
12299                         /* nchars == 0: off (bash 3.2 does this too) */
12300                         break;
12301                 case 's':
12302                         silent = 1;
12303                         break;
12304 #endif
12305 #if ENABLE_ASH_READ_TIMEOUT
12306                 case 't':
12307                         timeout = bb_strtou(optionarg, NULL, 10);
12308                         if (errno || timeout > UINT_MAX / 2048)
12309                                 ash_msg_and_raise_error("invalid timeout");
12310                         timeout *= 1000;
12311 #if 0 /* even bash have no -t N.NNN support */
12312                         ts.tv_sec = bb_strtou(optionarg, &p, 10);
12313                         ts.tv_usec = 0;
12314                         /* EINVAL means number is ok, but not terminated by NUL */
12315                         if (*p == '.' && errno == EINVAL) {
12316                                 char *p2;
12317                                 if (*++p) {
12318                                         int scale;
12319                                         ts.tv_usec = bb_strtou(p, &p2, 10);
12320                                         if (errno)
12321                                                 ash_msg_and_raise_error("invalid timeout");
12322                                         scale = p2 - p;
12323                                         /* normalize to usec */
12324                                         if (scale > 6)
12325                                                 ash_msg_and_raise_error("invalid timeout");
12326                                         while (scale++ < 6)
12327                                                 ts.tv_usec *= 10;
12328                                 }
12329                         } else if (ts.tv_sec < 0 || errno) {
12330                                 ash_msg_and_raise_error("invalid timeout");
12331                         }
12332                         if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12333                                 ash_msg_and_raise_error("invalid timeout");
12334                         }
12335 #endif /* if 0 */
12336                         break;
12337 #endif
12338                 case 'r':
12339                         rflag = 1;
12340                         break;
12341                 case 'u':
12342                         fd = bb_strtou(optionarg, NULL, 10);
12343                         if (fd < 0 || errno)
12344                                 ash_msg_and_raise_error("invalid file descriptor");
12345                         break;
12346                 default:
12347                         break;
12348                 }
12349         }
12350         if (prompt && isatty(fd)) {
12351                 out2str(prompt);
12352         }
12353         ap = argptr;
12354         if (*ap == NULL)
12355                 ap = (char**)arg_REPLY;
12356         ifs = bltinlookup("IFS");
12357         if (ifs == NULL)
12358                 ifs = defifs;
12359 #if ENABLE_ASH_READ_NCHARS
12360         tcgetattr(fd, &tty);
12361         old_tty = tty;
12362         if (nchars || silent) {
12363                 if (nchars) {
12364                         tty.c_lflag &= ~ICANON;
12365                         tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12366                 }
12367                 if (silent) {
12368                         tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12369                 }
12370                 /* if tcgetattr failed, tcsetattr will fail too.
12371                  * Ignoring, it's harmless. */
12372                 tcsetattr(fd, TCSANOW, &tty);
12373         }
12374 #endif
12375
12376         status = 0;
12377         startword = 1;
12378         backslash = 0;
12379 #if ENABLE_ASH_READ_TIMEOUT
12380         if (timeout) /* NB: ensuring end_ms is nonzero */
12381                 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12382 #endif
12383         STARTSTACKSTR(p);
12384         do {
12385 #if ENABLE_ASH_READ_TIMEOUT
12386                 if (end_ms) {
12387                         struct pollfd pfd[1];
12388                         pfd[0].fd = fd;
12389                         pfd[0].events = POLLIN;
12390                         timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12391                         if ((int)timeout <= 0 /* already late? */
12392                          || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12393                         ) { /* timed out! */
12394 #if ENABLE_ASH_READ_NCHARS
12395                                 tcsetattr(fd, TCSANOW, &old_tty);
12396 #endif
12397                                 return 1;
12398                         }
12399                 }
12400 #endif
12401                 if (nonblock_safe_read(fd, &c, 1) != 1) {
12402                         status = 1;
12403                         break;
12404                 }
12405                 if (c == '\0')
12406                         continue;
12407                 if (backslash) {
12408                         backslash = 0;
12409                         if (c != '\n')
12410                                 goto put;
12411                         continue;
12412                 }
12413                 if (!rflag && c == '\\') {
12414                         backslash++;
12415                         continue;
12416                 }
12417                 if (c == '\n')
12418                         break;
12419                 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12420                         continue;
12421                 }
12422                 startword = 0;
12423                 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12424                         STACKSTRNUL(p);
12425                         setvar(*ap, stackblock(), 0);
12426                         ap++;
12427                         startword = 1;
12428                         STARTSTACKSTR(p);
12429                 } else {
12430  put:
12431                         STPUTC(c, p);
12432                 }
12433         }
12434 /* end of do {} while: */
12435 #if ENABLE_ASH_READ_NCHARS
12436         while (--nchars);
12437 #else
12438         while (1);
12439 #endif
12440
12441 #if ENABLE_ASH_READ_NCHARS
12442         tcsetattr(fd, TCSANOW, &old_tty);
12443 #endif
12444
12445         STACKSTRNUL(p);
12446         /* Remove trailing blanks */
12447         while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12448                 *p = '\0';
12449         setvar(*ap, stackblock(), 0);
12450         while (*++ap != NULL)
12451                 setvar(*ap, nullstr, 0);
12452         return status;
12453 }
12454
12455 static int
12456 umaskcmd(int argc UNUSED_PARAM, char **argv)
12457 {
12458         static const char permuser[3] ALIGN1 = "ugo";
12459         static const char permmode[3] ALIGN1 = "rwx";
12460         static const short permmask[] ALIGN2 = {
12461                 S_IRUSR, S_IWUSR, S_IXUSR,
12462                 S_IRGRP, S_IWGRP, S_IXGRP,
12463                 S_IROTH, S_IWOTH, S_IXOTH
12464         };
12465
12466         char *ap;
12467         mode_t mask;
12468         int i;
12469         int symbolic_mode = 0;
12470
12471         while (nextopt("S") != '\0') {
12472                 symbolic_mode = 1;
12473         }
12474
12475         INT_OFF;
12476         mask = umask(0);
12477         umask(mask);
12478         INT_ON;
12479
12480         ap = *argptr;
12481         if (ap == NULL) {
12482                 if (symbolic_mode) {
12483                         char buf[18];
12484                         char *p = buf;
12485
12486                         for (i = 0; i < 3; i++) {
12487                                 int j;
12488
12489                                 *p++ = permuser[i];
12490                                 *p++ = '=';
12491                                 for (j = 0; j < 3; j++) {
12492                                         if ((mask & permmask[3 * i + j]) == 0) {
12493                                                 *p++ = permmode[j];
12494                                         }
12495                                 }
12496                                 *p++ = ',';
12497                         }
12498                         *--p = 0;
12499                         puts(buf);
12500                 } else {
12501                         out1fmt("%.4o\n", mask);
12502                 }
12503         } else {
12504                 if (isdigit((unsigned char) *ap)) {
12505                         mask = 0;
12506                         do {
12507                                 if (*ap >= '8' || *ap < '0')
12508                                         ash_msg_and_raise_error(illnum, argv[1]);
12509                                 mask = (mask << 3) + (*ap - '0');
12510                         } while (*++ap != '\0');
12511                         umask(mask);
12512                 } else {
12513                         mask = ~mask & 0777;
12514                         if (!bb_parse_mode(ap, &mask)) {
12515                                 ash_msg_and_raise_error("illegal mode: %s", ap);
12516                         }
12517                         umask(~mask & 0777);
12518                 }
12519         }
12520         return 0;
12521 }
12522
12523 /*
12524  * ulimit builtin
12525  *
12526  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12527  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12528  * ash by J.T. Conklin.
12529  *
12530  * Public domain.
12531  */
12532
12533 struct limits {
12534         uint8_t cmd;          /* RLIMIT_xxx fit into it */
12535         uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12536         char    option;
12537 };
12538
12539 static const struct limits limits_tbl[] = {
12540 #ifdef RLIMIT_CPU
12541         { RLIMIT_CPU,        0, 't' },
12542 #endif
12543 #ifdef RLIMIT_FSIZE
12544         { RLIMIT_FSIZE,      9, 'f' },
12545 #endif
12546 #ifdef RLIMIT_DATA
12547         { RLIMIT_DATA,      10, 'd' },
12548 #endif
12549 #ifdef RLIMIT_STACK
12550         { RLIMIT_STACK,     10, 's' },
12551 #endif
12552 #ifdef RLIMIT_CORE
12553         { RLIMIT_CORE,       9, 'c' },
12554 #endif
12555 #ifdef RLIMIT_RSS
12556         { RLIMIT_RSS,       10, 'm' },
12557 #endif
12558 #ifdef RLIMIT_MEMLOCK
12559         { RLIMIT_MEMLOCK,   10, 'l' },
12560 #endif
12561 #ifdef RLIMIT_NPROC
12562         { RLIMIT_NPROC,      0, 'p' },
12563 #endif
12564 #ifdef RLIMIT_NOFILE
12565         { RLIMIT_NOFILE,     0, 'n' },
12566 #endif
12567 #ifdef RLIMIT_AS
12568         { RLIMIT_AS,        10, 'v' },
12569 #endif
12570 #ifdef RLIMIT_LOCKS
12571         { RLIMIT_LOCKS,      0, 'w' },
12572 #endif
12573 };
12574 static const char limits_name[] =
12575 #ifdef RLIMIT_CPU
12576         "time(seconds)" "\0"
12577 #endif
12578 #ifdef RLIMIT_FSIZE
12579         "file(blocks)" "\0"
12580 #endif
12581 #ifdef RLIMIT_DATA
12582         "data(kb)" "\0"
12583 #endif
12584 #ifdef RLIMIT_STACK
12585         "stack(kb)" "\0"
12586 #endif
12587 #ifdef RLIMIT_CORE
12588         "coredump(blocks)" "\0"
12589 #endif
12590 #ifdef RLIMIT_RSS
12591         "memory(kb)" "\0"
12592 #endif
12593 #ifdef RLIMIT_MEMLOCK
12594         "locked memory(kb)" "\0"
12595 #endif
12596 #ifdef RLIMIT_NPROC
12597         "process" "\0"
12598 #endif
12599 #ifdef RLIMIT_NOFILE
12600         "nofiles" "\0"
12601 #endif
12602 #ifdef RLIMIT_AS
12603         "vmemory(kb)" "\0"
12604 #endif
12605 #ifdef RLIMIT_LOCKS
12606         "locks" "\0"
12607 #endif
12608 ;
12609
12610 enum limtype { SOFT = 0x1, HARD = 0x2 };
12611
12612 static void
12613 printlim(enum limtype how, const struct rlimit *limit,
12614                         const struct limits *l)
12615 {
12616         rlim_t val;
12617
12618         val = limit->rlim_max;
12619         if (how & SOFT)
12620                 val = limit->rlim_cur;
12621
12622         if (val == RLIM_INFINITY)
12623                 out1fmt("unlimited\n");
12624         else {
12625                 val >>= l->factor_shift;
12626                 out1fmt("%lld\n", (long long) val);
12627         }
12628 }
12629
12630 static int
12631 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12632 {
12633         int c;
12634         rlim_t val = 0;
12635         enum limtype how = SOFT | HARD;
12636         const struct limits *l;
12637         int set, all = 0;
12638         int optc, what;
12639         struct rlimit limit;
12640
12641         what = 'f';
12642         while ((optc = nextopt("HSa"
12643 #ifdef RLIMIT_CPU
12644                                 "t"
12645 #endif
12646 #ifdef RLIMIT_FSIZE
12647                                 "f"
12648 #endif
12649 #ifdef RLIMIT_DATA
12650                                 "d"
12651 #endif
12652 #ifdef RLIMIT_STACK
12653                                 "s"
12654 #endif
12655 #ifdef RLIMIT_CORE
12656                                 "c"
12657 #endif
12658 #ifdef RLIMIT_RSS
12659                                 "m"
12660 #endif
12661 #ifdef RLIMIT_MEMLOCK
12662                                 "l"
12663 #endif
12664 #ifdef RLIMIT_NPROC
12665                                 "p"
12666 #endif
12667 #ifdef RLIMIT_NOFILE
12668                                 "n"
12669 #endif
12670 #ifdef RLIMIT_AS
12671                                 "v"
12672 #endif
12673 #ifdef RLIMIT_LOCKS
12674                                 "w"
12675 #endif
12676                                         )) != '\0')
12677                 switch (optc) {
12678                 case 'H':
12679                         how = HARD;
12680                         break;
12681                 case 'S':
12682                         how = SOFT;
12683                         break;
12684                 case 'a':
12685                         all = 1;
12686                         break;
12687                 default:
12688                         what = optc;
12689                 }
12690
12691         for (l = limits_tbl; l->option != what; l++)
12692                 continue;
12693
12694         set = *argptr ? 1 : 0;
12695         if (set) {
12696                 char *p = *argptr;
12697
12698                 if (all || argptr[1])
12699                         ash_msg_and_raise_error("too many arguments");
12700                 if (strncmp(p, "unlimited\n", 9) == 0)
12701                         val = RLIM_INFINITY;
12702                 else {
12703                         val = (rlim_t) 0;
12704
12705                         while ((c = *p++) >= '0' && c <= '9') {
12706                                 val = (val * 10) + (long)(c - '0');
12707                                 // val is actually 'unsigned long int' and can't get < 0
12708                                 if (val < (rlim_t) 0)
12709                                         break;
12710                         }
12711                         if (c)
12712                                 ash_msg_and_raise_error("bad number");
12713                         val <<= l->factor_shift;
12714                 }
12715         }
12716         if (all) {
12717                 const char *lname = limits_name;
12718                 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12719                         getrlimit(l->cmd, &limit);
12720                         out1fmt("%-20s ", lname);
12721                         lname += strlen(lname) + 1;
12722                         printlim(how, &limit, l);
12723                 }
12724                 return 0;
12725         }
12726
12727         getrlimit(l->cmd, &limit);
12728         if (set) {
12729                 if (how & HARD)
12730                         limit.rlim_max = val;
12731                 if (how & SOFT)
12732                         limit.rlim_cur = val;
12733                 if (setrlimit(l->cmd, &limit) < 0)
12734                         ash_msg_and_raise_error("error setting limit (%m)");
12735         } else {
12736                 printlim(how, &limit, l);
12737         }
12738         return 0;
12739 }
12740
12741
12742 /* ============ Math support */
12743
12744 #if ENABLE_ASH_MATH_SUPPORT
12745
12746 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12747
12748    Permission is hereby granted, free of charge, to any person obtaining
12749    a copy of this software and associated documentation files (the
12750    "Software"), to deal in the Software without restriction, including
12751    without limitation the rights to use, copy, modify, merge, publish,
12752    distribute, sublicense, and/or sell copies of the Software, and to
12753    permit persons to whom the Software is furnished to do so, subject to
12754    the following conditions:
12755
12756    The above copyright notice and this permission notice shall be
12757    included in all copies or substantial portions of the Software.
12758
12759    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12760    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12761    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12762    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12763    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12764    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12765    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12766 */
12767
12768 /* This is my infix parser/evaluator. It is optimized for size, intended
12769  * as a replacement for yacc-based parsers. However, it may well be faster
12770  * than a comparable parser written in yacc. The supported operators are
12771  * listed in #defines below. Parens, order of operations, and error handling
12772  * are supported. This code is thread safe. The exact expression format should
12773  * be that which POSIX specifies for shells. */
12774
12775 /* The code uses a simple two-stack algorithm. See
12776  * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12777  * for a detailed explanation of the infix-to-postfix algorithm on which
12778  * this is based (this code differs in that it applies operators immediately
12779  * to the stack instead of adding them to a queue to end up with an
12780  * expression). */
12781
12782 /* To use the routine, call it with an expression string and error return
12783  * pointer */
12784
12785 /*
12786  * Aug 24, 2001              Manuel Novoa III
12787  *
12788  * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12789  *
12790  * 1) In arith_apply():
12791  *    a) Cached values of *numptr and &(numptr[-1]).
12792  *    b) Removed redundant test for zero denominator.
12793  *
12794  * 2) In arith():
12795  *    a) Eliminated redundant code for processing operator tokens by moving
12796  *       to a table-based implementation.  Also folded handling of parens
12797  *       into the table.
12798  *    b) Combined all 3 loops which called arith_apply to reduce generated
12799  *       code size at the cost of speed.
12800  *
12801  * 3) The following expressions were treated as valid by the original code:
12802  *       1()  ,    0!  ,    1 ( *3 )   .
12803  *    These bugs have been fixed by internally enclosing the expression in
12804  *    parens and then checking that all binary ops and right parens are
12805  *    preceded by a valid expression (NUM_TOKEN).
12806  *
12807  * Note: It may be desirable to replace Aaron's test for whitespace with
12808  * ctype's isspace() if it is used by another busybox applet or if additional
12809  * whitespace chars should be considered.  Look below the "#include"s for a
12810  * precompiler test.
12811  */
12812
12813 /*
12814  * Aug 26, 2001              Manuel Novoa III
12815  *
12816  * Return 0 for null expressions.  Pointed out by Vladimir Oleynik.
12817  *
12818  * Merge in Aaron's comments previously posted to the busybox list,
12819  * modified slightly to take account of my changes to the code.
12820  *
12821  */
12822
12823 /*
12824  *  (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12825  *
12826  * - allow access to variable,
12827  *   used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12828  * - realize assign syntax (VAR=expr, +=, *= etc)
12829  * - realize exponentiation (** operator)
12830  * - realize comma separated - expr, expr
12831  * - realise ++expr --expr expr++ expr--
12832  * - realise expr ? expr : expr (but, second expr calculate always)
12833  * - allow hexadecimal and octal numbers
12834  * - was restored loses XOR operator
12835  * - remove one goto label, added three ;-)
12836  * - protect $((num num)) as true zero expr (Manuel`s error)
12837  * - always use special isspace(), see comment from bash ;-)
12838  */
12839
12840 #define arith_isspace(arithval) \
12841         (arithval == ' ' || arithval == '\n' || arithval == '\t')
12842
12843 typedef unsigned char operator;
12844
12845 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12846  * precedence, and 3 high bits are an ID unique across operators of that
12847  * precedence. The ID portion is so that multiple operators can have the
12848  * same precedence, ensuring that the leftmost one is evaluated first.
12849  * Consider * and /. */
12850
12851 #define tok_decl(prec,id) (((id)<<5)|(prec))
12852 #define PREC(op) ((op) & 0x1F)
12853
12854 #define TOK_LPAREN tok_decl(0,0)
12855
12856 #define TOK_COMMA tok_decl(1,0)
12857
12858 #define TOK_ASSIGN tok_decl(2,0)
12859 #define TOK_AND_ASSIGN tok_decl(2,1)
12860 #define TOK_OR_ASSIGN tok_decl(2,2)
12861 #define TOK_XOR_ASSIGN tok_decl(2,3)
12862 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12863 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12864 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12865 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12866
12867 #define TOK_MUL_ASSIGN tok_decl(3,0)
12868 #define TOK_DIV_ASSIGN tok_decl(3,1)
12869 #define TOK_REM_ASSIGN tok_decl(3,2)
12870
12871 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12872 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12873
12874 /* conditional is right associativity too */
12875 #define TOK_CONDITIONAL tok_decl(4,0)
12876 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12877
12878 #define TOK_OR tok_decl(5,0)
12879
12880 #define TOK_AND tok_decl(6,0)
12881
12882 #define TOK_BOR tok_decl(7,0)
12883
12884 #define TOK_BXOR tok_decl(8,0)
12885
12886 #define TOK_BAND tok_decl(9,0)
12887
12888 #define TOK_EQ tok_decl(10,0)
12889 #define TOK_NE tok_decl(10,1)
12890
12891 #define TOK_LT tok_decl(11,0)
12892 #define TOK_GT tok_decl(11,1)
12893 #define TOK_GE tok_decl(11,2)
12894 #define TOK_LE tok_decl(11,3)
12895
12896 #define TOK_LSHIFT tok_decl(12,0)
12897 #define TOK_RSHIFT tok_decl(12,1)
12898
12899 #define TOK_ADD tok_decl(13,0)
12900 #define TOK_SUB tok_decl(13,1)
12901
12902 #define TOK_MUL tok_decl(14,0)
12903 #define TOK_DIV tok_decl(14,1)
12904 #define TOK_REM tok_decl(14,2)
12905
12906 /* exponent is right associativity */
12907 #define TOK_EXPONENT tok_decl(15,1)
12908
12909 /* For now unary operators. */
12910 #define UNARYPREC 16
12911 #define TOK_BNOT tok_decl(UNARYPREC,0)
12912 #define TOK_NOT tok_decl(UNARYPREC,1)
12913
12914 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12915 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12916
12917 #define PREC_PRE (UNARYPREC+2)
12918
12919 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12920 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12921
12922 #define PREC_POST (UNARYPREC+3)
12923
12924 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12925 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12926
12927 #define SPEC_PREC (UNARYPREC+4)
12928
12929 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12930 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12931
12932 #define NUMPTR (*numstackptr)
12933
12934 static int
12935 tok_have_assign(operator op)
12936 {
12937         operator prec = PREC(op);
12938
12939         convert_prec_is_assing(prec);
12940         return (prec == PREC(TOK_ASSIGN) ||
12941                         prec == PREC_PRE || prec == PREC_POST);
12942 }
12943
12944 static int
12945 is_right_associativity(operator prec)
12946 {
12947         return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12948                 || prec == PREC(TOK_CONDITIONAL));
12949 }
12950
12951 typedef struct {
12952         arith_t val;
12953         arith_t contidional_second_val;
12954         char contidional_second_val_initialized;
12955         char *var;      /* if NULL then is regular number,
12956                            else is variable name */
12957 } v_n_t;
12958
12959 typedef struct chk_var_recursive_looped_t {
12960         const char *var;
12961         struct chk_var_recursive_looped_t *next;
12962 } chk_var_recursive_looped_t;
12963
12964 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12965
12966 static int
12967 arith_lookup_val(v_n_t *t)
12968 {
12969         if (t->var) {
12970                 const char * p = lookupvar(t->var);
12971
12972                 if (p) {
12973                         int errcode;
12974
12975                         /* recursive try as expression */
12976                         chk_var_recursive_looped_t *cur;
12977                         chk_var_recursive_looped_t cur_save;
12978
12979                         for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12980                                 if (strcmp(cur->var, t->var) == 0) {
12981                                         /* expression recursion loop detected */
12982                                         return -5;
12983                                 }
12984                         }
12985                         /* save current lookuped var name */
12986                         cur = prev_chk_var_recursive;
12987                         cur_save.var = t->var;
12988                         cur_save.next = cur;
12989                         prev_chk_var_recursive = &cur_save;
12990
12991                         t->val = arith (p, &errcode);
12992                         /* restore previous ptr after recursiving */
12993                         prev_chk_var_recursive = cur;
12994                         return errcode;
12995                 }
12996                 /* allow undefined var as 0 */
12997                 t->val = 0;
12998         }
12999         return 0;
13000 }
13001
13002 /* "applying" a token means performing it on the top elements on the integer
13003  * stack. For a unary operator it will only change the top element, but a
13004  * binary operator will pop two arguments and push a result */
13005 static int
13006 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13007 {
13008         v_n_t *numptr_m1;
13009         arith_t numptr_val, rez;
13010         int ret_arith_lookup_val;
13011
13012         /* There is no operator that can work without arguments */
13013         if (NUMPTR == numstack) goto err;
13014         numptr_m1 = NUMPTR - 1;
13015
13016         /* check operand is var with noninteger value */
13017         ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13018         if (ret_arith_lookup_val)
13019                 return ret_arith_lookup_val;
13020
13021         rez = numptr_m1->val;
13022         if (op == TOK_UMINUS)
13023                 rez *= -1;
13024         else if (op == TOK_NOT)
13025                 rez = !rez;
13026         else if (op == TOK_BNOT)
13027                 rez = ~rez;
13028         else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13029                 rez++;
13030         else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13031                 rez--;
13032         else if (op != TOK_UPLUS) {
13033                 /* Binary operators */
13034
13035                 /* check and binary operators need two arguments */
13036                 if (numptr_m1 == numstack) goto err;
13037
13038                 /* ... and they pop one */
13039                 --NUMPTR;
13040                 numptr_val = rez;
13041                 if (op == TOK_CONDITIONAL) {
13042                         if (!numptr_m1->contidional_second_val_initialized) {
13043                                 /* protect $((expr1 ? expr2)) without ": expr" */
13044                                 goto err;
13045                         }
13046                         rez = numptr_m1->contidional_second_val;
13047                 } else if (numptr_m1->contidional_second_val_initialized) {
13048                         /* protect $((expr1 : expr2)) without "expr ? " */
13049                         goto err;
13050                 }
13051                 numptr_m1 = NUMPTR - 1;
13052                 if (op != TOK_ASSIGN) {
13053                         /* check operand is var with noninteger value for not '=' */
13054                         ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13055                         if (ret_arith_lookup_val)
13056                                 return ret_arith_lookup_val;
13057                 }
13058                 if (op == TOK_CONDITIONAL) {
13059                         numptr_m1->contidional_second_val = rez;
13060                 }
13061                 rez = numptr_m1->val;
13062                 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13063                         rez |= numptr_val;
13064                 else if (op == TOK_OR)
13065                         rez = numptr_val || rez;
13066                 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13067                         rez &= numptr_val;
13068                 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13069                         rez ^= numptr_val;
13070                 else if (op == TOK_AND)
13071                         rez = rez && numptr_val;
13072                 else if (op == TOK_EQ)
13073                         rez = (rez == numptr_val);
13074                 else if (op == TOK_NE)
13075                         rez = (rez != numptr_val);
13076                 else if (op == TOK_GE)
13077                         rez = (rez >= numptr_val);
13078                 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13079                         rez >>= numptr_val;
13080                 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13081                         rez <<= numptr_val;
13082                 else if (op == TOK_GT)
13083                         rez = (rez > numptr_val);
13084                 else if (op == TOK_LT)
13085                         rez = (rez < numptr_val);
13086                 else if (op == TOK_LE)
13087                         rez = (rez <= numptr_val);
13088                 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13089                         rez *= numptr_val;
13090                 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13091                         rez += numptr_val;
13092                 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13093                         rez -= numptr_val;
13094                 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13095                         rez = numptr_val;
13096                 else if (op == TOK_CONDITIONAL_SEP) {
13097                         if (numptr_m1 == numstack) {
13098                                 /* protect $((expr : expr)) without "expr ? " */
13099                                 goto err;
13100                         }
13101                         numptr_m1->contidional_second_val_initialized = op;
13102                         numptr_m1->contidional_second_val = numptr_val;
13103                 } else if (op == TOK_CONDITIONAL) {
13104                         rez = rez ?
13105                                 numptr_val : numptr_m1->contidional_second_val;
13106                 } else if (op == TOK_EXPONENT) {
13107                         if (numptr_val < 0)
13108                                 return -3;      /* exponent less than 0 */
13109                         else {
13110                                 arith_t c = 1;
13111
13112                                 if (numptr_val)
13113                                         while (numptr_val--)
13114                                                 c *= rez;
13115                                 rez = c;
13116                         }
13117                 } else if (numptr_val==0)          /* zero divisor check */
13118                         return -2;
13119                 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13120                         rez /= numptr_val;
13121                 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13122                         rez %= numptr_val;
13123         }
13124         if (tok_have_assign(op)) {
13125                 char buf[sizeof(arith_t_type)*3 + 2];
13126
13127                 if (numptr_m1->var == NULL) {
13128                         /* Hmm, 1=2 ? */
13129                         goto err;
13130                 }
13131                 /* save to shell variable */
13132 #if ENABLE_ASH_MATH_SUPPORT_64
13133                 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
13134 #else
13135                 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
13136 #endif
13137                 setvar(numptr_m1->var, buf, 0);
13138                 /* after saving, make previous value for v++ or v-- */
13139                 if (op == TOK_POST_INC)
13140                         rez--;
13141                 else if (op == TOK_POST_DEC)
13142                         rez++;
13143         }
13144         numptr_m1->val = rez;
13145         /* protect geting var value, is number now */
13146         numptr_m1->var = NULL;
13147         return 0;
13148  err:
13149         return -1;
13150 }
13151
13152 /* longest must be first */
13153 static const char op_tokens[] ALIGN1 = {
13154         '<','<','=',0, TOK_LSHIFT_ASSIGN,
13155         '>','>','=',0, TOK_RSHIFT_ASSIGN,
13156         '<','<',    0, TOK_LSHIFT,
13157         '>','>',    0, TOK_RSHIFT,
13158         '|','|',    0, TOK_OR,
13159         '&','&',    0, TOK_AND,
13160         '!','=',    0, TOK_NE,
13161         '<','=',    0, TOK_LE,
13162         '>','=',    0, TOK_GE,
13163         '=','=',    0, TOK_EQ,
13164         '|','=',    0, TOK_OR_ASSIGN,
13165         '&','=',    0, TOK_AND_ASSIGN,
13166         '*','=',    0, TOK_MUL_ASSIGN,
13167         '/','=',    0, TOK_DIV_ASSIGN,
13168         '%','=',    0, TOK_REM_ASSIGN,
13169         '+','=',    0, TOK_PLUS_ASSIGN,
13170         '-','=',    0, TOK_MINUS_ASSIGN,
13171         '-','-',    0, TOK_POST_DEC,
13172         '^','=',    0, TOK_XOR_ASSIGN,
13173         '+','+',    0, TOK_POST_INC,
13174         '*','*',    0, TOK_EXPONENT,
13175         '!',        0, TOK_NOT,
13176         '<',        0, TOK_LT,
13177         '>',        0, TOK_GT,
13178         '=',        0, TOK_ASSIGN,
13179         '|',        0, TOK_BOR,
13180         '&',        0, TOK_BAND,
13181         '*',        0, TOK_MUL,
13182         '/',        0, TOK_DIV,
13183         '%',        0, TOK_REM,
13184         '+',        0, TOK_ADD,
13185         '-',        0, TOK_SUB,
13186         '^',        0, TOK_BXOR,
13187         /* uniq */
13188         '~',        0, TOK_BNOT,
13189         ',',        0, TOK_COMMA,
13190         '?',        0, TOK_CONDITIONAL,
13191         ':',        0, TOK_CONDITIONAL_SEP,
13192         ')',        0, TOK_RPAREN,
13193         '(',        0, TOK_LPAREN,
13194         0
13195 };
13196 /* ptr to ")" */
13197 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
13198
13199 static arith_t
13200 arith(const char *expr, int *perrcode)
13201 {
13202         char arithval; /* Current character under analysis */
13203         operator lasttok, op;
13204         operator prec;
13205         operator *stack, *stackptr;
13206         const char *p = endexpression;
13207         int errcode;
13208         v_n_t *numstack, *numstackptr;
13209         unsigned datasizes = strlen(expr) + 2;
13210
13211         /* Stack of integers */
13212         /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13213          * in any given correct or incorrect expression is left as an exercise to
13214          * the reader. */
13215         numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
13216         /* Stack of operator tokens */
13217         stackptr = stack = alloca(datasizes * sizeof(stack[0]));
13218
13219         *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
13220         *perrcode = errcode = 0;
13221
13222         while (1) {
13223                 arithval = *expr;
13224                 if (arithval == 0) {
13225                         if (p == endexpression) {
13226                                 /* Null expression. */
13227                                 return 0;
13228                         }
13229
13230                         /* This is only reached after all tokens have been extracted from the
13231                          * input stream. If there are still tokens on the operator stack, they
13232                          * are to be applied in order. At the end, there should be a final
13233                          * result on the integer stack */
13234
13235                         if (expr != endexpression + 1) {
13236                                 /* If we haven't done so already, */
13237                                 /* append a closing right paren */
13238                                 expr = endexpression;
13239                                 /* and let the loop process it. */
13240                                 continue;
13241                         }
13242                         /* At this point, we're done with the expression. */
13243                         if (numstackptr != numstack+1) {
13244                                 /* ... but if there isn't, it's bad */
13245  err:
13246                                 *perrcode = -1;
13247                                 return *perrcode;
13248                         }
13249                         if (numstack->var) {
13250                                 /* expression is $((var)) only, lookup now */
13251                                 errcode = arith_lookup_val(numstack);
13252                         }
13253  ret:
13254                         *perrcode = errcode;
13255                         return numstack->val;
13256                 }
13257
13258                 /* Continue processing the expression. */
13259                 if (arith_isspace(arithval)) {
13260                         /* Skip whitespace */
13261                         goto prologue;
13262                 }
13263                 p = endofname(expr);
13264                 if (p != expr) {
13265                         size_t var_name_size = (p-expr) + 1;  /* trailing zero */
13266
13267                         numstackptr->var = alloca(var_name_size);
13268                         safe_strncpy(numstackptr->var, expr, var_name_size);
13269                         expr = p;
13270  num:
13271                         numstackptr->contidional_second_val_initialized = 0;
13272                         numstackptr++;
13273                         lasttok = TOK_NUM;
13274                         continue;
13275                 }
13276                 if (isdigit(arithval)) {
13277                         numstackptr->var = NULL;
13278 #if ENABLE_ASH_MATH_SUPPORT_64
13279                         numstackptr->val = strtoll(expr, (char **) &expr, 0);
13280 #else
13281                         numstackptr->val = strtol(expr, (char **) &expr, 0);
13282 #endif
13283                         goto num;
13284                 }
13285                 for (p = op_tokens; ; p++) {
13286                         const char *o;
13287
13288                         if (*p == 0) {
13289                                 /* strange operator not found */
13290                                 goto err;
13291                         }
13292                         for (o = expr; *p && *o == *p; p++)
13293                                 o++;
13294                         if (!*p) {
13295                                 /* found */
13296                                 expr = o - 1;
13297                                 break;
13298                         }
13299                         /* skip tail uncompared token */
13300                         while (*p)
13301                                 p++;
13302                         /* skip zero delim */
13303                         p++;
13304                 }
13305                 op = p[1];
13306
13307                 /* post grammar: a++ reduce to num */
13308                 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13309                         lasttok = TOK_NUM;
13310
13311                 /* Plus and minus are binary (not unary) _only_ if the last
13312                  * token was as number, or a right paren (which pretends to be
13313                  * a number, since it evaluates to one). Think about it.
13314                  * It makes sense. */
13315                 if (lasttok != TOK_NUM) {
13316                         switch (op) {
13317                         case TOK_ADD:
13318                                 op = TOK_UPLUS;
13319                                 break;
13320                         case TOK_SUB:
13321                                 op = TOK_UMINUS;
13322                                 break;
13323                         case TOK_POST_INC:
13324                                 op = TOK_PRE_INC;
13325                                 break;
13326                         case TOK_POST_DEC:
13327                                 op = TOK_PRE_DEC;
13328                                 break;
13329                         }
13330                 }
13331                 /* We don't want a unary operator to cause recursive descent on the
13332                  * stack, because there can be many in a row and it could cause an
13333                  * operator to be evaluated before its argument is pushed onto the
13334                  * integer stack. */
13335                 /* But for binary operators, "apply" everything on the operator
13336                  * stack until we find an operator with a lesser priority than the
13337                  * one we have just extracted. */
13338                 /* Left paren is given the lowest priority so it will never be
13339                  * "applied" in this way.
13340                  * if associativity is right and priority eq, applied also skip
13341                  */
13342                 prec = PREC(op);
13343                 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13344                         /* not left paren or unary */
13345                         if (lasttok != TOK_NUM) {
13346                                 /* binary op must be preceded by a num */
13347                                 goto err;
13348                         }
13349                         while (stackptr != stack) {
13350                                 if (op == TOK_RPAREN) {
13351                                         /* The algorithm employed here is simple: while we don't
13352                                          * hit an open paren nor the bottom of the stack, pop
13353                                          * tokens and apply them */
13354                                         if (stackptr[-1] == TOK_LPAREN) {
13355                                                 --stackptr;
13356                                                 /* Any operator directly after a */
13357                                                 lasttok = TOK_NUM;
13358                                                 /* close paren should consider itself binary */
13359                                                 goto prologue;
13360                                         }
13361                                 } else {
13362                                         operator prev_prec = PREC(stackptr[-1]);
13363
13364                                         convert_prec_is_assing(prec);
13365                                         convert_prec_is_assing(prev_prec);
13366                                         if (prev_prec < prec)
13367                                                 break;
13368                                         /* check right assoc */
13369                                         if (prev_prec == prec && is_right_associativity(prec))
13370                                                 break;
13371                                 }
13372                                 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13373                                 if (errcode) goto ret;
13374                         }
13375                         if (op == TOK_RPAREN) {
13376                                 goto err;
13377                         }
13378                 }
13379
13380                 /* Push this operator to the stack and remember it. */
13381                 *stackptr++ = lasttok = op;
13382  prologue:
13383                 ++expr;
13384         } /* while */
13385 }
13386 #endif /* ASH_MATH_SUPPORT */
13387
13388
13389 /* ============ main() and helpers */
13390
13391 /*
13392  * Called to exit the shell.
13393  */
13394 static void exitshell(void) NORETURN;
13395 static void
13396 exitshell(void)
13397 {
13398         struct jmploc loc;
13399         char *p;
13400         int status;
13401
13402         status = exitstatus;
13403         TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13404         if (setjmp(loc.loc)) {
13405                 if (exception == EXEXIT)
13406 /* dash bug: it just does _exit(exitstatus) here
13407  * but we have to do setjobctl(0) first!
13408  * (bug is still not fixed in dash-0.5.3 - if you run dash
13409  * under Midnight Commander, on exit from dash MC is backgrounded) */
13410                         status = exitstatus;
13411                 goto out;
13412         }
13413         exception_handler = &loc;
13414         p = trap[0];
13415         if (p) {
13416                 trap[0] = NULL;
13417                 evalstring(p, 0);
13418         }
13419         flush_stdout_stderr();
13420  out:
13421         setjobctl(0);
13422         _exit(status);
13423         /* NOTREACHED */
13424 }
13425
13426 static void
13427 init(void)
13428 {
13429         /* from input.c: */
13430         basepf.nextc = basepf.buf = basebuf;
13431
13432         /* from trap.c: */
13433         signal(SIGCHLD, SIG_DFL);
13434
13435         /* from var.c: */
13436         {
13437                 char **envp;
13438                 char ppid[sizeof(int)*3 + 1];
13439                 const char *p;
13440                 struct stat st1, st2;
13441
13442                 initvar();
13443                 for (envp = environ; envp && *envp; envp++) {
13444                         if (strchr(*envp, '=')) {
13445                                 setvareq(*envp, VEXPORT|VTEXTFIXED);
13446                         }
13447                 }
13448
13449                 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13450                 setvar("PPID", ppid, 0);
13451
13452                 p = lookupvar("PWD");
13453                 if (p)
13454                         if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13455                          || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13456                                 p = '\0';
13457                 setpwd(p, 0);
13458         }
13459 }
13460
13461 /*
13462  * Process the shell command line arguments.
13463  */
13464 static void
13465 procargs(char **argv)
13466 {
13467         int i;
13468         const char *xminusc;
13469         char **xargv;
13470
13471         xargv = argv;
13472         arg0 = xargv[0];
13473         /* if (xargv[0]) - mmm, this is always true! */
13474                 xargv++;
13475         for (i = 0; i < NOPTS; i++)
13476                 optlist[i] = 2;
13477         argptr = xargv;
13478         if (options(1)) {
13479                 /* it already printed err message */
13480                 raise_exception(EXERROR);
13481         }
13482         xargv = argptr;
13483         xminusc = minusc;
13484         if (*xargv == NULL) {
13485                 if (xminusc)
13486                         ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13487                 sflag = 1;
13488         }
13489         if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13490                 iflag = 1;
13491         if (mflag == 2)
13492                 mflag = iflag;
13493         for (i = 0; i < NOPTS; i++)
13494                 if (optlist[i] == 2)
13495                         optlist[i] = 0;
13496 #if DEBUG == 2
13497         debug = 1;
13498 #endif
13499         /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13500         if (xminusc) {
13501                 minusc = *xargv++;
13502                 if (*xargv)
13503                         goto setarg0;
13504         } else if (!sflag) {
13505                 setinputfile(*xargv, 0);
13506  setarg0:
13507                 arg0 = *xargv++;
13508                 commandname = arg0;
13509         }
13510
13511         shellparam.p = xargv;
13512 #if ENABLE_ASH_GETOPTS
13513         shellparam.optind = 1;
13514         shellparam.optoff = -1;
13515 #endif
13516         /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13517         while (*xargv) {
13518                 shellparam.nparam++;
13519                 xargv++;
13520         }
13521         optschanged();
13522 }
13523
13524 /*
13525  * Read /etc/profile or .profile.
13526  */
13527 static void
13528 read_profile(const char *name)
13529 {
13530         int skip;
13531
13532         if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13533                 return;
13534         skip = cmdloop(0);
13535         popfile();
13536         if (skip)
13537                 exitshell();
13538 }
13539
13540 /*
13541  * This routine is called when an error or an interrupt occurs in an
13542  * interactive shell and control is returned to the main command loop.
13543  */
13544 static void
13545 reset(void)
13546 {
13547         /* from eval.c: */
13548         evalskip = 0;
13549         loopnest = 0;
13550         /* from input.c: */
13551         parselleft = parsenleft = 0;      /* clear input buffer */
13552         popallfiles();
13553         /* from parser.c: */
13554         tokpushback = 0;
13555         checkkwd = 0;
13556         /* from redir.c: */
13557         clearredir(/*drop:*/ 0);
13558 }
13559
13560 #if PROFILE
13561 static short profile_buf[16384];
13562 extern int etext();
13563 #endif
13564
13565 /*
13566  * Main routine.  We initialize things, parse the arguments, execute
13567  * profiles if we're a login shell, and then call cmdloop to execute
13568  * commands.  The setjmp call sets up the location to jump to when an
13569  * exception occurs.  When an exception occurs the variable "state"
13570  * is used to figure out how far we had gotten.
13571  */
13572 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13573 int ash_main(int argc UNUSED_PARAM, char **argv)
13574 {
13575         char *shinit;
13576         volatile int state;
13577         struct jmploc jmploc;
13578         struct stackmark smark;
13579
13580         /* Initialize global data */
13581         INIT_G_misc();
13582         INIT_G_memstack();
13583         INIT_G_var();
13584 #if ENABLE_ASH_ALIAS
13585         INIT_G_alias();
13586 #endif
13587         INIT_G_cmdtable();
13588
13589 #if PROFILE
13590         monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13591 #endif
13592
13593 #if ENABLE_FEATURE_EDITING
13594         line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13595 #endif
13596         state = 0;
13597         if (setjmp(jmploc.loc)) {
13598                 int e;
13599                 int s;
13600
13601                 reset();
13602
13603                 e = exception;
13604                 if (e == EXERROR)
13605                         exitstatus = 2;
13606                 s = state;
13607                 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13608                         exitshell();
13609
13610                 if (e == EXINT) {
13611                         outcslow('\n', stderr);
13612                 }
13613                 popstackmark(&smark);
13614                 FORCE_INT_ON; /* enable interrupts */
13615                 if (s == 1)
13616                         goto state1;
13617                 if (s == 2)
13618                         goto state2;
13619                 if (s == 3)
13620                         goto state3;
13621                 goto state4;
13622         }
13623         exception_handler = &jmploc;
13624 #if DEBUG
13625         opentrace();
13626         trace_puts("Shell args: ");
13627         trace_puts_args(argv);
13628 #endif
13629         rootpid = getpid();
13630
13631 #if ENABLE_ASH_RANDOM_SUPPORT
13632         /* Can use monotonic_ns() for better randomness but for now it is
13633          * not used anywhere else in busybox... so avoid bloat */
13634         random_galois_LFSR = random_LCG = rootpid + monotonic_us();
13635 #endif
13636         init();
13637         setstackmark(&smark);
13638         procargs(argv);
13639
13640 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13641         if (iflag) {
13642                 const char *hp = lookupvar("HISTFILE");
13643
13644                 if (hp == NULL) {
13645                         hp = lookupvar("HOME");
13646                         if (hp != NULL) {
13647                                 char *defhp = concat_path_file(hp, ".ash_history");
13648                                 setvar("HISTFILE", defhp, 0);
13649                                 free(defhp);
13650                         }
13651                 }
13652         }
13653 #endif
13654         if (argv[0] && argv[0][0] == '-')
13655                 isloginsh = 1;
13656         if (isloginsh) {
13657                 state = 1;
13658                 read_profile("/etc/profile");
13659  state1:
13660                 state = 2;
13661                 read_profile(".profile");
13662         }
13663  state2:
13664         state = 3;
13665         if (
13666 #ifndef linux
13667          getuid() == geteuid() && getgid() == getegid() &&
13668 #endif
13669          iflag
13670         ) {
13671                 shinit = lookupvar("ENV");
13672                 if (shinit != NULL && *shinit != '\0') {
13673                         read_profile(shinit);
13674                 }
13675         }
13676  state3:
13677         state = 4;
13678         if (minusc)
13679                 evalstring(minusc, 0);
13680
13681         if (sflag || minusc == NULL) {
13682 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13683                 if (iflag) {
13684                         const char *hp = lookupvar("HISTFILE");
13685
13686                         if (hp != NULL)
13687                                 line_input_state->hist_file = hp;
13688                 }
13689 #endif
13690  state4: /* XXX ??? - why isn't this before the "if" statement */
13691                 cmdloop(1);
13692         }
13693 #if PROFILE
13694         monitor(0);
13695 #endif
13696 #ifdef GPROF
13697         {
13698                 extern void _mcleanup(void);
13699                 _mcleanup();
13700         }
13701 #endif
13702         exitshell();
13703         /* NOTREACHED */
13704 }
13705
13706 #if DEBUG
13707 const char *applet_name = "debug stuff usage";
13708 int main(int argc, char **argv)
13709 {
13710         return ash_main(argc, argv);
13711 }
13712 #endif
13713
13714
13715 /*-
13716  * Copyright (c) 1989, 1991, 1993, 1994
13717  *      The Regents of the University of California.  All rights reserved.
13718  *
13719  * This code is derived from software contributed to Berkeley by
13720  * Kenneth Almquist.
13721  *
13722  * Redistribution and use in source and binary forms, with or without
13723  * modification, are permitted provided that the following conditions
13724  * are met:
13725  * 1. Redistributions of source code must retain the above copyright
13726  *    notice, this list of conditions and the following disclaimer.
13727  * 2. Redistributions in binary form must reproduce the above copyright
13728  *    notice, this list of conditions and the following disclaimer in the
13729  *    documentation and/or other materials provided with the distribution.
13730  * 3. Neither the name of the University nor the names of its contributors
13731  *    may be used to endorse or promote products derived from this software
13732  *    without specific prior written permission.
13733  *
13734  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13735  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13736  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13737  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13738  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13739  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13740  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13741  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13742  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13743  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13744  * SUCH DAMAGE.
13745  */