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