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