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