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