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