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