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