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