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