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