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