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