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