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