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