libbb: add xfstat function
[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 GPLv2 or later, see file LICENSE in this source tree.
17  */
18
19 /*
20  * The following should be set to reflect the type of system you have:
21  *      JOBS -> 1 if you have Berkeley job control, 0 otherwise.
22  *      define SYSV if you are running under System V.
23  *      define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
24  *      define DEBUG=2 to compile in and turn on debugging.
25  *
26  * When debugging is on, debugging info will be written to ./trace and
27  * a quit signal will generate a core dump.
28  */
29 #define DEBUG 0
30 /* Tweak debug output verbosity here */
31 #define DEBUG_TIME 0
32 #define DEBUG_PID 1
33 #define DEBUG_SIG 1
34
35 #define PROFILE 0
36
37 #define JOBS ENABLE_ASH_JOB_CONTROL
38
39 #include "busybox.h" /* for applet_names */
40 #include <paths.h>
41 #include <setjmp.h>
42 #include <fnmatch.h>
43 #include <sys/times.h>
44
45 #include "shell_common.h"
46 #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
4993          && !S_ISREG(finfo2.st_mode)
4994          && finfo.st_dev == finfo2.st_dev
4995          && finfo.st_ino == finfo2.st_ino
4996         ) {
4997                 return fd;
4998         }
4999
5000         /* The file has been replaced.  badness. */
5001         close(fd);
5002         errno = EEXIST;
5003         return -1;
5004 }
5005
5006 /*
5007  * Handle here documents.  Normally we fork off a process to write the
5008  * data to a pipe.  If the document is short, we can stuff the data in
5009  * the pipe without forking.
5010  */
5011 /* openhere needs this forward reference */
5012 static void expandhere(union node *arg, int fd);
5013 static int
5014 openhere(union node *redir)
5015 {
5016         int pip[2];
5017         size_t len = 0;
5018
5019         if (pipe(pip) < 0)
5020                 ash_msg_and_raise_error("pipe call failed");
5021         if (redir->type == NHERE) {
5022                 len = strlen(redir->nhere.doc->narg.text);
5023                 if (len <= PIPE_BUF) {
5024                         full_write(pip[1], redir->nhere.doc->narg.text, len);
5025                         goto out;
5026                 }
5027         }
5028         if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5029                 /* child */
5030                 close(pip[0]);
5031                 ignoresig(SIGINT);  //signal(SIGINT, SIG_IGN);
5032                 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5033                 ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
5034                 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5035                 signal(SIGPIPE, SIG_DFL);
5036                 if (redir->type == NHERE)
5037                         full_write(pip[1], redir->nhere.doc->narg.text, len);
5038                 else /* NXHERE */
5039                         expandhere(redir->nhere.doc, pip[1]);
5040                 _exit(EXIT_SUCCESS);
5041         }
5042  out:
5043         close(pip[1]);
5044         return pip[0];
5045 }
5046
5047 static int
5048 openredirect(union node *redir)
5049 {
5050         char *fname;
5051         int f;
5052
5053         switch (redir->nfile.type) {
5054         case NFROM:
5055                 fname = redir->nfile.expfname;
5056                 f = open(fname, O_RDONLY);
5057                 if (f < 0)
5058                         goto eopen;
5059                 break;
5060         case NFROMTO:
5061                 fname = redir->nfile.expfname;
5062                 f = open(fname, O_RDWR|O_CREAT, 0666);
5063                 if (f < 0)
5064                         goto ecreate;
5065                 break;
5066         case NTO:
5067 #if ENABLE_ASH_BASH_COMPAT
5068         case NTO2:
5069 #endif
5070                 /* Take care of noclobber mode. */
5071                 if (Cflag) {
5072                         fname = redir->nfile.expfname;
5073                         f = noclobberopen(fname);
5074                         if (f < 0)
5075                                 goto ecreate;
5076                         break;
5077                 }
5078                 /* FALLTHROUGH */
5079         case NCLOBBER:
5080                 fname = redir->nfile.expfname;
5081                 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5082                 if (f < 0)
5083                         goto ecreate;
5084                 break;
5085         case NAPPEND:
5086                 fname = redir->nfile.expfname;
5087                 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5088                 if (f < 0)
5089                         goto ecreate;
5090                 break;
5091         default:
5092 #if DEBUG
5093                 abort();
5094 #endif
5095                 /* Fall through to eliminate warning. */
5096 /* Our single caller does this itself */
5097 //      case NTOFD:
5098 //      case NFROMFD:
5099 //              f = -1;
5100 //              break;
5101         case NHERE:
5102         case NXHERE:
5103                 f = openhere(redir);
5104                 break;
5105         }
5106
5107         return f;
5108  ecreate:
5109         ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5110  eopen:
5111         ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5112 }
5113
5114 /*
5115  * Copy a file descriptor to be >= to.  Returns -1
5116  * if the source file descriptor is closed, EMPTY if there are no unused
5117  * file descriptors left.
5118  */
5119 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5120  * old code was doing close(to) prior to copyfd() to achieve the same */
5121 enum {
5122         COPYFD_EXACT   = (int)~(INT_MAX),
5123         COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5124 };
5125 static int
5126 copyfd(int from, int to)
5127 {
5128         int newfd;
5129
5130         if (to & COPYFD_EXACT) {
5131                 to &= ~COPYFD_EXACT;
5132                 /*if (from != to)*/
5133                         newfd = dup2(from, to);
5134         } else {
5135                 newfd = fcntl(from, F_DUPFD, to);
5136         }
5137         if (newfd < 0) {
5138                 if (errno == EMFILE)
5139                         return EMPTY;
5140                 /* Happens when source fd is not open: try "echo >&99" */
5141                 ash_msg_and_raise_error("%d: %m", from);
5142         }
5143         return newfd;
5144 }
5145
5146 /* Struct def and variable are moved down to the first usage site */
5147 struct two_fd_t {
5148         int orig, copy;
5149 };
5150 struct redirtab {
5151         struct redirtab *next;
5152         int nullredirs;
5153         int pair_count;
5154         struct two_fd_t two_fd[];
5155 };
5156 #define redirlist (G_var.redirlist)
5157
5158 static int need_to_remember(struct redirtab *rp, int fd)
5159 {
5160         int i;
5161
5162         if (!rp) /* remembering was not requested */
5163                 return 0;
5164
5165         for (i = 0; i < rp->pair_count; i++) {
5166                 if (rp->two_fd[i].orig == fd) {
5167                         /* already remembered */
5168                         return 0;
5169                 }
5170         }
5171         return 1;
5172 }
5173
5174 /* "hidden" fd is a fd used to read scripts, or a copy of such */
5175 static int is_hidden_fd(struct redirtab *rp, int fd)
5176 {
5177         int i;
5178         struct parsefile *pf;
5179
5180         if (fd == -1)
5181                 return 0;
5182         /* Check open scripts' fds */
5183         pf = g_parsefile;
5184         while (pf) {
5185                 /* We skip pf_fd == 0 case because of the following case:
5186                  * $ ash  # running ash interactively
5187                  * $ . ./script.sh
5188                  * and in script.sh: "exec 9>&0".
5189                  * Even though top-level pf_fd _is_ 0,
5190                  * it's still ok to use it: "read" builtin uses it,
5191                  * why should we cripple "exec" builtin?
5192                  */
5193                 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
5194                         return 1;
5195                 }
5196                 pf = pf->prev;
5197         }
5198
5199         if (!rp)
5200                 return 0;
5201         /* Check saved fds of redirects */
5202         fd |= COPYFD_RESTORE;
5203         for (i = 0; i < rp->pair_count; i++) {
5204                 if (rp->two_fd[i].copy == fd) {
5205                         return 1;
5206                 }
5207         }
5208         return 0;
5209 }
5210
5211 /*
5212  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
5213  * old file descriptors are stashed away so that the redirection can be
5214  * undone by calling popredir.
5215  */
5216 /* flags passed to redirect */
5217 #define REDIR_PUSH    01        /* save previous values of file descriptors */
5218 #define REDIR_SAVEFD2 03        /* set preverrout */
5219 static void
5220 redirect(union node *redir, int flags)
5221 {
5222         struct redirtab *sv;
5223         int sv_pos;
5224         int i;
5225         int fd;
5226         int newfd;
5227         int copied_fd2 = -1;
5228
5229         g_nullredirs++;
5230         if (!redir) {
5231                 return;
5232         }
5233
5234         sv = NULL;
5235         sv_pos = 0;
5236         INT_OFF;
5237         if (flags & REDIR_PUSH) {
5238                 union node *tmp = redir;
5239                 do {
5240                         sv_pos++;
5241 #if ENABLE_ASH_BASH_COMPAT
5242                         if (tmp->nfile.type == NTO2)
5243                                 sv_pos++;
5244 #endif
5245                         tmp = tmp->nfile.next;
5246                 } while (tmp);
5247                 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
5248                 sv->next = redirlist;
5249                 sv->pair_count = sv_pos;
5250                 redirlist = sv;
5251                 sv->nullredirs = g_nullredirs - 1;
5252                 g_nullredirs = 0;
5253                 while (sv_pos > 0) {
5254                         sv_pos--;
5255                         sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5256                 }
5257         }
5258
5259         do {
5260                 int right_fd = -1;
5261                 fd = redir->nfile.fd;
5262                 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5263                         right_fd = redir->ndup.dupfd;
5264                         //bb_error_msg("doing %d > %d", fd, right_fd);
5265                         /* redirect from/to same file descriptor? */
5266                         if (right_fd == fd)
5267                                 continue;
5268                         /* "echo >&10" and 10 is a fd opened to a sh script? */
5269                         if (is_hidden_fd(sv, right_fd)) {
5270                                 errno = EBADF; /* as if it is closed */
5271                                 ash_msg_and_raise_error("%d: %m", right_fd);
5272                         }
5273                         newfd = -1;
5274                 } else {
5275                         newfd = openredirect(redir); /* always >= 0 */
5276                         if (fd == newfd) {
5277                                 /* Descriptor wasn't open before redirect.
5278                                  * Mark it for close in the future */
5279                                 if (need_to_remember(sv, fd)) {
5280                                         goto remember_to_close;
5281                                 }
5282                                 continue;
5283                         }
5284                 }
5285 #if ENABLE_ASH_BASH_COMPAT
5286  redirect_more:
5287 #endif
5288                 if (need_to_remember(sv, fd)) {
5289                         /* Copy old descriptor */
5290                         /* Careful to not accidentally "save"
5291                          * to the same fd as right side fd in N>&M */
5292                         int minfd = right_fd < 10 ? 10 : right_fd + 1;
5293                         i = fcntl(fd, F_DUPFD, minfd);
5294 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5295  * are closed in popredir() in the child, preventing them from leaking
5296  * into child. (popredir() also cleans up the mess in case of failures)
5297  */
5298                         if (i == -1) {
5299                                 i = errno;
5300                                 if (i != EBADF) {
5301                                         /* Strange error (e.g. "too many files" EMFILE?) */
5302                                         if (newfd >= 0)
5303                                                 close(newfd);
5304                                         errno = i;
5305                                         ash_msg_and_raise_error("%d: %m", fd);
5306                                         /* NOTREACHED */
5307                                 }
5308                                 /* EBADF: it is not open - good, remember to close it */
5309  remember_to_close:
5310                                 i = CLOSED;
5311                         } else { /* fd is open, save its copy */
5312                                 /* "exec fd>&-" should not close fds
5313                                  * which point to script file(s).
5314                                  * Force them to be restored afterwards */
5315                                 if (is_hidden_fd(sv, fd))
5316                                         i |= COPYFD_RESTORE;
5317                         }
5318                         if (fd == 2)
5319                                 copied_fd2 = i;
5320                         sv->two_fd[sv_pos].orig = fd;
5321                         sv->two_fd[sv_pos].copy = i;
5322                         sv_pos++;
5323                 }
5324                 if (newfd < 0) {
5325                         /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5326                         if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5327                                 /* Don't want to trigger debugging */
5328                                 if (fd != -1)
5329                                         close(fd);
5330                         } else {
5331                                 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5332                         }
5333                 } else if (fd != newfd) { /* move newfd to fd */
5334                         copyfd(newfd, fd | COPYFD_EXACT);
5335 #if ENABLE_ASH_BASH_COMPAT
5336                         if (!(redir->nfile.type == NTO2 && fd == 2))
5337 #endif
5338                                 close(newfd);
5339                 }
5340 #if ENABLE_ASH_BASH_COMPAT
5341                 if (redir->nfile.type == NTO2 && fd == 1) {
5342                         /* We already redirected it to fd 1, now copy it to 2 */
5343                         newfd = 1;
5344                         fd = 2;
5345                         goto redirect_more;
5346                 }
5347 #endif
5348         } while ((redir = redir->nfile.next) != NULL);
5349
5350         INT_ON;
5351         if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5352                 preverrout_fd = copied_fd2;
5353 }
5354
5355 /*
5356  * Undo the effects of the last redirection.
5357  */
5358 static void
5359 popredir(int drop, int restore)
5360 {
5361         struct redirtab *rp;
5362         int i;
5363
5364         if (--g_nullredirs >= 0)
5365                 return;
5366         INT_OFF;
5367         rp = redirlist;
5368         for (i = 0; i < rp->pair_count; i++) {
5369                 int fd = rp->two_fd[i].orig;
5370                 int copy = rp->two_fd[i].copy;
5371                 if (copy == CLOSED) {
5372                         if (!drop)
5373                                 close(fd);
5374                         continue;
5375                 }
5376                 if (copy != EMPTY) {
5377                         if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5378                                 copy &= ~COPYFD_RESTORE;
5379                                 /*close(fd);*/
5380                                 copyfd(copy, fd | COPYFD_EXACT);
5381                         }
5382                         close(copy & ~COPYFD_RESTORE);
5383                 }
5384         }
5385         redirlist = rp->next;
5386         g_nullredirs = rp->nullredirs;
5387         free(rp);
5388         INT_ON;
5389 }
5390
5391 /*
5392  * Undo all redirections.  Called on error or interrupt.
5393  */
5394
5395 /*
5396  * Discard all saved file descriptors.
5397  */
5398 static void
5399 clearredir(int drop)
5400 {
5401         for (;;) {
5402                 g_nullredirs = 0;
5403                 if (!redirlist)
5404                         break;
5405                 popredir(drop, /*restore:*/ 0);
5406         }
5407 }
5408
5409 static int
5410 redirectsafe(union node *redir, int flags)
5411 {
5412         int err;
5413         volatile int saveint;
5414         struct jmploc *volatile savehandler = exception_handler;
5415         struct jmploc jmploc;
5416
5417         SAVE_INT(saveint);
5418         /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5419         err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5420         if (!err) {
5421                 exception_handler = &jmploc;
5422                 redirect(redir, flags);
5423         }
5424         exception_handler = savehandler;
5425         if (err && exception_type != EXERROR)
5426                 longjmp(exception_handler->loc, 1);
5427         RESTORE_INT(saveint);
5428         return err;
5429 }
5430
5431
5432 /* ============ Routines to expand arguments to commands
5433  *
5434  * We have to deal with backquotes, shell variables, and file metacharacters.
5435  */
5436
5437 #if ENABLE_SH_MATH_SUPPORT
5438 static arith_t
5439 ash_arith(const char *s)
5440 {
5441         arith_eval_hooks_t math_hooks;
5442         arith_t result;
5443         int errcode = 0;
5444
5445         math_hooks.lookupvar = lookupvar;
5446         math_hooks.setvar    = setvar2;
5447         math_hooks.endofname = endofname;
5448
5449         INT_OFF;
5450         result = arith(s, &errcode, &math_hooks);
5451         if (errcode < 0) {
5452                 if (errcode == -3)
5453                         ash_msg_and_raise_error("exponent less than 0");
5454                 if (errcode == -2)
5455                         ash_msg_and_raise_error("divide by zero");
5456                 if (errcode == -5)
5457                         ash_msg_and_raise_error("expression recursion loop detected");
5458                 raise_error_syntax(s);
5459         }
5460         INT_ON;
5461
5462         return result;
5463 }
5464 #endif
5465
5466 /*
5467  * expandarg flags
5468  */
5469 #define EXP_FULL        0x1     /* perform word splitting & file globbing */
5470 #define EXP_TILDE       0x2     /* do normal tilde expansion */
5471 #define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
5472 #define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
5473 #define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
5474 #define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
5475 #define EXP_VARTILDE2   0x40    /* expand tildes after colons only */
5476 #define EXP_WORD        0x80    /* expand word in parameter expansion */
5477 #define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
5478 /*
5479  * rmescape() flags
5480  */
5481 #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
5482 #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
5483 #define RMESCAPE_QUOTED 0x4     /* Remove CTLESC unless in quotes */
5484 #define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
5485 #define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
5486
5487 /*
5488  * Structure specifying which parts of the string should be searched
5489  * for IFS characters.
5490  */
5491 struct ifsregion {
5492         struct ifsregion *next; /* next region in list */
5493         int begoff;             /* offset of start of region */
5494         int endoff;             /* offset of end of region */
5495         int nulonly;            /* search for nul bytes only */
5496 };
5497
5498 struct arglist {
5499         struct strlist *list;
5500         struct strlist **lastp;
5501 };
5502
5503 /* output of current string */
5504 static char *expdest;
5505 /* list of back quote expressions */
5506 static struct nodelist *argbackq;
5507 /* first struct in list of ifs regions */
5508 static struct ifsregion ifsfirst;
5509 /* last struct in list */
5510 static struct ifsregion *ifslastp;
5511 /* holds expanded arg list */
5512 static struct arglist exparg;
5513
5514 /*
5515  * Our own itoa().
5516  */
5517 static int
5518 cvtnum(arith_t num)
5519 {
5520         int len;
5521
5522         expdest = makestrspace(32, expdest);
5523         len = fmtstr(expdest, 32, arith_t_fmt, num);
5524         STADJUST(len, expdest);
5525         return len;
5526 }
5527
5528 static size_t
5529 esclen(const char *start, const char *p)
5530 {
5531         size_t esc = 0;
5532
5533         while (p > start && (unsigned char)*--p == CTLESC) {
5534                 esc++;
5535         }
5536         return esc;
5537 }
5538
5539 /*
5540  * Remove any CTLESC characters from a string.
5541  */
5542 static char *
5543 rmescapes(char *str, int flag)
5544 {
5545         static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5546
5547         char *p, *q, *r;
5548         unsigned inquotes;
5549         unsigned protect_against_glob;
5550         unsigned globbing;
5551
5552         p = strpbrk(str, qchars);
5553         if (!p)
5554                 return str;
5555
5556         q = p;
5557         r = str;
5558         if (flag & RMESCAPE_ALLOC) {
5559                 size_t len = p - str;
5560                 size_t fulllen = len + strlen(p) + 1;
5561
5562                 if (flag & RMESCAPE_GROW) {
5563                         int strloc = str - (char *)stackblock();
5564                         r = makestrspace(fulllen, expdest);
5565                         /* p and str may be invalidated by makestrspace */
5566                         str = (char *)stackblock() + strloc;
5567                         p = str + len;
5568                 } else if (flag & RMESCAPE_HEAP) {
5569                         r = ckmalloc(fulllen);
5570                 } else {
5571                         r = stalloc(fulllen);
5572                 }
5573                 q = r;
5574                 if (len > 0) {
5575                         q = (char *)memcpy(q, str, len) + len;
5576                 }
5577         }
5578
5579         inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5580         globbing = flag & RMESCAPE_GLOB;
5581         protect_against_glob = globbing;
5582         while (*p) {
5583                 if ((unsigned char)*p == CTLQUOTEMARK) {
5584 // TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
5585 // (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
5586 // Note: both inquotes and protect_against_glob only affect whether
5587 // CTLESC,<ch> gets converted to <ch> or to \<ch>
5588                         inquotes = ~inquotes;
5589                         p++;
5590                         protect_against_glob = globbing;
5591                         continue;
5592                 }
5593                 if (*p == '\\') {
5594                         /* naked back slash */
5595                         protect_against_glob = 0;
5596                         goto copy;
5597                 }
5598                 if ((unsigned char)*p == CTLESC) {
5599                         p++;
5600                         if (protect_against_glob && inquotes && *p != '/') {
5601                                 *q++ = '\\';
5602                         }
5603                 }
5604                 protect_against_glob = globbing;
5605  copy:
5606                 *q++ = *p++;
5607         }
5608         *q = '\0';
5609         if (flag & RMESCAPE_GROW) {
5610                 expdest = r;
5611                 STADJUST(q - r + 1, expdest);
5612         }
5613         return r;
5614 }
5615 #define pmatch(a, b) !fnmatch((a), (b), 0)
5616
5617 /*
5618  * Prepare a pattern for a expmeta (internal glob(3)) call.
5619  *
5620  * Returns an stalloced string.
5621  */
5622 static char *
5623 preglob(const char *pattern, int quoted, int flag)
5624 {
5625         flag |= RMESCAPE_GLOB;
5626         if (quoted) {
5627                 flag |= RMESCAPE_QUOTED;
5628         }
5629         return rmescapes((char *)pattern, flag);
5630 }
5631
5632 /*
5633  * Put a string on the stack.
5634  */
5635 static void
5636 memtodest(const char *p, size_t len, int syntax, int quotes)
5637 {
5638         char *q = expdest;
5639
5640         q = makestrspace(quotes ? len * 2 : len, q);
5641
5642         while (len--) {
5643                 unsigned char c = *p++;
5644                 if (c == '\0')
5645                         continue;
5646                 if (quotes) {
5647                         int n = SIT(c, syntax);
5648                         if (n == CCTL || n == CBACK)
5649                                 USTPUTC(CTLESC, q);
5650                 }
5651                 USTPUTC(c, q);
5652         }
5653
5654         expdest = q;
5655 }
5656
5657 static void
5658 strtodest(const char *p, int syntax, int quotes)
5659 {
5660         memtodest(p, strlen(p), syntax, quotes);
5661 }
5662
5663 /*
5664  * Record the fact that we have to scan this region of the
5665  * string for IFS characters.
5666  */
5667 static void
5668 recordregion(int start, int end, int nulonly)
5669 {
5670         struct ifsregion *ifsp;
5671
5672         if (ifslastp == NULL) {
5673                 ifsp = &ifsfirst;
5674         } else {
5675                 INT_OFF;
5676                 ifsp = ckzalloc(sizeof(*ifsp));
5677                 /*ifsp->next = NULL; - ckzalloc did it */
5678                 ifslastp->next = ifsp;
5679                 INT_ON;
5680         }
5681         ifslastp = ifsp;
5682         ifslastp->begoff = start;
5683         ifslastp->endoff = end;
5684         ifslastp->nulonly = nulonly;
5685 }
5686
5687 static void
5688 removerecordregions(int endoff)
5689 {
5690         if (ifslastp == NULL)
5691                 return;
5692
5693         if (ifsfirst.endoff > endoff) {
5694                 while (ifsfirst.next) {
5695                         struct ifsregion *ifsp;
5696                         INT_OFF;
5697                         ifsp = ifsfirst.next->next;
5698                         free(ifsfirst.next);
5699                         ifsfirst.next = ifsp;
5700                         INT_ON;
5701                 }
5702                 if (ifsfirst.begoff > endoff) {
5703                         ifslastp = NULL;
5704                 } else {
5705                         ifslastp = &ifsfirst;
5706                         ifsfirst.endoff = endoff;
5707                 }
5708                 return;
5709         }
5710
5711         ifslastp = &ifsfirst;
5712         while (ifslastp->next && ifslastp->next->begoff < endoff)
5713                 ifslastp = ifslastp->next;
5714         while (ifslastp->next) {
5715                 struct ifsregion *ifsp;
5716                 INT_OFF;
5717                 ifsp = ifslastp->next->next;
5718                 free(ifslastp->next);
5719                 ifslastp->next = ifsp;
5720                 INT_ON;
5721         }
5722         if (ifslastp->endoff > endoff)
5723                 ifslastp->endoff = endoff;
5724 }
5725
5726 static char *
5727 exptilde(char *startp, char *p, int flags)
5728 {
5729         unsigned char c;
5730         char *name;
5731         struct passwd *pw;
5732         const char *home;
5733         int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
5734         int startloc;
5735
5736         name = p + 1;
5737
5738         while ((c = *++p) != '\0') {
5739                 switch (c) {
5740                 case CTLESC:
5741                         return startp;
5742                 case CTLQUOTEMARK:
5743                         return startp;
5744                 case ':':
5745                         if (flags & EXP_VARTILDE)
5746                                 goto done;
5747                         break;
5748                 case '/':
5749                 case CTLENDVAR:
5750                         goto done;
5751                 }
5752         }
5753  done:
5754         *p = '\0';
5755         if (*name == '\0') {
5756                 home = lookupvar("HOME");
5757         } else {
5758                 pw = getpwnam(name);
5759                 if (pw == NULL)
5760                         goto lose;
5761                 home = pw->pw_dir;
5762         }
5763         if (!home || !*home)
5764                 goto lose;
5765         *p = c;
5766         startloc = expdest - (char *)stackblock();
5767         strtodest(home, SQSYNTAX, quotes);
5768         recordregion(startloc, expdest - (char *)stackblock(), 0);
5769         return p;
5770  lose:
5771         *p = c;
5772         return startp;
5773 }
5774
5775 /*
5776  * Execute a command inside back quotes.  If it's a builtin command, we
5777  * want to save its output in a block obtained from malloc.  Otherwise
5778  * we fork off a subprocess and get the output of the command via a pipe.
5779  * Should be called with interrupts off.
5780  */
5781 struct backcmd {                /* result of evalbackcmd */
5782         int fd;                 /* file descriptor to read from */
5783         int nleft;              /* number of chars in buffer */
5784         char *buf;              /* buffer */
5785         struct job *jp;         /* job structure for command */
5786 };
5787
5788 /* These forward decls are needed to use "eval" code for backticks handling: */
5789 static uint8_t back_exitstatus; /* exit status of backquoted command */
5790 #define EV_EXIT 01              /* exit after evaluating tree */
5791 static void evaltree(union node *, int);
5792
5793 static void FAST_FUNC
5794 evalbackcmd(union node *n, struct backcmd *result)
5795 {
5796         int saveherefd;
5797
5798         result->fd = -1;
5799         result->buf = NULL;
5800         result->nleft = 0;
5801         result->jp = NULL;
5802         if (n == NULL)
5803                 goto out;
5804
5805         saveherefd = herefd;
5806         herefd = -1;
5807
5808         {
5809                 int pip[2];
5810                 struct job *jp;
5811
5812                 if (pipe(pip) < 0)
5813                         ash_msg_and_raise_error("pipe call failed");
5814                 jp = makejob(/*n,*/ 1);
5815                 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5816                         FORCE_INT_ON;
5817                         close(pip[0]);
5818                         if (pip[1] != 1) {
5819                                 /*close(1);*/
5820                                 copyfd(pip[1], 1 | COPYFD_EXACT);
5821                                 close(pip[1]);
5822                         }
5823                         eflag = 0;
5824                         evaltree(n, EV_EXIT); /* actually evaltreenr... */
5825                         /* NOTREACHED */
5826                 }
5827                 close(pip[1]);
5828                 result->fd = pip[0];
5829                 result->jp = jp;
5830         }
5831         herefd = saveherefd;
5832  out:
5833         TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5834                 result->fd, result->buf, result->nleft, result->jp));
5835 }
5836
5837 /*
5838  * Expand stuff in backwards quotes.
5839  */
5840 static void
5841 expbackq(union node *cmd, int quoted, int quotes)
5842 {
5843         struct backcmd in;
5844         int i;
5845         char buf[128];
5846         char *p;
5847         char *dest;
5848         int startloc;
5849         int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5850         struct stackmark smark;
5851
5852         INT_OFF;
5853         setstackmark(&smark);
5854         dest = expdest;
5855         startloc = dest - (char *)stackblock();
5856         grabstackstr(dest);
5857         evalbackcmd(cmd, &in);
5858         popstackmark(&smark);
5859
5860         p = in.buf;
5861         i = in.nleft;
5862         if (i == 0)
5863                 goto read;
5864         for (;;) {
5865                 memtodest(p, i, syntax, quotes);
5866  read:
5867                 if (in.fd < 0)
5868                         break;
5869                 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5870                 TRACE(("expbackq: read returns %d\n", i));
5871                 if (i <= 0)
5872                         break;
5873                 p = buf;
5874         }
5875
5876         free(in.buf);
5877         if (in.fd >= 0) {
5878                 close(in.fd);
5879                 back_exitstatus = waitforjob(in.jp);
5880         }
5881         INT_ON;
5882
5883         /* Eat all trailing newlines */
5884         dest = expdest;
5885         for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5886                 STUNPUTC(dest);
5887         expdest = dest;
5888
5889         if (quoted == 0)
5890                 recordregion(startloc, dest - (char *)stackblock(), 0);
5891         TRACE(("evalbackq: size:%d:'%.*s'\n",
5892                 (int)((dest - (char *)stackblock()) - startloc),
5893                 (int)((dest - (char *)stackblock()) - startloc),
5894                 stackblock() + startloc));
5895 }
5896
5897 #if ENABLE_SH_MATH_SUPPORT
5898 /*
5899  * Expand arithmetic expression.  Backup to start of expression,
5900  * evaluate, place result in (backed up) result, adjust string position.
5901  */
5902 static void
5903 expari(int quotes)
5904 {
5905         char *p, *start;
5906         int begoff;
5907         int flag;
5908         int len;
5909
5910         /* ifsfree(); */
5911
5912         /*
5913          * This routine is slightly over-complicated for
5914          * efficiency.  Next we scan backwards looking for the
5915          * start of arithmetic.
5916          */
5917         start = stackblock();
5918         p = expdest - 1;
5919         *p = '\0';
5920         p--;
5921         do {
5922                 int esc;
5923
5924                 while ((unsigned char)*p != CTLARI) {
5925                         p--;
5926 #if DEBUG
5927                         if (p < start) {
5928                                 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5929                         }
5930 #endif
5931                 }
5932
5933                 esc = esclen(start, p);
5934                 if (!(esc % 2)) {
5935                         break;
5936                 }
5937
5938                 p -= esc + 1;
5939         } while (1);
5940
5941         begoff = p - start;
5942
5943         removerecordregions(begoff);
5944
5945         flag = p[1];
5946
5947         expdest = p;
5948
5949         if (quotes)
5950                 rmescapes(p + 2, 0);
5951
5952         len = cvtnum(ash_arith(p + 2));
5953
5954         if (flag != '"')
5955                 recordregion(begoff, begoff + len, 0);
5956 }
5957 #endif
5958
5959 /* argstr needs it */
5960 static char *evalvar(char *p, int flags, struct strlist *var_str_list);
5961
5962 /*
5963  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
5964  * characters to allow for further processing.  Otherwise treat
5965  * $@ like $* since no splitting will be performed.
5966  *
5967  * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5968  * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5969  * for correct expansion of "B=$A" word.
5970  */
5971 static void
5972 argstr(char *p, int flags, struct strlist *var_str_list)
5973 {
5974         static const char spclchars[] ALIGN1 = {
5975                 '=',
5976                 ':',
5977                 CTLQUOTEMARK,
5978                 CTLENDVAR,
5979                 CTLESC,
5980                 CTLVAR,
5981                 CTLBACKQ,
5982                 CTLBACKQ | CTLQUOTE,
5983 #if ENABLE_SH_MATH_SUPPORT
5984                 CTLENDARI,
5985 #endif
5986                 '\0'
5987         };
5988         const char *reject = spclchars;
5989         int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
5990         int breakall = flags & EXP_WORD;
5991         int inquotes;
5992         size_t length;
5993         int startloc;
5994
5995         if (!(flags & EXP_VARTILDE)) {
5996                 reject += 2;
5997         } else if (flags & EXP_VARTILDE2) {
5998                 reject++;
5999         }
6000         inquotes = 0;
6001         length = 0;
6002         if (flags & EXP_TILDE) {
6003                 char *q;
6004
6005                 flags &= ~EXP_TILDE;
6006  tilde:
6007                 q = p;
6008                 if (*q == CTLESC && (flags & EXP_QWORD))
6009                         q++;
6010                 if (*q == '~')
6011                         p = exptilde(p, q, flags);
6012         }
6013  start:
6014         startloc = expdest - (char *)stackblock();
6015         for (;;) {
6016                 unsigned char c;
6017
6018                 length += strcspn(p + length, reject);
6019                 c = p[length];
6020                 if (c) {
6021                         if (!(c & 0x80)
6022 #if ENABLE_SH_MATH_SUPPORT
6023                          || c == CTLENDARI
6024 #endif
6025                         ) {
6026                                 /* c == '=' || c == ':' || c == CTLENDARI */
6027                                 length++;
6028                         }
6029                 }
6030                 if (length > 0) {
6031                         int newloc;
6032                         expdest = stack_nputstr(p, length, expdest);
6033                         newloc = expdest - (char *)stackblock();
6034                         if (breakall && !inquotes && newloc > startloc) {
6035                                 recordregion(startloc, newloc, 0);
6036                         }
6037                         startloc = newloc;
6038                 }
6039                 p += length + 1;
6040                 length = 0;
6041
6042                 switch (c) {
6043                 case '\0':
6044                         goto breakloop;
6045                 case '=':
6046                         if (flags & EXP_VARTILDE2) {
6047                                 p--;
6048                                 continue;
6049                         }
6050                         flags |= EXP_VARTILDE2;
6051                         reject++;
6052                         /* fall through */
6053                 case ':':
6054                         /*
6055                          * sort of a hack - expand tildes in variable
6056                          * assignments (after the first '=' and after ':'s).
6057                          */
6058                         if (*--p == '~') {
6059                                 goto tilde;
6060                         }
6061                         continue;
6062                 }
6063
6064                 switch (c) {
6065                 case CTLENDVAR: /* ??? */
6066                         goto breakloop;
6067                 case CTLQUOTEMARK:
6068                         /* "$@" syntax adherence hack */
6069                         if (!inquotes
6070                          && memcmp(p, dolatstr, 4) == 0
6071                          && (  p[4] == CTLQUOTEMARK
6072                             || (p[4] == CTLENDVAR && p[5] == CTLQUOTEMARK)
6073                             )
6074                         ) {
6075                                 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
6076                                 goto start;
6077                         }
6078                         inquotes = !inquotes;
6079  addquote:
6080                         if (quotes) {
6081                                 p--;
6082                                 length++;
6083                                 startloc++;
6084                         }
6085                         break;
6086                 case CTLESC:
6087                         startloc++;
6088                         length++;
6089                         goto addquote;
6090                 case CTLVAR:
6091                         p = evalvar(p, flags, var_str_list);
6092                         goto start;
6093                 case CTLBACKQ:
6094                         c = '\0';
6095                 case CTLBACKQ|CTLQUOTE:
6096                         expbackq(argbackq->n, c, quotes);
6097                         argbackq = argbackq->next;
6098                         goto start;
6099 #if ENABLE_SH_MATH_SUPPORT
6100                 case CTLENDARI:
6101                         p--;
6102                         expari(quotes);
6103                         goto start;
6104 #endif
6105                 }
6106         }
6107  breakloop:
6108         ;
6109 }
6110
6111 static char *
6112 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6113                 char *pattern, int quotes, int zero)
6114 {
6115         char *loc, *loc2;
6116         char c;
6117
6118         loc = startp;
6119         loc2 = rmesc;
6120         do {
6121                 int match;
6122                 const char *s = loc2;
6123
6124                 c = *loc2;
6125                 if (zero) {
6126                         *loc2 = '\0';
6127                         s = rmesc;
6128                 }
6129                 match = pmatch(pattern, s);
6130
6131                 *loc2 = c;
6132                 if (match)
6133                         return loc;
6134                 if (quotes && (unsigned char)*loc == CTLESC)
6135                         loc++;
6136                 loc++;
6137                 loc2++;
6138         } while (c);
6139         return NULL;
6140 }
6141
6142 static char *
6143 scanright(char *startp, char *rmesc, char *rmescend,
6144                 char *pattern, int quotes, int match_at_start)
6145 {
6146 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6147         int try2optimize = match_at_start;
6148 #endif
6149         int esc = 0;
6150         char *loc;
6151         char *loc2;
6152
6153         /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6154          * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6155          * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6156          * Logic:
6157          * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6158          * and on each iteration they go back two/one char until they reach the beginning.
6159          * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6160          */
6161         /* TODO: document in what other circumstances we are called. */
6162
6163         for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6164                 int match;
6165                 char c = *loc2;
6166                 const char *s = loc2;
6167                 if (match_at_start) {
6168                         *loc2 = '\0';
6169                         s = rmesc;
6170                 }
6171                 match = pmatch(pattern, s);
6172                 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6173                 *loc2 = c;
6174                 if (match)
6175                         return loc;
6176 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6177                 if (try2optimize) {
6178                         /* Maybe we can optimize this:
6179                          * if pattern ends with unescaped *, we can avoid checking
6180                          * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6181                          * it wont match truncated "raw_value_of_" strings too.
6182                          */
6183                         unsigned plen = strlen(pattern);
6184                         /* Does it end with "*"? */
6185                         if (plen != 0 && pattern[--plen] == '*') {
6186                                 /* "xxxx*" is not escaped */
6187                                 /* "xxx\*" is escaped */
6188                                 /* "xx\\*" is not escaped */
6189                                 /* "x\\\*" is escaped */
6190                                 int slashes = 0;
6191                                 while (plen != 0 && pattern[--plen] == '\\')
6192                                         slashes++;
6193                                 if (!(slashes & 1))
6194                                         break; /* ends with unescaped "*" */
6195                         }
6196                         try2optimize = 0;
6197                 }
6198 #endif
6199                 loc--;
6200                 if (quotes) {
6201                         if (--esc < 0) {
6202                                 esc = esclen(startp, loc);
6203                         }
6204                         if (esc % 2) {
6205                                 esc--;
6206                                 loc--;
6207                         }
6208                 }
6209         }
6210         return NULL;
6211 }
6212
6213 static void varunset(const char *, const char *, const char *, int) NORETURN;
6214 static void
6215 varunset(const char *end, const char *var, const char *umsg, int varflags)
6216 {
6217         const char *msg;
6218         const char *tail;
6219
6220         tail = nullstr;
6221         msg = "parameter not set";
6222         if (umsg) {
6223                 if ((unsigned char)*end == CTLENDVAR) {
6224                         if (varflags & VSNUL)
6225                                 tail = " or null";
6226                 } else {
6227                         msg = umsg;
6228                 }
6229         }
6230         ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6231 }
6232
6233 #if ENABLE_ASH_BASH_COMPAT
6234 static char *
6235 parse_sub_pattern(char *arg, int varflags)
6236 {
6237         char *idx, *repl = NULL;
6238         unsigned char c;
6239
6240         //char *org_arg = arg;
6241         //bb_error_msg("arg:'%s' varflags:%x", arg, varflags);
6242         idx = arg;
6243         while (1) {
6244                 c = *arg;
6245                 if (!c)
6246                         break;
6247                 if (c == '/') {
6248                         /* Only the first '/' seen is our separator */
6249                         if (!repl) {
6250                                 repl = idx + 1;
6251                                 c = '\0';
6252                         }
6253                 }
6254                 *idx++ = c;
6255                 arg++;
6256                 /*
6257                  * Example: v='ab\c'; echo ${v/\\b/_\\_\z_}
6258                  * The result is a_\_z_c (not a\_\_z_c)!
6259                  *
6260                  * Enable debug prints in this function and you'll see:
6261                  * ash: arg:'\\b/_\\_z_' varflags:d
6262                  * ash: pattern:'\\b' repl:'_\_z_'
6263                  * That is, \\b is interpreted as \\b, but \\_ as \_!
6264                  * IOW: search pattern and replace string treat backslashes
6265                  * differently! That is the reason why we check repl below:
6266                  */
6267                 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE))
6268                         arg++; /* skip both '\', not just first one */
6269         }
6270         *idx = c; /* NUL */
6271         //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);
6272
6273         return repl;
6274 }
6275 #endif /* ENABLE_ASH_BASH_COMPAT */
6276
6277 static const char *
6278 subevalvar(char *p, char *varname, int strloc, int subtype,
6279                 int startloc, int varflags, int quotes, struct strlist *var_str_list)
6280 {
6281         struct nodelist *saveargbackq = argbackq;
6282         char *startp;
6283         char *loc;
6284         char *rmesc, *rmescend;
6285         char *str;
6286         IF_ASH_BASH_COMPAT(const char *repl = NULL;)
6287         IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6288         int saveherefd = herefd;
6289         int amount, workloc, resetloc;
6290         int zero;
6291         char *(*scan)(char*, char*, char*, char*, int, int);
6292
6293         //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d",
6294         //                      p, varname, strloc, subtype, startloc, varflags, quotes);
6295
6296         herefd = -1;
6297         argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6298                         var_str_list);
6299         STPUTC('\0', expdest);
6300         herefd = saveherefd;
6301         argbackq = saveargbackq;
6302         startp = (char *)stackblock() + startloc;
6303
6304         switch (subtype) {
6305         case VSASSIGN:
6306                 setvar(varname, startp, 0);
6307                 amount = startp - expdest;
6308                 STADJUST(amount, expdest);
6309                 return startp;
6310
6311         case VSQUESTION:
6312                 varunset(p, varname, startp, varflags);
6313                 /* NOTREACHED */
6314
6315 #if ENABLE_ASH_BASH_COMPAT
6316         case VSSUBSTR:
6317                 loc = str = stackblock() + strloc;
6318                 /* Read POS in ${var:POS:LEN} */
6319                 pos = atoi(loc); /* number(loc) errors out on "1:4" */
6320                 len = str - startp - 1;
6321
6322                 /* *loc != '\0', guaranteed by parser */
6323                 if (quotes) {
6324                         char *ptr;
6325
6326                         /* Adjust the length by the number of escapes */
6327                         for (ptr = startp; ptr < (str - 1); ptr++) {
6328                                 if ((unsigned char)*ptr == CTLESC) {
6329                                         len--;
6330                                         ptr++;
6331                                 }
6332                         }
6333                 }
6334                 orig_len = len;
6335
6336                 if (*loc++ == ':') {
6337                         /* ${var::LEN} */
6338                         len = number(loc);
6339                 } else {
6340                         /* Skip POS in ${var:POS:LEN} */
6341                         len = orig_len;
6342                         while (*loc && *loc != ':') {
6343                                 /* TODO?
6344                                  * bash complains on: var=qwe; echo ${var:1a:123}
6345                                 if (!isdigit(*loc))
6346                                         ash_msg_and_raise_error(msg_illnum, str);
6347                                  */
6348                                 loc++;
6349                         }
6350                         if (*loc++ == ':') {
6351                                 len = number(loc);
6352                         }
6353                 }
6354                 if (pos >= orig_len) {
6355                         pos = 0;
6356                         len = 0;
6357                 }
6358                 if (len > (orig_len - pos))
6359                         len = orig_len - pos;
6360
6361                 for (str = startp; pos; str++, pos--) {
6362                         if (quotes && (unsigned char)*str == CTLESC)
6363                                 str++;
6364                 }
6365                 for (loc = startp; len; len--) {
6366                         if (quotes && (unsigned char)*str == CTLESC)
6367                                 *loc++ = *str++;
6368                         *loc++ = *str++;
6369                 }
6370                 *loc = '\0';
6371                 amount = loc - expdest;
6372                 STADJUST(amount, expdest);
6373                 return loc;
6374 #endif
6375         }
6376
6377         resetloc = expdest - (char *)stackblock();
6378
6379         /* We'll comeback here if we grow the stack while handling
6380          * a VSREPLACE or VSREPLACEALL, since our pointers into the
6381          * stack will need rebasing, and we'll need to remove our work
6382          * areas each time
6383          */
6384  IF_ASH_BASH_COMPAT(restart:)
6385
6386         amount = expdest - ((char *)stackblock() + resetloc);
6387         STADJUST(-amount, expdest);
6388         startp = (char *)stackblock() + startloc;
6389
6390         rmesc = startp;
6391         rmescend = (char *)stackblock() + strloc;
6392         if (quotes) {
6393                 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6394                 if (rmesc != startp) {
6395                         rmescend = expdest;
6396                         startp = (char *)stackblock() + startloc;
6397                 }
6398         }
6399         rmescend--;
6400         str = (char *)stackblock() + strloc;
6401         preglob(str, varflags & VSQUOTE, 0);
6402         workloc = expdest - (char *)stackblock();
6403
6404 #if ENABLE_ASH_BASH_COMPAT
6405         if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6406                 char *idx, *end;
6407
6408                 if (!repl) {
6409                         repl = parse_sub_pattern(str, varflags);
6410                         //bb_error_msg("repl:'%s'", repl);
6411                         if (!repl)
6412                                 repl = nullstr;
6413                 }
6414
6415                 /* If there's no pattern to match, return the expansion unmolested */
6416                 if (str[0] == '\0')
6417                         return NULL;
6418
6419                 len = 0;
6420                 idx = startp;
6421                 end = str - 1;
6422                 while (idx < end) {
6423  try_to_match:
6424                         loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6425                         //bb_error_msg("scanright('%s'):'%s'", str, loc);
6426                         if (!loc) {
6427                                 /* No match, advance */
6428                                 char *restart_detect = stackblock();
6429  skip_matching:
6430                                 STPUTC(*idx, expdest);
6431                                 if (quotes && (unsigned char)*idx == CTLESC) {
6432                                         idx++;
6433                                         len++;
6434                                         STPUTC(*idx, expdest);
6435                                 }
6436                                 if (stackblock() != restart_detect)
6437                                         goto restart;
6438                                 idx++;
6439                                 len++;
6440                                 rmesc++;
6441                                 /* continue; - prone to quadratic behavior, smarter code: */
6442                                 if (idx >= end)
6443                                         break;
6444                                 if (str[0] == '*') {
6445                                         /* Pattern is "*foo". If "*foo" does not match "long_string",
6446                                          * it would never match "ong_string" etc, no point in trying.
6447                                          */
6448                                         goto skip_matching;
6449                                 }
6450                                 goto try_to_match;
6451                         }
6452
6453                         if (subtype == VSREPLACEALL) {
6454                                 while (idx < loc) {
6455                                         if (quotes && (unsigned char)*idx == CTLESC)
6456                                                 idx++;
6457                                         idx++;
6458                                         rmesc++;
6459                                 }
6460                         } else {
6461                                 idx = loc;
6462                         }
6463
6464                         //bb_error_msg("repl:'%s'", repl);
6465                         for (loc = (char*)repl; *loc; loc++) {
6466                                 char *restart_detect = stackblock();
6467                                 if (quotes && *loc == '\\') {
6468                                         STPUTC(CTLESC, expdest);
6469                                         len++;
6470                                 }
6471                                 STPUTC(*loc, expdest);
6472                                 if (stackblock() != restart_detect)
6473                                         goto restart;
6474                                 len++;
6475                         }
6476
6477                         if (subtype == VSREPLACE) {
6478                                 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
6479                                 while (*idx) {
6480                                         char *restart_detect = stackblock();
6481                                         STPUTC(*idx, expdest);
6482                                         if (stackblock() != restart_detect)
6483                                                 goto restart;
6484                                         len++;
6485                                         idx++;
6486                                 }
6487                                 break;
6488                         }
6489                 }
6490
6491                 /* We've put the replaced text into a buffer at workloc, now
6492                  * move it to the right place and adjust the stack.
6493                  */
6494                 STPUTC('\0', expdest);
6495                 startp = (char *)stackblock() + startloc;
6496                 memmove(startp, (char *)stackblock() + workloc, len + 1);
6497                 //bb_error_msg("startp:'%s'", startp);
6498                 amount = expdest - (startp + len);
6499                 STADJUST(-amount, expdest);
6500                 return startp;
6501         }
6502 #endif /* ENABLE_ASH_BASH_COMPAT */
6503
6504         subtype -= VSTRIMRIGHT;
6505 #if DEBUG
6506         if (subtype < 0 || subtype > 7)
6507                 abort();
6508 #endif
6509         /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
6510         zero = subtype >> 1;
6511         /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6512         scan = (subtype & 1) ^ zero ? scanleft : scanright;
6513
6514         loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6515         if (loc) {
6516                 if (zero) {
6517                         memmove(startp, loc, str - loc);
6518                         loc = startp + (str - loc) - 1;
6519                 }
6520                 *loc = '\0';
6521                 amount = loc - expdest;
6522                 STADJUST(amount, expdest);
6523         }
6524         return loc;
6525 }
6526
6527 /*
6528  * Add the value of a specialized variable to the stack string.
6529  * name parameter (examples):
6530  * ash -c 'echo $1'      name:'1='
6531  * ash -c 'echo $qwe'    name:'qwe='
6532  * ash -c 'echo $$'      name:'$='
6533  * ash -c 'echo ${$}'    name:'$='
6534  * ash -c 'echo ${$##q}' name:'$=q'
6535  * ash -c 'echo ${#$}'   name:'$='
6536  * note: examples with bad shell syntax:
6537  * ash -c 'echo ${#$1}'  name:'$=1'
6538  * ash -c 'echo ${#1#}'  name:'1=#'
6539  */
6540 static NOINLINE ssize_t
6541 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6542 {
6543         const char *p;
6544         int num;
6545         int i;
6546         int sepq = 0;
6547         ssize_t len = 0;
6548         int subtype = varflags & VSTYPE;
6549         int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
6550         int quoted = varflags & VSQUOTE;
6551         int syntax = quoted ? DQSYNTAX : BASESYNTAX;
6552
6553         switch (*name) {
6554         case '$':
6555                 num = rootpid;
6556                 goto numvar;
6557         case '?':
6558                 num = exitstatus;
6559                 goto numvar;
6560         case '#':
6561                 num = shellparam.nparam;
6562                 goto numvar;
6563         case '!':
6564                 num = backgndpid;
6565                 if (num == 0)
6566                         return -1;
6567  numvar:
6568                 len = cvtnum(num);
6569                 goto check_1char_name;
6570         case '-':
6571                 expdest = makestrspace(NOPTS, expdest);
6572                 for (i = NOPTS - 1; i >= 0; i--) {
6573                         if (optlist[i]) {
6574                                 USTPUTC(optletters(i), expdest);
6575                                 len++;
6576                         }
6577                 }
6578  check_1char_name:
6579 #if 0
6580                 /* handles cases similar to ${#$1} */
6581                 if (name[2] != '\0')
6582                         raise_error_syntax("bad substitution");
6583 #endif
6584                 break;
6585         case '@': {
6586                 char **ap;
6587                 int sep;
6588
6589                 if (quoted && (flags & EXP_FULL)) {
6590                         /* note: this is not meant as PEOF value */
6591                         sep = 1 << CHAR_BIT;
6592                         goto param;
6593                 }
6594                 /* fall through */
6595         case '*':
6596                 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
6597                 i = SIT(sep, syntax);
6598                 if (quotes && (i == CCTL || i == CBACK))
6599                         sepq = 1;
6600  param:
6601                 ap = shellparam.p;
6602                 if (!ap)
6603                         return -1;
6604                 while ((p = *ap++) != NULL) {
6605                         size_t partlen;
6606
6607                         partlen = strlen(p);
6608                         len += partlen;
6609
6610                         if (!(subtype == VSPLUS || subtype == VSLENGTH))
6611                                 memtodest(p, partlen, syntax, quotes);
6612
6613                         if (*ap && sep) {
6614                                 char *q;
6615
6616                                 len++;
6617                                 if (subtype == VSPLUS || subtype == VSLENGTH) {
6618                                         continue;
6619                                 }
6620                                 q = expdest;
6621                                 if (sepq)
6622                                         STPUTC(CTLESC, q);
6623                                 /* note: may put NUL despite sep != 0
6624                                  * (see sep = 1 << CHAR_BIT above) */
6625                                 STPUTC(sep, q);
6626                                 expdest = q;
6627                         }
6628                 }
6629                 return len;
6630         } /* case '@' and '*' */
6631         case '0':
6632         case '1':
6633         case '2':
6634         case '3':
6635         case '4':
6636         case '5':
6637         case '6':
6638         case '7':
6639         case '8':
6640         case '9':
6641                 num = atoi(name); /* number(name) fails on ${N#str} etc */
6642                 if (num < 0 || num > shellparam.nparam)
6643                         return -1;
6644                 p = num ? shellparam.p[num - 1] : arg0;
6645                 goto value;
6646         default:
6647                 /* NB: name has form "VAR=..." */
6648
6649                 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6650                  * which should be considered before we check variables. */
6651                 if (var_str_list) {
6652                         unsigned name_len = (strchrnul(name, '=') - name) + 1;
6653                         p = NULL;
6654                         do {
6655                                 char *str, *eq;
6656                                 str = var_str_list->text;
6657                                 eq = strchr(str, '=');
6658                                 if (!eq) /* stop at first non-assignment */
6659                                         break;
6660                                 eq++;
6661                                 if (name_len == (unsigned)(eq - str)
6662                                  && strncmp(str, name, name_len) == 0
6663                                 ) {
6664                                         p = eq;
6665                                         /* goto value; - WRONG! */
6666                                         /* think "A=1 A=2 B=$A" */
6667                                 }
6668                                 var_str_list = var_str_list->next;
6669                         } while (var_str_list);
6670                         if (p)
6671                                 goto value;
6672                 }
6673                 p = lookupvar(name);
6674  value:
6675                 if (!p)
6676                         return -1;
6677
6678                 len = strlen(p);
6679                 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6680                         memtodest(p, len, syntax, quotes);
6681                 return len;
6682         }
6683
6684         if (subtype == VSPLUS || subtype == VSLENGTH)
6685                 STADJUST(-len, expdest);
6686         return len;
6687 }
6688
6689 /*
6690  * Expand a variable, and return a pointer to the next character in the
6691  * input string.
6692  */
6693 static char *
6694 evalvar(char *p, int flags, struct strlist *var_str_list)
6695 {
6696         char varflags;
6697         char subtype;
6698         char quoted;
6699         char easy;
6700         char *var;
6701         int patloc;
6702         int startloc;
6703         ssize_t varlen;
6704
6705         varflags = (unsigned char) *p++;
6706         subtype = varflags & VSTYPE;
6707         quoted = varflags & VSQUOTE;
6708         var = p;
6709         easy = (!quoted || (*var == '@' && shellparam.nparam));
6710         startloc = expdest - (char *)stackblock();
6711         p = strchr(p, '=') + 1; //TODO: use var_end(p)?
6712
6713  again:
6714         varlen = varvalue(var, varflags, flags, var_str_list);
6715         if (varflags & VSNUL)
6716                 varlen--;
6717
6718         if (subtype == VSPLUS) {
6719                 varlen = -1 - varlen;
6720                 goto vsplus;
6721         }
6722
6723         if (subtype == VSMINUS) {
6724  vsplus:
6725                 if (varlen < 0) {
6726                         argstr(
6727                                 p, flags | EXP_TILDE |
6728                                         (quoted ? EXP_QWORD : EXP_WORD),
6729                                 var_str_list
6730                         );
6731                         goto end;
6732                 }
6733                 if (easy)
6734                         goto record;
6735                 goto end;
6736         }
6737
6738         if (subtype == VSASSIGN || subtype == VSQUESTION) {
6739                 if (varlen < 0) {
6740                         if (subevalvar(p, var, /* strloc: */ 0,
6741                                         subtype, startloc, varflags,
6742                                         /* quotes: */ 0,
6743                                         var_str_list)
6744                         ) {
6745                                 varflags &= ~VSNUL;
6746                                 /*
6747                                  * Remove any recorded regions beyond
6748                                  * start of variable
6749                                  */
6750                                 removerecordregions(startloc);
6751                                 goto again;
6752                         }
6753                         goto end;
6754                 }
6755                 if (easy)
6756                         goto record;
6757                 goto end;
6758         }
6759
6760         if (varlen < 0 && uflag)
6761                 varunset(p, var, 0, 0);
6762
6763         if (subtype == VSLENGTH) {
6764                 cvtnum(varlen > 0 ? varlen : 0);
6765                 goto record;
6766         }
6767
6768         if (subtype == VSNORMAL) {
6769                 if (easy)
6770                         goto record;
6771                 goto end;
6772         }
6773
6774 #if DEBUG
6775         switch (subtype) {
6776         case VSTRIMLEFT:
6777         case VSTRIMLEFTMAX:
6778         case VSTRIMRIGHT:
6779         case VSTRIMRIGHTMAX:
6780 #if ENABLE_ASH_BASH_COMPAT
6781         case VSSUBSTR:
6782         case VSREPLACE:
6783         case VSREPLACEALL:
6784 #endif
6785                 break;
6786         default:
6787                 abort();
6788         }
6789 #endif
6790
6791         if (varlen >= 0) {
6792                 /*
6793                  * Terminate the string and start recording the pattern
6794                  * right after it
6795                  */
6796                 STPUTC('\0', expdest);
6797                 patloc = expdest - (char *)stackblock();
6798                 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
6799                                 startloc, varflags,
6800 //TODO: | EXP_REDIR too? All other such places do it too
6801                                 /* quotes: */ flags & (EXP_FULL | EXP_CASE),
6802                                 var_str_list)
6803                 ) {
6804                         int amount = expdest - (
6805                                 (char *)stackblock() + patloc - 1
6806                         );
6807                         STADJUST(-amount, expdest);
6808                 }
6809                 /* Remove any recorded regions beyond start of variable */
6810                 removerecordregions(startloc);
6811  record:
6812                 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6813         }
6814
6815  end:
6816         if (subtype != VSNORMAL) {      /* skip to end of alternative */
6817                 int nesting = 1;
6818                 for (;;) {
6819                         unsigned char c = *p++;
6820                         if (c == CTLESC)
6821                                 p++;
6822                         else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6823                                 if (varlen >= 0)
6824                                         argbackq = argbackq->next;
6825                         } else if (c == CTLVAR) {
6826                                 if ((*p++ & VSTYPE) != VSNORMAL)
6827                                         nesting++;
6828                         } else if (c == CTLENDVAR) {
6829                                 if (--nesting == 0)
6830                                         break;
6831                         }
6832                 }
6833         }
6834         return p;
6835 }
6836
6837 /*
6838  * Break the argument string into pieces based upon IFS and add the
6839  * strings to the argument list.  The regions of the string to be
6840  * searched for IFS characters have been stored by recordregion.
6841  */
6842 static void
6843 ifsbreakup(char *string, struct arglist *arglist)
6844 {
6845         struct ifsregion *ifsp;
6846         struct strlist *sp;
6847         char *start;
6848         char *p;
6849         char *q;
6850         const char *ifs, *realifs;
6851         int ifsspc;
6852         int nulonly;
6853
6854         start = string;
6855         if (ifslastp != NULL) {
6856                 ifsspc = 0;
6857                 nulonly = 0;
6858                 realifs = ifsset() ? ifsval() : defifs;
6859                 ifsp = &ifsfirst;
6860                 do {
6861                         p = string + ifsp->begoff;
6862                         nulonly = ifsp->nulonly;
6863                         ifs = nulonly ? nullstr : realifs;
6864                         ifsspc = 0;
6865                         while (p < string + ifsp->endoff) {
6866                                 q = p;
6867                                 if ((unsigned char)*p == CTLESC)
6868                                         p++;
6869                                 if (!strchr(ifs, *p)) {
6870                                         p++;
6871                                         continue;
6872                                 }
6873                                 if (!nulonly)
6874                                         ifsspc = (strchr(defifs, *p) != NULL);
6875                                 /* Ignore IFS whitespace at start */
6876                                 if (q == start && ifsspc) {
6877                                         p++;
6878                                         start = p;
6879                                         continue;
6880                                 }
6881                                 *q = '\0';
6882                                 sp = stzalloc(sizeof(*sp));
6883                                 sp->text = start;
6884                                 *arglist->lastp = sp;
6885                                 arglist->lastp = &sp->next;
6886                                 p++;
6887                                 if (!nulonly) {
6888                                         for (;;) {
6889                                                 if (p >= string + ifsp->endoff) {
6890                                                         break;
6891                                                 }
6892                                                 q = p;
6893                                                 if ((unsigned char)*p == CTLESC)
6894                                                         p++;
6895                                                 if (strchr(ifs, *p) == NULL) {
6896                                                         p = q;
6897                                                         break;
6898                                                 }
6899                                                 if (strchr(defifs, *p) == NULL) {
6900                                                         if (ifsspc) {
6901                                                                 p++;
6902                                                                 ifsspc = 0;
6903                                                         } else {
6904                                                                 p = q;
6905                                                                 break;
6906                                                         }
6907                                                 } else
6908                                                         p++;
6909                                         }
6910                                 }
6911                                 start = p;
6912                         } /* while */
6913                         ifsp = ifsp->next;
6914                 } while (ifsp != NULL);
6915                 if (nulonly)
6916                         goto add;
6917         }
6918
6919         if (!*start)
6920                 return;
6921
6922  add:
6923         sp = stzalloc(sizeof(*sp));
6924         sp->text = start;
6925         *arglist->lastp = sp;
6926         arglist->lastp = &sp->next;
6927 }
6928
6929 static void
6930 ifsfree(void)
6931 {
6932         struct ifsregion *p;
6933
6934         INT_OFF;
6935         p = ifsfirst.next;
6936         do {
6937                 struct ifsregion *ifsp;
6938                 ifsp = p->next;
6939                 free(p);
6940                 p = ifsp;
6941         } while (p);
6942         ifslastp = NULL;
6943         ifsfirst.next = NULL;
6944         INT_ON;
6945 }
6946
6947 /*
6948  * Add a file name to the list.
6949  */
6950 static void
6951 addfname(const char *name)
6952 {
6953         struct strlist *sp;
6954
6955         sp = stzalloc(sizeof(*sp));
6956         sp->text = ststrdup(name);
6957         *exparg.lastp = sp;
6958         exparg.lastp = &sp->next;
6959 }
6960
6961 /*
6962  * Do metacharacter (i.e. *, ?, [...]) expansion.
6963  */
6964 static void
6965 expmeta(char *expdir, char *enddir, char *name)
6966 {
6967         char *p;
6968         const char *cp;
6969         char *start;
6970         char *endname;
6971         int metaflag;
6972         struct stat statb;
6973         DIR *dirp;
6974         struct dirent *dp;
6975         int atend;
6976         int matchdot;
6977
6978         metaflag = 0;
6979         start = name;
6980         for (p = name; *p; p++) {
6981                 if (*p == '*' || *p == '?')
6982                         metaflag = 1;
6983                 else if (*p == '[') {
6984                         char *q = p + 1;
6985                         if (*q == '!')
6986                                 q++;
6987                         for (;;) {
6988                                 if (*q == '\\')
6989                                         q++;
6990                                 if (*q == '/' || *q == '\0')
6991                                         break;
6992                                 if (*++q == ']') {
6993                                         metaflag = 1;
6994                                         break;
6995                                 }
6996                         }
6997                 } else if (*p == '\\')
6998                         p++;
6999                 else if (*p == '/') {
7000                         if (metaflag)
7001                                 goto out;
7002                         start = p + 1;
7003                 }
7004         }
7005  out:
7006         if (metaflag == 0) {    /* we've reached the end of the file name */
7007                 if (enddir != expdir)
7008                         metaflag++;
7009                 p = name;
7010                 do {
7011                         if (*p == '\\')
7012                                 p++;
7013                         *enddir++ = *p;
7014                 } while (*p++);
7015                 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7016                         addfname(expdir);
7017                 return;
7018         }
7019         endname = p;
7020         if (name < start) {
7021                 p = name;
7022                 do {
7023                         if (*p == '\\')
7024                                 p++;
7025                         *enddir++ = *p++;
7026                 } while (p < start);
7027         }
7028         if (enddir == expdir) {
7029                 cp = ".";
7030         } else if (enddir == expdir + 1 && *expdir == '/') {
7031                 cp = "/";
7032         } else {
7033                 cp = expdir;
7034                 enddir[-1] = '\0';
7035         }
7036         dirp = opendir(cp);
7037         if (dirp == NULL)
7038                 return;
7039         if (enddir != expdir)
7040                 enddir[-1] = '/';
7041         if (*endname == 0) {
7042                 atend = 1;
7043         } else {
7044                 atend = 0;
7045                 *endname++ = '\0';
7046         }
7047         matchdot = 0;
7048         p = start;
7049         if (*p == '\\')
7050                 p++;
7051         if (*p == '.')
7052                 matchdot++;
7053         while (!pending_int && (dp = readdir(dirp)) != NULL) {
7054                 if (dp->d_name[0] == '.' && !matchdot)
7055                         continue;
7056                 if (pmatch(start, dp->d_name)) {
7057                         if (atend) {
7058                                 strcpy(enddir, dp->d_name);
7059                                 addfname(expdir);
7060                         } else {
7061                                 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7062                                         continue;
7063                                 p[-1] = '/';
7064                                 expmeta(expdir, p, endname);
7065                         }
7066                 }
7067         }
7068         closedir(dirp);
7069         if (!atend)
7070                 endname[-1] = '/';
7071 }
7072
7073 static struct strlist *
7074 msort(struct strlist *list, int len)
7075 {
7076         struct strlist *p, *q = NULL;
7077         struct strlist **lpp;
7078         int half;
7079         int n;
7080
7081         if (len <= 1)
7082                 return list;
7083         half = len >> 1;
7084         p = list;
7085         for (n = half; --n >= 0;) {
7086                 q = p;
7087                 p = p->next;
7088         }
7089         q->next = NULL;                 /* terminate first half of list */
7090         q = msort(list, half);          /* sort first half of list */
7091         p = msort(p, len - half);               /* sort second half */
7092         lpp = &list;
7093         for (;;) {
7094 #if ENABLE_LOCALE_SUPPORT
7095                 if (strcoll(p->text, q->text) < 0)
7096 #else
7097                 if (strcmp(p->text, q->text) < 0)
7098 #endif
7099                                                 {
7100                         *lpp = p;
7101                         lpp = &p->next;
7102                         p = *lpp;
7103                         if (p == NULL) {
7104                                 *lpp = q;
7105                                 break;
7106                         }
7107                 } else {
7108                         *lpp = q;
7109                         lpp = &q->next;
7110                         q = *lpp;
7111                         if (q == NULL) {
7112                                 *lpp = p;
7113                                 break;
7114                         }
7115                 }
7116         }
7117         return list;
7118 }
7119
7120 /*
7121  * Sort the results of file name expansion.  It calculates the number of
7122  * strings to sort and then calls msort (short for merge sort) to do the
7123  * work.
7124  */
7125 static struct strlist *
7126 expsort(struct strlist *str)
7127 {
7128         int len;
7129         struct strlist *sp;
7130
7131         len = 0;
7132         for (sp = str; sp; sp = sp->next)
7133                 len++;
7134         return msort(str, len);
7135 }
7136
7137 static void
7138 expandmeta(struct strlist *str /*, int flag*/)
7139 {
7140         static const char metachars[] ALIGN1 = {
7141                 '*', '?', '[', 0
7142         };
7143         /* TODO - EXP_REDIR */
7144
7145         while (str) {
7146                 char *expdir;
7147                 struct strlist **savelastp;
7148                 struct strlist *sp;
7149                 char *p;
7150
7151                 if (fflag)
7152                         goto nometa;
7153                 if (!strpbrk(str->text, metachars))
7154                         goto nometa;
7155                 savelastp = exparg.lastp;
7156
7157                 INT_OFF;
7158                 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7159                 {
7160                         int i = strlen(str->text);
7161                         expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7162                 }
7163                 expmeta(expdir, expdir, p);
7164                 free(expdir);
7165                 if (p != str->text)
7166                         free(p);
7167                 INT_ON;
7168                 if (exparg.lastp == savelastp) {
7169                         /*
7170                          * no matches
7171                          */
7172  nometa:
7173                         *exparg.lastp = str;
7174                         rmescapes(str->text, 0);
7175                         exparg.lastp = &str->next;
7176                 } else {
7177                         *exparg.lastp = NULL;
7178                         *savelastp = sp = expsort(*savelastp);
7179                         while (sp->next != NULL)
7180                                 sp = sp->next;
7181                         exparg.lastp = &sp->next;
7182                 }
7183                 str = str->next;
7184         }
7185 }
7186
7187 /*
7188  * Perform variable substitution and command substitution on an argument,
7189  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
7190  * perform splitting and file name expansion.  When arglist is NULL, perform
7191  * here document expansion.
7192  */
7193 static void
7194 expandarg(union node *arg, struct arglist *arglist, int flag)
7195 {
7196         struct strlist *sp;
7197         char *p;
7198
7199         argbackq = arg->narg.backquote;
7200         STARTSTACKSTR(expdest);
7201         ifsfirst.next = NULL;
7202         ifslastp = NULL;
7203         argstr(arg->narg.text, flag,
7204                         /* var_str_list: */ arglist ? arglist->list : NULL);
7205         p = _STPUTC('\0', expdest);
7206         expdest = p - 1;
7207         if (arglist == NULL) {
7208                 return;                 /* here document expanded */
7209         }
7210         p = grabstackstr(p);
7211         exparg.lastp = &exparg.list;
7212         /*
7213          * TODO - EXP_REDIR
7214          */
7215         if (flag & EXP_FULL) {
7216                 ifsbreakup(p, &exparg);
7217                 *exparg.lastp = NULL;
7218                 exparg.lastp = &exparg.list;
7219                 expandmeta(exparg.list /*, flag*/);
7220         } else {
7221                 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
7222                         rmescapes(p, 0);
7223                 sp = stzalloc(sizeof(*sp));
7224                 sp->text = p;
7225                 *exparg.lastp = sp;
7226                 exparg.lastp = &sp->next;
7227         }
7228         if (ifsfirst.next)
7229                 ifsfree();
7230         *exparg.lastp = NULL;
7231         if (exparg.list) {
7232                 *arglist->lastp = exparg.list;
7233                 arglist->lastp = exparg.lastp;
7234         }
7235 }
7236
7237 /*
7238  * Expand shell variables and backquotes inside a here document.
7239  */
7240 static void
7241 expandhere(union node *arg, int fd)
7242 {
7243         herefd = fd;
7244         expandarg(arg, (struct arglist *)NULL, 0);
7245         full_write(fd, stackblock(), expdest - (char *)stackblock());
7246 }
7247
7248 /*
7249  * Returns true if the pattern matches the string.
7250  */
7251 static int
7252 patmatch(char *pattern, const char *string)
7253 {
7254         return pmatch(preglob(pattern, 0, 0), string);
7255 }
7256
7257 /*
7258  * See if a pattern matches in a case statement.
7259  */
7260 static int
7261 casematch(union node *pattern, char *val)
7262 {
7263         struct stackmark smark;
7264         int result;
7265
7266         setstackmark(&smark);
7267         argbackq = pattern->narg.backquote;
7268         STARTSTACKSTR(expdest);
7269         ifslastp = NULL;
7270         argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7271                         /* var_str_list: */ NULL);
7272         STACKSTRNUL(expdest);
7273         result = patmatch(stackblock(), val);
7274         popstackmark(&smark);
7275         return result;
7276 }
7277
7278
7279 /* ============ find_command */
7280
7281 struct builtincmd {
7282         const char *name;
7283         int (*builtin)(int, char **) FAST_FUNC;
7284         /* unsigned flags; */
7285 };
7286 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7287 /* "regular" builtins always take precedence over commands,
7288  * regardless of PATH=....%builtin... position */
7289 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7290 #define IS_BUILTIN_ASSIGN(b)  ((b)->name[0] & 4)
7291
7292 struct cmdentry {
7293         smallint cmdtype;       /* CMDxxx */
7294         union param {
7295                 int index;
7296                 /* index >= 0 for commands without path (slashes) */
7297                 /* (TODO: what exactly does the value mean? PATH position?) */
7298                 /* index == -1 for commands with slashes */
7299                 /* index == (-2 - applet_no) for NOFORK applets */
7300                 const struct builtincmd *cmd;
7301                 struct funcnode *func;
7302         } u;
7303 };
7304 /* values of cmdtype */
7305 #define CMDUNKNOWN      -1      /* no entry in table for command */
7306 #define CMDNORMAL       0       /* command is an executable program */
7307 #define CMDFUNCTION     1       /* command is a shell function */
7308 #define CMDBUILTIN      2       /* command is a shell builtin */
7309
7310 /* action to find_command() */
7311 #define DO_ERR          0x01    /* prints errors */
7312 #define DO_ABS          0x02    /* checks absolute paths */
7313 #define DO_NOFUNC       0x04    /* don't return shell functions, for command */
7314 #define DO_ALTPATH      0x08    /* using alternate path */
7315 #define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
7316
7317 static void find_command(char *, struct cmdentry *, int, const char *);
7318
7319
7320 /* ============ Hashing commands */
7321
7322 /*
7323  * When commands are first encountered, they are entered in a hash table.
7324  * This ensures that a full path search will not have to be done for them
7325  * on each invocation.
7326  *
7327  * We should investigate converting to a linear search, even though that
7328  * would make the command name "hash" a misnomer.
7329  */
7330
7331 struct tblentry {
7332         struct tblentry *next;  /* next entry in hash chain */
7333         union param param;      /* definition of builtin function */
7334         smallint cmdtype;       /* CMDxxx */
7335         char rehash;            /* if set, cd done since entry created */
7336         char cmdname[1];        /* name of command */
7337 };
7338
7339 static struct tblentry **cmdtable;
7340 #define INIT_G_cmdtable() do { \
7341         cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7342 } while (0)
7343
7344 static int builtinloc = -1;     /* index in path of %builtin, or -1 */
7345
7346
7347 static void
7348 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7349 {
7350         int repeated = 0;
7351
7352 #if ENABLE_FEATURE_SH_STANDALONE
7353         if (applet_no >= 0) {
7354                 if (APPLET_IS_NOEXEC(applet_no)) {
7355                         clearenv();
7356                         while (*envp)
7357                                 putenv(*envp++);
7358                         run_applet_no_and_exit(applet_no, argv);
7359                 }
7360                 /* re-exec ourselves with the new arguments */
7361                 execve(bb_busybox_exec_path, argv, envp);
7362                 /* If they called chroot or otherwise made the binary no longer
7363                  * executable, fall through */
7364         }
7365 #endif
7366
7367  repeat:
7368 #ifdef SYSV
7369         do {
7370                 execve(cmd, argv, envp);
7371         } while (errno == EINTR);
7372 #else
7373         execve(cmd, argv, envp);
7374 #endif
7375         if (repeated) {
7376                 free(argv);
7377                 return;
7378         }
7379         if (errno == ENOEXEC) {
7380                 char **ap;
7381                 char **new;
7382
7383                 for (ap = argv; *ap; ap++)
7384                         continue;
7385                 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
7386                 ap[1] = cmd;
7387                 ap[0] = cmd = (char *)DEFAULT_SHELL;
7388                 ap += 2;
7389                 argv++;
7390                 while ((*ap++ = *argv++) != NULL)
7391                         continue;
7392                 argv = new;
7393                 repeated++;
7394                 goto repeat;
7395         }
7396 }
7397
7398 /*
7399  * Exec a program.  Never returns.  If you change this routine, you may
7400  * have to change the find_command routine as well.
7401  */
7402 static void shellexec(char **, const char *, int) NORETURN;
7403 static void
7404 shellexec(char **argv, const char *path, int idx)
7405 {
7406         char *cmdname;
7407         int e;
7408         char **envp;
7409         int exerrno;
7410 #if ENABLE_FEATURE_SH_STANDALONE
7411         int applet_no = -1;
7412 #endif
7413
7414         clearredir(/*drop:*/ 1);
7415         envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7416         if (strchr(argv[0], '/') != NULL
7417 #if ENABLE_FEATURE_SH_STANDALONE
7418          || (applet_no = find_applet_by_name(argv[0])) >= 0
7419 #endif
7420         ) {
7421                 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7422                 e = errno;
7423         } else {
7424                 e = ENOENT;
7425                 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
7426                         if (--idx < 0 && pathopt == NULL) {
7427                                 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7428                                 if (errno != ENOENT && errno != ENOTDIR)
7429                                         e = errno;
7430                         }
7431                         stunalloc(cmdname);
7432                 }
7433         }
7434
7435         /* Map to POSIX errors */
7436         switch (e) {
7437         case EACCES:
7438                 exerrno = 126;
7439                 break;
7440         case ENOENT:
7441                 exerrno = 127;
7442                 break;
7443         default:
7444                 exerrno = 2;
7445                 break;
7446         }
7447         exitstatus = exerrno;
7448         TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7449                 argv[0], e, suppress_int));
7450         ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7451         /* NOTREACHED */
7452 }
7453
7454 static void
7455 printentry(struct tblentry *cmdp)
7456 {
7457         int idx;
7458         const char *path;
7459         char *name;
7460
7461         idx = cmdp->param.index;
7462         path = pathval();
7463         do {
7464                 name = path_advance(&path, cmdp->cmdname);
7465                 stunalloc(name);
7466         } while (--idx >= 0);
7467         out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7468 }
7469
7470 /*
7471  * Clear out command entries.  The argument specifies the first entry in
7472  * PATH which has changed.
7473  */
7474 static void
7475 clearcmdentry(int firstchange)
7476 {
7477         struct tblentry **tblp;
7478         struct tblentry **pp;
7479         struct tblentry *cmdp;
7480
7481         INT_OFF;
7482         for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7483                 pp = tblp;
7484                 while ((cmdp = *pp) != NULL) {
7485                         if ((cmdp->cmdtype == CMDNORMAL &&
7486                              cmdp->param.index >= firstchange)
7487                          || (cmdp->cmdtype == CMDBUILTIN &&
7488                              builtinloc >= firstchange)
7489                         ) {
7490                                 *pp = cmdp->next;
7491                                 free(cmdp);
7492                         } else {
7493                                 pp = &cmdp->next;
7494                         }
7495                 }
7496         }
7497         INT_ON;
7498 }
7499
7500 /*
7501  * Locate a command in the command hash table.  If "add" is nonzero,
7502  * add the command to the table if it is not already present.  The
7503  * variable "lastcmdentry" is set to point to the address of the link
7504  * pointing to the entry, so that delete_cmd_entry can delete the
7505  * entry.
7506  *
7507  * Interrupts must be off if called with add != 0.
7508  */
7509 static struct tblentry **lastcmdentry;
7510
7511 static struct tblentry *
7512 cmdlookup(const char *name, int add)
7513 {
7514         unsigned int hashval;
7515         const char *p;
7516         struct tblentry *cmdp;
7517         struct tblentry **pp;
7518
7519         p = name;
7520         hashval = (unsigned char)*p << 4;
7521         while (*p)
7522                 hashval += (unsigned char)*p++;
7523         hashval &= 0x7FFF;
7524         pp = &cmdtable[hashval % CMDTABLESIZE];
7525         for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7526                 if (strcmp(cmdp->cmdname, name) == 0)
7527                         break;
7528                 pp = &cmdp->next;
7529         }
7530         if (add && cmdp == NULL) {
7531                 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7532                                 + strlen(name)
7533                                 /* + 1 - already done because
7534                                  * tblentry::cmdname is char[1] */);
7535                 /*cmdp->next = NULL; - ckzalloc did it */
7536                 cmdp->cmdtype = CMDUNKNOWN;
7537                 strcpy(cmdp->cmdname, name);
7538         }
7539         lastcmdentry = pp;
7540         return cmdp;
7541 }
7542
7543 /*
7544  * Delete the command entry returned on the last lookup.
7545  */
7546 static void
7547 delete_cmd_entry(void)
7548 {
7549         struct tblentry *cmdp;
7550
7551         INT_OFF;
7552         cmdp = *lastcmdentry;
7553         *lastcmdentry = cmdp->next;
7554         if (cmdp->cmdtype == CMDFUNCTION)
7555                 freefunc(cmdp->param.func);
7556         free(cmdp);
7557         INT_ON;
7558 }
7559
7560 /*
7561  * Add a new command entry, replacing any existing command entry for
7562  * the same name - except special builtins.
7563  */
7564 static void
7565 addcmdentry(char *name, struct cmdentry *entry)
7566 {
7567         struct tblentry *cmdp;
7568
7569         cmdp = cmdlookup(name, 1);
7570         if (cmdp->cmdtype == CMDFUNCTION) {
7571                 freefunc(cmdp->param.func);
7572         }
7573         cmdp->cmdtype = entry->cmdtype;
7574         cmdp->param = entry->u;
7575         cmdp->rehash = 0;
7576 }
7577
7578 static int FAST_FUNC
7579 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7580 {
7581         struct tblentry **pp;
7582         struct tblentry *cmdp;
7583         int c;
7584         struct cmdentry entry;
7585         char *name;
7586
7587         if (nextopt("r") != '\0') {
7588                 clearcmdentry(0);
7589                 return 0;
7590         }
7591
7592         if (*argptr == NULL) {
7593                 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7594                         for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7595                                 if (cmdp->cmdtype == CMDNORMAL)
7596                                         printentry(cmdp);
7597                         }
7598                 }
7599                 return 0;
7600         }
7601
7602         c = 0;
7603         while ((name = *argptr) != NULL) {
7604                 cmdp = cmdlookup(name, 0);
7605                 if (cmdp != NULL
7606                  && (cmdp->cmdtype == CMDNORMAL
7607                      || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7608                 ) {
7609                         delete_cmd_entry();
7610                 }
7611                 find_command(name, &entry, DO_ERR, pathval());
7612                 if (entry.cmdtype == CMDUNKNOWN)
7613                         c = 1;
7614                 argptr++;
7615         }
7616         return c;
7617 }
7618
7619 /*
7620  * Called when a cd is done.  Marks all commands so the next time they
7621  * are executed they will be rehashed.
7622  */
7623 static void
7624 hashcd(void)
7625 {
7626         struct tblentry **pp;
7627         struct tblentry *cmdp;
7628
7629         for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7630                 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7631                         if (cmdp->cmdtype == CMDNORMAL
7632                          || (cmdp->cmdtype == CMDBUILTIN
7633                              && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7634                              && builtinloc > 0)
7635                         ) {
7636                                 cmdp->rehash = 1;
7637                         }
7638                 }
7639         }
7640 }
7641
7642 /*
7643  * Fix command hash table when PATH changed.
7644  * Called before PATH is changed.  The argument is the new value of PATH;
7645  * pathval() still returns the old value at this point.
7646  * Called with interrupts off.
7647  */
7648 static void FAST_FUNC
7649 changepath(const char *new)
7650 {
7651         const char *old;
7652         int firstchange;
7653         int idx;
7654         int idx_bltin;
7655
7656         old = pathval();
7657         firstchange = 9999;     /* assume no change */
7658         idx = 0;
7659         idx_bltin = -1;
7660         for (;;) {
7661                 if (*old != *new) {
7662                         firstchange = idx;
7663                         if ((*old == '\0' && *new == ':')
7664                          || (*old == ':' && *new == '\0')
7665                         ) {
7666                                 firstchange++;
7667                         }
7668                         old = new;      /* ignore subsequent differences */
7669                 }
7670                 if (*new == '\0')
7671                         break;
7672                 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7673                         idx_bltin = idx;
7674                 if (*new == ':')
7675                         idx++;
7676                 new++;
7677                 old++;
7678         }
7679         if (builtinloc < 0 && idx_bltin >= 0)
7680                 builtinloc = idx_bltin;             /* zap builtins */
7681         if (builtinloc >= 0 && idx_bltin < 0)
7682                 firstchange = 0;
7683         clearcmdentry(firstchange);
7684         builtinloc = idx_bltin;
7685 }
7686
7687 #define TEOF 0
7688 #define TNL 1
7689 #define TREDIR 2
7690 #define TWORD 3
7691 #define TSEMI 4
7692 #define TBACKGND 5
7693 #define TAND 6
7694 #define TOR 7
7695 #define TPIPE 8
7696 #define TLP 9
7697 #define TRP 10
7698 #define TENDCASE 11
7699 #define TENDBQUOTE 12
7700 #define TNOT 13
7701 #define TCASE 14
7702 #define TDO 15
7703 #define TDONE 16
7704 #define TELIF 17
7705 #define TELSE 18
7706 #define TESAC 19
7707 #define TFI 20
7708 #define TFOR 21
7709 #define TIF 22
7710 #define TIN 23
7711 #define TTHEN 24
7712 #define TUNTIL 25
7713 #define TWHILE 26
7714 #define TBEGIN 27
7715 #define TEND 28
7716 typedef smallint token_id_t;
7717
7718 /* first char is indicating which tokens mark the end of a list */
7719 static const char *const tokname_array[] = {
7720         "\1end of file",
7721         "\0newline",
7722         "\0redirection",
7723         "\0word",
7724         "\0;",
7725         "\0&",
7726         "\0&&",
7727         "\0||",
7728         "\0|",
7729         "\0(",
7730         "\1)",
7731         "\1;;",
7732         "\1`",
7733 #define KWDOFFSET 13
7734         /* the following are keywords */
7735         "\0!",
7736         "\0case",
7737         "\1do",
7738         "\1done",
7739         "\1elif",
7740         "\1else",
7741         "\1esac",
7742         "\1fi",
7743         "\0for",
7744         "\0if",
7745         "\0in",
7746         "\1then",
7747         "\0until",
7748         "\0while",
7749         "\0{",
7750         "\1}",
7751 };
7752
7753 /* Wrapper around strcmp for qsort/bsearch/... */
7754 static int
7755 pstrcmp(const void *a, const void *b)
7756 {
7757         return strcmp((char*) a, (*(char**) b) + 1);
7758 }
7759
7760 static const char *const *
7761 findkwd(const char *s)
7762 {
7763         return bsearch(s, tokname_array + KWDOFFSET,
7764                         ARRAY_SIZE(tokname_array) - KWDOFFSET,
7765                         sizeof(tokname_array[0]), pstrcmp);
7766 }
7767
7768 /*
7769  * Locate and print what a word is...
7770  */
7771 static int
7772 describe_command(char *command, int describe_command_verbose)
7773 {
7774         struct cmdentry entry;
7775         struct tblentry *cmdp;
7776 #if ENABLE_ASH_ALIAS
7777         const struct alias *ap;
7778 #endif
7779         const char *path = pathval();
7780
7781         if (describe_command_verbose) {
7782                 out1str(command);
7783         }
7784
7785         /* First look at the keywords */
7786         if (findkwd(command)) {
7787                 out1str(describe_command_verbose ? " is a shell keyword" : command);
7788                 goto out;
7789         }
7790
7791 #if ENABLE_ASH_ALIAS
7792         /* Then look at the aliases */
7793         ap = lookupalias(command, 0);
7794         if (ap != NULL) {
7795                 if (!describe_command_verbose) {
7796                         out1str("alias ");
7797                         printalias(ap);
7798                         return 0;
7799                 }
7800                 out1fmt(" is an alias for %s", ap->val);
7801                 goto out;
7802         }
7803 #endif
7804         /* Then check if it is a tracked alias */
7805         cmdp = cmdlookup(command, 0);
7806         if (cmdp != NULL) {
7807                 entry.cmdtype = cmdp->cmdtype;
7808                 entry.u = cmdp->param;
7809         } else {
7810                 /* Finally use brute force */
7811                 find_command(command, &entry, DO_ABS, path);
7812         }
7813
7814         switch (entry.cmdtype) {
7815         case CMDNORMAL: {
7816                 int j = entry.u.index;
7817                 char *p;
7818                 if (j < 0) {
7819                         p = command;
7820                 } else {
7821                         do {
7822                                 p = path_advance(&path, command);
7823                                 stunalloc(p);
7824                         } while (--j >= 0);
7825                 }
7826                 if (describe_command_verbose) {
7827                         out1fmt(" is%s %s",
7828                                 (cmdp ? " a tracked alias for" : nullstr), p
7829                         );
7830                 } else {
7831                         out1str(p);
7832                 }
7833                 break;
7834         }
7835
7836         case CMDFUNCTION:
7837                 if (describe_command_verbose) {
7838                         out1str(" is a shell function");
7839                 } else {
7840                         out1str(command);
7841                 }
7842                 break;
7843
7844         case CMDBUILTIN:
7845                 if (describe_command_verbose) {
7846                         out1fmt(" is a %sshell builtin",
7847                                 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7848                                         "special " : nullstr
7849                         );
7850                 } else {
7851                         out1str(command);
7852                 }
7853                 break;
7854
7855         default:
7856                 if (describe_command_verbose) {
7857                         out1str(": not found\n");
7858                 }
7859                 return 127;
7860         }
7861  out:
7862         out1str("\n");
7863         return 0;
7864 }
7865
7866 static int FAST_FUNC
7867 typecmd(int argc UNUSED_PARAM, char **argv)
7868 {
7869         int i = 1;
7870         int err = 0;
7871         int verbose = 1;
7872
7873         /* type -p ... ? (we don't bother checking for 'p') */
7874         if (argv[1] && argv[1][0] == '-') {
7875                 i++;
7876                 verbose = 0;
7877         }
7878         while (argv[i]) {
7879                 err |= describe_command(argv[i++], verbose);
7880         }
7881         return err;
7882 }
7883
7884 #if ENABLE_ASH_CMDCMD
7885 static int FAST_FUNC
7886 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7887 {
7888         int c;
7889         enum {
7890                 VERIFY_BRIEF = 1,
7891                 VERIFY_VERBOSE = 2,
7892         } verify = 0;
7893
7894         while ((c = nextopt("pvV")) != '\0')
7895                 if (c == 'V')
7896                         verify |= VERIFY_VERBOSE;
7897                 else if (c == 'v')
7898                         verify |= VERIFY_BRIEF;
7899 #if DEBUG
7900                 else if (c != 'p')
7901                         abort();
7902 #endif
7903         /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7904         if (verify && (*argptr != NULL)) {
7905                 return describe_command(*argptr, verify - VERIFY_BRIEF);
7906         }
7907
7908         return 0;
7909 }
7910 #endif
7911
7912
7913 /* ============ eval.c */
7914
7915 static int funcblocksize;       /* size of structures in function */
7916 static int funcstringsize;      /* size of strings in node */
7917 static void *funcblock;         /* block to allocate function from */
7918 static char *funcstring;        /* block to allocate strings from */
7919
7920 /* flags in argument to evaltree */
7921 #define EV_EXIT    01           /* exit after evaluating tree */
7922 #define EV_TESTED  02           /* exit status is checked; ignore -e flag */
7923 #define EV_BACKCMD 04           /* command executing within back quotes */
7924
7925 static const uint8_t nodesize[N_NUMBER] = {
7926         [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
7927         [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
7928         [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
7929         [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7930         [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7931         [NAND     ] = SHELL_ALIGN(sizeof(struct nbinary)),
7932         [NOR      ] = SHELL_ALIGN(sizeof(struct nbinary)),
7933         [NSEMI    ] = SHELL_ALIGN(sizeof(struct nbinary)),
7934         [NIF      ] = SHELL_ALIGN(sizeof(struct nif)),
7935         [NWHILE   ] = SHELL_ALIGN(sizeof(struct nbinary)),
7936         [NUNTIL   ] = SHELL_ALIGN(sizeof(struct nbinary)),
7937         [NFOR     ] = SHELL_ALIGN(sizeof(struct nfor)),
7938         [NCASE    ] = SHELL_ALIGN(sizeof(struct ncase)),
7939         [NCLIST   ] = SHELL_ALIGN(sizeof(struct nclist)),
7940         [NDEFUN   ] = SHELL_ALIGN(sizeof(struct narg)),
7941         [NARG     ] = SHELL_ALIGN(sizeof(struct narg)),
7942         [NTO      ] = SHELL_ALIGN(sizeof(struct nfile)),
7943 #if ENABLE_ASH_BASH_COMPAT
7944         [NTO2     ] = SHELL_ALIGN(sizeof(struct nfile)),
7945 #endif
7946         [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
7947         [NFROM    ] = SHELL_ALIGN(sizeof(struct nfile)),
7948         [NFROMTO  ] = SHELL_ALIGN(sizeof(struct nfile)),
7949         [NAPPEND  ] = SHELL_ALIGN(sizeof(struct nfile)),
7950         [NTOFD    ] = SHELL_ALIGN(sizeof(struct ndup)),
7951         [NFROMFD  ] = SHELL_ALIGN(sizeof(struct ndup)),
7952         [NHERE    ] = SHELL_ALIGN(sizeof(struct nhere)),
7953         [NXHERE   ] = SHELL_ALIGN(sizeof(struct nhere)),
7954         [NNOT     ] = SHELL_ALIGN(sizeof(struct nnot)),
7955 };
7956
7957 static void calcsize(union node *n);
7958
7959 static void
7960 sizenodelist(struct nodelist *lp)
7961 {
7962         while (lp) {
7963                 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7964                 calcsize(lp->n);
7965                 lp = lp->next;
7966         }
7967 }
7968
7969 static void
7970 calcsize(union node *n)
7971 {
7972         if (n == NULL)
7973                 return;
7974         funcblocksize += nodesize[n->type];
7975         switch (n->type) {
7976         case NCMD:
7977                 calcsize(n->ncmd.redirect);
7978                 calcsize(n->ncmd.args);
7979                 calcsize(n->ncmd.assign);
7980                 break;
7981         case NPIPE:
7982                 sizenodelist(n->npipe.cmdlist);
7983                 break;
7984         case NREDIR:
7985         case NBACKGND:
7986         case NSUBSHELL:
7987                 calcsize(n->nredir.redirect);
7988                 calcsize(n->nredir.n);
7989                 break;
7990         case NAND:
7991         case NOR:
7992         case NSEMI:
7993         case NWHILE:
7994         case NUNTIL:
7995                 calcsize(n->nbinary.ch2);
7996                 calcsize(n->nbinary.ch1);
7997                 break;
7998         case NIF:
7999                 calcsize(n->nif.elsepart);
8000                 calcsize(n->nif.ifpart);
8001                 calcsize(n->nif.test);
8002                 break;
8003         case NFOR:
8004                 funcstringsize += strlen(n->nfor.var) + 1;
8005                 calcsize(n->nfor.body);
8006                 calcsize(n->nfor.args);
8007                 break;
8008         case NCASE:
8009                 calcsize(n->ncase.cases);
8010                 calcsize(n->ncase.expr);
8011                 break;
8012         case NCLIST:
8013                 calcsize(n->nclist.body);
8014                 calcsize(n->nclist.pattern);
8015                 calcsize(n->nclist.next);
8016                 break;
8017         case NDEFUN:
8018         case NARG:
8019                 sizenodelist(n->narg.backquote);
8020                 funcstringsize += strlen(n->narg.text) + 1;
8021                 calcsize(n->narg.next);
8022                 break;
8023         case NTO:
8024 #if ENABLE_ASH_BASH_COMPAT
8025         case NTO2:
8026 #endif
8027         case NCLOBBER:
8028         case NFROM:
8029         case NFROMTO:
8030         case NAPPEND:
8031                 calcsize(n->nfile.fname);
8032                 calcsize(n->nfile.next);
8033                 break;
8034         case NTOFD:
8035         case NFROMFD:
8036                 calcsize(n->ndup.vname);
8037                 calcsize(n->ndup.next);
8038         break;
8039         case NHERE:
8040         case NXHERE:
8041                 calcsize(n->nhere.doc);
8042                 calcsize(n->nhere.next);
8043                 break;
8044         case NNOT:
8045                 calcsize(n->nnot.com);
8046                 break;
8047         };
8048 }
8049
8050 static char *
8051 nodeckstrdup(char *s)
8052 {
8053         char *rtn = funcstring;
8054
8055         strcpy(funcstring, s);
8056         funcstring += strlen(s) + 1;
8057         return rtn;
8058 }
8059
8060 static union node *copynode(union node *);
8061
8062 static struct nodelist *
8063 copynodelist(struct nodelist *lp)
8064 {
8065         struct nodelist *start;
8066         struct nodelist **lpp;
8067
8068         lpp = &start;
8069         while (lp) {
8070                 *lpp = funcblock;
8071                 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8072                 (*lpp)->n = copynode(lp->n);
8073                 lp = lp->next;
8074                 lpp = &(*lpp)->next;
8075         }
8076         *lpp = NULL;
8077         return start;
8078 }
8079
8080 static union node *
8081 copynode(union node *n)
8082 {
8083         union node *new;
8084
8085         if (n == NULL)
8086                 return NULL;
8087         new = funcblock;
8088         funcblock = (char *) funcblock + nodesize[n->type];
8089
8090         switch (n->type) {
8091         case NCMD:
8092                 new->ncmd.redirect = copynode(n->ncmd.redirect);
8093                 new->ncmd.args = copynode(n->ncmd.args);
8094                 new->ncmd.assign = copynode(n->ncmd.assign);
8095                 break;
8096         case NPIPE:
8097                 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8098                 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8099                 break;
8100         case NREDIR:
8101         case NBACKGND:
8102         case NSUBSHELL:
8103                 new->nredir.redirect = copynode(n->nredir.redirect);
8104                 new->nredir.n = copynode(n->nredir.n);
8105                 break;
8106         case NAND:
8107         case NOR:
8108         case NSEMI:
8109         case NWHILE:
8110         case NUNTIL:
8111                 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8112                 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8113                 break;
8114         case NIF:
8115                 new->nif.elsepart = copynode(n->nif.elsepart);
8116                 new->nif.ifpart = copynode(n->nif.ifpart);
8117                 new->nif.test = copynode(n->nif.test);
8118                 break;
8119         case NFOR:
8120                 new->nfor.var = nodeckstrdup(n->nfor.var);
8121                 new->nfor.body = copynode(n->nfor.body);
8122                 new->nfor.args = copynode(n->nfor.args);
8123                 break;
8124         case NCASE:
8125                 new->ncase.cases = copynode(n->ncase.cases);
8126                 new->ncase.expr = copynode(n->ncase.expr);
8127                 break;
8128         case NCLIST:
8129                 new->nclist.body = copynode(n->nclist.body);
8130                 new->nclist.pattern = copynode(n->nclist.pattern);
8131                 new->nclist.next = copynode(n->nclist.next);
8132                 break;
8133         case NDEFUN:
8134         case NARG:
8135                 new->narg.backquote = copynodelist(n->narg.backquote);
8136                 new->narg.text = nodeckstrdup(n->narg.text);
8137                 new->narg.next = copynode(n->narg.next);
8138                 break;
8139         case NTO:
8140 #if ENABLE_ASH_BASH_COMPAT
8141         case NTO2:
8142 #endif
8143         case NCLOBBER:
8144         case NFROM:
8145         case NFROMTO:
8146         case NAPPEND:
8147                 new->nfile.fname = copynode(n->nfile.fname);
8148                 new->nfile.fd = n->nfile.fd;
8149                 new->nfile.next = copynode(n->nfile.next);
8150                 break;
8151         case NTOFD:
8152         case NFROMFD:
8153                 new->ndup.vname = copynode(n->ndup.vname);
8154                 new->ndup.dupfd = n->ndup.dupfd;
8155                 new->ndup.fd = n->ndup.fd;
8156                 new->ndup.next = copynode(n->ndup.next);
8157                 break;
8158         case NHERE:
8159         case NXHERE:
8160                 new->nhere.doc = copynode(n->nhere.doc);
8161                 new->nhere.fd = n->nhere.fd;
8162                 new->nhere.next = copynode(n->nhere.next);
8163                 break;
8164         case NNOT:
8165                 new->nnot.com = copynode(n->nnot.com);
8166                 break;
8167         };
8168         new->type = n->type;
8169         return new;
8170 }
8171
8172 /*
8173  * Make a copy of a parse tree.
8174  */
8175 static struct funcnode *
8176 copyfunc(union node *n)
8177 {
8178         struct funcnode *f;
8179         size_t blocksize;
8180
8181         funcblocksize = offsetof(struct funcnode, n);
8182         funcstringsize = 0;
8183         calcsize(n);
8184         blocksize = funcblocksize;
8185         f = ckmalloc(blocksize + funcstringsize);
8186         funcblock = (char *) f + offsetof(struct funcnode, n);
8187         funcstring = (char *) f + blocksize;
8188         copynode(n);
8189         f->count = 0;
8190         return f;
8191 }
8192
8193 /*
8194  * Define a shell function.
8195  */
8196 static void
8197 defun(char *name, union node *func)
8198 {
8199         struct cmdentry entry;
8200
8201         INT_OFF;
8202         entry.cmdtype = CMDFUNCTION;
8203         entry.u.func = copyfunc(func);
8204         addcmdentry(name, &entry);
8205         INT_ON;
8206 }
8207
8208 /* Reasons for skipping commands (see comment on breakcmd routine) */
8209 #define SKIPBREAK      (1 << 0)
8210 #define SKIPCONT       (1 << 1)
8211 #define SKIPFUNC       (1 << 2)
8212 #define SKIPFILE       (1 << 3)
8213 #define SKIPEVAL       (1 << 4)
8214 static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
8215 static int skipcount;           /* number of levels to skip */
8216 static int funcnest;            /* depth of function calls */
8217 static int loopnest;            /* current loop nesting level */
8218
8219 /* Forward decl way out to parsing code - dotrap needs it */
8220 static int evalstring(char *s, int mask);
8221
8222 /* Called to execute a trap.
8223  * Single callsite - at the end of evaltree().
8224  * If we return non-zero, exaltree raises EXEXIT exception.
8225  *
8226  * Perhaps we should avoid entering new trap handlers
8227  * while we are executing a trap handler. [is it a TODO?]
8228  */
8229 static int
8230 dotrap(void)
8231 {
8232         uint8_t *g;
8233         int sig;
8234         uint8_t savestatus;
8235
8236         savestatus = exitstatus;
8237         pending_sig = 0;
8238         xbarrier();
8239
8240         TRACE(("dotrap entered\n"));
8241         for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8242                 int want_exexit;
8243                 char *t;
8244
8245                 if (*g == 0)
8246                         continue;
8247                 t = trap[sig];
8248                 /* non-trapped SIGINT is handled separately by raise_interrupt,
8249                  * don't upset it by resetting gotsig[SIGINT-1] */
8250                 if (sig == SIGINT && !t)
8251                         continue;
8252
8253                 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
8254                 *g = 0;
8255                 if (!t)
8256                         continue;
8257                 want_exexit = evalstring(t, SKIPEVAL);
8258                 exitstatus = savestatus;
8259                 if (want_exexit) {
8260                         TRACE(("dotrap returns %d\n", want_exexit));
8261                         return want_exexit;
8262                 }
8263         }
8264
8265         TRACE(("dotrap returns 0\n"));
8266         return 0;
8267 }
8268
8269 /* forward declarations - evaluation is fairly recursive business... */
8270 static void evalloop(union node *, int);
8271 static void evalfor(union node *, int);
8272 static void evalcase(union node *, int);
8273 static void evalsubshell(union node *, int);
8274 static void expredir(union node *);
8275 static void evalpipe(union node *, int);
8276 static void evalcommand(union node *, int);
8277 static int evalbltin(const struct builtincmd *, int, char **);
8278 static void prehash(union node *);
8279
8280 /*
8281  * Evaluate a parse tree.  The value is left in the global variable
8282  * exitstatus.
8283  */
8284 static void
8285 evaltree(union node *n, int flags)
8286 {
8287         struct jmploc *volatile savehandler = exception_handler;
8288         struct jmploc jmploc;
8289         int checkexit = 0;
8290         void (*evalfn)(union node *, int);
8291         int status;
8292         int int_level;
8293
8294         SAVE_INT(int_level);
8295
8296         if (n == NULL) {
8297                 TRACE(("evaltree(NULL) called\n"));
8298                 goto out1;
8299         }
8300         TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8301
8302         exception_handler = &jmploc;
8303         {
8304                 int err = setjmp(jmploc.loc);
8305                 if (err) {
8306                         /* if it was a signal, check for trap handlers */
8307                         if (exception_type == EXSIG) {
8308                                 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8309                                                 exception_type, err));
8310                                 goto out;
8311                         }
8312                         /* continue on the way out */
8313                         TRACE(("exception %d in evaltree, propagating err=%d\n",
8314                                         exception_type, err));
8315                         exception_handler = savehandler;
8316                         longjmp(exception_handler->loc, err);
8317                 }
8318         }
8319
8320         switch (n->type) {
8321         default:
8322 #if DEBUG
8323                 out1fmt("Node type = %d\n", n->type);
8324                 fflush_all();
8325                 break;
8326 #endif
8327         case NNOT:
8328                 evaltree(n->nnot.com, EV_TESTED);
8329                 status = !exitstatus;
8330                 goto setstatus;
8331         case NREDIR:
8332                 expredir(n->nredir.redirect);
8333                 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8334                 if (!status) {
8335                         evaltree(n->nredir.n, flags & EV_TESTED);
8336                         status = exitstatus;
8337                 }
8338                 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8339                 goto setstatus;
8340         case NCMD:
8341                 evalfn = evalcommand;
8342  checkexit:
8343                 if (eflag && !(flags & EV_TESTED))
8344                         checkexit = ~0;
8345                 goto calleval;
8346         case NFOR:
8347                 evalfn = evalfor;
8348                 goto calleval;
8349         case NWHILE:
8350         case NUNTIL:
8351                 evalfn = evalloop;
8352                 goto calleval;
8353         case NSUBSHELL:
8354         case NBACKGND:
8355                 evalfn = evalsubshell;
8356                 goto calleval;
8357         case NPIPE:
8358                 evalfn = evalpipe;
8359                 goto checkexit;
8360         case NCASE:
8361                 evalfn = evalcase;
8362                 goto calleval;
8363         case NAND:
8364         case NOR:
8365         case NSEMI: {
8366
8367 #if NAND + 1 != NOR
8368 #error NAND + 1 != NOR
8369 #endif
8370 #if NOR + 1 != NSEMI
8371 #error NOR + 1 != NSEMI
8372 #endif
8373                 unsigned is_or = n->type - NAND;
8374                 evaltree(
8375                         n->nbinary.ch1,
8376                         (flags | ((is_or >> 1) - 1)) & EV_TESTED
8377                 );
8378                 if (!exitstatus == is_or)
8379                         break;
8380                 if (!evalskip) {
8381                         n = n->nbinary.ch2;
8382  evaln:
8383                         evalfn = evaltree;
8384  calleval:
8385                         evalfn(n, flags);
8386                         break;
8387                 }
8388                 break;
8389         }
8390         case NIF:
8391                 evaltree(n->nif.test, EV_TESTED);
8392                 if (evalskip)
8393                         break;
8394                 if (exitstatus == 0) {
8395                         n = n->nif.ifpart;
8396                         goto evaln;
8397                 }
8398                 if (n->nif.elsepart) {
8399                         n = n->nif.elsepart;
8400                         goto evaln;
8401                 }
8402                 goto success;
8403         case NDEFUN:
8404                 defun(n->narg.text, n->narg.next);
8405  success:
8406                 status = 0;
8407  setstatus:
8408                 exitstatus = status;
8409                 break;
8410         }
8411
8412  out:
8413         exception_handler = savehandler;
8414  out1:
8415         if (checkexit & exitstatus)
8416                 evalskip |= SKIPEVAL;
8417         else if (pending_sig && dotrap())
8418                 goto exexit;
8419
8420         if (flags & EV_EXIT) {
8421  exexit:
8422                 raise_exception(EXEXIT);
8423         }
8424
8425         RESTORE_INT(int_level);
8426         TRACE(("leaving evaltree (no interrupts)\n"));
8427 }
8428
8429 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8430 static
8431 #endif
8432 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8433
8434 static void
8435 evalloop(union node *n, int flags)
8436 {
8437         int status;
8438
8439         loopnest++;
8440         status = 0;
8441         flags &= EV_TESTED;
8442         for (;;) {
8443                 int i;
8444
8445                 evaltree(n->nbinary.ch1, EV_TESTED);
8446                 if (evalskip) {
8447  skipping:
8448                         if (evalskip == SKIPCONT && --skipcount <= 0) {
8449                                 evalskip = 0;
8450                                 continue;
8451                         }
8452                         if (evalskip == SKIPBREAK && --skipcount <= 0)
8453                                 evalskip = 0;
8454                         break;
8455                 }
8456                 i = exitstatus;
8457                 if (n->type != NWHILE)
8458                         i = !i;
8459                 if (i != 0)
8460                         break;
8461                 evaltree(n->nbinary.ch2, flags);
8462                 status = exitstatus;
8463                 if (evalskip)
8464                         goto skipping;
8465         }
8466         loopnest--;
8467         exitstatus = status;
8468 }
8469
8470 static void
8471 evalfor(union node *n, int flags)
8472 {
8473         struct arglist arglist;
8474         union node *argp;
8475         struct strlist *sp;
8476         struct stackmark smark;
8477
8478         setstackmark(&smark);
8479         arglist.list = NULL;
8480         arglist.lastp = &arglist.list;
8481         for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8482                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8483                 /* XXX */
8484                 if (evalskip)
8485                         goto out;
8486         }
8487         *arglist.lastp = NULL;
8488
8489         exitstatus = 0;
8490         loopnest++;
8491         flags &= EV_TESTED;
8492         for (sp = arglist.list; sp; sp = sp->next) {
8493                 setvar(n->nfor.var, sp->text, 0);
8494                 evaltree(n->nfor.body, flags);
8495                 if (evalskip) {
8496                         if (evalskip == SKIPCONT && --skipcount <= 0) {
8497                                 evalskip = 0;
8498                                 continue;
8499                         }
8500                         if (evalskip == SKIPBREAK && --skipcount <= 0)
8501                                 evalskip = 0;
8502                         break;
8503                 }
8504         }
8505         loopnest--;
8506  out:
8507         popstackmark(&smark);
8508 }
8509
8510 static void
8511 evalcase(union node *n, int flags)
8512 {
8513         union node *cp;
8514         union node *patp;
8515         struct arglist arglist;
8516         struct stackmark smark;
8517
8518         setstackmark(&smark);
8519         arglist.list = NULL;
8520         arglist.lastp = &arglist.list;
8521         expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8522         exitstatus = 0;
8523         for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8524                 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8525                         if (casematch(patp, arglist.list->text)) {
8526                                 if (evalskip == 0) {
8527                                         evaltree(cp->nclist.body, flags);
8528                                 }
8529                                 goto out;
8530                         }
8531                 }
8532         }
8533  out:
8534         popstackmark(&smark);
8535 }
8536
8537 /*
8538  * Kick off a subshell to evaluate a tree.
8539  */
8540 static void
8541 evalsubshell(union node *n, int flags)
8542 {
8543         struct job *jp;
8544         int backgnd = (n->type == NBACKGND);
8545         int status;
8546
8547         expredir(n->nredir.redirect);
8548         if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
8549                 goto nofork;
8550         INT_OFF;
8551         jp = makejob(/*n,*/ 1);
8552         if (forkshell(jp, n, backgnd) == 0) {
8553                 /* child */
8554                 INT_ON;
8555                 flags |= EV_EXIT;
8556                 if (backgnd)
8557                         flags &= ~EV_TESTED;
8558  nofork:
8559                 redirect(n->nredir.redirect, 0);
8560                 evaltreenr(n->nredir.n, flags);
8561                 /* never returns */
8562         }
8563         status = 0;
8564         if (!backgnd)
8565                 status = waitforjob(jp);
8566         exitstatus = status;
8567         INT_ON;
8568 }
8569
8570 /*
8571  * Compute the names of the files in a redirection list.
8572  */
8573 static void fixredir(union node *, const char *, int);
8574 static void
8575 expredir(union node *n)
8576 {
8577         union node *redir;
8578
8579         for (redir = n; redir; redir = redir->nfile.next) {
8580                 struct arglist fn;
8581
8582                 fn.list = NULL;
8583                 fn.lastp = &fn.list;
8584                 switch (redir->type) {
8585                 case NFROMTO:
8586                 case NFROM:
8587                 case NTO:
8588 #if ENABLE_ASH_BASH_COMPAT
8589                 case NTO2:
8590 #endif
8591                 case NCLOBBER:
8592                 case NAPPEND:
8593                         expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8594 #if ENABLE_ASH_BASH_COMPAT
8595  store_expfname:
8596 #endif
8597                         redir->nfile.expfname = fn.list->text;
8598                         break;
8599                 case NFROMFD:
8600                 case NTOFD: /* >& */
8601                         if (redir->ndup.vname) {
8602                                 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8603                                 if (fn.list == NULL)
8604                                         ash_msg_and_raise_error("redir error");
8605 #if ENABLE_ASH_BASH_COMPAT
8606 //FIXME: we used expandarg with different args!
8607                                 if (!isdigit_str9(fn.list->text)) {
8608                                         /* >&file, not >&fd */
8609                                         if (redir->nfile.fd != 1) /* 123>&file - BAD */
8610                                                 ash_msg_and_raise_error("redir error");
8611                                         redir->type = NTO2;
8612                                         goto store_expfname;
8613                                 }
8614 #endif
8615                                 fixredir(redir, fn.list->text, 1);
8616                         }
8617                         break;
8618                 }
8619         }
8620 }
8621
8622 /*
8623  * Evaluate a pipeline.  All the processes in the pipeline are children
8624  * of the process creating the pipeline.  (This differs from some versions
8625  * of the shell, which make the last process in a pipeline the parent
8626  * of all the rest.)
8627  */
8628 static void
8629 evalpipe(union node *n, int flags)
8630 {
8631         struct job *jp;
8632         struct nodelist *lp;
8633         int pipelen;
8634         int prevfd;
8635         int pip[2];
8636
8637         TRACE(("evalpipe(0x%lx) called\n", (long)n));
8638         pipelen = 0;
8639         for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8640                 pipelen++;
8641         flags |= EV_EXIT;
8642         INT_OFF;
8643         jp = makejob(/*n,*/ pipelen);
8644         prevfd = -1;
8645         for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8646                 prehash(lp->n);
8647                 pip[1] = -1;
8648                 if (lp->next) {
8649                         if (pipe(pip) < 0) {
8650                                 close(prevfd);
8651                                 ash_msg_and_raise_error("pipe call failed");
8652                         }
8653                 }
8654                 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8655                         INT_ON;
8656                         if (pip[1] >= 0) {
8657                                 close(pip[0]);
8658                         }
8659                         if (prevfd > 0) {
8660                                 dup2(prevfd, 0);
8661                                 close(prevfd);
8662                         }
8663                         if (pip[1] > 1) {
8664                                 dup2(pip[1], 1);
8665                                 close(pip[1]);
8666                         }
8667                         evaltreenr(lp->n, flags);
8668                         /* never returns */
8669                 }
8670                 if (prevfd >= 0)
8671                         close(prevfd);
8672                 prevfd = pip[0];
8673                 /* Don't want to trigger debugging */
8674                 if (pip[1] != -1)
8675                         close(pip[1]);
8676         }
8677         if (n->npipe.pipe_backgnd == 0) {
8678                 exitstatus = waitforjob(jp);
8679                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
8680         }
8681         INT_ON;
8682 }
8683
8684 /*
8685  * Controls whether the shell is interactive or not.
8686  */
8687 static void
8688 setinteractive(int on)
8689 {
8690         static smallint is_interactive;
8691
8692         if (++on == is_interactive)
8693                 return;
8694         is_interactive = on;
8695         setsignal(SIGINT);
8696         setsignal(SIGQUIT);
8697         setsignal(SIGTERM);
8698 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8699         if (is_interactive > 1) {
8700                 /* Looks like they want an interactive shell */
8701                 static smallint did_banner;
8702
8703                 if (!did_banner) {
8704                         /* note: ash and hush share this string */
8705                         out1fmt("\n\n%s %s\n"
8706                                 "Enter 'help' for a list of built-in commands."
8707                                 "\n\n",
8708                                 bb_banner,
8709                                 "built-in shell (ash)"
8710                         );
8711                         did_banner = 1;
8712                 }
8713         }
8714 #endif
8715 }
8716
8717 static void
8718 optschanged(void)
8719 {
8720 #if DEBUG
8721         opentrace();
8722 #endif
8723         setinteractive(iflag);
8724         setjobctl(mflag);
8725 #if ENABLE_FEATURE_EDITING_VI
8726         if (viflag)
8727                 line_input_state->flags |= VI_MODE;
8728         else
8729                 line_input_state->flags &= ~VI_MODE;
8730 #else
8731         viflag = 0; /* forcibly keep the option off */
8732 #endif
8733 }
8734
8735 static struct localvar *localvars;
8736
8737 /*
8738  * Called after a function returns.
8739  * Interrupts must be off.
8740  */
8741 static void
8742 poplocalvars(void)
8743 {
8744         struct localvar *lvp;
8745         struct var *vp;
8746
8747         while ((lvp = localvars) != NULL) {
8748                 localvars = lvp->next;
8749                 vp = lvp->vp;
8750                 TRACE(("poplocalvar %s\n", vp ? vp->text : "-"));
8751                 if (vp == NULL) {       /* $- saved */
8752                         memcpy(optlist, lvp->text, sizeof(optlist));
8753                         free((char*)lvp->text);
8754                         optschanged();
8755                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8756                         unsetvar(vp->var_text);
8757                 } else {
8758                         if (vp->var_func)
8759                                 vp->var_func(var_end(lvp->text));
8760                         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8761                                 free((char*)vp->var_text);
8762                         vp->flags = lvp->flags;
8763                         vp->var_text = lvp->text;
8764                 }
8765                 free(lvp);
8766         }
8767 }
8768
8769 static int
8770 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8771 {
8772         volatile struct shparam saveparam;
8773         struct localvar *volatile savelocalvars;
8774         struct jmploc *volatile savehandler;
8775         struct jmploc jmploc;
8776         int e;
8777
8778         saveparam = shellparam;
8779         savelocalvars = localvars;
8780         e = setjmp(jmploc.loc);
8781         if (e) {
8782                 goto funcdone;
8783         }
8784         INT_OFF;
8785         savehandler = exception_handler;
8786         exception_handler = &jmploc;
8787         localvars = NULL;
8788         shellparam.malloced = 0;
8789         func->count++;
8790         funcnest++;
8791         INT_ON;
8792         shellparam.nparam = argc - 1;
8793         shellparam.p = argv + 1;
8794 #if ENABLE_ASH_GETOPTS
8795         shellparam.optind = 1;
8796         shellparam.optoff = -1;
8797 #endif
8798         evaltree(&func->n, flags & EV_TESTED);
8799  funcdone:
8800         INT_OFF;
8801         funcnest--;
8802         freefunc(func);
8803         poplocalvars();
8804         localvars = savelocalvars;
8805         freeparam(&shellparam);
8806         shellparam = saveparam;
8807         exception_handler = savehandler;
8808         INT_ON;
8809         evalskip &= ~SKIPFUNC;
8810         return e;
8811 }
8812
8813 #if ENABLE_ASH_CMDCMD
8814 static char **
8815 parse_command_args(char **argv, const char **path)
8816 {
8817         char *cp, c;
8818
8819         for (;;) {
8820                 cp = *++argv;
8821                 if (!cp)
8822                         return 0;
8823                 if (*cp++ != '-')
8824                         break;
8825                 c = *cp++;
8826                 if (!c)
8827                         break;
8828                 if (c == '-' && !*cp) {
8829                         argv++;
8830                         break;
8831                 }
8832                 do {
8833                         switch (c) {
8834                         case 'p':
8835                                 *path = bb_default_path;
8836                                 break;
8837                         default:
8838                                 /* run 'typecmd' for other options */
8839                                 return 0;
8840                         }
8841                         c = *cp++;
8842                 } while (c);
8843         }
8844         return argv;
8845 }
8846 #endif
8847
8848 /*
8849  * Make a variable a local variable.  When a variable is made local, it's
8850  * value and flags are saved in a localvar structure.  The saved values
8851  * will be restored when the shell function returns.  We handle the name
8852  * "-" as a special case.
8853  */
8854 static void
8855 mklocal(char *name)
8856 {
8857         struct localvar *lvp;
8858         struct var **vpp;
8859         struct var *vp;
8860
8861         INT_OFF;
8862         lvp = ckzalloc(sizeof(struct localvar));
8863         if (LONE_DASH(name)) {
8864                 char *p;
8865                 p = ckmalloc(sizeof(optlist));
8866                 lvp->text = memcpy(p, optlist, sizeof(optlist));
8867                 vp = NULL;
8868         } else {
8869                 char *eq;
8870
8871                 vpp = hashvar(name);
8872                 vp = *findvar(vpp, name);
8873                 eq = strchr(name, '=');
8874                 if (vp == NULL) {
8875                         if (eq)
8876                                 setvareq(name, VSTRFIXED);
8877                         else
8878                                 setvar(name, NULL, VSTRFIXED);
8879                         vp = *vpp;      /* the new variable */
8880                         lvp->flags = VUNSET;
8881                 } else {
8882                         lvp->text = vp->var_text;
8883                         lvp->flags = vp->flags;
8884                         vp->flags |= VSTRFIXED|VTEXTFIXED;
8885                         if (eq)
8886                                 setvareq(name, 0);
8887                 }
8888         }
8889         lvp->vp = vp;
8890         lvp->next = localvars;
8891         localvars = lvp;
8892         INT_ON;
8893 }
8894
8895 /*
8896  * The "local" command.
8897  */
8898 static int FAST_FUNC
8899 localcmd(int argc UNUSED_PARAM, char **argv)
8900 {
8901         char *name;
8902
8903         argv = argptr;
8904         while ((name = *argv++) != NULL) {
8905                 mklocal(name);
8906         }
8907         return 0;
8908 }
8909
8910 static int FAST_FUNC
8911 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8912 {
8913         return 1;
8914 }
8915
8916 static int FAST_FUNC
8917 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8918 {
8919         return 0;
8920 }
8921
8922 static int FAST_FUNC
8923 execcmd(int argc UNUSED_PARAM, char **argv)
8924 {
8925         if (argv[1]) {
8926                 iflag = 0;              /* exit on error */
8927                 mflag = 0;
8928                 optschanged();
8929                 shellexec(argv + 1, pathval(), 0);
8930         }
8931         return 0;
8932 }
8933
8934 /*
8935  * The return command.
8936  */
8937 static int FAST_FUNC
8938 returncmd(int argc UNUSED_PARAM, char **argv)
8939 {
8940         /*
8941          * If called outside a function, do what ksh does;
8942          * skip the rest of the file.
8943          */
8944         evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8945         return argv[1] ? number(argv[1]) : exitstatus;
8946 }
8947
8948 /* Forward declarations for builtintab[] */
8949 static int breakcmd(int, char **) FAST_FUNC;
8950 static int dotcmd(int, char **) FAST_FUNC;
8951 static int evalcmd(int, char **) FAST_FUNC;
8952 static int exitcmd(int, char **) FAST_FUNC;
8953 static int exportcmd(int, char **) FAST_FUNC;
8954 #if ENABLE_ASH_GETOPTS
8955 static int getoptscmd(int, char **) FAST_FUNC;
8956 #endif
8957 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8958 static int helpcmd(int, char **) FAST_FUNC;
8959 #endif
8960 #if ENABLE_SH_MATH_SUPPORT
8961 static int letcmd(int, char **) FAST_FUNC;
8962 #endif
8963 static int readcmd(int, char **) FAST_FUNC;
8964 static int setcmd(int, char **) FAST_FUNC;
8965 static int shiftcmd(int, char **) FAST_FUNC;
8966 static int timescmd(int, char **) FAST_FUNC;
8967 static int trapcmd(int, char **) FAST_FUNC;
8968 static int umaskcmd(int, char **) FAST_FUNC;
8969 static int unsetcmd(int, char **) FAST_FUNC;
8970 static int ulimitcmd(int, char **) FAST_FUNC;
8971
8972 #define BUILTIN_NOSPEC          "0"
8973 #define BUILTIN_SPECIAL         "1"
8974 #define BUILTIN_REGULAR         "2"
8975 #define BUILTIN_SPEC_REG        "3"
8976 #define BUILTIN_ASSIGN          "4"
8977 #define BUILTIN_SPEC_ASSG       "5"
8978 #define BUILTIN_REG_ASSG        "6"
8979 #define BUILTIN_SPEC_REG_ASSG   "7"
8980
8981 /* Stubs for calling non-FAST_FUNC's */
8982 #if ENABLE_ASH_BUILTIN_ECHO
8983 static int FAST_FUNC echocmd(int argc, char **argv)   { return echo_main(argc, argv); }
8984 #endif
8985 #if ENABLE_ASH_BUILTIN_PRINTF
8986 static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
8987 #endif
8988 #if ENABLE_ASH_BUILTIN_TEST
8989 static int FAST_FUNC testcmd(int argc, char **argv)   { return test_main(argc, argv); }
8990 #endif
8991
8992 /* Keep these in proper order since it is searched via bsearch() */
8993 static const struct builtincmd builtintab[] = {
8994         { BUILTIN_SPEC_REG      "."       , dotcmd     },
8995         { BUILTIN_SPEC_REG      ":"       , truecmd    },
8996 #if ENABLE_ASH_BUILTIN_TEST
8997         { BUILTIN_REGULAR       "["       , testcmd    },
8998 #if ENABLE_ASH_BASH_COMPAT
8999         { BUILTIN_REGULAR       "[["      , testcmd    },
9000 #endif
9001 #endif
9002 #if ENABLE_ASH_ALIAS
9003         { BUILTIN_REG_ASSG      "alias"   , aliascmd   },
9004 #endif
9005 #if JOBS
9006         { BUILTIN_REGULAR       "bg"      , fg_bgcmd   },
9007 #endif
9008         { BUILTIN_SPEC_REG      "break"   , breakcmd   },
9009         { BUILTIN_REGULAR       "cd"      , cdcmd      },
9010         { BUILTIN_NOSPEC        "chdir"   , cdcmd      },
9011 #if ENABLE_ASH_CMDCMD
9012         { BUILTIN_REGULAR       "command" , commandcmd },
9013 #endif
9014         { BUILTIN_SPEC_REG      "continue", breakcmd   },
9015 #if ENABLE_ASH_BUILTIN_ECHO
9016         { BUILTIN_REGULAR       "echo"    , echocmd    },
9017 #endif
9018         { BUILTIN_SPEC_REG      "eval"    , evalcmd    },
9019         { BUILTIN_SPEC_REG      "exec"    , execcmd    },
9020         { BUILTIN_SPEC_REG      "exit"    , exitcmd    },
9021         { BUILTIN_SPEC_REG_ASSG "export"  , exportcmd  },
9022         { BUILTIN_REGULAR       "false"   , falsecmd   },
9023 #if JOBS
9024         { BUILTIN_REGULAR       "fg"      , fg_bgcmd   },
9025 #endif
9026 #if ENABLE_ASH_GETOPTS
9027         { BUILTIN_REGULAR       "getopts" , getoptscmd },
9028 #endif
9029         { BUILTIN_NOSPEC        "hash"    , hashcmd    },
9030 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
9031         { BUILTIN_NOSPEC        "help"    , helpcmd    },
9032 #endif
9033 #if JOBS
9034         { BUILTIN_REGULAR       "jobs"    , jobscmd    },
9035         { BUILTIN_REGULAR       "kill"    , killcmd    },
9036 #endif
9037 #if ENABLE_SH_MATH_SUPPORT
9038         { BUILTIN_NOSPEC        "let"     , letcmd     },
9039 #endif
9040         { BUILTIN_ASSIGN        "local"   , localcmd   },
9041 #if ENABLE_ASH_BUILTIN_PRINTF
9042         { BUILTIN_REGULAR       "printf"  , printfcmd  },
9043 #endif
9044         { BUILTIN_NOSPEC        "pwd"     , pwdcmd     },
9045         { BUILTIN_REGULAR       "read"    , readcmd    },
9046         { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd  },
9047         { BUILTIN_SPEC_REG      "return"  , returncmd  },
9048         { BUILTIN_SPEC_REG      "set"     , setcmd     },
9049         { BUILTIN_SPEC_REG      "shift"   , shiftcmd   },
9050 #if ENABLE_ASH_BASH_COMPAT
9051         { BUILTIN_SPEC_REG      "source"  , dotcmd     },
9052 #endif
9053 #if ENABLE_ASH_BUILTIN_TEST
9054         { BUILTIN_REGULAR       "test"    , testcmd    },
9055 #endif
9056         { BUILTIN_SPEC_REG      "times"   , timescmd   },
9057         { BUILTIN_SPEC_REG      "trap"    , trapcmd    },
9058         { BUILTIN_REGULAR       "true"    , truecmd    },
9059         { BUILTIN_NOSPEC        "type"    , typecmd    },
9060         { BUILTIN_NOSPEC        "ulimit"  , ulimitcmd  },
9061         { BUILTIN_REGULAR       "umask"   , umaskcmd   },
9062 #if ENABLE_ASH_ALIAS
9063         { BUILTIN_REGULAR       "unalias" , unaliascmd },
9064 #endif
9065         { BUILTIN_SPEC_REG      "unset"   , unsetcmd   },
9066         { BUILTIN_REGULAR       "wait"    , waitcmd    },
9067 };
9068
9069 /* Should match the above table! */
9070 #define COMMANDCMD (builtintab + \
9071         2 + \
9072         1 * ENABLE_ASH_BUILTIN_TEST + \
9073         1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9074         1 * ENABLE_ASH_ALIAS + \
9075         1 * ENABLE_ASH_JOB_CONTROL + \
9076         3)
9077 #define EXECCMD (builtintab + \
9078         2 + \
9079         1 * ENABLE_ASH_BUILTIN_TEST + \
9080         1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9081         1 * ENABLE_ASH_ALIAS + \
9082         1 * ENABLE_ASH_JOB_CONTROL + \
9083         3 + \
9084         1 * ENABLE_ASH_CMDCMD + \
9085         1 + \
9086         ENABLE_ASH_BUILTIN_ECHO + \
9087         1)
9088
9089 /*
9090  * Search the table of builtin commands.
9091  */
9092 static struct builtincmd *
9093 find_builtin(const char *name)
9094 {
9095         struct builtincmd *bp;
9096
9097         bp = bsearch(
9098                 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9099                 pstrcmp
9100         );
9101         return bp;
9102 }
9103
9104 /*
9105  * Execute a simple command.
9106  */
9107 static int
9108 isassignment(const char *p)
9109 {
9110         const char *q = endofname(p);
9111         if (p == q)
9112                 return 0;
9113         return *q == '=';
9114 }
9115 static int FAST_FUNC
9116 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9117 {
9118         /* Preserve exitstatus of a previous possible redirection
9119          * as POSIX mandates */
9120         return back_exitstatus;
9121 }
9122 static void
9123 evalcommand(union node *cmd, int flags)
9124 {
9125         static const struct builtincmd null_bltin = {
9126                 "\0\0", bltincmd /* why three NULs? */
9127         };
9128         struct stackmark smark;
9129         union node *argp;
9130         struct arglist arglist;
9131         struct arglist varlist;
9132         char **argv;
9133         int argc;
9134         const struct strlist *sp;
9135         struct cmdentry cmdentry;
9136         struct job *jp;
9137         char *lastarg;
9138         const char *path;
9139         int spclbltin;
9140         int status;
9141         char **nargv;
9142         struct builtincmd *bcmd;
9143         smallint cmd_is_exec;
9144         smallint pseudovarflag = 0;
9145
9146         /* First expand the arguments. */
9147         TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9148         setstackmark(&smark);
9149         back_exitstatus = 0;
9150
9151         cmdentry.cmdtype = CMDBUILTIN;
9152         cmdentry.u.cmd = &null_bltin;
9153         varlist.lastp = &varlist.list;
9154         *varlist.lastp = NULL;
9155         arglist.lastp = &arglist.list;
9156         *arglist.lastp = NULL;
9157
9158         argc = 0;
9159         if (cmd->ncmd.args) {
9160                 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9161                 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9162         }
9163
9164         for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9165                 struct strlist **spp;
9166
9167                 spp = arglist.lastp;
9168                 if (pseudovarflag && isassignment(argp->narg.text))
9169                         expandarg(argp, &arglist, EXP_VARTILDE);
9170                 else
9171                         expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9172
9173                 for (sp = *spp; sp; sp = sp->next)
9174                         argc++;
9175         }
9176
9177         argv = nargv = stalloc(sizeof(char *) * (argc + 1));
9178         for (sp = arglist.list; sp; sp = sp->next) {
9179                 TRACE(("evalcommand arg: %s\n", sp->text));
9180                 *nargv++ = sp->text;
9181         }
9182         *nargv = NULL;
9183
9184         lastarg = NULL;
9185         if (iflag && funcnest == 0 && argc > 0)
9186                 lastarg = nargv[-1];
9187
9188         preverrout_fd = 2;
9189         expredir(cmd->ncmd.redirect);
9190         status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
9191
9192         path = vpath.var_text;
9193         for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9194                 struct strlist **spp;
9195                 char *p;
9196
9197                 spp = varlist.lastp;
9198                 expandarg(argp, &varlist, EXP_VARTILDE);
9199
9200                 /*
9201                  * Modify the command lookup path, if a PATH= assignment
9202                  * is present
9203                  */
9204                 p = (*spp)->text;
9205                 if (varcmp(p, path) == 0)
9206                         path = p;
9207         }
9208
9209         /* Print the command if xflag is set. */
9210         if (xflag) {
9211                 int n;
9212                 const char *p = " %s" + 1;
9213
9214                 fdprintf(preverrout_fd, p, expandstr(ps4val()));
9215                 sp = varlist.list;
9216                 for (n = 0; n < 2; n++) {
9217                         while (sp) {
9218                                 fdprintf(preverrout_fd, p, sp->text);
9219                                 sp = sp->next;
9220                                 p = " %s";
9221                         }
9222                         sp = arglist.list;
9223                 }
9224                 safe_write(preverrout_fd, "\n", 1);
9225         }
9226
9227         cmd_is_exec = 0;
9228         spclbltin = -1;
9229
9230         /* Now locate the command. */
9231         if (argc) {
9232                 const char *oldpath;
9233                 int cmd_flag = DO_ERR;
9234
9235                 path += 5;
9236                 oldpath = path;
9237                 for (;;) {
9238                         find_command(argv[0], &cmdentry, cmd_flag, path);
9239                         if (cmdentry.cmdtype == CMDUNKNOWN) {
9240                                 flush_stdout_stderr();
9241                                 status = 127;
9242                                 goto bail;
9243                         }
9244
9245                         /* implement bltin and command here */
9246                         if (cmdentry.cmdtype != CMDBUILTIN)
9247                                 break;
9248                         if (spclbltin < 0)
9249                                 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9250                         if (cmdentry.u.cmd == EXECCMD)
9251                                 cmd_is_exec = 1;
9252 #if ENABLE_ASH_CMDCMD
9253                         if (cmdentry.u.cmd == COMMANDCMD) {
9254                                 path = oldpath;
9255                                 nargv = parse_command_args(argv, &path);
9256                                 if (!nargv)
9257                                         break;
9258                                 argc -= nargv - argv;
9259                                 argv = nargv;
9260                                 cmd_flag |= DO_NOFUNC;
9261                         } else
9262 #endif
9263                                 break;
9264                 }
9265         }
9266
9267         if (status) {
9268                 /* We have a redirection error. */
9269                 if (spclbltin > 0)
9270                         raise_exception(EXERROR);
9271  bail:
9272                 exitstatus = status;
9273                 goto out;
9274         }
9275
9276         /* Execute the command. */
9277         switch (cmdentry.cmdtype) {
9278         default: {
9279
9280 #if ENABLE_FEATURE_SH_NOFORK
9281 /* (1) BUG: if variables are set, we need to fork, or save/restore them
9282  *     around run_nofork_applet() call.
9283  * (2) Should this check also be done in forkshell()?
9284  *     (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9285  */
9286                 /* find_command() encodes applet_no as (-2 - applet_no) */
9287                 int applet_no = (- cmdentry.u.index - 2);
9288                 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
9289                         listsetvar(varlist.list, VEXPORT|VSTACK);
9290                         /* run <applet>_main() */
9291                         exitstatus = run_nofork_applet(applet_no, argv);
9292                         break;
9293                 }
9294 #endif
9295                 /* Can we avoid forking off? For example, very last command
9296                  * in a script or a subshell does not need forking,
9297                  * we can just exec it.
9298                  */
9299                 if (!(flags & EV_EXIT) || may_have_traps) {
9300                         /* No, forking off a child is necessary */
9301                         INT_OFF;
9302                         jp = makejob(/*cmd,*/ 1);
9303                         if (forkshell(jp, cmd, FORK_FG) != 0) {
9304                                 /* parent */
9305                                 exitstatus = waitforjob(jp);
9306                                 INT_ON;
9307                                 TRACE(("forked child exited with %d\n", exitstatus));
9308                                 break;
9309                         }
9310                         /* child */
9311                         FORCE_INT_ON;
9312                         /* fall through to exec'ing external program */
9313                 }
9314                 listsetvar(varlist.list, VEXPORT|VSTACK);
9315                 shellexec(argv, path, cmdentry.u.index);
9316                 /* NOTREACHED */
9317         } /* default */
9318         case CMDBUILTIN:
9319                 cmdenviron = varlist.list;
9320                 if (cmdenviron) {
9321                         struct strlist *list = cmdenviron;
9322                         int i = VNOSET;
9323                         if (spclbltin > 0 || argc == 0) {
9324                                 i = 0;
9325                                 if (cmd_is_exec && argc > 1)
9326                                         i = VEXPORT;
9327                         }
9328                         listsetvar(list, i);
9329                 }
9330                 /* Tight loop with builtins only:
9331                  * "while kill -0 $child; do true; done"
9332                  * will never exit even if $child died, unless we do this
9333                  * to reap the zombie and make kill detect that it's gone: */
9334                 dowait(DOWAIT_NONBLOCK, NULL);
9335
9336                 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9337                         int exit_status;
9338                         int i = exception_type;
9339                         if (i == EXEXIT)
9340                                 goto raise;
9341                         exit_status = 2;
9342                         if (i == EXINT)
9343                                 exit_status = 128 + SIGINT;
9344                         if (i == EXSIG)
9345                                 exit_status = 128 + pending_sig;
9346                         exitstatus = exit_status;
9347                         if (i == EXINT || spclbltin > 0) {
9348  raise:
9349                                 longjmp(exception_handler->loc, 1);
9350                         }
9351                         FORCE_INT_ON;
9352                 }
9353                 break;
9354
9355         case CMDFUNCTION:
9356                 listsetvar(varlist.list, 0);
9357                 /* See above for the rationale */
9358                 dowait(DOWAIT_NONBLOCK, NULL);
9359                 if (evalfun(cmdentry.u.func, argc, argv, flags))
9360                         goto raise;
9361                 break;
9362
9363         } /* switch */
9364
9365  out:
9366         popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9367         if (lastarg) {
9368                 /* dsl: I think this is intended to be used to support
9369                  * '_' in 'vi' command mode during line editing...
9370                  * However I implemented that within libedit itself.
9371                  */
9372                 setvar("_", lastarg, 0);
9373         }
9374         popstackmark(&smark);
9375 }
9376
9377 static int
9378 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9379 {
9380         char *volatile savecmdname;
9381         struct jmploc *volatile savehandler;
9382         struct jmploc jmploc;
9383         int i;
9384
9385         savecmdname = commandname;
9386         i = setjmp(jmploc.loc);
9387         if (i)
9388                 goto cmddone;
9389         savehandler = exception_handler;
9390         exception_handler = &jmploc;
9391         commandname = argv[0];
9392         argptr = argv + 1;
9393         optptr = NULL;                  /* initialize nextopt */
9394         exitstatus = (*cmd->builtin)(argc, argv);
9395         flush_stdout_stderr();
9396  cmddone:
9397         exitstatus |= ferror(stdout);
9398         clearerr(stdout);
9399         commandname = savecmdname;
9400         exception_handler = savehandler;
9401
9402         return i;
9403 }
9404
9405 static int
9406 goodname(const char *p)
9407 {
9408         return !*endofname(p);
9409 }
9410
9411
9412 /*
9413  * Search for a command.  This is called before we fork so that the
9414  * location of the command will be available in the parent as well as
9415  * the child.  The check for "goodname" is an overly conservative
9416  * check that the name will not be subject to expansion.
9417  */
9418 static void
9419 prehash(union node *n)
9420 {
9421         struct cmdentry entry;
9422
9423         if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9424                 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9425 }
9426
9427
9428 /* ============ Builtin commands
9429  *
9430  * Builtin commands whose functions are closely tied to evaluation
9431  * are implemented here.
9432  */
9433
9434 /*
9435  * Handle break and continue commands.  Break, continue, and return are
9436  * all handled by setting the evalskip flag.  The evaluation routines
9437  * above all check this flag, and if it is set they start skipping
9438  * commands rather than executing them.  The variable skipcount is
9439  * the number of loops to break/continue, or the number of function
9440  * levels to return.  (The latter is always 1.)  It should probably
9441  * be an error to break out of more loops than exist, but it isn't
9442  * in the standard shell so we don't make it one here.
9443  */
9444 static int FAST_FUNC
9445 breakcmd(int argc UNUSED_PARAM, char **argv)
9446 {
9447         int n = argv[1] ? number(argv[1]) : 1;
9448
9449         if (n <= 0)
9450                 ash_msg_and_raise_error(msg_illnum, argv[1]);
9451         if (n > loopnest)
9452                 n = loopnest;
9453         if (n > 0) {
9454                 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9455                 skipcount = n;
9456         }
9457         return 0;
9458 }
9459
9460
9461 /* ============ input.c
9462  *
9463  * This implements the input routines used by the parser.
9464  */
9465
9466 enum {
9467         INPUT_PUSH_FILE = 1,
9468         INPUT_NOFILE_OK = 2,
9469 };
9470
9471 static smallint checkkwd;
9472 /* values of checkkwd variable */
9473 #define CHKALIAS        0x1
9474 #define CHKKWD          0x2
9475 #define CHKNL           0x4
9476
9477 /*
9478  * Push a string back onto the input at this current parsefile level.
9479  * We handle aliases this way.
9480  */
9481 #if !ENABLE_ASH_ALIAS
9482 #define pushstring(s, ap) pushstring(s)
9483 #endif
9484 static void
9485 pushstring(char *s, struct alias *ap)
9486 {
9487         struct strpush *sp;
9488         int len;
9489
9490         len = strlen(s);
9491         INT_OFF;
9492         if (g_parsefile->strpush) {
9493                 sp = ckzalloc(sizeof(*sp));
9494                 sp->prev = g_parsefile->strpush;
9495         } else {
9496                 sp = &(g_parsefile->basestrpush);
9497         }
9498         g_parsefile->strpush = sp;
9499         sp->prev_string = g_parsefile->next_to_pgetc;
9500         sp->prev_left_in_line = g_parsefile->left_in_line;
9501 #if ENABLE_ASH_ALIAS
9502         sp->ap = ap;
9503         if (ap) {
9504                 ap->flag |= ALIASINUSE;
9505                 sp->string = s;
9506         }
9507 #endif
9508         g_parsefile->next_to_pgetc = s;
9509         g_parsefile->left_in_line = len;
9510         INT_ON;
9511 }
9512
9513 static void
9514 popstring(void)
9515 {
9516         struct strpush *sp = g_parsefile->strpush;
9517
9518         INT_OFF;
9519 #if ENABLE_ASH_ALIAS
9520         if (sp->ap) {
9521                 if (g_parsefile->next_to_pgetc[-1] == ' '
9522                  || g_parsefile->next_to_pgetc[-1] == '\t'
9523                 ) {
9524                         checkkwd |= CHKALIAS;
9525                 }
9526                 if (sp->string != sp->ap->val) {
9527                         free(sp->string);
9528                 }
9529                 sp->ap->flag &= ~ALIASINUSE;
9530                 if (sp->ap->flag & ALIASDEAD) {
9531                         unalias(sp->ap->name);
9532                 }
9533         }
9534 #endif
9535         g_parsefile->next_to_pgetc = sp->prev_string;
9536         g_parsefile->left_in_line = sp->prev_left_in_line;
9537         g_parsefile->strpush = sp->prev;
9538         if (sp != &(g_parsefile->basestrpush))
9539                 free(sp);
9540         INT_ON;
9541 }
9542
9543 //FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9544 //it peeks whether it is &>, and then pushes back both chars.
9545 //This function needs to save last *next_to_pgetc to buf[0]
9546 //to make two pungetc() reliable. Currently,
9547 // pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
9548 static int
9549 preadfd(void)
9550 {
9551         int nr;
9552         char *buf = g_parsefile->buf;
9553
9554         g_parsefile->next_to_pgetc = buf;
9555 #if ENABLE_FEATURE_EDITING
9556  retry:
9557         if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
9558                 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9559         else {
9560 #if ENABLE_FEATURE_TAB_COMPLETION
9561                 line_input_state->path_lookup = pathval();
9562 #endif
9563                 nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state);
9564                 if (nr == 0) {
9565                         /* Ctrl+C pressed */
9566                         if (trap[SIGINT]) {
9567                                 buf[0] = '\n';
9568                                 buf[1] = '\0';
9569                                 raise(SIGINT);
9570                                 return 1;
9571                         }
9572                         goto retry;
9573                 }
9574                 if (nr < 0 && errno == 0) {
9575                         /* Ctrl+D pressed */
9576                         nr = 0;
9577                 }
9578         }
9579 #else
9580         nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9581 #endif
9582
9583 #if 0
9584 /* nonblock_safe_read() handles this problem */
9585         if (nr < 0) {
9586                 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9587                         int flags = fcntl(0, F_GETFL);
9588                         if (flags >= 0 && (flags & O_NONBLOCK)) {
9589                                 flags &= ~O_NONBLOCK;
9590                                 if (fcntl(0, F_SETFL, flags) >= 0) {
9591                                         out2str("sh: turning off NDELAY mode\n");
9592                                         goto retry;
9593                                 }
9594                         }
9595                 }
9596         }
9597 #endif
9598         return nr;
9599 }
9600
9601 /*
9602  * Refill the input buffer and return the next input character:
9603  *
9604  * 1) If a string was pushed back on the input, pop it;
9605  * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9606  *    or we are reading from a string so we can't refill the buffer,
9607  *    return EOF.
9608  * 3) If there is more stuff in this buffer, use it else call read to fill it.
9609  * 4) Process input up to the next newline, deleting nul characters.
9610  */
9611 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9612 #define pgetc_debug(...) ((void)0)
9613 static int
9614 preadbuffer(void)
9615 {
9616         char *q;
9617         int more;
9618
9619         while (g_parsefile->strpush) {
9620 #if ENABLE_ASH_ALIAS
9621                 if (g_parsefile->left_in_line == -1
9622                  && g_parsefile->strpush->ap
9623                  && g_parsefile->next_to_pgetc[-1] != ' '
9624                  && g_parsefile->next_to_pgetc[-1] != '\t'
9625                 ) {
9626                         pgetc_debug("preadbuffer PEOA");
9627                         return PEOA;
9628                 }
9629 #endif
9630                 popstring();
9631                 /* try "pgetc" now: */
9632                 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9633                                 g_parsefile->left_in_line,
9634                                 g_parsefile->next_to_pgetc,
9635                                 g_parsefile->next_to_pgetc);
9636                 if (--g_parsefile->left_in_line >= 0)
9637                         return (unsigned char)(*g_parsefile->next_to_pgetc++);
9638         }
9639         /* on both branches above g_parsefile->left_in_line < 0.
9640          * "pgetc" needs refilling.
9641          */
9642
9643         /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9644          * pungetc() may increment it a few times.
9645          * Assuming it won't increment it to less than -90.
9646          */
9647         if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9648                 pgetc_debug("preadbuffer PEOF1");
9649                 /* even in failure keep left_in_line and next_to_pgetc
9650                  * in lock step, for correct multi-layer pungetc.
9651                  * left_in_line was decremented before preadbuffer(),
9652                  * must inc next_to_pgetc: */
9653                 g_parsefile->next_to_pgetc++;
9654                 return PEOF;
9655         }
9656
9657         more = g_parsefile->left_in_buffer;
9658         if (more <= 0) {
9659                 flush_stdout_stderr();
9660  again:
9661                 more = preadfd();
9662                 if (more <= 0) {
9663                         /* don't try reading again */
9664                         g_parsefile->left_in_line = -99;
9665                         pgetc_debug("preadbuffer PEOF2");
9666                         g_parsefile->next_to_pgetc++;
9667                         return PEOF;
9668                 }
9669         }
9670
9671         /* Find out where's the end of line.
9672          * Set g_parsefile->left_in_line
9673          * and g_parsefile->left_in_buffer acordingly.
9674          * NUL chars are deleted.
9675          */
9676         q = g_parsefile->next_to_pgetc;
9677         for (;;) {
9678                 char c;
9679
9680                 more--;
9681
9682                 c = *q;
9683                 if (c == '\0') {
9684                         memmove(q, q + 1, more);
9685                 } else {
9686                         q++;
9687                         if (c == '\n') {
9688                                 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9689                                 break;
9690                         }
9691                 }
9692
9693                 if (more <= 0) {
9694                         g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9695                         if (g_parsefile->left_in_line < 0)
9696                                 goto again;
9697                         break;
9698                 }
9699         }
9700         g_parsefile->left_in_buffer = more;
9701
9702         if (vflag) {
9703                 char save = *q;
9704                 *q = '\0';
9705                 out2str(g_parsefile->next_to_pgetc);
9706                 *q = save;
9707         }
9708
9709         pgetc_debug("preadbuffer at %d:%p'%s'",
9710                         g_parsefile->left_in_line,
9711                         g_parsefile->next_to_pgetc,
9712                         g_parsefile->next_to_pgetc);
9713         return (unsigned char)*g_parsefile->next_to_pgetc++;
9714 }
9715
9716 #define pgetc_as_macro() \
9717         (--g_parsefile->left_in_line >= 0 \
9718         ? (unsigned char)*g_parsefile->next_to_pgetc++ \
9719         : preadbuffer() \
9720         )
9721
9722 static int
9723 pgetc(void)
9724 {
9725         pgetc_debug("pgetc_fast at %d:%p'%s'",
9726                         g_parsefile->left_in_line,
9727                         g_parsefile->next_to_pgetc,
9728                         g_parsefile->next_to_pgetc);
9729         return pgetc_as_macro();
9730 }
9731
9732 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9733 # define pgetc_fast() pgetc()
9734 #else
9735 # define pgetc_fast() pgetc_as_macro()
9736 #endif
9737
9738 #if ENABLE_ASH_ALIAS
9739 static int
9740 pgetc_without_PEOA(void)
9741 {
9742         int c;
9743         do {
9744                 pgetc_debug("pgetc_fast at %d:%p'%s'",
9745                                 g_parsefile->left_in_line,
9746                                 g_parsefile->next_to_pgetc,
9747                                 g_parsefile->next_to_pgetc);
9748                 c = pgetc_fast();
9749         } while (c == PEOA);
9750         return c;
9751 }
9752 #else
9753 # define pgetc_without_PEOA() pgetc()
9754 #endif
9755
9756 /*
9757  * Read a line from the script.
9758  */
9759 static char *
9760 pfgets(char *line, int len)
9761 {
9762         char *p = line;
9763         int nleft = len;
9764         int c;
9765
9766         while (--nleft > 0) {
9767                 c = pgetc_without_PEOA();
9768                 if (c == PEOF) {
9769                         if (p == line)
9770                                 return NULL;
9771                         break;
9772                 }
9773                 *p++ = c;
9774                 if (c == '\n')
9775                         break;
9776         }
9777         *p = '\0';
9778         return line;
9779 }
9780
9781 /*
9782  * Undo the last call to pgetc.  Only one character may be pushed back.
9783  * PEOF may be pushed back.
9784  */
9785 static void
9786 pungetc(void)
9787 {
9788         g_parsefile->left_in_line++;
9789         g_parsefile->next_to_pgetc--;
9790         pgetc_debug("pushed back to %d:%p'%s'",
9791                         g_parsefile->left_in_line,
9792                         g_parsefile->next_to_pgetc,
9793                         g_parsefile->next_to_pgetc);
9794 }
9795
9796 /*
9797  * To handle the "." command, a stack of input files is used.  Pushfile
9798  * adds a new entry to the stack and popfile restores the previous level.
9799  */
9800 static void
9801 pushfile(void)
9802 {
9803         struct parsefile *pf;
9804
9805         pf = ckzalloc(sizeof(*pf));
9806         pf->prev = g_parsefile;
9807         pf->pf_fd = -1;
9808         /*pf->strpush = NULL; - ckzalloc did it */
9809         /*pf->basestrpush.prev = NULL;*/
9810         g_parsefile = pf;
9811 }
9812
9813 static void
9814 popfile(void)
9815 {
9816         struct parsefile *pf = g_parsefile;
9817
9818         INT_OFF;
9819         if (pf->pf_fd >= 0)
9820                 close(pf->pf_fd);
9821         free(pf->buf);
9822         while (pf->strpush)
9823                 popstring();
9824         g_parsefile = pf->prev;
9825         free(pf);
9826         INT_ON;
9827 }
9828
9829 /*
9830  * Return to top level.
9831  */
9832 static void
9833 popallfiles(void)
9834 {
9835         while (g_parsefile != &basepf)
9836                 popfile();
9837 }
9838
9839 /*
9840  * Close the file(s) that the shell is reading commands from.  Called
9841  * after a fork is done.
9842  */
9843 static void
9844 closescript(void)
9845 {
9846         popallfiles();
9847         if (g_parsefile->pf_fd > 0) {
9848                 close(g_parsefile->pf_fd);
9849                 g_parsefile->pf_fd = 0;
9850         }
9851 }
9852
9853 /*
9854  * Like setinputfile, but takes an open file descriptor.  Call this with
9855  * interrupts off.
9856  */
9857 static void
9858 setinputfd(int fd, int push)
9859 {
9860         close_on_exec_on(fd);
9861         if (push) {
9862                 pushfile();
9863                 g_parsefile->buf = NULL;
9864         }
9865         g_parsefile->pf_fd = fd;
9866         if (g_parsefile->buf == NULL)
9867                 g_parsefile->buf = ckmalloc(IBUFSIZ);
9868         g_parsefile->left_in_buffer = 0;
9869         g_parsefile->left_in_line = 0;
9870         g_parsefile->linno = 1;
9871 }
9872
9873 /*
9874  * Set the input to take input from a file.  If push is set, push the
9875  * old input onto the stack first.
9876  */
9877 static int
9878 setinputfile(const char *fname, int flags)
9879 {
9880         int fd;
9881         int fd2;
9882
9883         INT_OFF;
9884         fd = open(fname, O_RDONLY);
9885         if (fd < 0) {
9886                 if (flags & INPUT_NOFILE_OK)
9887                         goto out;
9888                 ash_msg_and_raise_error("can't open '%s'", fname);
9889         }
9890         if (fd < 10) {
9891                 fd2 = copyfd(fd, 10);
9892                 close(fd);
9893                 if (fd2 < 0)
9894                         ash_msg_and_raise_error("out of file descriptors");
9895                 fd = fd2;
9896         }
9897         setinputfd(fd, flags & INPUT_PUSH_FILE);
9898  out:
9899         INT_ON;
9900         return fd;
9901 }
9902
9903 /*
9904  * Like setinputfile, but takes input from a string.
9905  */
9906 static void
9907 setinputstring(char *string)
9908 {
9909         INT_OFF;
9910         pushfile();
9911         g_parsefile->next_to_pgetc = string;
9912         g_parsefile->left_in_line = strlen(string);
9913         g_parsefile->buf = NULL;
9914         g_parsefile->linno = 1;
9915         INT_ON;
9916 }
9917
9918
9919 /* ============ mail.c
9920  *
9921  * Routines to check for mail.
9922  */
9923
9924 #if ENABLE_ASH_MAIL
9925
9926 #define MAXMBOXES 10
9927
9928 /* times of mailboxes */
9929 static time_t mailtime[MAXMBOXES];
9930 /* Set if MAIL or MAILPATH is changed. */
9931 static smallint mail_var_path_changed;
9932
9933 /*
9934  * Print appropriate message(s) if mail has arrived.
9935  * If mail_var_path_changed is set,
9936  * then the value of MAIL has mail_var_path_changed,
9937  * so we just update the values.
9938  */
9939 static void
9940 chkmail(void)
9941 {
9942         const char *mpath;
9943         char *p;
9944         char *q;
9945         time_t *mtp;
9946         struct stackmark smark;
9947         struct stat statb;
9948
9949         setstackmark(&smark);
9950         mpath = mpathset() ? mpathval() : mailval();
9951         for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9952                 p = path_advance(&mpath, nullstr);
9953                 if (p == NULL)
9954                         break;
9955                 if (*p == '\0')
9956                         continue;
9957                 for (q = p; *q; q++)
9958                         continue;
9959 #if DEBUG
9960                 if (q[-1] != '/')
9961                         abort();
9962 #endif
9963                 q[-1] = '\0';                   /* delete trailing '/' */
9964                 if (stat(p, &statb) < 0) {
9965                         *mtp = 0;
9966                         continue;
9967                 }
9968                 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9969                         fprintf(
9970                                 stderr, "%s\n",
9971                                 pathopt ? pathopt : "you have mail"
9972                         );
9973                 }
9974                 *mtp = statb.st_mtime;
9975         }
9976         mail_var_path_changed = 0;
9977         popstackmark(&smark);
9978 }
9979
9980 static void FAST_FUNC
9981 changemail(const char *val UNUSED_PARAM)
9982 {
9983         mail_var_path_changed = 1;
9984 }
9985
9986 #endif /* ASH_MAIL */
9987
9988
9989 /* ============ ??? */
9990
9991 /*
9992  * Set the shell parameters.
9993  */
9994 static void
9995 setparam(char **argv)
9996 {
9997         char **newparam;
9998         char **ap;
9999         int nparam;
10000
10001         for (nparam = 0; argv[nparam]; nparam++)
10002                 continue;
10003         ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10004         while (*argv) {
10005                 *ap++ = ckstrdup(*argv++);
10006         }
10007         *ap = NULL;
10008         freeparam(&shellparam);
10009         shellparam.malloced = 1;
10010         shellparam.nparam = nparam;
10011         shellparam.p = newparam;
10012 #if ENABLE_ASH_GETOPTS
10013         shellparam.optind = 1;
10014         shellparam.optoff = -1;
10015 #endif
10016 }
10017
10018 /*
10019  * Process shell options.  The global variable argptr contains a pointer
10020  * to the argument list; we advance it past the options.
10021  *
10022  * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10023  * For a non-interactive shell, an error condition encountered
10024  * by a special built-in ... shall cause the shell to write a diagnostic message
10025  * to standard error and exit as shown in the following table:
10026  * Error                                           Special Built-In
10027  * ...
10028  * Utility syntax error (option or operand error)  Shall exit
10029  * ...
10030  * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10031  * we see that bash does not do that (set "finishes" with error code 1 instead,
10032  * and shell continues), and people rely on this behavior!
10033  * Testcase:
10034  * set -o barfoo 2>/dev/null
10035  * echo $?
10036  *
10037  * Oh well. Let's mimic that.
10038  */
10039 static int
10040 plus_minus_o(char *name, int val)
10041 {
10042         int i;
10043
10044         if (name) {
10045                 for (i = 0; i < NOPTS; i++) {
10046                         if (strcmp(name, optnames(i)) == 0) {
10047                                 optlist[i] = val;
10048                                 return 0;
10049                         }
10050                 }
10051                 ash_msg("illegal option %co %s", val ? '-' : '+', name);
10052                 return 1;
10053         }
10054         for (i = 0; i < NOPTS; i++) {
10055                 if (val) {
10056                         out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10057                 } else {
10058                         out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10059                 }
10060         }
10061         return 0;
10062 }
10063 static void
10064 setoption(int flag, int val)
10065 {
10066         int i;
10067
10068         for (i = 0; i < NOPTS; i++) {
10069                 if (optletters(i) == flag) {
10070                         optlist[i] = val;
10071                         return;
10072                 }
10073         }
10074         ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
10075         /* NOTREACHED */
10076 }
10077 static int
10078 options(int cmdline)
10079 {
10080         char *p;
10081         int val;
10082         int c;
10083
10084         if (cmdline)
10085                 minusc = NULL;
10086         while ((p = *argptr) != NULL) {
10087                 c = *p++;
10088                 if (c != '-' && c != '+')
10089                         break;
10090                 argptr++;
10091                 val = 0; /* val = 0 if c == '+' */
10092                 if (c == '-') {
10093                         val = 1;
10094                         if (p[0] == '\0' || LONE_DASH(p)) {
10095                                 if (!cmdline) {
10096                                         /* "-" means turn off -x and -v */
10097                                         if (p[0] == '\0')
10098                                                 xflag = vflag = 0;
10099                                         /* "--" means reset params */
10100                                         else if (*argptr == NULL)
10101                                                 setparam(argptr);
10102                                 }
10103                                 break;    /* "-" or  "--" terminates options */
10104                         }
10105                 }
10106                 /* first char was + or - */
10107                 while ((c = *p++) != '\0') {
10108                         /* bash 3.2 indeed handles -c CMD and +c CMD the same */
10109                         if (c == 'c' && cmdline) {
10110                                 minusc = p;     /* command is after shell args */
10111                         } else if (c == 'o') {
10112                                 if (plus_minus_o(*argptr, val)) {
10113                                         /* it already printed err message */
10114                                         return 1; /* error */
10115                                 }
10116                                 if (*argptr)
10117                                         argptr++;
10118                         } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10119                                 isloginsh = 1;
10120                         /* bash does not accept +-login, we also won't */
10121                         } else if (cmdline && val && (c == '-')) { /* long options */
10122                                 if (strcmp(p, "login") == 0)
10123                                         isloginsh = 1;
10124                                 break;
10125                         } else {
10126                                 setoption(c, val);
10127                         }
10128                 }
10129         }
10130         return 0;
10131 }
10132
10133 /*
10134  * The shift builtin command.
10135  */
10136 static int FAST_FUNC
10137 shiftcmd(int argc UNUSED_PARAM, char **argv)
10138 {
10139         int n;
10140         char **ap1, **ap2;
10141
10142         n = 1;
10143         if (argv[1])
10144                 n = number(argv[1]);
10145         if (n > shellparam.nparam)
10146                 n = 0; /* bash compat, was = shellparam.nparam; */
10147         INT_OFF;
10148         shellparam.nparam -= n;
10149         for (ap1 = shellparam.p; --n >= 0; ap1++) {
10150                 if (shellparam.malloced)
10151                         free(*ap1);
10152         }
10153         ap2 = shellparam.p;
10154         while ((*ap2++ = *ap1++) != NULL)
10155                 continue;
10156 #if ENABLE_ASH_GETOPTS
10157         shellparam.optind = 1;
10158         shellparam.optoff = -1;
10159 #endif
10160         INT_ON;
10161         return 0;
10162 }
10163
10164 /*
10165  * POSIX requires that 'set' (but not export or readonly) output the
10166  * variables in lexicographic order - by the locale's collating order (sigh).
10167  * Maybe we could keep them in an ordered balanced binary tree
10168  * instead of hashed lists.
10169  * For now just roll 'em through qsort for printing...
10170  */
10171 static int
10172 showvars(const char *sep_prefix, int on, int off)
10173 {
10174         const char *sep;
10175         char **ep, **epend;
10176
10177         ep = listvars(on, off, &epend);
10178         qsort(ep, epend - ep, sizeof(char *), vpcmp);
10179
10180         sep = *sep_prefix ? " " : sep_prefix;
10181
10182         for (; ep < epend; ep++) {
10183                 const char *p;
10184                 const char *q;
10185
10186                 p = strchrnul(*ep, '=');
10187                 q = nullstr;
10188                 if (*p)
10189                         q = single_quote(++p);
10190                 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10191         }
10192         return 0;
10193 }
10194
10195 /*
10196  * The set command builtin.
10197  */
10198 static int FAST_FUNC
10199 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10200 {
10201         int retval;
10202
10203         if (!argv[1])
10204                 return showvars(nullstr, 0, VUNSET);
10205         INT_OFF;
10206         retval = 1;
10207         if (!options(0)) { /* if no parse error... */
10208                 retval = 0;
10209                 optschanged();
10210                 if (*argptr != NULL) {
10211                         setparam(argptr);
10212                 }
10213         }
10214         INT_ON;
10215         return retval;
10216 }
10217
10218 #if ENABLE_ASH_RANDOM_SUPPORT
10219 static void FAST_FUNC
10220 change_random(const char *value)
10221 {
10222         uint32_t t;
10223
10224         if (value == NULL) {
10225                 /* "get", generate */
10226                 t = next_random(&random_gen);
10227                 /* set without recursion */
10228                 setvar(vrandom.var_text, utoa(t), VNOFUNC);
10229                 vrandom.flags &= ~VNOFUNC;
10230         } else {
10231                 /* set/reset */
10232                 t = strtoul(value, NULL, 10);
10233                 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
10234         }
10235 }
10236 #endif
10237
10238 #if ENABLE_ASH_GETOPTS
10239 static int
10240 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
10241 {
10242         char *p, *q;
10243         char c = '?';
10244         int done = 0;
10245         int err = 0;
10246         char s[12];
10247         char **optnext;
10248
10249         if (*param_optind < 1)
10250                 return 1;
10251         optnext = optfirst + *param_optind - 1;
10252
10253         if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
10254                 p = NULL;
10255         else
10256                 p = optnext[-1] + *optoff;
10257         if (p == NULL || *p == '\0') {
10258                 /* Current word is done, advance */
10259                 p = *optnext;
10260                 if (p == NULL || *p != '-' || *++p == '\0') {
10261  atend:
10262                         p = NULL;
10263                         done = 1;
10264                         goto out;
10265                 }
10266                 optnext++;
10267                 if (LONE_DASH(p))        /* check for "--" */
10268                         goto atend;
10269         }
10270
10271         c = *p++;
10272         for (q = optstr; *q != c;) {
10273                 if (*q == '\0') {
10274                         if (optstr[0] == ':') {
10275                                 s[0] = c;
10276                                 s[1] = '\0';
10277                                 err |= setvarsafe("OPTARG", s, 0);
10278                         } else {
10279                                 fprintf(stderr, "Illegal option -%c\n", c);
10280                                 unsetvar("OPTARG");
10281                         }
10282                         c = '?';
10283                         goto out;
10284                 }
10285                 if (*++q == ':')
10286                         q++;
10287         }
10288
10289         if (*++q == ':') {
10290                 if (*p == '\0' && (p = *optnext) == NULL) {
10291                         if (optstr[0] == ':') {
10292                                 s[0] = c;
10293                                 s[1] = '\0';
10294                                 err |= setvarsafe("OPTARG", s, 0);
10295                                 c = ':';
10296                         } else {
10297                                 fprintf(stderr, "No arg for -%c option\n", c);
10298                                 unsetvar("OPTARG");
10299                                 c = '?';
10300                         }
10301                         goto out;
10302                 }
10303
10304                 if (p == *optnext)
10305                         optnext++;
10306                 err |= setvarsafe("OPTARG", p, 0);
10307                 p = NULL;
10308         } else
10309                 err |= setvarsafe("OPTARG", nullstr, 0);
10310  out:
10311         *optoff = p ? p - *(optnext - 1) : -1;
10312         *param_optind = optnext - optfirst + 1;
10313         fmtstr(s, sizeof(s), "%d", *param_optind);
10314         err |= setvarsafe("OPTIND", s, VNOFUNC);
10315         s[0] = c;
10316         s[1] = '\0';
10317         err |= setvarsafe(optvar, s, 0);
10318         if (err) {
10319                 *param_optind = 1;
10320                 *optoff = -1;
10321                 flush_stdout_stderr();
10322                 raise_exception(EXERROR);
10323         }
10324         return done;
10325 }
10326
10327 /*
10328  * The getopts builtin.  Shellparam.optnext points to the next argument
10329  * to be processed.  Shellparam.optptr points to the next character to
10330  * be processed in the current argument.  If shellparam.optnext is NULL,
10331  * then it's the first time getopts has been called.
10332  */
10333 static int FAST_FUNC
10334 getoptscmd(int argc, char **argv)
10335 {
10336         char **optbase;
10337
10338         if (argc < 3)
10339                 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10340         if (argc == 3) {
10341                 optbase = shellparam.p;
10342                 if (shellparam.optind > shellparam.nparam + 1) {
10343                         shellparam.optind = 1;
10344                         shellparam.optoff = -1;
10345                 }
10346         } else {
10347                 optbase = &argv[3];
10348                 if (shellparam.optind > argc - 2) {
10349                         shellparam.optind = 1;
10350                         shellparam.optoff = -1;
10351                 }
10352         }
10353
10354         return getopts(argv[1], argv[2], optbase, &shellparam.optind,
10355                         &shellparam.optoff);
10356 }
10357 #endif /* ASH_GETOPTS */
10358
10359
10360 /* ============ Shell parser */
10361
10362 struct heredoc {
10363         struct heredoc *next;   /* next here document in list */
10364         union node *here;       /* redirection node */
10365         char *eofmark;          /* string indicating end of input */
10366         smallint striptabs;     /* if set, strip leading tabs */
10367 };
10368
10369 static smallint tokpushback;           /* last token pushed back */
10370 static smallint parsebackquote;        /* nonzero if we are inside backquotes */
10371 static smallint quoteflag;             /* set if (part of) last token was quoted */
10372 static token_id_t lasttoken;           /* last token read (integer id Txxx) */
10373 static struct heredoc *heredoclist;    /* list of here documents to read */
10374 static char *wordtext;                 /* text of last word returned by readtoken */
10375 static struct nodelist *backquotelist;
10376 static union node *redirnode;
10377 static struct heredoc *heredoc;
10378
10379 static const char *
10380 tokname(char *buf, int tok)
10381 {
10382         if (tok < TSEMI)
10383                 return tokname_array[tok] + 1;
10384         sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10385         return buf;
10386 }
10387
10388 /* raise_error_unexpected_syntax:
10389  * Called when an unexpected token is read during the parse.  The argument
10390  * is the token that is expected, or -1 if more than one type of token can
10391  * occur at this point.
10392  */
10393 static void raise_error_unexpected_syntax(int) NORETURN;
10394 static void
10395 raise_error_unexpected_syntax(int token)
10396 {
10397         char msg[64];
10398         char buf[16];
10399         int l;
10400
10401         l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
10402         if (token >= 0)
10403                 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
10404         raise_error_syntax(msg);
10405         /* NOTREACHED */
10406 }
10407
10408 #define EOFMARKLEN 79
10409
10410 /* parsing is heavily cross-recursive, need these forward decls */
10411 static union node *andor(void);
10412 static union node *pipeline(void);
10413 static union node *parse_command(void);
10414 static void parseheredoc(void);
10415 static char peektoken(void);
10416 static int readtoken(void);
10417
10418 static union node *
10419 list(int nlflag)
10420 {
10421         union node *n1, *n2, *n3;
10422         int tok;
10423
10424         checkkwd = CHKNL | CHKKWD | CHKALIAS;
10425         if (nlflag == 2 && peektoken())
10426                 return NULL;
10427         n1 = NULL;
10428         for (;;) {
10429                 n2 = andor();
10430                 tok = readtoken();
10431                 if (tok == TBACKGND) {
10432                         if (n2->type == NPIPE) {
10433                                 n2->npipe.pipe_backgnd = 1;
10434                         } else {
10435                                 if (n2->type != NREDIR) {
10436                                         n3 = stzalloc(sizeof(struct nredir));
10437                                         n3->nredir.n = n2;
10438                                         /*n3->nredir.redirect = NULL; - stzalloc did it */
10439                                         n2 = n3;
10440                                 }
10441                                 n2->type = NBACKGND;
10442                         }
10443                 }
10444                 if (n1 == NULL) {
10445                         n1 = n2;
10446                 } else {
10447                         n3 = stzalloc(sizeof(struct nbinary));
10448                         n3->type = NSEMI;
10449                         n3->nbinary.ch1 = n1;
10450                         n3->nbinary.ch2 = n2;
10451                         n1 = n3;
10452                 }
10453                 switch (tok) {
10454                 case TBACKGND:
10455                 case TSEMI:
10456                         tok = readtoken();
10457                         /* fall through */
10458                 case TNL:
10459                         if (tok == TNL) {
10460                                 parseheredoc();
10461                                 if (nlflag == 1)
10462                                         return n1;
10463                         } else {
10464                                 tokpushback = 1;
10465                         }
10466                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
10467                         if (peektoken())
10468                                 return n1;
10469                         break;
10470                 case TEOF:
10471                         if (heredoclist)
10472                                 parseheredoc();
10473                         else
10474                                 pungetc();              /* push back EOF on input */
10475                         return n1;
10476                 default:
10477                         if (nlflag == 1)
10478                                 raise_error_unexpected_syntax(-1);
10479                         tokpushback = 1;
10480                         return n1;
10481                 }
10482         }
10483 }
10484
10485 static union node *
10486 andor(void)
10487 {
10488         union node *n1, *n2, *n3;
10489         int t;
10490
10491         n1 = pipeline();
10492         for (;;) {
10493                 t = readtoken();
10494                 if (t == TAND) {
10495                         t = NAND;
10496                 } else if (t == TOR) {
10497                         t = NOR;
10498                 } else {
10499                         tokpushback = 1;
10500                         return n1;
10501                 }
10502                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10503                 n2 = pipeline();
10504                 n3 = stzalloc(sizeof(struct nbinary));
10505                 n3->type = t;
10506                 n3->nbinary.ch1 = n1;
10507                 n3->nbinary.ch2 = n2;
10508                 n1 = n3;
10509         }
10510 }
10511
10512 static union node *
10513 pipeline(void)
10514 {
10515         union node *n1, *n2, *pipenode;
10516         struct nodelist *lp, *prev;
10517         int negate;
10518
10519         negate = 0;
10520         TRACE(("pipeline: entered\n"));
10521         if (readtoken() == TNOT) {
10522                 negate = !negate;
10523                 checkkwd = CHKKWD | CHKALIAS;
10524         } else
10525                 tokpushback = 1;
10526         n1 = parse_command();
10527         if (readtoken() == TPIPE) {
10528                 pipenode = stzalloc(sizeof(struct npipe));
10529                 pipenode->type = NPIPE;
10530                 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10531                 lp = stzalloc(sizeof(struct nodelist));
10532                 pipenode->npipe.cmdlist = lp;
10533                 lp->n = n1;
10534                 do {
10535                         prev = lp;
10536                         lp = stzalloc(sizeof(struct nodelist));
10537                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
10538                         lp->n = parse_command();
10539                         prev->next = lp;
10540                 } while (readtoken() == TPIPE);
10541                 lp->next = NULL;
10542                 n1 = pipenode;
10543         }
10544         tokpushback = 1;
10545         if (negate) {
10546                 n2 = stzalloc(sizeof(struct nnot));
10547                 n2->type = NNOT;
10548                 n2->nnot.com = n1;
10549                 return n2;
10550         }
10551         return n1;
10552 }
10553
10554 static union node *
10555 makename(void)
10556 {
10557         union node *n;
10558
10559         n = stzalloc(sizeof(struct narg));
10560         n->type = NARG;
10561         /*n->narg.next = NULL; - stzalloc did it */
10562         n->narg.text = wordtext;
10563         n->narg.backquote = backquotelist;
10564         return n;
10565 }
10566
10567 static void
10568 fixredir(union node *n, const char *text, int err)
10569 {
10570         int fd;
10571
10572         TRACE(("Fix redir %s %d\n", text, err));
10573         if (!err)
10574                 n->ndup.vname = NULL;
10575
10576         fd = bb_strtou(text, NULL, 10);
10577         if (!errno && fd >= 0)
10578                 n->ndup.dupfd = fd;
10579         else if (LONE_DASH(text))
10580                 n->ndup.dupfd = -1;
10581         else {
10582                 if (err)
10583                         raise_error_syntax("bad fd number");
10584                 n->ndup.vname = makename();
10585         }
10586 }
10587
10588 /*
10589  * Returns true if the text contains nothing to expand (no dollar signs
10590  * or backquotes).
10591  */
10592 static int
10593 noexpand(const char *text)
10594 {
10595         unsigned char c;
10596
10597         while ((c = *text++) != '\0') {
10598                 if (c == CTLQUOTEMARK)
10599                         continue;
10600                 if (c == CTLESC)
10601                         text++;
10602                 else if (SIT(c, BASESYNTAX) == CCTL)
10603                         return 0;
10604         }
10605         return 1;
10606 }
10607
10608 static void
10609 parsefname(void)
10610 {
10611         union node *n = redirnode;
10612
10613         if (readtoken() != TWORD)
10614                 raise_error_unexpected_syntax(-1);
10615         if (n->type == NHERE) {
10616                 struct heredoc *here = heredoc;
10617                 struct heredoc *p;
10618                 int i;
10619
10620                 if (quoteflag == 0)
10621                         n->type = NXHERE;
10622                 TRACE(("Here document %d\n", n->type));
10623                 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10624                         raise_error_syntax("illegal eof marker for << redirection");
10625                 rmescapes(wordtext, 0);
10626                 here->eofmark = wordtext;
10627                 here->next = NULL;
10628                 if (heredoclist == NULL)
10629                         heredoclist = here;
10630                 else {
10631                         for (p = heredoclist; p->next; p = p->next)
10632                                 continue;
10633                         p->next = here;
10634                 }
10635         } else if (n->type == NTOFD || n->type == NFROMFD) {
10636                 fixredir(n, wordtext, 0);
10637         } else {
10638                 n->nfile.fname = makename();
10639         }
10640 }
10641
10642 static union node *
10643 simplecmd(void)
10644 {
10645         union node *args, **app;
10646         union node *n = NULL;
10647         union node *vars, **vpp;
10648         union node **rpp, *redir;
10649         int savecheckkwd;
10650 #if ENABLE_ASH_BASH_COMPAT
10651         smallint double_brackets_flag = 0;
10652 #endif
10653
10654         args = NULL;
10655         app = &args;
10656         vars = NULL;
10657         vpp = &vars;
10658         redir = NULL;
10659         rpp = &redir;
10660
10661         savecheckkwd = CHKALIAS;
10662         for (;;) {
10663                 int t;
10664                 checkkwd = savecheckkwd;
10665                 t = readtoken();
10666                 switch (t) {
10667 #if ENABLE_ASH_BASH_COMPAT
10668                 case TAND: /* "&&" */
10669                 case TOR: /* "||" */
10670                         if (!double_brackets_flag) {
10671                                 tokpushback = 1;
10672                                 goto out;
10673                         }
10674                         wordtext = (char *) (t == TAND ? "-a" : "-o");
10675 #endif
10676                 case TWORD:
10677                         n = stzalloc(sizeof(struct narg));
10678                         n->type = NARG;
10679                         /*n->narg.next = NULL; - stzalloc did it */
10680                         n->narg.text = wordtext;
10681 #if ENABLE_ASH_BASH_COMPAT
10682                         if (strcmp("[[", wordtext) == 0)
10683                                 double_brackets_flag = 1;
10684                         else if (strcmp("]]", wordtext) == 0)
10685                                 double_brackets_flag = 0;
10686 #endif
10687                         n->narg.backquote = backquotelist;
10688                         if (savecheckkwd && isassignment(wordtext)) {
10689                                 *vpp = n;
10690                                 vpp = &n->narg.next;
10691                         } else {
10692                                 *app = n;
10693                                 app = &n->narg.next;
10694                                 savecheckkwd = 0;
10695                         }
10696                         break;
10697                 case TREDIR:
10698                         *rpp = n = redirnode;
10699                         rpp = &n->nfile.next;
10700                         parsefname();   /* read name of redirection file */
10701                         break;
10702                 case TLP:
10703                         if (args && app == &args->narg.next
10704                          && !vars && !redir
10705                         ) {
10706                                 struct builtincmd *bcmd;
10707                                 const char *name;
10708
10709                                 /* We have a function */
10710                                 if (readtoken() != TRP)
10711                                         raise_error_unexpected_syntax(TRP);
10712                                 name = n->narg.text;
10713                                 if (!goodname(name)
10714                                  || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10715                                 ) {
10716                                         raise_error_syntax("bad function name");
10717                                 }
10718                                 n->type = NDEFUN;
10719                                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10720                                 n->narg.next = parse_command();
10721                                 return n;
10722                         }
10723                         /* fall through */
10724                 default:
10725                         tokpushback = 1;
10726                         goto out;
10727                 }
10728         }
10729  out:
10730         *app = NULL;
10731         *vpp = NULL;
10732         *rpp = NULL;
10733         n = stzalloc(sizeof(struct ncmd));
10734         n->type = NCMD;
10735         n->ncmd.args = args;
10736         n->ncmd.assign = vars;
10737         n->ncmd.redirect = redir;
10738         return n;
10739 }
10740
10741 static union node *
10742 parse_command(void)
10743 {
10744         union node *n1, *n2;
10745         union node *ap, **app;
10746         union node *cp, **cpp;
10747         union node *redir, **rpp;
10748         union node **rpp2;
10749         int t;
10750
10751         redir = NULL;
10752         rpp2 = &redir;
10753
10754         switch (readtoken()) {
10755         default:
10756                 raise_error_unexpected_syntax(-1);
10757                 /* NOTREACHED */
10758         case TIF:
10759                 n1 = stzalloc(sizeof(struct nif));
10760                 n1->type = NIF;
10761                 n1->nif.test = list(0);
10762                 if (readtoken() != TTHEN)
10763                         raise_error_unexpected_syntax(TTHEN);
10764                 n1->nif.ifpart = list(0);
10765                 n2 = n1;
10766                 while (readtoken() == TELIF) {
10767                         n2->nif.elsepart = stzalloc(sizeof(struct nif));
10768                         n2 = n2->nif.elsepart;
10769                         n2->type = NIF;
10770                         n2->nif.test = list(0);
10771                         if (readtoken() != TTHEN)
10772                                 raise_error_unexpected_syntax(TTHEN);
10773                         n2->nif.ifpart = list(0);
10774                 }
10775                 if (lasttoken == TELSE)
10776                         n2->nif.elsepart = list(0);
10777                 else {
10778                         n2->nif.elsepart = NULL;
10779                         tokpushback = 1;
10780                 }
10781                 t = TFI;
10782                 break;
10783         case TWHILE:
10784         case TUNTIL: {
10785                 int got;
10786                 n1 = stzalloc(sizeof(struct nbinary));
10787                 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10788                 n1->nbinary.ch1 = list(0);
10789                 got = readtoken();
10790                 if (got != TDO) {
10791                         TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
10792                                         got == TWORD ? wordtext : ""));
10793                         raise_error_unexpected_syntax(TDO);
10794                 }
10795                 n1->nbinary.ch2 = list(0);
10796                 t = TDONE;
10797                 break;
10798         }
10799         case TFOR:
10800                 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10801                         raise_error_syntax("bad for loop variable");
10802                 n1 = stzalloc(sizeof(struct nfor));
10803                 n1->type = NFOR;
10804                 n1->nfor.var = wordtext;
10805                 checkkwd = CHKKWD | CHKALIAS;
10806                 if (readtoken() == TIN) {
10807                         app = &ap;
10808                         while (readtoken() == TWORD) {
10809                                 n2 = stzalloc(sizeof(struct narg));
10810                                 n2->type = NARG;
10811                                 /*n2->narg.next = NULL; - stzalloc did it */
10812                                 n2->narg.text = wordtext;
10813                                 n2->narg.backquote = backquotelist;
10814                                 *app = n2;
10815                                 app = &n2->narg.next;
10816                         }
10817                         *app = NULL;
10818                         n1->nfor.args = ap;
10819                         if (lasttoken != TNL && lasttoken != TSEMI)
10820                                 raise_error_unexpected_syntax(-1);
10821                 } else {
10822                         n2 = stzalloc(sizeof(struct narg));
10823                         n2->type = NARG;
10824                         /*n2->narg.next = NULL; - stzalloc did it */
10825                         n2->narg.text = (char *)dolatstr;
10826                         /*n2->narg.backquote = NULL;*/
10827                         n1->nfor.args = n2;
10828                         /*
10829                          * Newline or semicolon here is optional (but note
10830                          * that the original Bourne shell only allowed NL).
10831                          */
10832                         if (lasttoken != TNL && lasttoken != TSEMI)
10833                                 tokpushback = 1;
10834                 }
10835                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10836                 if (readtoken() != TDO)
10837                         raise_error_unexpected_syntax(TDO);
10838                 n1->nfor.body = list(0);
10839                 t = TDONE;
10840                 break;
10841         case TCASE:
10842                 n1 = stzalloc(sizeof(struct ncase));
10843                 n1->type = NCASE;
10844                 if (readtoken() != TWORD)
10845                         raise_error_unexpected_syntax(TWORD);
10846                 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10847                 n2->type = NARG;
10848                 /*n2->narg.next = NULL; - stzalloc did it */
10849                 n2->narg.text = wordtext;
10850                 n2->narg.backquote = backquotelist;
10851                 do {
10852                         checkkwd = CHKKWD | CHKALIAS;
10853                 } while (readtoken() == TNL);
10854                 if (lasttoken != TIN)
10855                         raise_error_unexpected_syntax(TIN);
10856                 cpp = &n1->ncase.cases;
10857  next_case:
10858                 checkkwd = CHKNL | CHKKWD;
10859                 t = readtoken();
10860                 while (t != TESAC) {
10861                         if (lasttoken == TLP)
10862                                 readtoken();
10863                         *cpp = cp = stzalloc(sizeof(struct nclist));
10864                         cp->type = NCLIST;
10865                         app = &cp->nclist.pattern;
10866                         for (;;) {
10867                                 *app = ap = stzalloc(sizeof(struct narg));
10868                                 ap->type = NARG;
10869                                 /*ap->narg.next = NULL; - stzalloc did it */
10870                                 ap->narg.text = wordtext;
10871                                 ap->narg.backquote = backquotelist;
10872                                 if (readtoken() != TPIPE)
10873                                         break;
10874                                 app = &ap->narg.next;
10875                                 readtoken();
10876                         }
10877                         //ap->narg.next = NULL;
10878                         if (lasttoken != TRP)
10879                                 raise_error_unexpected_syntax(TRP);
10880                         cp->nclist.body = list(2);
10881
10882                         cpp = &cp->nclist.next;
10883
10884                         checkkwd = CHKNL | CHKKWD;
10885                         t = readtoken();
10886                         if (t != TESAC) {
10887                                 if (t != TENDCASE)
10888                                         raise_error_unexpected_syntax(TENDCASE);
10889                                 goto next_case;
10890                         }
10891                 }
10892                 *cpp = NULL;
10893                 goto redir;
10894         case TLP:
10895                 n1 = stzalloc(sizeof(struct nredir));
10896                 n1->type = NSUBSHELL;
10897                 n1->nredir.n = list(0);
10898                 /*n1->nredir.redirect = NULL; - stzalloc did it */
10899                 t = TRP;
10900                 break;
10901         case TBEGIN:
10902                 n1 = list(0);
10903                 t = TEND;
10904                 break;
10905         case TWORD:
10906         case TREDIR:
10907                 tokpushback = 1;
10908                 return simplecmd();
10909         }
10910
10911         if (readtoken() != t)
10912                 raise_error_unexpected_syntax(t);
10913
10914  redir:
10915         /* Now check for redirection which may follow command */
10916         checkkwd = CHKKWD | CHKALIAS;
10917         rpp = rpp2;
10918         while (readtoken() == TREDIR) {
10919                 *rpp = n2 = redirnode;
10920                 rpp = &n2->nfile.next;
10921                 parsefname();
10922         }
10923         tokpushback = 1;
10924         *rpp = NULL;
10925         if (redir) {
10926                 if (n1->type != NSUBSHELL) {
10927                         n2 = stzalloc(sizeof(struct nredir));
10928                         n2->type = NREDIR;
10929                         n2->nredir.n = n1;
10930                         n1 = n2;
10931                 }
10932                 n1->nredir.redirect = redir;
10933         }
10934         return n1;
10935 }
10936
10937 #if ENABLE_ASH_BASH_COMPAT
10938 static int decode_dollar_squote(void)
10939 {
10940         static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10941         int c, cnt;
10942         char *p;
10943         char buf[4];
10944
10945         c = pgetc();
10946         p = strchr(C_escapes, c);
10947         if (p) {
10948                 buf[0] = c;
10949                 p = buf;
10950                 cnt = 3;
10951                 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10952                         do {
10953                                 c = pgetc();
10954                                 *++p = c;
10955                         } while ((unsigned char)(c - '0') <= 7 && --cnt);
10956                         pungetc();
10957                 } else if (c == 'x') { /* \xHH */
10958                         do {
10959                                 c = pgetc();
10960                                 *++p = c;
10961                         } while (isxdigit(c) && --cnt);
10962                         pungetc();
10963                         if (cnt == 3) { /* \x but next char is "bad" */
10964                                 c = 'x';
10965                                 goto unrecognized;
10966                         }
10967                 } else { /* simple seq like \\ or \t */
10968                         p++;
10969                 }
10970                 *p = '\0';
10971                 p = buf;
10972                 c = bb_process_escape_sequence((void*)&p);
10973         } else { /* unrecognized "\z": print both chars unless ' or " */
10974                 if (c != '\'' && c != '"') {
10975  unrecognized:
10976                         c |= 0x100; /* "please encode \, then me" */
10977                 }
10978         }
10979         return c;
10980 }
10981 #endif
10982
10983 /*
10984  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10985  * is not NULL, read a here document.  In the latter case, eofmark is the
10986  * word which marks the end of the document and striptabs is true if
10987  * leading tabs should be stripped from the document.  The argument c
10988  * is the first character of the input token or document.
10989  *
10990  * Because C does not have internal subroutines, I have simulated them
10991  * using goto's to implement the subroutine linkage.  The following macros
10992  * will run code that appears at the end of readtoken1.
10993  */
10994 #define CHECKEND()      {goto checkend; checkend_return:;}
10995 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10996 #define PARSESUB()      {goto parsesub; parsesub_return:;}
10997 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10998 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10999 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
11000 static int
11001 readtoken1(int c, int syntax, char *eofmark, int striptabs)
11002 {
11003         /* NB: syntax parameter fits into smallint */
11004         /* c parameter is an unsigned char or PEOF or PEOA */
11005         char *out;
11006         int len;
11007         char line[EOFMARKLEN + 1];
11008         struct nodelist *bqlist;
11009         smallint quotef;
11010         smallint dblquote;
11011         smallint oldstyle;
11012         smallint prevsyntax; /* syntax before arithmetic */
11013 #if ENABLE_ASH_EXPAND_PRMT
11014         smallint pssyntax;   /* we are expanding a prompt string */
11015 #endif
11016         int varnest;         /* levels of variables expansion */
11017         int arinest;         /* levels of arithmetic expansion */
11018         int parenlevel;      /* levels of parens in arithmetic */
11019         int dqvarnest;       /* levels of variables expansion within double quotes */
11020
11021         IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
11022
11023 #if __GNUC__
11024         /* Avoid longjmp clobbering */
11025         (void) &out;
11026         (void) &quotef;
11027         (void) &dblquote;
11028         (void) &varnest;
11029         (void) &arinest;
11030         (void) &parenlevel;
11031         (void) &dqvarnest;
11032         (void) &oldstyle;
11033         (void) &prevsyntax;
11034         (void) &syntax;
11035 #endif
11036         startlinno = g_parsefile->linno;
11037         bqlist = NULL;
11038         quotef = 0;
11039         oldstyle = 0;
11040         prevsyntax = 0;
11041 #if ENABLE_ASH_EXPAND_PRMT
11042         pssyntax = (syntax == PSSYNTAX);
11043         if (pssyntax)
11044                 syntax = DQSYNTAX;
11045 #endif
11046         dblquote = (syntax == DQSYNTAX);
11047         varnest = 0;
11048         arinest = 0;
11049         parenlevel = 0;
11050         dqvarnest = 0;
11051
11052         STARTSTACKSTR(out);
11053  loop:
11054         /* For each line, until end of word */
11055         {
11056                 CHECKEND();     /* set c to PEOF if at end of here document */
11057                 for (;;) {      /* until end of line or end of word */
11058                         CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
11059                         switch (SIT(c, syntax)) {
11060                         case CNL:       /* '\n' */
11061                                 if (syntax == BASESYNTAX)
11062                                         goto endword;   /* exit outer loop */
11063                                 USTPUTC(c, out);
11064                                 g_parsefile->linno++;
11065                                 if (doprompt)
11066                                         setprompt(2);
11067                                 c = pgetc();
11068                                 goto loop;              /* continue outer loop */
11069                         case CWORD:
11070                                 USTPUTC(c, out);
11071                                 break;
11072                         case CCTL:
11073                                 if (eofmark == NULL || dblquote)
11074                                         USTPUTC(CTLESC, out);
11075 #if ENABLE_ASH_BASH_COMPAT
11076                                 if (c == '\\' && bash_dollar_squote) {
11077                                         c = decode_dollar_squote();
11078                                         if (c & 0x100) {
11079                                                 USTPUTC('\\', out);
11080                                                 c = (unsigned char)c;
11081                                         }
11082                                 }
11083 #endif
11084                                 USTPUTC(c, out);
11085                                 break;
11086                         case CBACK:     /* backslash */
11087                                 c = pgetc_without_PEOA();
11088                                 if (c == PEOF) {
11089                                         USTPUTC(CTLESC, out);
11090                                         USTPUTC('\\', out);
11091                                         pungetc();
11092                                 } else if (c == '\n') {
11093                                         if (doprompt)
11094                                                 setprompt(2);
11095                                 } else {
11096 #if ENABLE_ASH_EXPAND_PRMT
11097                                         if (c == '$' && pssyntax) {
11098                                                 USTPUTC(CTLESC, out);
11099                                                 USTPUTC('\\', out);
11100                                         }
11101 #endif
11102                                         /* Backslash is retained if we are in "str" and next char isn't special */
11103                                         if (dblquote
11104                                          && c != '\\'
11105                                          && c != '`'
11106                                          && c != '$'
11107                                          && (c != '"' || eofmark != NULL)
11108                                         ) {
11109                                                 USTPUTC(CTLESC, out);
11110                                                 USTPUTC('\\', out);
11111                                         }
11112                                         if (SIT(c, SQSYNTAX) == CCTL)
11113                                                 USTPUTC(CTLESC, out);
11114                                         USTPUTC(c, out);
11115                                         quotef = 1;
11116                                 }
11117                                 break;
11118                         case CSQUOTE:
11119                                 syntax = SQSYNTAX;
11120  quotemark:
11121                                 if (eofmark == NULL) {
11122                                         USTPUTC(CTLQUOTEMARK, out);
11123                                 }
11124                                 break;
11125                         case CDQUOTE:
11126                                 syntax = DQSYNTAX;
11127                                 dblquote = 1;
11128                                 goto quotemark;
11129                         case CENDQUOTE:
11130                                 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11131                                 if (eofmark != NULL && arinest == 0
11132                                  && varnest == 0
11133                                 ) {
11134                                         USTPUTC(c, out);
11135                                 } else {
11136                                         if (dqvarnest == 0) {
11137                                                 syntax = BASESYNTAX;
11138                                                 dblquote = 0;
11139                                         }
11140                                         quotef = 1;
11141                                         goto quotemark;
11142                                 }
11143                                 break;
11144                         case CVAR:      /* '$' */
11145                                 PARSESUB();             /* parse substitution */
11146                                 break;
11147                         case CENDVAR:   /* '}' */
11148                                 if (varnest > 0) {
11149                                         varnest--;
11150                                         if (dqvarnest > 0) {
11151                                                 dqvarnest--;
11152                                         }
11153                                         c = CTLENDVAR;
11154                                 }
11155                                 USTPUTC(c, out);
11156                                 break;
11157 #if ENABLE_SH_MATH_SUPPORT
11158                         case CLP:       /* '(' in arithmetic */
11159                                 parenlevel++;
11160                                 USTPUTC(c, out);
11161                                 break;
11162                         case CRP:       /* ')' in arithmetic */
11163                                 if (parenlevel > 0) {
11164                                         parenlevel--;
11165                                 } else {
11166                                         if (pgetc() == ')') {
11167                                                 if (--arinest == 0) {
11168                                                         syntax = prevsyntax;
11169                                                         dblquote = (syntax == DQSYNTAX);
11170                                                         c = CTLENDARI;
11171                                                 }
11172                                         } else {
11173                                                 /*
11174                                                  * unbalanced parens
11175                                                  * (don't 2nd guess - no error)
11176                                                  */
11177                                                 pungetc();
11178                                         }
11179                                 }
11180                                 USTPUTC(c, out);
11181                                 break;
11182 #endif
11183                         case CBQUOTE:   /* '`' */
11184                                 PARSEBACKQOLD();
11185                                 break;
11186                         case CENDFILE:
11187                                 goto endword;           /* exit outer loop */
11188                         case CIGN:
11189                                 break;
11190                         default:
11191                                 if (varnest == 0) {
11192 #if ENABLE_ASH_BASH_COMPAT
11193                                         if (c == '&') {
11194                                                 if (pgetc() == '>')
11195                                                         c = 0x100 + '>'; /* flag &> */
11196                                                 pungetc();
11197                                         }
11198 #endif
11199                                         goto endword;   /* exit outer loop */
11200                                 }
11201                                 IF_ASH_ALIAS(if (c != PEOA))
11202                                         USTPUTC(c, out);
11203                         }
11204                         c = pgetc_fast();
11205                 } /* for (;;) */
11206         }
11207  endword:
11208 #if ENABLE_SH_MATH_SUPPORT
11209         if (syntax == ARISYNTAX)
11210                 raise_error_syntax("missing '))'");
11211 #endif
11212         if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
11213                 raise_error_syntax("unterminated quoted string");
11214         if (varnest != 0) {
11215                 startlinno = g_parsefile->linno;
11216                 /* { */
11217                 raise_error_syntax("missing '}'");
11218         }
11219         USTPUTC('\0', out);
11220         len = out - (char *)stackblock();
11221         out = stackblock();
11222         if (eofmark == NULL) {
11223                 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
11224                  && quotef == 0
11225                 ) {
11226                         if (isdigit_str9(out)) {
11227                                 PARSEREDIR(); /* passed as params: out, c */
11228                                 lasttoken = TREDIR;
11229                                 return lasttoken;
11230                         }
11231                         /* else: non-number X seen, interpret it
11232                          * as "NNNX>file" = "NNNX >file" */
11233                 }
11234                 pungetc();
11235         }
11236         quoteflag = quotef;
11237         backquotelist = bqlist;
11238         grabstackblock(len);
11239         wordtext = out;
11240         lasttoken = TWORD;
11241         return lasttoken;
11242 /* end of readtoken routine */
11243
11244 /*
11245  * Check to see whether we are at the end of the here document.  When this
11246  * is called, c is set to the first character of the next input line.  If
11247  * we are at the end of the here document, this routine sets the c to PEOF.
11248  */
11249 checkend: {
11250         if (eofmark) {
11251 #if ENABLE_ASH_ALIAS
11252                 if (c == PEOA)
11253                         c = pgetc_without_PEOA();
11254 #endif
11255                 if (striptabs) {
11256                         while (c == '\t') {
11257                                 c = pgetc_without_PEOA();
11258                         }
11259                 }
11260                 if (c == *eofmark) {
11261                         if (pfgets(line, sizeof(line)) != NULL) {
11262                                 char *p, *q;
11263
11264                                 p = line;
11265                                 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11266                                         continue;
11267                                 if (*p == '\n' && *q == '\0') {
11268                                         c = PEOF;
11269                                         g_parsefile->linno++;
11270                                         needprompt = doprompt;
11271                                 } else {
11272                                         pushstring(line, NULL);
11273                                 }
11274                         }
11275                 }
11276         }
11277         goto checkend_return;
11278 }
11279
11280 /*
11281  * Parse a redirection operator.  The variable "out" points to a string
11282  * specifying the fd to be redirected.  The variable "c" contains the
11283  * first character of the redirection operator.
11284  */
11285 parseredir: {
11286         /* out is already checked to be a valid number or "" */
11287         int fd = (*out == '\0' ? -1 : atoi(out));
11288         union node *np;
11289
11290         np = stzalloc(sizeof(struct nfile));
11291         if (c == '>') {
11292                 np->nfile.fd = 1;
11293                 c = pgetc();
11294                 if (c == '>')
11295                         np->type = NAPPEND;
11296                 else if (c == '|')
11297                         np->type = NCLOBBER;
11298                 else if (c == '&')
11299                         np->type = NTOFD;
11300                         /* it also can be NTO2 (>&file), but we can't figure it out yet */
11301                 else {
11302                         np->type = NTO;
11303                         pungetc();
11304                 }
11305         }
11306 #if ENABLE_ASH_BASH_COMPAT
11307         else if (c == 0x100 + '>') { /* this flags &> redirection */
11308                 np->nfile.fd = 1;
11309                 pgetc(); /* this is '>', no need to check */
11310                 np->type = NTO2;
11311         }
11312 #endif
11313         else { /* c == '<' */
11314                 /*np->nfile.fd = 0; - stzalloc did it */
11315                 c = pgetc();
11316                 switch (c) {
11317                 case '<':
11318                         if (sizeof(struct nfile) != sizeof(struct nhere)) {
11319                                 np = stzalloc(sizeof(struct nhere));
11320                                 /*np->nfile.fd = 0; - stzalloc did it */
11321                         }
11322                         np->type = NHERE;
11323                         heredoc = stzalloc(sizeof(struct heredoc));
11324                         heredoc->here = np;
11325                         c = pgetc();
11326                         if (c == '-') {
11327                                 heredoc->striptabs = 1;
11328                         } else {
11329                                 /*heredoc->striptabs = 0; - stzalloc did it */
11330                                 pungetc();
11331                         }
11332                         break;
11333
11334                 case '&':
11335                         np->type = NFROMFD;
11336                         break;
11337
11338                 case '>':
11339                         np->type = NFROMTO;
11340                         break;
11341
11342                 default:
11343                         np->type = NFROM;
11344                         pungetc();
11345                         break;
11346                 }
11347         }
11348         if (fd >= 0)
11349                 np->nfile.fd = fd;
11350         redirnode = np;
11351         goto parseredir_return;
11352 }
11353
11354 /*
11355  * Parse a substitution.  At this point, we have read the dollar sign
11356  * and nothing else.
11357  */
11358
11359 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11360  * (assuming ascii char codes, as the original implementation did) */
11361 #define is_special(c) \
11362         (((unsigned)(c) - 33 < 32) \
11363                         && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11364 parsesub: {
11365         unsigned char subtype;
11366         int typeloc;
11367         int flags;
11368
11369         c = pgetc();
11370         if (c > 255 /* PEOA or PEOF */
11371          || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11372         ) {
11373 #if ENABLE_ASH_BASH_COMPAT
11374                 if (c == '\'')
11375                         bash_dollar_squote = 1;
11376                 else
11377 #endif
11378                         USTPUTC('$', out);
11379                 pungetc();
11380         } else if (c == '(') {
11381                 /* $(command) or $((arith)) */
11382                 if (pgetc() == '(') {
11383 #if ENABLE_SH_MATH_SUPPORT
11384                         PARSEARITH();
11385 #else
11386                         raise_error_syntax("you disabled math support for $((arith)) syntax");
11387 #endif
11388                 } else {
11389                         pungetc();
11390                         PARSEBACKQNEW();
11391                 }
11392         } else {
11393                 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
11394                 USTPUTC(CTLVAR, out);
11395                 typeloc = out - (char *)stackblock();
11396                 USTPUTC(VSNORMAL, out);
11397                 subtype = VSNORMAL;
11398                 if (c == '{') {
11399                         c = pgetc();
11400                         if (c == '#') {
11401                                 c = pgetc();
11402                                 if (c == '}')
11403                                         c = '#'; /* ${#} - same as $# */
11404                                 else
11405                                         subtype = VSLENGTH; /* ${#VAR} */
11406                         } else {
11407                                 subtype = 0;
11408                         }
11409                 }
11410                 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
11411                         /* $[{[#]]NAME[}] */
11412                         do {
11413                                 STPUTC(c, out);
11414                                 c = pgetc();
11415                         } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
11416                 } else if (isdigit(c)) {
11417                         /* $[{[#]]NUM[}] */
11418                         do {
11419                                 STPUTC(c, out);
11420                                 c = pgetc();
11421                         } while (isdigit(c));
11422                 } else if (is_special(c)) {
11423                         /* $[{[#]]<specialchar>[}] */
11424                         USTPUTC(c, out);
11425                         c = pgetc();
11426                 } else {
11427  badsub:
11428                         raise_error_syntax("bad substitution");
11429                 }
11430                 if (c != '}' && subtype == VSLENGTH) {
11431                         /* ${#VAR didn't end with } */
11432                         goto badsub;
11433                 }
11434
11435                 STPUTC('=', out);
11436                 flags = 0;
11437                 if (subtype == 0) {
11438                         /* ${VAR...} but not $VAR or ${#VAR} */
11439                         /* c == first char after VAR */
11440                         switch (c) {
11441                         case ':':
11442                                 c = pgetc();
11443 #if ENABLE_ASH_BASH_COMPAT
11444                                 if (c == ':' || c == '$' || isdigit(c)) {
11445                                         subtype = VSSUBSTR;
11446                                         pungetc();
11447                                         break; /* "goto do_pungetc" is bigger (!) */
11448                                 }
11449 #endif
11450                                 flags = VSNUL;
11451                                 /*FALLTHROUGH*/
11452                         default: {
11453                                 static const char types[] ALIGN1 = "}-+?=";
11454                                 const char *p = strchr(types, c);
11455                                 if (p == NULL)
11456                                         goto badsub;
11457                                 subtype = p - types + VSNORMAL;
11458                                 break;
11459                         }
11460                         case '%':
11461                         case '#': {
11462                                 int cc = c;
11463                                 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
11464                                 c = pgetc();
11465                                 if (c != cc)
11466                                         goto do_pungetc;
11467                                 subtype++;
11468                                 break;
11469                         }
11470 #if ENABLE_ASH_BASH_COMPAT
11471                         case '/':
11472                                 subtype = VSREPLACE;
11473                                 c = pgetc();
11474                                 if (c != '/')
11475                                         goto do_pungetc;
11476                                 subtype++; /* VSREPLACEALL */
11477                                 break;
11478 #endif
11479                         }
11480                 } else {
11481  do_pungetc:
11482                         pungetc();
11483                 }
11484                 if (dblquote || arinest)
11485                         flags |= VSQUOTE;
11486                 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
11487                 if (subtype != VSNORMAL) {
11488                         varnest++;
11489                         if (dblquote || arinest) {
11490                                 dqvarnest++;
11491                         }
11492                 }
11493         }
11494         goto parsesub_return;
11495 }
11496
11497 /*
11498  * Called to parse command substitutions.  Newstyle is set if the command
11499  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11500  * list of commands (passed by reference), and savelen is the number of
11501  * characters on the top of the stack which must be preserved.
11502  */
11503 parsebackq: {
11504         struct nodelist **nlpp;
11505         smallint savepbq;
11506         union node *n;
11507         char *volatile str;
11508         struct jmploc jmploc;
11509         struct jmploc *volatile savehandler;
11510         size_t savelen;
11511         smallint saveprompt = 0;
11512
11513 #ifdef __GNUC__
11514         (void) &saveprompt;
11515 #endif
11516         savepbq = parsebackquote;
11517         if (setjmp(jmploc.loc)) {
11518                 free(str);
11519                 parsebackquote = 0;
11520                 exception_handler = savehandler;
11521                 longjmp(exception_handler->loc, 1);
11522         }
11523         INT_OFF;
11524         str = NULL;
11525         savelen = out - (char *)stackblock();
11526         if (savelen > 0) {
11527                 str = ckmalloc(savelen);
11528                 memcpy(str, stackblock(), savelen);
11529         }
11530         savehandler = exception_handler;
11531         exception_handler = &jmploc;
11532         INT_ON;
11533         if (oldstyle) {
11534                 /* We must read until the closing backquote, giving special
11535                    treatment to some slashes, and then push the string and
11536                    reread it as input, interpreting it normally.  */
11537                 char *pout;
11538                 int pc;
11539                 size_t psavelen;
11540                 char *pstr;
11541
11542
11543                 STARTSTACKSTR(pout);
11544                 for (;;) {
11545                         if (needprompt) {
11546                                 setprompt(2);
11547                         }
11548                         pc = pgetc();
11549                         switch (pc) {
11550                         case '`':
11551                                 goto done;
11552
11553                         case '\\':
11554                                 pc = pgetc();
11555                                 if (pc == '\n') {
11556                                         g_parsefile->linno++;
11557                                         if (doprompt)
11558                                                 setprompt(2);
11559                                         /*
11560                                          * If eating a newline, avoid putting
11561                                          * the newline into the new character
11562                                          * stream (via the STPUTC after the
11563                                          * switch).
11564                                          */
11565                                         continue;
11566                                 }
11567                                 if (pc != '\\' && pc != '`' && pc != '$'
11568                                  && (!dblquote || pc != '"')
11569                                 ) {
11570                                         STPUTC('\\', pout);
11571                                 }
11572                                 if (pc <= 255 /* not PEOA or PEOF */) {
11573                                         break;
11574                                 }
11575                                 /* fall through */
11576
11577                         case PEOF:
11578                         IF_ASH_ALIAS(case PEOA:)
11579                                 startlinno = g_parsefile->linno;
11580                                 raise_error_syntax("EOF in backquote substitution");
11581
11582                         case '\n':
11583                                 g_parsefile->linno++;
11584                                 needprompt = doprompt;
11585                                 break;
11586
11587                         default:
11588                                 break;
11589                         }
11590                         STPUTC(pc, pout);
11591                 }
11592  done:
11593                 STPUTC('\0', pout);
11594                 psavelen = pout - (char *)stackblock();
11595                 if (psavelen > 0) {
11596                         pstr = grabstackstr(pout);
11597                         setinputstring(pstr);
11598                 }
11599         }
11600         nlpp = &bqlist;
11601         while (*nlpp)
11602                 nlpp = &(*nlpp)->next;
11603         *nlpp = stzalloc(sizeof(**nlpp));
11604         /* (*nlpp)->next = NULL; - stzalloc did it */
11605         parsebackquote = oldstyle;
11606
11607         if (oldstyle) {
11608                 saveprompt = doprompt;
11609                 doprompt = 0;
11610         }
11611
11612         n = list(2);
11613
11614         if (oldstyle)
11615                 doprompt = saveprompt;
11616         else if (readtoken() != TRP)
11617                 raise_error_unexpected_syntax(TRP);
11618
11619         (*nlpp)->n = n;
11620         if (oldstyle) {
11621                 /*
11622                  * Start reading from old file again, ignoring any pushed back
11623                  * tokens left from the backquote parsing
11624                  */
11625                 popfile();
11626                 tokpushback = 0;
11627         }
11628         while (stackblocksize() <= savelen)
11629                 growstackblock();
11630         STARTSTACKSTR(out);
11631         if (str) {
11632                 memcpy(out, str, savelen);
11633                 STADJUST(savelen, out);
11634                 INT_OFF;
11635                 free(str);
11636                 str = NULL;
11637                 INT_ON;
11638         }
11639         parsebackquote = savepbq;
11640         exception_handler = savehandler;
11641         if (arinest || dblquote)
11642                 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11643         else
11644                 USTPUTC(CTLBACKQ, out);
11645         if (oldstyle)
11646                 goto parsebackq_oldreturn;
11647         goto parsebackq_newreturn;
11648 }
11649
11650 #if ENABLE_SH_MATH_SUPPORT
11651 /*
11652  * Parse an arithmetic expansion (indicate start of one and set state)
11653  */
11654 parsearith: {
11655         if (++arinest == 1) {
11656                 prevsyntax = syntax;
11657                 syntax = ARISYNTAX;
11658                 USTPUTC(CTLARI, out);
11659                 if (dblquote)
11660                         USTPUTC('"', out);
11661                 else
11662                         USTPUTC(' ', out);
11663         } else {
11664                 /*
11665                  * we collapse embedded arithmetic expansion to
11666                  * parenthesis, which should be equivalent
11667                  */
11668                 USTPUTC('(', out);
11669         }
11670         goto parsearith_return;
11671 }
11672 #endif
11673
11674 } /* end of readtoken */
11675
11676 /*
11677  * Read the next input token.
11678  * If the token is a word, we set backquotelist to the list of cmds in
11679  *      backquotes.  We set quoteflag to true if any part of the word was
11680  *      quoted.
11681  * If the token is TREDIR, then we set redirnode to a structure containing
11682  *      the redirection.
11683  * In all cases, the variable startlinno is set to the number of the line
11684  *      on which the token starts.
11685  *
11686  * [Change comment:  here documents and internal procedures]
11687  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
11688  *  word parsing code into a separate routine.  In this case, readtoken
11689  *  doesn't need to have any internal procedures, but parseword does.
11690  *  We could also make parseoperator in essence the main routine, and
11691  *  have parseword (readtoken1?) handle both words and redirection.]
11692  */
11693 #define NEW_xxreadtoken
11694 #ifdef NEW_xxreadtoken
11695 /* singles must be first! */
11696 static const char xxreadtoken_chars[7] ALIGN1 = {
11697         '\n', '(', ')', /* singles */
11698         '&', '|', ';',  /* doubles */
11699         0
11700 };
11701
11702 #define xxreadtoken_singles 3
11703 #define xxreadtoken_doubles 3
11704
11705 static const char xxreadtoken_tokens[] ALIGN1 = {
11706         TNL, TLP, TRP,          /* only single occurrence allowed */
11707         TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11708         TEOF,                   /* corresponds to trailing nul */
11709         TAND, TOR, TENDCASE     /* if double occurrence */
11710 };
11711
11712 static int
11713 xxreadtoken(void)
11714 {
11715         int c;
11716
11717         if (tokpushback) {
11718                 tokpushback = 0;
11719                 return lasttoken;
11720         }
11721         if (needprompt) {
11722                 setprompt(2);
11723         }
11724         startlinno = g_parsefile->linno;
11725         for (;;) {                      /* until token or start of word found */
11726                 c = pgetc_fast();
11727                 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
11728                         continue;
11729
11730                 if (c == '#') {
11731                         while ((c = pgetc()) != '\n' && c != PEOF)
11732                                 continue;
11733                         pungetc();
11734                 } else if (c == '\\') {
11735                         if (pgetc() != '\n') {
11736                                 pungetc();
11737                                 break; /* return readtoken1(...) */
11738                         }
11739                         startlinno = ++g_parsefile->linno;
11740                         if (doprompt)
11741                                 setprompt(2);
11742                 } else {
11743                         const char *p;
11744
11745                         p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11746                         if (c != PEOF) {
11747                                 if (c == '\n') {
11748                                         g_parsefile->linno++;
11749                                         needprompt = doprompt;
11750                                 }
11751
11752                                 p = strchr(xxreadtoken_chars, c);
11753                                 if (p == NULL)
11754                                         break; /* return readtoken1(...) */
11755
11756                                 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11757                                         int cc = pgetc();
11758                                         if (cc == c) {    /* double occurrence? */
11759                                                 p += xxreadtoken_doubles + 1;
11760                                         } else {
11761                                                 pungetc();
11762 #if ENABLE_ASH_BASH_COMPAT
11763                                                 if (c == '&' && cc == '>') /* &> */
11764                                                         break; /* return readtoken1(...) */
11765 #endif
11766                                         }
11767                                 }
11768                         }
11769                         lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11770                         return lasttoken;
11771                 }
11772         } /* for (;;) */
11773
11774         return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11775 }
11776 #else /* old xxreadtoken */
11777 #define RETURN(token)   return lasttoken = token
11778 static int
11779 xxreadtoken(void)
11780 {
11781         int c;
11782
11783         if (tokpushback) {
11784                 tokpushback = 0;
11785                 return lasttoken;
11786         }
11787         if (needprompt) {
11788                 setprompt(2);
11789         }
11790         startlinno = g_parsefile->linno;
11791         for (;;) {      /* until token or start of word found */
11792                 c = pgetc_fast();
11793                 switch (c) {
11794                 case ' ': case '\t':
11795                 IF_ASH_ALIAS(case PEOA:)
11796                         continue;
11797                 case '#':
11798                         while ((c = pgetc()) != '\n' && c != PEOF)
11799                                 continue;
11800                         pungetc();
11801                         continue;
11802                 case '\\':
11803                         if (pgetc() == '\n') {
11804                                 startlinno = ++g_parsefile->linno;
11805                                 if (doprompt)
11806                                         setprompt(2);
11807                                 continue;
11808                         }
11809                         pungetc();
11810                         goto breakloop;
11811                 case '\n':
11812                         g_parsefile->linno++;
11813                         needprompt = doprompt;
11814                         RETURN(TNL);
11815                 case PEOF:
11816                         RETURN(TEOF);
11817                 case '&':
11818                         if (pgetc() == '&')
11819                                 RETURN(TAND);
11820                         pungetc();
11821                         RETURN(TBACKGND);
11822                 case '|':
11823                         if (pgetc() == '|')
11824                                 RETURN(TOR);
11825                         pungetc();
11826                         RETURN(TPIPE);
11827                 case ';':
11828                         if (pgetc() == ';')
11829                                 RETURN(TENDCASE);
11830                         pungetc();
11831                         RETURN(TSEMI);
11832                 case '(':
11833                         RETURN(TLP);
11834                 case ')':
11835                         RETURN(TRP);
11836                 default:
11837                         goto breakloop;
11838                 }
11839         }
11840  breakloop:
11841         return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11842 #undef RETURN
11843 }
11844 #endif /* old xxreadtoken */
11845
11846 static int
11847 readtoken(void)
11848 {
11849         int t;
11850 #if DEBUG
11851         smallint alreadyseen = tokpushback;
11852 #endif
11853
11854 #if ENABLE_ASH_ALIAS
11855  top:
11856 #endif
11857
11858         t = xxreadtoken();
11859
11860         /*
11861          * eat newlines
11862          */
11863         if (checkkwd & CHKNL) {
11864                 while (t == TNL) {
11865                         parseheredoc();
11866                         t = xxreadtoken();
11867                 }
11868         }
11869
11870         if (t != TWORD || quoteflag) {
11871                 goto out;
11872         }
11873
11874         /*
11875          * check for keywords
11876          */
11877         if (checkkwd & CHKKWD) {
11878                 const char *const *pp;
11879
11880                 pp = findkwd(wordtext);
11881                 if (pp) {
11882                         lasttoken = t = pp - tokname_array;
11883                         TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
11884                         goto out;
11885                 }
11886         }
11887
11888         if (checkkwd & CHKALIAS) {
11889 #if ENABLE_ASH_ALIAS
11890                 struct alias *ap;
11891                 ap = lookupalias(wordtext, 1);
11892                 if (ap != NULL) {
11893                         if (*ap->val) {
11894                                 pushstring(ap->val, ap);
11895                         }
11896                         goto top;
11897                 }
11898 #endif
11899         }
11900  out:
11901         checkkwd = 0;
11902 #if DEBUG
11903         if (!alreadyseen)
11904                 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
11905         else
11906                 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
11907 #endif
11908         return t;
11909 }
11910
11911 static char
11912 peektoken(void)
11913 {
11914         int t;
11915
11916         t = readtoken();
11917         tokpushback = 1;
11918         return tokname_array[t][0];
11919 }
11920
11921 /*
11922  * Read and parse a command.  Returns NODE_EOF on end of file.
11923  * (NULL is a valid parse tree indicating a blank line.)
11924  */
11925 static union node *
11926 parsecmd(int interact)
11927 {
11928         int t;
11929
11930         tokpushback = 0;
11931         doprompt = interact;
11932         if (doprompt)
11933                 setprompt(doprompt);
11934         needprompt = 0;
11935         t = readtoken();
11936         if (t == TEOF)
11937                 return NODE_EOF;
11938         if (t == TNL)
11939                 return NULL;
11940         tokpushback = 1;
11941         return list(1);
11942 }
11943
11944 /*
11945  * Input any here documents.
11946  */
11947 static void
11948 parseheredoc(void)
11949 {
11950         struct heredoc *here;
11951         union node *n;
11952
11953         here = heredoclist;
11954         heredoclist = NULL;
11955
11956         while (here) {
11957                 if (needprompt) {
11958                         setprompt(2);
11959                 }
11960                 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11961                                 here->eofmark, here->striptabs);
11962                 n = stzalloc(sizeof(struct narg));
11963                 n->narg.type = NARG;
11964                 /*n->narg.next = NULL; - stzalloc did it */
11965                 n->narg.text = wordtext;
11966                 n->narg.backquote = backquotelist;
11967                 here->here->nhere.doc = n;
11968                 here = here->next;
11969         }
11970 }
11971
11972
11973 /*
11974  * called by editline -- any expansions to the prompt should be added here.
11975  */
11976 #if ENABLE_ASH_EXPAND_PRMT
11977 static const char *
11978 expandstr(const char *ps)
11979 {
11980         union node n;
11981
11982         /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
11983          * and token processing _can_ alter it (delete NULs etc). */
11984         setinputstring((char *)ps);
11985         readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11986         popfile();
11987
11988         n.narg.type = NARG;
11989         n.narg.next = NULL;
11990         n.narg.text = wordtext;
11991         n.narg.backquote = backquotelist;
11992
11993         expandarg(&n, NULL, 0);
11994         return stackblock();
11995 }
11996 #endif
11997
11998 /*
11999  * Execute a command or commands contained in a string.
12000  */
12001 static int
12002 evalstring(char *s, int mask)
12003 {
12004         union node *n;
12005         struct stackmark smark;
12006         int skip;
12007
12008         setinputstring(s);
12009         setstackmark(&smark);
12010
12011         skip = 0;
12012         while ((n = parsecmd(0)) != NODE_EOF) {
12013                 evaltree(n, 0);
12014                 popstackmark(&smark);
12015                 skip = evalskip;
12016                 if (skip)
12017                         break;
12018         }
12019         popfile();
12020
12021         skip &= mask;
12022         evalskip = skip;
12023         return skip;
12024 }
12025
12026 /*
12027  * The eval command.
12028  */
12029 static int FAST_FUNC
12030 evalcmd(int argc UNUSED_PARAM, char **argv)
12031 {
12032         char *p;
12033         char *concat;
12034
12035         if (argv[1]) {
12036                 p = argv[1];
12037                 argv += 2;
12038                 if (argv[0]) {
12039                         STARTSTACKSTR(concat);
12040                         for (;;) {
12041                                 concat = stack_putstr(p, concat);
12042                                 p = *argv++;
12043                                 if (p == NULL)
12044                                         break;
12045                                 STPUTC(' ', concat);
12046                         }
12047                         STPUTC('\0', concat);
12048                         p = grabstackstr(concat);
12049                 }
12050                 evalstring(p, ~SKIPEVAL);
12051         }
12052         return exitstatus;
12053 }
12054
12055 /*
12056  * Read and execute commands.
12057  * "Top" is nonzero for the top level command loop;
12058  * it turns on prompting if the shell is interactive.
12059  */
12060 static int
12061 cmdloop(int top)
12062 {
12063         union node *n;
12064         struct stackmark smark;
12065         int inter;
12066         int numeof = 0;
12067
12068         TRACE(("cmdloop(%d) called\n", top));
12069         for (;;) {
12070                 int skip;
12071
12072                 setstackmark(&smark);
12073 #if JOBS
12074                 if (doing_jobctl)
12075                         showjobs(stderr, SHOW_CHANGED);
12076 #endif
12077                 inter = 0;
12078                 if (iflag && top) {
12079                         inter++;
12080 #if ENABLE_ASH_MAIL
12081                         chkmail();
12082 #endif
12083                 }
12084                 n = parsecmd(inter);
12085 #if DEBUG
12086                 if (DEBUG > 2 && debug && (n != NODE_EOF))
12087                         showtree(n);
12088 #endif
12089                 if (n == NODE_EOF) {
12090                         if (!top || numeof >= 50)
12091                                 break;
12092                         if (!stoppedjobs()) {
12093                                 if (!Iflag)
12094                                         break;
12095                                 out2str("\nUse \"exit\" to leave shell.\n");
12096                         }
12097                         numeof++;
12098                 } else if (nflag == 0) {
12099                         /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12100                         job_warning >>= 1;
12101                         numeof = 0;
12102                         evaltree(n, 0);
12103                 }
12104                 popstackmark(&smark);
12105                 skip = evalskip;
12106
12107                 if (skip) {
12108                         evalskip = 0;
12109                         return skip & SKIPEVAL;
12110                 }
12111         }
12112         return 0;
12113 }
12114
12115 /*
12116  * Take commands from a file.  To be compatible we should do a path
12117  * search for the file, which is necessary to find sub-commands.
12118  */
12119 static char *
12120 find_dot_file(char *name)
12121 {
12122         char *fullname;
12123         const char *path = pathval();
12124         struct stat statb;
12125
12126         /* don't try this for absolute or relative paths */
12127         if (strchr(name, '/'))
12128                 return name;
12129
12130         /* IIRC standards do not say whether . is to be searched.
12131          * And it is even smaller this way, making it unconditional for now:
12132          */
12133         if (1) { /* ENABLE_ASH_BASH_COMPAT */
12134                 fullname = name;
12135                 goto try_cur_dir;
12136         }
12137
12138         while ((fullname = path_advance(&path, name)) != NULL) {
12139  try_cur_dir:
12140                 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12141                         /*
12142                          * Don't bother freeing here, since it will
12143                          * be freed by the caller.
12144                          */
12145                         return fullname;
12146                 }
12147                 if (fullname != name)
12148                         stunalloc(fullname);
12149         }
12150
12151         /* not found in the PATH */
12152         ash_msg_and_raise_error("%s: not found", name);
12153         /* NOTREACHED */
12154 }
12155
12156 static int FAST_FUNC
12157 dotcmd(int argc, char **argv)
12158 {
12159         char *fullname;
12160         struct strlist *sp;
12161         volatile struct shparam saveparam;
12162
12163         for (sp = cmdenviron; sp; sp = sp->next)
12164                 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
12165
12166         if (!argv[1]) {
12167                 /* bash says: "bash: .: filename argument required" */
12168                 return 2; /* bash compat */
12169         }
12170
12171         /* "false; . empty_file; echo $?" should print 0, not 1: */
12172         exitstatus = 0;
12173
12174         fullname = find_dot_file(argv[1]);
12175
12176         argv += 2;
12177         argc -= 2;
12178         if (argc) { /* argc > 0, argv[0] != NULL */
12179                 saveparam = shellparam;
12180                 shellparam.malloced = 0;
12181                 shellparam.nparam = argc;
12182                 shellparam.p = argv;
12183         };
12184
12185         setinputfile(fullname, INPUT_PUSH_FILE);
12186         commandname = fullname;
12187         cmdloop(0);
12188         popfile();
12189
12190         if (argc) {
12191                 freeparam(&shellparam);
12192                 shellparam = saveparam;
12193         };
12194
12195         return exitstatus;
12196 }
12197
12198 static int FAST_FUNC
12199 exitcmd(int argc UNUSED_PARAM, char **argv)
12200 {
12201         if (stoppedjobs())
12202                 return 0;
12203         if (argv[1])
12204                 exitstatus = number(argv[1]);
12205         raise_exception(EXEXIT);
12206         /* NOTREACHED */
12207 }
12208
12209 /*
12210  * Read a file containing shell functions.
12211  */
12212 static void
12213 readcmdfile(char *name)
12214 {
12215         setinputfile(name, INPUT_PUSH_FILE);
12216         cmdloop(0);
12217         popfile();
12218 }
12219
12220
12221 /* ============ find_command inplementation */
12222
12223 /*
12224  * Resolve a command name.  If you change this routine, you may have to
12225  * change the shellexec routine as well.
12226  */
12227 static void
12228 find_command(char *name, struct cmdentry *entry, int act, const char *path)
12229 {
12230         struct tblentry *cmdp;
12231         int idx;
12232         int prev;
12233         char *fullname;
12234         struct stat statb;
12235         int e;
12236         int updatetbl;
12237         struct builtincmd *bcmd;
12238
12239         /* If name contains a slash, don't use PATH or hash table */
12240         if (strchr(name, '/') != NULL) {
12241                 entry->u.index = -1;
12242                 if (act & DO_ABS) {
12243                         while (stat(name, &statb) < 0) {
12244 #ifdef SYSV
12245                                 if (errno == EINTR)
12246                                         continue;
12247 #endif
12248                                 entry->cmdtype = CMDUNKNOWN;
12249                                 return;
12250                         }
12251                 }
12252                 entry->cmdtype = CMDNORMAL;
12253                 return;
12254         }
12255
12256 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12257
12258         updatetbl = (path == pathval());
12259         if (!updatetbl) {
12260                 act |= DO_ALTPATH;
12261                 if (strstr(path, "%builtin") != NULL)
12262                         act |= DO_ALTBLTIN;
12263         }
12264
12265         /* If name is in the table, check answer will be ok */
12266         cmdp = cmdlookup(name, 0);
12267         if (cmdp != NULL) {
12268                 int bit;
12269
12270                 switch (cmdp->cmdtype) {
12271                 default:
12272 #if DEBUG
12273                         abort();
12274 #endif
12275                 case CMDNORMAL:
12276                         bit = DO_ALTPATH;
12277                         break;
12278                 case CMDFUNCTION:
12279                         bit = DO_NOFUNC;
12280                         break;
12281                 case CMDBUILTIN:
12282                         bit = DO_ALTBLTIN;
12283                         break;
12284                 }
12285                 if (act & bit) {
12286                         updatetbl = 0;
12287                         cmdp = NULL;
12288                 } else if (cmdp->rehash == 0)
12289                         /* if not invalidated by cd, we're done */
12290                         goto success;
12291         }
12292
12293         /* If %builtin not in path, check for builtin next */
12294         bcmd = find_builtin(name);
12295         if (bcmd) {
12296                 if (IS_BUILTIN_REGULAR(bcmd))
12297                         goto builtin_success;
12298                 if (act & DO_ALTPATH) {
12299                         if (!(act & DO_ALTBLTIN))
12300                                 goto builtin_success;
12301                 } else if (builtinloc <= 0) {
12302                         goto builtin_success;
12303                 }
12304         }
12305
12306 #if ENABLE_FEATURE_SH_STANDALONE
12307         {
12308                 int applet_no = find_applet_by_name(name);
12309                 if (applet_no >= 0) {
12310                         entry->cmdtype = CMDNORMAL;
12311                         entry->u.index = -2 - applet_no;
12312                         return;
12313                 }
12314         }
12315 #endif
12316
12317         /* We have to search path. */
12318         prev = -1;              /* where to start */
12319         if (cmdp && cmdp->rehash) {     /* doing a rehash */
12320                 if (cmdp->cmdtype == CMDBUILTIN)
12321                         prev = builtinloc;
12322                 else
12323                         prev = cmdp->param.index;
12324         }
12325
12326         e = ENOENT;
12327         idx = -1;
12328  loop:
12329         while ((fullname = path_advance(&path, name)) != NULL) {
12330                 stunalloc(fullname);
12331                 /* NB: code below will still use fullname
12332                  * despite it being "unallocated" */
12333                 idx++;
12334                 if (pathopt) {
12335                         if (prefix(pathopt, "builtin")) {
12336                                 if (bcmd)
12337                                         goto builtin_success;
12338                                 continue;
12339                         }
12340                         if ((act & DO_NOFUNC)
12341                          || !prefix(pathopt, "func")
12342                         ) {     /* ignore unimplemented options */
12343                                 continue;
12344                         }
12345                 }
12346                 /* if rehash, don't redo absolute path names */
12347                 if (fullname[0] == '/' && idx <= prev) {
12348                         if (idx < prev)
12349                                 continue;
12350                         TRACE(("searchexec \"%s\": no change\n", name));
12351                         goto success;
12352                 }
12353                 while (stat(fullname, &statb) < 0) {
12354 #ifdef SYSV
12355                         if (errno == EINTR)
12356                                 continue;
12357 #endif
12358                         if (errno != ENOENT && errno != ENOTDIR)
12359                                 e = errno;
12360                         goto loop;
12361                 }
12362                 e = EACCES;     /* if we fail, this will be the error */
12363                 if (!S_ISREG(statb.st_mode))
12364                         continue;
12365                 if (pathopt) {          /* this is a %func directory */
12366                         stalloc(strlen(fullname) + 1);
12367                         /* NB: stalloc will return space pointed by fullname
12368                          * (because we don't have any intervening allocations
12369                          * between stunalloc above and this stalloc) */
12370                         readcmdfile(fullname);
12371                         cmdp = cmdlookup(name, 0);
12372                         if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12373                                 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12374                         stunalloc(fullname);
12375                         goto success;
12376                 }
12377                 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12378                 if (!updatetbl) {
12379                         entry->cmdtype = CMDNORMAL;
12380                         entry->u.index = idx;
12381                         return;
12382                 }
12383                 INT_OFF;
12384                 cmdp = cmdlookup(name, 1);
12385                 cmdp->cmdtype = CMDNORMAL;
12386                 cmdp->param.index = idx;
12387                 INT_ON;
12388                 goto success;
12389         }
12390
12391         /* We failed.  If there was an entry for this command, delete it */
12392         if (cmdp && updatetbl)
12393                 delete_cmd_entry();
12394         if (act & DO_ERR)
12395                 ash_msg("%s: %s", name, errmsg(e, "not found"));
12396         entry->cmdtype = CMDUNKNOWN;
12397         return;
12398
12399  builtin_success:
12400         if (!updatetbl) {
12401                 entry->cmdtype = CMDBUILTIN;
12402                 entry->u.cmd = bcmd;
12403                 return;
12404         }
12405         INT_OFF;
12406         cmdp = cmdlookup(name, 1);
12407         cmdp->cmdtype = CMDBUILTIN;
12408         cmdp->param.cmd = bcmd;
12409         INT_ON;
12410  success:
12411         cmdp->rehash = 0;
12412         entry->cmdtype = cmdp->cmdtype;
12413         entry->u = cmdp->param;
12414 }
12415
12416
12417 /* ============ trap.c */
12418
12419 /*
12420  * The trap builtin.
12421  */
12422 static int FAST_FUNC
12423 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12424 {
12425         char *action;
12426         char **ap;
12427         int signo, exitcode;
12428
12429         nextopt(nullstr);
12430         ap = argptr;
12431         if (!*ap) {
12432                 for (signo = 0; signo < NSIG; signo++) {
12433                         char *tr = trap_ptr[signo];
12434                         if (tr) {
12435                                 /* note: bash adds "SIG", but only if invoked
12436                                  * as "bash". If called as "sh", or if set -o posix,
12437                                  * then it prints short signal names.
12438                                  * We are printing short names: */
12439                                 out1fmt("trap -- %s %s\n",
12440                                                 single_quote(tr),
12441                                                 get_signame(signo));
12442                 /* trap_ptr != trap only if we are in special-cased `trap` code.
12443                  * In this case, we will exit very soon, no need to free(). */
12444                                 /* if (trap_ptr != trap && tp[0]) */
12445                                 /*      free(tr); */
12446                         }
12447                 }
12448                 /*
12449                 if (trap_ptr != trap) {
12450                         free(trap_ptr);
12451                         trap_ptr = trap;
12452                 }
12453                 */
12454                 return 0;
12455         }
12456
12457         action = NULL;
12458         if (ap[1])
12459                 action = *ap++;
12460         exitcode = 0;
12461         while (*ap) {
12462                 signo = get_signum(*ap);
12463                 if (signo < 0) {
12464                         /* Mimic bash message exactly */
12465                         ash_msg("%s: invalid signal specification", *ap);
12466                         exitcode = 1;
12467                         goto next;
12468                 }
12469                 INT_OFF;
12470                 if (action) {
12471                         if (LONE_DASH(action))
12472                                 action = NULL;
12473                         else
12474                                 action = ckstrdup(action);
12475                 }
12476                 free(trap[signo]);
12477                 if (action)
12478                         may_have_traps = 1;
12479                 trap[signo] = action;
12480                 if (signo != 0)
12481                         setsignal(signo);
12482                 INT_ON;
12483  next:
12484                 ap++;
12485         }
12486         return exitcode;
12487 }
12488
12489
12490 /* ============ Builtins */
12491
12492 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12493 /*
12494  * Lists available builtins
12495  */
12496 static int FAST_FUNC
12497 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12498 {
12499         unsigned col;
12500         unsigned i;
12501
12502         out1fmt(
12503                 "Built-in commands:\n"
12504                 "------------------\n");
12505         for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12506                 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12507                                         builtintab[i].name + 1);
12508                 if (col > 60) {
12509                         out1fmt("\n");
12510                         col = 0;
12511                 }
12512         }
12513 #if ENABLE_FEATURE_SH_STANDALONE
12514         {
12515                 const char *a = applet_names;
12516                 while (*a) {
12517                         col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12518                         if (col > 60) {
12519                                 out1fmt("\n");
12520                                 col = 0;
12521                         }
12522                         a += strlen(a) + 1;
12523                 }
12524         }
12525 #endif
12526         out1fmt("\n\n");
12527         return EXIT_SUCCESS;
12528 }
12529 #endif /* FEATURE_SH_EXTRA_QUIET */
12530
12531 /*
12532  * The export and readonly commands.
12533  */
12534 static int FAST_FUNC
12535 exportcmd(int argc UNUSED_PARAM, char **argv)
12536 {
12537         struct var *vp;
12538         char *name;
12539         const char *p;
12540         char **aptr;
12541         int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
12542
12543         if (nextopt("p") != 'p') {
12544                 aptr = argptr;
12545                 name = *aptr;
12546                 if (name) {
12547                         do {
12548                                 p = strchr(name, '=');
12549                                 if (p != NULL) {
12550                                         p++;
12551                                 } else {
12552                                         vp = *findvar(hashvar(name), name);
12553                                         if (vp) {
12554                                                 vp->flags |= flag;
12555                                                 continue;
12556                                         }
12557                                 }
12558                                 setvar(name, p, flag);
12559                         } while ((name = *++aptr) != NULL);
12560                         return 0;
12561                 }
12562         }
12563         showvars(argv[0], flag, 0);
12564         return 0;
12565 }
12566
12567 /*
12568  * Delete a function if it exists.
12569  */
12570 static void
12571 unsetfunc(const char *name)
12572 {
12573         struct tblentry *cmdp;
12574
12575         cmdp = cmdlookup(name, 0);
12576         if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
12577                 delete_cmd_entry();
12578 }
12579
12580 /*
12581  * The unset builtin command.  We unset the function before we unset the
12582  * variable to allow a function to be unset when there is a readonly variable
12583  * with the same name.
12584  */
12585 static int FAST_FUNC
12586 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12587 {
12588         char **ap;
12589         int i;
12590         int flag = 0;
12591         int ret = 0;
12592
12593         while ((i = nextopt("vf")) != 0) {
12594                 flag = i;
12595         }
12596
12597         for (ap = argptr; *ap; ap++) {
12598                 if (flag != 'f') {
12599                         i = unsetvar(*ap);
12600                         ret |= i;
12601                         if (!(i & 2))
12602                                 continue;
12603                 }
12604                 if (flag != 'v')
12605                         unsetfunc(*ap);
12606         }
12607         return ret & 1;
12608 }
12609
12610 static const unsigned char timescmd_str[] ALIGN1 = {
12611         ' ',  offsetof(struct tms, tms_utime),
12612         '\n', offsetof(struct tms, tms_stime),
12613         ' ',  offsetof(struct tms, tms_cutime),
12614         '\n', offsetof(struct tms, tms_cstime),
12615         0
12616 };
12617 static int FAST_FUNC
12618 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12619 {
12620         unsigned long clk_tck, s, t;
12621         const unsigned char *p;
12622         struct tms buf;
12623
12624         clk_tck = sysconf(_SC_CLK_TCK);
12625         times(&buf);
12626
12627         p = timescmd_str;
12628         do {
12629                 t = *(clock_t *)(((char *) &buf) + p[1]);
12630                 s = t / clk_tck;
12631                 t = t % clk_tck;
12632                 out1fmt("%lum%lu.%03lus%c",
12633                         s / 60, s % 60,
12634                         (t * 1000) / clk_tck,
12635                         p[0]);
12636                 p += 2;
12637         } while (*p);
12638
12639         return 0;
12640 }
12641
12642 #if ENABLE_SH_MATH_SUPPORT
12643 /*
12644  * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
12645  * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12646  *
12647  * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12648  */
12649 static int FAST_FUNC
12650 letcmd(int argc UNUSED_PARAM, char **argv)
12651 {
12652         arith_t i;
12653
12654         argv++;
12655         if (!*argv)
12656                 ash_msg_and_raise_error("expression expected");
12657         do {
12658                 i = ash_arith(*argv);
12659         } while (*++argv);
12660
12661         return !i;
12662 }
12663 #endif
12664
12665 /*
12666  * The read builtin. Options:
12667  *      -r              Do not interpret '\' specially
12668  *      -s              Turn off echo (tty only)
12669  *      -n NCHARS       Read NCHARS max
12670  *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
12671  *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
12672  *      -u FD           Read from given FD instead of fd 0
12673  * This uses unbuffered input, which may be avoidable in some cases.
12674  * TODO: bash also has:
12675  *      -a ARRAY        Read into array[0],[1],etc
12676  *      -d DELIM        End on DELIM char, not newline
12677  *      -e              Use line editing (tty only)
12678  */
12679 static int FAST_FUNC
12680 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12681 {
12682         char *opt_n = NULL;
12683         char *opt_p = NULL;
12684         char *opt_t = NULL;
12685         char *opt_u = NULL;
12686         int read_flags = 0;
12687         const char *r;
12688         int i;
12689
12690         while ((i = nextopt("p:u:rt:n:s")) != '\0') {
12691                 switch (i) {
12692                 case 'p':
12693                         opt_p = optionarg;
12694                         break;
12695                 case 'n':
12696                         opt_n = optionarg;
12697                         break;
12698                 case 's':
12699                         read_flags |= BUILTIN_READ_SILENT;
12700                         break;
12701                 case 't':
12702                         opt_t = optionarg;
12703                         break;
12704                 case 'r':
12705                         read_flags |= BUILTIN_READ_RAW;
12706                         break;
12707                 case 'u':
12708                         opt_u = optionarg;
12709                         break;
12710                 default:
12711                         break;
12712                 }
12713         }
12714
12715         r = shell_builtin_read(setvar2,
12716                 argptr,
12717                 bltinlookup("IFS"), /* can be NULL */
12718                 read_flags,
12719                 opt_n,
12720                 opt_p,
12721                 opt_t,
12722                 opt_u
12723         );
12724
12725         if ((uintptr_t)r > 1)
12726                 ash_msg_and_raise_error(r);
12727
12728         return (uintptr_t)r;
12729 }
12730
12731 static int FAST_FUNC
12732 umaskcmd(int argc UNUSED_PARAM, char **argv)
12733 {
12734         static const char permuser[3] ALIGN1 = "ugo";
12735         static const char permmode[3] ALIGN1 = "rwx";
12736         static const short permmask[] ALIGN2 = {
12737                 S_IRUSR, S_IWUSR, S_IXUSR,
12738                 S_IRGRP, S_IWGRP, S_IXGRP,
12739                 S_IROTH, S_IWOTH, S_IXOTH
12740         };
12741
12742         /* TODO: use bb_parse_mode() instead */
12743
12744         char *ap;
12745         mode_t mask;
12746         int i;
12747         int symbolic_mode = 0;
12748
12749         while (nextopt("S") != '\0') {
12750                 symbolic_mode = 1;
12751         }
12752
12753         INT_OFF;
12754         mask = umask(0);
12755         umask(mask);
12756         INT_ON;
12757
12758         ap = *argptr;
12759         if (ap == NULL) {
12760                 if (symbolic_mode) {
12761                         char buf[18];
12762                         char *p = buf;
12763
12764                         for (i = 0; i < 3; i++) {
12765                                 int j;
12766
12767                                 *p++ = permuser[i];
12768                                 *p++ = '=';
12769                                 for (j = 0; j < 3; j++) {
12770                                         if ((mask & permmask[3 * i + j]) == 0) {
12771                                                 *p++ = permmode[j];
12772                                         }
12773                                 }
12774                                 *p++ = ',';
12775                         }
12776                         *--p = 0;
12777                         puts(buf);
12778                 } else {
12779                         out1fmt("%.4o\n", mask);
12780                 }
12781         } else {
12782                 if (isdigit((unsigned char) *ap)) {
12783                         mask = 0;
12784                         do {
12785                                 if (*ap >= '8' || *ap < '0')
12786                                         ash_msg_and_raise_error(msg_illnum, argv[1]);
12787                                 mask = (mask << 3) + (*ap - '0');
12788                         } while (*++ap != '\0');
12789                         umask(mask);
12790                 } else {
12791                         mask = ~mask & 0777;
12792                         if (!bb_parse_mode(ap, &mask)) {
12793                                 ash_msg_and_raise_error("illegal mode: %s", ap);
12794                         }
12795                         umask(~mask & 0777);
12796                 }
12797         }
12798         return 0;
12799 }
12800
12801 static int FAST_FUNC
12802 ulimitcmd(int argc UNUSED_PARAM, char **argv)
12803 {
12804         return shell_builtin_ulimit(argv);
12805 }
12806
12807 /* ============ main() and helpers */
12808
12809 /*
12810  * Called to exit the shell.
12811  */
12812 static void exitshell(void) NORETURN;
12813 static void
12814 exitshell(void)
12815 {
12816         struct jmploc loc;
12817         char *p;
12818         int status;
12819
12820         status = exitstatus;
12821         TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12822         if (setjmp(loc.loc)) {
12823                 if (exception_type == EXEXIT)
12824 /* dash bug: it just does _exit(exitstatus) here
12825  * but we have to do setjobctl(0) first!
12826  * (bug is still not fixed in dash-0.5.3 - if you run dash
12827  * under Midnight Commander, on exit from dash MC is backgrounded) */
12828                         status = exitstatus;
12829                 goto out;
12830         }
12831         exception_handler = &loc;
12832         p = trap[0];
12833         if (p) {
12834                 trap[0] = NULL;
12835                 evalstring(p, 0);
12836                 free(p);
12837         }
12838         flush_stdout_stderr();
12839  out:
12840         setjobctl(0);
12841         _exit(status);
12842         /* NOTREACHED */
12843 }
12844
12845 static void
12846 init(void)
12847 {
12848         /* from input.c: */
12849         /* we will never free this */
12850         basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
12851
12852         /* from trap.c: */
12853         signal(SIGCHLD, SIG_DFL);
12854         /* bash re-enables SIGHUP which is SIG_IGNed on entry.
12855          * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
12856          */
12857         signal(SIGHUP, SIG_DFL);
12858
12859         /* from var.c: */
12860         {
12861                 char **envp;
12862                 const char *p;
12863                 struct stat st1, st2;
12864
12865                 initvar();
12866                 for (envp = environ; envp && *envp; envp++) {
12867                         if (strchr(*envp, '=')) {
12868                                 setvareq(*envp, VEXPORT|VTEXTFIXED);
12869                         }
12870                 }
12871
12872                 setvar("PPID", utoa(getppid()), 0);
12873
12874                 p = lookupvar("PWD");
12875                 if (p)
12876                         if (*p != '/' || stat(p, &st1) || stat(".", &st2)
12877                          || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
12878                                 p = '\0';
12879                 setpwd(p, 0);
12880         }
12881 }
12882
12883 /*
12884  * Process the shell command line arguments.
12885  */
12886 static void
12887 procargs(char **argv)
12888 {
12889         int i;
12890         const char *xminusc;
12891         char **xargv;
12892
12893         xargv = argv;
12894         arg0 = xargv[0];
12895         /* if (xargv[0]) - mmm, this is always true! */
12896                 xargv++;
12897         for (i = 0; i < NOPTS; i++)
12898                 optlist[i] = 2;
12899         argptr = xargv;
12900         if (options(1)) {
12901                 /* it already printed err message */
12902                 raise_exception(EXERROR);
12903         }
12904         xargv = argptr;
12905         xminusc = minusc;
12906         if (*xargv == NULL) {
12907                 if (xminusc)
12908                         ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
12909                 sflag = 1;
12910         }
12911         if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
12912                 iflag = 1;
12913         if (mflag == 2)
12914                 mflag = iflag;
12915         for (i = 0; i < NOPTS; i++)
12916                 if (optlist[i] == 2)
12917                         optlist[i] = 0;
12918 #if DEBUG == 2
12919         debug = 1;
12920 #endif
12921         /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
12922         if (xminusc) {
12923                 minusc = *xargv++;
12924                 if (*xargv)
12925                         goto setarg0;
12926         } else if (!sflag) {
12927                 setinputfile(*xargv, 0);
12928  setarg0:
12929                 arg0 = *xargv++;
12930                 commandname = arg0;
12931         }
12932
12933         shellparam.p = xargv;
12934 #if ENABLE_ASH_GETOPTS
12935         shellparam.optind = 1;
12936         shellparam.optoff = -1;
12937 #endif
12938         /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
12939         while (*xargv) {
12940                 shellparam.nparam++;
12941                 xargv++;
12942         }
12943         optschanged();
12944 }
12945
12946 /*
12947  * Read /etc/profile or .profile.
12948  */
12949 static void
12950 read_profile(const char *name)
12951 {
12952         int skip;
12953
12954         if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
12955                 return;
12956         skip = cmdloop(0);
12957         popfile();
12958         if (skip)
12959                 exitshell();
12960 }
12961
12962 /*
12963  * This routine is called when an error or an interrupt occurs in an
12964  * interactive shell and control is returned to the main command loop.
12965  */
12966 static void
12967 reset(void)
12968 {
12969         /* from eval.c: */
12970         evalskip = 0;
12971         loopnest = 0;
12972         /* from input.c: */
12973         g_parsefile->left_in_buffer = 0;
12974         g_parsefile->left_in_line = 0;      /* clear input buffer */
12975         popallfiles();
12976         /* from parser.c: */
12977         tokpushback = 0;
12978         checkkwd = 0;
12979         /* from redir.c: */
12980         clearredir(/*drop:*/ 0);
12981 }
12982
12983 #if PROFILE
12984 static short profile_buf[16384];
12985 extern int etext();
12986 #endif
12987
12988 /*
12989  * Main routine.  We initialize things, parse the arguments, execute
12990  * profiles if we're a login shell, and then call cmdloop to execute
12991  * commands.  The setjmp call sets up the location to jump to when an
12992  * exception occurs.  When an exception occurs the variable "state"
12993  * is used to figure out how far we had gotten.
12994  */
12995 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
12996 int ash_main(int argc UNUSED_PARAM, char **argv)
12997 {
12998         const char *shinit;
12999         volatile smallint state;
13000         struct jmploc jmploc;
13001         struct stackmark smark;
13002
13003         /* Initialize global data */
13004         INIT_G_misc();
13005         INIT_G_memstack();
13006         INIT_G_var();
13007 #if ENABLE_ASH_ALIAS
13008         INIT_G_alias();
13009 #endif
13010         INIT_G_cmdtable();
13011
13012 #if PROFILE
13013         monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13014 #endif
13015
13016 #if ENABLE_FEATURE_EDITING
13017         line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13018 #endif
13019         state = 0;
13020         if (setjmp(jmploc.loc)) {
13021                 smallint e;
13022                 smallint s;
13023
13024                 reset();
13025
13026                 e = exception_type;
13027                 if (e == EXERROR)
13028                         exitstatus = 2;
13029                 s = state;
13030                 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13031                         exitshell();
13032                 if (e == EXINT)
13033                         outcslow('\n', stderr);
13034
13035                 popstackmark(&smark);
13036                 FORCE_INT_ON; /* enable interrupts */
13037                 if (s == 1)
13038                         goto state1;
13039                 if (s == 2)
13040                         goto state2;
13041                 if (s == 3)
13042                         goto state3;
13043                 goto state4;
13044         }
13045         exception_handler = &jmploc;
13046 #if DEBUG
13047         opentrace();
13048         TRACE(("Shell args: "));
13049         trace_puts_args(argv);
13050 #endif
13051         rootpid = getpid();
13052
13053         init();
13054         setstackmark(&smark);
13055         procargs(argv);
13056
13057 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13058         if (iflag) {
13059                 const char *hp = lookupvar("HISTFILE");
13060
13061                 if (hp == NULL) {
13062                         hp = lookupvar("HOME");
13063                         if (hp != NULL) {
13064                                 char *defhp = concat_path_file(hp, ".ash_history");
13065                                 setvar("HISTFILE", defhp, 0);
13066                                 free(defhp);
13067                         }
13068                 }
13069         }
13070 #endif
13071         if (/* argv[0] && */ argv[0][0] == '-')
13072                 isloginsh = 1;
13073         if (isloginsh) {
13074                 state = 1;
13075                 read_profile("/etc/profile");
13076  state1:
13077                 state = 2;
13078                 read_profile(".profile");
13079         }
13080  state2:
13081         state = 3;
13082         if (
13083 #ifndef linux
13084          getuid() == geteuid() && getgid() == getegid() &&
13085 #endif
13086          iflag
13087         ) {
13088                 shinit = lookupvar("ENV");
13089                 if (shinit != NULL && *shinit != '\0') {
13090                         read_profile(shinit);
13091                 }
13092         }
13093  state3:
13094         state = 4;
13095         if (minusc) {
13096                 /* evalstring pushes parsefile stack.
13097                  * Ensure we don't falsely claim that 0 (stdin)
13098                  * is one of stacked source fds.
13099                  * Testcase: ash -c 'exec 1>&0' must not complain. */
13100                 // if (!sflag) g_parsefile->pf_fd = -1;
13101                 // ^^ not necessary since now we special-case fd 0
13102                 // in is_hidden_fd() to not be considered "hidden fd"
13103                 evalstring(minusc, 0);
13104         }
13105
13106         if (sflag || minusc == NULL) {
13107 #if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
13108                 if (iflag) {
13109                         const char *hp = lookupvar("HISTFILE");
13110                         if (hp)
13111                                 line_input_state->hist_file = hp;
13112                 }
13113 #endif
13114  state4: /* XXX ??? - why isn't this before the "if" statement */
13115                 cmdloop(1);
13116         }
13117 #if PROFILE
13118         monitor(0);
13119 #endif
13120 #ifdef GPROF
13121         {
13122                 extern void _mcleanup(void);
13123                 _mcleanup();
13124         }
13125 #endif
13126         exitshell();
13127         /* NOTREACHED */
13128 }
13129
13130
13131 /*-
13132  * Copyright (c) 1989, 1991, 1993, 1994
13133  *      The Regents of the University of California.  All rights reserved.
13134  *
13135  * This code is derived from software contributed to Berkeley by
13136  * Kenneth Almquist.
13137  *
13138  * Redistribution and use in source and binary forms, with or without
13139  * modification, are permitted provided that the following conditions
13140  * are met:
13141  * 1. Redistributions of source code must retain the above copyright
13142  *    notice, this list of conditions and the following disclaimer.
13143  * 2. Redistributions in binary form must reproduce the above copyright
13144  *    notice, this list of conditions and the following disclaimer in the
13145  *    documentation and/or other materials provided with the distribution.
13146  * 3. Neither the name of the University nor the names of its contributors
13147  *    may be used to endorse or promote products derived from this software
13148  *    without specific prior written permission.
13149  *
13150  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13151  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13152  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13153  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13154  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13155  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13156  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13157  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13158  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13159  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13160  * SUCH DAMAGE.
13161  */