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