1 /* vi: set sw=4 ts=4: */
2 /*
3  * ash shell port for busybox
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * Original BSD copyright notice is retained at the end of this file.
9  *
10  * Copyright (c) 1989, 1991, 1993, 1994
11  *      The Regents of the University of California.  All rights reserved.
12  *
13  * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
14  * was re-ported from NetBSD and debianized.
15  *
16  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
17  */
18 //config:config ASH
19 //config:	bool "ash"
20 //config:	default y
21 //config:	depends on !NOMMU
22 //config:	help
23 //config:	  Tha 'ash' shell adds about 60k in the default configuration and is
24 //config:	  the most complete and most pedantically correct shell included with
25 //config:	  busybox. This shell is actually a derivative of the Debian 'dash'
26 //config:	  shell (by Herbert Xu), which was created by porting the 'ash' shell
27 //config:	  (written by Kenneth Almquist) from NetBSD.
28 //config:
29 //config:config ASH_OPTIMIZE_FOR_SIZE
30 //config:	bool "Optimize for size instead of speed"
31 //config:	default y
32 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
33 //config:	help
34 //config:	  Compile ash for reduced size at the price of speed.
35 //config:
36 //config:config ASH_INTERNAL_GLOB
37 //config:	bool "Use internal glob() implementation"
38 //config:	default y	# Y is bigger, but because of uclibc glob() bug, let Y be default for now
39 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
40 //config:	help
41 //config:	  Do not use glob() function from libc, use internal implementation.
42 //config:	  Use this if you are getting "glob.h: No such file or directory"
43 //config:	  or similar build errors.
44 //config:
45 //config:config ASH_RANDOM_SUPPORT
46 //config:	bool "Pseudorandom generator and $RANDOM variable"
47 //config:	default y
48 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
49 //config:	help
50 //config:	  Enable pseudorandom generator and dynamic variable "$RANDOM".
51 //config:	  Each read of "$RANDOM" will generate a new pseudorandom value.
52 //config:	  You can reset the generator by using a specified start value.
53 //config:	  After "unset RANDOM" the generator will switch off and this
54 //config:	  variable will no longer have special treatment.
55 //config:
56 //config:config ASH_EXPAND_PRMT
57 //config:	bool "Expand prompt string"
58 //config:	default y
59 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
60 //config:	help
61 //config:	  "PS#" may contain volatile content, such as backquote commands.
62 //config:	  This option recreates the prompt string from the environment
63 //config:	  variable each time it is displayed.
64 //config:
65 //config:config ASH_BASH_COMPAT
66 //config:	bool "bash-compatible extensions"
67 //config:	default y
68 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
69 //config:	help
70 //config:	  Enable bash-compatible extensions.
71 //config:
72 //config:config ASH_IDLE_TIMEOUT
73 //config:	bool "Idle timeout variable"
74 //config:	default n
75 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
76 //config:	help
77 //config:	  Enables bash-like auto-logout after $TMOUT seconds of idle time.
78 //config:
79 //config:config ASH_JOB_CONTROL
80 //config:	bool "Job control"
81 //config:	default y
82 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
83 //config:	help
84 //config:	  Enable job control in the ash shell.
85 //config:
86 //config:config ASH_ALIAS
87 //config:	bool "Alias support"
88 //config:	default y
89 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
90 //config:	help
91 //config:	  Enable alias support in the ash shell.
92 //config:
93 //config:config ASH_GETOPTS
94 //config:	bool "Builtin getopt to parse positional parameters"
95 //config:	default y
96 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
97 //config:	help
98 //config:	  Enable support for getopts builtin in ash.
99 //config:
100 //config:config ASH_BUILTIN_ECHO
101 //config:	bool "Builtin version of 'echo'"
102 //config:	default y
103 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
104 //config:	help
105 //config:	  Enable support for echo builtin in ash.
106 //config:
107 //config:config ASH_BUILTIN_PRINTF
108 //config:	bool "Builtin version of 'printf'"
109 //config:	default y
110 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
111 //config:	help
112 //config:	  Enable support for printf builtin in ash.
113 //config:
114 //config:config ASH_BUILTIN_TEST
115 //config:	bool "Builtin version of 'test'"
116 //config:	default y
117 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
118 //config:	help
119 //config:	  Enable support for test builtin in ash.
120 //config:
121 //config:config ASH_HELP
122 //config:	bool "help builtin"
123 //config:	default y
124 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
125 //config:	help
126 //config:	  Enable help builtin in ash.
127 //config:
128 //config:config ASH_CMDCMD
129 //config:	bool "'command' command to override shell builtins"
130 //config:	default y
131 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
132 //config:	help
133 //config:	  Enable support for the ash 'command' builtin, which allows
134 //config:	  you to run the specified command with the specified arguments,
135 //config:	  even when there is an ash builtin command with the same name.
136 //config:
137 //config:config ASH_MAIL
138 //config:	bool "Check for new mail on interactive shells"
139 //config:	default y
140 //config:	depends on ASH || SH_IS_ASH || BASH_IS_ASH
141 //config:	help
142 //config:	  Enable "check for new mail" function in the ash shell.
143 
144 //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
145 //applet:IF_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
146 //applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
147 
148 //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
149 //kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
150 //kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
151 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
152 
153 /*
154  * The following should be set to reflect the type of system you have:
155  *      JOBS -> 1 if you have Berkeley job control, 0 otherwise.
156  *      define SYSV if you are running under System V.
157  *      define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
158  *      define DEBUG=2 to compile in and turn on debugging.
159  *
160  * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
161  * debugging info will be written to ./trace and a quit signal
162  * will generate a core dump.
163  */
164 #define DEBUG 0
165 /* Tweak debug output verbosity here */
166 #define DEBUG_TIME 0
167 #define DEBUG_PID 1
168 #define DEBUG_SIG 1
169 #define DEBUG_INTONOFF 0
170 
171 #define PROFILE 0
172 
173 #define JOBS ENABLE_ASH_JOB_CONTROL
174 
175 #include <setjmp.h>
176 #include <fnmatch.h>
177 #include <sys/times.h>
178 #include <sys/utsname.h> /* for setting $HOSTNAME */
179 
180 #include "busybox.h" /* for applet_names */
181 
182 #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
183 /* Bionic at least up to version 24 has no glob() */
184 # undef  ENABLE_ASH_INTERNAL_GLOB
185 # define ENABLE_ASH_INTERNAL_GLOB 1
186 #endif
187 
188 #if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
189 # error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
190 # error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
191 # error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
192 # error glob() should unbackslash them and match. uClibc does not unbackslash,
193 # error fails to match dirname, subsequently not expanding <pattern> in it.
194 // Testcase:
195 // if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
196 // if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
197 #endif
198 
199 #if !ENABLE_ASH_INTERNAL_GLOB
200 # include <glob.h>
201 #endif
202 
203 #include "unicode.h"
204 #include "shell_common.h"
205 #if ENABLE_FEATURE_SH_MATH
206 # include "math.h"
207 #endif
208 #if ENABLE_ASH_RANDOM_SUPPORT
209 # include "random.h"
210 #else
211 # define CLEAR_RANDOM_T(rnd) ((void)0)
212 #endif
213 
214 #include "NUM_APPLETS.h"
215 #if NUM_APPLETS == 1
216 /* STANDALONE does not make sense, and won't compile */
217 # undef CONFIG_FEATURE_SH_STANDALONE
218 # undef ENABLE_FEATURE_SH_STANDALONE
219 # undef IF_FEATURE_SH_STANDALONE
220 # undef IF_NOT_FEATURE_SH_STANDALONE
221 # define ENABLE_FEATURE_SH_STANDALONE 0
222 # define IF_FEATURE_SH_STANDALONE(...)
223 # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
224 #endif
225 
226 #ifndef PIPE_BUF
227 # define PIPE_BUF 4096           /* amount of buffering in a pipe */
228 #endif
229 
230 #if !BB_MMU
231 # error "Do not even bother, ash will not run on NOMMU machine"
232 #endif
233 
234 
235 /* ============ Hash table sizes. Configurable. */
236 
237 #define VTABSIZE 39
238 #define ATABSIZE 39
239 #define CMDTABLESIZE 31         /* should be prime */
240 
241 
242 /* ============ Shell options */
243 
244 static const char *const optletters_optnames[] = {
245 	"e"   "errexit",
246 	"f"   "noglob",
247 	"I"   "ignoreeof",
248 	"i"   "interactive",
249 	"m"   "monitor",
250 	"n"   "noexec",
251 	"s"   "stdin",
252 	"x"   "xtrace",
253 	"v"   "verbose",
254 	"C"   "noclobber",
255 	"a"   "allexport",
256 	"b"   "notify",
257 	"u"   "nounset",
258 	"\0"  "vi"
259 #if ENABLE_ASH_BASH_COMPAT
260 	,"\0"  "pipefail"
261 #endif
262 #if DEBUG
263 	,"\0"  "nolog"
264 	,"\0"  "debug"
265 #endif
266 };
267 
268 #define optletters(n)  optletters_optnames[n][0]
269 #define optnames(n)   (optletters_optnames[n] + 1)
270 
271 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
272 
273 
274 /* ============ Misc data */
275 
276 #define msg_illnum "Illegal number: %s"
277 
278 /*
279  * We enclose jmp_buf in a structure so that we can declare pointers to
280  * jump locations.  The global variable handler contains the location to
281  * jump to when an exception occurs, and the global variable exception_type
282  * contains a code identifying the exception.  To implement nested
283  * exception handlers, the user should save the value of handler on entry
284  * to an inner scope, set handler to point to a jmploc structure for the
285  * inner scope, and restore handler on exit from the scope.
286  */
287 struct jmploc {
288 	jmp_buf loc;
289 };
290 
291 struct globals_misc {
292 	uint8_t exitstatus;     /* exit status of last command */
293 	uint8_t back_exitstatus;/* exit status of backquoted command */
294 	smallint job_warning;   /* user was warned about stopped jobs (can be 2, 1 or 0). */
295 	int rootpid;            /* pid of main shell */
296 	/* shell level: 0 for the main shell, 1 for its children, and so on */
297 	int shlvl;
298 #define rootshell (!shlvl)
299 	char *minusc;  /* argument to -c option */
300 
301 	char *curdir; // = nullstr;     /* current working directory */
302 	char *physdir; // = nullstr;    /* physical working directory */
303 
304 	char *arg0; /* value of $0 */
305 
306 	struct jmploc *exception_handler;
307 
308 	volatile int suppress_int; /* counter */
309 	volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
310 	volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
311 	volatile /*sig_atomic_t*/ smallint pending_sig;	/* last pending signal */
312 	smallint exception_type; /* kind of exception (0..5) */
313 	/* exceptions */
314 #define EXINT 0         /* SIGINT received */
315 #define EXERROR 1       /* a generic error */
316 #define EXEXIT 4        /* exit the shell */
317 
318 	smallint isloginsh;
319 	char nullstr[1];        /* zero length string */
320 
321 	char optlist[NOPTS];
322 #define eflag optlist[0]
323 #define fflag optlist[1]
324 #define Iflag optlist[2]
325 #define iflag optlist[3]
326 #define mflag optlist[4]
327 #define nflag optlist[5]
328 #define sflag optlist[6]
329 #define xflag optlist[7]
330 #define vflag optlist[8]
331 #define Cflag optlist[9]
332 #define aflag optlist[10]
333 #define bflag optlist[11]
334 #define uflag optlist[12]
335 #define viflag optlist[13]
336 #if ENABLE_ASH_BASH_COMPAT
337 # define pipefail optlist[14]
338 #else
339 # define pipefail 0
340 #endif
341 #if DEBUG
342 # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
343 # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
344 #endif
345 
346 	/* trap handler commands */
347 	/*
348 	 * Sigmode records the current value of the signal handlers for the various
349 	 * modes.  A value of zero means that the current handler is not known.
350 	 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
351 	 */
352 	char sigmode[NSIG - 1];
353 #define S_DFL      1            /* default signal handling (SIG_DFL) */
354 #define S_CATCH    2            /* signal is caught */
355 #define S_IGN      3            /* signal is ignored (SIG_IGN) */
356 #define S_HARD_IGN 4            /* signal is ignored permanently */
357 
358 	/* indicates specified signal received */
359 	uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
360 	uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
361 	char *trap[NSIG];
362 	char **trap_ptr;        /* used only by "trap hack" */
363 
364 	/* Rarely referenced stuff */
365 #if ENABLE_ASH_RANDOM_SUPPORT
366 	random_t random_gen;
367 #endif
368 	pid_t backgndpid;        /* pid of last background process */
369 };
370 extern struct globals_misc *const ash_ptr_to_globals_misc;
371 #define G_misc (*ash_ptr_to_globals_misc)
372 #define exitstatus        (G_misc.exitstatus )
373 #define back_exitstatus   (G_misc.back_exitstatus )
374 #define job_warning       (G_misc.job_warning)
375 #define rootpid     (G_misc.rootpid    )
376 #define shlvl       (G_misc.shlvl      )
377 #define minusc      (G_misc.minusc     )
378 #define curdir      (G_misc.curdir     )
379 #define physdir     (G_misc.physdir    )
380 #define arg0        (G_misc.arg0       )
381 #define exception_handler (G_misc.exception_handler)
382 #define exception_type    (G_misc.exception_type   )
383 #define suppress_int      (G_misc.suppress_int     )
384 #define pending_int       (G_misc.pending_int      )
385 #define got_sigchld       (G_misc.got_sigchld      )
386 #define pending_sig       (G_misc.pending_sig      )
387 #define isloginsh   (G_misc.isloginsh  )
388 #define nullstr     (G_misc.nullstr    )
389 #define optlist     (G_misc.optlist    )
390 #define sigmode     (G_misc.sigmode    )
391 #define gotsig      (G_misc.gotsig     )
392 #define may_have_traps    (G_misc.may_have_traps   )
393 #define trap        (G_misc.trap       )
394 #define trap_ptr    (G_misc.trap_ptr   )
395 #define random_gen  (G_misc.random_gen )
396 #define backgndpid  (G_misc.backgndpid )
397 #define INIT_G_misc() do { \
398 	(*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
399 	barrier(); \
400 	curdir = nullstr; \
401 	physdir = nullstr; \
402 	trap_ptr = trap; \
403 } while (0)
404 
405 
406 /* ============ DEBUG */
407 #if DEBUG
408 static void trace_printf(const char *fmt, ...);
409 static void trace_vprintf(const char *fmt, va_list va);
410 # define TRACE(param)    trace_printf param
411 # define TRACEV(param)   trace_vprintf param
412 # define close(fd) do { \
413 	int dfd = (fd); \
414 	if (close(dfd) < 0) \
415 		bb_error_msg("bug on %d: closing %d(0x%x)", \
416 			__LINE__, dfd, dfd); \
417 } while (0)
418 #else
419 # define TRACE(param)
420 # define TRACEV(param)
421 #endif
422 
423 
424 /* ============ Utility functions */
425 #define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
426 #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
427 
428 static int
isdigit_str9(const char * str)429 isdigit_str9(const char *str)
430 {
431 	int maxlen = 9 + 1; /* max 9 digits: 999999999 */
432 	while (--maxlen && isdigit(*str))
433 		str++;
434 	return (*str == '\0');
435 }
436 
437 static const char *
var_end(const char * var)438 var_end(const char *var)
439 {
440 	while (*var)
441 		if (*var++ == '=')
442 			break;
443 	return var;
444 }
445 
446 
447 /* ============ Interrupts / exceptions */
448 
449 static void exitshell(void) NORETURN;
450 
451 /*
452  * These macros allow the user to suspend the handling of interrupt signals
453  * over a period of time.  This is similar to SIGHOLD or to sigblock, but
454  * much more efficient and portable.  (But hacking the kernel is so much
455  * more fun than worrying about efficiency and portability. :-))
456  */
457 #if DEBUG_INTONOFF
458 # define INT_OFF do { \
459 	TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
460 	suppress_int++; \
461 	barrier(); \
462 } while (0)
463 #else
464 # define INT_OFF do { \
465 	suppress_int++; \
466 	barrier(); \
467 } while (0)
468 #endif
469 
470 /*
471  * Called to raise an exception.  Since C doesn't include exceptions, we
472  * just do a longjmp to the exception handler.  The type of exception is
473  * stored in the global variable "exception_type".
474  */
475 static void raise_exception(int) NORETURN;
476 static void
raise_exception(int e)477 raise_exception(int e)
478 {
479 #if DEBUG
480 	if (exception_handler == NULL)
481 		abort();
482 #endif
483 	INT_OFF;
484 	exception_type = e;
485 	longjmp(exception_handler->loc, 1);
486 }
487 #if DEBUG
488 #define raise_exception(e) do { \
489 	TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
490 	raise_exception(e); \
491 } while (0)
492 #endif
493 
494 /*
495  * Called when a SIGINT is received.  (If the user specifies
496  * that SIGINT is to be trapped or ignored using the trap builtin, then
497  * this routine is not called.)  Suppressint is nonzero when interrupts
498  * are held using the INT_OFF macro.  (The test for iflag is just
499  * defensive programming.)
500  */
501 static void raise_interrupt(void) NORETURN;
502 static void
raise_interrupt(void)503 raise_interrupt(void)
504 {
505 	pending_int = 0;
506 	/* Signal is not automatically unmasked after it is raised,
507 	 * do it ourself - unmask all signals */
508 	sigprocmask_allsigs(SIG_UNBLOCK);
509 	/* pending_sig = 0; - now done in signal_handler() */
510 
511 	if (!(rootshell && iflag)) {
512 		/* Kill ourself with SIGINT */
513 		signal(SIGINT, SIG_DFL);
514 		raise(SIGINT);
515 	}
516 	/* bash: ^C even on empty command line sets $? */
517 	exitstatus = SIGINT + 128;
518 	raise_exception(EXINT);
519 	/* NOTREACHED */
520 }
521 #if DEBUG
522 #define raise_interrupt() do { \
523 	TRACE(("raising interrupt on line %d\n", __LINE__)); \
524 	raise_interrupt(); \
525 } while (0)
526 #endif
527 
IF_ASH_OPTIMIZE_FOR_SIZE(inline)528 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
529 int_on(void)
530 {
531 	barrier();
532 	if (--suppress_int == 0 && pending_int) {
533 		raise_interrupt();
534 	}
535 }
536 #if DEBUG_INTONOFF
537 # define INT_ON do { \
538 	TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
539 	int_on(); \
540 } while (0)
541 #else
542 # define INT_ON int_on()
543 #endif
IF_ASH_OPTIMIZE_FOR_SIZE(inline)544 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
545 force_int_on(void)
546 {
547 	barrier();
548 	suppress_int = 0;
549 	if (pending_int)
550 		raise_interrupt();
551 }
552 #define FORCE_INT_ON force_int_on()
553 
554 #define SAVE_INT(v) ((v) = suppress_int)
555 
556 #define RESTORE_INT(v) do { \
557 	barrier(); \
558 	suppress_int = (v); \
559 	if (suppress_int == 0 && pending_int) \
560 		raise_interrupt(); \
561 } while (0)
562 
563 
564 /* ============ Stdout/stderr output */
565 
566 static void
outstr(const char * p,FILE * file)567 outstr(const char *p, FILE *file)
568 {
569 	INT_OFF;
570 	fputs(p, file);
571 	INT_ON;
572 }
573 
574 static void
flush_stdout_stderr(void)575 flush_stdout_stderr(void)
576 {
577 	INT_OFF;
578 	fflush_all();
579 	INT_ON;
580 }
581 
582 /* Was called outcslow(c,FILE*), but c was always '\n' */
583 static void
newline_and_flush(FILE * dest)584 newline_and_flush(FILE *dest)
585 {
586 	INT_OFF;
587 	putc('\n', dest);
588 	fflush(dest);
589 	INT_ON;
590 }
591 
592 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
593 static int
out1fmt(const char * fmt,...)594 out1fmt(const char *fmt, ...)
595 {
596 	va_list ap;
597 	int r;
598 
599 	INT_OFF;
600 	va_start(ap, fmt);
601 	r = vprintf(fmt, ap);
602 	va_end(ap);
603 	INT_ON;
604 	return r;
605 }
606 
607 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
608 static int
fmtstr(char * outbuf,size_t length,const char * fmt,...)609 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
610 {
611 	va_list ap;
612 	int ret;
613 
614 	va_start(ap, fmt);
615 	INT_OFF;
616 	ret = vsnprintf(outbuf, length, fmt, ap);
617 	va_end(ap);
618 	INT_ON;
619 	return ret;
620 }
621 
622 static void
out1str(const char * p)623 out1str(const char *p)
624 {
625 	outstr(p, stdout);
626 }
627 
628 static void
out2str(const char * p)629 out2str(const char *p)
630 {
631 	outstr(p, stderr);
632 	flush_stdout_stderr();
633 }
634 
635 
636 /* ============ Parser structures */
637 
638 /* control characters in argument strings */
639 #define CTL_FIRST CTLESC
640 #define CTLESC       ((unsigned char)'\201')    /* escape next character */
641 #define CTLVAR       ((unsigned char)'\202')    /* variable defn */
642 #define CTLENDVAR    ((unsigned char)'\203')
643 #define CTLBACKQ     ((unsigned char)'\204')
644 #define CTLARI       ((unsigned char)'\206')    /* arithmetic expression */
645 #define CTLENDARI    ((unsigned char)'\207')
646 #define CTLQUOTEMARK ((unsigned char)'\210')
647 #define CTL_LAST CTLQUOTEMARK
648 
649 /* variable substitution byte (follows CTLVAR) */
650 #define VSTYPE  0x0f            /* type of variable substitution */
651 #define VSNUL   0x10            /* colon--treat the empty string as unset */
652 
653 /* values of VSTYPE field */
654 #define VSNORMAL        0x1     /* normal variable:  $var or ${var} */
655 #define VSMINUS         0x2     /* ${var-text} */
656 #define VSPLUS          0x3     /* ${var+text} */
657 #define VSQUESTION      0x4     /* ${var?message} */
658 #define VSASSIGN        0x5     /* ${var=text} */
659 #define VSTRIMRIGHT     0x6     /* ${var%pattern} */
660 #define VSTRIMRIGHTMAX  0x7     /* ${var%%pattern} */
661 #define VSTRIMLEFT      0x8     /* ${var#pattern} */
662 #define VSTRIMLEFTMAX   0x9     /* ${var##pattern} */
663 #define VSLENGTH        0xa     /* ${#var} */
664 #if ENABLE_ASH_BASH_COMPAT
665 #define VSSUBSTR        0xc     /* ${var:position:length} */
666 #define VSREPLACE       0xd     /* ${var/pattern/replacement} */
667 #define VSREPLACEALL    0xe     /* ${var//pattern/replacement} */
668 #endif
669 
670 static const char dolatstr[] ALIGN1 = {
671 	CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
672 };
673 #define DOLATSTRLEN 6
674 
675 #define NCMD      0
676 #define NPIPE     1
677 #define NREDIR    2
678 #define NBACKGND  3
679 #define NSUBSHELL 4
680 #define NAND      5
681 #define NOR       6
682 #define NSEMI     7
683 #define NIF       8
684 #define NWHILE    9
685 #define NUNTIL   10
686 #define NFOR     11
687 #define NCASE    12
688 #define NCLIST   13
689 #define NDEFUN   14
690 #define NARG     15
691 #define NTO      16
692 #if ENABLE_ASH_BASH_COMPAT
693 #define NTO2     17
694 #endif
695 #define NCLOBBER 18
696 #define NFROM    19
697 #define NFROMTO  20
698 #define NAPPEND  21
699 #define NTOFD    22
700 #define NFROMFD  23
701 #define NHERE    24
702 #define NXHERE   25
703 #define NNOT     26
704 #define N_NUMBER 27
705 
706 union node;
707 
708 struct ncmd {
709 	smallint type; /* Nxxxx */
710 	union node *assign;
711 	union node *args;
712 	union node *redirect;
713 };
714 
715 struct npipe {
716 	smallint type;
717 	smallint pipe_backgnd;
718 	struct nodelist *cmdlist;
719 };
720 
721 struct nredir {
722 	smallint type;
723 	union node *n;
724 	union node *redirect;
725 };
726 
727 struct nbinary {
728 	smallint type;
729 	union node *ch1;
730 	union node *ch2;
731 };
732 
733 struct nif {
734 	smallint type;
735 	union node *test;
736 	union node *ifpart;
737 	union node *elsepart;
738 };
739 
740 struct nfor {
741 	smallint type;
742 	union node *args;
743 	union node *body;
744 	char *var;
745 };
746 
747 struct ncase {
748 	smallint type;
749 	union node *expr;
750 	union node *cases;
751 };
752 
753 struct nclist {
754 	smallint type;
755 	union node *next;
756 	union node *pattern;
757 	union node *body;
758 };
759 
760 struct narg {
761 	smallint type;
762 	union node *next;
763 	char *text;
764 	struct nodelist *backquote;
765 };
766 
767 /* nfile and ndup layout must match!
768  * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
769  * that it is actually NTO2 (>&file), and change its type.
770  */
771 struct nfile {
772 	smallint type;
773 	union node *next;
774 	int fd;
775 	int _unused_dupfd;
776 	union node *fname;
777 	char *expfname;
778 };
779 
780 struct ndup {
781 	smallint type;
782 	union node *next;
783 	int fd;
784 	int dupfd;
785 	union node *vname;
786 	char *_unused_expfname;
787 };
788 
789 struct nhere {
790 	smallint type;
791 	union node *next;
792 	int fd;
793 	union node *doc;
794 };
795 
796 struct nnot {
797 	smallint type;
798 	union node *com;
799 };
800 
801 union node {
802 	smallint type;
803 	struct ncmd ncmd;
804 	struct npipe npipe;
805 	struct nredir nredir;
806 	struct nbinary nbinary;
807 	struct nif nif;
808 	struct nfor nfor;
809 	struct ncase ncase;
810 	struct nclist nclist;
811 	struct narg narg;
812 	struct nfile nfile;
813 	struct ndup ndup;
814 	struct nhere nhere;
815 	struct nnot nnot;
816 };
817 
818 /*
819  * NODE_EOF is returned by parsecmd when it encounters an end of file.
820  * It must be distinct from NULL.
821  */
822 #define NODE_EOF ((union node *) -1L)
823 
824 struct nodelist {
825 	struct nodelist *next;
826 	union node *n;
827 };
828 
829 struct funcnode {
830 	int count;
831 	union node n;
832 };
833 
834 /*
835  * Free a parse tree.
836  */
837 static void
freefunc(struct funcnode * f)838 freefunc(struct funcnode *f)
839 {
840 	if (f && --f->count < 0)
841 		free(f);
842 }
843 
844 
845 /* ============ Debugging output */
846 
847 #if DEBUG
848 
849 static FILE *tracefile;
850 
851 static void
trace_printf(const char * fmt,...)852 trace_printf(const char *fmt, ...)
853 {
854 	va_list va;
855 
856 	if (debug != 1)
857 		return;
858 	if (DEBUG_TIME)
859 		fprintf(tracefile, "%u ", (int) time(NULL));
860 	if (DEBUG_PID)
861 		fprintf(tracefile, "[%u] ", (int) getpid());
862 	if (DEBUG_SIG)
863 		fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
864 	va_start(va, fmt);
865 	vfprintf(tracefile, fmt, va);
866 	va_end(va);
867 }
868 
869 static void
trace_vprintf(const char * fmt,va_list va)870 trace_vprintf(const char *fmt, va_list va)
871 {
872 	if (debug != 1)
873 		return;
874 	vfprintf(tracefile, fmt, va);
875 	fprintf(tracefile, "\n");
876 }
877 
878 static void
trace_puts(const char * s)879 trace_puts(const char *s)
880 {
881 	if (debug != 1)
882 		return;
883 	fputs(s, tracefile);
884 }
885 
886 static void
trace_puts_quoted(char * s)887 trace_puts_quoted(char *s)
888 {
889 	char *p;
890 	char c;
891 
892 	if (debug != 1)
893 		return;
894 	putc('"', tracefile);
895 	for (p = s; *p; p++) {
896 		switch ((unsigned char)*p) {
897 		case '\n': c = 'n'; goto backslash;
898 		case '\t': c = 't'; goto backslash;
899 		case '\r': c = 'r'; goto backslash;
900 		case '\"': c = '\"'; goto backslash;
901 		case '\\': c = '\\'; goto backslash;
902 		case CTLESC: c = 'e'; goto backslash;
903 		case CTLVAR: c = 'v'; goto backslash;
904 		case CTLBACKQ: c = 'q'; goto backslash;
905  backslash:
906 			putc('\\', tracefile);
907 			putc(c, tracefile);
908 			break;
909 		default:
910 			if (*p >= ' ' && *p <= '~')
911 				putc(*p, tracefile);
912 			else {
913 				putc('\\', tracefile);
914 				putc((*p >> 6) & 03, tracefile);
915 				putc((*p >> 3) & 07, tracefile);
916 				putc(*p & 07, tracefile);
917 			}
918 			break;
919 		}
920 	}
921 	putc('"', tracefile);
922 }
923 
924 static void
trace_puts_args(char ** ap)925 trace_puts_args(char **ap)
926 {
927 	if (debug != 1)
928 		return;
929 	if (!*ap)
930 		return;
931 	while (1) {
932 		trace_puts_quoted(*ap);
933 		if (!*++ap) {
934 			putc('\n', tracefile);
935 			break;
936 		}
937 		putc(' ', tracefile);
938 	}
939 }
940 
941 static void
opentrace(void)942 opentrace(void)
943 {
944 	char s[100];
945 #ifdef O_APPEND
946 	int flags;
947 #endif
948 
949 	if (debug != 1) {
950 		if (tracefile)
951 			fflush(tracefile);
952 		/* leave open because libedit might be using it */
953 		return;
954 	}
955 	strcpy(s, "./trace");
956 	if (tracefile) {
957 		if (!freopen(s, "a", tracefile)) {
958 			fprintf(stderr, "Can't re-open %s\n", s);
959 			debug = 0;
960 			return;
961 		}
962 	} else {
963 		tracefile = fopen(s, "a");
964 		if (tracefile == NULL) {
965 			fprintf(stderr, "Can't open %s\n", s);
966 			debug = 0;
967 			return;
968 		}
969 	}
970 #ifdef O_APPEND
971 	flags = fcntl(fileno(tracefile), F_GETFL);
972 	if (flags >= 0)
973 		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
974 #endif
975 	setlinebuf(tracefile);
976 	fputs("\nTracing started.\n", tracefile);
977 }
978 
979 static void
indent(int amount,char * pfx,FILE * fp)980 indent(int amount, char *pfx, FILE *fp)
981 {
982 	int i;
983 
984 	for (i = 0; i < amount; i++) {
985 		if (pfx && i == amount - 1)
986 			fputs(pfx, fp);
987 		putc('\t', fp);
988 	}
989 }
990 
991 /* little circular references here... */
992 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
993 
994 static void
sharg(union node * arg,FILE * fp)995 sharg(union node *arg, FILE *fp)
996 {
997 	char *p;
998 	struct nodelist *bqlist;
999 	unsigned char subtype;
1000 
1001 	if (arg->type != NARG) {
1002 		out1fmt("<node type %d>\n", arg->type);
1003 		abort();
1004 	}
1005 	bqlist = arg->narg.backquote;
1006 	for (p = arg->narg.text; *p; p++) {
1007 		switch ((unsigned char)*p) {
1008 		case CTLESC:
1009 			p++;
1010 			putc(*p, fp);
1011 			break;
1012 		case CTLVAR:
1013 			putc('$', fp);
1014 			putc('{', fp);
1015 			subtype = *++p;
1016 			if (subtype == VSLENGTH)
1017 				putc('#', fp);
1018 
1019 			while (*p != '=') {
1020 				putc(*p, fp);
1021 				p++;
1022 			}
1023 
1024 			if (subtype & VSNUL)
1025 				putc(':', fp);
1026 
1027 			switch (subtype & VSTYPE) {
1028 			case VSNORMAL:
1029 				putc('}', fp);
1030 				break;
1031 			case VSMINUS:
1032 				putc('-', fp);
1033 				break;
1034 			case VSPLUS:
1035 				putc('+', fp);
1036 				break;
1037 			case VSQUESTION:
1038 				putc('?', fp);
1039 				break;
1040 			case VSASSIGN:
1041 				putc('=', fp);
1042 				break;
1043 			case VSTRIMLEFT:
1044 				putc('#', fp);
1045 				break;
1046 			case VSTRIMLEFTMAX:
1047 				putc('#', fp);
1048 				putc('#', fp);
1049 				break;
1050 			case VSTRIMRIGHT:
1051 				putc('%', fp);
1052 				break;
1053 			case VSTRIMRIGHTMAX:
1054 				putc('%', fp);
1055 				putc('%', fp);
1056 				break;
1057 			case VSLENGTH:
1058 				break;
1059 			default:
1060 				out1fmt("<subtype %d>", subtype);
1061 			}
1062 			break;
1063 		case CTLENDVAR:
1064 			putc('}', fp);
1065 			break;
1066 		case CTLBACKQ:
1067 			putc('$', fp);
1068 			putc('(', fp);
1069 			shtree(bqlist->n, -1, NULL, fp);
1070 			putc(')', fp);
1071 			break;
1072 		default:
1073 			putc(*p, fp);
1074 			break;
1075 		}
1076 	}
1077 }
1078 
1079 static void
shcmd(union node * cmd,FILE * fp)1080 shcmd(union node *cmd, FILE *fp)
1081 {
1082 	union node *np;
1083 	int first;
1084 	const char *s;
1085 	int dftfd;
1086 
1087 	first = 1;
1088 	for (np = cmd->ncmd.args; np; np = np->narg.next) {
1089 		if (!first)
1090 			putc(' ', fp);
1091 		sharg(np, fp);
1092 		first = 0;
1093 	}
1094 	for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1095 		if (!first)
1096 			putc(' ', fp);
1097 		dftfd = 0;
1098 		switch (np->nfile.type) {
1099 		case NTO:      s = ">>"+1; dftfd = 1; break;
1100 		case NCLOBBER: s = ">|"; dftfd = 1; break;
1101 		case NAPPEND:  s = ">>"; dftfd = 1; break;
1102 #if ENABLE_ASH_BASH_COMPAT
1103 		case NTO2:
1104 #endif
1105 		case NTOFD:    s = ">&"; dftfd = 1; break;
1106 		case NFROM:    s = "<"; break;
1107 		case NFROMFD:  s = "<&"; break;
1108 		case NFROMTO:  s = "<>"; break;
1109 		default:       s = "*error*"; break;
1110 		}
1111 		if (np->nfile.fd != dftfd)
1112 			fprintf(fp, "%d", np->nfile.fd);
1113 		fputs(s, fp);
1114 		if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1115 			fprintf(fp, "%d", np->ndup.dupfd);
1116 		} else {
1117 			sharg(np->nfile.fname, fp);
1118 		}
1119 		first = 0;
1120 	}
1121 }
1122 
1123 static void
shtree(union node * n,int ind,char * pfx,FILE * fp)1124 shtree(union node *n, int ind, char *pfx, FILE *fp)
1125 {
1126 	struct nodelist *lp;
1127 	const char *s;
1128 
1129 	if (n == NULL)
1130 		return;
1131 
1132 	indent(ind, pfx, fp);
1133 
1134 	if (n == NODE_EOF) {
1135 		fputs("<EOF>", fp);
1136 		return;
1137 	}
1138 
1139 	switch (n->type) {
1140 	case NSEMI:
1141 		s = "; ";
1142 		goto binop;
1143 	case NAND:
1144 		s = " && ";
1145 		goto binop;
1146 	case NOR:
1147 		s = " || ";
1148  binop:
1149 		shtree(n->nbinary.ch1, ind, NULL, fp);
1150 		/* if (ind < 0) */
1151 			fputs(s, fp);
1152 		shtree(n->nbinary.ch2, ind, NULL, fp);
1153 		break;
1154 	case NCMD:
1155 		shcmd(n, fp);
1156 		if (ind >= 0)
1157 			putc('\n', fp);
1158 		break;
1159 	case NPIPE:
1160 		for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1161 			shtree(lp->n, 0, NULL, fp);
1162 			if (lp->next)
1163 				fputs(" | ", fp);
1164 		}
1165 		if (n->npipe.pipe_backgnd)
1166 			fputs(" &", fp);
1167 		if (ind >= 0)
1168 			putc('\n', fp);
1169 		break;
1170 	default:
1171 		fprintf(fp, "<node type %d>", n->type);
1172 		if (ind >= 0)
1173 			putc('\n', fp);
1174 		break;
1175 	}
1176 }
1177 
1178 static void
showtree(union node * n)1179 showtree(union node *n)
1180 {
1181 	trace_puts("showtree called\n");
1182 	shtree(n, 1, NULL, stderr);
1183 }
1184 
1185 #endif /* DEBUG */
1186 
1187 
1188 /* ============ Parser data */
1189 
1190 /*
1191  * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1192  */
1193 struct strlist {
1194 	struct strlist *next;
1195 	char *text;
1196 };
1197 
1198 struct alias;
1199 
1200 struct strpush {
1201 	struct strpush *prev;   /* preceding string on stack */
1202 	char *prev_string;
1203 	int prev_left_in_line;
1204 #if ENABLE_ASH_ALIAS
1205 	struct alias *ap;       /* if push was associated with an alias */
1206 #endif
1207 	char *string;           /* remember the string since it may change */
1208 
1209 	/* Remember last two characters for pungetc. */
1210 	int lastc[2];
1211 
1212 	/* Number of outstanding calls to pungetc. */
1213 	int unget;
1214 };
1215 
1216 struct parsefile {
1217 	struct parsefile *prev; /* preceding file on stack */
1218 	int linno;              /* current line */
1219 	int pf_fd;              /* file descriptor (or -1 if string) */
1220 	int left_in_line;       /* number of chars left in this line */
1221 	int left_in_buffer;     /* number of chars left in this buffer past the line */
1222 	char *next_to_pgetc;    /* next char in buffer */
1223 	char *buf;              /* input buffer */
1224 	struct strpush *strpush; /* for pushing strings at this level */
1225 	struct strpush basestrpush; /* so pushing one is fast */
1226 
1227 	/* Remember last two characters for pungetc. */
1228 	int lastc[2];
1229 
1230 	/* Number of outstanding calls to pungetc. */
1231 	int unget;
1232 };
1233 
1234 static struct parsefile basepf;        /* top level input file */
1235 static struct parsefile *g_parsefile = &basepf;  /* current input file */
1236 static int startlinno;                 /* line # where last token started */
1237 static char *commandname;              /* currently executing command */
1238 static struct strlist *cmdenviron;     /* environment for builtin command */
1239 
1240 
1241 /* ============ Message printing */
1242 
1243 static void
ash_vmsg(const char * msg,va_list ap)1244 ash_vmsg(const char *msg, va_list ap)
1245 {
1246 	fprintf(stderr, "%s: ", arg0);
1247 	if (commandname) {
1248 		if (strcmp(arg0, commandname))
1249 			fprintf(stderr, "%s: ", commandname);
1250 		if (!iflag || g_parsefile->pf_fd > 0)
1251 			fprintf(stderr, "line %d: ", startlinno);
1252 	}
1253 	vfprintf(stderr, msg, ap);
1254 	newline_and_flush(stderr);
1255 }
1256 
1257 /*
1258  * Exverror is called to raise the error exception.  If the second argument
1259  * is not NULL then error prints an error message using printf style
1260  * formatting.  It then raises the error exception.
1261  */
1262 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1263 static void
ash_vmsg_and_raise(int cond,const char * msg,va_list ap)1264 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1265 {
1266 #if DEBUG
1267 	if (msg) {
1268 		TRACE(("ash_vmsg_and_raise(%d):", cond));
1269 		TRACEV((msg, ap));
1270 	} else
1271 		TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1272 	if (msg)
1273 #endif
1274 		ash_vmsg(msg, ap);
1275 
1276 	flush_stdout_stderr();
1277 	raise_exception(cond);
1278 	/* NOTREACHED */
1279 }
1280 
1281 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1282 static void
ash_msg_and_raise_error(const char * msg,...)1283 ash_msg_and_raise_error(const char *msg, ...)
1284 {
1285 	va_list ap;
1286 
1287 	exitstatus = 2;
1288 
1289 	va_start(ap, msg);
1290 	ash_vmsg_and_raise(EXERROR, msg, ap);
1291 	/* NOTREACHED */
1292 	va_end(ap);
1293 }
1294 
1295 static void raise_error_syntax(const char *) NORETURN;
1296 static void
raise_error_syntax(const char * msg)1297 raise_error_syntax(const char *msg)
1298 {
1299 	ash_msg_and_raise_error("syntax error: %s", msg);
1300 	/* NOTREACHED */
1301 }
1302 
1303 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1304 static void
ash_msg_and_raise(int cond,const char * msg,...)1305 ash_msg_and_raise(int cond, const char *msg, ...)
1306 {
1307 	va_list ap;
1308 
1309 	va_start(ap, msg);
1310 	ash_vmsg_and_raise(cond, msg, ap);
1311 	/* NOTREACHED */
1312 	va_end(ap);
1313 }
1314 
1315 /*
1316  * error/warning routines for external builtins
1317  */
1318 static void
ash_msg(const char * fmt,...)1319 ash_msg(const char *fmt, ...)
1320 {
1321 	va_list ap;
1322 
1323 	va_start(ap, fmt);
1324 	ash_vmsg(fmt, ap);
1325 	va_end(ap);
1326 }
1327 
1328 /*
1329  * Return a string describing an error.  The returned string may be a
1330  * pointer to a static buffer that will be overwritten on the next call.
1331  * Action describes the operation that got the error.
1332  */
1333 static const char *
errmsg(int e,const char * em)1334 errmsg(int e, const char *em)
1335 {
1336 	if (e == ENOENT || e == ENOTDIR) {
1337 		return em;
1338 	}
1339 	return strerror(e);
1340 }
1341 
1342 
1343 /* ============ Memory allocation */
1344 
1345 #if 0
1346 /* I consider these wrappers nearly useless:
1347  * ok, they return you to nearest exception handler, but
1348  * how much memory do you leak in the process, making
1349  * memory starvation worse?
1350  */
1351 static void *
1352 ckrealloc(void * p, size_t nbytes)
1353 {
1354 	p = realloc(p, nbytes);
1355 	if (!p)
1356 		ash_msg_and_raise_error(bb_msg_memory_exhausted);
1357 	return p;
1358 }
1359 
1360 static void *
1361 ckmalloc(size_t nbytes)
1362 {
1363 	return ckrealloc(NULL, nbytes);
1364 }
1365 
1366 static void *
1367 ckzalloc(size_t nbytes)
1368 {
1369 	return memset(ckmalloc(nbytes), 0, nbytes);
1370 }
1371 
1372 static char *
1373 ckstrdup(const char *s)
1374 {
1375 	char *p = strdup(s);
1376 	if (!p)
1377 		ash_msg_and_raise_error(bb_msg_memory_exhausted);
1378 	return p;
1379 }
1380 #else
1381 /* Using bbox equivalents. They exit if out of memory */
1382 # define ckrealloc xrealloc
1383 # define ckmalloc  xmalloc
1384 # define ckzalloc  xzalloc
1385 # define ckstrdup  xstrdup
1386 #endif
1387 
1388 /*
1389  * It appears that grabstackstr() will barf with such alignments
1390  * because stalloc() will return a string allocated in a new stackblock.
1391  */
1392 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1393 enum {
1394 	/* Most machines require the value returned from malloc to be aligned
1395 	 * in some way.  The following macro will get this right
1396 	 * on many machines.  */
1397 	SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1398 	/* Minimum size of a block */
1399 	MINSIZE = SHELL_ALIGN(504),
1400 };
1401 
1402 struct stack_block {
1403 	struct stack_block *prev;
1404 	char space[MINSIZE];
1405 };
1406 
1407 struct stackmark {
1408 	struct stack_block *stackp;
1409 	char *stacknxt;
1410 	size_t stacknleft;
1411 };
1412 
1413 
1414 struct globals_memstack {
1415 	struct stack_block *g_stackp; // = &stackbase;
1416 	char *g_stacknxt; // = stackbase.space;
1417 	char *sstrend; // = stackbase.space + MINSIZE;
1418 	size_t g_stacknleft; // = MINSIZE;
1419 	struct stack_block stackbase;
1420 };
1421 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1422 #define G_memstack (*ash_ptr_to_globals_memstack)
1423 #define g_stackp     (G_memstack.g_stackp    )
1424 #define g_stacknxt   (G_memstack.g_stacknxt  )
1425 #define sstrend      (G_memstack.sstrend     )
1426 #define g_stacknleft (G_memstack.g_stacknleft)
1427 #define stackbase    (G_memstack.stackbase   )
1428 #define INIT_G_memstack() do { \
1429 	(*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1430 	barrier(); \
1431 	g_stackp = &stackbase; \
1432 	g_stacknxt = stackbase.space; \
1433 	g_stacknleft = MINSIZE; \
1434 	sstrend = stackbase.space + MINSIZE; \
1435 } while (0)
1436 
1437 
1438 #define stackblock()     ((void *)g_stacknxt)
1439 #define stackblocksize() g_stacknleft
1440 
1441 /*
1442  * Parse trees for commands are allocated in lifo order, so we use a stack
1443  * to make this more efficient, and also to avoid all sorts of exception
1444  * handling code to handle interrupts in the middle of a parse.
1445  *
1446  * The size 504 was chosen because the Ultrix malloc handles that size
1447  * well.
1448  */
1449 static void *
stalloc(size_t nbytes)1450 stalloc(size_t nbytes)
1451 {
1452 	char *p;
1453 	size_t aligned;
1454 
1455 	aligned = SHELL_ALIGN(nbytes);
1456 	if (aligned > g_stacknleft) {
1457 		size_t len;
1458 		size_t blocksize;
1459 		struct stack_block *sp;
1460 
1461 		blocksize = aligned;
1462 		if (blocksize < MINSIZE)
1463 			blocksize = MINSIZE;
1464 		len = sizeof(struct stack_block) - MINSIZE + blocksize;
1465 		if (len < blocksize)
1466 			ash_msg_and_raise_error(bb_msg_memory_exhausted);
1467 		INT_OFF;
1468 		sp = ckmalloc(len);
1469 		sp->prev = g_stackp;
1470 		g_stacknxt = sp->space;
1471 		g_stacknleft = blocksize;
1472 		sstrend = g_stacknxt + blocksize;
1473 		g_stackp = sp;
1474 		INT_ON;
1475 	}
1476 	p = g_stacknxt;
1477 	g_stacknxt += aligned;
1478 	g_stacknleft -= aligned;
1479 	return p;
1480 }
1481 
1482 static void *
stzalloc(size_t nbytes)1483 stzalloc(size_t nbytes)
1484 {
1485 	return memset(stalloc(nbytes), 0, nbytes);
1486 }
1487 
1488 static void
stunalloc(void * p)1489 stunalloc(void *p)
1490 {
1491 #if DEBUG
1492 	if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1493 		write(STDERR_FILENO, "stunalloc\n", 10);
1494 		abort();
1495 	}
1496 #endif
1497 	g_stacknleft += g_stacknxt - (char *)p;
1498 	g_stacknxt = p;
1499 }
1500 
1501 /*
1502  * Like strdup but works with the ash stack.
1503  */
1504 static char *
sstrdup(const char * p)1505 sstrdup(const char *p)
1506 {
1507 	size_t len = strlen(p) + 1;
1508 	return memcpy(stalloc(len), p, len);
1509 }
1510 
1511 static inline void
grabstackblock(size_t len)1512 grabstackblock(size_t len)
1513 {
1514 	stalloc(len);
1515 }
1516 
1517 static void
pushstackmark(struct stackmark * mark,size_t len)1518 pushstackmark(struct stackmark *mark, size_t len)
1519 {
1520 	mark->stackp = g_stackp;
1521 	mark->stacknxt = g_stacknxt;
1522 	mark->stacknleft = g_stacknleft;
1523 	grabstackblock(len);
1524 }
1525 
1526 static void
setstackmark(struct stackmark * mark)1527 setstackmark(struct stackmark *mark)
1528 {
1529 	pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1530 }
1531 
1532 static void
popstackmark(struct stackmark * mark)1533 popstackmark(struct stackmark *mark)
1534 {
1535 	struct stack_block *sp;
1536 
1537 	if (!mark->stackp)
1538 		return;
1539 
1540 	INT_OFF;
1541 	while (g_stackp != mark->stackp) {
1542 		sp = g_stackp;
1543 		g_stackp = sp->prev;
1544 		free(sp);
1545 	}
1546 	g_stacknxt = mark->stacknxt;
1547 	g_stacknleft = mark->stacknleft;
1548 	sstrend = mark->stacknxt + mark->stacknleft;
1549 	INT_ON;
1550 }
1551 
1552 /*
1553  * When the parser reads in a string, it wants to stick the string on the
1554  * stack and only adjust the stack pointer when it knows how big the
1555  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
1556  * of space on top of the stack and stackblocklen returns the length of
1557  * this block.  Growstackblock will grow this space by at least one byte,
1558  * possibly moving it (like realloc).  Grabstackblock actually allocates the
1559  * part of the block that has been used.
1560  */
1561 static void
growstackblock(void)1562 growstackblock(void)
1563 {
1564 	size_t newlen;
1565 
1566 	newlen = g_stacknleft * 2;
1567 	if (newlen < g_stacknleft)
1568 		ash_msg_and_raise_error(bb_msg_memory_exhausted);
1569 	if (newlen < 128)
1570 		newlen += 128;
1571 
1572 	if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1573 		struct stack_block *sp;
1574 		struct stack_block *prevstackp;
1575 		size_t grosslen;
1576 
1577 		INT_OFF;
1578 		sp = g_stackp;
1579 		prevstackp = sp->prev;
1580 		grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1581 		sp = ckrealloc(sp, grosslen);
1582 		sp->prev = prevstackp;
1583 		g_stackp = sp;
1584 		g_stacknxt = sp->space;
1585 		g_stacknleft = newlen;
1586 		sstrend = sp->space + newlen;
1587 		INT_ON;
1588 	} else {
1589 		char *oldspace = g_stacknxt;
1590 		size_t oldlen = g_stacknleft;
1591 		char *p = stalloc(newlen);
1592 
1593 		/* free the space we just allocated */
1594 		g_stacknxt = memcpy(p, oldspace, oldlen);
1595 		g_stacknleft += newlen;
1596 	}
1597 }
1598 
1599 /*
1600  * The following routines are somewhat easier to use than the above.
1601  * The user declares a variable of type STACKSTR, which may be declared
1602  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
1603  * the user uses the macro STPUTC to add characters to the string.  In
1604  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1605  * grown as necessary.  When the user is done, she can just leave the
1606  * string there and refer to it using stackblock().  Or she can allocate
1607  * the space for it using grabstackstr().  If it is necessary to allow
1608  * someone else to use the stack temporarily and then continue to grow
1609  * the string, the user should use grabstack to allocate the space, and
1610  * then call ungrabstr(p) to return to the previous mode of operation.
1611  *
1612  * USTPUTC is like STPUTC except that it doesn't check for overflow.
1613  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1614  * is space for at least one character.
1615  */
1616 static void *
growstackstr(void)1617 growstackstr(void)
1618 {
1619 	size_t len = stackblocksize();
1620 	growstackblock();
1621 	return (char *)stackblock() + len;
1622 }
1623 
1624 /*
1625  * Called from CHECKSTRSPACE.
1626  */
1627 static char *
makestrspace(size_t newlen,char * p)1628 makestrspace(size_t newlen, char *p)
1629 {
1630 	size_t len = p - g_stacknxt;
1631 	size_t size;
1632 
1633 	for (;;) {
1634 		size_t nleft;
1635 
1636 		size = stackblocksize();
1637 		nleft = size - len;
1638 		if (nleft >= newlen)
1639 			break;
1640 		growstackblock();
1641 	}
1642 	return (char *)stackblock() + len;
1643 }
1644 
1645 static char *
stack_nputstr(const char * s,size_t n,char * p)1646 stack_nputstr(const char *s, size_t n, char *p)
1647 {
1648 	p = makestrspace(n, p);
1649 	p = (char *)memcpy(p, s, n) + n;
1650 	return p;
1651 }
1652 
1653 static char *
stack_putstr(const char * s,char * p)1654 stack_putstr(const char *s, char *p)
1655 {
1656 	return stack_nputstr(s, strlen(s), p);
1657 }
1658 
1659 static char *
_STPUTC(int c,char * p)1660 _STPUTC(int c, char *p)
1661 {
1662 	if (p == sstrend)
1663 		p = growstackstr();
1664 	*p++ = c;
1665 	return p;
1666 }
1667 
1668 #define STARTSTACKSTR(p)        ((p) = stackblock())
1669 #define STPUTC(c, p)            ((p) = _STPUTC((c), (p)))
1670 #define CHECKSTRSPACE(n, p) do { \
1671 	char *q = (p); \
1672 	size_t l = (n); \
1673 	size_t m = sstrend - q; \
1674 	if (l > m) \
1675 		(p) = makestrspace(l, q); \
1676 } while (0)
1677 #define USTPUTC(c, p)           (*(p)++ = (c))
1678 #define STACKSTRNUL(p) do { \
1679 	if ((p) == sstrend) \
1680 		(p) = growstackstr(); \
1681 	*(p) = '\0'; \
1682 } while (0)
1683 #define STUNPUTC(p)             (--(p))
1684 #define STTOPC(p)               ((p)[-1])
1685 #define STADJUST(amount, p)     ((p) += (amount))
1686 
1687 #define grabstackstr(p)         stalloc((char *)(p) - (char *)stackblock())
1688 #define ungrabstackstr(s, p)    stunalloc(s)
1689 #define stackstrend()           ((void *)sstrend)
1690 
1691 
1692 /* ============ String helpers */
1693 
1694 /*
1695  * prefix -- see if pfx is a prefix of string.
1696  */
1697 static char *
prefix(const char * string,const char * pfx)1698 prefix(const char *string, const char *pfx)
1699 {
1700 	while (*pfx) {
1701 		if (*pfx++ != *string++)
1702 			return NULL;
1703 	}
1704 	return (char *) string;
1705 }
1706 
1707 /*
1708  * Check for a valid number.  This should be elsewhere.
1709  */
1710 static int
is_number(const char * p)1711 is_number(const char *p)
1712 {
1713 	do {
1714 		if (!isdigit(*p))
1715 			return 0;
1716 	} while (*++p != '\0');
1717 	return 1;
1718 }
1719 
1720 /*
1721  * Convert a string of digits to an integer, printing an error message on
1722  * failure.
1723  */
1724 static int
number(const char * s)1725 number(const char *s)
1726 {
1727 	if (!is_number(s))
1728 		ash_msg_and_raise_error(msg_illnum, s);
1729 	return atoi(s);
1730 }
1731 
1732 /*
1733  * Produce a possibly single quoted string suitable as input to the shell.
1734  * The return string is allocated on the stack.
1735  */
1736 static char *
single_quote(const char * s)1737 single_quote(const char *s)
1738 {
1739 	char *p;
1740 
1741 	STARTSTACKSTR(p);
1742 
1743 	do {
1744 		char *q;
1745 		size_t len;
1746 
1747 		len = strchrnul(s, '\'') - s;
1748 
1749 		q = p = makestrspace(len + 3, p);
1750 
1751 		*q++ = '\'';
1752 		q = (char *)memcpy(q, s, len) + len;
1753 		*q++ = '\'';
1754 		s += len;
1755 
1756 		STADJUST(q - p, p);
1757 
1758 		if (*s != '\'')
1759 			break;
1760 		len = 0;
1761 		do len++; while (*++s == '\'');
1762 
1763 		q = p = makestrspace(len + 3, p);
1764 
1765 		*q++ = '"';
1766 		q = (char *)memcpy(q, s - len, len) + len;
1767 		*q++ = '"';
1768 
1769 		STADJUST(q - p, p);
1770 	} while (*s);
1771 
1772 	USTPUTC('\0', p);
1773 
1774 	return stackblock();
1775 }
1776 
1777 
1778 /* ============ nextopt */
1779 
1780 static char **argptr;                  /* argument list for builtin commands */
1781 static char *optionarg;                /* set by nextopt (like getopt) */
1782 static char *optptr;                   /* used by nextopt */
1783 
1784 /*
1785  * XXX - should get rid of. Have all builtins use getopt(3).
1786  * The library getopt must have the BSD extension static variable
1787  * "optreset", otherwise it can't be used within the shell safely.
1788  *
1789  * Standard option processing (a la getopt) for builtin routines.
1790  * The only argument that is passed to nextopt is the option string;
1791  * the other arguments are unnecessary. It returns the character,
1792  * or '\0' on end of input.
1793  */
1794 static int
nextopt(const char * optstring)1795 nextopt(const char *optstring)
1796 {
1797 	char *p;
1798 	const char *q;
1799 	char c;
1800 
1801 	p = optptr;
1802 	if (p == NULL || *p == '\0') {
1803 		/* We ate entire "-param", take next one */
1804 		p = *argptr;
1805 		if (p == NULL)
1806 			return '\0';
1807 		if (*p != '-')
1808 			return '\0';
1809 		if (*++p == '\0') /* just "-" ? */
1810 			return '\0';
1811 		argptr++;
1812 		if (LONE_DASH(p)) /* "--" ? */
1813 			return '\0';
1814 		/* p => next "-param" */
1815 	}
1816 	/* p => some option char in the middle of a "-param" */
1817 	c = *p++;
1818 	for (q = optstring; *q != c;) {
1819 		if (*q == '\0')
1820 			ash_msg_and_raise_error("illegal option -%c", c);
1821 		if (*++q == ':')
1822 			q++;
1823 	}
1824 	if (*++q == ':') {
1825 		if (*p == '\0') {
1826 			p = *argptr++;
1827 			if (p == NULL)
1828 				ash_msg_and_raise_error("no arg for -%c option", c);
1829 		}
1830 		optionarg = p;
1831 		p = NULL;
1832 	}
1833 	optptr = p;
1834 	return c;
1835 }
1836 
1837 
1838 /* ============ Shell variables */
1839 
1840 /*
1841  * The parsefile structure pointed to by the global variable parsefile
1842  * contains information about the current file being read.
1843  */
1844 struct shparam {
1845 	int nparam;             /* # of positional parameters (without $0) */
1846 #if ENABLE_ASH_GETOPTS
1847 	int optind;             /* next parameter to be processed by getopts */
1848 	int optoff;             /* used by getopts */
1849 #endif
1850 	unsigned char malloced; /* if parameter list dynamically allocated */
1851 	char **p;               /* parameter list */
1852 };
1853 
1854 /*
1855  * Free the list of positional parameters.
1856  */
1857 static void
freeparam(volatile struct shparam * param)1858 freeparam(volatile struct shparam *param)
1859 {
1860 	if (param->malloced) {
1861 		char **ap, **ap1;
1862 		ap = ap1 = param->p;
1863 		while (*ap)
1864 			free(*ap++);
1865 		free(ap1);
1866 	}
1867 }
1868 
1869 #if ENABLE_ASH_GETOPTS
1870 static void FAST_FUNC getoptsreset(const char *value);
1871 #endif
1872 
1873 struct var {
1874 	struct var *next;               /* next entry in hash list */
1875 	int flags;                      /* flags are defined above */
1876 	const char *var_text;           /* name=value */
1877 	void (*var_func)(const char *) FAST_FUNC; /* function to be called when  */
1878 					/* the variable gets set/unset */
1879 };
1880 
1881 struct localvar {
1882 	struct localvar *next;          /* next local variable in list */
1883 	struct var *vp;                 /* the variable that was made local */
1884 	int flags;                      /* saved flags */
1885 	const char *text;               /* saved text */
1886 };
1887 
1888 /* flags */
1889 #define VEXPORT         0x01    /* variable is exported */
1890 #define VREADONLY       0x02    /* variable cannot be modified */
1891 #define VSTRFIXED       0x04    /* variable struct is statically allocated */
1892 #define VTEXTFIXED      0x08    /* text is statically allocated */
1893 #define VSTACK          0x10    /* text is allocated on the stack */
1894 #define VUNSET          0x20    /* the variable is not set */
1895 #define VNOFUNC         0x40    /* don't call the callback function */
1896 #define VNOSET          0x80    /* do not set variable - just readonly test */
1897 #define VNOSAVE         0x100   /* when text is on the heap before setvareq */
1898 #if ENABLE_ASH_RANDOM_SUPPORT
1899 # define VDYNAMIC       0x200   /* dynamic variable */
1900 #else
1901 # define VDYNAMIC       0
1902 #endif
1903 
1904 
1905 /* Need to be before varinit_data[] */
1906 #if ENABLE_LOCALE_SUPPORT
1907 static void FAST_FUNC
change_lc_all(const char * value)1908 change_lc_all(const char *value)
1909 {
1910 	if (value && *value != '\0')
1911 		setlocale(LC_ALL, value);
1912 }
1913 static void FAST_FUNC
change_lc_ctype(const char * value)1914 change_lc_ctype(const char *value)
1915 {
1916 	if (value && *value != '\0')
1917 		setlocale(LC_CTYPE, value);
1918 }
1919 #endif
1920 #if ENABLE_ASH_MAIL
1921 static void chkmail(void);
1922 static void changemail(const char *var_value) FAST_FUNC;
1923 #else
1924 # define chkmail()  ((void)0)
1925 #endif
1926 static void changepath(const char *) FAST_FUNC;
1927 #if ENABLE_ASH_RANDOM_SUPPORT
1928 static void change_random(const char *) FAST_FUNC;
1929 #endif
1930 
1931 static const struct {
1932 	int flags;
1933 	const char *var_text;
1934 	void (*var_func)(const char *) FAST_FUNC;
1935 } varinit_data[] = {
1936 	/*
1937 	 * Note: VEXPORT would not work correctly here for NOFORK applets:
1938 	 * some environment strings may be constant.
1939 	 */
1940 	{ VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
1941 #if ENABLE_ASH_MAIL
1942 	{ VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL"      , changemail      },
1943 	{ VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH"  , changemail      },
1944 #endif
1945 	{ VSTRFIXED|VTEXTFIXED       , bb_PATH_root_path, changepath },
1946 	{ VSTRFIXED|VTEXTFIXED       , "PS1=$ "    , NULL            },
1947 	{ VSTRFIXED|VTEXTFIXED       , "PS2=> "    , NULL            },
1948 	{ VSTRFIXED|VTEXTFIXED       , "PS4=+ "    , NULL            },
1949 #if ENABLE_ASH_GETOPTS
1950 	{ VSTRFIXED|VTEXTFIXED       , defoptindvar, getoptsreset    },
1951 #endif
1952 #if ENABLE_ASH_RANDOM_SUPPORT
1953 	{ VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
1954 #endif
1955 #if ENABLE_LOCALE_SUPPORT
1956 	{ VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL"    , change_lc_all   },
1957 	{ VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE"  , change_lc_ctype },
1958 #endif
1959 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1960 	{ VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE"  , NULL            },
1961 #endif
1962 };
1963 
1964 struct redirtab;
1965 
1966 struct globals_var {
1967 	struct shparam shellparam;      /* $@ current positional parameters */
1968 	struct redirtab *redirlist;
1969 	int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
1970 	struct var *vartab[VTABSIZE];
1971 	struct var varinit[ARRAY_SIZE(varinit_data)];
1972 };
1973 extern struct globals_var *const ash_ptr_to_globals_var;
1974 #define G_var (*ash_ptr_to_globals_var)
1975 #define shellparam    (G_var.shellparam   )
1976 //#define redirlist     (G_var.redirlist    )
1977 #define preverrout_fd (G_var.preverrout_fd)
1978 #define vartab        (G_var.vartab       )
1979 #define varinit       (G_var.varinit      )
1980 #define INIT_G_var() do { \
1981 	unsigned i; \
1982 	(*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1983 	barrier(); \
1984 	for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1985 		varinit[i].flags    = varinit_data[i].flags; \
1986 		varinit[i].var_text = varinit_data[i].var_text; \
1987 		varinit[i].var_func = varinit_data[i].var_func; \
1988 	} \
1989 } while (0)
1990 
1991 #define vifs      varinit[0]
1992 #if ENABLE_ASH_MAIL
1993 # define vmail    (&vifs)[1]
1994 # define vmpath   (&vmail)[1]
1995 # define vpath    (&vmpath)[1]
1996 #else
1997 # define vpath    (&vifs)[1]
1998 #endif
1999 #define vps1      (&vpath)[1]
2000 #define vps2      (&vps1)[1]
2001 #define vps4      (&vps2)[1]
2002 #if ENABLE_ASH_GETOPTS
2003 # define voptind  (&vps4)[1]
2004 # if ENABLE_ASH_RANDOM_SUPPORT
2005 #  define vrandom (&voptind)[1]
2006 # endif
2007 #else
2008 # if ENABLE_ASH_RANDOM_SUPPORT
2009 #  define vrandom (&vps4)[1]
2010 # endif
2011 #endif
2012 
2013 /*
2014  * The following macros access the values of the above variables.
2015  * They have to skip over the name.  They return the null string
2016  * for unset variables.
2017  */
2018 #define ifsval()        (vifs.var_text + 4)
2019 #define ifsset()        ((vifs.flags & VUNSET) == 0)
2020 #if ENABLE_ASH_MAIL
2021 # define mailval()      (vmail.var_text + 5)
2022 # define mpathval()     (vmpath.var_text + 9)
2023 # define mpathset()     ((vmpath.flags & VUNSET) == 0)
2024 #endif
2025 #define pathval()       (vpath.var_text + 5)
2026 #define ps1val()        (vps1.var_text + 4)
2027 #define ps2val()        (vps2.var_text + 4)
2028 #define ps4val()        (vps4.var_text + 4)
2029 #if ENABLE_ASH_GETOPTS
2030 # define optindval()    (voptind.var_text + 7)
2031 #endif
2032 
2033 #if ENABLE_ASH_GETOPTS
2034 static void FAST_FUNC
getoptsreset(const char * value)2035 getoptsreset(const char *value)
2036 {
2037 	shellparam.optind = number(value) ?: 1;
2038 	shellparam.optoff = -1;
2039 }
2040 #endif
2041 
2042 /*
2043  * Compares two strings up to the first = or '\0'.  The first
2044  * string must be terminated by '='; the second may be terminated by
2045  * either '=' or '\0'.
2046  */
2047 static int
varcmp(const char * p,const char * q)2048 varcmp(const char *p, const char *q)
2049 {
2050 	int c, d;
2051 
2052 	while ((c = *p) == (d = *q)) {
2053 		if (c == '\0' || c == '=')
2054 			goto out;
2055 		p++;
2056 		q++;
2057 	}
2058 	if (c == '=')
2059 		c = '\0';
2060 	if (d == '=')
2061 		d = '\0';
2062  out:
2063 	return c - d;
2064 }
2065 
2066 /*
2067  * Find the appropriate entry in the hash table from the name.
2068  */
2069 static struct var **
hashvar(const char * p)2070 hashvar(const char *p)
2071 {
2072 	unsigned hashval;
2073 
2074 	hashval = ((unsigned char) *p) << 4;
2075 	while (*p && *p != '=')
2076 		hashval += (unsigned char) *p++;
2077 	return &vartab[hashval % VTABSIZE];
2078 }
2079 
2080 static int
vpcmp(const void * a,const void * b)2081 vpcmp(const void *a, const void *b)
2082 {
2083 	return varcmp(*(const char **)a, *(const char **)b);
2084 }
2085 
2086 /*
2087  * This routine initializes the builtin variables.
2088  */
2089 static void
initvar(void)2090 initvar(void)
2091 {
2092 	struct var *vp;
2093 	struct var *end;
2094 	struct var **vpp;
2095 
2096 	/*
2097 	 * PS1 depends on uid
2098 	 */
2099 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2100 	vps1.var_text = "PS1=\\w \\$ ";
2101 #else
2102 	if (!geteuid())
2103 		vps1.var_text = "PS1=# ";
2104 #endif
2105 	vp = varinit;
2106 	end = vp + ARRAY_SIZE(varinit);
2107 	do {
2108 		vpp = hashvar(vp->var_text);
2109 		vp->next = *vpp;
2110 		*vpp = vp;
2111 	} while (++vp < end);
2112 }
2113 
2114 static struct var **
findvar(struct var ** vpp,const char * name)2115 findvar(struct var **vpp, const char *name)
2116 {
2117 	for (; *vpp; vpp = &(*vpp)->next) {
2118 		if (varcmp((*vpp)->var_text, name) == 0) {
2119 			break;
2120 		}
2121 	}
2122 	return vpp;
2123 }
2124 
2125 /*
2126  * Find the value of a variable.  Returns NULL if not set.
2127  */
2128 static const char* FAST_FUNC
lookupvar(const char * name)2129 lookupvar(const char *name)
2130 {
2131 	struct var *v;
2132 
2133 	v = *findvar(hashvar(name), name);
2134 	if (v) {
2135 #if ENABLE_ASH_RANDOM_SUPPORT
2136 	/*
2137 	 * Dynamic variables are implemented roughly the same way they are
2138 	 * in bash. Namely, they're "special" so long as they aren't unset.
2139 	 * As soon as they're unset, they're no longer dynamic, and dynamic
2140 	 * lookup will no longer happen at that point. -- PFM.
2141 	 */
2142 		if (v->flags & VDYNAMIC)
2143 			v->var_func(NULL);
2144 #endif
2145 		if (!(v->flags & VUNSET))
2146 			return var_end(v->var_text);
2147 	}
2148 	return NULL;
2149 }
2150 
2151 #if ENABLE_UNICODE_SUPPORT
2152 static void
reinit_unicode_for_ash(void)2153 reinit_unicode_for_ash(void)
2154 {
2155 	/* Unicode support should be activated even if LANG is set
2156 	 * _during_ shell execution, not only if it was set when
2157 	 * shell was started. Therefore, re-check LANG every time:
2158 	 */
2159 	if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2160 	 || ENABLE_UNICODE_USING_LOCALE
2161 	) {
2162 		const char *s = lookupvar("LC_ALL");
2163 		if (!s) s = lookupvar("LC_CTYPE");
2164 		if (!s) s = lookupvar("LANG");
2165 		reinit_unicode(s);
2166 	}
2167 }
2168 #else
2169 # define reinit_unicode_for_ash() ((void)0)
2170 #endif
2171 
2172 /*
2173  * Search the environment of a builtin command.
2174  */
2175 static const char *
bltinlookup(const char * name)2176 bltinlookup(const char *name)
2177 {
2178 	struct strlist *sp;
2179 
2180 	for (sp = cmdenviron; sp; sp = sp->next) {
2181 		if (varcmp(sp->text, name) == 0)
2182 			return var_end(sp->text);
2183 	}
2184 	return lookupvar(name);
2185 }
2186 
2187 /*
2188  * Same as setvar except that the variable and value are passed in
2189  * the first argument as name=value.  Since the first argument will
2190  * be actually stored in the table, it should not be a string that
2191  * will go away.
2192  * Called with interrupts off.
2193  */
2194 static void
setvareq(char * s,int flags)2195 setvareq(char *s, int flags)
2196 {
2197 	struct var *vp, **vpp;
2198 
2199 	vpp = hashvar(s);
2200 	flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2201 	vp = *findvar(vpp, s);
2202 	if (vp) {
2203 		if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2204 			const char *n;
2205 
2206 			if (flags & VNOSAVE)
2207 				free(s);
2208 			n = vp->var_text;
2209 			exitstatus = 1;
2210 			ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2211 		}
2212 
2213 		if (flags & VNOSET)
2214 			return;
2215 
2216 		if (vp->var_func && !(flags & VNOFUNC))
2217 			vp->var_func(var_end(s));
2218 
2219 		if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2220 			free((char*)vp->var_text);
2221 
2222 		flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2223 	} else {
2224 		/* variable s is not found */
2225 		if (flags & VNOSET)
2226 			return;
2227 		vp = ckzalloc(sizeof(*vp));
2228 		vp->next = *vpp;
2229 		/*vp->func = NULL; - ckzalloc did it */
2230 		*vpp = vp;
2231 	}
2232 	if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2233 		s = ckstrdup(s);
2234 	vp->var_text = s;
2235 	vp->flags = flags;
2236 }
2237 
2238 /*
2239  * Set the value of a variable.  The flags argument is ored with the
2240  * flags of the variable.  If val is NULL, the variable is unset.
2241  */
2242 static void
setvar(const char * name,const char * val,int flags)2243 setvar(const char *name, const char *val, int flags)
2244 {
2245 	const char *q;
2246 	char *p;
2247 	char *nameeq;
2248 	size_t namelen;
2249 	size_t vallen;
2250 
2251 	q = endofname(name);
2252 	p = strchrnul(q, '=');
2253 	namelen = p - name;
2254 	if (!namelen || p != q)
2255 		ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2256 	vallen = 0;
2257 	if (val == NULL) {
2258 		flags |= VUNSET;
2259 	} else {
2260 		vallen = strlen(val);
2261 	}
2262 
2263 	INT_OFF;
2264 	nameeq = ckmalloc(namelen + vallen + 2);
2265 	p = memcpy(nameeq, name, namelen) + namelen;
2266 	if (val) {
2267 		*p++ = '=';
2268 		p = memcpy(p, val, vallen) + vallen;
2269 	}
2270 	*p = '\0';
2271 	setvareq(nameeq, flags | VNOSAVE);
2272 	INT_ON;
2273 }
2274 
2275 static void FAST_FUNC
setvar0(const char * name,const char * val)2276 setvar0(const char *name, const char *val)
2277 {
2278 	setvar(name, val, 0);
2279 }
2280 
2281 /*
2282  * Unset the specified variable.
2283  */
2284 static int
unsetvar(const char * s)2285 unsetvar(const char *s)
2286 {
2287 	struct var **vpp;
2288 	struct var *vp;
2289 	int retval;
2290 
2291 	vpp = findvar(hashvar(s), s);
2292 	vp = *vpp;
2293 	retval = 2;
2294 	if (vp) {
2295 		int flags = vp->flags;
2296 
2297 		retval = 1;
2298 		if (flags & VREADONLY)
2299 			goto out;
2300 #if ENABLE_ASH_RANDOM_SUPPORT
2301 		vp->flags &= ~VDYNAMIC;
2302 #endif
2303 		if (flags & VUNSET)
2304 			goto ok;
2305 		if ((flags & VSTRFIXED) == 0) {
2306 			INT_OFF;
2307 			if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2308 				free((char*)vp->var_text);
2309 			*vpp = vp->next;
2310 			free(vp);
2311 			INT_ON;
2312 		} else {
2313 			setvar0(s, NULL);
2314 			vp->flags &= ~VEXPORT;
2315 		}
2316  ok:
2317 		retval = 0;
2318 	}
2319  out:
2320 	return retval;
2321 }
2322 
2323 /*
2324  * Process a linked list of variable assignments.
2325  */
2326 static void
listsetvar(struct strlist * list_set_var,int flags)2327 listsetvar(struct strlist *list_set_var, int flags)
2328 {
2329 	struct strlist *lp = list_set_var;
2330 
2331 	if (!lp)
2332 		return;
2333 	INT_OFF;
2334 	do {
2335 		setvareq(lp->text, flags);
2336 		lp = lp->next;
2337 	} while (lp);
2338 	INT_ON;
2339 }
2340 
2341 /*
2342  * Generate a list of variables satisfying the given conditions.
2343  */
2344 static char **
listvars(int on,int off,char *** end)2345 listvars(int on, int off, char ***end)
2346 {
2347 	struct var **vpp;
2348 	struct var *vp;
2349 	char **ep;
2350 	int mask;
2351 
2352 	STARTSTACKSTR(ep);
2353 	vpp = vartab;
2354 	mask = on | off;
2355 	do {
2356 		for (vp = *vpp; vp; vp = vp->next) {
2357 			if ((vp->flags & mask) == on) {
2358 				if (ep == stackstrend())
2359 					ep = growstackstr();
2360 				*ep++ = (char*)vp->var_text;
2361 			}
2362 		}
2363 	} while (++vpp < vartab + VTABSIZE);
2364 	if (ep == stackstrend())
2365 		ep = growstackstr();
2366 	if (end)
2367 		*end = ep;
2368 	*ep++ = NULL;
2369 	return grabstackstr(ep);
2370 }
2371 
2372 
2373 /* ============ Path search helper
2374  *
2375  * The variable path (passed by reference) should be set to the start
2376  * of the path before the first call; path_advance will update
2377  * this value as it proceeds.  Successive calls to path_advance will return
2378  * the possible path expansions in sequence.  If an option (indicated by
2379  * a percent sign) appears in the path entry then the global variable
2380  * pathopt will be set to point to it; otherwise pathopt will be set to
2381  * NULL.
2382  */
2383 static const char *pathopt;     /* set by path_advance */
2384 
2385 static char *
path_advance(const char ** path,const char * name)2386 path_advance(const char **path, const char *name)
2387 {
2388 	const char *p;
2389 	char *q;
2390 	const char *start;
2391 	size_t len;
2392 
2393 	if (*path == NULL)
2394 		return NULL;
2395 	start = *path;
2396 	for (p = start; *p && *p != ':' && *p != '%'; p++)
2397 		continue;
2398 	len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
2399 	while (stackblocksize() < len)
2400 		growstackblock();
2401 	q = stackblock();
2402 	if (p != start) {
2403 		memcpy(q, start, p - start);
2404 		q += p - start;
2405 		*q++ = '/';
2406 	}
2407 	strcpy(q, name);
2408 	pathopt = NULL;
2409 	if (*p == '%') {
2410 		pathopt = ++p;
2411 		while (*p && *p != ':')
2412 			p++;
2413 	}
2414 	if (*p == ':')
2415 		*path = p + 1;
2416 	else
2417 		*path = NULL;
2418 	return stalloc(len);
2419 }
2420 
2421 
2422 /* ============ Prompt */
2423 
2424 static smallint doprompt;                   /* if set, prompt the user */
2425 static smallint needprompt;                 /* true if interactive and at start of line */
2426 
2427 #if ENABLE_FEATURE_EDITING
2428 static line_input_t *line_input_state;
2429 static const char *cmdedit_prompt;
2430 static void
putprompt(const char * s)2431 putprompt(const char *s)
2432 {
2433 	if (ENABLE_ASH_EXPAND_PRMT) {
2434 		free((char*)cmdedit_prompt);
2435 		cmdedit_prompt = ckstrdup(s);
2436 		return;
2437 	}
2438 	cmdedit_prompt = s;
2439 }
2440 #else
2441 static void
putprompt(const char * s)2442 putprompt(const char *s)
2443 {
2444 	out2str(s);
2445 }
2446 #endif
2447 
2448 #if ENABLE_ASH_EXPAND_PRMT
2449 /* expandstr() needs parsing machinery, so it is far away ahead... */
2450 static const char *expandstr(const char *ps);
2451 #else
2452 #define expandstr(s) s
2453 #endif
2454 
2455 static void
setprompt_if(smallint do_set,int whichprompt)2456 setprompt_if(smallint do_set, int whichprompt)
2457 {
2458 	const char *prompt;
2459 	IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2460 
2461 	if (!do_set)
2462 		return;
2463 
2464 	needprompt = 0;
2465 
2466 	switch (whichprompt) {
2467 	case 1:
2468 		prompt = ps1val();
2469 		break;
2470 	case 2:
2471 		prompt = ps2val();
2472 		break;
2473 	default:                        /* 0 */
2474 		prompt = nullstr;
2475 	}
2476 #if ENABLE_ASH_EXPAND_PRMT
2477 	pushstackmark(&smark, stackblocksize());
2478 #endif
2479 	putprompt(expandstr(prompt));
2480 #if ENABLE_ASH_EXPAND_PRMT
2481 	popstackmark(&smark);
2482 #endif
2483 }
2484 
2485 
2486 /* ============ The cd and pwd commands */
2487 
2488 #define CD_PHYSICAL 1
2489 #define CD_PRINT 2
2490 
2491 static int
cdopt(void)2492 cdopt(void)
2493 {
2494 	int flags = 0;
2495 	int i, j;
2496 
2497 	j = 'L';
2498 	while ((i = nextopt("LP")) != '\0') {
2499 		if (i != j) {
2500 			flags ^= CD_PHYSICAL;
2501 			j = i;
2502 		}
2503 	}
2504 
2505 	return flags;
2506 }
2507 
2508 /*
2509  * Update curdir (the name of the current directory) in response to a
2510  * cd command.
2511  */
2512 static const char *
updatepwd(const char * dir)2513 updatepwd(const char *dir)
2514 {
2515 	char *new;
2516 	char *p;
2517 	char *cdcomppath;
2518 	const char *lim;
2519 
2520 	cdcomppath = sstrdup(dir);
2521 	STARTSTACKSTR(new);
2522 	if (*dir != '/') {
2523 		if (curdir == nullstr)
2524 			return 0;
2525 		new = stack_putstr(curdir, new);
2526 	}
2527 	new = makestrspace(strlen(dir) + 2, new);
2528 	lim = (char *)stackblock() + 1;
2529 	if (*dir != '/') {
2530 		if (new[-1] != '/')
2531 			USTPUTC('/', new);
2532 		if (new > lim && *lim == '/')
2533 			lim++;
2534 	} else {
2535 		USTPUTC('/', new);
2536 		cdcomppath++;
2537 		if (dir[1] == '/' && dir[2] != '/') {
2538 			USTPUTC('/', new);
2539 			cdcomppath++;
2540 			lim++;
2541 		}
2542 	}
2543 	p = strtok(cdcomppath, "/");
2544 	while (p) {
2545 		switch (*p) {
2546 		case '.':
2547 			if (p[1] == '.' && p[2] == '\0') {
2548 				while (new > lim) {
2549 					STUNPUTC(new);
2550 					if (new[-1] == '/')
2551 						break;
2552 				}
2553 				break;
2554 			}
2555 			if (p[1] == '\0')
2556 				break;
2557 			/* fall through */
2558 		default:
2559 			new = stack_putstr(p, new);
2560 			USTPUTC('/', new);
2561 		}
2562 		p = strtok(NULL, "/");
2563 	}
2564 	if (new > lim)
2565 		STUNPUTC(new);
2566 	*new = 0;
2567 	return stackblock();
2568 }
2569 
2570 /*
2571  * Find out what the current directory is. If we already know the current
2572  * directory, this routine returns immediately.
2573  */
2574 static char *
getpwd(void)2575 getpwd(void)
2576 {
2577 	char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2578 	return dir ? dir : nullstr;
2579 }
2580 
2581 static void
setpwd(const char * val,int setold)2582 setpwd(const char *val, int setold)
2583 {
2584 	char *oldcur, *dir;
2585 
2586 	oldcur = dir = curdir;
2587 
2588 	if (setold) {
2589 		setvar("OLDPWD", oldcur, VEXPORT);
2590 	}
2591 	INT_OFF;
2592 	if (physdir != nullstr) {
2593 		if (physdir != oldcur)
2594 			free(physdir);
2595 		physdir = nullstr;
2596 	}
2597 	if (oldcur == val || !val) {
2598 		char *s = getpwd();
2599 		physdir = s;
2600 		if (!val)
2601 			dir = s;
2602 	} else
2603 		dir = ckstrdup(val);
2604 	if (oldcur != dir && oldcur != nullstr) {
2605 		free(oldcur);
2606 	}
2607 	curdir = dir;
2608 	INT_ON;
2609 	setvar("PWD", dir, VEXPORT);
2610 }
2611 
2612 static void hashcd(void);
2613 
2614 /*
2615  * Actually do the chdir.  We also call hashcd to let other routines
2616  * know that the current directory has changed.
2617  */
2618 static int
docd(const char * dest,int flags)2619 docd(const char *dest, int flags)
2620 {
2621 	const char *dir = NULL;
2622 	int err;
2623 
2624 	TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2625 
2626 	INT_OFF;
2627 	if (!(flags & CD_PHYSICAL)) {
2628 		dir = updatepwd(dest);
2629 		if (dir)
2630 			dest = dir;
2631 	}
2632 	err = chdir(dest);
2633 	if (err)
2634 		goto out;
2635 	setpwd(dir, 1);
2636 	hashcd();
2637  out:
2638 	INT_ON;
2639 	return err;
2640 }
2641 
2642 static int FAST_FUNC
cdcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)2643 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2644 {
2645 	const char *dest;
2646 	const char *path;
2647 	const char *p;
2648 	char c;
2649 	struct stat statb;
2650 	int flags;
2651 
2652 	flags = cdopt();
2653 	dest = *argptr;
2654 	if (!dest)
2655 		dest = bltinlookup("HOME");
2656 	else if (LONE_DASH(dest)) {
2657 		dest = bltinlookup("OLDPWD");
2658 		flags |= CD_PRINT;
2659 	}
2660 	if (!dest)
2661 		dest = nullstr;
2662 	if (*dest == '/')
2663 		goto step6;
2664 	if (*dest == '.') {
2665 		c = dest[1];
2666  dotdot:
2667 		switch (c) {
2668 		case '\0':
2669 		case '/':
2670 			goto step6;
2671 		case '.':
2672 			c = dest[2];
2673 			if (c != '.')
2674 				goto dotdot;
2675 		}
2676 	}
2677 	if (!*dest)
2678 		dest = ".";
2679 	path = bltinlookup("CDPATH");
2680 	while (path) {
2681 		c = *path;
2682 		p = path_advance(&path, dest);
2683 		if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2684 			if (c && c != ':')
2685 				flags |= CD_PRINT;
2686  docd:
2687 			if (!docd(p, flags))
2688 				goto out;
2689 			goto err;
2690 		}
2691 	}
2692 
2693  step6:
2694 	p = dest;
2695 	goto docd;
2696 
2697  err:
2698 	ash_msg_and_raise_error("can't cd to %s", dest);
2699 	/* NOTREACHED */
2700  out:
2701 	if (flags & CD_PRINT)
2702 		out1fmt("%s\n", curdir);
2703 	return 0;
2704 }
2705 
2706 static int FAST_FUNC
pwdcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)2707 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2708 {
2709 	int flags;
2710 	const char *dir = curdir;
2711 
2712 	flags = cdopt();
2713 	if (flags) {
2714 		if (physdir == nullstr)
2715 			setpwd(dir, 0);
2716 		dir = physdir;
2717 	}
2718 	out1fmt("%s\n", dir);
2719 	return 0;
2720 }
2721 
2722 
2723 /* ============ ... */
2724 
2725 
2726 #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2727 
2728 /* Syntax classes */
2729 #define CWORD     0             /* character is nothing special */
2730 #define CNL       1             /* newline character */
2731 #define CBACK     2             /* a backslash character */
2732 #define CSQUOTE   3             /* single quote */
2733 #define CDQUOTE   4             /* double quote */
2734 #define CENDQUOTE 5             /* a terminating quote */
2735 #define CBQUOTE   6             /* backwards single quote */
2736 #define CVAR      7             /* a dollar sign */
2737 #define CENDVAR   8             /* a '}' character */
2738 #define CLP       9             /* a left paren in arithmetic */
2739 #define CRP      10             /* a right paren in arithmetic */
2740 #define CENDFILE 11             /* end of file */
2741 #define CCTL     12             /* like CWORD, except it must be escaped */
2742 #define CSPCL    13             /* these terminate a word */
2743 #define CIGN     14             /* character should be ignored */
2744 
2745 #define PEOF     256
2746 #if ENABLE_ASH_ALIAS
2747 # define PEOA    257
2748 #endif
2749 
2750 #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2751 
2752 #if ENABLE_FEATURE_SH_MATH
2753 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2754 #else
2755 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2756 #endif
2757 static const uint16_t S_I_T[] ALIGN2 = {
2758 #if ENABLE_ASH_ALIAS
2759 	SIT_ITEM(CSPCL   , CIGN     , CIGN , CIGN   ),    /* 0, PEOA */
2760 #endif
2761 	SIT_ITEM(CSPCL   , CWORD    , CWORD, CWORD  ),    /* 1, ' ' */
2762 	SIT_ITEM(CNL     , CNL      , CNL  , CNL    ),    /* 2, \n */
2763 	SIT_ITEM(CWORD   , CCTL     , CCTL , CWORD  ),    /* 3, !*-/:=?[]~ */
2764 	SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD  ),    /* 4, '"' */
2765 	SIT_ITEM(CVAR    , CVAR     , CWORD, CVAR   ),    /* 5, $ */
2766 	SIT_ITEM(CSQUOTE , CWORD    , CENDQUOTE, CWORD),  /* 6, "'" */
2767 	SIT_ITEM(CSPCL   , CWORD    , CWORD, CLP    ),    /* 7, ( */
2768 	SIT_ITEM(CSPCL   , CWORD    , CWORD, CRP    ),    /* 8, ) */
2769 	SIT_ITEM(CBACK   , CBACK    , CCTL , CBACK  ),    /* 9, \ */
2770 	SIT_ITEM(CBQUOTE , CBQUOTE  , CWORD, CBQUOTE),    /* 10, ` */
2771 	SIT_ITEM(CENDVAR , CENDVAR  , CWORD, CENDVAR),    /* 11, } */
2772 #if !USE_SIT_FUNCTION
2773 	SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2774 	SIT_ITEM(CWORD   , CWORD    , CWORD, CWORD  ),    /* 13, 0-9A-Za-z */
2775 	SIT_ITEM(CCTL    , CCTL     , CCTL , CCTL   )     /* 14, CTLESC ... */
2776 #endif
2777 #undef SIT_ITEM
2778 };
2779 /* Constants below must match table above */
2780 enum {
2781 #if ENABLE_ASH_ALIAS
2782 	CSPCL_CIGN_CIGN_CIGN               , /*  0 */
2783 #endif
2784 	CSPCL_CWORD_CWORD_CWORD            , /*  1 */
2785 	CNL_CNL_CNL_CNL                    , /*  2 */
2786 	CWORD_CCTL_CCTL_CWORD              , /*  3 */
2787 	CDQUOTE_CENDQUOTE_CWORD_CWORD      , /*  4 */
2788 	CVAR_CVAR_CWORD_CVAR               , /*  5 */
2789 	CSQUOTE_CWORD_CENDQUOTE_CWORD      , /*  6 */
2790 	CSPCL_CWORD_CWORD_CLP              , /*  7 */
2791 	CSPCL_CWORD_CWORD_CRP              , /*  8 */
2792 	CBACK_CBACK_CCTL_CBACK             , /*  9 */
2793 	CBQUOTE_CBQUOTE_CWORD_CBQUOTE      , /* 10 */
2794 	CENDVAR_CENDVAR_CWORD_CENDVAR      , /* 11 */
2795 	CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2796 	CWORD_CWORD_CWORD_CWORD            , /* 13 */
2797 	CCTL_CCTL_CCTL_CCTL                , /* 14 */
2798 };
2799 
2800 /* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2801  * caller must ensure proper cast on it if c is *char_ptr!
2802  */
2803 /* Values for syntax param */
2804 #define BASESYNTAX 0    /* not in quotes */
2805 #define DQSYNTAX   1    /* in double quotes */
2806 #define SQSYNTAX   2    /* in single quotes */
2807 #define ARISYNTAX  3    /* in arithmetic */
2808 #define PSSYNTAX   4    /* prompt. never passed to SIT() */
2809 
2810 #if USE_SIT_FUNCTION
2811 
2812 static int
SIT(int c,int syntax)2813 SIT(int c, int syntax)
2814 {
2815 	/* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2816 	static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2817 	/*
2818 	 * This causes '/' to be prepended with CTLESC in dquoted string,
2819 	 * making "./file"* treated incorrectly because we feed
2820 	 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2821 	 * The "homegrown" glob implementation is okay with that,
2822 	 * but glibc one isn't. With '/' always treated as CWORD,
2823 	 * both work fine.
2824 	 */
2825 # if ENABLE_ASH_ALIAS
2826 	static const uint8_t syntax_index_table[] ALIGN1 = {
2827 		1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
2828 		7, 8, 3, 3,/*3,*/3, 1, 1,       /* "()*-/:;<" */
2829 		3, 1, 3, 3, 9, 3, 10, 1,        /* "=>?[\\]`|" */
2830 		11, 3                           /* "}~" */
2831 	};
2832 # else
2833 	static const uint8_t syntax_index_table[] ALIGN1 = {
2834 		0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
2835 		6, 7, 2, 2,/*2,*/2, 0, 0,       /* "()*-/:;<" */
2836 		2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
2837 		10, 2                           /* "}~" */
2838 	};
2839 # endif
2840 	const char *s;
2841 	int indx;
2842 
2843 	if (c == PEOF)
2844 		return CENDFILE;
2845 # if ENABLE_ASH_ALIAS
2846 	if (c == PEOA)
2847 		indx = 0;
2848 	else
2849 # endif
2850 	{
2851 		/* Cast is purely for paranoia here,
2852 		 * just in case someone passed signed char to us */
2853 		if ((unsigned char)c >= CTL_FIRST
2854 		 && (unsigned char)c <= CTL_LAST
2855 		) {
2856 			return CCTL;
2857 		}
2858 		s = strchrnul(spec_symbls, c);
2859 		if (*s == '\0')
2860 			return CWORD;
2861 		indx = syntax_index_table[s - spec_symbls];
2862 	}
2863 	return (S_I_T[indx] >> (syntax*4)) & 0xf;
2864 }
2865 
2866 #else   /* !USE_SIT_FUNCTION */
2867 
2868 static const uint8_t syntax_index_table[] ALIGN1 = {
2869 	/* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2870 	/*   0      */ CWORD_CWORD_CWORD_CWORD,
2871 	/*   1      */ CWORD_CWORD_CWORD_CWORD,
2872 	/*   2      */ CWORD_CWORD_CWORD_CWORD,
2873 	/*   3      */ CWORD_CWORD_CWORD_CWORD,
2874 	/*   4      */ CWORD_CWORD_CWORD_CWORD,
2875 	/*   5      */ CWORD_CWORD_CWORD_CWORD,
2876 	/*   6      */ CWORD_CWORD_CWORD_CWORD,
2877 	/*   7      */ CWORD_CWORD_CWORD_CWORD,
2878 	/*   8      */ CWORD_CWORD_CWORD_CWORD,
2879 	/*   9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2880 	/*  10 "\n" */ CNL_CNL_CNL_CNL,
2881 	/*  11      */ CWORD_CWORD_CWORD_CWORD,
2882 	/*  12      */ CWORD_CWORD_CWORD_CWORD,
2883 	/*  13      */ CWORD_CWORD_CWORD_CWORD,
2884 	/*  14      */ CWORD_CWORD_CWORD_CWORD,
2885 	/*  15      */ CWORD_CWORD_CWORD_CWORD,
2886 	/*  16      */ CWORD_CWORD_CWORD_CWORD,
2887 	/*  17      */ CWORD_CWORD_CWORD_CWORD,
2888 	/*  18      */ CWORD_CWORD_CWORD_CWORD,
2889 	/*  19      */ CWORD_CWORD_CWORD_CWORD,
2890 	/*  20      */ CWORD_CWORD_CWORD_CWORD,
2891 	/*  21      */ CWORD_CWORD_CWORD_CWORD,
2892 	/*  22      */ CWORD_CWORD_CWORD_CWORD,
2893 	/*  23      */ CWORD_CWORD_CWORD_CWORD,
2894 	/*  24      */ CWORD_CWORD_CWORD_CWORD,
2895 	/*  25      */ CWORD_CWORD_CWORD_CWORD,
2896 	/*  26      */ CWORD_CWORD_CWORD_CWORD,
2897 	/*  27      */ CWORD_CWORD_CWORD_CWORD,
2898 	/*  28      */ CWORD_CWORD_CWORD_CWORD,
2899 	/*  29      */ CWORD_CWORD_CWORD_CWORD,
2900 	/*  30      */ CWORD_CWORD_CWORD_CWORD,
2901 	/*  31      */ CWORD_CWORD_CWORD_CWORD,
2902 	/*  32  " " */ CSPCL_CWORD_CWORD_CWORD,
2903 	/*  33  "!" */ CWORD_CCTL_CCTL_CWORD,
2904 	/*  34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2905 	/*  35  "#" */ CWORD_CWORD_CWORD_CWORD,
2906 	/*  36  "$" */ CVAR_CVAR_CWORD_CVAR,
2907 	/*  37  "%" */ CWORD_CWORD_CWORD_CWORD,
2908 	/*  38  "&" */ CSPCL_CWORD_CWORD_CWORD,
2909 	/*  39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2910 	/*  40  "(" */ CSPCL_CWORD_CWORD_CLP,
2911 	/*  41  ")" */ CSPCL_CWORD_CWORD_CRP,
2912 	/*  42  "*" */ CWORD_CCTL_CCTL_CWORD,
2913 	/*  43  "+" */ CWORD_CWORD_CWORD_CWORD,
2914 	/*  44  "," */ CWORD_CWORD_CWORD_CWORD,
2915 	/*  45  "-" */ CWORD_CCTL_CCTL_CWORD,
2916 	/*  46  "." */ CWORD_CWORD_CWORD_CWORD,
2917 /* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2918 	/*  47  "/" */ CWORD_CWORD_CWORD_CWORD,
2919 	/*  48  "0" */ CWORD_CWORD_CWORD_CWORD,
2920 	/*  49  "1" */ CWORD_CWORD_CWORD_CWORD,
2921 	/*  50  "2" */ CWORD_CWORD_CWORD_CWORD,
2922 	/*  51  "3" */ CWORD_CWORD_CWORD_CWORD,
2923 	/*  52  "4" */ CWORD_CWORD_CWORD_CWORD,
2924 	/*  53  "5" */ CWORD_CWORD_CWORD_CWORD,
2925 	/*  54  "6" */ CWORD_CWORD_CWORD_CWORD,
2926 	/*  55  "7" */ CWORD_CWORD_CWORD_CWORD,
2927 	/*  56  "8" */ CWORD_CWORD_CWORD_CWORD,
2928 	/*  57  "9" */ CWORD_CWORD_CWORD_CWORD,
2929 	/*  58  ":" */ CWORD_CCTL_CCTL_CWORD,
2930 	/*  59  ";" */ CSPCL_CWORD_CWORD_CWORD,
2931 	/*  60  "<" */ CSPCL_CWORD_CWORD_CWORD,
2932 	/*  61  "=" */ CWORD_CCTL_CCTL_CWORD,
2933 	/*  62  ">" */ CSPCL_CWORD_CWORD_CWORD,
2934 	/*  63  "?" */ CWORD_CCTL_CCTL_CWORD,
2935 	/*  64  "@" */ CWORD_CWORD_CWORD_CWORD,
2936 	/*  65  "A" */ CWORD_CWORD_CWORD_CWORD,
2937 	/*  66  "B" */ CWORD_CWORD_CWORD_CWORD,
2938 	/*  67  "C" */ CWORD_CWORD_CWORD_CWORD,
2939 	/*  68  "D" */ CWORD_CWORD_CWORD_CWORD,
2940 	/*  69  "E" */ CWORD_CWORD_CWORD_CWORD,
2941 	/*  70  "F" */ CWORD_CWORD_CWORD_CWORD,
2942 	/*  71  "G" */ CWORD_CWORD_CWORD_CWORD,
2943 	/*  72  "H" */ CWORD_CWORD_CWORD_CWORD,
2944 	/*  73  "I" */ CWORD_CWORD_CWORD_CWORD,
2945 	/*  74  "J" */ CWORD_CWORD_CWORD_CWORD,
2946 	/*  75  "K" */ CWORD_CWORD_CWORD_CWORD,
2947 	/*  76  "L" */ CWORD_CWORD_CWORD_CWORD,
2948 	/*  77  "M" */ CWORD_CWORD_CWORD_CWORD,
2949 	/*  78  "N" */ CWORD_CWORD_CWORD_CWORD,
2950 	/*  79  "O" */ CWORD_CWORD_CWORD_CWORD,
2951 	/*  80  "P" */ CWORD_CWORD_CWORD_CWORD,
2952 	/*  81  "Q" */ CWORD_CWORD_CWORD_CWORD,
2953 	/*  82  "R" */ CWORD_CWORD_CWORD_CWORD,
2954 	/*  83  "S" */ CWORD_CWORD_CWORD_CWORD,
2955 	/*  84  "T" */ CWORD_CWORD_CWORD_CWORD,
2956 	/*  85  "U" */ CWORD_CWORD_CWORD_CWORD,
2957 	/*  86  "V" */ CWORD_CWORD_CWORD_CWORD,
2958 	/*  87  "W" */ CWORD_CWORD_CWORD_CWORD,
2959 	/*  88  "X" */ CWORD_CWORD_CWORD_CWORD,
2960 	/*  89  "Y" */ CWORD_CWORD_CWORD_CWORD,
2961 	/*  90  "Z" */ CWORD_CWORD_CWORD_CWORD,
2962 	/*  91  "[" */ CWORD_CCTL_CCTL_CWORD,
2963 	/*  92  "\" */ CBACK_CBACK_CCTL_CBACK,
2964 	/*  93  "]" */ CWORD_CCTL_CCTL_CWORD,
2965 	/*  94  "^" */ CWORD_CWORD_CWORD_CWORD,
2966 	/*  95  "_" */ CWORD_CWORD_CWORD_CWORD,
2967 	/*  96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2968 	/*  97  "a" */ CWORD_CWORD_CWORD_CWORD,
2969 	/*  98  "b" */ CWORD_CWORD_CWORD_CWORD,
2970 	/*  99  "c" */ CWORD_CWORD_CWORD_CWORD,
2971 	/* 100  "d" */ CWORD_CWORD_CWORD_CWORD,
2972 	/* 101  "e" */ CWORD_CWORD_CWORD_CWORD,
2973 	/* 102  "f" */ CWORD_CWORD_CWORD_CWORD,
2974 	/* 103  "g" */ CWORD_CWORD_CWORD_CWORD,
2975 	/* 104  "h" */ CWORD_CWORD_CWORD_CWORD,
2976 	/* 105  "i" */ CWORD_CWORD_CWORD_CWORD,
2977 	/* 106  "j" */ CWORD_CWORD_CWORD_CWORD,
2978 	/* 107  "k" */ CWORD_CWORD_CWORD_CWORD,
2979 	/* 108  "l" */ CWORD_CWORD_CWORD_CWORD,
2980 	/* 109  "m" */ CWORD_CWORD_CWORD_CWORD,
2981 	/* 110  "n" */ CWORD_CWORD_CWORD_CWORD,
2982 	/* 111  "o" */ CWORD_CWORD_CWORD_CWORD,
2983 	/* 112  "p" */ CWORD_CWORD_CWORD_CWORD,
2984 	/* 113  "q" */ CWORD_CWORD_CWORD_CWORD,
2985 	/* 114  "r" */ CWORD_CWORD_CWORD_CWORD,
2986 	/* 115  "s" */ CWORD_CWORD_CWORD_CWORD,
2987 	/* 116  "t" */ CWORD_CWORD_CWORD_CWORD,
2988 	/* 117  "u" */ CWORD_CWORD_CWORD_CWORD,
2989 	/* 118  "v" */ CWORD_CWORD_CWORD_CWORD,
2990 	/* 119  "w" */ CWORD_CWORD_CWORD_CWORD,
2991 	/* 120  "x" */ CWORD_CWORD_CWORD_CWORD,
2992 	/* 121  "y" */ CWORD_CWORD_CWORD_CWORD,
2993 	/* 122  "z" */ CWORD_CWORD_CWORD_CWORD,
2994 	/* 123  "{" */ CWORD_CWORD_CWORD_CWORD,
2995 	/* 124  "|" */ CSPCL_CWORD_CWORD_CWORD,
2996 	/* 125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2997 	/* 126  "~" */ CWORD_CCTL_CCTL_CWORD,
2998 	/* 127  del */ CWORD_CWORD_CWORD_CWORD,
2999 	/* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3000 	/* 129 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
3001 	/* 130 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
3002 	/* 131 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
3003 	/* 132 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
3004 	/* 133 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
3005 	/* 134 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
3006 	/* 135 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
3007 	/* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3008 	/* 137      */ CWORD_CWORD_CWORD_CWORD,
3009 	/* 138      */ CWORD_CWORD_CWORD_CWORD,
3010 	/* 139      */ CWORD_CWORD_CWORD_CWORD,
3011 	/* 140      */ CWORD_CWORD_CWORD_CWORD,
3012 	/* 141      */ CWORD_CWORD_CWORD_CWORD,
3013 	/* 142      */ CWORD_CWORD_CWORD_CWORD,
3014 	/* 143      */ CWORD_CWORD_CWORD_CWORD,
3015 	/* 144      */ CWORD_CWORD_CWORD_CWORD,
3016 	/* 145      */ CWORD_CWORD_CWORD_CWORD,
3017 	/* 146      */ CWORD_CWORD_CWORD_CWORD,
3018 	/* 147      */ CWORD_CWORD_CWORD_CWORD,
3019 	/* 148      */ CWORD_CWORD_CWORD_CWORD,
3020 	/* 149      */ CWORD_CWORD_CWORD_CWORD,
3021 	/* 150      */ CWORD_CWORD_CWORD_CWORD,
3022 	/* 151      */ CWORD_CWORD_CWORD_CWORD,
3023 	/* 152      */ CWORD_CWORD_CWORD_CWORD,
3024 	/* 153      */ CWORD_CWORD_CWORD_CWORD,
3025 	/* 154      */ CWORD_CWORD_CWORD_CWORD,
3026 	/* 155      */ CWORD_CWORD_CWORD_CWORD,
3027 	/* 156      */ CWORD_CWORD_CWORD_CWORD,
3028 	/* 157      */ CWORD_CWORD_CWORD_CWORD,
3029 	/* 158      */ CWORD_CWORD_CWORD_CWORD,
3030 	/* 159      */ CWORD_CWORD_CWORD_CWORD,
3031 	/* 160      */ CWORD_CWORD_CWORD_CWORD,
3032 	/* 161      */ CWORD_CWORD_CWORD_CWORD,
3033 	/* 162      */ CWORD_CWORD_CWORD_CWORD,
3034 	/* 163      */ CWORD_CWORD_CWORD_CWORD,
3035 	/* 164      */ CWORD_CWORD_CWORD_CWORD,
3036 	/* 165      */ CWORD_CWORD_CWORD_CWORD,
3037 	/* 166      */ CWORD_CWORD_CWORD_CWORD,
3038 	/* 167      */ CWORD_CWORD_CWORD_CWORD,
3039 	/* 168      */ CWORD_CWORD_CWORD_CWORD,
3040 	/* 169      */ CWORD_CWORD_CWORD_CWORD,
3041 	/* 170      */ CWORD_CWORD_CWORD_CWORD,
3042 	/* 171      */ CWORD_CWORD_CWORD_CWORD,
3043 	/* 172      */ CWORD_CWORD_CWORD_CWORD,
3044 	/* 173      */ CWORD_CWORD_CWORD_CWORD,
3045 	/* 174      */ CWORD_CWORD_CWORD_CWORD,
3046 	/* 175      */ CWORD_CWORD_CWORD_CWORD,
3047 	/* 176      */ CWORD_CWORD_CWORD_CWORD,
3048 	/* 177      */ CWORD_CWORD_CWORD_CWORD,
3049 	/* 178      */ CWORD_CWORD_CWORD_CWORD,
3050 	/* 179      */ CWORD_CWORD_CWORD_CWORD,
3051 	/* 180      */ CWORD_CWORD_CWORD_CWORD,
3052 	/* 181      */ CWORD_CWORD_CWORD_CWORD,
3053 	/* 182      */ CWORD_CWORD_CWORD_CWORD,
3054 	/* 183      */ CWORD_CWORD_CWORD_CWORD,
3055 	/* 184      */ CWORD_CWORD_CWORD_CWORD,
3056 	/* 185      */ CWORD_CWORD_CWORD_CWORD,
3057 	/* 186      */ CWORD_CWORD_CWORD_CWORD,
3058 	/* 187      */ CWORD_CWORD_CWORD_CWORD,
3059 	/* 188      */ CWORD_CWORD_CWORD_CWORD,
3060 	/* 189      */ CWORD_CWORD_CWORD_CWORD,
3061 	/* 190      */ CWORD_CWORD_CWORD_CWORD,
3062 	/* 191      */ CWORD_CWORD_CWORD_CWORD,
3063 	/* 192      */ CWORD_CWORD_CWORD_CWORD,
3064 	/* 193      */ CWORD_CWORD_CWORD_CWORD,
3065 	/* 194      */ CWORD_CWORD_CWORD_CWORD,
3066 	/* 195      */ CWORD_CWORD_CWORD_CWORD,
3067 	/* 196      */ CWORD_CWORD_CWORD_CWORD,
3068 	/* 197      */ CWORD_CWORD_CWORD_CWORD,
3069 	/* 198      */ CWORD_CWORD_CWORD_CWORD,
3070 	/* 199      */ CWORD_CWORD_CWORD_CWORD,
3071 	/* 200      */ CWORD_CWORD_CWORD_CWORD,
3072 	/* 201      */ CWORD_CWORD_CWORD_CWORD,
3073 	/* 202      */ CWORD_CWORD_CWORD_CWORD,
3074 	/* 203      */ CWORD_CWORD_CWORD_CWORD,
3075 	/* 204      */ CWORD_CWORD_CWORD_CWORD,
3076 	/* 205      */ CWORD_CWORD_CWORD_CWORD,
3077 	/* 206      */ CWORD_CWORD_CWORD_CWORD,
3078 	/* 207      */ CWORD_CWORD_CWORD_CWORD,
3079 	/* 208      */ CWORD_CWORD_CWORD_CWORD,
3080 	/* 209      */ CWORD_CWORD_CWORD_CWORD,
3081 	/* 210      */ CWORD_CWORD_CWORD_CWORD,
3082 	/* 211      */ CWORD_CWORD_CWORD_CWORD,
3083 	/* 212      */ CWORD_CWORD_CWORD_CWORD,
3084 	/* 213      */ CWORD_CWORD_CWORD_CWORD,
3085 	/* 214      */ CWORD_CWORD_CWORD_CWORD,
3086 	/* 215      */ CWORD_CWORD_CWORD_CWORD,
3087 	/* 216      */ CWORD_CWORD_CWORD_CWORD,
3088 	/* 217      */ CWORD_CWORD_CWORD_CWORD,
3089 	/* 218      */ CWORD_CWORD_CWORD_CWORD,
3090 	/* 219      */ CWORD_CWORD_CWORD_CWORD,
3091 	/* 220      */ CWORD_CWORD_CWORD_CWORD,
3092 	/* 221      */ CWORD_CWORD_CWORD_CWORD,
3093 	/* 222      */ CWORD_CWORD_CWORD_CWORD,
3094 	/* 223      */ CWORD_CWORD_CWORD_CWORD,
3095 	/* 224      */ CWORD_CWORD_CWORD_CWORD,
3096 	/* 225      */ CWORD_CWORD_CWORD_CWORD,
3097 	/* 226      */ CWORD_CWORD_CWORD_CWORD,
3098 	/* 227      */ CWORD_CWORD_CWORD_CWORD,
3099 	/* 228      */ CWORD_CWORD_CWORD_CWORD,
3100 	/* 229      */ CWORD_CWORD_CWORD_CWORD,
3101 	/* 230      */ CWORD_CWORD_CWORD_CWORD,
3102 	/* 231      */ CWORD_CWORD_CWORD_CWORD,
3103 	/* 232      */ CWORD_CWORD_CWORD_CWORD,
3104 	/* 233      */ CWORD_CWORD_CWORD_CWORD,
3105 	/* 234      */ CWORD_CWORD_CWORD_CWORD,
3106 	/* 235      */ CWORD_CWORD_CWORD_CWORD,
3107 	/* 236      */ CWORD_CWORD_CWORD_CWORD,
3108 	/* 237      */ CWORD_CWORD_CWORD_CWORD,
3109 	/* 238      */ CWORD_CWORD_CWORD_CWORD,
3110 	/* 239      */ CWORD_CWORD_CWORD_CWORD,
3111 	/* 230      */ CWORD_CWORD_CWORD_CWORD,
3112 	/* 241      */ CWORD_CWORD_CWORD_CWORD,
3113 	/* 242      */ CWORD_CWORD_CWORD_CWORD,
3114 	/* 243      */ CWORD_CWORD_CWORD_CWORD,
3115 	/* 244      */ CWORD_CWORD_CWORD_CWORD,
3116 	/* 245      */ CWORD_CWORD_CWORD_CWORD,
3117 	/* 246      */ CWORD_CWORD_CWORD_CWORD,
3118 	/* 247      */ CWORD_CWORD_CWORD_CWORD,
3119 	/* 248      */ CWORD_CWORD_CWORD_CWORD,
3120 	/* 249      */ CWORD_CWORD_CWORD_CWORD,
3121 	/* 250      */ CWORD_CWORD_CWORD_CWORD,
3122 	/* 251      */ CWORD_CWORD_CWORD_CWORD,
3123 	/* 252      */ CWORD_CWORD_CWORD_CWORD,
3124 	/* 253      */ CWORD_CWORD_CWORD_CWORD,
3125 	/* 254      */ CWORD_CWORD_CWORD_CWORD,
3126 	/* 255      */ CWORD_CWORD_CWORD_CWORD,
3127 	/* PEOF */     CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3128 # if ENABLE_ASH_ALIAS
3129 	/* PEOA */     CSPCL_CIGN_CIGN_CIGN,
3130 # endif
3131 };
3132 
3133 #if 1
3134 # define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3135 #else /* debug version, caught one signed char bug */
3136 # define SIT(c, syntax) \
3137 	({ \
3138 		if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3139 			bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3140 		if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3141 			bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3142 		((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3143 	})
3144 #endif
3145 
3146 #endif  /* !USE_SIT_FUNCTION */
3147 
3148 
3149 /* ============ Alias handling */
3150 
3151 #if ENABLE_ASH_ALIAS
3152 
3153 #define ALIASINUSE 1
3154 #define ALIASDEAD  2
3155 
3156 struct alias {
3157 	struct alias *next;
3158 	char *name;
3159 	char *val;
3160 	int flag;
3161 };
3162 
3163 
3164 static struct alias **atab; // [ATABSIZE];
3165 #define INIT_G_alias() do { \
3166 	atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3167 } while (0)
3168 
3169 
3170 static struct alias **
__lookupalias(const char * name)3171 __lookupalias(const char *name)
3172 {
3173 	unsigned int hashval;
3174 	struct alias **app;
3175 	const char *p;
3176 	unsigned int ch;
3177 
3178 	p = name;
3179 
3180 	ch = (unsigned char)*p;
3181 	hashval = ch << 4;
3182 	while (ch) {
3183 		hashval += ch;
3184 		ch = (unsigned char)*++p;
3185 	}
3186 	app = &atab[hashval % ATABSIZE];
3187 
3188 	for (; *app; app = &(*app)->next) {
3189 		if (strcmp(name, (*app)->name) == 0) {
3190 			break;
3191 		}
3192 	}
3193 
3194 	return app;
3195 }
3196 
3197 static struct alias *
lookupalias(const char * name,int check)3198 lookupalias(const char *name, int check)
3199 {
3200 	struct alias *ap = *__lookupalias(name);
3201 
3202 	if (check && ap && (ap->flag & ALIASINUSE))
3203 		return NULL;
3204 	return ap;
3205 }
3206 
3207 static struct alias *
freealias(struct alias * ap)3208 freealias(struct alias *ap)
3209 {
3210 	struct alias *next;
3211 
3212 	if (ap->flag & ALIASINUSE) {
3213 		ap->flag |= ALIASDEAD;
3214 		return ap;
3215 	}
3216 
3217 	next = ap->next;
3218 	free(ap->name);
3219 	free(ap->val);
3220 	free(ap);
3221 	return next;
3222 }
3223 
3224 static void
setalias(const char * name,const char * val)3225 setalias(const char *name, const char *val)
3226 {
3227 	struct alias *ap, **app;
3228 
3229 	app = __lookupalias(name);
3230 	ap = *app;
3231 	INT_OFF;
3232 	if (ap) {
3233 		if (!(ap->flag & ALIASINUSE)) {
3234 			free(ap->val);
3235 		}
3236 		ap->val = ckstrdup(val);
3237 		ap->flag &= ~ALIASDEAD;
3238 	} else {
3239 		/* not found */
3240 		ap = ckzalloc(sizeof(struct alias));
3241 		ap->name = ckstrdup(name);
3242 		ap->val = ckstrdup(val);
3243 		/*ap->flag = 0; - ckzalloc did it */
3244 		/*ap->next = NULL;*/
3245 		*app = ap;
3246 	}
3247 	INT_ON;
3248 }
3249 
3250 static int
unalias(const char * name)3251 unalias(const char *name)
3252 {
3253 	struct alias **app;
3254 
3255 	app = __lookupalias(name);
3256 
3257 	if (*app) {
3258 		INT_OFF;
3259 		*app = freealias(*app);
3260 		INT_ON;
3261 		return 0;
3262 	}
3263 
3264 	return 1;
3265 }
3266 
3267 static void
rmaliases(void)3268 rmaliases(void)
3269 {
3270 	struct alias *ap, **app;
3271 	int i;
3272 
3273 	INT_OFF;
3274 	for (i = 0; i < ATABSIZE; i++) {
3275 		app = &atab[i];
3276 		for (ap = *app; ap; ap = *app) {
3277 			*app = freealias(*app);
3278 			if (ap == *app) {
3279 				app = &ap->next;
3280 			}
3281 		}
3282 	}
3283 	INT_ON;
3284 }
3285 
3286 static void
printalias(const struct alias * ap)3287 printalias(const struct alias *ap)
3288 {
3289 	out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3290 }
3291 
3292 /*
3293  * TODO - sort output
3294  */
3295 static int FAST_FUNC
aliascmd(int argc UNUSED_PARAM,char ** argv)3296 aliascmd(int argc UNUSED_PARAM, char **argv)
3297 {
3298 	char *n, *v;
3299 	int ret = 0;
3300 	struct alias *ap;
3301 
3302 	if (!argv[1]) {
3303 		int i;
3304 
3305 		for (i = 0; i < ATABSIZE; i++) {
3306 			for (ap = atab[i]; ap; ap = ap->next) {
3307 				printalias(ap);
3308 			}
3309 		}
3310 		return 0;
3311 	}
3312 	while ((n = *++argv) != NULL) {
3313 		v = strchr(n+1, '=');
3314 		if (v == NULL) { /* n+1: funny ksh stuff */
3315 			ap = *__lookupalias(n);
3316 			if (ap == NULL) {
3317 				fprintf(stderr, "%s: %s not found\n", "alias", n);
3318 				ret = 1;
3319 			} else
3320 				printalias(ap);
3321 		} else {
3322 			*v++ = '\0';
3323 			setalias(n, v);
3324 		}
3325 	}
3326 
3327 	return ret;
3328 }
3329 
3330 static int FAST_FUNC
unaliascmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)3331 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3332 {
3333 	int i;
3334 
3335 	while ((i = nextopt("a")) != '\0') {
3336 		if (i == 'a') {
3337 			rmaliases();
3338 			return 0;
3339 		}
3340 	}
3341 	for (i = 0; *argptr; argptr++) {
3342 		if (unalias(*argptr)) {
3343 			fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3344 			i = 1;
3345 		}
3346 	}
3347 
3348 	return i;
3349 }
3350 
3351 #endif /* ASH_ALIAS */
3352 
3353 
3354 /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
3355 #define FORK_FG    0
3356 #define FORK_BG    1
3357 #define FORK_NOJOB 2
3358 
3359 /* mode flags for showjob(s) */
3360 #define SHOW_ONLY_PGID  0x01    /* show only pgid (jobs -p) */
3361 #define SHOW_PIDS       0x02    /* show individual pids, not just one line per job */
3362 #define SHOW_CHANGED    0x04    /* only jobs whose state has changed */
3363 #define SHOW_STDERR     0x08    /* print to stderr (else stdout) */
3364 
3365 /*
3366  * A job structure contains information about a job.  A job is either a
3367  * single process or a set of processes contained in a pipeline.  In the
3368  * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3369  * array of pids.
3370  */
3371 struct procstat {
3372 	pid_t   ps_pid;         /* process id */
3373 	int     ps_status;      /* last process status from wait() */
3374 	char    *ps_cmd;        /* text of command being run */
3375 };
3376 
3377 struct job {
3378 	struct procstat ps0;    /* status of process */
3379 	struct procstat *ps;    /* status or processes when more than one */
3380 #if JOBS
3381 	int stopstatus;         /* status of a stopped job */
3382 #endif
3383 	uint32_t
3384 		nprocs: 16,     /* number of processes */
3385 		state: 8,
3386 #define JOBRUNNING      0       /* at least one proc running */
3387 #define JOBSTOPPED      1       /* all procs are stopped */
3388 #define JOBDONE         2       /* all procs are completed */
3389 #if JOBS
3390 		sigint: 1,      /* job was killed by SIGINT */
3391 		jobctl: 1,      /* job running under job control */
3392 #endif
3393 		waited: 1,      /* true if this entry has been waited for */
3394 		used: 1,        /* true if this entry is in used */
3395 		changed: 1;     /* true if status has changed */
3396 	struct job *prev_job;   /* previous job */
3397 };
3398 
3399 static struct job *makejob(/*union node *,*/ int);
3400 static int forkshell(struct job *, union node *, int);
3401 static int waitforjob(struct job *);
3402 
3403 #if !JOBS
3404 enum { doing_jobctl = 0 };
3405 #define setjobctl(on) do {} while (0)
3406 #else
3407 static smallint doing_jobctl; //references:8
3408 static void setjobctl(int);
3409 #endif
3410 
3411 /*
3412  * Ignore a signal.
3413  */
3414 static void
ignoresig(int signo)3415 ignoresig(int signo)
3416 {
3417 	/* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3418 	if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3419 		/* No, need to do it */
3420 		signal(signo, SIG_IGN);
3421 	}
3422 	sigmode[signo - 1] = S_HARD_IGN;
3423 }
3424 
3425 /*
3426  * Only one usage site - in setsignal()
3427  */
3428 static void
signal_handler(int signo)3429 signal_handler(int signo)
3430 {
3431 	if (signo == SIGCHLD) {
3432 		got_sigchld = 1;
3433 		if (!trap[SIGCHLD])
3434 			return;
3435 	}
3436 
3437 	gotsig[signo - 1] = 1;
3438 	pending_sig = signo;
3439 
3440 	if (signo == SIGINT && !trap[SIGINT]) {
3441 		if (!suppress_int) {
3442 			pending_sig = 0;
3443 			raise_interrupt(); /* does not return */
3444 		}
3445 		pending_int = 1;
3446 	}
3447 }
3448 
3449 /*
3450  * Set the signal handler for the specified signal.  The routine figures
3451  * out what it should be set to.
3452  */
3453 static void
setsignal(int signo)3454 setsignal(int signo)
3455 {
3456 	char *t;
3457 	char cur_act, new_act;
3458 	struct sigaction act;
3459 
3460 	t = trap[signo];
3461 	new_act = S_DFL;
3462 	if (t != NULL) { /* trap for this sig is set */
3463 		new_act = S_CATCH;
3464 		if (t[0] == '\0') /* trap is "": ignore this sig */
3465 			new_act = S_IGN;
3466 	}
3467 
3468 	if (rootshell && new_act == S_DFL) {
3469 		switch (signo) {
3470 		case SIGINT:
3471 			if (iflag || minusc || sflag == 0)
3472 				new_act = S_CATCH;
3473 			break;
3474 		case SIGQUIT:
3475 #if DEBUG
3476 			if (debug)
3477 				break;
3478 #endif
3479 			/* man bash:
3480 			 * "In all cases, bash ignores SIGQUIT. Non-builtin
3481 			 * commands run by bash have signal handlers
3482 			 * set to the values inherited by the shell
3483 			 * from its parent". */
3484 			new_act = S_IGN;
3485 			break;
3486 		case SIGTERM:
3487 			if (iflag)
3488 				new_act = S_IGN;
3489 			break;
3490 #if JOBS
3491 		case SIGTSTP:
3492 		case SIGTTOU:
3493 			if (mflag)
3494 				new_act = S_IGN;
3495 			break;
3496 #endif
3497 		}
3498 	}
3499 //TODO: if !rootshell, we reset SIGQUIT to DFL,
3500 //whereas we have to restore it to what shell got on entry
3501 //from the parent. See comment above
3502 
3503 	if (signo == SIGCHLD)
3504 		new_act = S_CATCH;
3505 
3506 	t = &sigmode[signo - 1];
3507 	cur_act = *t;
3508 	if (cur_act == 0) {
3509 		/* current setting is not yet known */
3510 		if (sigaction(signo, NULL, &act)) {
3511 			/* pretend it worked; maybe we should give a warning,
3512 			 * but other shells don't. We don't alter sigmode,
3513 			 * so we retry every time.
3514 			 * btw, in Linux it never fails. --vda */
3515 			return;
3516 		}
3517 		if (act.sa_handler == SIG_IGN) {
3518 			cur_act = S_HARD_IGN;
3519 			if (mflag
3520 			 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3521 			) {
3522 				cur_act = S_IGN;   /* don't hard ignore these */
3523 			}
3524 		}
3525 	}
3526 	if (cur_act == S_HARD_IGN || cur_act == new_act)
3527 		return;
3528 
3529 	act.sa_handler = SIG_DFL;
3530 	switch (new_act) {
3531 	case S_CATCH:
3532 		act.sa_handler = signal_handler;
3533 		break;
3534 	case S_IGN:
3535 		act.sa_handler = SIG_IGN;
3536 		break;
3537 	}
3538 
3539 	/* flags and mask matter only if !DFL and !IGN, but we do it
3540 	 * for all cases for more deterministic behavior:
3541 	 */
3542 	act.sa_flags = 0;
3543 	sigfillset(&act.sa_mask);
3544 
3545 	sigaction_set(signo, &act);
3546 
3547 	*t = new_act;
3548 }
3549 
3550 /* mode flags for set_curjob */
3551 #define CUR_DELETE 2
3552 #define CUR_RUNNING 1
3553 #define CUR_STOPPED 0
3554 
3555 #if JOBS
3556 /* pgrp of shell on invocation */
3557 static int initialpgrp; //references:2
3558 static int ttyfd = -1; //5
3559 #endif
3560 /* array of jobs */
3561 static struct job *jobtab; //5
3562 /* size of array */
3563 static unsigned njobs; //4
3564 /* current job */
3565 static struct job *curjob; //lots
3566 /* number of presumed living untracked jobs */
3567 static int jobless; //4
3568 
3569 static void
set_curjob(struct job * jp,unsigned mode)3570 set_curjob(struct job *jp, unsigned mode)
3571 {
3572 	struct job *jp1;
3573 	struct job **jpp, **curp;
3574 
3575 	/* first remove from list */
3576 	jpp = curp = &curjob;
3577 	while (1) {
3578 		jp1 = *jpp;
3579 		if (jp1 == jp)
3580 			break;
3581 		jpp = &jp1->prev_job;
3582 	}
3583 	*jpp = jp1->prev_job;
3584 
3585 	/* Then re-insert in correct position */
3586 	jpp = curp;
3587 	switch (mode) {
3588 	default:
3589 #if DEBUG
3590 		abort();
3591 #endif
3592 	case CUR_DELETE:
3593 		/* job being deleted */
3594 		break;
3595 	case CUR_RUNNING:
3596 		/* newly created job or backgrounded job,
3597 		 * put after all stopped jobs.
3598 		 */
3599 		while (1) {
3600 			jp1 = *jpp;
3601 #if JOBS
3602 			if (!jp1 || jp1->state != JOBSTOPPED)
3603 #endif
3604 				break;
3605 			jpp = &jp1->prev_job;
3606 		}
3607 		/* FALLTHROUGH */
3608 #if JOBS
3609 	case CUR_STOPPED:
3610 #endif
3611 		/* newly stopped job - becomes curjob */
3612 		jp->prev_job = *jpp;
3613 		*jpp = jp;
3614 		break;
3615 	}
3616 }
3617 
3618 #if JOBS || DEBUG
3619 static int
jobno(const struct job * jp)3620 jobno(const struct job *jp)
3621 {
3622 	return jp - jobtab + 1;
3623 }
3624 #endif
3625 
3626 /*
3627  * Convert a job name to a job structure.
3628  */
3629 #if !JOBS
3630 #define getjob(name, getctl) getjob(name)
3631 #endif
3632 static struct job *
getjob(const char * name,int getctl)3633 getjob(const char *name, int getctl)
3634 {
3635 	struct job *jp;
3636 	struct job *found;
3637 	const char *err_msg = "%s: no such job";
3638 	unsigned num;
3639 	int c;
3640 	const char *p;
3641 	char *(*match)(const char *, const char *);
3642 
3643 	jp = curjob;
3644 	p = name;
3645 	if (!p)
3646 		goto currentjob;
3647 
3648 	if (*p != '%')
3649 		goto err;
3650 
3651 	c = *++p;
3652 	if (!c)
3653 		goto currentjob;
3654 
3655 	if (!p[1]) {
3656 		if (c == '+' || c == '%') {
3657  currentjob:
3658 			err_msg = "No current job";
3659 			goto check;
3660 		}
3661 		if (c == '-') {
3662 			if (jp)
3663 				jp = jp->prev_job;
3664 			err_msg = "No previous job";
3665  check:
3666 			if (!jp)
3667 				goto err;
3668 			goto gotit;
3669 		}
3670 	}
3671 
3672 	if (is_number(p)) {
3673 		num = atoi(p);
3674 		if (num > 0 && num <= njobs) {
3675 			jp = jobtab + num - 1;
3676 			if (jp->used)
3677 				goto gotit;
3678 			goto err;
3679 		}
3680 	}
3681 
3682 	match = prefix;
3683 	if (*p == '?') {
3684 		match = strstr;
3685 		p++;
3686 	}
3687 
3688 	found = NULL;
3689 	while (jp) {
3690 		if (match(jp->ps[0].ps_cmd, p)) {
3691 			if (found)
3692 				goto err;
3693 			found = jp;
3694 			err_msg = "%s: ambiguous";
3695 		}
3696 		jp = jp->prev_job;
3697 	}
3698 	if (!found)
3699 		goto err;
3700 	jp = found;
3701 
3702  gotit:
3703 #if JOBS
3704 	err_msg = "job %s not created under job control";
3705 	if (getctl && jp->jobctl == 0)
3706 		goto err;
3707 #endif
3708 	return jp;
3709  err:
3710 	ash_msg_and_raise_error(err_msg, name);
3711 }
3712 
3713 /*
3714  * Mark a job structure as unused.
3715  */
3716 static void
freejob(struct job * jp)3717 freejob(struct job *jp)
3718 {
3719 	struct procstat *ps;
3720 	int i;
3721 
3722 	INT_OFF;
3723 	for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3724 		if (ps->ps_cmd != nullstr)
3725 			free(ps->ps_cmd);
3726 	}
3727 	if (jp->ps != &jp->ps0)
3728 		free(jp->ps);
3729 	jp->used = 0;
3730 	set_curjob(jp, CUR_DELETE);
3731 	INT_ON;
3732 }
3733 
3734 #if JOBS
3735 static void
xtcsetpgrp(int fd,pid_t pgrp)3736 xtcsetpgrp(int fd, pid_t pgrp)
3737 {
3738 	if (tcsetpgrp(fd, pgrp))
3739 		ash_msg_and_raise_error("can't set tty process group (%m)");
3740 }
3741 
3742 /*
3743  * Turn job control on and off.
3744  *
3745  * Note:  This code assumes that the third arg to ioctl is a character
3746  * pointer, which is true on Berkeley systems but not System V.  Since
3747  * System V doesn't have job control yet, this isn't a problem now.
3748  *
3749  * Called with interrupts off.
3750  */
3751 static void
setjobctl(int on)3752 setjobctl(int on)
3753 {
3754 	int fd;
3755 	int pgrp;
3756 
3757 	if (on == doing_jobctl || rootshell == 0)
3758 		return;
3759 	if (on) {
3760 		int ofd;
3761 		ofd = fd = open(_PATH_TTY, O_RDWR);
3762 		if (fd < 0) {
3763 	/* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3764 	 * That sometimes helps to acquire controlling tty.
3765 	 * Obviously, a workaround for bugs when someone
3766 	 * failed to provide a controlling tty to bash! :) */
3767 			fd = 2;
3768 			while (!isatty(fd))
3769 				if (--fd < 0)
3770 					goto out;
3771 		}
3772 		/* fd is a tty at this point */
3773 		fd = fcntl(fd, F_DUPFD, 10);
3774 		if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
3775 			close(ofd);
3776 		if (fd < 0)
3777 			goto out; /* F_DUPFD failed */
3778 		close_on_exec_on(fd);
3779 		while (1) { /* while we are in the background */
3780 			pgrp = tcgetpgrp(fd);
3781 			if (pgrp < 0) {
3782  out:
3783 				ash_msg("can't access tty; job control turned off");
3784 				mflag = on = 0;
3785 				goto close;
3786 			}
3787 			if (pgrp == getpgrp())
3788 				break;
3789 			killpg(0, SIGTTIN);
3790 		}
3791 		initialpgrp = pgrp;
3792 
3793 		setsignal(SIGTSTP);
3794 		setsignal(SIGTTOU);
3795 		setsignal(SIGTTIN);
3796 		pgrp = rootpid;
3797 		setpgid(0, pgrp);
3798 		xtcsetpgrp(fd, pgrp);
3799 	} else {
3800 		/* turning job control off */
3801 		fd = ttyfd;
3802 		pgrp = initialpgrp;
3803 		/* was xtcsetpgrp, but this can make exiting ash
3804 		 * loop forever if pty is already deleted */
3805 		tcsetpgrp(fd, pgrp);
3806 		setpgid(0, pgrp);
3807 		setsignal(SIGTSTP);
3808 		setsignal(SIGTTOU);
3809 		setsignal(SIGTTIN);
3810  close:
3811 		if (fd >= 0)
3812 			close(fd);
3813 		fd = -1;
3814 	}
3815 	ttyfd = fd;
3816 	doing_jobctl = on;
3817 }
3818 
3819 static int FAST_FUNC
killcmd(int argc,char ** argv)3820 killcmd(int argc, char **argv)
3821 {
3822 	if (argv[1] && strcmp(argv[1], "-l") != 0) {
3823 		int i = 1;
3824 		do {
3825 			if (argv[i][0] == '%') {
3826 				/*
3827 				 * "kill %N" - job kill
3828 				 * Converting to pgrp / pid kill
3829 				 */
3830 				struct job *jp;
3831 				char *dst;
3832 				int j, n;
3833 
3834 				jp = getjob(argv[i], 0);
3835 				/*
3836 				 * In jobs started under job control, we signal
3837 				 * entire process group by kill -PGRP_ID.
3838 				 * This happens, f.e., in interactive shell.
3839 				 *
3840 				 * Otherwise, we signal each child via
3841 				 * kill PID1 PID2 PID3.
3842 				 * Testcases:
3843 				 * sh -c 'sleep 1|sleep 1 & kill %1'
3844 				 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3845 				 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3846 				 */
3847 				n = jp->nprocs; /* can't be 0 (I hope) */
3848 				if (jp->jobctl)
3849 					n = 1;
3850 				dst = alloca(n * sizeof(int)*4);
3851 				argv[i] = dst;
3852 				for (j = 0; j < n; j++) {
3853 					struct procstat *ps = &jp->ps[j];
3854 					/* Skip non-running and not-stopped members
3855 					 * (i.e. dead members) of the job
3856 					 */
3857 					if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3858 						continue;
3859 					/*
3860 					 * kill_main has matching code to expect
3861 					 * leading space. Needed to not confuse
3862 					 * negative pids with "kill -SIGNAL_NO" syntax
3863 					 */
3864 					dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3865 				}
3866 				*dst = '\0';
3867 			}
3868 		} while (argv[++i]);
3869 	}
3870 	return kill_main(argc, argv);
3871 }
3872 
3873 static void
showpipe(struct job * jp)3874 showpipe(struct job *jp /*, FILE *out*/)
3875 {
3876 	struct procstat *ps;
3877 	struct procstat *psend;
3878 
3879 	psend = jp->ps + jp->nprocs;
3880 	for (ps = jp->ps + 1; ps < psend; ps++)
3881 		printf(" | %s", ps->ps_cmd);
3882 	newline_and_flush(stdout);
3883 	flush_stdout_stderr();
3884 }
3885 
3886 
3887 static int
restartjob(struct job * jp,int mode)3888 restartjob(struct job *jp, int mode)
3889 {
3890 	struct procstat *ps;
3891 	int i;
3892 	int status;
3893 	pid_t pgid;
3894 
3895 	INT_OFF;
3896 	if (jp->state == JOBDONE)
3897 		goto out;
3898 	jp->state = JOBRUNNING;
3899 	pgid = jp->ps[0].ps_pid;
3900 	if (mode == FORK_FG)
3901 		xtcsetpgrp(ttyfd, pgid);
3902 	killpg(pgid, SIGCONT);
3903 	ps = jp->ps;
3904 	i = jp->nprocs;
3905 	do {
3906 		if (WIFSTOPPED(ps->ps_status)) {
3907 			ps->ps_status = -1;
3908 		}
3909 		ps++;
3910 	} while (--i);
3911  out:
3912 	status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3913 	INT_ON;
3914 	return status;
3915 }
3916 
3917 static int FAST_FUNC
fg_bgcmd(int argc UNUSED_PARAM,char ** argv)3918 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3919 {
3920 	struct job *jp;
3921 	int mode;
3922 	int retval;
3923 
3924 	mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3925 	nextopt(nullstr);
3926 	argv = argptr;
3927 	do {
3928 		jp = getjob(*argv, 1);
3929 		if (mode == FORK_BG) {
3930 			set_curjob(jp, CUR_RUNNING);
3931 			printf("[%d] ", jobno(jp));
3932 		}
3933 		out1str(jp->ps[0].ps_cmd);
3934 		showpipe(jp /*, stdout*/);
3935 		retval = restartjob(jp, mode);
3936 	} while (*argv && *++argv);
3937 	return retval;
3938 }
3939 #endif
3940 
3941 static int
sprint_status48(char * s,int status,int sigonly)3942 sprint_status48(char *s, int status, int sigonly)
3943 {
3944 	int col;
3945 	int st;
3946 
3947 	col = 0;
3948 	if (!WIFEXITED(status)) {
3949 		if (JOBS && WIFSTOPPED(status))
3950 			st = WSTOPSIG(status);
3951 		else
3952 			st = WTERMSIG(status);
3953 		if (sigonly) {
3954 			if (st == SIGINT || st == SIGPIPE)
3955 				goto out;
3956 			if (JOBS && WIFSTOPPED(status))
3957 				goto out;
3958 		}
3959 		st &= 0x7f;
3960 //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
3961 		col = fmtstr(s, 32, strsignal(st));
3962 		if (WCOREDUMP(status)) {
3963 			strcpy(s + col, " (core dumped)");
3964 			col += sizeof(" (core dumped)")-1;
3965 		}
3966 	} else if (!sigonly) {
3967 		st = WEXITSTATUS(status);
3968 		col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
3969 	}
3970  out:
3971 	return col;
3972 }
3973 
3974 static int
wait_block_or_sig(int * status)3975 wait_block_or_sig(int *status)
3976 {
3977 	int pid;
3978 
3979 	do {
3980 		sigset_t mask;
3981 
3982 		/* Poll all children for changes in their state */
3983 		got_sigchld = 0;
3984 		/* if job control is active, accept stopped processes too */
3985 		pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
3986 		if (pid != 0)
3987 			break; /* Error (e.g. EINTR, ECHILD) or pid */
3988 
3989 		/* Children exist, but none are ready. Sleep until interesting signal */
3990 #if 1
3991 		sigfillset(&mask);
3992 		sigprocmask(SIG_SETMASK, &mask, &mask);
3993 		while (!got_sigchld && !pending_sig)
3994 			sigsuspend(&mask);
3995 		sigprocmask(SIG_SETMASK, &mask, NULL);
3996 #else /* unsafe: a signal can set pending_sig after check, but before pause() */
3997 		while (!got_sigchld && !pending_sig)
3998 			pause();
3999 #endif
4000 
4001 		/* If it was SIGCHLD, poll children again */
4002 	} while (got_sigchld);
4003 
4004 	return pid;
4005 }
4006 
4007 #define DOWAIT_NONBLOCK 0
4008 #define DOWAIT_BLOCK    1
4009 #define DOWAIT_BLOCK_OR_SIG 2
4010 
4011 static int
dowait(int block,struct job * job)4012 dowait(int block, struct job *job)
4013 {
4014 	int pid;
4015 	int status;
4016 	struct job *jp;
4017 	struct job *thisjob = NULL;
4018 
4019 	TRACE(("dowait(0x%x) called\n", block));
4020 
4021 	/* It's wrong to call waitpid() outside of INT_OFF region:
4022 	 * signal can arrive just after syscall return and handler can
4023 	 * longjmp away, losing stop/exit notification processing.
4024 	 * Thus, for "jobs" builtin, and for waiting for a fg job,
4025 	 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4026 	 *
4027 	 * However, for "wait" builtin it is wrong to simply call waitpid()
4028 	 * in INT_OFF region: "wait" needs to wait for any running job
4029 	 * to change state, but should exit on any trap too.
4030 	 * In INT_OFF region, a signal just before syscall entry can set
4031 	 * pending_sig variables, but we can't check them, and we would
4032 	 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
4033 	 *
4034 	 * Because of this, we run inside INT_OFF, but use a special routine
4035 	 * which combines waitpid() and sigsuspend().
4036 	 * This is the reason why we need to have a handler for SIGCHLD:
4037 	 * SIG_DFL handler does not wake sigsuspend().
4038 	 */
4039 	INT_OFF;
4040 	if (block == DOWAIT_BLOCK_OR_SIG) {
4041 		pid = wait_block_or_sig(&status);
4042 	} else {
4043 		int wait_flags = 0;
4044 		if (block == DOWAIT_NONBLOCK)
4045 			wait_flags = WNOHANG;
4046 		/* if job control is active, accept stopped processes too */
4047 		if (doing_jobctl)
4048 			wait_flags |= WUNTRACED;
4049 		/* NB: _not_ safe_waitpid, we need to detect EINTR */
4050 		pid = waitpid(-1, &status, wait_flags);
4051 	}
4052 	TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4053 				pid, status, errno, strerror(errno)));
4054 	if (pid <= 0)
4055 		goto out;
4056 
4057 	thisjob = NULL;
4058 	for (jp = curjob; jp; jp = jp->prev_job) {
4059 		int jobstate;
4060 		struct procstat *ps;
4061 		struct procstat *psend;
4062 		if (jp->state == JOBDONE)
4063 			continue;
4064 		jobstate = JOBDONE;
4065 		ps = jp->ps;
4066 		psend = ps + jp->nprocs;
4067 		do {
4068 			if (ps->ps_pid == pid) {
4069 				TRACE(("Job %d: changing status of proc %d "
4070 					"from 0x%x to 0x%x\n",
4071 					jobno(jp), pid, ps->ps_status, status));
4072 				ps->ps_status = status;
4073 				thisjob = jp;
4074 			}
4075 			if (ps->ps_status == -1)
4076 				jobstate = JOBRUNNING;
4077 #if JOBS
4078 			if (jobstate == JOBRUNNING)
4079 				continue;
4080 			if (WIFSTOPPED(ps->ps_status)) {
4081 				jp->stopstatus = ps->ps_status;
4082 				jobstate = JOBSTOPPED;
4083 			}
4084 #endif
4085 		} while (++ps < psend);
4086 		if (!thisjob)
4087 			continue;
4088 
4089 		/* Found the job where one of its processes changed its state.
4090 		 * Is there at least one live and running process in this job? */
4091 		if (jobstate != JOBRUNNING) {
4092 			/* No. All live processes in the job are stopped
4093 			 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4094 			 */
4095 			thisjob->changed = 1;
4096 			if (thisjob->state != jobstate) {
4097 				TRACE(("Job %d: changing state from %d to %d\n",
4098 					jobno(thisjob), thisjob->state, jobstate));
4099 				thisjob->state = jobstate;
4100 #if JOBS
4101 				if (jobstate == JOBSTOPPED)
4102 					set_curjob(thisjob, CUR_STOPPED);
4103 #endif
4104 			}
4105 		}
4106 		goto out;
4107 	}
4108 	/* The process wasn't found in job list */
4109 	if (JOBS && !WIFSTOPPED(status))
4110 		jobless--;
4111  out:
4112 	INT_ON;
4113 
4114 	if (thisjob && thisjob == job) {
4115 		char s[48 + 1];
4116 		int len;
4117 
4118 		len = sprint_status48(s, status, 1);
4119 		if (len) {
4120 			s[len] = '\n';
4121 			s[len + 1] = '\0';
4122 			out2str(s);
4123 		}
4124 	}
4125 	return pid;
4126 }
4127 
4128 #if JOBS
4129 static void
showjob(struct job * jp,int mode)4130 showjob(struct job *jp, int mode)
4131 {
4132 	struct procstat *ps;
4133 	struct procstat *psend;
4134 	int col;
4135 	int indent_col;
4136 	char s[16 + 16 + 48];
4137 	FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4138 
4139 	ps = jp->ps;
4140 
4141 	if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4142 		/* just output process (group) id of pipeline */
4143 		fprintf(out, "%d\n", ps->ps_pid);
4144 		return;
4145 	}
4146 
4147 	col = fmtstr(s, 16, "[%d]   ", jobno(jp));
4148 	indent_col = col;
4149 
4150 	if (jp == curjob)
4151 		s[col - 3] = '+';
4152 	else if (curjob && jp == curjob->prev_job)
4153 		s[col - 3] = '-';
4154 
4155 	if (mode & SHOW_PIDS)
4156 		col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4157 
4158 	psend = ps + jp->nprocs;
4159 
4160 	if (jp->state == JOBRUNNING) {
4161 		strcpy(s + col, "Running");
4162 		col += sizeof("Running") - 1;
4163 	} else {
4164 		int status = psend[-1].ps_status;
4165 		if (jp->state == JOBSTOPPED)
4166 			status = jp->stopstatus;
4167 		col += sprint_status48(s + col, status, 0);
4168 	}
4169 	/* By now, "[JOBID]*  [maybe PID] STATUS" is printed */
4170 
4171 	/* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4172 	 * or prints several "PID             | <cmdN>" lines,
4173 	 * depending on SHOW_PIDS bit.
4174 	 * We do not print status of individual processes
4175 	 * between PID and <cmdN>. bash does it, but not very well:
4176 	 * first line shows overall job status, not process status,
4177 	 * making it impossible to know 1st process status.
4178 	 */
4179 	goto start;
4180 	do {
4181 		/* for each process */
4182 		s[0] = '\0';
4183 		col = 33;
4184 		if (mode & SHOW_PIDS)
4185 			col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4186  start:
4187 		fprintf(out, "%s%*c%s%s",
4188 				s,
4189 				33 - col >= 0 ? 33 - col : 0, ' ',
4190 				ps == jp->ps ? "" : "| ",
4191 				ps->ps_cmd
4192 		);
4193 	} while (++ps != psend);
4194 	newline_and_flush(out);
4195 
4196 	jp->changed = 0;
4197 
4198 	if (jp->state == JOBDONE) {
4199 		TRACE(("showjob: freeing job %d\n", jobno(jp)));
4200 		freejob(jp);
4201 	}
4202 }
4203 
4204 /*
4205  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
4206  * statuses have changed since the last call to showjobs.
4207  */
4208 static void
showjobs(int mode)4209 showjobs(int mode)
4210 {
4211 	struct job *jp;
4212 
4213 	TRACE(("showjobs(0x%x) called\n", mode));
4214 
4215 	/* Handle all finished jobs */
4216 	while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
4217 		continue;
4218 
4219 	for (jp = curjob; jp; jp = jp->prev_job) {
4220 		if (!(mode & SHOW_CHANGED) || jp->changed) {
4221 			showjob(jp, mode);
4222 		}
4223 	}
4224 }
4225 
4226 static int FAST_FUNC
jobscmd(int argc UNUSED_PARAM,char ** argv)4227 jobscmd(int argc UNUSED_PARAM, char **argv)
4228 {
4229 	int mode, m;
4230 
4231 	mode = 0;
4232 	while ((m = nextopt("lp")) != '\0') {
4233 		if (m == 'l')
4234 			mode |= SHOW_PIDS;
4235 		else
4236 			mode |= SHOW_ONLY_PGID;
4237 	}
4238 
4239 	argv = argptr;
4240 	if (*argv) {
4241 		do
4242 			showjob(getjob(*argv, 0), mode);
4243 		while (*++argv);
4244 	} else {
4245 		showjobs(mode);
4246 	}
4247 
4248 	return 0;
4249 }
4250 #endif /* JOBS */
4251 
4252 /* Called only on finished or stopped jobs (no members are running) */
4253 static int
getstatus(struct job * job)4254 getstatus(struct job *job)
4255 {
4256 	int status;
4257 	int retval;
4258 	struct procstat *ps;
4259 
4260 	/* Fetch last member's status */
4261 	ps = job->ps + job->nprocs - 1;
4262 	status = ps->ps_status;
4263 	if (pipefail) {
4264 		/* "set -o pipefail" mode: use last _nonzero_ status */
4265 		while (status == 0 && --ps >= job->ps)
4266 			status = ps->ps_status;
4267 	}
4268 
4269 	retval = WEXITSTATUS(status);
4270 	if (!WIFEXITED(status)) {
4271 #if JOBS
4272 		retval = WSTOPSIG(status);
4273 		if (!WIFSTOPPED(status))
4274 #endif
4275 		{
4276 			/* XXX: limits number of signals */
4277 			retval = WTERMSIG(status);
4278 #if JOBS
4279 			if (retval == SIGINT)
4280 				job->sigint = 1;
4281 #endif
4282 		}
4283 		retval += 128;
4284 	}
4285 	TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4286 		jobno(job), job->nprocs, status, retval));
4287 	return retval;
4288 }
4289 
4290 static int FAST_FUNC
waitcmd(int argc UNUSED_PARAM,char ** argv)4291 waitcmd(int argc UNUSED_PARAM, char **argv)
4292 {
4293 	struct job *job;
4294 	int retval;
4295 	struct job *jp;
4296 
4297 	nextopt(nullstr);
4298 	retval = 0;
4299 
4300 	argv = argptr;
4301 	if (!*argv) {
4302 		/* wait for all jobs */
4303 		for (;;) {
4304 			jp = curjob;
4305 			while (1) {
4306 				if (!jp) /* no running procs */
4307 					goto ret;
4308 				if (jp->state == JOBRUNNING)
4309 					break;
4310 				jp->waited = 1;
4311 				jp = jp->prev_job;
4312 			}
4313 	/* man bash:
4314 	 * "When bash is waiting for an asynchronous command via
4315 	 * the wait builtin, the reception of a signal for which a trap
4316 	 * has been set will cause the wait builtin to return immediately
4317 	 * with an exit status greater than 128, immediately after which
4318 	 * the trap is executed."
4319 	 */
4320 			dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4321 	/* if child sends us a signal *and immediately exits*,
4322 	 * dowait() returns pid > 0. Check this case,
4323 	 * not "if (dowait() < 0)"!
4324 	 */
4325 			if (pending_sig)
4326 				goto sigout;
4327 		}
4328 	}
4329 
4330 	retval = 127;
4331 	do {
4332 		if (**argv != '%') {
4333 			pid_t pid = number(*argv);
4334 			job = curjob;
4335 			while (1) {
4336 				if (!job)
4337 					goto repeat;
4338 				if (job->ps[job->nprocs - 1].ps_pid == pid)
4339 					break;
4340 				job = job->prev_job;
4341 			}
4342 		} else {
4343 			job = getjob(*argv, 0);
4344 		}
4345 		/* loop until process terminated or stopped */
4346 		while (job->state == JOBRUNNING) {
4347 			dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4348 			if (pending_sig)
4349 				goto sigout;
4350 		}
4351 		job->waited = 1;
4352 		retval = getstatus(job);
4353  repeat: ;
4354 	} while (*++argv);
4355 
4356  ret:
4357 	return retval;
4358  sigout:
4359 	retval = 128 + pending_sig;
4360 	return retval;
4361 }
4362 
4363 static struct job *
growjobtab(void)4364 growjobtab(void)
4365 {
4366 	size_t len;
4367 	ptrdiff_t offset;
4368 	struct job *jp, *jq;
4369 
4370 	len = njobs * sizeof(*jp);
4371 	jq = jobtab;
4372 	jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4373 
4374 	offset = (char *)jp - (char *)jq;
4375 	if (offset) {
4376 		/* Relocate pointers */
4377 		size_t l = len;
4378 
4379 		jq = (struct job *)((char *)jq + l);
4380 		while (l) {
4381 			l -= sizeof(*jp);
4382 			jq--;
4383 #define joff(p) ((struct job *)((char *)(p) + l))
4384 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4385 			if (joff(jp)->ps == &jq->ps0)
4386 				jmove(joff(jp)->ps);
4387 			if (joff(jp)->prev_job)
4388 				jmove(joff(jp)->prev_job);
4389 		}
4390 		if (curjob)
4391 			jmove(curjob);
4392 #undef joff
4393 #undef jmove
4394 	}
4395 
4396 	njobs += 4;
4397 	jobtab = jp;
4398 	jp = (struct job *)((char *)jp + len);
4399 	jq = jp + 3;
4400 	do {
4401 		jq->used = 0;
4402 	} while (--jq >= jp);
4403 	return jp;
4404 }
4405 
4406 /*
4407  * Return a new job structure.
4408  * Called with interrupts off.
4409  */
4410 static struct job *
makejob(int nprocs)4411 makejob(/*union node *node,*/ int nprocs)
4412 {
4413 	int i;
4414 	struct job *jp;
4415 
4416 	for (i = njobs, jp = jobtab; ; jp++) {
4417 		if (--i < 0) {
4418 			jp = growjobtab();
4419 			break;
4420 		}
4421 		if (jp->used == 0)
4422 			break;
4423 		if (jp->state != JOBDONE || !jp->waited)
4424 			continue;
4425 #if JOBS
4426 		if (doing_jobctl)
4427 			continue;
4428 #endif
4429 		freejob(jp);
4430 		break;
4431 	}
4432 	memset(jp, 0, sizeof(*jp));
4433 #if JOBS
4434 	/* jp->jobctl is a bitfield.
4435 	 * "jp->jobctl |= jobctl" likely to give awful code */
4436 	if (doing_jobctl)
4437 		jp->jobctl = 1;
4438 #endif
4439 	jp->prev_job = curjob;
4440 	curjob = jp;
4441 	jp->used = 1;
4442 	jp->ps = &jp->ps0;
4443 	if (nprocs > 1) {
4444 		jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4445 	}
4446 	TRACE(("makejob(%d) returns %%%d\n", nprocs,
4447 				jobno(jp)));
4448 	return jp;
4449 }
4450 
4451 #if JOBS
4452 /*
4453  * Return a string identifying a command (to be printed by the
4454  * jobs command).
4455  */
4456 static char *cmdnextc;
4457 
4458 static void
cmdputs(const char * s)4459 cmdputs(const char *s)
4460 {
4461 	static const char vstype[VSTYPE + 1][3] = {
4462 		"", "}", "-", "+", "?", "=",
4463 		"%", "%%", "#", "##"
4464 		IF_ASH_BASH_COMPAT(, ":", "/", "//")
4465 	};
4466 
4467 	const char *p, *str;
4468 	char cc[2];
4469 	char *nextc;
4470 	unsigned char c;
4471 	unsigned char subtype = 0;
4472 	int quoted = 0;
4473 
4474 	cc[1] = '\0';
4475 	nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4476 	p = s;
4477 	while ((c = *p++) != '\0') {
4478 		str = NULL;
4479 		switch (c) {
4480 		case CTLESC:
4481 			c = *p++;
4482 			break;
4483 		case CTLVAR:
4484 			subtype = *p++;
4485 			if ((subtype & VSTYPE) == VSLENGTH)
4486 				str = "${#";
4487 			else
4488 				str = "${";
4489 			goto dostr;
4490 		case CTLENDVAR:
4491 			str = "\"}" + !(quoted & 1);
4492 			quoted >>= 1;
4493 			subtype = 0;
4494 			goto dostr;
4495 		case CTLBACKQ:
4496 			str = "$(...)";
4497 			goto dostr;
4498 #if ENABLE_FEATURE_SH_MATH
4499 		case CTLARI:
4500 			str = "$((";
4501 			goto dostr;
4502 		case CTLENDARI:
4503 			str = "))";
4504 			goto dostr;
4505 #endif
4506 		case CTLQUOTEMARK:
4507 			quoted ^= 1;
4508 			c = '"';
4509 			break;
4510 		case '=':
4511 			if (subtype == 0)
4512 				break;
4513 			if ((subtype & VSTYPE) != VSNORMAL)
4514 				quoted <<= 1;
4515 			str = vstype[subtype & VSTYPE];
4516 			if (subtype & VSNUL)
4517 				c = ':';
4518 			else
4519 				goto checkstr;
4520 			break;
4521 		case '\'':
4522 		case '\\':
4523 		case '"':
4524 		case '$':
4525 			/* These can only happen inside quotes */
4526 			cc[0] = c;
4527 			str = cc;
4528 			c = '\\';
4529 			break;
4530 		default:
4531 			break;
4532 		}
4533 		USTPUTC(c, nextc);
4534  checkstr:
4535 		if (!str)
4536 			continue;
4537  dostr:
4538 		while ((c = *str++) != '\0') {
4539 			USTPUTC(c, nextc);
4540 		}
4541 	} /* while *p++ not NUL */
4542 
4543 	if (quoted & 1) {
4544 		USTPUTC('"', nextc);
4545 	}
4546 	*nextc = 0;
4547 	cmdnextc = nextc;
4548 }
4549 
4550 /* cmdtxt() and cmdlist() call each other */
4551 static void cmdtxt(union node *n);
4552 
4553 static void
cmdlist(union node * np,int sep)4554 cmdlist(union node *np, int sep)
4555 {
4556 	for (; np; np = np->narg.next) {
4557 		if (!sep)
4558 			cmdputs(" ");
4559 		cmdtxt(np);
4560 		if (sep && np->narg.next)
4561 			cmdputs(" ");
4562 	}
4563 }
4564 
4565 static void
cmdtxt(union node * n)4566 cmdtxt(union node *n)
4567 {
4568 	union node *np;
4569 	struct nodelist *lp;
4570 	const char *p;
4571 
4572 	if (!n)
4573 		return;
4574 	switch (n->type) {
4575 	default:
4576 #if DEBUG
4577 		abort();
4578 #endif
4579 	case NPIPE:
4580 		lp = n->npipe.cmdlist;
4581 		for (;;) {
4582 			cmdtxt(lp->n);
4583 			lp = lp->next;
4584 			if (!lp)
4585 				break;
4586 			cmdputs(" | ");
4587 		}
4588 		break;
4589 	case NSEMI:
4590 		p = "; ";
4591 		goto binop;
4592 	case NAND:
4593 		p = " && ";
4594 		goto binop;
4595 	case NOR:
4596 		p = " || ";
4597  binop:
4598 		cmdtxt(n->nbinary.ch1);
4599 		cmdputs(p);
4600 		n = n->nbinary.ch2;
4601 		goto donode;
4602 	case NREDIR:
4603 	case NBACKGND:
4604 		n = n->nredir.n;
4605 		goto donode;
4606 	case NNOT:
4607 		cmdputs("!");
4608 		n = n->nnot.com;
4609  donode:
4610 		cmdtxt(n);
4611 		break;
4612 	case NIF:
4613 		cmdputs("if ");
4614 		cmdtxt(n->nif.test);
4615 		cmdputs("; then ");
4616 		if (n->nif.elsepart) {
4617 			cmdtxt(n->nif.ifpart);
4618 			cmdputs("; else ");
4619 			n = n->nif.elsepart;
4620 		} else {
4621 			n = n->nif.ifpart;
4622 		}
4623 		p = "; fi";
4624 		goto dotail;
4625 	case NSUBSHELL:
4626 		cmdputs("(");
4627 		n = n->nredir.n;
4628 		p = ")";
4629 		goto dotail;
4630 	case NWHILE:
4631 		p = "while ";
4632 		goto until;
4633 	case NUNTIL:
4634 		p = "until ";
4635  until:
4636 		cmdputs(p);
4637 		cmdtxt(n->nbinary.ch1);
4638 		n = n->nbinary.ch2;
4639 		p = "; done";
4640  dodo:
4641 		cmdputs("; do ");
4642  dotail:
4643 		cmdtxt(n);
4644 		goto dotail2;
4645 	case NFOR:
4646 		cmdputs("for ");
4647 		cmdputs(n->nfor.var);
4648 		cmdputs(" in ");
4649 		cmdlist(n->nfor.args, 1);
4650 		n = n->nfor.body;
4651 		p = "; done";
4652 		goto dodo;
4653 	case NDEFUN:
4654 		cmdputs(n->narg.text);
4655 		p = "() { ... }";
4656 		goto dotail2;
4657 	case NCMD:
4658 		cmdlist(n->ncmd.args, 1);
4659 		cmdlist(n->ncmd.redirect, 0);
4660 		break;
4661 	case NARG:
4662 		p = n->narg.text;
4663  dotail2:
4664 		cmdputs(p);
4665 		break;
4666 	case NHERE:
4667 	case NXHERE:
4668 		p = "<<...";
4669 		goto dotail2;
4670 	case NCASE:
4671 		cmdputs("case ");
4672 		cmdputs(n->ncase.expr->narg.text);
4673 		cmdputs(" in ");
4674 		for (np = n->ncase.cases; np; np = np->nclist.next) {
4675 			cmdtxt(np->nclist.pattern);
4676 			cmdputs(") ");
4677 			cmdtxt(np->nclist.body);
4678 			cmdputs(";; ");
4679 		}
4680 		p = "esac";
4681 		goto dotail2;
4682 	case NTO:
4683 		p = ">";
4684 		goto redir;
4685 	case NCLOBBER:
4686 		p = ">|";
4687 		goto redir;
4688 	case NAPPEND:
4689 		p = ">>";
4690 		goto redir;
4691 #if ENABLE_ASH_BASH_COMPAT
4692 	case NTO2:
4693 #endif
4694 	case NTOFD:
4695 		p = ">&";
4696 		goto redir;
4697 	case NFROM:
4698 		p = "<";
4699 		goto redir;
4700 	case NFROMFD:
4701 		p = "<&";
4702 		goto redir;
4703 	case NFROMTO:
4704 		p = "<>";
4705  redir:
4706 		cmdputs(utoa(n->nfile.fd));
4707 		cmdputs(p);
4708 		if (n->type == NTOFD || n->type == NFROMFD) {
4709 			cmdputs(utoa(n->ndup.dupfd));
4710 			break;
4711 		}
4712 		n = n->nfile.fname;
4713 		goto donode;
4714 	}
4715 }
4716 
4717 static char *
commandtext(union node * n)4718 commandtext(union node *n)
4719 {
4720 	char *name;
4721 
4722 	STARTSTACKSTR(cmdnextc);
4723 	cmdtxt(n);
4724 	name = stackblock();
4725 	TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
4726 	return ckstrdup(name);
4727 }
4728 #endif /* JOBS */
4729 
4730 /*
4731  * Fork off a subshell.  If we are doing job control, give the subshell its
4732  * own process group.  Jp is a job structure that the job is to be added to.
4733  * N is the command that will be evaluated by the child.  Both jp and n may
4734  * be NULL.  The mode parameter can be one of the following:
4735  *      FORK_FG - Fork off a foreground process.
4736  *      FORK_BG - Fork off a background process.
4737  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
4738  *                   process group even if job control is on.
4739  *
4740  * When job control is turned off, background processes have their standard
4741  * input redirected to /dev/null (except for the second and later processes
4742  * in a pipeline).
4743  *
4744  * Called with interrupts off.
4745  */
4746 /*
4747  * Clear traps on a fork.
4748  */
4749 static void
clear_traps(void)4750 clear_traps(void)
4751 {
4752 	char **tp;
4753 
4754 	INT_OFF;
4755 	for (tp = trap; tp < &trap[NSIG]; tp++) {
4756 		if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */
4757 			if (trap_ptr == trap)
4758 				free(*tp);
4759 			/* else: it "belongs" to trap_ptr vector, don't free */
4760 			*tp = NULL;
4761 			if ((tp - trap) != 0)
4762 				setsignal(tp - trap);
4763 		}
4764 	}
4765 	may_have_traps = 0;
4766 	INT_ON;
4767 }
4768 
4769 /* Lives far away from here, needed for forkchild */
4770 static void closescript(void);
4771 
4772 /* Called after fork(), in child */
4773 /* jp and n are NULL when called by openhere() for heredoc support */
4774 static NOINLINE void
forkchild(struct job * jp,union node * n,int mode)4775 forkchild(struct job *jp, union node *n, int mode)
4776 {
4777 	int oldlvl;
4778 
4779 	TRACE(("Child shell %d\n", getpid()));
4780 	oldlvl = shlvl;
4781 	shlvl++;
4782 
4783 	/* man bash: "Non-builtin commands run by bash have signal handlers
4784 	 * set to the values inherited by the shell from its parent".
4785 	 * Do we do it correctly? */
4786 
4787 	closescript();
4788 
4789 	if (mode == FORK_NOJOB          /* is it `xxx` ? */
4790 	 && n && n->type == NCMD        /* is it single cmd? */
4791 	/* && n->ncmd.args->type == NARG - always true? */
4792 	 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
4793 	 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4794 	/* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4795 	) {
4796 		TRACE(("Trap hack\n"));
4797 		/* Awful hack for `trap` or $(trap).
4798 		 *
4799 		 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4800 		 * contains an example where "trap" is executed in a subshell:
4801 		 *
4802 		 * save_traps=$(trap)
4803 		 * ...
4804 		 * eval "$save_traps"
4805 		 *
4806 		 * Standard does not say that "trap" in subshell shall print
4807 		 * parent shell's traps. It only says that its output
4808 		 * must have suitable form, but then, in the above example
4809 		 * (which is not supposed to be normative), it implies that.
4810 		 *
4811 		 * bash (and probably other shell) does implement it
4812 		 * (traps are reset to defaults, but "trap" still shows them),
4813 		 * but as a result, "trap" logic is hopelessly messed up:
4814 		 *
4815 		 * # trap
4816 		 * trap -- 'echo Ho' SIGWINCH  <--- we have a handler
4817 		 * # (trap)        <--- trap is in subshell - no output (correct, traps are reset)
4818 		 * # true | trap   <--- trap is in subshell - no output (ditto)
4819 		 * # echo `true | trap`    <--- in subshell - output (but traps are reset!)
4820 		 * trap -- 'echo Ho' SIGWINCH
4821 		 * # echo `(trap)`         <--- in subshell in subshell - output
4822 		 * trap -- 'echo Ho' SIGWINCH
4823 		 * # echo `true | (trap)`  <--- in subshell in subshell in subshell - output!
4824 		 * trap -- 'echo Ho' SIGWINCH
4825 		 *
4826 		 * The rules when to forget and when to not forget traps
4827 		 * get really complex and nonsensical.
4828 		 *
4829 		 * Our solution: ONLY bare $(trap) or `trap` is special.
4830 		 */
4831 		/* Save trap handler strings for trap builtin to print */
4832 		trap_ptr = xmemdup(trap, sizeof(trap));
4833 		/* Fall through into clearing traps */
4834 	}
4835 	clear_traps();
4836 #if JOBS
4837 	/* do job control only in root shell */
4838 	doing_jobctl = 0;
4839 	if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
4840 		pid_t pgrp;
4841 
4842 		if (jp->nprocs == 0)
4843 			pgrp = getpid();
4844 		else
4845 			pgrp = jp->ps[0].ps_pid;
4846 		/* this can fail because we are doing it in the parent also */
4847 		setpgid(0, pgrp);
4848 		if (mode == FORK_FG)
4849 			xtcsetpgrp(ttyfd, pgrp);
4850 		setsignal(SIGTSTP);
4851 		setsignal(SIGTTOU);
4852 	} else
4853 #endif
4854 	if (mode == FORK_BG) {
4855 		/* man bash: "When job control is not in effect,
4856 		 * asynchronous commands ignore SIGINT and SIGQUIT" */
4857 		ignoresig(SIGINT);
4858 		ignoresig(SIGQUIT);
4859 		if (jp->nprocs == 0) {
4860 			close(0);
4861 			if (open(bb_dev_null, O_RDONLY) != 0)
4862 				ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4863 		}
4864 	}
4865 	if (oldlvl == 0) {
4866 		if (iflag) { /* why if iflag only? */
4867 			setsignal(SIGINT);
4868 			setsignal(SIGTERM);
4869 		}
4870 		/* man bash:
4871 		 * "In all cases, bash ignores SIGQUIT. Non-builtin
4872 		 * commands run by bash have signal handlers
4873 		 * set to the values inherited by the shell
4874 		 * from its parent".
4875 		 * Take care of the second rule: */
4876 		setsignal(SIGQUIT);
4877 	}
4878 #if JOBS
4879 	if (n && n->type == NCMD
4880 	 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
4881 	) {
4882 		TRACE(("Job hack\n"));
4883 		/* "jobs": we do not want to clear job list for it,
4884 		 * instead we remove only _its_ own_ job from job list.
4885 		 * This makes "jobs .... | cat" more useful.
4886 		 */
4887 		freejob(curjob);
4888 		return;
4889 	}
4890 #endif
4891 	for (jp = curjob; jp; jp = jp->prev_job)
4892 		freejob(jp);
4893 	jobless = 0;
4894 }
4895 
4896 /* Called after fork(), in parent */
4897 #if !JOBS
4898 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4899 #endif
4900 static void
forkparent(struct job * jp,union node * n,int mode,pid_t pid)4901 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4902 {
4903 	TRACE(("In parent shell: child = %d\n", pid));
4904 	if (!jp) {
4905 		/* jp is NULL when called by openhere() for heredoc support */
4906 		while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4907 			continue;
4908 		jobless++;
4909 		return;
4910 	}
4911 #if JOBS
4912 	if (mode != FORK_NOJOB && jp->jobctl) {
4913 		int pgrp;
4914 
4915 		if (jp->nprocs == 0)
4916 			pgrp = pid;
4917 		else
4918 			pgrp = jp->ps[0].ps_pid;
4919 		/* This can fail because we are doing it in the child also */
4920 		setpgid(pid, pgrp);
4921 	}
4922 #endif
4923 	if (mode == FORK_BG) {
4924 		backgndpid = pid;               /* set $! */
4925 		set_curjob(jp, CUR_RUNNING);
4926 	}
4927 	if (jp) {
4928 		struct procstat *ps = &jp->ps[jp->nprocs++];
4929 		ps->ps_pid = pid;
4930 		ps->ps_status = -1;
4931 		ps->ps_cmd = nullstr;
4932 #if JOBS
4933 		if (doing_jobctl && n)
4934 			ps->ps_cmd = commandtext(n);
4935 #endif
4936 	}
4937 }
4938 
4939 /* jp and n are NULL when called by openhere() for heredoc support */
4940 static int
forkshell(struct job * jp,union node * n,int mode)4941 forkshell(struct job *jp, union node *n, int mode)
4942 {
4943 	int pid;
4944 
4945 	TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4946 	pid = fork();
4947 	if (pid < 0) {
4948 		TRACE(("Fork failed, errno=%d", errno));
4949 		if (jp)
4950 			freejob(jp);
4951 		ash_msg_and_raise_error("can't fork");
4952 	}
4953 	if (pid == 0) {
4954 		CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
4955 		forkchild(jp, n, mode);
4956 	} else {
4957 		forkparent(jp, n, mode, pid);
4958 	}
4959 	return pid;
4960 }
4961 
4962 /*
4963  * Wait for job to finish.
4964  *
4965  * Under job control we have the problem that while a child process
4966  * is running interrupts generated by the user are sent to the child
4967  * but not to the shell.  This means that an infinite loop started by
4968  * an interactive user may be hard to kill.  With job control turned off,
4969  * an interactive user may place an interactive program inside a loop.
4970  * If the interactive program catches interrupts, the user doesn't want
4971  * these interrupts to also abort the loop.  The approach we take here
4972  * is to have the shell ignore interrupt signals while waiting for a
4973  * foreground process to terminate, and then send itself an interrupt
4974  * signal if the child process was terminated by an interrupt signal.
4975  * Unfortunately, some programs want to do a bit of cleanup and then
4976  * exit on interrupt; unless these processes terminate themselves by
4977  * sending a signal to themselves (instead of calling exit) they will
4978  * confuse this approach.
4979  *
4980  * Called with interrupts off.
4981  */
4982 static int
waitforjob(struct job * jp)4983 waitforjob(struct job *jp)
4984 {
4985 	int st;
4986 
4987 	TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4988 
4989 	INT_OFF;
4990 	while (jp->state == JOBRUNNING) {
4991 		/* In non-interactive shells, we _can_ get
4992 		 * a keyboard signal here and be EINTRed,
4993 		 * but we just loop back, waiting for command to complete.
4994 		 *
4995 		 * man bash:
4996 		 * "If bash is waiting for a command to complete and receives
4997 		 * a signal for which a trap has been set, the trap
4998 		 * will not be executed until the command completes."
4999 		 *
5000 		 * Reality is that even if trap is not set, bash
5001 		 * will not act on the signal until command completes.
5002 		 * Try this. sleep5intoff.c:
5003 		 * #include <signal.h>
5004 		 * #include <unistd.h>
5005 		 * int main() {
5006 		 *         sigset_t set;
5007 		 *         sigemptyset(&set);
5008 		 *         sigaddset(&set, SIGINT);
5009 		 *         sigaddset(&set, SIGQUIT);
5010 		 *         sigprocmask(SIG_BLOCK, &set, NULL);
5011 		 *         sleep(5);
5012 		 *         return 0;
5013 		 * }
5014 		 * $ bash -c './sleep5intoff; echo hi'
5015 		 * ^C^C^C^C <--- pressing ^C once a second
5016 		 * $ _
5017 		 * $ bash -c './sleep5intoff; echo hi'
5018 		 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5019 		 * $ _
5020 		 */
5021 		dowait(DOWAIT_BLOCK, jp);
5022 	}
5023 	INT_ON;
5024 
5025 	st = getstatus(jp);
5026 #if JOBS
5027 	if (jp->jobctl) {
5028 		xtcsetpgrp(ttyfd, rootpid);
5029 		/*
5030 		 * This is truly gross.
5031 		 * If we're doing job control, then we did a TIOCSPGRP which
5032 		 * caused us (the shell) to no longer be in the controlling
5033 		 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
5034 		 * intuit from the subprocess exit status whether a SIGINT
5035 		 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
5036 		 */
5037 		if (jp->sigint) /* TODO: do the same with all signals */
5038 			raise(SIGINT); /* ... by raise(jp->sig) instead? */
5039 	}
5040 	if (jp->state == JOBDONE)
5041 #endif
5042 		freejob(jp);
5043 	return st;
5044 }
5045 
5046 /*
5047  * return 1 if there are stopped jobs, otherwise 0
5048  */
5049 static int
stoppedjobs(void)5050 stoppedjobs(void)
5051 {
5052 	struct job *jp;
5053 	int retval;
5054 
5055 	retval = 0;
5056 	if (job_warning)
5057 		goto out;
5058 	jp = curjob;
5059 	if (jp && jp->state == JOBSTOPPED) {
5060 		out2str("You have stopped jobs.\n");
5061 		job_warning = 2;
5062 		retval++;
5063 	}
5064  out:
5065 	return retval;
5066 }
5067 
5068 
5069 /*
5070  * Code for dealing with input/output redirection.
5071  */
5072 
5073 #undef EMPTY
5074 #undef CLOSED
5075 #define EMPTY -2                /* marks an unused slot in redirtab */
5076 #define CLOSED -3               /* marks a slot of previously-closed fd */
5077 
5078 /*
5079  * Open a file in noclobber mode.
5080  * The code was copied from bash.
5081  */
5082 static int
noclobberopen(const char * fname)5083 noclobberopen(const char *fname)
5084 {
5085 	int r, fd;
5086 	struct stat finfo, finfo2;
5087 
5088 	/*
5089 	 * If the file exists and is a regular file, return an error
5090 	 * immediately.
5091 	 */
5092 	r = stat(fname, &finfo);
5093 	if (r == 0 && S_ISREG(finfo.st_mode)) {
5094 		errno = EEXIST;
5095 		return -1;
5096 	}
5097 
5098 	/*
5099 	 * If the file was not present (r != 0), make sure we open it
5100 	 * exclusively so that if it is created before we open it, our open
5101 	 * will fail.  Make sure that we do not truncate an existing file.
5102 	 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5103 	 * file was not a regular file, we leave O_EXCL off.
5104 	 */
5105 	if (r != 0)
5106 		return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5107 	fd = open(fname, O_WRONLY|O_CREAT, 0666);
5108 
5109 	/* If the open failed, return the file descriptor right away. */
5110 	if (fd < 0)
5111 		return fd;
5112 
5113 	/*
5114 	 * OK, the open succeeded, but the file may have been changed from a
5115 	 * non-regular file to a regular file between the stat and the open.
5116 	 * We are assuming that the O_EXCL open handles the case where FILENAME
5117 	 * did not exist and is symlinked to an existing file between the stat
5118 	 * and open.
5119 	 */
5120 
5121 	/*
5122 	 * If we can open it and fstat the file descriptor, and neither check
5123 	 * revealed that it was a regular file, and the file has not been
5124 	 * replaced, return the file descriptor.
5125 	 */
5126 	if (fstat(fd, &finfo2) == 0
5127 	 && !S_ISREG(finfo2.st_mode)
5128 	 && finfo.st_dev == finfo2.st_dev
5129 	 && finfo.st_ino == finfo2.st_ino
5130 	) {
5131 		return fd;
5132 	}
5133 
5134 	/* The file has been replaced.  badness. */
5135 	close(fd);
5136 	errno = EEXIST;
5137 	return -1;
5138 }
5139 
5140 /*
5141  * Handle here documents.  Normally we fork off a process to write the
5142  * data to a pipe.  If the document is short, we can stuff the data in
5143  * the pipe without forking.
5144  */
5145 /* openhere needs this forward reference */
5146 static void expandhere(union node *arg, int fd);
5147 static int
openhere(union node * redir)5148 openhere(union node *redir)
5149 {
5150 	int pip[2];
5151 	size_t len = 0;
5152 
5153 	if (pipe(pip) < 0)
5154 		ash_msg_and_raise_error("pipe call failed");
5155 	if (redir->type == NHERE) {
5156 		len = strlen(redir->nhere.doc->narg.text);
5157 		if (len <= PIPE_BUF) {
5158 			full_write(pip[1], redir->nhere.doc->narg.text, len);
5159 			goto out;
5160 		}
5161 	}
5162 	if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5163 		/* child */
5164 		close(pip[0]);
5165 		ignoresig(SIGINT);  //signal(SIGINT, SIG_IGN);
5166 		ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5167 		ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
5168 		ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5169 		signal(SIGPIPE, SIG_DFL);
5170 		if (redir->type == NHERE)
5171 			full_write(pip[1], redir->nhere.doc->narg.text, len);
5172 		else /* NXHERE */
5173 			expandhere(redir->nhere.doc, pip[1]);
5174 		_exit(EXIT_SUCCESS);
5175 	}
5176  out:
5177 	close(pip[1]);
5178 	return pip[0];
5179 }
5180 
5181 static int
openredirect(union node * redir)5182 openredirect(union node *redir)
5183 {
5184 	char *fname;
5185 	int f;
5186 
5187 	switch (redir->nfile.type) {
5188 /* Can't happen, our single caller does this itself */
5189 //	case NTOFD:
5190 //	case NFROMFD:
5191 //		return -1;
5192 	case NHERE:
5193 	case NXHERE:
5194 		return openhere(redir);
5195 	}
5196 
5197 	/* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5198 	 * allocated space. Do it only when we know it is safe.
5199 	 */
5200 	fname = redir->nfile.expfname;
5201 
5202 	switch (redir->nfile.type) {
5203 	default:
5204 #if DEBUG
5205 		abort();
5206 #endif
5207 	case NFROM:
5208 		f = open(fname, O_RDONLY);
5209 		if (f < 0)
5210 			goto eopen;
5211 		break;
5212 	case NFROMTO:
5213 		f = open(fname, O_RDWR|O_CREAT, 0666);
5214 		if (f < 0)
5215 			goto ecreate;
5216 		break;
5217 	case NTO:
5218 #if ENABLE_ASH_BASH_COMPAT
5219 	case NTO2:
5220 #endif
5221 		/* Take care of noclobber mode. */
5222 		if (Cflag) {
5223 			f = noclobberopen(fname);
5224 			if (f < 0)
5225 				goto ecreate;
5226 			break;
5227 		}
5228 		/* FALLTHROUGH */
5229 	case NCLOBBER:
5230 		f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5231 		if (f < 0)
5232 			goto ecreate;
5233 		break;
5234 	case NAPPEND:
5235 		f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5236 		if (f < 0)
5237 			goto ecreate;
5238 		break;
5239 	}
5240 
5241 	return f;
5242  ecreate:
5243 	ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5244  eopen:
5245 	ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5246 }
5247 
5248 /*
5249  * Copy a file descriptor to be >= 10. Throws exception on error.
5250  */
5251 static int
savefd(int from)5252 savefd(int from)
5253 {
5254 	int newfd;
5255 	int err;
5256 
5257 	newfd = fcntl(from, F_DUPFD, 10);
5258 	err = newfd < 0 ? errno : 0;
5259 	if (err != EBADF) {
5260 		if (err)
5261 			ash_msg_and_raise_error("%d: %m", from);
5262 		close(from);
5263 		fcntl(newfd, F_SETFD, FD_CLOEXEC);
5264 	}
5265 
5266 	return newfd;
5267 }
5268 static int
dup2_or_raise(int from,int to)5269 dup2_or_raise(int from, int to)
5270 {
5271 	int newfd;
5272 
5273 	newfd = (from != to) ? dup2(from, to) : to;
5274 	if (newfd < 0) {
5275 		/* Happens when source fd is not open: try "echo >&99" */
5276 		ash_msg_and_raise_error("%d: %m", from);
5277 	}
5278 	return newfd;
5279 }
5280 
5281 /* Struct def and variable are moved down to the first usage site */
5282 struct two_fd_t {
5283 	int orig, copy;
5284 };
5285 struct redirtab {
5286 	struct redirtab *next;
5287 	int pair_count;
5288 	struct two_fd_t two_fd[];
5289 };
5290 #define redirlist (G_var.redirlist)
5291 enum {
5292 	COPYFD_RESTORE = (int)~(INT_MAX),
5293 };
5294 
5295 static int
need_to_remember(struct redirtab * rp,int fd)5296 need_to_remember(struct redirtab *rp, int fd)
5297 {
5298 	int i;
5299 
5300 	if (!rp) /* remembering was not requested */
5301 		return 0;
5302 
5303 	for (i = 0; i < rp->pair_count; i++) {
5304 		if (rp->two_fd[i].orig == fd) {
5305 			/* already remembered */
5306 			return 0;
5307 		}
5308 	}
5309 	return 1;
5310 }
5311 
5312 /* "hidden" fd is a fd used to read scripts, or a copy of such */
5313 static int
is_hidden_fd(struct redirtab * rp,int fd)5314 is_hidden_fd(struct redirtab *rp, int fd)
5315 {
5316 	int i;
5317 	struct parsefile *pf;
5318 
5319 	if (fd == -1)
5320 		return 0;
5321 	/* Check open scripts' fds */
5322 	pf = g_parsefile;
5323 	while (pf) {
5324 		/* We skip pf_fd == 0 case because of the following case:
5325 		 * $ ash  # running ash interactively
5326 		 * $ . ./script.sh
5327 		 * and in script.sh: "exec 9>&0".
5328 		 * Even though top-level pf_fd _is_ 0,
5329 		 * it's still ok to use it: "read" builtin uses it,
5330 		 * why should we cripple "exec" builtin?
5331 		 */
5332 		if (pf->pf_fd > 0 && fd == pf->pf_fd) {
5333 			return 1;
5334 		}
5335 		pf = pf->prev;
5336 	}
5337 
5338 	if (!rp)
5339 		return 0;
5340 	/* Check saved fds of redirects */
5341 	fd |= COPYFD_RESTORE;
5342 	for (i = 0; i < rp->pair_count; i++) {
5343 		if (rp->two_fd[i].copy == fd) {
5344 			return 1;
5345 		}
5346 	}
5347 	return 0;
5348 }
5349 
5350 /*
5351  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
5352  * old file descriptors are stashed away so that the redirection can be
5353  * undone by calling popredir.
5354  */
5355 /* flags passed to redirect */
5356 #define REDIR_PUSH    01        /* save previous values of file descriptors */
5357 #define REDIR_SAVEFD2 03        /* set preverrout */
5358 static void
redirect(union node * redir,int flags)5359 redirect(union node *redir, int flags)
5360 {
5361 	struct redirtab *sv;
5362 	int sv_pos;
5363 	int i;
5364 	int fd;
5365 	int newfd;
5366 	int copied_fd2 = -1;
5367 
5368 	if (!redir) {
5369 		return;
5370 	}
5371 
5372 	sv = NULL;
5373 	sv_pos = 0;
5374 	INT_OFF;
5375 	if (flags & REDIR_PUSH) {
5376 		union node *tmp = redir;
5377 		do {
5378 			sv_pos++;
5379 #if ENABLE_ASH_BASH_COMPAT
5380 			if (tmp->nfile.type == NTO2)
5381 				sv_pos++;
5382 #endif
5383 			tmp = tmp->nfile.next;
5384 		} while (tmp);
5385 		sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
5386 		sv->next = redirlist;
5387 		sv->pair_count = sv_pos;
5388 		redirlist = sv;
5389 		while (sv_pos > 0) {
5390 			sv_pos--;
5391 			sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5392 		}
5393 	}
5394 
5395 	do {
5396 		int right_fd = -1;
5397 		fd = redir->nfile.fd;
5398 		if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5399 			right_fd = redir->ndup.dupfd;
5400 			//bb_error_msg("doing %d > %d", fd, right_fd);
5401 			/* redirect from/to same file descriptor? */
5402 			if (right_fd == fd)
5403 				continue;
5404 			/* "echo >&10" and 10 is a fd opened to a sh script? */
5405 			if (is_hidden_fd(sv, right_fd)) {
5406 				errno = EBADF; /* as if it is closed */
5407 				ash_msg_and_raise_error("%d: %m", right_fd);
5408 			}
5409 			newfd = -1;
5410 		} else {
5411 			newfd = openredirect(redir); /* always >= 0 */
5412 			if (fd == newfd) {
5413 				/* Descriptor wasn't open before redirect.
5414 				 * Mark it for close in the future */
5415 				if (need_to_remember(sv, fd)) {
5416 					goto remember_to_close;
5417 				}
5418 				continue;
5419 			}
5420 		}
5421 #if ENABLE_ASH_BASH_COMPAT
5422  redirect_more:
5423 #endif
5424 		if (need_to_remember(sv, fd)) {
5425 			/* Copy old descriptor */
5426 			/* Careful to not accidentally "save"
5427 			 * to the same fd as right side fd in N>&M */
5428 			int minfd = right_fd < 10 ? 10 : right_fd + 1;
5429 #if defined(F_DUPFD_CLOEXEC)
5430 			i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5431 #else
5432 			i = fcntl(fd, F_DUPFD, minfd);
5433 #endif
5434 			if (i == -1) {
5435 				i = errno;
5436 				if (i != EBADF) {
5437 					/* Strange error (e.g. "too many files" EMFILE?) */
5438 					if (newfd >= 0)
5439 						close(newfd);
5440 					errno = i;
5441 					ash_msg_and_raise_error("%d: %m", fd);
5442 					/* NOTREACHED */
5443 				}
5444 				/* EBADF: it is not open - good, remember to close it */
5445  remember_to_close:
5446 				i = CLOSED;
5447 			} else { /* fd is open, save its copy */
5448 #if !defined(F_DUPFD_CLOEXEC)
5449 				fcntl(i, F_SETFD, FD_CLOEXEC);
5450 #endif
5451 				/* "exec fd>&-" should not close fds
5452 				 * which point to script file(s).
5453 				 * Force them to be restored afterwards */
5454 				if (is_hidden_fd(sv, fd))
5455 					i |= COPYFD_RESTORE;
5456 			}
5457 			if (fd == 2)
5458 				copied_fd2 = i;
5459 			sv->two_fd[sv_pos].orig = fd;
5460 			sv->two_fd[sv_pos].copy = i;
5461 			sv_pos++;
5462 		}
5463 		if (newfd < 0) {
5464 			/* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5465 			if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5466 				/* Don't want to trigger debugging */
5467 				if (fd != -1)
5468 					close(fd);
5469 			} else {
5470 				dup2_or_raise(redir->ndup.dupfd, fd);
5471 			}
5472 		} else if (fd != newfd) { /* move newfd to fd */
5473 			dup2_or_raise(newfd, fd);
5474 #if ENABLE_ASH_BASH_COMPAT
5475 			if (!(redir->nfile.type == NTO2 && fd == 2))
5476 #endif
5477 				close(newfd);
5478 		}
5479 #if ENABLE_ASH_BASH_COMPAT
5480 		if (redir->nfile.type == NTO2 && fd == 1) {
5481 			/* We already redirected it to fd 1, now copy it to 2 */
5482 			newfd = 1;
5483 			fd = 2;
5484 			goto redirect_more;
5485 		}
5486 #endif
5487 	} while ((redir = redir->nfile.next) != NULL);
5488 
5489 	INT_ON;
5490 	if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5491 		preverrout_fd = copied_fd2;
5492 }
5493 
5494 /*
5495  * Undo the effects of the last redirection.
5496  */
5497 static void
popredir(int drop,int restore)5498 popredir(int drop, int restore)
5499 {
5500 	struct redirtab *rp;
5501 	int i;
5502 
5503 	if (redirlist == NULL)
5504 		return;
5505 	INT_OFF;
5506 	rp = redirlist;
5507 	for (i = 0; i < rp->pair_count; i++) {
5508 		int fd = rp->two_fd[i].orig;
5509 		int copy = rp->two_fd[i].copy;
5510 		if (copy == CLOSED) {
5511 			if (!drop)
5512 				close(fd);
5513 			continue;
5514 		}
5515 		if (copy != EMPTY) {
5516 			if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5517 				copy &= ~COPYFD_RESTORE;
5518 				/*close(fd);*/
5519 				dup2_or_raise(copy, fd);
5520 			}
5521 			close(copy & ~COPYFD_RESTORE);
5522 		}
5523 	}
5524 	redirlist = rp->next;
5525 	free(rp);
5526 	INT_ON;
5527 }
5528 
5529 /*
5530  * Undo all redirections.  Called on error or interrupt.
5531  */
5532 
5533 static int
redirectsafe(union node * redir,int flags)5534 redirectsafe(union node *redir, int flags)
5535 {
5536 	int err;
5537 	volatile int saveint;
5538 	struct jmploc *volatile savehandler = exception_handler;
5539 	struct jmploc jmploc;
5540 
5541 	SAVE_INT(saveint);
5542 	/* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5543 	err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5544 	if (!err) {
5545 		exception_handler = &jmploc;
5546 		redirect(redir, flags);
5547 	}
5548 	exception_handler = savehandler;
5549 	if (err && exception_type != EXERROR)
5550 		longjmp(exception_handler->loc, 1);
5551 	RESTORE_INT(saveint);
5552 	return err;
5553 }
5554 
5555 
5556 /* ============ Routines to expand arguments to commands
5557  *
5558  * We have to deal with backquotes, shell variables, and file metacharacters.
5559  */
5560 
5561 #if ENABLE_FEATURE_SH_MATH
5562 static arith_t
ash_arith(const char * s)5563 ash_arith(const char *s)
5564 {
5565 	arith_state_t math_state;
5566 	arith_t result;
5567 
5568 	math_state.lookupvar = lookupvar;
5569 	math_state.setvar    = setvar0;
5570 	//math_state.endofname = endofname;
5571 
5572 	INT_OFF;
5573 	result = arith(&math_state, s);
5574 	if (math_state.errmsg)
5575 		ash_msg_and_raise_error(math_state.errmsg);
5576 	INT_ON;
5577 
5578 	return result;
5579 }
5580 #endif
5581 
5582 /*
5583  * expandarg flags
5584  */
5585 #define EXP_FULL        0x1     /* perform word splitting & file globbing */
5586 #define EXP_TILDE       0x2     /* do normal tilde expansion */
5587 #define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
5588 #define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
5589 /* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5590  * POSIX says for this case:
5591  *  Pathname expansion shall not be performed on the word by a
5592  *  non-interactive shell; an interactive shell may perform it, but shall
5593  *  do so only when the expansion would result in one word.
5594  * Currently, our code complies to the above rule by never globbing
5595  * redirection filenames.
5596  * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5597  * (this means that on a typical Linux distro, bash almost always
5598  * performs globbing, and thus diverges from what we do).
5599  */
5600 #define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
5601 #define EXP_QPAT        0x20    /* pattern in quoted parameter expansion */
5602 #define EXP_VARTILDE2   0x40    /* expand tildes after colons only */
5603 #define EXP_WORD        0x80    /* expand word in parameter expansion */
5604 #define EXP_QUOTED      0x100   /* expand word in double quotes */
5605 /*
5606  * rmescape() flags
5607  */
5608 #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
5609 #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
5610 #define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
5611 #define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
5612 #define RMESCAPE_SLASH  0x20    /* Stop globbing after slash */
5613 
5614 /* Add CTLESC when necessary. */
5615 #define QUOTES_ESC     (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
5616 /* Do not skip NUL characters. */
5617 #define QUOTES_KEEPNUL EXP_TILDE
5618 
5619 /*
5620  * Structure specifying which parts of the string should be searched
5621  * for IFS characters.
5622  */
5623 struct ifsregion {
5624 	struct ifsregion *next; /* next region in list */
5625 	int begoff;             /* offset of start of region */
5626 	int endoff;             /* offset of end of region */
5627 	int nulonly;            /* search for nul bytes only */
5628 };
5629 
5630 struct arglist {
5631 	struct strlist *list;
5632 	struct strlist **lastp;
5633 };
5634 
5635 /* output of current string */
5636 static char *expdest;
5637 /* list of back quote expressions */
5638 static struct nodelist *argbackq;
5639 /* first struct in list of ifs regions */
5640 static struct ifsregion ifsfirst;
5641 /* last struct in list */
5642 static struct ifsregion *ifslastp;
5643 /* holds expanded arg list */
5644 static struct arglist exparg;
5645 
5646 /*
5647  * Our own itoa().
5648  */
5649 #if !ENABLE_FEATURE_SH_MATH
5650 /* cvtnum() is used even if math support is off (to prepare $? values and such) */
5651 typedef long arith_t;
5652 # define ARITH_FMT "%ld"
5653 #endif
5654 static int
cvtnum(arith_t num)5655 cvtnum(arith_t num)
5656 {
5657 	int len;
5658 
5659 	expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5660 	len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
5661 	STADJUST(len, expdest);
5662 	return len;
5663 }
5664 
5665 /*
5666  * Break the argument string into pieces based upon IFS and add the
5667  * strings to the argument list.  The regions of the string to be
5668  * searched for IFS characters have been stored by recordregion.
5669  */
5670 static void
ifsbreakup(char * string,struct arglist * arglist)5671 ifsbreakup(char *string, struct arglist *arglist)
5672 {
5673 	struct ifsregion *ifsp;
5674 	struct strlist *sp;
5675 	char *start;
5676 	char *p;
5677 	char *q;
5678 	const char *ifs, *realifs;
5679 	int ifsspc;
5680 	int nulonly;
5681 
5682 	start = string;
5683 	if (ifslastp != NULL) {
5684 		ifsspc = 0;
5685 		nulonly = 0;
5686 		realifs = ifsset() ? ifsval() : defifs;
5687 		ifsp = &ifsfirst;
5688 		do {
5689 			p = string + ifsp->begoff;
5690 			nulonly = ifsp->nulonly;
5691 			ifs = nulonly ? nullstr : realifs;
5692 			ifsspc = 0;
5693 			while (p < string + ifsp->endoff) {
5694 				q = p;
5695 				if ((unsigned char)*p == CTLESC)
5696 					p++;
5697 				if (!strchr(ifs, *p)) {
5698 					p++;
5699 					continue;
5700 				}
5701 				if (!nulonly)
5702 					ifsspc = (strchr(defifs, *p) != NULL);
5703 				/* Ignore IFS whitespace at start */
5704 				if (q == start && ifsspc) {
5705 					p++;
5706 					start = p;
5707 					continue;
5708 				}
5709 				*q = '\0';
5710 				sp = stzalloc(sizeof(*sp));
5711 				sp->text = start;
5712 				*arglist->lastp = sp;
5713 				arglist->lastp = &sp->next;
5714 				p++;
5715 				if (!nulonly) {
5716 					for (;;) {
5717 						if (p >= string + ifsp->endoff) {
5718 							break;
5719 						}
5720 						q = p;
5721 						if ((unsigned char)*p == CTLESC)
5722 							p++;
5723 						if (strchr(ifs, *p) == NULL) {
5724 							p = q;
5725 							break;
5726 						}
5727 						if (strchr(defifs, *p) == NULL) {
5728 							if (ifsspc) {
5729 								p++;
5730 								ifsspc = 0;
5731 							} else {
5732 								p = q;
5733 								break;
5734 							}
5735 						} else
5736 							p++;
5737 					}
5738 				}
5739 				start = p;
5740 			} /* while */
5741 			ifsp = ifsp->next;
5742 		} while (ifsp != NULL);
5743 		if (nulonly)
5744 			goto add;
5745 	}
5746 
5747 	if (!*start)
5748 		return;
5749 
5750  add:
5751 	sp = stzalloc(sizeof(*sp));
5752 	sp->text = start;
5753 	*arglist->lastp = sp;
5754 	arglist->lastp = &sp->next;
5755 }
5756 
5757 static void
ifsfree(void)5758 ifsfree(void)
5759 {
5760 	struct ifsregion *p = ifsfirst.next;
5761 
5762 	if (!p)
5763 		goto out;
5764 
5765 	INT_OFF;
5766 	do {
5767 		struct ifsregion *ifsp;
5768 		ifsp = p->next;
5769 		free(p);
5770 		p = ifsp;
5771 	} while (p);
5772 	ifsfirst.next = NULL;
5773 	INT_ON;
5774  out:
5775 	ifslastp = NULL;
5776 }
5777 
5778 static size_t
esclen(const char * start,const char * p)5779 esclen(const char *start, const char *p)
5780 {
5781 	size_t esc = 0;
5782 
5783 	while (p > start && (unsigned char)*--p == CTLESC) {
5784 		esc++;
5785 	}
5786 	return esc;
5787 }
5788 
5789 /*
5790  * Remove any CTLESC characters from a string.
5791  */
5792 static char *
rmescapes(char * str,int flag)5793 rmescapes(char *str, int flag)
5794 {
5795 	static const char qchars[] ALIGN1 = {
5796 		IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
5797 
5798 	char *p, *q, *r;
5799 	unsigned inquotes;
5800 	unsigned protect_against_glob;
5801 	unsigned globbing;
5802 	IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
5803 
5804 	p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
5805 	if (!p)
5806 		return str;
5807 
5808 	q = p;
5809 	r = str;
5810 	if (flag & RMESCAPE_ALLOC) {
5811 		size_t len = p - str;
5812 		size_t fulllen = len + strlen(p) + 1;
5813 
5814 		if (flag & RMESCAPE_GROW) {
5815 			int strloc = str - (char *)stackblock();
5816 			r = makestrspace(fulllen, expdest);
5817 			/* p and str may be invalidated by makestrspace */
5818 			str = (char *)stackblock() + strloc;
5819 			p = str + len;
5820 		} else if (flag & RMESCAPE_HEAP) {
5821 			r = ckmalloc(fulllen);
5822 		} else {
5823 			r = stalloc(fulllen);
5824 		}
5825 		q = r;
5826 		if (len > 0) {
5827 			q = (char *)memcpy(q, str, len) + len;
5828 		}
5829 	}
5830 
5831 	inquotes = 0;
5832 	globbing = flag & RMESCAPE_GLOB;
5833 	protect_against_glob = globbing;
5834 	while (*p) {
5835 		if ((unsigned char)*p == CTLQUOTEMARK) {
5836 // Note: both inquotes and protect_against_glob only affect whether
5837 			inquotes = ~inquotes;
5838 			p++;
5839 			protect_against_glob = globbing;
5840 			continue;
5841 		}
5842 		if ((unsigned char)*p == CTLESC) {
5843 			p++;
5844 #if DEBUG
5845 			if (*p == '\0')
5846 				ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5847 #endif
5848 			if (protect_against_glob) {
5849 				*q++ = '\\';
5850 			}
5851 		} else if (*p == '\\' && !inquotes) {
5852 			/* naked back slash */
5853 			protect_against_glob = 0;
5854 			goto copy;
5855 		}
5856 #if ENABLE_ASH_BASH_COMPAT
5857 		else if (*p == '/' && slash) {
5858 			/* stop handling globbing and mark location of slash */
5859 			globbing = slash = 0;
5860 			*p = CTLESC;
5861 		}
5862 #endif
5863 		protect_against_glob = globbing;
5864  copy:
5865 		*q++ = *p++;
5866 	}
5867 	*q = '\0';
5868 	if (flag & RMESCAPE_GROW) {
5869 		expdest = r;
5870 		STADJUST(q - r + 1, expdest);
5871 	}
5872 	return r;
5873 }
5874 #define pmatch(a, b) !fnmatch((a), (b), 0)
5875 
5876 /*
5877  * Prepare a pattern for a expmeta (internal glob(3)) call.
5878  *
5879  * Returns an stalloced string.
5880  */
5881 static char *
preglob(const char * pattern,int flag)5882 preglob(const char *pattern, int flag)
5883 {
5884 	return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
5885 }
5886 
5887 /*
5888  * Put a string on the stack.
5889  */
5890 static void
memtodest(const char * p,size_t len,int syntax,int quotes)5891 memtodest(const char *p, size_t len, int syntax, int quotes)
5892 {
5893 	char *q;
5894 
5895 	if (!len)
5896 		return;
5897 
5898 	q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5899 
5900 	do {
5901 		unsigned char c = *p++;
5902 		if (c) {
5903 			if (quotes & QUOTES_ESC) {
5904 				int n = SIT(c, syntax);
5905 				if (n == CCTL
5906 				 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5907 				     && n == CBACK
5908 				    )
5909 				) {
5910 					USTPUTC(CTLESC, q);
5911 				}
5912 			}
5913 		} else if (!(quotes & QUOTES_KEEPNUL))
5914 			continue;
5915 		USTPUTC(c, q);
5916 	} while (--len);
5917 
5918 	expdest = q;
5919 }
5920 
5921 static size_t
strtodest(const char * p,int syntax,int quotes)5922 strtodest(const char *p, int syntax, int quotes)
5923 {
5924 	size_t len = strlen(p);
5925 	memtodest(p, len, syntax, quotes);
5926 	return len;
5927 }
5928 
5929 /*
5930  * Record the fact that we have to scan this region of the
5931  * string for IFS characters.
5932  */
5933 static void
recordregion(int start,int end,int nulonly)5934 recordregion(int start, int end, int nulonly)
5935 {
5936 	struct ifsregion *ifsp;
5937 
5938 	if (ifslastp == NULL) {
5939 		ifsp = &ifsfirst;
5940 	} else {
5941 		INT_OFF;
5942 		ifsp = ckzalloc(sizeof(*ifsp));
5943 		/*ifsp->next = NULL; - ckzalloc did it */
5944 		ifslastp->next = ifsp;
5945 		INT_ON;
5946 	}
5947 	ifslastp = ifsp;
5948 	ifslastp->begoff = start;
5949 	ifslastp->endoff = end;
5950 	ifslastp->nulonly = nulonly;
5951 }
5952 
5953 static void
removerecordregions(int endoff)5954 removerecordregions(int endoff)
5955 {
5956 	if (ifslastp == NULL)
5957 		return;
5958 
5959 	if (ifsfirst.endoff > endoff) {
5960 		while (ifsfirst.next) {
5961 			struct ifsregion *ifsp;
5962 			INT_OFF;
5963 			ifsp = ifsfirst.next->next;
5964 			free(ifsfirst.next);
5965 			ifsfirst.next = ifsp;
5966 			INT_ON;
5967 		}
5968 		if (ifsfirst.begoff > endoff) {
5969 			ifslastp = NULL;
5970 		} else {
5971 			ifslastp = &ifsfirst;
5972 			ifsfirst.endoff = endoff;
5973 		}
5974 		return;
5975 	}
5976 
5977 	ifslastp = &ifsfirst;
5978 	while (ifslastp->next && ifslastp->next->begoff < endoff)
5979 		ifslastp = ifslastp->next;
5980 	while (ifslastp->next) {
5981 		struct ifsregion *ifsp;
5982 		INT_OFF;
5983 		ifsp = ifslastp->next->next;
5984 		free(ifslastp->next);
5985 		ifslastp->next = ifsp;
5986 		INT_ON;
5987 	}
5988 	if (ifslastp->endoff > endoff)
5989 		ifslastp->endoff = endoff;
5990 }
5991 
5992 static char *
exptilde(char * startp,char * p,int flags)5993 exptilde(char *startp, char *p, int flags)
5994 {
5995 	unsigned char c;
5996 	char *name;
5997 	struct passwd *pw;
5998 	const char *home;
5999 	int quotes = flags & QUOTES_ESC;
6000 
6001 	name = p + 1;
6002 
6003 	while ((c = *++p) != '\0') {
6004 		switch (c) {
6005 		case CTLESC:
6006 			return startp;
6007 		case CTLQUOTEMARK:
6008 			return startp;
6009 		case ':':
6010 			if (flags & EXP_VARTILDE)
6011 				goto done;
6012 			break;
6013 		case '/':
6014 		case CTLENDVAR:
6015 			goto done;
6016 		}
6017 	}
6018  done:
6019 	*p = '\0';
6020 	if (*name == '\0') {
6021 		home = lookupvar("HOME");
6022 	} else {
6023 		pw = getpwnam(name);
6024 		if (pw == NULL)
6025 			goto lose;
6026 		home = pw->pw_dir;
6027 	}
6028 	if (!home || !*home)
6029 		goto lose;
6030 	*p = c;
6031 	strtodest(home, SQSYNTAX, quotes);
6032 	return p;
6033  lose:
6034 	*p = c;
6035 	return startp;
6036 }
6037 
6038 /*
6039  * Execute a command inside back quotes.  If it's a builtin command, we
6040  * want to save its output in a block obtained from malloc.  Otherwise
6041  * we fork off a subprocess and get the output of the command via a pipe.
6042  * Should be called with interrupts off.
6043  */
6044 struct backcmd {                /* result of evalbackcmd */
6045 	int fd;                 /* file descriptor to read from */
6046 	int nleft;              /* number of chars in buffer */
6047 	char *buf;              /* buffer */
6048 	struct job *jp;         /* job structure for command */
6049 };
6050 
6051 /* These forward decls are needed to use "eval" code for backticks handling: */
6052 #define EV_EXIT 01              /* exit after evaluating tree */
6053 static int evaltree(union node *, int);
6054 
6055 static void FAST_FUNC
evalbackcmd(union node * n,struct backcmd * result)6056 evalbackcmd(union node *n, struct backcmd *result)
6057 {
6058 	int pip[2];
6059 	struct job *jp;
6060 
6061 	result->fd = -1;
6062 	result->buf = NULL;
6063 	result->nleft = 0;
6064 	result->jp = NULL;
6065 	if (n == NULL) {
6066 		goto out;
6067 	}
6068 
6069 	if (pipe(pip) < 0)
6070 		ash_msg_and_raise_error("pipe call failed");
6071 	jp = makejob(/*n,*/ 1);
6072 	if (forkshell(jp, n, FORK_NOJOB) == 0) {
6073 		/* child */
6074 		FORCE_INT_ON;
6075 		close(pip[0]);
6076 		if (pip[1] != 1) {
6077 			/*close(1);*/
6078 			dup2_or_raise(pip[1], 1);
6079 			close(pip[1]);
6080 		}
6081 /* TODO: eflag clearing makes the following not abort:
6082  *  ash -c 'set -e; z=$(false;echo foo); echo $z'
6083  * which is what bash does (unless it is in POSIX mode).
6084  * dash deleted "eflag = 0" line in the commit
6085  *  Date: Mon, 28 Jun 2010 17:11:58 +1000
6086  *  [EVAL] Don't clear eflag in evalbackcmd
6087  * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6088  */
6089 		eflag = 0;
6090 		ifsfree();
6091 		evaltree(n, EV_EXIT); /* actually evaltreenr... */
6092 		/* NOTREACHED */
6093 	}
6094 	/* parent */
6095 	close(pip[1]);
6096 	result->fd = pip[0];
6097 	result->jp = jp;
6098 
6099  out:
6100 	TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6101 		result->fd, result->buf, result->nleft, result->jp));
6102 }
6103 
6104 /*
6105  * Expand stuff in backwards quotes.
6106  */
6107 static void
expbackq(union node * cmd,int flag)6108 expbackq(union node *cmd, int flag)
6109 {
6110 	struct backcmd in;
6111 	int i;
6112 	char buf[128];
6113 	char *p;
6114 	char *dest;
6115 	int startloc;
6116 	int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6117 	struct stackmark smark;
6118 
6119 	INT_OFF;
6120 	startloc = expdest - (char *)stackblock();
6121 	pushstackmark(&smark, startloc);
6122 	evalbackcmd(cmd, &in);
6123 	popstackmark(&smark);
6124 
6125 	p = in.buf;
6126 	i = in.nleft;
6127 	if (i == 0)
6128 		goto read;
6129 	for (;;) {
6130 		memtodest(p, i, syntax, flag & QUOTES_ESC);
6131  read:
6132 		if (in.fd < 0)
6133 			break;
6134 		i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6135 		TRACE(("expbackq: read returns %d\n", i));
6136 		if (i <= 0)
6137 			break;
6138 		p = buf;
6139 	}
6140 
6141 	free(in.buf);
6142 	if (in.fd >= 0) {
6143 		close(in.fd);
6144 		back_exitstatus = waitforjob(in.jp);
6145 	}
6146 	INT_ON;
6147 
6148 	/* Eat all trailing newlines */
6149 	dest = expdest;
6150 	for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6151 		STUNPUTC(dest);
6152 	expdest = dest;
6153 
6154 	if (!(flag & EXP_QUOTED))
6155 		recordregion(startloc, dest - (char *)stackblock(), 0);
6156 	TRACE(("evalbackq: size:%d:'%.*s'\n",
6157 		(int)((dest - (char *)stackblock()) - startloc),
6158 		(int)((dest - (char *)stackblock()) - startloc),
6159 		stackblock() + startloc));
6160 }
6161 
6162 #if ENABLE_FEATURE_SH_MATH
6163 /*
6164  * Expand arithmetic expression.  Backup to start of expression,
6165  * evaluate, place result in (backed up) result, adjust string position.
6166  */
6167 static void
expari(int flag)6168 expari(int flag)
6169 {
6170 	char *p, *start;
6171 	int begoff;
6172 	int len;
6173 
6174 	/* ifsfree(); */
6175 
6176 	/*
6177 	 * This routine is slightly over-complicated for
6178 	 * efficiency.  Next we scan backwards looking for the
6179 	 * start of arithmetic.
6180 	 */
6181 	start = stackblock();
6182 	p = expdest - 1;
6183 	*p = '\0';
6184 	p--;
6185 	while (1) {
6186 		int esc;
6187 
6188 		while ((unsigned char)*p != CTLARI) {
6189 			p--;
6190 #if DEBUG
6191 			if (p < start) {
6192 				ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6193 			}
6194 #endif
6195 		}
6196 
6197 		esc = esclen(start, p);
6198 		if (!(esc % 2)) {
6199 			break;
6200 		}
6201 
6202 		p -= esc + 1;
6203 	}
6204 
6205 	begoff = p - start;
6206 
6207 	removerecordregions(begoff);
6208 
6209 	expdest = p;
6210 
6211 	if (flag & QUOTES_ESC)
6212 		rmescapes(p + 1, 0);
6213 
6214 	len = cvtnum(ash_arith(p + 1));
6215 
6216 	if (!(flag & EXP_QUOTED))
6217 		recordregion(begoff, begoff + len, 0);
6218 }
6219 #endif
6220 
6221 /* argstr needs it */
6222 static char *evalvar(char *p, int flags, struct strlist *var_str_list);
6223 
6224 /*
6225  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
6226  * characters to allow for further processing.  Otherwise treat
6227  * $@ like $* since no splitting will be performed.
6228  *
6229  * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6230  * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6231  * for correct expansion of "B=$A" word.
6232  */
6233 static void
argstr(char * p,int flags,struct strlist * var_str_list)6234 argstr(char *p, int flags, struct strlist *var_str_list)
6235 {
6236 	static const char spclchars[] ALIGN1 = {
6237 		'=',
6238 		':',
6239 		CTLQUOTEMARK,
6240 		CTLENDVAR,
6241 		CTLESC,
6242 		CTLVAR,
6243 		CTLBACKQ,
6244 #if ENABLE_FEATURE_SH_MATH
6245 		CTLENDARI,
6246 #endif
6247 		'\0'
6248 	};
6249 	const char *reject = spclchars;
6250 	int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6251 	int inquotes;
6252 	size_t length;
6253 	int startloc;
6254 
6255 	if (!(flags & EXP_VARTILDE)) {
6256 		reject += 2;
6257 	} else if (flags & EXP_VARTILDE2) {
6258 		reject++;
6259 	}
6260 	inquotes = 0;
6261 	length = 0;
6262 	if (flags & EXP_TILDE) {
6263 		char *q;
6264 
6265 		flags &= ~EXP_TILDE;
6266  tilde:
6267 		q = p;
6268 		if (*q == '~')
6269 			p = exptilde(p, q, flags);
6270 	}
6271  start:
6272 	startloc = expdest - (char *)stackblock();
6273 	for (;;) {
6274 		unsigned char c;
6275 
6276 		length += strcspn(p + length, reject);
6277 		c = p[length];
6278 		if (c) {
6279 			if (!(c & 0x80)
6280 			IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6281 			) {
6282 				/* c == '=' || c == ':' || c == CTLENDARI */
6283 				length++;
6284 			}
6285 		}
6286 		if (length > 0) {
6287 			int newloc;
6288 			expdest = stack_nputstr(p, length, expdest);
6289 			newloc = expdest - (char *)stackblock();
6290 			if (breakall && !inquotes && newloc > startloc) {
6291 				recordregion(startloc, newloc, 0);
6292 			}
6293 			startloc = newloc;
6294 		}
6295 		p += length + 1;
6296 		length = 0;
6297 
6298 		switch (c) {
6299 		case '\0':
6300 			goto breakloop;
6301 		case '=':
6302 			if (flags & EXP_VARTILDE2) {
6303 				p--;
6304 				continue;
6305 			}
6306 			flags |= EXP_VARTILDE2;
6307 			reject++;
6308 			/* fall through */
6309 		case ':':
6310 			/*
6311 			 * sort of a hack - expand tildes in variable
6312 			 * assignments (after the first '=' and after ':'s).
6313 			 */
6314 			if (*--p == '~') {
6315 				goto tilde;
6316 			}
6317 			continue;
6318 		}
6319 
6320 		switch (c) {
6321 		case CTLENDVAR: /* ??? */
6322 			goto breakloop;
6323 		case CTLQUOTEMARK:
6324 			inquotes ^= EXP_QUOTED;
6325 			/* "$@" syntax adherence hack */
6326 			if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6327 				p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
6328 				goto start;
6329 			}
6330  addquote:
6331 			if (flags & QUOTES_ESC) {
6332 				p--;
6333 				length++;
6334 				startloc++;
6335 			}
6336 			break;
6337 		case CTLESC:
6338 			startloc++;
6339 			length++;
6340 
6341 			/*
6342 			 * Quoted parameter expansion pattern: remove quote
6343 			 * unless inside inner quotes or we have a literal
6344 			 * backslash.
6345 			 */
6346 			if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6347 			    EXP_QPAT && *p != '\\')
6348 				break;
6349 
6350 			goto addquote;
6351 		case CTLVAR:
6352 			TRACE(("argstr: evalvar('%s')\n", p));
6353 			p = evalvar(p, flags | inquotes, var_str_list);
6354 			TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6355 			goto start;
6356 		case CTLBACKQ:
6357 			expbackq(argbackq->n, flags | inquotes);
6358 			argbackq = argbackq->next;
6359 			goto start;
6360 #if ENABLE_FEATURE_SH_MATH
6361 		case CTLENDARI:
6362 			p--;
6363 			expari(flags | inquotes);
6364 			goto start;
6365 #endif
6366 		}
6367 	}
6368  breakloop: ;
6369 }
6370 
6371 static char *
scanleft(char * startp,char * rmesc,char * rmescend UNUSED_PARAM,char * pattern,int quotes,int zero)6372 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6373 		char *pattern, int quotes, int zero)
6374 {
6375 	char *loc, *loc2;
6376 	char c;
6377 
6378 	loc = startp;
6379 	loc2 = rmesc;
6380 	do {
6381 		int match;
6382 		const char *s = loc2;
6383 
6384 		c = *loc2;
6385 		if (zero) {
6386 			*loc2 = '\0';
6387 			s = rmesc;
6388 		}
6389 		match = pmatch(pattern, s);
6390 
6391 		*loc2 = c;
6392 		if (match)
6393 			return loc;
6394 		if (quotes && (unsigned char)*loc == CTLESC)
6395 			loc++;
6396 		loc++;
6397 		loc2++;
6398 	} while (c);
6399 	return NULL;
6400 }
6401 
6402 static char *
scanright(char * startp,char * rmesc,char * rmescend,char * pattern,int quotes,int match_at_start)6403 scanright(char *startp, char *rmesc, char *rmescend,
6404 		char *pattern, int quotes, int match_at_start)
6405 {
6406 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6407 	int try2optimize = match_at_start;
6408 #endif
6409 	int esc = 0;
6410 	char *loc;
6411 	char *loc2;
6412 
6413 	/* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6414 	 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6415 	 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6416 	 * Logic:
6417 	 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6418 	 * and on each iteration they go back two/one char until they reach the beginning.
6419 	 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6420 	 */
6421 	/* TODO: document in what other circumstances we are called. */
6422 
6423 	for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6424 		int match;
6425 		char c = *loc2;
6426 		const char *s = loc2;
6427 		if (match_at_start) {
6428 			*loc2 = '\0';
6429 			s = rmesc;
6430 		}
6431 		match = pmatch(pattern, s);
6432 		//bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6433 		*loc2 = c;
6434 		if (match)
6435 			return loc;
6436 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6437 		if (try2optimize) {
6438 			/* Maybe we can optimize this:
6439 			 * if pattern ends with unescaped *, we can avoid checking
6440 			 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6441 			 * it wont match truncated "raw_value_of_" strings too.
6442 			 */
6443 			unsigned plen = strlen(pattern);
6444 			/* Does it end with "*"? */
6445 			if (plen != 0 && pattern[--plen] == '*') {
6446 				/* "xxxx*" is not escaped */
6447 				/* "xxx\*" is escaped */
6448 				/* "xx\\*" is not escaped */
6449 				/* "x\\\*" is escaped */
6450 				int slashes = 0;
6451 				while (plen != 0 && pattern[--plen] == '\\')
6452 					slashes++;
6453 				if (!(slashes & 1))
6454 					break; /* ends with unescaped "*" */
6455 			}
6456 			try2optimize = 0;
6457 		}
6458 #endif
6459 		loc--;
6460 		if (quotes) {
6461 			if (--esc < 0) {
6462 				esc = esclen(startp, loc);
6463 			}
6464 			if (esc % 2) {
6465 				esc--;
6466 				loc--;
6467 			}
6468 		}
6469 	}
6470 	return NULL;
6471 }
6472 
6473 static void varunset(const char *, const char *, const char *, int) NORETURN;
6474 static void
varunset(const char * end,const char * var,const char * umsg,int varflags)6475 varunset(const char *end, const char *var, const char *umsg, int varflags)
6476 {
6477 	const char *msg;
6478 	const char *tail;
6479 
6480 	tail = nullstr;
6481 	msg = "parameter not set";
6482 	if (umsg) {
6483 		if ((unsigned char)*end == CTLENDVAR) {
6484 			if (varflags & VSNUL)
6485 				tail = " or null";
6486 		} else {
6487 			msg = umsg;
6488 		}
6489 	}
6490 	ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6491 }
6492 
6493 static const char *
subevalvar(char * p,char * varname,int strloc,int subtype,int startloc,int varflags,int flag,struct strlist * var_str_list)6494 subevalvar(char *p, char *varname, int strloc, int subtype,
6495 		int startloc, int varflags, int flag, struct strlist *var_str_list)
6496 {
6497 	struct nodelist *saveargbackq = argbackq;
6498 	int quotes = flag & QUOTES_ESC;
6499 	char *startp;
6500 	char *loc;
6501 	char *rmesc, *rmescend;
6502 	char *str;
6503 	IF_ASH_BASH_COMPAT(char *repl = NULL;)
6504 	IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6505 	int amount, resetloc;
6506 	IF_ASH_BASH_COMPAT(int workloc;)
6507 	int zero;
6508 	char *(*scan)(char*, char*, char*, char*, int, int);
6509 
6510 	//bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6511 	//		p, varname, strloc, subtype, startloc, varflags, quotes);
6512 
6513 	argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
6514 			(flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6515 			var_str_list);
6516 	STPUTC('\0', expdest);
6517 	argbackq = saveargbackq;
6518 	startp = (char *)stackblock() + startloc;
6519 
6520 	switch (subtype) {
6521 	case VSASSIGN:
6522 		setvar0(varname, startp);
6523 		amount = startp - expdest;
6524 		STADJUST(amount, expdest);
6525 		return startp;
6526 
6527 	case VSQUESTION:
6528 		varunset(p, varname, startp, varflags);
6529 		/* NOTREACHED */
6530 
6531 #if ENABLE_ASH_BASH_COMPAT
6532 	case VSSUBSTR:
6533 //TODO: support more general format ${v:EXPR:EXPR},
6534 // where EXPR follows $(()) rules
6535 		loc = str = stackblock() + strloc;
6536 		/* Read POS in ${var:POS:LEN} */
6537 		pos = atoi(loc); /* number(loc) errors out on "1:4" */
6538 		len = str - startp - 1;
6539 
6540 		/* *loc != '\0', guaranteed by parser */
6541 		if (quotes) {
6542 			char *ptr;
6543 
6544 			/* Adjust the length by the number of escapes */
6545 			for (ptr = startp; ptr < (str - 1); ptr++) {
6546 				if ((unsigned char)*ptr == CTLESC) {
6547 					len--;
6548 					ptr++;
6549 				}
6550 			}
6551 		}
6552 		orig_len = len;
6553 
6554 		if (*loc++ == ':') {
6555 			/* ${var::LEN} */
6556 			len = number(loc);
6557 		} else {
6558 			/* Skip POS in ${var:POS:LEN} */
6559 			len = orig_len;
6560 			while (*loc && *loc != ':') {
6561 				/* TODO?
6562 				 * bash complains on: var=qwe; echo ${var:1a:123}
6563 				if (!isdigit(*loc))
6564 					ash_msg_and_raise_error(msg_illnum, str);
6565 				 */
6566 				loc++;
6567 			}
6568 			if (*loc++ == ':') {
6569 				len = number(loc);
6570 			}
6571 		}
6572 		if (pos < 0) {
6573 			/* ${VAR:$((-n)):l} starts n chars from the end */
6574 			pos = orig_len + pos;
6575 		}
6576 		if ((unsigned)pos >= orig_len) {
6577 			/* apart from obvious ${VAR:999999:l},
6578 			 * covers ${VAR:$((-9999999)):l} - result is ""
6579 			 * (bash-compat)
6580 			 */
6581 			pos = 0;
6582 			len = 0;
6583 		}
6584 		if (len > (orig_len - pos))
6585 			len = orig_len - pos;
6586 
6587 		for (str = startp; pos; str++, pos--) {
6588 			if (quotes && (unsigned char)*str == CTLESC)
6589 				str++;
6590 		}
6591 		for (loc = startp; len; len--) {
6592 			if (quotes && (unsigned char)*str == CTLESC)
6593 				*loc++ = *str++;
6594 			*loc++ = *str++;
6595 		}
6596 		*loc = '\0';
6597 		amount = loc - expdest;
6598 		STADJUST(amount, expdest);
6599 		return loc;
6600 #endif
6601 	}
6602 
6603 	resetloc = expdest - (char *)stackblock();
6604 
6605 	/* We'll comeback here if we grow the stack while handling
6606 	 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6607 	 * stack will need rebasing, and we'll need to remove our work
6608 	 * areas each time
6609 	 */
6610  IF_ASH_BASH_COMPAT(restart:)
6611 
6612 	amount = expdest - ((char *)stackblock() + resetloc);
6613 	STADJUST(-amount, expdest);
6614 	startp = (char *)stackblock() + startloc;
6615 
6616 	rmesc = startp;
6617 	rmescend = (char *)stackblock() + strloc;
6618 	if (quotes) {
6619 		rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6620 		if (rmesc != startp) {
6621 			rmescend = expdest;
6622 			startp = (char *)stackblock() + startloc;
6623 		}
6624 	}
6625 	rmescend--;
6626 	str = (char *)stackblock() + strloc;
6627 	/*
6628 	 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6629 	 * The result is a_\_z_c (not a\_\_z_c)!
6630 	 *
6631 	 * The search pattern and replace string treat backslashes differently!
6632 	 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6633 	 * and string.  It's only used on the first call.
6634 	 */
6635 	preglob(str, IF_ASH_BASH_COMPAT(
6636 		(subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6637 			RMESCAPE_SLASH :) 0);
6638 
6639 #if ENABLE_ASH_BASH_COMPAT
6640 	workloc = expdest - (char *)stackblock();
6641 	if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6642 		char *idx, *end;
6643 
6644 		if (!repl) {
6645 			repl = strchr(str, CTLESC);
6646 			if (repl)
6647 				*repl++ = '\0';
6648 			else
6649 				repl = nullstr;
6650 		}
6651 		//bb_error_msg("str:'%s' repl:'%s'", str, repl);
6652 
6653 		/* If there's no pattern to match, return the expansion unmolested */
6654 		if (str[0] == '\0')
6655 			return NULL;
6656 
6657 		len = 0;
6658 		idx = startp;
6659 		end = str - 1;
6660 		while (idx < end) {
6661  try_to_match:
6662 			loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6663 			//bb_error_msg("scanright('%s'):'%s'", str, loc);
6664 			if (!loc) {
6665 				/* No match, advance */
6666 				char *restart_detect = stackblock();
6667  skip_matching:
6668 				STPUTC(*idx, expdest);
6669 				if (quotes && (unsigned char)*idx == CTLESC) {
6670 					idx++;
6671 					len++;
6672 					STPUTC(*idx, expdest);
6673 				}
6674 				if (stackblock() != restart_detect)
6675 					goto restart;
6676 				idx++;
6677 				len++;
6678 				rmesc++;
6679 				/* continue; - prone to quadratic behavior, smarter code: */
6680 				if (idx >= end)
6681 					break;
6682 				if (str[0] == '*') {
6683 					/* Pattern is "*foo". If "*foo" does not match "long_string",
6684 					 * it would never match "ong_string" etc, no point in trying.
6685 					 */
6686 					goto skip_matching;
6687 				}
6688 				goto try_to_match;
6689 			}
6690 
6691 			if (subtype == VSREPLACEALL) {
6692 				while (idx < loc) {
6693 					if (quotes && (unsigned char)*idx == CTLESC)
6694 						idx++;
6695 					idx++;
6696 					rmesc++;
6697 				}
6698 			} else {
6699 				idx = loc;
6700 			}
6701 
6702 			//bb_error_msg("repl:'%s'", repl);
6703 			for (loc = (char*)repl; *loc; loc++) {
6704 				char *restart_detect = stackblock();
6705 				if (quotes && *loc == '\\') {
6706 					STPUTC(CTLESC, expdest);
6707 					len++;
6708 				}
6709 				STPUTC(*loc, expdest);
6710 				if (stackblock() != restart_detect)
6711 					goto restart;
6712 				len++;
6713 			}
6714 
6715 			if (subtype == VSREPLACE) {
6716 				//bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
6717 				while (*idx) {
6718 					char *restart_detect = stackblock();
6719 					STPUTC(*idx, expdest);
6720 					if (stackblock() != restart_detect)
6721 						goto restart;
6722 					len++;
6723 					idx++;
6724 				}
6725 				break;
6726 			}
6727 		}
6728 
6729 		/* We've put the replaced text into a buffer at workloc, now
6730 		 * move it to the right place and adjust the stack.
6731 		 */
6732 		STPUTC('\0', expdest);
6733 		startp = (char *)stackblock() + startloc;
6734 		memmove(startp, (char *)stackblock() + workloc, len + 1);
6735 		//bb_error_msg("startp:'%s'", startp);
6736 		amount = expdest - (startp + len);
6737 		STADJUST(-amount, expdest);
6738 		return startp;
6739 	}
6740 #endif /* ENABLE_ASH_BASH_COMPAT */
6741 
6742 	subtype -= VSTRIMRIGHT;
6743 #if DEBUG
6744 	if (subtype < 0 || subtype > 7)
6745 		abort();
6746 #endif
6747 	/* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
6748 	zero = subtype >> 1;
6749 	/* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6750 	scan = (subtype & 1) ^ zero ? scanleft : scanright;
6751 
6752 	loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6753 	if (loc) {
6754 		if (zero) {
6755 			memmove(startp, loc, str - loc);
6756 			loc = startp + (str - loc) - 1;
6757 		}
6758 		*loc = '\0';
6759 		amount = loc - expdest;
6760 		STADJUST(amount, expdest);
6761 	}
6762 	return loc;
6763 }
6764 
6765 /*
6766  * Add the value of a specialized variable to the stack string.
6767  * name parameter (examples):
6768  * ash -c 'echo $1'      name:'1='
6769  * ash -c 'echo $qwe'    name:'qwe='
6770  * ash -c 'echo $$'      name:'$='
6771  * ash -c 'echo ${$}'    name:'$='
6772  * ash -c 'echo ${$##q}' name:'$=q'
6773  * ash -c 'echo ${#$}'   name:'$='
6774  * note: examples with bad shell syntax:
6775  * ash -c 'echo ${#$1}'  name:'$=1'
6776  * ash -c 'echo ${#1#}'  name:'1=#'
6777  */
6778 static NOINLINE ssize_t
varvalue(char * name,int varflags,int flags,struct strlist * var_str_list,int * quotedp)6779 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
6780 {
6781 	const char *p;
6782 	int num;
6783 	int i;
6784 	ssize_t len = 0;
6785 	int sep;
6786 	int quoted = *quotedp;
6787 	int subtype = varflags & VSTYPE;
6788 	int discard = subtype == VSPLUS || subtype == VSLENGTH;
6789 	int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
6790 	int syntax;
6791 
6792 	sep = (flags & EXP_FULL) << CHAR_BIT;
6793 	syntax = quoted ? DQSYNTAX : BASESYNTAX;
6794 
6795 	switch (*name) {
6796 	case '$':
6797 		num = rootpid;
6798 		goto numvar;
6799 	case '?':
6800 		num = exitstatus;
6801 		goto numvar;
6802 	case '#':
6803 		num = shellparam.nparam;
6804 		goto numvar;
6805 	case '!':
6806 		num = backgndpid;
6807 		if (num == 0)
6808 			return -1;
6809  numvar:
6810 		len = cvtnum(num);
6811 		goto check_1char_name;
6812 	case '-':
6813 		expdest = makestrspace(NOPTS, expdest);
6814 		for (i = NOPTS - 1; i >= 0; i--) {
6815 			if (optlist[i]) {
6816 				USTPUTC(optletters(i), expdest);
6817 				len++;
6818 			}
6819 		}
6820  check_1char_name:
6821 #if 0
6822 		/* handles cases similar to ${#$1} */
6823 		if (name[2] != '\0')
6824 			raise_error_syntax("bad substitution");
6825 #endif
6826 		break;
6827 	case '@':
6828 		if (quoted && sep)
6829 			goto param;
6830 		/* fall through */
6831 	case '*': {
6832 		char **ap;
6833 		char sepc;
6834 
6835 		if (quoted)
6836 			sep = 0;
6837 		sep |= ifsset() ? ifsval()[0] : ' ';
6838  param:
6839 		sepc = sep;
6840 		*quotedp = !sepc;
6841 		ap = shellparam.p;
6842 		if (!ap)
6843 			return -1;
6844 		while ((p = *ap++) != NULL) {
6845 			len += strtodest(p, syntax, quotes);
6846 
6847 			if (*ap && sep) {
6848 				len++;
6849 				memtodest(&sepc, 1, syntax, quotes);
6850 			}
6851 		}
6852 		break;
6853 	} /* case '*' */
6854 	case '0':
6855 	case '1':
6856 	case '2':
6857 	case '3':
6858 	case '4':
6859 	case '5':
6860 	case '6':
6861 	case '7':
6862 	case '8':
6863 	case '9':
6864 		num = atoi(name); /* number(name) fails on ${N#str} etc */
6865 		if (num < 0 || num > shellparam.nparam)
6866 			return -1;
6867 		p = num ? shellparam.p[num - 1] : arg0;
6868 		goto value;
6869 	default:
6870 		/* NB: name has form "VAR=..." */
6871 
6872 		/* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6873 		 * which should be considered before we check variables. */
6874 		if (var_str_list) {
6875 			unsigned name_len = (strchrnul(name, '=') - name) + 1;
6876 			p = NULL;
6877 			do {
6878 				char *str, *eq;
6879 				str = var_str_list->text;
6880 				eq = strchr(str, '=');
6881 				if (!eq) /* stop at first non-assignment */
6882 					break;
6883 				eq++;
6884 				if (name_len == (unsigned)(eq - str)
6885 				 && strncmp(str, name, name_len) == 0
6886 				) {
6887 					p = eq;
6888 					/* goto value; - WRONG! */
6889 					/* think "A=1 A=2 B=$A" */
6890 				}
6891 				var_str_list = var_str_list->next;
6892 			} while (var_str_list);
6893 			if (p)
6894 				goto value;
6895 		}
6896 		p = lookupvar(name);
6897  value:
6898 		if (!p)
6899 			return -1;
6900 
6901 		len = strtodest(p, syntax, quotes);
6902 #if ENABLE_UNICODE_SUPPORT
6903 		if (subtype == VSLENGTH && len > 0) {
6904 			reinit_unicode_for_ash();
6905 			if (unicode_status == UNICODE_ON) {
6906 				STADJUST(-len, expdest);
6907 				discard = 0;
6908 				len = unicode_strlen(p);
6909 			}
6910 		}
6911 #endif
6912 		break;
6913 	}
6914 
6915 	if (discard)
6916 		STADJUST(-len, expdest);
6917 	return len;
6918 }
6919 
6920 /*
6921  * Expand a variable, and return a pointer to the next character in the
6922  * input string.
6923  */
6924 static char *
evalvar(char * p,int flag,struct strlist * var_str_list)6925 evalvar(char *p, int flag, struct strlist *var_str_list)
6926 {
6927 	char varflags;
6928 	char subtype;
6929 	int quoted;
6930 	char easy;
6931 	char *var;
6932 	int patloc;
6933 	int startloc;
6934 	ssize_t varlen;
6935 
6936 	varflags = (unsigned char) *p++;
6937 	subtype = varflags & VSTYPE;
6938 
6939 	if (!subtype)
6940 		raise_error_syntax("bad substitution");
6941 
6942 	quoted = flag & EXP_QUOTED;
6943 	var = p;
6944 	easy = (!quoted || (*var == '@' && shellparam.nparam));
6945 	startloc = expdest - (char *)stackblock();
6946 	p = strchr(p, '=') + 1; //TODO: use var_end(p)?
6947 
6948  again:
6949 	varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
6950 	if (varflags & VSNUL)
6951 		varlen--;
6952 
6953 	if (subtype == VSPLUS) {
6954 		varlen = -1 - varlen;
6955 		goto vsplus;
6956 	}
6957 
6958 	if (subtype == VSMINUS) {
6959  vsplus:
6960 		if (varlen < 0) {
6961 			argstr(
6962 				p,
6963 				flag | EXP_TILDE | EXP_WORD,
6964 				var_str_list
6965 			);
6966 			goto end;
6967 		}
6968 		goto record;
6969 	}
6970 
6971 	if (subtype == VSASSIGN || subtype == VSQUESTION) {
6972 		if (varlen >= 0)
6973 			goto record;
6974 
6975 		subevalvar(p, var, 0, subtype, startloc, varflags,
6976 			   flag & ~QUOTES_ESC, var_str_list);
6977 		varflags &= ~VSNUL;
6978 		/*
6979 		 * Remove any recorded regions beyond
6980 		 * start of variable
6981 		 */
6982 		removerecordregions(startloc);
6983 		goto again;
6984 	}
6985 
6986 	if (varlen < 0 && uflag)
6987 		varunset(p, var, 0, 0);
6988 
6989 	if (subtype == VSLENGTH) {
6990 		cvtnum(varlen > 0 ? varlen : 0);
6991 		goto record;
6992 	}
6993 
6994 	if (subtype == VSNORMAL) {
6995  record:
6996 		if (!easy)
6997 			goto end;
6998 		recordregion(startloc, expdest - (char *)stackblock(), quoted);
6999 		goto end;
7000 	}
7001 
7002 #if DEBUG
7003 	switch (subtype) {
7004 	case VSTRIMLEFT:
7005 	case VSTRIMLEFTMAX:
7006 	case VSTRIMRIGHT:
7007 	case VSTRIMRIGHTMAX:
7008 #if ENABLE_ASH_BASH_COMPAT
7009 	case VSSUBSTR:
7010 	case VSREPLACE:
7011 	case VSREPLACEALL:
7012 #endif
7013 		break;
7014 	default:
7015 		abort();
7016 	}
7017 #endif
7018 
7019 	if (varlen >= 0) {
7020 		/*
7021 		 * Terminate the string and start recording the pattern
7022 		 * right after it
7023 		 */
7024 		STPUTC('\0', expdest);
7025 		patloc = expdest - (char *)stackblock();
7026 		if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
7027 				startloc, varflags, flag, var_str_list)) {
7028 			int amount = expdest - (
7029 				(char *)stackblock() + patloc - 1
7030 			);
7031 			STADJUST(-amount, expdest);
7032 		}
7033 		/* Remove any recorded regions beyond start of variable */
7034 		removerecordregions(startloc);
7035 		goto record;
7036 	}
7037 
7038  end:
7039 	if (subtype != VSNORMAL) {      /* skip to end of alternative */
7040 		int nesting = 1;
7041 		for (;;) {
7042 			unsigned char c = *p++;
7043 			if (c == CTLESC)
7044 				p++;
7045 			else if (c == CTLBACKQ) {
7046 				if (varlen >= 0)
7047 					argbackq = argbackq->next;
7048 			} else if (c == CTLVAR) {
7049 				if ((*p++ & VSTYPE) != VSNORMAL)
7050 					nesting++;
7051 			} else if (c == CTLENDVAR) {
7052 				if (--nesting == 0)
7053 					break;
7054 			}
7055 		}
7056 	}
7057 	return p;
7058 }
7059 
7060 /*
7061  * Add a file name to the list.
7062  */
7063 static void
addfname(const char * name)7064 addfname(const char *name)
7065 {
7066 	struct strlist *sp;
7067 
7068 	sp = stzalloc(sizeof(*sp));
7069 	sp->text = sstrdup(name);
7070 	*exparg.lastp = sp;
7071 	exparg.lastp = &sp->next;
7072 }
7073 
7074 /* If we want to use glob() from libc... */
7075 #if !ENABLE_ASH_INTERNAL_GLOB
7076 
7077 /* Add the result of glob() to the list */
7078 static void
addglob(const glob_t * pglob)7079 addglob(const glob_t *pglob)
7080 {
7081 	char **p = pglob->gl_pathv;
7082 
7083 	do {
7084 		addfname(*p);
7085 	} while (*++p);
7086 }
7087 static void
expandmeta(struct strlist * str)7088 expandmeta(struct strlist *str /*, int flag*/)
7089 {
7090 	/* TODO - EXP_REDIR */
7091 
7092 	while (str) {
7093 		char *p;
7094 		glob_t pglob;
7095 		int i;
7096 
7097 		if (fflag)
7098 			goto nometa;
7099 
7100 		/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7101 		p = str->text;
7102 		while (*p) {
7103 			if (*p == '*')
7104 				goto need_glob;
7105 			if (*p == '?')
7106 				goto need_glob;
7107 			if (*p == '[')
7108 				goto need_glob;
7109 			p++;
7110 		}
7111 		goto nometa;
7112 
7113  need_glob:
7114 		INT_OFF;
7115 		p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7116 // GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7117 // GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7118 //
7119 // glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7120 // if you pass it "file\?", it returns "file\?", not "file?", if no match.
7121 // Which means you need to unescape the string, right? Not so fast:
7122 // if there _is_ a file named "file\?" (with backslash), it is returned
7123 // as "file\?" too (whichever pattern you used to find it, say, "file*").
7124 // You DONT KNOW by looking at the result whether you need to unescape it.
7125 //
7126 // Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7127 // returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7128 // Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7129 // With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7130 //		i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7131 //		i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7132 		i = glob(p, 0, NULL, &pglob);
7133 		//bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7134 		if (p != str->text)
7135 			free(p);
7136 		switch (i) {
7137 		case 0:
7138 #if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7139 			/* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7140 			if (!(pglob.gl_flags & GLOB_MAGCHAR))
7141 				goto nometa2;
7142 #endif
7143 			addglob(&pglob);
7144 			globfree(&pglob);
7145 			INT_ON;
7146 			break;
7147 		case GLOB_NOMATCH:
7148  //nometa2:
7149 			globfree(&pglob);
7150 			INT_ON;
7151  nometa:
7152 			*exparg.lastp = str;
7153 			rmescapes(str->text, 0);
7154 			exparg.lastp = &str->next;
7155 			break;
7156 		default:	/* GLOB_NOSPACE */
7157 			globfree(&pglob);
7158 			INT_ON;
7159 			ash_msg_and_raise_error(bb_msg_memory_exhausted);
7160 		}
7161 		str = str->next;
7162 	}
7163 }
7164 
7165 #else
7166 /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7167 
7168 /*
7169  * Do metacharacter (i.e. *, ?, [...]) expansion.
7170  */
7171 static void
expmeta(char * expdir,char * enddir,char * name)7172 expmeta(char *expdir, char *enddir, char *name)
7173 {
7174 	char *p;
7175 	const char *cp;
7176 	char *start;
7177 	char *endname;
7178 	int metaflag;
7179 	struct stat statb;
7180 	DIR *dirp;
7181 	struct dirent *dp;
7182 	int atend;
7183 	int matchdot;
7184 	int esc;
7185 
7186 	metaflag = 0;
7187 	start = name;
7188 	for (p = name; esc = 0, *p; p += esc + 1) {
7189 		if (*p == '*' || *p == '?')
7190 			metaflag = 1;
7191 		else if (*p == '[') {
7192 			char *q = p + 1;
7193 			if (*q == '!')
7194 				q++;
7195 			for (;;) {
7196 				if (*q == '\\')
7197 					q++;
7198 				if (*q == '/' || *q == '\0')
7199 					break;
7200 				if (*++q == ']') {
7201 					metaflag = 1;
7202 					break;
7203 				}
7204 			}
7205 		} else {
7206 			if (*p == '\\')
7207 				esc++;
7208 			if (p[esc] == '/') {
7209 				if (metaflag)
7210 					break;
7211 				start = p + esc + 1;
7212 			}
7213 		}
7214 	}
7215 	if (metaflag == 0) {    /* we've reached the end of the file name */
7216 		if (enddir != expdir)
7217 			metaflag++;
7218 		p = name;
7219 		do {
7220 			if (*p == '\\')
7221 				p++;
7222 			*enddir++ = *p;
7223 		} while (*p++);
7224 		if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7225 			addfname(expdir);
7226 		return;
7227 	}
7228 	endname = p;
7229 	if (name < start) {
7230 		p = name;
7231 		do {
7232 			if (*p == '\\')
7233 				p++;
7234 			*enddir++ = *p++;
7235 		} while (p < start);
7236 	}
7237 	if (enddir == expdir) {
7238 		cp = ".";
7239 	} else if (enddir == expdir + 1 && *expdir == '/') {
7240 		cp = "/";
7241 	} else {
7242 		cp = expdir;
7243 		enddir[-1] = '\0';
7244 	}
7245 	dirp = opendir(cp);
7246 	if (dirp == NULL)
7247 		return;
7248 	if (enddir != expdir)
7249 		enddir[-1] = '/';
7250 	if (*endname == 0) {
7251 		atend = 1;
7252 	} else {
7253 		atend = 0;
7254 		*endname = '\0';
7255 		endname += esc + 1;
7256 	}
7257 	matchdot = 0;
7258 	p = start;
7259 	if (*p == '\\')
7260 		p++;
7261 	if (*p == '.')
7262 		matchdot++;
7263 	while (!pending_int && (dp = readdir(dirp)) != NULL) {
7264 		if (dp->d_name[0] == '.' && !matchdot)
7265 			continue;
7266 		if (pmatch(start, dp->d_name)) {
7267 			if (atend) {
7268 				strcpy(enddir, dp->d_name);
7269 				addfname(expdir);
7270 			} else {
7271 				for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7272 					continue;
7273 				p[-1] = '/';
7274 				expmeta(expdir, p, endname);
7275 			}
7276 		}
7277 	}
7278 	closedir(dirp);
7279 	if (!atend)
7280 		endname[-esc - 1] = esc ? '\\' : '/';
7281 }
7282 
7283 static struct strlist *
msort(struct strlist * list,int len)7284 msort(struct strlist *list, int len)
7285 {
7286 	struct strlist *p, *q = NULL;
7287 	struct strlist **lpp;
7288 	int half;
7289 	int n;
7290 
7291 	if (len <= 1)
7292 		return list;
7293 	half = len >> 1;
7294 	p = list;
7295 	for (n = half; --n >= 0;) {
7296 		q = p;
7297 		p = p->next;
7298 	}
7299 	q->next = NULL;                 /* terminate first half of list */
7300 	q = msort(list, half);          /* sort first half of list */
7301 	p = msort(p, len - half);               /* sort second half */
7302 	lpp = &list;
7303 	for (;;) {
7304 #if ENABLE_LOCALE_SUPPORT
7305 		if (strcoll(p->text, q->text) < 0)
7306 #else
7307 		if (strcmp(p->text, q->text) < 0)
7308 #endif
7309 						{
7310 			*lpp = p;
7311 			lpp = &p->next;
7312 			p = *lpp;
7313 			if (p == NULL) {
7314 				*lpp = q;
7315 				break;
7316 			}
7317 		} else {
7318 			*lpp = q;
7319 			lpp = &q->next;
7320 			q = *lpp;
7321 			if (q == NULL) {
7322 				*lpp = p;
7323 				break;
7324 			}
7325 		}
7326 	}
7327 	return list;
7328 }
7329 
7330 /*
7331  * Sort the results of file name expansion.  It calculates the number of
7332  * strings to sort and then calls msort (short for merge sort) to do the
7333  * work.
7334  */
7335 static struct strlist *
expsort(struct strlist * str)7336 expsort(struct strlist *str)
7337 {
7338 	int len;
7339 	struct strlist *sp;
7340 
7341 	len = 0;
7342 	for (sp = str; sp; sp = sp->next)
7343 		len++;
7344 	return msort(str, len);
7345 }
7346 
7347 static void
expandmeta(struct strlist * str)7348 expandmeta(struct strlist *str /*, int flag*/)
7349 {
7350 	static const char metachars[] ALIGN1 = {
7351 		'*', '?', '[', 0
7352 	};
7353 	/* TODO - EXP_REDIR */
7354 
7355 	while (str) {
7356 		char *expdir;
7357 		struct strlist **savelastp;
7358 		struct strlist *sp;
7359 		char *p;
7360 
7361 		if (fflag)
7362 			goto nometa;
7363 		if (!strpbrk(str->text, metachars))
7364 			goto nometa;
7365 		savelastp = exparg.lastp;
7366 
7367 		INT_OFF;
7368 		p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7369 		{
7370 			int i = strlen(str->text);
7371 //BUGGY estimation of how long expanded name can be
7372 			expdir = ckmalloc(i < 2048 ? 2048 : i+1);
7373 		}
7374 		expmeta(expdir, expdir, p);
7375 		free(expdir);
7376 		if (p != str->text)
7377 			free(p);
7378 		INT_ON;
7379 		if (exparg.lastp == savelastp) {
7380 			/*
7381 			 * no matches
7382 			 */
7383  nometa:
7384 			*exparg.lastp = str;
7385 			rmescapes(str->text, 0);
7386 			exparg.lastp = &str->next;
7387 		} else {
7388 			*exparg.lastp = NULL;
7389 			*savelastp = sp = expsort(*savelastp);
7390 			while (sp->next != NULL)
7391 				sp = sp->next;
7392 			exparg.lastp = &sp->next;
7393 		}
7394 		str = str->next;
7395 	}
7396 }
7397 #endif /* ENABLE_ASH_INTERNAL_GLOB */
7398 
7399 /*
7400  * Perform variable substitution and command substitution on an argument,
7401  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
7402  * perform splitting and file name expansion.  When arglist is NULL, perform
7403  * here document expansion.
7404  */
7405 static void
expandarg(union node * arg,struct arglist * arglist,int flag)7406 expandarg(union node *arg, struct arglist *arglist, int flag)
7407 {
7408 	struct strlist *sp;
7409 	char *p;
7410 
7411 	argbackq = arg->narg.backquote;
7412 	STARTSTACKSTR(expdest);
7413 	TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7414 	argstr(arg->narg.text, flag,
7415 			/* var_str_list: */ arglist ? arglist->list : NULL);
7416 	p = _STPUTC('\0', expdest);
7417 	expdest = p - 1;
7418 	if (arglist == NULL) {
7419 		/* here document expanded */
7420 		goto out;
7421 	}
7422 	p = grabstackstr(p);
7423 	TRACE(("expandarg: p:'%s'\n", p));
7424 	exparg.lastp = &exparg.list;
7425 	/*
7426 	 * TODO - EXP_REDIR
7427 	 */
7428 	if (flag & EXP_FULL) {
7429 		ifsbreakup(p, &exparg);
7430 		*exparg.lastp = NULL;
7431 		exparg.lastp = &exparg.list;
7432 		expandmeta(exparg.list /*, flag*/);
7433 	} else {
7434 		if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
7435 			rmescapes(p, 0);
7436 			TRACE(("expandarg: rmescapes:'%s'\n", p));
7437 		}
7438 		sp = stzalloc(sizeof(*sp));
7439 		sp->text = p;
7440 		*exparg.lastp = sp;
7441 		exparg.lastp = &sp->next;
7442 	}
7443 	*exparg.lastp = NULL;
7444 	if (exparg.list) {
7445 		*arglist->lastp = exparg.list;
7446 		arglist->lastp = exparg.lastp;
7447 	}
7448 
7449  out:
7450 	ifsfree();
7451 }
7452 
7453 /*
7454  * Expand shell variables and backquotes inside a here document.
7455  */
7456 static void
expandhere(union node * arg,int fd)7457 expandhere(union node *arg, int fd)
7458 {
7459 	expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7460 	full_write(fd, stackblock(), expdest - (char *)stackblock());
7461 }
7462 
7463 /*
7464  * Returns true if the pattern matches the string.
7465  */
7466 static int
patmatch(char * pattern,const char * string)7467 patmatch(char *pattern, const char *string)
7468 {
7469 	return pmatch(preglob(pattern, 0), string);
7470 }
7471 
7472 /*
7473  * See if a pattern matches in a case statement.
7474  */
7475 static int
casematch(union node * pattern,char * val)7476 casematch(union node *pattern, char *val)
7477 {
7478 	struct stackmark smark;
7479 	int result;
7480 
7481 	setstackmark(&smark);
7482 	argbackq = pattern->narg.backquote;
7483 	STARTSTACKSTR(expdest);
7484 	argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7485 			/* var_str_list: */ NULL);
7486 	STACKSTRNUL(expdest);
7487 	ifsfree();
7488 	result = patmatch(stackblock(), val);
7489 	popstackmark(&smark);
7490 	return result;
7491 }
7492 
7493 
7494 /* ============ find_command */
7495 
7496 struct builtincmd {
7497 	const char *name;
7498 	int (*builtin)(int, char **) FAST_FUNC;
7499 	/* unsigned flags; */
7500 };
7501 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7502 /* "regular" builtins always take precedence over commands,
7503  * regardless of PATH=....%builtin... position */
7504 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7505 #define IS_BUILTIN_ASSIGN(b)  ((b)->name[0] & 4)
7506 
7507 struct cmdentry {
7508 	smallint cmdtype;       /* CMDxxx */
7509 	union param {
7510 		int index;
7511 		/* index >= 0 for commands without path (slashes) */
7512 		/* (TODO: what exactly does the value mean? PATH position?) */
7513 		/* index == -1 for commands with slashes */
7514 		/* index == (-2 - applet_no) for NOFORK applets */
7515 		const struct builtincmd *cmd;
7516 		struct funcnode *func;
7517 	} u;
7518 };
7519 /* values of cmdtype */
7520 #define CMDUNKNOWN      -1      /* no entry in table for command */
7521 #define CMDNORMAL       0       /* command is an executable program */
7522 #define CMDFUNCTION     1       /* command is a shell function */
7523 #define CMDBUILTIN      2       /* command is a shell builtin */
7524 
7525 /* action to find_command() */
7526 #define DO_ERR          0x01    /* prints errors */
7527 #define DO_ABS          0x02    /* checks absolute paths */
7528 #define DO_NOFUNC       0x04    /* don't return shell functions, for command */
7529 #define DO_ALTPATH      0x08    /* using alternate path */
7530 #define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
7531 
7532 static void find_command(char *, struct cmdentry *, int, const char *);
7533 
7534 
7535 /* ============ Hashing commands */
7536 
7537 /*
7538  * When commands are first encountered, they are entered in a hash table.
7539  * This ensures that a full path search will not have to be done for them
7540  * on each invocation.
7541  *
7542  * We should investigate converting to a linear search, even though that
7543  * would make the command name "hash" a misnomer.
7544  */
7545 
7546 struct tblentry {
7547 	struct tblentry *next;  /* next entry in hash chain */
7548 	union param param;      /* definition of builtin function */
7549 	smallint cmdtype;       /* CMDxxx */
7550 	char rehash;            /* if set, cd done since entry created */
7551 	char cmdname[1];        /* name of command */
7552 };
7553 
7554 static struct tblentry **cmdtable;
7555 #define INIT_G_cmdtable() do { \
7556 	cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7557 } while (0)
7558 
7559 static int builtinloc = -1;     /* index in path of %builtin, or -1 */
7560 
7561 
7562 static void
7563 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7564 {
7565 #if ENABLE_FEATURE_SH_STANDALONE
7566 	if (applet_no >= 0) {
7567 		if (APPLET_IS_NOEXEC(applet_no)) {
7568 			clearenv();
7569 			while (*envp)
7570 				putenv(*envp++);
7571 			run_applet_no_and_exit(applet_no, argv);
7572 		}
7573 		/* re-exec ourselves with the new arguments */
7574 		execve(bb_busybox_exec_path, argv, envp);
7575 		/* If they called chroot or otherwise made the binary no longer
7576 		 * executable, fall through */
7577 	}
7578 #endif
7579 
7580  repeat:
7581 #ifdef SYSV
7582 	do {
7583 		execve(cmd, argv, envp);
7584 	} while (errno == EINTR);
7585 #else
7586 	execve(cmd, argv, envp);
7587 #endif
7588 	if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
7589 		/* Run "cmd" as a shell script:
7590 		 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7591 		 * "If the execve() function fails with ENOEXEC, the shell
7592 		 * shall execute a command equivalent to having a shell invoked
7593 		 * with the command name as its first operand,
7594 		 * with any remaining arguments passed to the new shell"
7595 		 *
7596 		 * That is, do not use $SHELL, user's shell, or /bin/sh;
7597 		 * just call ourselves.
7598 		 *
7599 		 * Note that bash reads ~80 chars of the file, and if it sees
7600 		 * a zero byte before it sees newline, it doesn't try to
7601 		 * interpret it, but fails with "cannot execute binary file"
7602 		 * message and exit code 126. For one, this prevents attempts
7603 		 * to interpret foreign ELF binaries as shell scripts.
7604 		 */
7605 		argv[0] = cmd;
7606 		cmd = (char*) bb_busybox_exec_path;
7607 		/* NB: this is only possible because all callers of shellexec()
7608 		 * ensure that the argv[-1] slot exists!
7609 		 */
7610 		argv--;
7611 		argv[0] = (char*) "ash";
7612 		goto repeat;
7613 	}
7614 }
7615 
7616 /*
7617  * Exec a program.  Never returns.  If you change this routine, you may
7618  * have to change the find_command routine as well.
7619  * argv[-1] must exist and be writable! See tryexec() for why.
7620  */
7621 static void shellexec(char **, const char *, int) NORETURN;
7622 static void
shellexec(char ** argv,const char * path,int idx)7623 shellexec(char **argv, const char *path, int idx)
7624 {
7625 	char *cmdname;
7626 	int e;
7627 	char **envp;
7628 	int exerrno;
7629 	int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7630 
7631 	envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7632 	if (strchr(argv[0], '/') != NULL
7633 #if ENABLE_FEATURE_SH_STANDALONE
7634 	 || (applet_no = find_applet_by_name(argv[0])) >= 0
7635 #endif
7636 	) {
7637 		tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7638 		if (applet_no >= 0) {
7639 			/* We tried execing ourself, but it didn't work.
7640 			 * Maybe /proc/self/exe doesn't exist?
7641 			 * Try $PATH search.
7642 			 */
7643 			goto try_PATH;
7644 		}
7645 		e = errno;
7646 	} else {
7647  try_PATH:
7648 		e = ENOENT;
7649 		while ((cmdname = path_advance(&path, argv[0])) != NULL) {
7650 			if (--idx < 0 && pathopt == NULL) {
7651 				tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7652 				if (errno != ENOENT && errno != ENOTDIR)
7653 					e = errno;
7654 			}
7655 			stunalloc(cmdname);
7656 		}
7657 	}
7658 
7659 	/* Map to POSIX errors */
7660 	switch (e) {
7661 	case EACCES:
7662 		exerrno = 126;
7663 		break;
7664 	case ENOENT:
7665 		exerrno = 127;
7666 		break;
7667 	default:
7668 		exerrno = 2;
7669 		break;
7670 	}
7671 	exitstatus = exerrno;
7672 	TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7673 		argv[0], e, suppress_int));
7674 	ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
7675 	/* NOTREACHED */
7676 }
7677 
7678 static void
printentry(struct tblentry * cmdp)7679 printentry(struct tblentry *cmdp)
7680 {
7681 	int idx;
7682 	const char *path;
7683 	char *name;
7684 
7685 	idx = cmdp->param.index;
7686 	path = pathval();
7687 	do {
7688 		name = path_advance(&path, cmdp->cmdname);
7689 		stunalloc(name);
7690 	} while (--idx >= 0);
7691 	out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7692 }
7693 
7694 /*
7695  * Clear out command entries.  The argument specifies the first entry in
7696  * PATH which has changed.
7697  */
7698 static void
clearcmdentry(int firstchange)7699 clearcmdentry(int firstchange)
7700 {
7701 	struct tblentry **tblp;
7702 	struct tblentry **pp;
7703 	struct tblentry *cmdp;
7704 
7705 	INT_OFF;
7706 	for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7707 		pp = tblp;
7708 		while ((cmdp = *pp) != NULL) {
7709 			if ((cmdp->cmdtype == CMDNORMAL &&
7710 			     cmdp->param.index >= firstchange)
7711 			 || (cmdp->cmdtype == CMDBUILTIN &&
7712 			     builtinloc >= firstchange)
7713 			) {
7714 				*pp = cmdp->next;
7715 				free(cmdp);
7716 			} else {
7717 				pp = &cmdp->next;
7718 			}
7719 		}
7720 	}
7721 	INT_ON;
7722 }
7723 
7724 /*
7725  * Locate a command in the command hash table.  If "add" is nonzero,
7726  * add the command to the table if it is not already present.  The
7727  * variable "lastcmdentry" is set to point to the address of the link
7728  * pointing to the entry, so that delete_cmd_entry can delete the
7729  * entry.
7730  *
7731  * Interrupts must be off if called with add != 0.
7732  */
7733 static struct tblentry **lastcmdentry;
7734 
7735 static struct tblentry *
cmdlookup(const char * name,int add)7736 cmdlookup(const char *name, int add)
7737 {
7738 	unsigned int hashval;
7739 	const char *p;
7740 	struct tblentry *cmdp;
7741 	struct tblentry **pp;
7742 
7743 	p = name;
7744 	hashval = (unsigned char)*p << 4;
7745 	while (*p)
7746 		hashval += (unsigned char)*p++;
7747 	hashval &= 0x7FFF;
7748 	pp = &cmdtable[hashval % CMDTABLESIZE];
7749 	for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7750 		if (strcmp(cmdp->cmdname, name) == 0)
7751 			break;
7752 		pp = &cmdp->next;
7753 	}
7754 	if (add && cmdp == NULL) {
7755 		cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7756 				+ strlen(name)
7757 				/* + 1 - already done because
7758 				 * tblentry::cmdname is char[1] */);
7759 		/*cmdp->next = NULL; - ckzalloc did it */
7760 		cmdp->cmdtype = CMDUNKNOWN;
7761 		strcpy(cmdp->cmdname, name);
7762 	}
7763 	lastcmdentry = pp;
7764 	return cmdp;
7765 }
7766 
7767 /*
7768  * Delete the command entry returned on the last lookup.
7769  */
7770 static void
delete_cmd_entry(void)7771 delete_cmd_entry(void)
7772 {
7773 	struct tblentry *cmdp;
7774 
7775 	INT_OFF;
7776 	cmdp = *lastcmdentry;
7777 	*lastcmdentry = cmdp->next;
7778 	if (cmdp->cmdtype == CMDFUNCTION)
7779 		freefunc(cmdp->param.func);
7780 	free(cmdp);
7781 	INT_ON;
7782 }
7783 
7784 /*
7785  * Add a new command entry, replacing any existing command entry for
7786  * the same name - except special builtins.
7787  */
7788 static void
addcmdentry(char * name,struct cmdentry * entry)7789 addcmdentry(char *name, struct cmdentry *entry)
7790 {
7791 	struct tblentry *cmdp;
7792 
7793 	cmdp = cmdlookup(name, 1);
7794 	if (cmdp->cmdtype == CMDFUNCTION) {
7795 		freefunc(cmdp->param.func);
7796 	}
7797 	cmdp->cmdtype = entry->cmdtype;
7798 	cmdp->param = entry->u;
7799 	cmdp->rehash = 0;
7800 }
7801 
7802 static int FAST_FUNC
hashcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)7803 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7804 {
7805 	struct tblentry **pp;
7806 	struct tblentry *cmdp;
7807 	int c;
7808 	struct cmdentry entry;
7809 	char *name;
7810 
7811 	if (nextopt("r") != '\0') {
7812 		clearcmdentry(0);
7813 		return 0;
7814 	}
7815 
7816 	if (*argptr == NULL) {
7817 		for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7818 			for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7819 				if (cmdp->cmdtype == CMDNORMAL)
7820 					printentry(cmdp);
7821 			}
7822 		}
7823 		return 0;
7824 	}
7825 
7826 	c = 0;
7827 	while ((name = *argptr) != NULL) {
7828 		cmdp = cmdlookup(name, 0);
7829 		if (cmdp != NULL
7830 		 && (cmdp->cmdtype == CMDNORMAL
7831 		     || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7832 		) {
7833 			delete_cmd_entry();
7834 		}
7835 		find_command(name, &entry, DO_ERR, pathval());
7836 		if (entry.cmdtype == CMDUNKNOWN)
7837 			c = 1;
7838 		argptr++;
7839 	}
7840 	return c;
7841 }
7842 
7843 /*
7844  * Called when a cd is done.  Marks all commands so the next time they
7845  * are executed they will be rehashed.
7846  */
7847 static void
hashcd(void)7848 hashcd(void)
7849 {
7850 	struct tblentry **pp;
7851 	struct tblentry *cmdp;
7852 
7853 	for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7854 		for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7855 			if (cmdp->cmdtype == CMDNORMAL
7856 			 || (cmdp->cmdtype == CMDBUILTIN
7857 			     && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7858 			     && builtinloc > 0)
7859 			) {
7860 				cmdp->rehash = 1;
7861 			}
7862 		}
7863 	}
7864 }
7865 
7866 /*
7867  * Fix command hash table when PATH changed.
7868  * Called before PATH is changed.  The argument is the new value of PATH;
7869  * pathval() still returns the old value at this point.
7870  * Called with interrupts off.
7871  */
7872 static void FAST_FUNC
changepath(const char * new)7873 changepath(const char *new)
7874 {
7875 	const char *old;
7876 	int firstchange;
7877 	int idx;
7878 	int idx_bltin;
7879 
7880 	old = pathval();
7881 	firstchange = 9999;     /* assume no change */
7882 	idx = 0;
7883 	idx_bltin = -1;
7884 	for (;;) {
7885 		if (*old != *new) {
7886 			firstchange = idx;
7887 			if ((*old == '\0' && *new == ':')
7888 			 || (*old == ':' && *new == '\0')
7889 			) {
7890 				firstchange++;
7891 			}
7892 			old = new;      /* ignore subsequent differences */
7893 		}
7894 		if (*new == '\0')
7895 			break;
7896 		if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7897 			idx_bltin = idx;
7898 		if (*new == ':')
7899 			idx++;
7900 		new++;
7901 		old++;
7902 	}
7903 	if (builtinloc < 0 && idx_bltin >= 0)
7904 		builtinloc = idx_bltin;             /* zap builtins */
7905 	if (builtinloc >= 0 && idx_bltin < 0)
7906 		firstchange = 0;
7907 	clearcmdentry(firstchange);
7908 	builtinloc = idx_bltin;
7909 }
7910 enum {
7911 	TEOF,
7912 	TNL,
7913 	TREDIR,
7914 	TWORD,
7915 	TSEMI,
7916 	TBACKGND,
7917 	TAND,
7918 	TOR,
7919 	TPIPE,
7920 	TLP,
7921 	TRP,
7922 	TENDCASE,
7923 	TENDBQUOTE,
7924 	TNOT,
7925 	TCASE,
7926 	TDO,
7927 	TDONE,
7928 	TELIF,
7929 	TELSE,
7930 	TESAC,
7931 	TFI,
7932 	TFOR,
7933 #if ENABLE_ASH_BASH_COMPAT
7934 	TFUNCTION,
7935 #endif
7936 	TIF,
7937 	TIN,
7938 	TTHEN,
7939 	TUNTIL,
7940 	TWHILE,
7941 	TBEGIN,
7942 	TEND
7943 };
7944 typedef smallint token_id_t;
7945 
7946 /* Nth bit indicates if token marks the end of a list */
7947 enum {
7948 	tokendlist = 0
7949 	/*  0 */ | (1u << TEOF)
7950 	/*  1 */ | (0u << TNL)
7951 	/*  2 */ | (0u << TREDIR)
7952 	/*  3 */ | (0u << TWORD)
7953 	/*  4 */ | (0u << TSEMI)
7954 	/*  5 */ | (0u << TBACKGND)
7955 	/*  6 */ | (0u << TAND)
7956 	/*  7 */ | (0u << TOR)
7957 	/*  8 */ | (0u << TPIPE)
7958 	/*  9 */ | (0u << TLP)
7959 	/* 10 */ | (1u << TRP)
7960 	/* 11 */ | (1u << TENDCASE)
7961 	/* 12 */ | (1u << TENDBQUOTE)
7962 	/* 13 */ | (0u << TNOT)
7963 	/* 14 */ | (0u << TCASE)
7964 	/* 15 */ | (1u << TDO)
7965 	/* 16 */ | (1u << TDONE)
7966 	/* 17 */ | (1u << TELIF)
7967 	/* 18 */ | (1u << TELSE)
7968 	/* 19 */ | (1u << TESAC)
7969 	/* 20 */ | (1u << TFI)
7970 	/* 21 */ | (0u << TFOR)
7971 #if ENABLE_ASH_BASH_COMPAT
7972 	/* 22 */ | (0u << TFUNCTION)
7973 #endif
7974 	/* 23 */ | (0u << TIF)
7975 	/* 24 */ | (0u << TIN)
7976 	/* 25 */ | (1u << TTHEN)
7977 	/* 26 */ | (0u << TUNTIL)
7978 	/* 27 */ | (0u << TWHILE)
7979 	/* 28 */ | (0u << TBEGIN)
7980 	/* 29 */ | (1u << TEND)
7981 	, /* thus far 29 bits used */
7982 };
7983 
7984 static const char *const tokname_array[] = {
7985 	"end of file",
7986 	"newline",
7987 	"redirection",
7988 	"word",
7989 	";",
7990 	"&",
7991 	"&&",
7992 	"||",
7993 	"|",
7994 	"(",
7995 	")",
7996 	";;",
7997 	"`",
7998 #define KWDOFFSET 13
7999 	/* the following are keywords */
8000 	"!",
8001 	"case",
8002 	"do",
8003 	"done",
8004 	"elif",
8005 	"else",
8006 	"esac",
8007 	"fi",
8008 	"for",
8009 #if ENABLE_ASH_BASH_COMPAT
8010 	"function",
8011 #endif
8012 	"if",
8013 	"in",
8014 	"then",
8015 	"until",
8016 	"while",
8017 	"{",
8018 	"}",
8019 };
8020 
8021 /* Wrapper around strcmp for qsort/bsearch/... */
8022 static int
pstrcmp(const void * a,const void * b)8023 pstrcmp(const void *a, const void *b)
8024 {
8025 	return strcmp((char*)a, *(char**)b);
8026 }
8027 
8028 static const char *const *
findkwd(const char * s)8029 findkwd(const char *s)
8030 {
8031 	return bsearch(s, tokname_array + KWDOFFSET,
8032 			ARRAY_SIZE(tokname_array) - KWDOFFSET,
8033 			sizeof(tokname_array[0]), pstrcmp);
8034 }
8035 
8036 /*
8037  * Locate and print what a word is...
8038  */
8039 static int
describe_command(char * command,const char * path,int describe_command_verbose)8040 describe_command(char *command, const char *path, int describe_command_verbose)
8041 {
8042 	struct cmdentry entry;
8043 	struct tblentry *cmdp;
8044 #if ENABLE_ASH_ALIAS
8045 	const struct alias *ap;
8046 #endif
8047 
8048 	path = path ? path : pathval();
8049 
8050 	if (describe_command_verbose) {
8051 		out1str(command);
8052 	}
8053 
8054 	/* First look at the keywords */
8055 	if (findkwd(command)) {
8056 		out1str(describe_command_verbose ? " is a shell keyword" : command);
8057 		goto out;
8058 	}
8059 
8060 #if ENABLE_ASH_ALIAS
8061 	/* Then look at the aliases */
8062 	ap = lookupalias(command, 0);
8063 	if (ap != NULL) {
8064 		if (!describe_command_verbose) {
8065 			out1str("alias ");
8066 			printalias(ap);
8067 			return 0;
8068 		}
8069 		out1fmt(" is an alias for %s", ap->val);
8070 		goto out;
8071 	}
8072 #endif
8073 	/* Then check if it is a tracked alias */
8074 	cmdp = cmdlookup(command, 0);
8075 	if (cmdp != NULL) {
8076 		entry.cmdtype = cmdp->cmdtype;
8077 		entry.u = cmdp->param;
8078 	} else {
8079 		/* Finally use brute force */
8080 		find_command(command, &entry, DO_ABS, path);
8081 	}
8082 
8083 	switch (entry.cmdtype) {
8084 	case CMDNORMAL: {
8085 		int j = entry.u.index;
8086 		char *p;
8087 		if (j < 0) {
8088 			p = command;
8089 		} else {
8090 			do {
8091 				p = path_advance(&path, command);
8092 				stunalloc(p);
8093 			} while (--j >= 0);
8094 		}
8095 		if (describe_command_verbose) {
8096 			out1fmt(" is%s %s",
8097 				(cmdp ? " a tracked alias for" : nullstr), p
8098 			);
8099 		} else {
8100 			out1str(p);
8101 		}
8102 		break;
8103 	}
8104 
8105 	case CMDFUNCTION:
8106 		if (describe_command_verbose) {
8107 			out1str(" is a shell function");
8108 		} else {
8109 			out1str(command);
8110 		}
8111 		break;
8112 
8113 	case CMDBUILTIN:
8114 		if (describe_command_verbose) {
8115 			out1fmt(" is a %sshell builtin",
8116 				IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8117 					"special " : nullstr
8118 			);
8119 		} else {
8120 			out1str(command);
8121 		}
8122 		break;
8123 
8124 	default:
8125 		if (describe_command_verbose) {
8126 			out1str(": not found\n");
8127 		}
8128 		return 127;
8129 	}
8130  out:
8131 	out1str("\n");
8132 	return 0;
8133 }
8134 
8135 static int FAST_FUNC
typecmd(int argc UNUSED_PARAM,char ** argv)8136 typecmd(int argc UNUSED_PARAM, char **argv)
8137 {
8138 	int i = 1;
8139 	int err = 0;
8140 	int verbose = 1;
8141 
8142 	/* type -p ... ? (we don't bother checking for 'p') */
8143 	if (argv[1] && argv[1][0] == '-') {
8144 		i++;
8145 		verbose = 0;
8146 	}
8147 	while (argv[i]) {
8148 		err |= describe_command(argv[i++], NULL, verbose);
8149 	}
8150 	return err;
8151 }
8152 
8153 #if ENABLE_ASH_CMDCMD
8154 /* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8155 static char **
parse_command_args(char ** argv,const char ** path)8156 parse_command_args(char **argv, const char **path)
8157 {
8158 	char *cp, c;
8159 
8160 	for (;;) {
8161 		cp = *++argv;
8162 		if (!cp)
8163 			return NULL;
8164 		if (*cp++ != '-')
8165 			break;
8166 		c = *cp++;
8167 		if (!c)
8168 			break;
8169 		if (c == '-' && !*cp) {
8170 			if (!*++argv)
8171 				return NULL;
8172 			break;
8173 		}
8174 		do {
8175 			switch (c) {
8176 			case 'p':
8177 				*path = bb_default_path;
8178 				break;
8179 			default:
8180 				/* run 'typecmd' for other options */
8181 				return NULL;
8182 			}
8183 			c = *cp++;
8184 		} while (c);
8185 	}
8186 	return argv;
8187 }
8188 
8189 static int FAST_FUNC
commandcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)8190 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8191 {
8192 	char *cmd;
8193 	int c;
8194 	enum {
8195 		VERIFY_BRIEF = 1,
8196 		VERIFY_VERBOSE = 2,
8197 	} verify = 0;
8198 	const char *path = NULL;
8199 
8200 	/* "command [-p] PROG ARGS" (that is, without -V or -v)
8201 	 * never reaches this function.
8202 	 */
8203 
8204 	while ((c = nextopt("pvV")) != '\0')
8205 		if (c == 'V')
8206 			verify |= VERIFY_VERBOSE;
8207 		else if (c == 'v')
8208 			/*verify |= VERIFY_BRIEF*/;
8209 #if DEBUG
8210 		else if (c != 'p')
8211 			abort();
8212 #endif
8213 		else
8214 			path = bb_default_path;
8215 
8216 	/* Mimic bash: just "command -v" doesn't complain, it's a nop */
8217 	cmd = *argptr;
8218 	if (/*verify && */ cmd)
8219 		return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8220 
8221 	return 0;
8222 }
8223 #endif
8224 
8225 
8226 /*static int funcblocksize;     // size of structures in function */
8227 /*static int funcstringsize;    // size of strings in node */
8228 static void *funcblock;         /* block to allocate function from */
8229 static char *funcstring_end;    /* end of block to allocate strings from */
8230 
8231 /* flags in argument to evaltree */
8232 #define EV_EXIT    01           /* exit after evaluating tree */
8233 #define EV_TESTED  02           /* exit status is checked; ignore -e flag */
8234 
8235 static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8236 	[NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
8237 	[NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
8238 	[NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
8239 	[NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8240 	[NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8241 	[NAND     ] = SHELL_ALIGN(sizeof(struct nbinary)),
8242 	[NOR      ] = SHELL_ALIGN(sizeof(struct nbinary)),
8243 	[NSEMI    ] = SHELL_ALIGN(sizeof(struct nbinary)),
8244 	[NIF      ] = SHELL_ALIGN(sizeof(struct nif)),
8245 	[NWHILE   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8246 	[NUNTIL   ] = SHELL_ALIGN(sizeof(struct nbinary)),
8247 	[NFOR     ] = SHELL_ALIGN(sizeof(struct nfor)),
8248 	[NCASE    ] = SHELL_ALIGN(sizeof(struct ncase)),
8249 	[NCLIST   ] = SHELL_ALIGN(sizeof(struct nclist)),
8250 	[NDEFUN   ] = SHELL_ALIGN(sizeof(struct narg)),
8251 	[NARG     ] = SHELL_ALIGN(sizeof(struct narg)),
8252 	[NTO      ] = SHELL_ALIGN(sizeof(struct nfile)),
8253 #if ENABLE_ASH_BASH_COMPAT
8254 	[NTO2     ] = SHELL_ALIGN(sizeof(struct nfile)),
8255 #endif
8256 	[NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8257 	[NFROM    ] = SHELL_ALIGN(sizeof(struct nfile)),
8258 	[NFROMTO  ] = SHELL_ALIGN(sizeof(struct nfile)),
8259 	[NAPPEND  ] = SHELL_ALIGN(sizeof(struct nfile)),
8260 	[NTOFD    ] = SHELL_ALIGN(sizeof(struct ndup)),
8261 	[NFROMFD  ] = SHELL_ALIGN(sizeof(struct ndup)),
8262 	[NHERE    ] = SHELL_ALIGN(sizeof(struct nhere)),
8263 	[NXHERE   ] = SHELL_ALIGN(sizeof(struct nhere)),
8264 	[NNOT     ] = SHELL_ALIGN(sizeof(struct nnot)),
8265 };
8266 
8267 static int calcsize(int funcblocksize, union node *n);
8268 
8269 static int
sizenodelist(int funcblocksize,struct nodelist * lp)8270 sizenodelist(int funcblocksize, struct nodelist *lp)
8271 {
8272 	while (lp) {
8273 		funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8274 		funcblocksize = calcsize(funcblocksize, lp->n);
8275 		lp = lp->next;
8276 	}
8277 	return funcblocksize;
8278 }
8279 
8280 static int
calcsize(int funcblocksize,union node * n)8281 calcsize(int funcblocksize, union node *n)
8282 {
8283 	if (n == NULL)
8284 		return funcblocksize;
8285 	funcblocksize += nodesize[n->type];
8286 	switch (n->type) {
8287 	case NCMD:
8288 		funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8289 		funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8290 		funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8291 		break;
8292 	case NPIPE:
8293 		funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8294 		break;
8295 	case NREDIR:
8296 	case NBACKGND:
8297 	case NSUBSHELL:
8298 		funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8299 		funcblocksize = calcsize(funcblocksize, n->nredir.n);
8300 		break;
8301 	case NAND:
8302 	case NOR:
8303 	case NSEMI:
8304 	case NWHILE:
8305 	case NUNTIL:
8306 		funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8307 		funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
8308 		break;
8309 	case NIF:
8310 		funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8311 		funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8312 		funcblocksize = calcsize(funcblocksize, n->nif.test);
8313 		break;
8314 	case NFOR:
8315 		funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
8316 		funcblocksize = calcsize(funcblocksize, n->nfor.body);
8317 		funcblocksize = calcsize(funcblocksize, n->nfor.args);
8318 		break;
8319 	case NCASE:
8320 		funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8321 		funcblocksize = calcsize(funcblocksize, n->ncase.expr);
8322 		break;
8323 	case NCLIST:
8324 		funcblocksize = calcsize(funcblocksize, n->nclist.body);
8325 		funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8326 		funcblocksize = calcsize(funcblocksize, n->nclist.next);
8327 		break;
8328 	case NDEFUN:
8329 	case NARG:
8330 		funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
8331 		funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
8332 		funcblocksize = calcsize(funcblocksize, n->narg.next);
8333 		break;
8334 	case NTO:
8335 #if ENABLE_ASH_BASH_COMPAT
8336 	case NTO2:
8337 #endif
8338 	case NCLOBBER:
8339 	case NFROM:
8340 	case NFROMTO:
8341 	case NAPPEND:
8342 		funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8343 		funcblocksize = calcsize(funcblocksize, n->nfile.next);
8344 		break;
8345 	case NTOFD:
8346 	case NFROMFD:
8347 		funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8348 		funcblocksize = calcsize(funcblocksize, n->ndup.next);
8349 	break;
8350 	case NHERE:
8351 	case NXHERE:
8352 		funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8353 		funcblocksize = calcsize(funcblocksize, n->nhere.next);
8354 		break;
8355 	case NNOT:
8356 		funcblocksize = calcsize(funcblocksize, n->nnot.com);
8357 		break;
8358 	};
8359 	return funcblocksize;
8360 }
8361 
8362 static char *
nodeckstrdup(char * s)8363 nodeckstrdup(char *s)
8364 {
8365 	funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
8366 	return strcpy(funcstring_end, s);
8367 }
8368 
8369 static union node *copynode(union node *);
8370 
8371 static struct nodelist *
copynodelist(struct nodelist * lp)8372 copynodelist(struct nodelist *lp)
8373 {
8374 	struct nodelist *start;
8375 	struct nodelist **lpp;
8376 
8377 	lpp = &start;
8378 	while (lp) {
8379 		*lpp = funcblock;
8380 		funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8381 		(*lpp)->n = copynode(lp->n);
8382 		lp = lp->next;
8383 		lpp = &(*lpp)->next;
8384 	}
8385 	*lpp = NULL;
8386 	return start;
8387 }
8388 
8389 static union node *
copynode(union node * n)8390 copynode(union node *n)
8391 {
8392 	union node *new;
8393 
8394 	if (n == NULL)
8395 		return NULL;
8396 	new = funcblock;
8397 	funcblock = (char *) funcblock + nodesize[n->type];
8398 
8399 	switch (n->type) {
8400 	case NCMD:
8401 		new->ncmd.redirect = copynode(n->ncmd.redirect);
8402 		new->ncmd.args = copynode(n->ncmd.args);
8403 		new->ncmd.assign = copynode(n->ncmd.assign);
8404 		break;
8405 	case NPIPE:
8406 		new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8407 		new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8408 		break;
8409 	case NREDIR:
8410 	case NBACKGND:
8411 	case NSUBSHELL:
8412 		new->nredir.redirect = copynode(n->nredir.redirect);
8413 		new->nredir.n = copynode(n->nredir.n);
8414 		break;
8415 	case NAND:
8416 	case NOR:
8417 	case NSEMI:
8418 	case NWHILE:
8419 	case NUNTIL:
8420 		new->nbinary.ch2 = copynode(n->nbinary.ch2);
8421 		new->nbinary.ch1 = copynode(n->nbinary.ch1);
8422 		break;
8423 	case NIF:
8424 		new->nif.elsepart = copynode(n->nif.elsepart);
8425 		new->nif.ifpart = copynode(n->nif.ifpart);
8426 		new->nif.test = copynode(n->nif.test);
8427 		break;
8428 	case NFOR:
8429 		new->nfor.var = nodeckstrdup(n->nfor.var);
8430 		new->nfor.body = copynode(n->nfor.body);
8431 		new->nfor.args = copynode(n->nfor.args);
8432 		break;
8433 	case NCASE:
8434 		new->ncase.cases = copynode(n->ncase.cases);
8435 		new->ncase.expr = copynode(n->ncase.expr);
8436 		break;
8437 	case NCLIST:
8438 		new->nclist.body = copynode(n->nclist.body);
8439 		new->nclist.pattern = copynode(n->nclist.pattern);
8440 		new->nclist.next = copynode(n->nclist.next);
8441 		break;
8442 	case NDEFUN:
8443 	case NARG:
8444 		new->narg.backquote = copynodelist(n->narg.backquote);
8445 		new->narg.text = nodeckstrdup(n->narg.text);
8446 		new->narg.next = copynode(n->narg.next);
8447 		break;
8448 	case NTO:
8449 #if ENABLE_ASH_BASH_COMPAT
8450 	case NTO2:
8451 #endif
8452 	case NCLOBBER:
8453 	case NFROM:
8454 	case NFROMTO:
8455 	case NAPPEND:
8456 		new->nfile.fname = copynode(n->nfile.fname);
8457 		new->nfile.fd = n->nfile.fd;
8458 		new->nfile.next = copynode(n->nfile.next);
8459 		break;
8460 	case NTOFD:
8461 	case NFROMFD:
8462 		new->ndup.vname = copynode(n->ndup.vname);
8463 		new->ndup.dupfd = n->ndup.dupfd;
8464 		new->ndup.fd = n->ndup.fd;
8465 		new->ndup.next = copynode(n->ndup.next);
8466 		break;
8467 	case NHERE:
8468 	case NXHERE:
8469 		new->nhere.doc = copynode(n->nhere.doc);
8470 		new->nhere.fd = n->nhere.fd;
8471 		new->nhere.next = copynode(n->nhere.next);
8472 		break;
8473 	case NNOT:
8474 		new->nnot.com = copynode(n->nnot.com);
8475 		break;
8476 	};
8477 	new->type = n->type;
8478 	return new;
8479 }
8480 
8481 /*
8482  * Make a copy of a parse tree.
8483  */
8484 static struct funcnode *
copyfunc(union node * n)8485 copyfunc(union node *n)
8486 {
8487 	struct funcnode *f;
8488 	size_t blocksize;
8489 
8490 	/*funcstringsize = 0;*/
8491 	blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8492 	f = ckzalloc(blocksize /* + funcstringsize */);
8493 	funcblock = (char *) f + offsetof(struct funcnode, n);
8494 	funcstring_end = (char *) f + blocksize;
8495 	copynode(n);
8496 	/* f->count = 0; - ckzalloc did it */
8497 	return f;
8498 }
8499 
8500 /*
8501  * Define a shell function.
8502  */
8503 static void
defun(union node * func)8504 defun(union node *func)
8505 {
8506 	struct cmdentry entry;
8507 
8508 	INT_OFF;
8509 	entry.cmdtype = CMDFUNCTION;
8510 	entry.u.func = copyfunc(func);
8511 	addcmdentry(func->narg.text, &entry);
8512 	INT_ON;
8513 }
8514 
8515 /* Reasons for skipping commands (see comment on breakcmd routine) */
8516 #define SKIPBREAK      (1 << 0)
8517 #define SKIPCONT       (1 << 1)
8518 #define SKIPFUNC       (1 << 2)
8519 static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
8520 static int skipcount;           /* number of levels to skip */
8521 static int funcnest;            /* depth of function calls */
8522 static int loopnest;            /* current loop nesting level */
8523 
8524 /* Forward decl way out to parsing code - dotrap needs it */
8525 static int evalstring(char *s, int flags);
8526 
8527 /* Called to execute a trap.
8528  * Single callsite - at the end of evaltree().
8529  * If we return non-zero, evaltree raises EXEXIT exception.
8530  *
8531  * Perhaps we should avoid entering new trap handlers
8532  * while we are executing a trap handler. [is it a TODO?]
8533  */
8534 static void
dotrap(void)8535 dotrap(void)
8536 {
8537 	uint8_t *g;
8538 	int sig;
8539 	uint8_t last_status;
8540 
8541 	if (!pending_sig)
8542 		return;
8543 
8544 	last_status = exitstatus;
8545 	pending_sig = 0;
8546 	barrier();
8547 
8548 	TRACE(("dotrap entered\n"));
8549 	for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8550 		char *p;
8551 
8552 		if (!*g)
8553 			continue;
8554 
8555 		if (evalskip) {
8556 			pending_sig = sig;
8557 			break;
8558 		}
8559 
8560 		p = trap[sig];
8561 		/* non-trapped SIGINT is handled separately by raise_interrupt,
8562 		 * don't upset it by resetting gotsig[SIGINT-1] */
8563 		if (sig == SIGINT && !p)
8564 			continue;
8565 
8566 		TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
8567 		*g = 0;
8568 		if (!p)
8569 			continue;
8570 		evalstring(p, 0);
8571 	}
8572 	exitstatus = last_status;
8573 	TRACE(("dotrap returns\n"));
8574 }
8575 
8576 /* forward declarations - evaluation is fairly recursive business... */
8577 static int evalloop(union node *, int);
8578 static int evalfor(union node *, int);
8579 static int evalcase(union node *, int);
8580 static int evalsubshell(union node *, int);
8581 static void expredir(union node *);
8582 static int evalpipe(union node *, int);
8583 static int evalcommand(union node *, int);
8584 static int evalbltin(const struct builtincmd *, int, char **, int);
8585 static void prehash(union node *);
8586 
8587 /*
8588  * Evaluate a parse tree.  The value is left in the global variable
8589  * exitstatus.
8590  */
8591 static int
evaltree(union node * n,int flags)8592 evaltree(union node *n, int flags)
8593 {
8594 	int checkexit = 0;
8595 	int (*evalfn)(union node *, int);
8596 	int status = 0;
8597 
8598 	if (n == NULL) {
8599 		TRACE(("evaltree(NULL) called\n"));
8600 		goto out;
8601 	}
8602 	TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8603 
8604 	dotrap();
8605 
8606 	switch (n->type) {
8607 	default:
8608 #if DEBUG
8609 		out1fmt("Node type = %d\n", n->type);
8610 		fflush_all();
8611 		break;
8612 #endif
8613 	case NNOT:
8614 		status = !evaltree(n->nnot.com, EV_TESTED);
8615 		goto setstatus;
8616 	case NREDIR:
8617 		expredir(n->nredir.redirect);
8618 		status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8619 		if (!status) {
8620 			status = evaltree(n->nredir.n, flags & EV_TESTED);
8621 		}
8622 		if (n->nredir.redirect)
8623 			popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8624 		goto setstatus;
8625 	case NCMD:
8626 		evalfn = evalcommand;
8627  checkexit:
8628 		if (eflag && !(flags & EV_TESTED))
8629 			checkexit = ~0;
8630 		goto calleval;
8631 	case NFOR:
8632 		evalfn = evalfor;
8633 		goto calleval;
8634 	case NWHILE:
8635 	case NUNTIL:
8636 		evalfn = evalloop;
8637 		goto calleval;
8638 	case NSUBSHELL:
8639 	case NBACKGND:
8640 		evalfn = evalsubshell;
8641 		goto checkexit;
8642 	case NPIPE:
8643 		evalfn = evalpipe;
8644 		goto checkexit;
8645 	case NCASE:
8646 		evalfn = evalcase;
8647 		goto calleval;
8648 	case NAND:
8649 	case NOR:
8650 	case NSEMI: {
8651 
8652 #if NAND + 1 != NOR
8653 #error NAND + 1 != NOR
8654 #endif
8655 #if NOR + 1 != NSEMI
8656 #error NOR + 1 != NSEMI
8657 #endif
8658 		unsigned is_or = n->type - NAND;
8659 		status = evaltree(
8660 			n->nbinary.ch1,
8661 			(flags | ((is_or >> 1) - 1)) & EV_TESTED
8662 		);
8663 		if ((!status) == is_or || evalskip)
8664 			break;
8665 		n = n->nbinary.ch2;
8666  evaln:
8667 		evalfn = evaltree;
8668  calleval:
8669 		status = evalfn(n, flags);
8670 		goto setstatus;
8671 	}
8672 	case NIF:
8673 		status = evaltree(n->nif.test, EV_TESTED);
8674 		if (evalskip)
8675 			break;
8676 		if (!status) {
8677 			n = n->nif.ifpart;
8678 			goto evaln;
8679 		}
8680 		if (n->nif.elsepart) {
8681 			n = n->nif.elsepart;
8682 			goto evaln;
8683 		}
8684 		status = 0;
8685 		goto setstatus;
8686 	case NDEFUN:
8687 		defun(n);
8688 		/* Not necessary. To test it:
8689 		 * "false; f() { qwerty; }; echo $?" should print 0.
8690 		 */
8691 		/* status = 0; */
8692  setstatus:
8693 		exitstatus = status;
8694 		break;
8695 	}
8696  out:
8697 	/* Order of checks below is important:
8698 	 * signal handlers trigger before exit caused by "set -e".
8699 	 */
8700 	dotrap();
8701 
8702 	if (checkexit & status)
8703 		raise_exception(EXEXIT);
8704 	if (flags & EV_EXIT)
8705 		raise_exception(EXEXIT);
8706 
8707 	TRACE(("leaving evaltree (no interrupts)\n"));
8708 	return exitstatus;
8709 }
8710 
8711 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8712 static
8713 #endif
8714 int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8715 
8716 static int
skiploop(void)8717 skiploop(void)
8718 {
8719 	int skip = evalskip;
8720 
8721 	switch (skip) {
8722 	case 0:
8723 		break;
8724 	case SKIPBREAK:
8725 	case SKIPCONT:
8726 		if (--skipcount <= 0) {
8727 			evalskip = 0;
8728 			break;
8729 		}
8730 		skip = SKIPBREAK;
8731 		break;
8732 	}
8733 	return skip;
8734 }
8735 
8736 static int
evalloop(union node * n,int flags)8737 evalloop(union node *n, int flags)
8738 {
8739 	int skip;
8740 	int status;
8741 
8742 	loopnest++;
8743 	status = 0;
8744 	flags &= EV_TESTED;
8745 	do {
8746 		int i;
8747 
8748 		i = evaltree(n->nbinary.ch1, EV_TESTED);
8749 		skip = skiploop();
8750 		if (skip == SKIPFUNC)
8751 			status = i;
8752 		if (skip)
8753 			continue;
8754 		if (n->type != NWHILE)
8755 			i = !i;
8756 		if (i != 0)
8757 			break;
8758 		status = evaltree(n->nbinary.ch2, flags);
8759 		skip = skiploop();
8760 	} while (!(skip & ~SKIPCONT));
8761 	loopnest--;
8762 
8763 	return status;
8764 }
8765 
8766 static int
evalfor(union node * n,int flags)8767 evalfor(union node *n, int flags)
8768 {
8769 	struct arglist arglist;
8770 	union node *argp;
8771 	struct strlist *sp;
8772 	struct stackmark smark;
8773 	int status = 0;
8774 
8775 	setstackmark(&smark);
8776 	arglist.list = NULL;
8777 	arglist.lastp = &arglist.list;
8778 	for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8779 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8780 	}
8781 	*arglist.lastp = NULL;
8782 
8783 	loopnest++;
8784 	flags &= EV_TESTED;
8785 	for (sp = arglist.list; sp; sp = sp->next) {
8786 		setvar0(n->nfor.var, sp->text);
8787 		status = evaltree(n->nfor.body, flags);
8788 		if (skiploop() & ~SKIPCONT)
8789 			break;
8790 	}
8791 	loopnest--;
8792 	popstackmark(&smark);
8793 
8794 	return status;
8795 }
8796 
8797 static int
evalcase(union node * n,int flags)8798 evalcase(union node *n, int flags)
8799 {
8800 	union node *cp;
8801 	union node *patp;
8802 	struct arglist arglist;
8803 	struct stackmark smark;
8804 	int status = 0;
8805 
8806 	setstackmark(&smark);
8807 	arglist.list = NULL;
8808 	arglist.lastp = &arglist.list;
8809 	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8810 	for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8811 		for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8812 			if (casematch(patp, arglist.list->text)) {
8813 				/* Ensure body is non-empty as otherwise
8814 				 * EV_EXIT may prevent us from setting the
8815 				 * exit status.
8816 				 */
8817 				if (evalskip == 0 && cp->nclist.body) {
8818 					status = evaltree(cp->nclist.body, flags);
8819 				}
8820 				goto out;
8821 			}
8822 		}
8823 	}
8824  out:
8825 	popstackmark(&smark);
8826 
8827 	return status;
8828 }
8829 
8830 /*
8831  * Kick off a subshell to evaluate a tree.
8832  */
8833 static int
evalsubshell(union node * n,int flags)8834 evalsubshell(union node *n, int flags)
8835 {
8836 	struct job *jp;
8837 	int backgnd = (n->type == NBACKGND);
8838 	int status;
8839 
8840 	expredir(n->nredir.redirect);
8841 	if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
8842 		goto nofork;
8843 	INT_OFF;
8844 	jp = makejob(/*n,*/ 1);
8845 	if (forkshell(jp, n, backgnd) == 0) {
8846 		/* child */
8847 		INT_ON;
8848 		flags |= EV_EXIT;
8849 		if (backgnd)
8850 			flags &= ~EV_TESTED;
8851  nofork:
8852 		redirect(n->nredir.redirect, 0);
8853 		evaltreenr(n->nredir.n, flags);
8854 		/* never returns */
8855 	}
8856 	/* parent */
8857 	status = 0;
8858 	if (!backgnd)
8859 		status = waitforjob(jp);
8860 	INT_ON;
8861 	return status;
8862 }
8863 
8864 /*
8865  * Compute the names of the files in a redirection list.
8866  */
8867 static void fixredir(union node *, const char *, int);
8868 static void
expredir(union node * n)8869 expredir(union node *n)
8870 {
8871 	union node *redir;
8872 
8873 	for (redir = n; redir; redir = redir->nfile.next) {
8874 		struct arglist fn;
8875 
8876 		fn.list = NULL;
8877 		fn.lastp = &fn.list;
8878 		switch (redir->type) {
8879 		case NFROMTO:
8880 		case NFROM:
8881 		case NTO:
8882 #if ENABLE_ASH_BASH_COMPAT
8883 		case NTO2:
8884 #endif
8885 		case NCLOBBER:
8886 		case NAPPEND:
8887 			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8888 			TRACE(("expredir expanded to '%s'\n", fn.list->text));
8889 #if ENABLE_ASH_BASH_COMPAT
8890  store_expfname:
8891 #endif
8892 #if 0
8893 // By the design of stack allocator, the loop of this kind:
8894 //	while true; do while true; do break; done </dev/null; done
8895 // will look like a memory leak: ash plans to free expfname's
8896 // of "/dev/null" as soon as it finishes running the loop
8897 // (in this case, never).
8898 // This "fix" is wrong:
8899 			if (redir->nfile.expfname)
8900 				stunalloc(redir->nfile.expfname);
8901 // It results in corrupted state of stacked allocations.
8902 #endif
8903 			redir->nfile.expfname = fn.list->text;
8904 			break;
8905 		case NFROMFD:
8906 		case NTOFD: /* >& */
8907 			if (redir->ndup.vname) {
8908 				expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8909 				if (fn.list == NULL)
8910 					ash_msg_and_raise_error("redir error");
8911 #if ENABLE_ASH_BASH_COMPAT
8912 //FIXME: we used expandarg with different args!
8913 				if (!isdigit_str9(fn.list->text)) {
8914 					/* >&file, not >&fd */
8915 					if (redir->nfile.fd != 1) /* 123>&file - BAD */
8916 						ash_msg_and_raise_error("redir error");
8917 					redir->type = NTO2;
8918 					goto store_expfname;
8919 				}
8920 #endif
8921 				fixredir(redir, fn.list->text, 1);
8922 			}
8923 			break;
8924 		}
8925 	}
8926 }
8927 
8928 /*
8929  * Evaluate a pipeline.  All the processes in the pipeline are children
8930  * of the process creating the pipeline.  (This differs from some versions
8931  * of the shell, which make the last process in a pipeline the parent
8932  * of all the rest.)
8933  */
8934 static int
evalpipe(union node * n,int flags)8935 evalpipe(union node *n, int flags)
8936 {
8937 	struct job *jp;
8938 	struct nodelist *lp;
8939 	int pipelen;
8940 	int prevfd;
8941 	int pip[2];
8942 	int status = 0;
8943 
8944 	TRACE(("evalpipe(0x%lx) called\n", (long)n));
8945 	pipelen = 0;
8946 	for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8947 		pipelen++;
8948 	flags |= EV_EXIT;
8949 	INT_OFF;
8950 	jp = makejob(/*n,*/ pipelen);
8951 	prevfd = -1;
8952 	for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8953 		prehash(lp->n);
8954 		pip[1] = -1;
8955 		if (lp->next) {
8956 			if (pipe(pip) < 0) {
8957 				close(prevfd);
8958 				ash_msg_and_raise_error("pipe call failed");
8959 			}
8960 		}
8961 		if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8962 			/* child */
8963 			INT_ON;
8964 			if (pip[1] >= 0) {
8965 				close(pip[0]);
8966 			}
8967 			if (prevfd > 0) {
8968 				dup2(prevfd, 0);
8969 				close(prevfd);
8970 			}
8971 			if (pip[1] > 1) {
8972 				dup2(pip[1], 1);
8973 				close(pip[1]);
8974 			}
8975 			evaltreenr(lp->n, flags);
8976 			/* never returns */
8977 		}
8978 		/* parent */
8979 		if (prevfd >= 0)
8980 			close(prevfd);
8981 		prevfd = pip[0];
8982 		/* Don't want to trigger debugging */
8983 		if (pip[1] != -1)
8984 			close(pip[1]);
8985 	}
8986 	if (n->npipe.pipe_backgnd == 0) {
8987 		status = waitforjob(jp);
8988 		TRACE(("evalpipe:  job done exit status %d\n", status));
8989 	}
8990 	INT_ON;
8991 
8992 	return status;
8993 }
8994 
8995 /*
8996  * Controls whether the shell is interactive or not.
8997  */
8998 static void
setinteractive(int on)8999 setinteractive(int on)
9000 {
9001 	static smallint is_interactive;
9002 
9003 	if (++on == is_interactive)
9004 		return;
9005 	is_interactive = on;
9006 	setsignal(SIGINT);
9007 	setsignal(SIGQUIT);
9008 	setsignal(SIGTERM);
9009 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
9010 	if (is_interactive > 1) {
9011 		/* Looks like they want an interactive shell */
9012 		static smallint did_banner;
9013 
9014 		if (!did_banner) {
9015 			/* note: ash and hush share this string */
9016 			out1fmt("\n\n%s %s\n"
9017 				IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9018 				"\n",
9019 				bb_banner,
9020 				"built-in shell (ash)"
9021 			);
9022 			did_banner = 1;
9023 		}
9024 	}
9025 #endif
9026 }
9027 
9028 static void
optschanged(void)9029 optschanged(void)
9030 {
9031 #if DEBUG
9032 	opentrace();
9033 #endif
9034 	setinteractive(iflag);
9035 	setjobctl(mflag);
9036 #if ENABLE_FEATURE_EDITING_VI
9037 	if (viflag)
9038 		line_input_state->flags |= VI_MODE;
9039 	else
9040 		line_input_state->flags &= ~VI_MODE;
9041 #else
9042 	viflag = 0; /* forcibly keep the option off */
9043 #endif
9044 }
9045 
9046 static struct localvar *localvars;
9047 
9048 /*
9049  * Called after a function returns.
9050  * Interrupts must be off.
9051  */
9052 static void
poplocalvars(void)9053 poplocalvars(void)
9054 {
9055 	struct localvar *lvp;
9056 	struct var *vp;
9057 
9058 	while ((lvp = localvars) != NULL) {
9059 		localvars = lvp->next;
9060 		vp = lvp->vp;
9061 		TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9062 		if (vp == NULL) {       /* $- saved */
9063 			memcpy(optlist, lvp->text, sizeof(optlist));
9064 			free((char*)lvp->text);
9065 			optschanged();
9066 		} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
9067 			unsetvar(vp->var_text);
9068 		} else {
9069 			if (vp->var_func)
9070 				vp->var_func(var_end(lvp->text));
9071 			if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9072 				free((char*)vp->var_text);
9073 			vp->flags = lvp->flags;
9074 			vp->var_text = lvp->text;
9075 		}
9076 		free(lvp);
9077 	}
9078 }
9079 
9080 static int
evalfun(struct funcnode * func,int argc,char ** argv,int flags)9081 evalfun(struct funcnode *func, int argc, char **argv, int flags)
9082 {
9083 	volatile struct shparam saveparam;
9084 	struct localvar *volatile savelocalvars;
9085 	struct jmploc *volatile savehandler;
9086 	struct jmploc jmploc;
9087 	int e;
9088 
9089 	saveparam = shellparam;
9090 	savelocalvars = localvars;
9091 	savehandler = exception_handler;
9092 	e = setjmp(jmploc.loc);
9093 	if (e) {
9094 		goto funcdone;
9095 	}
9096 	INT_OFF;
9097 	exception_handler = &jmploc;
9098 	localvars = NULL;
9099 	shellparam.malloced = 0;
9100 	func->count++;
9101 	funcnest++;
9102 	INT_ON;
9103 	shellparam.nparam = argc - 1;
9104 	shellparam.p = argv + 1;
9105 #if ENABLE_ASH_GETOPTS
9106 	shellparam.optind = 1;
9107 	shellparam.optoff = -1;
9108 #endif
9109 	evaltree(func->n.narg.next, flags & EV_TESTED);
9110  funcdone:
9111 	INT_OFF;
9112 	funcnest--;
9113 	freefunc(func);
9114 	poplocalvars();
9115 	localvars = savelocalvars;
9116 	freeparam(&shellparam);
9117 	shellparam = saveparam;
9118 	exception_handler = savehandler;
9119 	INT_ON;
9120 	evalskip &= ~SKIPFUNC;
9121 	return e;
9122 }
9123 
9124 /*
9125  * Make a variable a local variable.  When a variable is made local, it's
9126  * value and flags are saved in a localvar structure.  The saved values
9127  * will be restored when the shell function returns.  We handle the name
9128  * "-" as a special case: it makes changes to "set +-options" local
9129  * (options will be restored on return from the function).
9130  */
9131 static void
mklocal(char * name)9132 mklocal(char *name)
9133 {
9134 	struct localvar *lvp;
9135 	struct var **vpp;
9136 	struct var *vp;
9137 	char *eq = strchr(name, '=');
9138 
9139 	INT_OFF;
9140 	/* Cater for duplicate "local". Examples:
9141 	 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9142 	 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9143 	 */
9144 	lvp = localvars;
9145 	while (lvp) {
9146 		if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9147 			if (eq)
9148 				setvareq(name, 0);
9149 			/* else:
9150 			 * it's a duplicate "local VAR" declaration, do nothing
9151 			 */
9152 			goto ret;
9153 		}
9154 		lvp = lvp->next;
9155 	}
9156 
9157 	lvp = ckzalloc(sizeof(*lvp));
9158 	if (LONE_DASH(name)) {
9159 		char *p;
9160 		p = ckmalloc(sizeof(optlist));
9161 		lvp->text = memcpy(p, optlist, sizeof(optlist));
9162 		vp = NULL;
9163 	} else {
9164 		vpp = hashvar(name);
9165 		vp = *findvar(vpp, name);
9166 		if (vp == NULL) {
9167 			/* variable did not exist yet */
9168 			if (eq)
9169 				setvareq(name, VSTRFIXED);
9170 			else
9171 				setvar(name, NULL, VSTRFIXED);
9172 			vp = *vpp;      /* the new variable */
9173 			lvp->flags = VUNSET;
9174 		} else {
9175 			lvp->text = vp->var_text;
9176 			lvp->flags = vp->flags;
9177 			/* make sure neither "struct var" nor string gets freed
9178 			 * during (un)setting:
9179 			 */
9180 			vp->flags |= VSTRFIXED|VTEXTFIXED;
9181 			if (eq)
9182 				setvareq(name, 0);
9183 			else
9184 				/* "local VAR" unsets VAR: */
9185 				setvar0(name, NULL);
9186 		}
9187 	}
9188 	lvp->vp = vp;
9189 	lvp->next = localvars;
9190 	localvars = lvp;
9191  ret:
9192 	INT_ON;
9193 }
9194 
9195 /*
9196  * The "local" command.
9197  */
9198 static int FAST_FUNC
localcmd(int argc UNUSED_PARAM,char ** argv)9199 localcmd(int argc UNUSED_PARAM, char **argv)
9200 {
9201 	char *name;
9202 
9203 	if (!funcnest)
9204 		ash_msg_and_raise_error("not in a function");
9205 
9206 	argv = argptr;
9207 	while ((name = *argv++) != NULL) {
9208 		mklocal(name);
9209 	}
9210 	return 0;
9211 }
9212 
9213 static int FAST_FUNC
falsecmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)9214 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9215 {
9216 	return 1;
9217 }
9218 
9219 static int FAST_FUNC
truecmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)9220 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9221 {
9222 	return 0;
9223 }
9224 
9225 static int FAST_FUNC
execcmd(int argc UNUSED_PARAM,char ** argv)9226 execcmd(int argc UNUSED_PARAM, char **argv)
9227 {
9228 	if (argv[1]) {
9229 		iflag = 0;              /* exit on error */
9230 		mflag = 0;
9231 		optschanged();
9232 		/* We should set up signals for "exec CMD"
9233 		 * the same way as for "CMD" without "exec".
9234 		 * But optschanged->setinteractive->setsignal
9235 		 * still thought we are a root shell. Therefore, for example,
9236 		 * SIGQUIT is still set to IGN. Fix it:
9237 		 */
9238 		shlvl++;
9239 		setsignal(SIGQUIT);
9240 		/*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9241 		/*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9242 		/*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9243 
9244 		shellexec(argv + 1, pathval(), 0);
9245 		/* NOTREACHED */
9246 	}
9247 	return 0;
9248 }
9249 
9250 /*
9251  * The return command.
9252  */
9253 static int FAST_FUNC
returncmd(int argc UNUSED_PARAM,char ** argv)9254 returncmd(int argc UNUSED_PARAM, char **argv)
9255 {
9256 	/*
9257 	 * If called outside a function, do what ksh does;
9258 	 * skip the rest of the file.
9259 	 */
9260 	evalskip = SKIPFUNC;
9261 	return argv[1] ? number(argv[1]) : exitstatus;
9262 }
9263 
9264 /* Forward declarations for builtintab[] */
9265 static int breakcmd(int, char **) FAST_FUNC;
9266 static int dotcmd(int, char **) FAST_FUNC;
9267 static int evalcmd(int, char **, int) FAST_FUNC;
9268 static int exitcmd(int, char **) FAST_FUNC;
9269 static int exportcmd(int, char **) FAST_FUNC;
9270 #if ENABLE_ASH_GETOPTS
9271 static int getoptscmd(int, char **) FAST_FUNC;
9272 #endif
9273 #if ENABLE_ASH_HELP
9274 static int helpcmd(int, char **) FAST_FUNC;
9275 #endif
9276 #if MAX_HISTORY
9277 static int historycmd(int, char **) FAST_FUNC;
9278 #endif
9279 #if ENABLE_FEATURE_SH_MATH
9280 static int letcmd(int, char **) FAST_FUNC;
9281 #endif
9282 static int readcmd(int, char **) FAST_FUNC;
9283 static int setcmd(int, char **) FAST_FUNC;
9284 static int shiftcmd(int, char **) FAST_FUNC;
9285 static int timescmd(int, char **) FAST_FUNC;
9286 static int trapcmd(int, char **) FAST_FUNC;
9287 static int umaskcmd(int, char **) FAST_FUNC;
9288 static int unsetcmd(int, char **) FAST_FUNC;
9289 static int ulimitcmd(int, char **) FAST_FUNC;
9290 
9291 #define BUILTIN_NOSPEC          "0"
9292 #define BUILTIN_SPECIAL         "1"
9293 #define BUILTIN_REGULAR         "2"
9294 #define BUILTIN_SPEC_REG        "3"
9295 #define BUILTIN_ASSIGN          "4"
9296 #define BUILTIN_SPEC_ASSG       "5"
9297 #define BUILTIN_REG_ASSG        "6"
9298 #define BUILTIN_SPEC_REG_ASSG   "7"
9299 
9300 /* Stubs for calling non-FAST_FUNC's */
9301 #if ENABLE_ASH_BUILTIN_ECHO
echocmd(int argc,char ** argv)9302 static int FAST_FUNC echocmd(int argc, char **argv)   { return echo_main(argc, argv); }
9303 #endif
9304 #if ENABLE_ASH_BUILTIN_PRINTF
printfcmd(int argc,char ** argv)9305 static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
9306 #endif
9307 #if ENABLE_ASH_BUILTIN_TEST
testcmd(int argc,char ** argv)9308 static int FAST_FUNC testcmd(int argc, char **argv)   { return test_main(argc, argv); }
9309 #endif
9310 
9311 /* Keep these in proper order since it is searched via bsearch() */
9312 static const struct builtincmd builtintab[] = {
9313 	{ BUILTIN_SPEC_REG      "."       , dotcmd     },
9314 	{ BUILTIN_SPEC_REG      ":"       , truecmd    },
9315 #if ENABLE_ASH_BUILTIN_TEST
9316 	{ BUILTIN_REGULAR       "["       , testcmd    },
9317 # if ENABLE_ASH_BASH_COMPAT
9318 	{ BUILTIN_REGULAR       "[["      , testcmd    },
9319 # endif
9320 #endif
9321 #if ENABLE_ASH_ALIAS
9322 	{ BUILTIN_REG_ASSG      "alias"   , aliascmd   },
9323 #endif
9324 #if JOBS
9325 	{ BUILTIN_REGULAR       "bg"      , fg_bgcmd   },
9326 #endif
9327 	{ BUILTIN_SPEC_REG      "break"   , breakcmd   },
9328 	{ BUILTIN_REGULAR       "cd"      , cdcmd      },
9329 	{ BUILTIN_NOSPEC        "chdir"   , cdcmd      },
9330 #if ENABLE_ASH_CMDCMD
9331 	{ BUILTIN_REGULAR       "command" , commandcmd },
9332 #endif
9333 	{ BUILTIN_SPEC_REG      "continue", breakcmd   },
9334 #if ENABLE_ASH_BUILTIN_ECHO
9335 	{ BUILTIN_REGULAR       "echo"    , echocmd    },
9336 #endif
9337 	{ BUILTIN_SPEC_REG      "eval"    , NULL       }, /*evalcmd() has a differing prototype*/
9338 	{ BUILTIN_SPEC_REG      "exec"    , execcmd    },
9339 	{ BUILTIN_SPEC_REG      "exit"    , exitcmd    },
9340 	{ BUILTIN_SPEC_REG_ASSG "export"  , exportcmd  },
9341 	{ BUILTIN_REGULAR       "false"   , falsecmd   },
9342 #if JOBS
9343 	{ BUILTIN_REGULAR       "fg"      , fg_bgcmd   },
9344 #endif
9345 #if ENABLE_ASH_GETOPTS
9346 	{ BUILTIN_REGULAR       "getopts" , getoptscmd },
9347 #endif
9348 	{ BUILTIN_NOSPEC        "hash"    , hashcmd    },
9349 #if ENABLE_ASH_HELP
9350 	{ BUILTIN_NOSPEC        "help"    , helpcmd    },
9351 #endif
9352 #if MAX_HISTORY
9353 	{ BUILTIN_NOSPEC        "history" , historycmd },
9354 #endif
9355 #if JOBS
9356 	{ BUILTIN_REGULAR       "jobs"    , jobscmd    },
9357 	{ BUILTIN_REGULAR       "kill"    , killcmd    },
9358 #endif
9359 #if ENABLE_FEATURE_SH_MATH
9360 	{ BUILTIN_NOSPEC        "let"     , letcmd     },
9361 #endif
9362 	{ BUILTIN_ASSIGN        "local"   , localcmd   },
9363 #if ENABLE_ASH_BUILTIN_PRINTF
9364 	{ BUILTIN_REGULAR       "printf"  , printfcmd  },
9365 #endif
9366 	{ BUILTIN_NOSPEC        "pwd"     , pwdcmd     },
9367 	{ BUILTIN_REGULAR       "read"    , readcmd    },
9368 	{ BUILTIN_SPEC_REG_ASSG "readonly", exportcmd  },
9369 	{ BUILTIN_SPEC_REG      "return"  , returncmd  },
9370 	{ BUILTIN_SPEC_REG      "set"     , setcmd     },
9371 	{ BUILTIN_SPEC_REG      "shift"   , shiftcmd   },
9372 #if ENABLE_ASH_BASH_COMPAT
9373 	{ BUILTIN_SPEC_REG      "source"  , dotcmd     },
9374 #endif
9375 #if ENABLE_ASH_BUILTIN_TEST
9376 	{ BUILTIN_REGULAR       "test"    , testcmd    },
9377 #endif
9378 	{ BUILTIN_SPEC_REG      "times"   , timescmd   },
9379 	{ BUILTIN_SPEC_REG      "trap"    , trapcmd    },
9380 	{ BUILTIN_REGULAR       "true"    , truecmd    },
9381 	{ BUILTIN_NOSPEC        "type"    , typecmd    },
9382 	{ BUILTIN_NOSPEC        "ulimit"  , ulimitcmd  },
9383 	{ BUILTIN_REGULAR       "umask"   , umaskcmd   },
9384 #if ENABLE_ASH_ALIAS
9385 	{ BUILTIN_REGULAR       "unalias" , unaliascmd },
9386 #endif
9387 	{ BUILTIN_SPEC_REG      "unset"   , unsetcmd   },
9388 	{ BUILTIN_REGULAR       "wait"    , waitcmd    },
9389 };
9390 
9391 /* Should match the above table! */
9392 #define COMMANDCMD (builtintab + \
9393 	/* . : */	2 + \
9394 	/* [ */		1 * ENABLE_ASH_BUILTIN_TEST + \
9395 	/* [[ */	1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9396 	/* alias */	1 * ENABLE_ASH_ALIAS + \
9397 	/* bg */	1 * ENABLE_ASH_JOB_CONTROL + \
9398 	/* break cd cddir  */	3)
9399 #define EVALCMD (COMMANDCMD + \
9400 	/* command */	1 * ENABLE_ASH_CMDCMD + \
9401 	/* continue */	1 + \
9402 	/* echo */	1 * ENABLE_ASH_BUILTIN_ECHO + \
9403 	0)
9404 #define EXECCMD (EVALCMD + \
9405 	/* eval */	1)
9406 
9407 /*
9408  * Search the table of builtin commands.
9409  */
9410 static int
pstrcmp1(const void * a,const void * b)9411 pstrcmp1(const void *a, const void *b)
9412 {
9413 	return strcmp((char*)a, *(char**)b + 1);
9414 }
9415 static struct builtincmd *
find_builtin(const char * name)9416 find_builtin(const char *name)
9417 {
9418 	struct builtincmd *bp;
9419 
9420 	bp = bsearch(
9421 		name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9422 		pstrcmp1
9423 	);
9424 	return bp;
9425 }
9426 
9427 /*
9428  * Execute a simple command.
9429  */
9430 static int
isassignment(const char * p)9431 isassignment(const char *p)
9432 {
9433 	const char *q = endofname(p);
9434 	if (p == q)
9435 		return 0;
9436 	return *q == '=';
9437 }
9438 static int FAST_FUNC
bltincmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)9439 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9440 {
9441 	/* Preserve exitstatus of a previous possible redirection
9442 	 * as POSIX mandates */
9443 	return back_exitstatus;
9444 }
9445 static int
evalcommand(union node * cmd,int flags)9446 evalcommand(union node *cmd, int flags)
9447 {
9448 	static const struct builtincmd null_bltin = {
9449 		"\0\0", bltincmd /* why three NULs? */
9450 	};
9451 	struct stackmark smark;
9452 	union node *argp;
9453 	struct arglist arglist;
9454 	struct arglist varlist;
9455 	char **argv;
9456 	int argc;
9457 	const struct strlist *sp;
9458 	struct cmdentry cmdentry;
9459 	struct job *jp;
9460 	char *lastarg;
9461 	const char *path;
9462 	int spclbltin;
9463 	int status;
9464 	char **nargv;
9465 	struct builtincmd *bcmd;
9466 	smallint cmd_is_exec;
9467 	smallint pseudovarflag = 0;
9468 
9469 	/* First expand the arguments. */
9470 	TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9471 	setstackmark(&smark);
9472 	back_exitstatus = 0;
9473 
9474 	cmdentry.cmdtype = CMDBUILTIN;
9475 	cmdentry.u.cmd = &null_bltin;
9476 	varlist.lastp = &varlist.list;
9477 	*varlist.lastp = NULL;
9478 	arglist.lastp = &arglist.list;
9479 	*arglist.lastp = NULL;
9480 
9481 	argc = 0;
9482 	if (cmd->ncmd.args) {
9483 		bcmd = find_builtin(cmd->ncmd.args->narg.text);
9484 		pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9485 	}
9486 
9487 	for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9488 		struct strlist **spp;
9489 
9490 		spp = arglist.lastp;
9491 		if (pseudovarflag && isassignment(argp->narg.text))
9492 			expandarg(argp, &arglist, EXP_VARTILDE);
9493 		else
9494 			expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9495 
9496 		for (sp = *spp; sp; sp = sp->next)
9497 			argc++;
9498 	}
9499 
9500 	/* Reserve one extra spot at the front for shellexec. */
9501 	nargv = stalloc(sizeof(char *) * (argc + 2));
9502 	argv = ++nargv;
9503 	for (sp = arglist.list; sp; sp = sp->next) {
9504 		TRACE(("evalcommand arg: %s\n", sp->text));
9505 		*nargv++ = sp->text;
9506 	}
9507 	*nargv = NULL;
9508 
9509 	lastarg = NULL;
9510 	if (iflag && funcnest == 0 && argc > 0)
9511 		lastarg = nargv[-1];
9512 
9513 	preverrout_fd = 2;
9514 	expredir(cmd->ncmd.redirect);
9515 	status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
9516 
9517 	path = vpath.var_text;
9518 	for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9519 		struct strlist **spp;
9520 		char *p;
9521 
9522 		spp = varlist.lastp;
9523 		expandarg(argp, &varlist, EXP_VARTILDE);
9524 
9525 		/*
9526 		 * Modify the command lookup path, if a PATH= assignment
9527 		 * is present
9528 		 */
9529 		p = (*spp)->text;
9530 		if (varcmp(p, path) == 0)
9531 			path = p;
9532 	}
9533 
9534 	/* Print the command if xflag is set. */
9535 	if (xflag) {
9536 		int n;
9537 		const char *p = " %s" + 1;
9538 
9539 		fdprintf(preverrout_fd, p, expandstr(ps4val()));
9540 		sp = varlist.list;
9541 		for (n = 0; n < 2; n++) {
9542 			while (sp) {
9543 				fdprintf(preverrout_fd, p, sp->text);
9544 				sp = sp->next;
9545 				p = " %s";
9546 			}
9547 			sp = arglist.list;
9548 		}
9549 		safe_write(preverrout_fd, "\n", 1);
9550 	}
9551 
9552 	cmd_is_exec = 0;
9553 	spclbltin = -1;
9554 
9555 	/* Now locate the command. */
9556 	if (argc) {
9557 		int cmd_flag = DO_ERR;
9558 #if ENABLE_ASH_CMDCMD
9559 		const char *oldpath = path + 5;
9560 #endif
9561 		path += 5;
9562 		for (;;) {
9563 			find_command(argv[0], &cmdentry, cmd_flag, path);
9564 			if (cmdentry.cmdtype == CMDUNKNOWN) {
9565 				flush_stdout_stderr();
9566 				status = 127;
9567 				goto bail;
9568 			}
9569 
9570 			/* implement bltin and command here */
9571 			if (cmdentry.cmdtype != CMDBUILTIN)
9572 				break;
9573 			if (spclbltin < 0)
9574 				spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9575 			if (cmdentry.u.cmd == EXECCMD)
9576 				cmd_is_exec = 1;
9577 #if ENABLE_ASH_CMDCMD
9578 			if (cmdentry.u.cmd == COMMANDCMD) {
9579 				path = oldpath;
9580 				nargv = parse_command_args(argv, &path);
9581 				if (!nargv)
9582 					break;
9583 				/* It's "command [-p] PROG ARGS" (that is, no -Vv).
9584 				 * nargv => "PROG". path is updated if -p.
9585 				 */
9586 				argc -= nargv - argv;
9587 				argv = nargv;
9588 				cmd_flag |= DO_NOFUNC;
9589 			} else
9590 #endif
9591 				break;
9592 		}
9593 	}
9594 
9595 	if (status) {
9596  bail:
9597 		exitstatus = status;
9598 
9599 		/* We have a redirection error. */
9600 		if (spclbltin > 0)
9601 			raise_exception(EXERROR);
9602 
9603 		goto out;
9604 	}
9605 
9606 	/* Execute the command. */
9607 	switch (cmdentry.cmdtype) {
9608 	default: {
9609 
9610 #if ENABLE_FEATURE_SH_NOFORK
9611 /* (1) BUG: if variables are set, we need to fork, or save/restore them
9612  *     around run_nofork_applet() call.
9613  * (2) Should this check also be done in forkshell()?
9614  *     (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9615  */
9616 		/* find_command() encodes applet_no as (-2 - applet_no) */
9617 		int applet_no = (- cmdentry.u.index - 2);
9618 		if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
9619 			listsetvar(varlist.list, VEXPORT|VSTACK);
9620 			/* run <applet>_main() */
9621 			status = run_nofork_applet(applet_no, argv);
9622 			break;
9623 		}
9624 #endif
9625 		/* Can we avoid forking off? For example, very last command
9626 		 * in a script or a subshell does not need forking,
9627 		 * we can just exec it.
9628 		 */
9629 		if (!(flags & EV_EXIT) || may_have_traps) {
9630 			/* No, forking off a child is necessary */
9631 			INT_OFF;
9632 			jp = makejob(/*cmd,*/ 1);
9633 			if (forkshell(jp, cmd, FORK_FG) != 0) {
9634 				/* parent */
9635 				status = waitforjob(jp);
9636 				INT_ON;
9637 				TRACE(("forked child exited with %d\n", status));
9638 				break;
9639 			}
9640 			/* child */
9641 			FORCE_INT_ON;
9642 			/* fall through to exec'ing external program */
9643 		}
9644 		listsetvar(varlist.list, VEXPORT|VSTACK);
9645 		shellexec(argv, path, cmdentry.u.index);
9646 		/* NOTREACHED */
9647 	} /* default */
9648 	case CMDBUILTIN:
9649 		cmdenviron = varlist.list;
9650 		if (cmdenviron) {
9651 			struct strlist *list = cmdenviron;
9652 			int i = VNOSET;
9653 			if (spclbltin > 0 || argc == 0) {
9654 				i = 0;
9655 				if (cmd_is_exec && argc > 1)
9656 					i = VEXPORT;
9657 			}
9658 			listsetvar(list, i);
9659 		}
9660 		/* Tight loop with builtins only:
9661 		 * "while kill -0 $child; do true; done"
9662 		 * will never exit even if $child died, unless we do this
9663 		 * to reap the zombie and make kill detect that it's gone: */
9664 		dowait(DOWAIT_NONBLOCK, NULL);
9665 
9666 		if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
9667 			if (exception_type == EXERROR && spclbltin <= 0) {
9668 				FORCE_INT_ON;
9669 				goto readstatus;
9670 			}
9671  raise:
9672 			longjmp(exception_handler->loc, 1);
9673 		}
9674 		goto readstatus;
9675 
9676 	case CMDFUNCTION:
9677 		listsetvar(varlist.list, 0);
9678 		/* See above for the rationale */
9679 		dowait(DOWAIT_NONBLOCK, NULL);
9680 		if (evalfun(cmdentry.u.func, argc, argv, flags))
9681 			goto raise;
9682  readstatus:
9683 		status = exitstatus;
9684 		break;
9685 	} /* switch */
9686 
9687  out:
9688 	if (cmd->ncmd.redirect)
9689 		popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9690 	if (lastarg) {
9691 		/* dsl: I think this is intended to be used to support
9692 		 * '_' in 'vi' command mode during line editing...
9693 		 * However I implemented that within libedit itself.
9694 		 */
9695 		setvar0("_", lastarg);
9696 	}
9697 	popstackmark(&smark);
9698 
9699 	return status;
9700 }
9701 
9702 static int
evalbltin(const struct builtincmd * cmd,int argc,char ** argv,int flags)9703 evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
9704 {
9705 	char *volatile savecmdname;
9706 	struct jmploc *volatile savehandler;
9707 	struct jmploc jmploc;
9708 	int status;
9709 	int i;
9710 
9711 	savecmdname = commandname;
9712 	savehandler = exception_handler;
9713 	i = setjmp(jmploc.loc);
9714 	if (i)
9715 		goto cmddone;
9716 	exception_handler = &jmploc;
9717 	commandname = argv[0];
9718 	argptr = argv + 1;
9719 	optptr = NULL;                  /* initialize nextopt */
9720 	if (cmd == EVALCMD)
9721 		status = evalcmd(argc, argv, flags);
9722 	else
9723 		status = (*cmd->builtin)(argc, argv);
9724 	flush_stdout_stderr();
9725 	status |= ferror(stdout);
9726 	exitstatus = status;
9727  cmddone:
9728 	clearerr(stdout);
9729 	commandname = savecmdname;
9730 	exception_handler = savehandler;
9731 
9732 	return i;
9733 }
9734 
9735 static int
goodname(const char * p)9736 goodname(const char *p)
9737 {
9738 	return endofname(p)[0] == '\0';
9739 }
9740 
9741 
9742 /*
9743  * Search for a command.  This is called before we fork so that the
9744  * location of the command will be available in the parent as well as
9745  * the child.  The check for "goodname" is an overly conservative
9746  * check that the name will not be subject to expansion.
9747  */
9748 static void
prehash(union node * n)9749 prehash(union node *n)
9750 {
9751 	struct cmdentry entry;
9752 
9753 	if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9754 		find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9755 }
9756 
9757 
9758 /* ============ Builtin commands
9759  *
9760  * Builtin commands whose functions are closely tied to evaluation
9761  * are implemented here.
9762  */
9763 
9764 /*
9765  * Handle break and continue commands.  Break, continue, and return are
9766  * all handled by setting the evalskip flag.  The evaluation routines
9767  * above all check this flag, and if it is set they start skipping
9768  * commands rather than executing them.  The variable skipcount is
9769  * the number of loops to break/continue, or the number of function
9770  * levels to return.  (The latter is always 1.)  It should probably
9771  * be an error to break out of more loops than exist, but it isn't
9772  * in the standard shell so we don't make it one here.
9773  */
9774 static int FAST_FUNC
breakcmd(int argc UNUSED_PARAM,char ** argv)9775 breakcmd(int argc UNUSED_PARAM, char **argv)
9776 {
9777 	int n = argv[1] ? number(argv[1]) : 1;
9778 
9779 	if (n <= 0)
9780 		ash_msg_and_raise_error(msg_illnum, argv[1]);
9781 	if (n > loopnest)
9782 		n = loopnest;
9783 	if (n > 0) {
9784 		evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9785 		skipcount = n;
9786 	}
9787 	return 0;
9788 }
9789 
9790 
9791 /*
9792  * This implements the input routines used by the parser.
9793  */
9794 
9795 enum {
9796 	INPUT_PUSH_FILE = 1,
9797 	INPUT_NOFILE_OK = 2,
9798 };
9799 
9800 static smallint checkkwd;
9801 /* values of checkkwd variable */
9802 #define CHKALIAS        0x1
9803 #define CHKKWD          0x2
9804 #define CHKNL           0x4
9805 
9806 /*
9807  * Push a string back onto the input at this current parsefile level.
9808  * We handle aliases this way.
9809  */
9810 #if !ENABLE_ASH_ALIAS
9811 #define pushstring(s, ap) pushstring(s)
9812 #endif
9813 static void
pushstring(char * s,struct alias * ap)9814 pushstring(char *s, struct alias *ap)
9815 {
9816 	struct strpush *sp;
9817 	int len;
9818 
9819 	len = strlen(s);
9820 	INT_OFF;
9821 	if (g_parsefile->strpush) {
9822 		sp = ckzalloc(sizeof(*sp));
9823 		sp->prev = g_parsefile->strpush;
9824 	} else {
9825 		sp = &(g_parsefile->basestrpush);
9826 	}
9827 	g_parsefile->strpush = sp;
9828 	sp->prev_string = g_parsefile->next_to_pgetc;
9829 	sp->prev_left_in_line = g_parsefile->left_in_line;
9830 	sp->unget = g_parsefile->unget;
9831 	memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
9832 #if ENABLE_ASH_ALIAS
9833 	sp->ap = ap;
9834 	if (ap) {
9835 		ap->flag |= ALIASINUSE;
9836 		sp->string = s;
9837 	}
9838 #endif
9839 	g_parsefile->next_to_pgetc = s;
9840 	g_parsefile->left_in_line = len;
9841 	g_parsefile->unget = 0;
9842 	INT_ON;
9843 }
9844 
9845 static void
popstring(void)9846 popstring(void)
9847 {
9848 	struct strpush *sp = g_parsefile->strpush;
9849 
9850 	INT_OFF;
9851 #if ENABLE_ASH_ALIAS
9852 	if (sp->ap) {
9853 		if (g_parsefile->next_to_pgetc[-1] == ' '
9854 		 || g_parsefile->next_to_pgetc[-1] == '\t'
9855 		) {
9856 			checkkwd |= CHKALIAS;
9857 		}
9858 		if (sp->string != sp->ap->val) {
9859 			free(sp->string);
9860 		}
9861 		sp->ap->flag &= ~ALIASINUSE;
9862 		if (sp->ap->flag & ALIASDEAD) {
9863 			unalias(sp->ap->name);
9864 		}
9865 	}
9866 #endif
9867 	g_parsefile->next_to_pgetc = sp->prev_string;
9868 	g_parsefile->left_in_line = sp->prev_left_in_line;
9869 	g_parsefile->unget = sp->unget;
9870 	memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
9871 	g_parsefile->strpush = sp->prev;
9872 	if (sp != &(g_parsefile->basestrpush))
9873 		free(sp);
9874 	INT_ON;
9875 }
9876 
9877 static int
preadfd(void)9878 preadfd(void)
9879 {
9880 	int nr;
9881 	char *buf = g_parsefile->buf;
9882 
9883 	g_parsefile->next_to_pgetc = buf;
9884 #if ENABLE_FEATURE_EDITING
9885  retry:
9886 	if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
9887 		nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9888 	else {
9889 		int timeout = -1;
9890 # if ENABLE_ASH_IDLE_TIMEOUT
9891 		if (iflag) {
9892 			const char *tmout_var = lookupvar("TMOUT");
9893 			if (tmout_var) {
9894 				timeout = atoi(tmout_var) * 1000;
9895 				if (timeout <= 0)
9896 					timeout = -1;
9897 			}
9898 		}
9899 # endif
9900 # if ENABLE_FEATURE_TAB_COMPLETION
9901 		line_input_state->path_lookup = pathval();
9902 # endif
9903 		reinit_unicode_for_ash();
9904 		nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
9905 		if (nr == 0) {
9906 			/* ^C pressed, "convert" to SIGINT */
9907 			write(STDOUT_FILENO, "^C", 2);
9908 			if (trap[SIGINT]) {
9909 				buf[0] = '\n';
9910 				buf[1] = '\0';
9911 				raise(SIGINT);
9912 				return 1;
9913 			}
9914 			exitstatus = 128 + SIGINT;
9915 			bb_putchar('\n');
9916 			goto retry;
9917 		}
9918 		if (nr < 0) {
9919 			if (errno == 0) {
9920 				/* Ctrl+D pressed */
9921 				nr = 0;
9922 			}
9923 # if ENABLE_ASH_IDLE_TIMEOUT
9924 			else if (errno == EAGAIN && timeout > 0) {
9925 				puts("\007timed out waiting for input: auto-logout");
9926 				exitshell();
9927 			}
9928 # endif
9929 		}
9930 	}
9931 #else
9932 	nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9933 #endif
9934 
9935 #if 0 /* disabled: nonblock_immune_read() handles this problem */
9936 	if (nr < 0) {
9937 		if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9938 			int flags = fcntl(0, F_GETFL);
9939 			if (flags >= 0 && (flags & O_NONBLOCK)) {
9940 				flags &= ~O_NONBLOCK;
9941 				if (fcntl(0, F_SETFL, flags) >= 0) {
9942 					out2str("sh: turning off NDELAY mode\n");
9943 					goto retry;
9944 				}
9945 			}
9946 		}
9947 	}
9948 #endif
9949 	return nr;
9950 }
9951 
9952 /*
9953  * Refill the input buffer and return the next input character:
9954  *
9955  * 1) If a string was pushed back on the input, pop it;
9956  * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9957  *    or we are reading from a string so we can't refill the buffer,
9958  *    return EOF.
9959  * 3) If there is more stuff in this buffer, use it else call read to fill it.
9960  * 4) Process input up to the next newline, deleting nul characters.
9961  */
9962 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9963 #define pgetc_debug(...) ((void)0)
9964 static int pgetc(void);
9965 static int
preadbuffer(void)9966 preadbuffer(void)
9967 {
9968 	char *q;
9969 	int more;
9970 
9971 	if (g_parsefile->strpush) {
9972 #if ENABLE_ASH_ALIAS
9973 		if (g_parsefile->left_in_line == -1
9974 		 && g_parsefile->strpush->ap
9975 		 && g_parsefile->next_to_pgetc[-1] != ' '
9976 		 && g_parsefile->next_to_pgetc[-1] != '\t'
9977 		) {
9978 			pgetc_debug("preadbuffer PEOA");
9979 			return PEOA;
9980 		}
9981 #endif
9982 		popstring();
9983 		return pgetc();
9984 	}
9985 	/* on both branches above g_parsefile->left_in_line < 0.
9986 	 * "pgetc" needs refilling.
9987 	 */
9988 
9989 	/* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9990 	 * pungetc() may increment it a few times.
9991 	 * Assuming it won't increment it to less than -90.
9992 	 */
9993 	if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9994 		pgetc_debug("preadbuffer PEOF1");
9995 		/* even in failure keep left_in_line and next_to_pgetc
9996 		 * in lock step, for correct multi-layer pungetc.
9997 		 * left_in_line was decremented before preadbuffer(),
9998 		 * must inc next_to_pgetc: */
9999 		g_parsefile->next_to_pgetc++;
10000 		return PEOF;
10001 	}
10002 
10003 	more = g_parsefile->left_in_buffer;
10004 	if (more <= 0) {
10005 		flush_stdout_stderr();
10006  again:
10007 		more = preadfd();
10008 		if (more <= 0) {
10009 			/* don't try reading again */
10010 			g_parsefile->left_in_line = -99;
10011 			pgetc_debug("preadbuffer PEOF2");
10012 			g_parsefile->next_to_pgetc++;
10013 			return PEOF;
10014 		}
10015 	}
10016 
10017 	/* Find out where's the end of line.
10018 	 * Set g_parsefile->left_in_line
10019 	 * and g_parsefile->left_in_buffer acordingly.
10020 	 * NUL chars are deleted.
10021 	 */
10022 	q = g_parsefile->next_to_pgetc;
10023 	for (;;) {
10024 		char c;
10025 
10026 		more--;
10027 
10028 		c = *q;
10029 		if (c == '\0') {
10030 			memmove(q, q + 1, more);
10031 		} else {
10032 			q++;
10033 			if (c == '\n') {
10034 				g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10035 				break;
10036 			}
10037 		}
10038 
10039 		if (more <= 0) {
10040 			g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10041 			if (g_parsefile->left_in_line < 0)
10042 				goto again;
10043 			break;
10044 		}
10045 	}
10046 	g_parsefile->left_in_buffer = more;
10047 
10048 	if (vflag) {
10049 		char save = *q;
10050 		*q = '\0';
10051 		out2str(g_parsefile->next_to_pgetc);
10052 		*q = save;
10053 	}
10054 
10055 	pgetc_debug("preadbuffer at %d:%p'%s'",
10056 			g_parsefile->left_in_line,
10057 			g_parsefile->next_to_pgetc,
10058 			g_parsefile->next_to_pgetc);
10059 	return (unsigned char)*g_parsefile->next_to_pgetc++;
10060 }
10061 
10062 static void
nlprompt(void)10063 nlprompt(void)
10064 {
10065 	g_parsefile->linno++;
10066 	setprompt_if(doprompt, 2);
10067 }
10068 static void
nlnoprompt(void)10069 nlnoprompt(void)
10070 {
10071 	g_parsefile->linno++;
10072 	needprompt = doprompt;
10073 }
10074 
10075 static int
pgetc(void)10076 pgetc(void)
10077 {
10078 	int c;
10079 
10080 	pgetc_debug("pgetc at %d:%p'%s'",
10081 			g_parsefile->left_in_line,
10082 			g_parsefile->next_to_pgetc,
10083 			g_parsefile->next_to_pgetc);
10084 	if (g_parsefile->unget)
10085 		return g_parsefile->lastc[--g_parsefile->unget];
10086 
10087 	if (--g_parsefile->left_in_line >= 0)
10088 		c = (unsigned char)*g_parsefile->next_to_pgetc++;
10089 	else
10090 		c = preadbuffer();
10091 
10092 	g_parsefile->lastc[1] = g_parsefile->lastc[0];
10093 	g_parsefile->lastc[0] = c;
10094 
10095 	return c;
10096 }
10097 
10098 #if ENABLE_ASH_ALIAS
10099 static int
pgetc_without_PEOA(void)10100 pgetc_without_PEOA(void)
10101 {
10102 	int c;
10103 	do {
10104 		pgetc_debug("pgetc at %d:%p'%s'",
10105 				g_parsefile->left_in_line,
10106 				g_parsefile->next_to_pgetc,
10107 				g_parsefile->next_to_pgetc);
10108 		c = pgetc();
10109 	} while (c == PEOA);
10110 	return c;
10111 }
10112 #else
10113 # define pgetc_without_PEOA() pgetc()
10114 #endif
10115 
10116 /*
10117  * Read a line from the script.
10118  */
10119 static char *
pfgets(char * line,int len)10120 pfgets(char *line, int len)
10121 {
10122 	char *p = line;
10123 	int nleft = len;
10124 	int c;
10125 
10126 	while (--nleft > 0) {
10127 		c = pgetc_without_PEOA();
10128 		if (c == PEOF) {
10129 			if (p == line)
10130 				return NULL;
10131 			break;
10132 		}
10133 		*p++ = c;
10134 		if (c == '\n')
10135 			break;
10136 	}
10137 	*p = '\0';
10138 	return line;
10139 }
10140 
10141 /*
10142  * Undo a call to pgetc.  Only two characters may be pushed back.
10143  * PEOF may be pushed back.
10144  */
10145 static void
pungetc(void)10146 pungetc(void)
10147 {
10148 	g_parsefile->unget++;
10149 }
10150 
10151 /* This one eats backslash+newline */
10152 static int
pgetc_eatbnl(void)10153 pgetc_eatbnl(void)
10154 {
10155 	int c;
10156 
10157 	while ((c = pgetc()) == '\\') {
10158 		if (pgetc() != '\n') {
10159 			pungetc();
10160 			break;
10161 		}
10162 
10163 		nlprompt();
10164 	}
10165 
10166 	return c;
10167 }
10168 
10169 /*
10170  * To handle the "." command, a stack of input files is used.  Pushfile
10171  * adds a new entry to the stack and popfile restores the previous level.
10172  */
10173 static void
pushfile(void)10174 pushfile(void)
10175 {
10176 	struct parsefile *pf;
10177 
10178 	pf = ckzalloc(sizeof(*pf));
10179 	pf->prev = g_parsefile;
10180 	pf->pf_fd = -1;
10181 	/*pf->strpush = NULL; - ckzalloc did it */
10182 	/*pf->basestrpush.prev = NULL;*/
10183 	/*pf->unget = 0;*/
10184 	g_parsefile = pf;
10185 }
10186 
10187 static void
popfile(void)10188 popfile(void)
10189 {
10190 	struct parsefile *pf = g_parsefile;
10191 
10192 	if (pf == &basepf)
10193 		return;
10194 
10195 	INT_OFF;
10196 	if (pf->pf_fd >= 0)
10197 		close(pf->pf_fd);
10198 	free(pf->buf);
10199 	while (pf->strpush)
10200 		popstring();
10201 	g_parsefile = pf->prev;
10202 	free(pf);
10203 	INT_ON;
10204 }
10205 
10206 /*
10207  * Return to top level.
10208  */
10209 static void
popallfiles(void)10210 popallfiles(void)
10211 {
10212 	while (g_parsefile != &basepf)
10213 		popfile();
10214 }
10215 
10216 /*
10217  * Close the file(s) that the shell is reading commands from.  Called
10218  * after a fork is done.
10219  */
10220 static void
closescript(void)10221 closescript(void)
10222 {
10223 	popallfiles();
10224 	if (g_parsefile->pf_fd > 0) {
10225 		close(g_parsefile->pf_fd);
10226 		g_parsefile->pf_fd = 0;
10227 	}
10228 }
10229 
10230 /*
10231  * Like setinputfile, but takes an open file descriptor.  Call this with
10232  * interrupts off.
10233  */
10234 static void
setinputfd(int fd,int push)10235 setinputfd(int fd, int push)
10236 {
10237 	if (push) {
10238 		pushfile();
10239 		g_parsefile->buf = NULL;
10240 	}
10241 	g_parsefile->pf_fd = fd;
10242 	if (g_parsefile->buf == NULL)
10243 		g_parsefile->buf = ckmalloc(IBUFSIZ);
10244 	g_parsefile->left_in_buffer = 0;
10245 	g_parsefile->left_in_line = 0;
10246 	g_parsefile->linno = 1;
10247 }
10248 
10249 /*
10250  * Set the input to take input from a file.  If push is set, push the
10251  * old input onto the stack first.
10252  */
10253 static int
setinputfile(const char * fname,int flags)10254 setinputfile(const char *fname, int flags)
10255 {
10256 	int fd;
10257 
10258 	INT_OFF;
10259 	fd = open(fname, O_RDONLY);
10260 	if (fd < 0) {
10261 		if (flags & INPUT_NOFILE_OK)
10262 			goto out;
10263 		exitstatus = 127;
10264 		ash_msg_and_raise_error("can't open '%s'", fname);
10265 	}
10266 	if (fd < 10)
10267 		fd = savefd(fd);
10268 	else
10269 		close_on_exec_on(fd);
10270 	setinputfd(fd, flags & INPUT_PUSH_FILE);
10271  out:
10272 	INT_ON;
10273 	return fd;
10274 }
10275 
10276 /*
10277  * Like setinputfile, but takes input from a string.
10278  */
10279 static void
setinputstring(char * string)10280 setinputstring(char *string)
10281 {
10282 	INT_OFF;
10283 	pushfile();
10284 	g_parsefile->next_to_pgetc = string;
10285 	g_parsefile->left_in_line = strlen(string);
10286 	g_parsefile->buf = NULL;
10287 	g_parsefile->linno = 1;
10288 	INT_ON;
10289 }
10290 
10291 
10292 /*
10293  * Routines to check for mail.
10294  */
10295 
10296 #if ENABLE_ASH_MAIL
10297 
10298 /* Hash of mtimes of mailboxes */
10299 static unsigned mailtime_hash;
10300 /* Set if MAIL or MAILPATH is changed. */
10301 static smallint mail_var_path_changed;
10302 
10303 /*
10304  * Print appropriate message(s) if mail has arrived.
10305  * If mail_var_path_changed is set,
10306  * then the value of MAIL has mail_var_path_changed,
10307  * so we just update the values.
10308  */
10309 static void
chkmail(void)10310 chkmail(void)
10311 {
10312 	const char *mpath;
10313 	char *p;
10314 	char *q;
10315 	unsigned new_hash;
10316 	struct stackmark smark;
10317 	struct stat statb;
10318 
10319 	setstackmark(&smark);
10320 	mpath = mpathset() ? mpathval() : mailval();
10321 	new_hash = 0;
10322 	for (;;) {
10323 		p = path_advance(&mpath, nullstr);
10324 		if (p == NULL)
10325 			break;
10326 		if (*p == '\0')
10327 			continue;
10328 		for (q = p; *q; q++)
10329 			continue;
10330 #if DEBUG
10331 		if (q[-1] != '/')
10332 			abort();
10333 #endif
10334 		q[-1] = '\0';                   /* delete trailing '/' */
10335 		if (stat(p, &statb) < 0) {
10336 			continue;
10337 		}
10338 		/* Very simplistic "hash": just a sum of all mtimes */
10339 		new_hash += (unsigned)statb.st_mtime;
10340 	}
10341 	if (!mail_var_path_changed && mailtime_hash != new_hash) {
10342 		if (mailtime_hash != 0)
10343 			out2str("you have mail\n");
10344 		mailtime_hash = new_hash;
10345 	}
10346 	mail_var_path_changed = 0;
10347 	popstackmark(&smark);
10348 }
10349 
10350 static void FAST_FUNC
changemail(const char * val UNUSED_PARAM)10351 changemail(const char *val UNUSED_PARAM)
10352 {
10353 	mail_var_path_changed = 1;
10354 }
10355 
10356 #endif /* ASH_MAIL */
10357 
10358 
10359 /* ============ ??? */
10360 
10361 /*
10362  * Set the shell parameters.
10363  */
10364 static void
setparam(char ** argv)10365 setparam(char **argv)
10366 {
10367 	char **newparam;
10368 	char **ap;
10369 	int nparam;
10370 
10371 	for (nparam = 0; argv[nparam]; nparam++)
10372 		continue;
10373 	ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10374 	while (*argv) {
10375 		*ap++ = ckstrdup(*argv++);
10376 	}
10377 	*ap = NULL;
10378 	freeparam(&shellparam);
10379 	shellparam.malloced = 1;
10380 	shellparam.nparam = nparam;
10381 	shellparam.p = newparam;
10382 #if ENABLE_ASH_GETOPTS
10383 	shellparam.optind = 1;
10384 	shellparam.optoff = -1;
10385 #endif
10386 }
10387 
10388 /*
10389  * Process shell options.  The global variable argptr contains a pointer
10390  * to the argument list; we advance it past the options.
10391  *
10392  * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10393  * For a non-interactive shell, an error condition encountered
10394  * by a special built-in ... shall cause the shell to write a diagnostic message
10395  * to standard error and exit as shown in the following table:
10396  * Error                                           Special Built-In
10397  * ...
10398  * Utility syntax error (option or operand error)  Shall exit
10399  * ...
10400  * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10401  * we see that bash does not do that (set "finishes" with error code 1 instead,
10402  * and shell continues), and people rely on this behavior!
10403  * Testcase:
10404  * set -o barfoo 2>/dev/null
10405  * echo $?
10406  *
10407  * Oh well. Let's mimic that.
10408  */
10409 static int
plus_minus_o(char * name,int val)10410 plus_minus_o(char *name, int val)
10411 {
10412 	int i;
10413 
10414 	if (name) {
10415 		for (i = 0; i < NOPTS; i++) {
10416 			if (strcmp(name, optnames(i)) == 0) {
10417 				optlist[i] = val;
10418 				return 0;
10419 			}
10420 		}
10421 		ash_msg("illegal option %co %s", val ? '-' : '+', name);
10422 		return 1;
10423 	}
10424 	for (i = 0; i < NOPTS; i++) {
10425 		if (val) {
10426 			out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10427 		} else {
10428 			out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10429 		}
10430 	}
10431 	return 0;
10432 }
10433 static void
setoption(int flag,int val)10434 setoption(int flag, int val)
10435 {
10436 	int i;
10437 
10438 	for (i = 0; i < NOPTS; i++) {
10439 		if (optletters(i) == flag) {
10440 			optlist[i] = val;
10441 			return;
10442 		}
10443 	}
10444 	ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
10445 	/* NOTREACHED */
10446 }
10447 static int
options(int cmdline)10448 options(int cmdline)
10449 {
10450 	char *p;
10451 	int val;
10452 	int c;
10453 
10454 	if (cmdline)
10455 		minusc = NULL;
10456 	while ((p = *argptr) != NULL) {
10457 		c = *p++;
10458 		if (c != '-' && c != '+')
10459 			break;
10460 		argptr++;
10461 		val = 0; /* val = 0 if c == '+' */
10462 		if (c == '-') {
10463 			val = 1;
10464 			if (p[0] == '\0' || LONE_DASH(p)) {
10465 				if (!cmdline) {
10466 					/* "-" means turn off -x and -v */
10467 					if (p[0] == '\0')
10468 						xflag = vflag = 0;
10469 					/* "--" means reset params */
10470 					else if (*argptr == NULL)
10471 						setparam(argptr);
10472 				}
10473 				break;    /* "-" or "--" terminates options */
10474 			}
10475 		}
10476 		/* first char was + or - */
10477 		while ((c = *p++) != '\0') {
10478 			/* bash 3.2 indeed handles -c CMD and +c CMD the same */
10479 			if (c == 'c' && cmdline) {
10480 				minusc = p;     /* command is after shell args */
10481 			} else if (c == 'o') {
10482 				if (plus_minus_o(*argptr, val)) {
10483 					/* it already printed err message */
10484 					return 1; /* error */
10485 				}
10486 				if (*argptr)
10487 					argptr++;
10488 			} else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10489 				isloginsh = 1;
10490 			/* bash does not accept +-login, we also won't */
10491 			} else if (cmdline && val && (c == '-')) { /* long options */
10492 				if (strcmp(p, "login") == 0)
10493 					isloginsh = 1;
10494 				break;
10495 			} else {
10496 				setoption(c, val);
10497 			}
10498 		}
10499 	}
10500 	return 0;
10501 }
10502 
10503 /*
10504  * The shift builtin command.
10505  */
10506 static int FAST_FUNC
shiftcmd(int argc UNUSED_PARAM,char ** argv)10507 shiftcmd(int argc UNUSED_PARAM, char **argv)
10508 {
10509 	int n;
10510 	char **ap1, **ap2;
10511 
10512 	n = 1;
10513 	if (argv[1])
10514 		n = number(argv[1]);
10515 	if (n > shellparam.nparam)
10516 		n = 0; /* bash compat, was = shellparam.nparam; */
10517 	INT_OFF;
10518 	shellparam.nparam -= n;
10519 	for (ap1 = shellparam.p; --n >= 0; ap1++) {
10520 		if (shellparam.malloced)
10521 			free(*ap1);
10522 	}
10523 	ap2 = shellparam.p;
10524 	while ((*ap2++ = *ap1++) != NULL)
10525 		continue;
10526 #if ENABLE_ASH_GETOPTS
10527 	shellparam.optind = 1;
10528 	shellparam.optoff = -1;
10529 #endif
10530 	INT_ON;
10531 	return 0;
10532 }
10533 
10534 /*
10535  * POSIX requires that 'set' (but not export or readonly) output the
10536  * variables in lexicographic order - by the locale's collating order (sigh).
10537  * Maybe we could keep them in an ordered balanced binary tree
10538  * instead of hashed lists.
10539  * For now just roll 'em through qsort for printing...
10540  */
10541 static int
showvars(const char * sep_prefix,int on,int off)10542 showvars(const char *sep_prefix, int on, int off)
10543 {
10544 	const char *sep;
10545 	char **ep, **epend;
10546 
10547 	ep = listvars(on, off, &epend);
10548 	qsort(ep, epend - ep, sizeof(char *), vpcmp);
10549 
10550 	sep = *sep_prefix ? " " : sep_prefix;
10551 
10552 	for (; ep < epend; ep++) {
10553 		const char *p;
10554 		const char *q;
10555 
10556 		p = strchrnul(*ep, '=');
10557 		q = nullstr;
10558 		if (*p)
10559 			q = single_quote(++p);
10560 		out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10561 	}
10562 	return 0;
10563 }
10564 
10565 /*
10566  * The set command builtin.
10567  */
10568 static int FAST_FUNC
setcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)10569 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10570 {
10571 	int retval;
10572 
10573 	if (!argv[1])
10574 		return showvars(nullstr, 0, VUNSET);
10575 
10576 	INT_OFF;
10577 	retval = options(/*cmdline:*/ 0);
10578 	if (retval == 0) { /* if no parse error... */
10579 		optschanged();
10580 		if (*argptr != NULL) {
10581 			setparam(argptr);
10582 		}
10583 	}
10584 	INT_ON;
10585 	return retval;
10586 }
10587 
10588 #if ENABLE_ASH_RANDOM_SUPPORT
10589 static void FAST_FUNC
change_random(const char * value)10590 change_random(const char *value)
10591 {
10592 	uint32_t t;
10593 
10594 	if (value == NULL) {
10595 		/* "get", generate */
10596 		t = next_random(&random_gen);
10597 		/* set without recursion */
10598 		setvar(vrandom.var_text, utoa(t), VNOFUNC);
10599 		vrandom.flags &= ~VNOFUNC;
10600 	} else {
10601 		/* set/reset */
10602 		t = strtoul(value, NULL, 10);
10603 		INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
10604 	}
10605 }
10606 #endif
10607 
10608 #if ENABLE_ASH_GETOPTS
10609 static int
getopts(char * optstr,char * optvar,char ** optfirst)10610 getopts(char *optstr, char *optvar, char **optfirst)
10611 {
10612 	char *p, *q;
10613 	char c = '?';
10614 	int done = 0;
10615 	char sbuf[2];
10616 	char **optnext;
10617 	int ind = shellparam.optind;
10618 	int off = shellparam.optoff;
10619 
10620 	sbuf[1] = '\0';
10621 
10622 	shellparam.optind = -1;
10623 	optnext = optfirst + ind - 1;
10624 
10625 	if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
10626 		p = NULL;
10627 	else
10628 		p = optnext[-1] + off;
10629 	if (p == NULL || *p == '\0') {
10630 		/* Current word is done, advance */
10631 		p = *optnext;
10632 		if (p == NULL || *p != '-' || *++p == '\0') {
10633  atend:
10634 			p = NULL;
10635 			done = 1;
10636 			goto out;
10637 		}
10638 		optnext++;
10639 		if (LONE_DASH(p))        /* check for "--" */
10640 			goto atend;
10641 	}
10642 
10643 	c = *p++;
10644 	for (q = optstr; *q != c;) {
10645 		if (*q == '\0') {
10646 			if (optstr[0] == ':') {
10647 				sbuf[0] = c;
10648 				/*sbuf[1] = '\0'; - already is */
10649 				setvar0("OPTARG", sbuf);
10650 			} else {
10651 				fprintf(stderr, "Illegal option -%c\n", c);
10652 				unsetvar("OPTARG");
10653 			}
10654 			c = '?';
10655 			goto out;
10656 		}
10657 		if (*++q == ':')
10658 			q++;
10659 	}
10660 
10661 	if (*++q == ':') {
10662 		if (*p == '\0' && (p = *optnext) == NULL) {
10663 			if (optstr[0] == ':') {
10664 				sbuf[0] = c;
10665 				/*sbuf[1] = '\0'; - already is */
10666 				setvar0("OPTARG", sbuf);
10667 				c = ':';
10668 			} else {
10669 				fprintf(stderr, "No arg for -%c option\n", c);
10670 				unsetvar("OPTARG");
10671 				c = '?';
10672 			}
10673 			goto out;
10674 		}
10675 
10676 		if (p == *optnext)
10677 			optnext++;
10678 		setvar0("OPTARG", p);
10679 		p = NULL;
10680 	} else
10681 		setvar0("OPTARG", nullstr);
10682  out:
10683 	ind = optnext - optfirst + 1;
10684 	setvar("OPTIND", itoa(ind), VNOFUNC);
10685 	sbuf[0] = c;
10686 	/*sbuf[1] = '\0'; - already is */
10687 	setvar0(optvar, sbuf);
10688 
10689 	shellparam.optoff = p ? p - *(optnext - 1) : -1;
10690 	shellparam.optind = ind;
10691 
10692 	return done;
10693 }
10694 
10695 /*
10696  * The getopts builtin.  Shellparam.optnext points to the next argument
10697  * to be processed.  Shellparam.optptr points to the next character to
10698  * be processed in the current argument.  If shellparam.optnext is NULL,
10699  * then it's the first time getopts has been called.
10700  */
10701 static int FAST_FUNC
getoptscmd(int argc,char ** argv)10702 getoptscmd(int argc, char **argv)
10703 {
10704 	char **optbase;
10705 
10706 	if (argc < 3)
10707 		ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10708 	if (argc == 3) {
10709 		optbase = shellparam.p;
10710 		if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
10711 			shellparam.optind = 1;
10712 			shellparam.optoff = -1;
10713 		}
10714 	} else {
10715 		optbase = &argv[3];
10716 		if ((unsigned)shellparam.optind > argc - 2) {
10717 			shellparam.optind = 1;
10718 			shellparam.optoff = -1;
10719 		}
10720 	}
10721 
10722 	return getopts(argv[1], argv[2], optbase);
10723 }
10724 #endif /* ASH_GETOPTS */
10725 
10726 
10727 /* ============ Shell parser */
10728 
10729 struct heredoc {
10730 	struct heredoc *next;   /* next here document in list */
10731 	union node *here;       /* redirection node */
10732 	char *eofmark;          /* string indicating end of input */
10733 	smallint striptabs;     /* if set, strip leading tabs */
10734 };
10735 
10736 static smallint tokpushback;           /* last token pushed back */
10737 static smallint quoteflag;             /* set if (part of) last token was quoted */
10738 static token_id_t lasttoken;           /* last token read (integer id Txxx) */
10739 static struct heredoc *heredoclist;    /* list of here documents to read */
10740 static char *wordtext;                 /* text of last word returned by readtoken */
10741 static struct nodelist *backquotelist;
10742 static union node *redirnode;
10743 static struct heredoc *heredoc;
10744 
10745 static const char *
tokname(char * buf,int tok)10746 tokname(char *buf, int tok)
10747 {
10748 	if (tok < TSEMI)
10749 		return tokname_array[tok];
10750 	sprintf(buf, "\"%s\"", tokname_array[tok]);
10751 	return buf;
10752 }
10753 
10754 /* raise_error_unexpected_syntax:
10755  * Called when an unexpected token is read during the parse.  The argument
10756  * is the token that is expected, or -1 if more than one type of token can
10757  * occur at this point.
10758  */
10759 static void raise_error_unexpected_syntax(int) NORETURN;
10760 static void
raise_error_unexpected_syntax(int token)10761 raise_error_unexpected_syntax(int token)
10762 {
10763 	char msg[64];
10764 	char buf[16];
10765 	int l;
10766 
10767 	l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
10768 	if (token >= 0)
10769 		sprintf(msg + l, " (expecting %s)", tokname(buf, token));
10770 	raise_error_syntax(msg);
10771 	/* NOTREACHED */
10772 }
10773 
10774 #define EOFMARKLEN 79
10775 
10776 /* parsing is heavily cross-recursive, need these forward decls */
10777 static union node *andor(void);
10778 static union node *pipeline(void);
10779 static union node *parse_command(void);
10780 static void parseheredoc(void);
10781 static int peektoken(void);
10782 static int readtoken(void);
10783 
10784 static union node *
list(int nlflag)10785 list(int nlflag)
10786 {
10787 	union node *n1, *n2, *n3;
10788 	int tok;
10789 
10790 	n1 = NULL;
10791 	for (;;) {
10792 		switch (peektoken()) {
10793 		case TNL:
10794 			if (!(nlflag & 1))
10795 				break;
10796 			parseheredoc();
10797 			return n1;
10798 
10799 		case TEOF:
10800 			if (!n1 && (nlflag & 1))
10801 				n1 = NODE_EOF;
10802 			parseheredoc();
10803 			return n1;
10804 		}
10805 
10806 		checkkwd = CHKNL | CHKKWD | CHKALIAS;
10807 		if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
10808 			return n1;
10809 		nlflag |= 2;
10810 
10811 		n2 = andor();
10812 		tok = readtoken();
10813 		if (tok == TBACKGND) {
10814 			if (n2->type == NPIPE) {
10815 				n2->npipe.pipe_backgnd = 1;
10816 			} else {
10817 				if (n2->type != NREDIR) {
10818 					n3 = stzalloc(sizeof(struct nredir));
10819 					n3->nredir.n = n2;
10820 					/*n3->nredir.redirect = NULL; - stzalloc did it */
10821 					n2 = n3;
10822 				}
10823 				n2->type = NBACKGND;
10824 			}
10825 		}
10826 		if (n1 == NULL) {
10827 			n1 = n2;
10828 		} else {
10829 			n3 = stzalloc(sizeof(struct nbinary));
10830 			n3->type = NSEMI;
10831 			n3->nbinary.ch1 = n1;
10832 			n3->nbinary.ch2 = n2;
10833 			n1 = n3;
10834 		}
10835 		switch (tok) {
10836 		case TNL:
10837 		case TEOF:
10838 			tokpushback = 1;
10839 			/* fall through */
10840 		case TBACKGND:
10841 		case TSEMI:
10842 			break;
10843 		default:
10844 			if ((nlflag & 1))
10845 				raise_error_unexpected_syntax(-1);
10846 			tokpushback = 1;
10847 			return n1;
10848 		}
10849 	}
10850 }
10851 
10852 static union node *
andor(void)10853 andor(void)
10854 {
10855 	union node *n1, *n2, *n3;
10856 	int t;
10857 
10858 	n1 = pipeline();
10859 	for (;;) {
10860 		t = readtoken();
10861 		if (t == TAND) {
10862 			t = NAND;
10863 		} else if (t == TOR) {
10864 			t = NOR;
10865 		} else {
10866 			tokpushback = 1;
10867 			return n1;
10868 		}
10869 		checkkwd = CHKNL | CHKKWD | CHKALIAS;
10870 		n2 = pipeline();
10871 		n3 = stzalloc(sizeof(struct nbinary));
10872 		n3->type = t;
10873 		n3->nbinary.ch1 = n1;
10874 		n3->nbinary.ch2 = n2;
10875 		n1 = n3;
10876 	}
10877 }
10878 
10879 static union node *
pipeline(void)10880 pipeline(void)
10881 {
10882 	union node *n1, *n2, *pipenode;
10883 	struct nodelist *lp, *prev;
10884 	int negate;
10885 
10886 	negate = 0;
10887 	TRACE(("pipeline: entered\n"));
10888 	if (readtoken() == TNOT) {
10889 		negate = !negate;
10890 		checkkwd = CHKKWD | CHKALIAS;
10891 	} else
10892 		tokpushback = 1;
10893 	n1 = parse_command();
10894 	if (readtoken() == TPIPE) {
10895 		pipenode = stzalloc(sizeof(struct npipe));
10896 		pipenode->type = NPIPE;
10897 		/*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10898 		lp = stzalloc(sizeof(struct nodelist));
10899 		pipenode->npipe.cmdlist = lp;
10900 		lp->n = n1;
10901 		do {
10902 			prev = lp;
10903 			lp = stzalloc(sizeof(struct nodelist));
10904 			checkkwd = CHKNL | CHKKWD | CHKALIAS;
10905 			lp->n = parse_command();
10906 			prev->next = lp;
10907 		} while (readtoken() == TPIPE);
10908 		lp->next = NULL;
10909 		n1 = pipenode;
10910 	}
10911 	tokpushback = 1;
10912 	if (negate) {
10913 		n2 = stzalloc(sizeof(struct nnot));
10914 		n2->type = NNOT;
10915 		n2->nnot.com = n1;
10916 		return n2;
10917 	}
10918 	return n1;
10919 }
10920 
10921 static union node *
makename(void)10922 makename(void)
10923 {
10924 	union node *n;
10925 
10926 	n = stzalloc(sizeof(struct narg));
10927 	n->type = NARG;
10928 	/*n->narg.next = NULL; - stzalloc did it */
10929 	n->narg.text = wordtext;
10930 	n->narg.backquote = backquotelist;
10931 	return n;
10932 }
10933 
10934 static void
fixredir(union node * n,const char * text,int err)10935 fixredir(union node *n, const char *text, int err)
10936 {
10937 	int fd;
10938 
10939 	TRACE(("Fix redir %s %d\n", text, err));
10940 	if (!err)
10941 		n->ndup.vname = NULL;
10942 
10943 	fd = bb_strtou(text, NULL, 10);
10944 	if (!errno && fd >= 0)
10945 		n->ndup.dupfd = fd;
10946 	else if (LONE_DASH(text))
10947 		n->ndup.dupfd = -1;
10948 	else {
10949 		if (err)
10950 			raise_error_syntax("bad fd number");
10951 		n->ndup.vname = makename();
10952 	}
10953 }
10954 
10955 /*
10956  * Returns true if the text contains nothing to expand (no dollar signs
10957  * or backquotes).
10958  */
10959 static int
noexpand(const char * text)10960 noexpand(const char *text)
10961 {
10962 	unsigned char c;
10963 
10964 	while ((c = *text++) != '\0') {
10965 		if (c == CTLQUOTEMARK)
10966 			continue;
10967 		if (c == CTLESC)
10968 			text++;
10969 		else if (SIT(c, BASESYNTAX) == CCTL)
10970 			return 0;
10971 	}
10972 	return 1;
10973 }
10974 
10975 static void
parsefname(void)10976 parsefname(void)
10977 {
10978 	union node *n = redirnode;
10979 
10980 	if (readtoken() != TWORD)
10981 		raise_error_unexpected_syntax(-1);
10982 	if (n->type == NHERE) {
10983 		struct heredoc *here = heredoc;
10984 		struct heredoc *p;
10985 		int i;
10986 
10987 		if (quoteflag == 0)
10988 			n->type = NXHERE;
10989 		TRACE(("Here document %d\n", n->type));
10990 		if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10991 			raise_error_syntax("illegal eof marker for << redirection");
10992 		rmescapes(wordtext, 0);
10993 		here->eofmark = wordtext;
10994 		here->next = NULL;
10995 		if (heredoclist == NULL)
10996 			heredoclist = here;
10997 		else {
10998 			for (p = heredoclist; p->next; p = p->next)
10999 				continue;
11000 			p->next = here;
11001 		}
11002 	} else if (n->type == NTOFD || n->type == NFROMFD) {
11003 		fixredir(n, wordtext, 0);
11004 	} else {
11005 		n->nfile.fname = makename();
11006 	}
11007 }
11008 
11009 static union node *
simplecmd(void)11010 simplecmd(void)
11011 {
11012 	union node *args, **app;
11013 	union node *n = NULL;
11014 	union node *vars, **vpp;
11015 	union node **rpp, *redir;
11016 	int savecheckkwd;
11017 #if ENABLE_ASH_BASH_COMPAT
11018 	smallint double_brackets_flag = 0;
11019 	smallint function_flag = 0;
11020 #endif
11021 
11022 	args = NULL;
11023 	app = &args;
11024 	vars = NULL;
11025 	vpp = &vars;
11026 	redir = NULL;
11027 	rpp = &redir;
11028 
11029 	savecheckkwd = CHKALIAS;
11030 	for (;;) {
11031 		int t;
11032 		checkkwd = savecheckkwd;
11033 		t = readtoken();
11034 		switch (t) {
11035 #if ENABLE_ASH_BASH_COMPAT
11036 		case TFUNCTION:
11037 			if (peektoken() != TWORD)
11038 				raise_error_unexpected_syntax(TWORD);
11039 			function_flag = 1;
11040 			break;
11041 		case TAND: /* "&&" */
11042 		case TOR: /* "||" */
11043 			if (!double_brackets_flag) {
11044 				tokpushback = 1;
11045 				goto out;
11046 			}
11047 			wordtext = (char *) (t == TAND ? "-a" : "-o");
11048 #endif
11049 		case TWORD:
11050 			n = stzalloc(sizeof(struct narg));
11051 			n->type = NARG;
11052 			/*n->narg.next = NULL; - stzalloc did it */
11053 			n->narg.text = wordtext;
11054 #if ENABLE_ASH_BASH_COMPAT
11055 			if (strcmp("[[", wordtext) == 0)
11056 				double_brackets_flag = 1;
11057 			else if (strcmp("]]", wordtext) == 0)
11058 				double_brackets_flag = 0;
11059 #endif
11060 			n->narg.backquote = backquotelist;
11061 			if (savecheckkwd && isassignment(wordtext)) {
11062 				*vpp = n;
11063 				vpp = &n->narg.next;
11064 			} else {
11065 				*app = n;
11066 				app = &n->narg.next;
11067 				savecheckkwd = 0;
11068 			}
11069 #if ENABLE_ASH_BASH_COMPAT
11070 			if (function_flag) {
11071 				checkkwd = CHKNL | CHKKWD;
11072 				switch (peektoken()) {
11073 				case TBEGIN:
11074 				case TIF:
11075 				case TCASE:
11076 				case TUNTIL:
11077 				case TWHILE:
11078 				case TFOR:
11079 					goto do_func;
11080 				case TLP:
11081 					function_flag = 0;
11082 					break;
11083 				case TWORD:
11084 					if (strcmp("[[", wordtext) == 0)
11085 						goto do_func;
11086 					/* fall through */
11087 				default:
11088 					raise_error_unexpected_syntax(-1);
11089 				}
11090 			}
11091 #endif
11092 			break;
11093 		case TREDIR:
11094 			*rpp = n = redirnode;
11095 			rpp = &n->nfile.next;
11096 			parsefname();   /* read name of redirection file */
11097 			break;
11098 		case TLP:
11099  IF_ASH_BASH_COMPAT(do_func:)
11100 			if (args && app == &args->narg.next
11101 			 && !vars && !redir
11102 			) {
11103 				struct builtincmd *bcmd;
11104 				const char *name;
11105 
11106 				/* We have a function */
11107 				if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
11108 					raise_error_unexpected_syntax(TRP);
11109 				name = n->narg.text;
11110 				if (!goodname(name)
11111 				 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11112 				) {
11113 					raise_error_syntax("bad function name");
11114 				}
11115 				n->type = NDEFUN;
11116 				checkkwd = CHKNL | CHKKWD | CHKALIAS;
11117 				n->narg.next = parse_command();
11118 				return n;
11119 			}
11120 			IF_ASH_BASH_COMPAT(function_flag = 0;)
11121 			/* fall through */
11122 		default:
11123 			tokpushback = 1;
11124 			goto out;
11125 		}
11126 	}
11127  out:
11128 	*app = NULL;
11129 	*vpp = NULL;
11130 	*rpp = NULL;
11131 	n = stzalloc(sizeof(struct ncmd));
11132 	n->type = NCMD;
11133 	n->ncmd.args = args;
11134 	n->ncmd.assign = vars;
11135 	n->ncmd.redirect = redir;
11136 	return n;
11137 }
11138 
11139 static union node *
parse_command(void)11140 parse_command(void)
11141 {
11142 	union node *n1, *n2;
11143 	union node *ap, **app;
11144 	union node *cp, **cpp;
11145 	union node *redir, **rpp;
11146 	union node **rpp2;
11147 	int t;
11148 
11149 	redir = NULL;
11150 	rpp2 = &redir;
11151 
11152 	switch (readtoken()) {
11153 	default:
11154 		raise_error_unexpected_syntax(-1);
11155 		/* NOTREACHED */
11156 	case TIF:
11157 		n1 = stzalloc(sizeof(struct nif));
11158 		n1->type = NIF;
11159 		n1->nif.test = list(0);
11160 		if (readtoken() != TTHEN)
11161 			raise_error_unexpected_syntax(TTHEN);
11162 		n1->nif.ifpart = list(0);
11163 		n2 = n1;
11164 		while (readtoken() == TELIF) {
11165 			n2->nif.elsepart = stzalloc(sizeof(struct nif));
11166 			n2 = n2->nif.elsepart;
11167 			n2->type = NIF;
11168 			n2->nif.test = list(0);
11169 			if (readtoken() != TTHEN)
11170 				raise_error_unexpected_syntax(TTHEN);
11171 			n2->nif.ifpart = list(0);
11172 		}
11173 		if (lasttoken == TELSE)
11174 			n2->nif.elsepart = list(0);
11175 		else {
11176 			n2->nif.elsepart = NULL;
11177 			tokpushback = 1;
11178 		}
11179 		t = TFI;
11180 		break;
11181 	case TWHILE:
11182 	case TUNTIL: {
11183 		int got;
11184 		n1 = stzalloc(sizeof(struct nbinary));
11185 		n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
11186 		n1->nbinary.ch1 = list(0);
11187 		got = readtoken();
11188 		if (got != TDO) {
11189 			TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
11190 					got == TWORD ? wordtext : ""));
11191 			raise_error_unexpected_syntax(TDO);
11192 		}
11193 		n1->nbinary.ch2 = list(0);
11194 		t = TDONE;
11195 		break;
11196 	}
11197 	case TFOR:
11198 		if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
11199 			raise_error_syntax("bad for loop variable");
11200 		n1 = stzalloc(sizeof(struct nfor));
11201 		n1->type = NFOR;
11202 		n1->nfor.var = wordtext;
11203 		checkkwd = CHKNL | CHKKWD | CHKALIAS;
11204 		if (readtoken() == TIN) {
11205 			app = &ap;
11206 			while (readtoken() == TWORD) {
11207 				n2 = stzalloc(sizeof(struct narg));
11208 				n2->type = NARG;
11209 				/*n2->narg.next = NULL; - stzalloc did it */
11210 				n2->narg.text = wordtext;
11211 				n2->narg.backquote = backquotelist;
11212 				*app = n2;
11213 				app = &n2->narg.next;
11214 			}
11215 			*app = NULL;
11216 			n1->nfor.args = ap;
11217 			if (lasttoken != TNL && lasttoken != TSEMI)
11218 				raise_error_unexpected_syntax(-1);
11219 		} else {
11220 			n2 = stzalloc(sizeof(struct narg));
11221 			n2->type = NARG;
11222 			/*n2->narg.next = NULL; - stzalloc did it */
11223 			n2->narg.text = (char *)dolatstr;
11224 			/*n2->narg.backquote = NULL;*/
11225 			n1->nfor.args = n2;
11226 			/*
11227 			 * Newline or semicolon here is optional (but note
11228 			 * that the original Bourne shell only allowed NL).
11229 			 */
11230 			if (lasttoken != TSEMI)
11231 				tokpushback = 1;
11232 		}
11233 		checkkwd = CHKNL | CHKKWD | CHKALIAS;
11234 		if (readtoken() != TDO)
11235 			raise_error_unexpected_syntax(TDO);
11236 		n1->nfor.body = list(0);
11237 		t = TDONE;
11238 		break;
11239 	case TCASE:
11240 		n1 = stzalloc(sizeof(struct ncase));
11241 		n1->type = NCASE;
11242 		if (readtoken() != TWORD)
11243 			raise_error_unexpected_syntax(TWORD);
11244 		n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
11245 		n2->type = NARG;
11246 		/*n2->narg.next = NULL; - stzalloc did it */
11247 		n2->narg.text = wordtext;
11248 		n2->narg.backquote = backquotelist;
11249 		checkkwd = CHKNL | CHKKWD | CHKALIAS;
11250 		if (readtoken() != TIN)
11251 			raise_error_unexpected_syntax(TIN);
11252 		cpp = &n1->ncase.cases;
11253  next_case:
11254 		checkkwd = CHKNL | CHKKWD;
11255 		t = readtoken();
11256 		while (t != TESAC) {
11257 			if (lasttoken == TLP)
11258 				readtoken();
11259 			*cpp = cp = stzalloc(sizeof(struct nclist));
11260 			cp->type = NCLIST;
11261 			app = &cp->nclist.pattern;
11262 			for (;;) {
11263 				*app = ap = stzalloc(sizeof(struct narg));
11264 				ap->type = NARG;
11265 				/*ap->narg.next = NULL; - stzalloc did it */
11266 				ap->narg.text = wordtext;
11267 				ap->narg.backquote = backquotelist;
11268 				if (readtoken() != TPIPE)
11269 					break;
11270 				app = &ap->narg.next;
11271 				readtoken();
11272 			}
11273 			//ap->narg.next = NULL;
11274 			if (lasttoken != TRP)
11275 				raise_error_unexpected_syntax(TRP);
11276 			cp->nclist.body = list(2);
11277 
11278 			cpp = &cp->nclist.next;
11279 
11280 			checkkwd = CHKNL | CHKKWD;
11281 			t = readtoken();
11282 			if (t != TESAC) {
11283 				if (t != TENDCASE)
11284 					raise_error_unexpected_syntax(TENDCASE);
11285 				goto next_case;
11286 			}
11287 		}
11288 		*cpp = NULL;
11289 		goto redir;
11290 	case TLP:
11291 		n1 = stzalloc(sizeof(struct nredir));
11292 		n1->type = NSUBSHELL;
11293 		n1->nredir.n = list(0);
11294 		/*n1->nredir.redirect = NULL; - stzalloc did it */
11295 		t = TRP;
11296 		break;
11297 	case TBEGIN:
11298 		n1 = list(0);
11299 		t = TEND;
11300 		break;
11301 	IF_ASH_BASH_COMPAT(case TFUNCTION:)
11302 	case TWORD:
11303 	case TREDIR:
11304 		tokpushback = 1;
11305 		return simplecmd();
11306 	}
11307 
11308 	if (readtoken() != t)
11309 		raise_error_unexpected_syntax(t);
11310 
11311  redir:
11312 	/* Now check for redirection which may follow command */
11313 	checkkwd = CHKKWD | CHKALIAS;
11314 	rpp = rpp2;
11315 	while (readtoken() == TREDIR) {
11316 		*rpp = n2 = redirnode;
11317 		rpp = &n2->nfile.next;
11318 		parsefname();
11319 	}
11320 	tokpushback = 1;
11321 	*rpp = NULL;
11322 	if (redir) {
11323 		if (n1->type != NSUBSHELL) {
11324 			n2 = stzalloc(sizeof(struct nredir));
11325 			n2->type = NREDIR;
11326 			n2->nredir.n = n1;
11327 			n1 = n2;
11328 		}
11329 		n1->nredir.redirect = redir;
11330 	}
11331 	return n1;
11332 }
11333 
11334 #if ENABLE_ASH_BASH_COMPAT
11335 static int
decode_dollar_squote(void)11336 decode_dollar_squote(void)
11337 {
11338 	static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11339 	int c, cnt;
11340 	char *p;
11341 	char buf[4];
11342 
11343 	c = pgetc();
11344 	p = strchr(C_escapes, c);
11345 	if (p) {
11346 		buf[0] = c;
11347 		p = buf;
11348 		cnt = 3;
11349 		if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11350 			do {
11351 				c = pgetc();
11352 				*++p = c;
11353 			} while ((unsigned char)(c - '0') <= 7 && --cnt);
11354 			pungetc();
11355 		} else if (c == 'x') { /* \xHH */
11356 			do {
11357 				c = pgetc();
11358 				*++p = c;
11359 			} while (isxdigit(c) && --cnt);
11360 			pungetc();
11361 			if (cnt == 3) { /* \x but next char is "bad" */
11362 				c = 'x';
11363 				goto unrecognized;
11364 			}
11365 		} else { /* simple seq like \\ or \t */
11366 			p++;
11367 		}
11368 		*p = '\0';
11369 		p = buf;
11370 		c = bb_process_escape_sequence((void*)&p);
11371 	} else { /* unrecognized "\z": print both chars unless ' or " */
11372 		if (c != '\'' && c != '"') {
11373  unrecognized:
11374 			c |= 0x100; /* "please encode \, then me" */
11375 		}
11376 	}
11377 	return c;
11378 }
11379 #endif
11380 
11381 /*
11382  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
11383  * is not NULL, read a here document.  In the latter case, eofmark is the
11384  * word which marks the end of the document and striptabs is true if
11385  * leading tabs should be stripped from the document.  The argument c
11386  * is the first character of the input token or document.
11387  *
11388  * Because C does not have internal subroutines, I have simulated them
11389  * using goto's to implement the subroutine linkage.  The following macros
11390  * will run code that appears at the end of readtoken1.
11391  */
11392 #define CHECKEND()      {goto checkend; checkend_return:;}
11393 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
11394 #define PARSESUB()      {goto parsesub; parsesub_return:;}
11395 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11396 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11397 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
11398 static int
readtoken1(int c,int syntax,char * eofmark,int striptabs)11399 readtoken1(int c, int syntax, char *eofmark, int striptabs)
11400 {
11401 	/* NB: syntax parameter fits into smallint */
11402 	/* c parameter is an unsigned char or PEOF or PEOA */
11403 	char *out;
11404 	size_t len;
11405 	char line[EOFMARKLEN + 1];
11406 	struct nodelist *bqlist;
11407 	smallint quotef;
11408 	smallint dblquote;
11409 	smallint oldstyle;
11410 	IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
11411 #if ENABLE_ASH_EXPAND_PRMT
11412 	smallint pssyntax;   /* we are expanding a prompt string */
11413 #endif
11414 	int varnest;         /* levels of variables expansion */
11415 	IF_FEATURE_SH_MATH(int arinest;)    /* levels of arithmetic expansion */
11416 	IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
11417 	int dqvarnest;       /* levels of variables expansion within double quotes */
11418 
11419 	IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
11420 
11421 	startlinno = g_parsefile->linno;
11422 	bqlist = NULL;
11423 	quotef = 0;
11424 	IF_FEATURE_SH_MATH(prevsyntax = 0;)
11425 #if ENABLE_ASH_EXPAND_PRMT
11426 	pssyntax = (syntax == PSSYNTAX);
11427 	if (pssyntax)
11428 		syntax = DQSYNTAX;
11429 #endif
11430 	dblquote = (syntax == DQSYNTAX);
11431 	varnest = 0;
11432 	IF_FEATURE_SH_MATH(arinest = 0;)
11433 	IF_FEATURE_SH_MATH(parenlevel = 0;)
11434 	dqvarnest = 0;
11435 
11436 	STARTSTACKSTR(out);
11437  loop:
11438 	/* For each line, until end of word */
11439 	CHECKEND();     /* set c to PEOF if at end of here document */
11440 	for (;;) {      /* until end of line or end of word */
11441 		CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
11442 		switch (SIT(c, syntax)) {
11443 		case CNL:       /* '\n' */
11444 			if (syntax == BASESYNTAX)
11445 				goto endword;   /* exit outer loop */
11446 			USTPUTC(c, out);
11447 			nlprompt();
11448 			c = pgetc();
11449 			goto loop;              /* continue outer loop */
11450 		case CWORD:
11451 			USTPUTC(c, out);
11452 			break;
11453 		case CCTL:
11454 #if ENABLE_ASH_BASH_COMPAT
11455 			if (c == '\\' && bash_dollar_squote) {
11456 				c = decode_dollar_squote();
11457 				if (c == '\0') {
11458 					/* skip $'\000', $'\x00' (like bash) */
11459 					break;
11460 				}
11461 				if (c & 0x100) {
11462 					/* Unknown escape. Encode as '\z' */
11463 					c = (unsigned char)c;
11464 					if (eofmark == NULL || dblquote)
11465 						USTPUTC(CTLESC, out);
11466 					USTPUTC('\\', out);
11467 				}
11468 			}
11469 #endif
11470 			if (eofmark == NULL || dblquote)
11471 				USTPUTC(CTLESC, out);
11472 			USTPUTC(c, out);
11473 			break;
11474 		case CBACK:     /* backslash */
11475 			c = pgetc_without_PEOA();
11476 			if (c == PEOF) {
11477 				USTPUTC(CTLESC, out);
11478 				USTPUTC('\\', out);
11479 				pungetc();
11480 			} else if (c == '\n') {
11481 				nlprompt();
11482 			} else {
11483 #if ENABLE_ASH_EXPAND_PRMT
11484 				if (c == '$' && pssyntax) {
11485 					USTPUTC(CTLESC, out);
11486 					USTPUTC('\\', out);
11487 				}
11488 #endif
11489 				/* Backslash is retained if we are in "str" and next char isn't special */
11490 				if (dblquote
11491 				 && c != '\\'
11492 				 && c != '`'
11493 				 && c != '$'
11494 				 && (c != '"' || eofmark != NULL)
11495 				) {
11496 					USTPUTC('\\', out);
11497 				}
11498 				USTPUTC(CTLESC, out);
11499 				USTPUTC(c, out);
11500 				quotef = 1;
11501 			}
11502 			break;
11503 		case CSQUOTE:
11504 			syntax = SQSYNTAX;
11505  quotemark:
11506 			if (eofmark == NULL) {
11507 				USTPUTC(CTLQUOTEMARK, out);
11508 			}
11509 			break;
11510 		case CDQUOTE:
11511 			syntax = DQSYNTAX;
11512 			dblquote = 1;
11513 			goto quotemark;
11514 		case CENDQUOTE:
11515 			IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11516 			if (eofmark != NULL && varnest == 0) {
11517 				USTPUTC(c, out);
11518 			} else {
11519 				if (dqvarnest == 0) {
11520 					syntax = BASESYNTAX;
11521 					dblquote = 0;
11522 				}
11523 				quotef = 1;
11524 				goto quotemark;
11525 			}
11526 			break;
11527 		case CVAR:      /* '$' */
11528 			PARSESUB();             /* parse substitution */
11529 			break;
11530 		case CENDVAR:   /* '}' */
11531 			if (varnest > 0) {
11532 				varnest--;
11533 				if (dqvarnest > 0) {
11534 					dqvarnest--;
11535 				}
11536 				c = CTLENDVAR;
11537 			}
11538 			USTPUTC(c, out);
11539 			break;
11540 #if ENABLE_FEATURE_SH_MATH
11541 		case CLP:       /* '(' in arithmetic */
11542 			parenlevel++;
11543 			USTPUTC(c, out);
11544 			break;
11545 		case CRP:       /* ')' in arithmetic */
11546 			if (parenlevel > 0) {
11547 				parenlevel--;
11548 			} else {
11549 				if (pgetc_eatbnl() == ')') {
11550 					c = CTLENDARI;
11551 					if (--arinest == 0) {
11552 						syntax = prevsyntax;
11553 					}
11554 				} else {
11555 					/*
11556 					 * unbalanced parens
11557 					 * (don't 2nd guess - no error)
11558 					 */
11559 					pungetc();
11560 				}
11561 			}
11562 			USTPUTC(c, out);
11563 			break;
11564 #endif
11565 		case CBQUOTE:   /* '`' */
11566 			PARSEBACKQOLD();
11567 			break;
11568 		case CENDFILE:
11569 			goto endword;           /* exit outer loop */
11570 		case CIGN:
11571 			break;
11572 		default:
11573 			if (varnest == 0) {
11574 #if ENABLE_ASH_BASH_COMPAT
11575 				if (c == '&') {
11576 //Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
11577 					if (pgetc() == '>')
11578 						c = 0x100 + '>'; /* flag &> */
11579 					pungetc();
11580 				}
11581 #endif
11582 				goto endword;   /* exit outer loop */
11583 			}
11584 			IF_ASH_ALIAS(if (c != PEOA))
11585 				USTPUTC(c, out);
11586 		}
11587 		c = pgetc();
11588 	} /* for (;;) */
11589  endword:
11590 
11591 #if ENABLE_FEATURE_SH_MATH
11592 	if (syntax == ARISYNTAX)
11593 		raise_error_syntax("missing '))'");
11594 #endif
11595 	if (syntax != BASESYNTAX && eofmark == NULL)
11596 		raise_error_syntax("unterminated quoted string");
11597 	if (varnest != 0) {
11598 		startlinno = g_parsefile->linno;
11599 		/* { */
11600 		raise_error_syntax("missing '}'");
11601 	}
11602 	USTPUTC('\0', out);
11603 	len = out - (char *)stackblock();
11604 	out = stackblock();
11605 	if (eofmark == NULL) {
11606 		if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
11607 		 && quotef == 0
11608 		) {
11609 			if (isdigit_str9(out)) {
11610 				PARSEREDIR(); /* passed as params: out, c */
11611 				lasttoken = TREDIR;
11612 				return lasttoken;
11613 			}
11614 			/* else: non-number X seen, interpret it
11615 			 * as "NNNX>file" = "NNNX >file" */
11616 		}
11617 		pungetc();
11618 	}
11619 	quoteflag = quotef;
11620 	backquotelist = bqlist;
11621 	grabstackblock(len);
11622 	wordtext = out;
11623 	lasttoken = TWORD;
11624 	return lasttoken;
11625 /* end of readtoken routine */
11626 
11627 /*
11628  * Check to see whether we are at the end of the here document.  When this
11629  * is called, c is set to the first character of the next input line.  If
11630  * we are at the end of the here document, this routine sets the c to PEOF.
11631  */
11632 checkend: {
11633 	if (eofmark) {
11634 #if ENABLE_ASH_ALIAS
11635 		if (c == PEOA)
11636 			c = pgetc_without_PEOA();
11637 #endif
11638 		if (striptabs) {
11639 			while (c == '\t') {
11640 				c = pgetc_without_PEOA();
11641 			}
11642 		}
11643 		if (c == *eofmark) {
11644 			if (pfgets(line, sizeof(line)) != NULL) {
11645 				char *p, *q;
11646 				int cc;
11647 
11648 				p = line;
11649 				for (q = eofmark + 1;; p++, q++) {
11650 					cc = *p;
11651 					if (cc == '\n')
11652 						cc = 0;
11653 					if (!*q || cc != *q)
11654 						break;
11655 				}
11656 				if (cc == *q) {
11657 					c = PEOF;
11658 					nlnoprompt();
11659 				} else {
11660 					pushstring(line, NULL);
11661 				}
11662 			}
11663 		}
11664 	}
11665 	goto checkend_return;
11666 }
11667 
11668 /*
11669  * Parse a redirection operator.  The variable "out" points to a string
11670  * specifying the fd to be redirected.  The variable "c" contains the
11671  * first character of the redirection operator.
11672  */
11673 parseredir: {
11674 	/* out is already checked to be a valid number or "" */
11675 	int fd = (*out == '\0' ? -1 : atoi(out));
11676 	union node *np;
11677 
11678 	np = stzalloc(sizeof(struct nfile));
11679 	if (c == '>') {
11680 		np->nfile.fd = 1;
11681 		c = pgetc();
11682 		if (c == '>')
11683 			np->type = NAPPEND;
11684 		else if (c == '|')
11685 			np->type = NCLOBBER;
11686 		else if (c == '&')
11687 			np->type = NTOFD;
11688 			/* it also can be NTO2 (>&file), but we can't figure it out yet */
11689 		else {
11690 			np->type = NTO;
11691 			pungetc();
11692 		}
11693 	}
11694 #if ENABLE_ASH_BASH_COMPAT
11695 	else if (c == 0x100 + '>') { /* this flags &> redirection */
11696 		np->nfile.fd = 1;
11697 		pgetc(); /* this is '>', no need to check */
11698 		np->type = NTO2;
11699 	}
11700 #endif
11701 	else { /* c == '<' */
11702 		/*np->nfile.fd = 0; - stzalloc did it */
11703 		c = pgetc();
11704 		switch (c) {
11705 		case '<':
11706 			if (sizeof(struct nfile) != sizeof(struct nhere)) {
11707 				np = stzalloc(sizeof(struct nhere));
11708 				/*np->nfile.fd = 0; - stzalloc did it */
11709 			}
11710 			np->type = NHERE;
11711 			heredoc = stzalloc(sizeof(struct heredoc));
11712 			heredoc->here = np;
11713 			c = pgetc();
11714 			if (c == '-') {
11715 				heredoc->striptabs = 1;
11716 			} else {
11717 				/*heredoc->striptabs = 0; - stzalloc did it */
11718 				pungetc();
11719 			}
11720 			break;
11721 
11722 		case '&':
11723 			np->type = NFROMFD;
11724 			break;
11725 
11726 		case '>':
11727 			np->type = NFROMTO;
11728 			break;
11729 
11730 		default:
11731 			np->type = NFROM;
11732 			pungetc();
11733 			break;
11734 		}
11735 	}
11736 	if (fd >= 0)
11737 		np->nfile.fd = fd;
11738 	redirnode = np;
11739 	goto parseredir_return;
11740 }
11741 
11742 /*
11743  * Parse a substitution.  At this point, we have read the dollar sign
11744  * and nothing else.
11745  */
11746 
11747 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11748  * (assuming ascii char codes, as the original implementation did) */
11749 #define is_special(c) \
11750 	(((unsigned)(c) - 33 < 32) \
11751 			&& ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11752 parsesub: {
11753 	unsigned char subtype;
11754 	int typeloc;
11755 
11756 	c = pgetc_eatbnl();
11757 	if (c > 255 /* PEOA or PEOF */
11758 	 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11759 	) {
11760 #if ENABLE_ASH_BASH_COMPAT
11761 		if (syntax != DQSYNTAX && c == '\'')
11762 			bash_dollar_squote = 1;
11763 		else
11764 #endif
11765 			USTPUTC('$', out);
11766 		pungetc();
11767 	} else if (c == '(') {
11768 		/* $(command) or $((arith)) */
11769 		if (pgetc_eatbnl() == '(') {
11770 #if ENABLE_FEATURE_SH_MATH
11771 			PARSEARITH();
11772 #else
11773 			raise_error_syntax("you disabled math support for $((arith)) syntax");
11774 #endif
11775 		} else {
11776 			pungetc();
11777 			PARSEBACKQNEW();
11778 		}
11779 	} else {
11780 		/* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
11781 		USTPUTC(CTLVAR, out);
11782 		typeloc = out - (char *)stackblock();
11783 		STADJUST(1, out);
11784 		subtype = VSNORMAL;
11785 		if (c == '{') {
11786 			c = pgetc_eatbnl();
11787 			subtype = 0;
11788 		}
11789  varname:
11790 		if (is_name(c)) {
11791 			/* $[{[#]]NAME[}] */
11792 			do {
11793 				STPUTC(c, out);
11794 				c = pgetc_eatbnl();
11795 			} while (is_in_name(c));
11796 		} else if (isdigit(c)) {
11797 			/* $[{[#]]NUM[}] */
11798 			do {
11799 				STPUTC(c, out);
11800 				c = pgetc_eatbnl();
11801 			} while (isdigit(c));
11802 		} else if (is_special(c)) {
11803 			/* $[{[#]]<specialchar>[}] */
11804 			int cc = c;
11805 
11806 			c = pgetc_eatbnl();
11807 			if (!subtype && cc == '#') {
11808 				subtype = VSLENGTH;
11809 				if (c == '_' || isalnum(c))
11810 					goto varname;
11811 				cc = c;
11812 				c = pgetc_eatbnl();
11813 				if (cc == '}' || c != '}') {
11814 					pungetc();
11815 					subtype = 0;
11816 					c = cc;
11817 					cc = '#';
11818 				}
11819 			}
11820 			USTPUTC(cc, out);
11821 		} else {
11822 			goto badsub;
11823 		}
11824 		if (c != '}' && subtype == VSLENGTH) {
11825 			/* ${#VAR didn't end with } */
11826 			goto badsub;
11827 		}
11828 
11829 		if (subtype == 0) {
11830 			static const char types[] ALIGN1 = "}-+?=";
11831 			/* ${VAR...} but not $VAR or ${#VAR} */
11832 			/* c == first char after VAR */
11833 			switch (c) {
11834 			case ':':
11835 				c = pgetc_eatbnl();
11836 #if ENABLE_ASH_BASH_COMPAT
11837 				/* This check is only needed to not misinterpret
11838 				 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11839 				 * constructs.
11840 				 */
11841 				if (!strchr(types, c)) {
11842 					subtype = VSSUBSTR;
11843 					pungetc();
11844 					break; /* "goto badsub" is bigger (!) */
11845 				}
11846 #endif
11847 				subtype = VSNUL;
11848 				/*FALLTHROUGH*/
11849 			default: {
11850 				const char *p = strchr(types, c);
11851 				if (p == NULL)
11852 					break;
11853 				subtype |= p - types + VSNORMAL;
11854 				break;
11855 			}
11856 			case '%':
11857 			case '#': {
11858 				int cc = c;
11859 				subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
11860 				c = pgetc_eatbnl();
11861 				if (c != cc)
11862 					goto badsub;
11863 				subtype++;
11864 				break;
11865 			}
11866 #if ENABLE_ASH_BASH_COMPAT
11867 			case '/':
11868 				/* ${v/[/]pattern/repl} */
11869 //TODO: encode pattern and repl separately.
11870 // Currently ${v/$var_with_slash/repl} is horribly broken
11871 				subtype = VSREPLACE;
11872 				c = pgetc_eatbnl();
11873 				if (c != '/')
11874 					goto badsub;
11875 				subtype++; /* VSREPLACEALL */
11876 				break;
11877 #endif
11878 			}
11879 		} else {
11880  badsub:
11881 			pungetc();
11882 		}
11883 		((unsigned char *)stackblock())[typeloc] = subtype;
11884 		if (subtype != VSNORMAL) {
11885 			varnest++;
11886 			if (dblquote)
11887 				dqvarnest++;
11888 		}
11889 		STPUTC('=', out);
11890 	}
11891 	goto parsesub_return;
11892 }
11893 
11894 /*
11895  * Called to parse command substitutions.  Newstyle is set if the command
11896  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11897  * list of commands (passed by reference), and savelen is the number of
11898  * characters on the top of the stack which must be preserved.
11899  */
11900 parsebackq: {
11901 	struct nodelist **nlpp;
11902 	union node *n;
11903 	char *str;
11904 	size_t savelen;
11905 	smallint saveprompt = 0;
11906 
11907 	str = NULL;
11908 	savelen = out - (char *)stackblock();
11909 	if (savelen > 0) {
11910 		/*
11911 		 * FIXME: this can allocate very large block on stack and SEGV.
11912 		 * Example:
11913 		 * echo "..<100kbytes>..`true` $(true) `true` ..."
11914 		 * allocates 100kb for every command subst. With about
11915 		 * a hundred command substitutions stack overflows.
11916 		 * With larger prepended string, SEGV happens sooner.
11917 		 */
11918 		str = alloca(savelen);
11919 		memcpy(str, stackblock(), savelen);
11920 	}
11921 
11922 	if (oldstyle) {
11923 		/* We must read until the closing backquote, giving special
11924 		 * treatment to some slashes, and then push the string and
11925 		 * reread it as input, interpreting it normally.
11926 		 */
11927 		char *pout;
11928 		size_t psavelen;
11929 		char *pstr;
11930 
11931 		STARTSTACKSTR(pout);
11932 		for (;;) {
11933 			int pc;
11934 
11935 			setprompt_if(needprompt, 2);
11936 			pc = pgetc();
11937 			switch (pc) {
11938 			case '`':
11939 				goto done;
11940 
11941 			case '\\':
11942 				pc = pgetc();
11943 				if (pc == '\n') {
11944 					nlprompt();
11945 					/*
11946 					 * If eating a newline, avoid putting
11947 					 * the newline into the new character
11948 					 * stream (via the STPUTC after the
11949 					 * switch).
11950 					 */
11951 					continue;
11952 				}
11953 				if (pc != '\\' && pc != '`' && pc != '$'
11954 				 && (!dblquote || pc != '"')
11955 				) {
11956 					STPUTC('\\', pout);
11957 				}
11958 				if (pc <= 255 /* not PEOA or PEOF */) {
11959 					break;
11960 				}
11961 				/* fall through */
11962 
11963 			case PEOF:
11964 			IF_ASH_ALIAS(case PEOA:)
11965 				startlinno = g_parsefile->linno;
11966 				raise_error_syntax("EOF in backquote substitution");
11967 
11968 			case '\n':
11969 				nlnoprompt();
11970 				break;
11971 
11972 			default:
11973 				break;
11974 			}
11975 			STPUTC(pc, pout);
11976 		}
11977  done:
11978 		STPUTC('\0', pout);
11979 		psavelen = pout - (char *)stackblock();
11980 		if (psavelen > 0) {
11981 			pstr = grabstackstr(pout);
11982 			setinputstring(pstr);
11983 		}
11984 	}
11985 	nlpp = &bqlist;
11986 	while (*nlpp)
11987 		nlpp = &(*nlpp)->next;
11988 	*nlpp = stzalloc(sizeof(**nlpp));
11989 	/* (*nlpp)->next = NULL; - stzalloc did it */
11990 
11991 	if (oldstyle) {
11992 		saveprompt = doprompt;
11993 		doprompt = 0;
11994 	}
11995 
11996 	n = list(2);
11997 
11998 	if (oldstyle)
11999 		doprompt = saveprompt;
12000 	else if (readtoken() != TRP)
12001 		raise_error_unexpected_syntax(TRP);
12002 
12003 	(*nlpp)->n = n;
12004 	if (oldstyle) {
12005 		/*
12006 		 * Start reading from old file again, ignoring any pushed back
12007 		 * tokens left from the backquote parsing
12008 		 */
12009 		popfile();
12010 		tokpushback = 0;
12011 	}
12012 	while (stackblocksize() <= savelen)
12013 		growstackblock();
12014 	STARTSTACKSTR(out);
12015 	if (str) {
12016 		memcpy(out, str, savelen);
12017 		STADJUST(savelen, out);
12018 	}
12019 	USTPUTC(CTLBACKQ, out);
12020 	if (oldstyle)
12021 		goto parsebackq_oldreturn;
12022 	goto parsebackq_newreturn;
12023 }
12024 
12025 #if ENABLE_FEATURE_SH_MATH
12026 /*
12027  * Parse an arithmetic expansion (indicate start of one and set state)
12028  */
12029 parsearith: {
12030 	if (++arinest == 1) {
12031 		prevsyntax = syntax;
12032 		syntax = ARISYNTAX;
12033 	}
12034 	USTPUTC(CTLARI, out);
12035 	goto parsearith_return;
12036 }
12037 #endif
12038 } /* end of readtoken */
12039 
12040 /*
12041  * Read the next input token.
12042  * If the token is a word, we set backquotelist to the list of cmds in
12043  *      backquotes.  We set quoteflag to true if any part of the word was
12044  *      quoted.
12045  * If the token is TREDIR, then we set redirnode to a structure containing
12046  *      the redirection.
12047  * In all cases, the variable startlinno is set to the number of the line
12048  *      on which the token starts.
12049  *
12050  * [Change comment:  here documents and internal procedures]
12051  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
12052  *  word parsing code into a separate routine.  In this case, readtoken
12053  *  doesn't need to have any internal procedures, but parseword does.
12054  *  We could also make parseoperator in essence the main routine, and
12055  *  have parseword (readtoken1?) handle both words and redirection.]
12056  */
12057 #define NEW_xxreadtoken
12058 #ifdef NEW_xxreadtoken
12059 /* singles must be first! */
12060 static const char xxreadtoken_chars[7] ALIGN1 = {
12061 	'\n', '(', ')', /* singles */
12062 	'&', '|', ';',  /* doubles */
12063 	0
12064 };
12065 
12066 #define xxreadtoken_singles 3
12067 #define xxreadtoken_doubles 3
12068 
12069 static const char xxreadtoken_tokens[] ALIGN1 = {
12070 	TNL, TLP, TRP,          /* only single occurrence allowed */
12071 	TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12072 	TEOF,                   /* corresponds to trailing nul */
12073 	TAND, TOR, TENDCASE     /* if double occurrence */
12074 };
12075 
12076 static int
xxreadtoken(void)12077 xxreadtoken(void)
12078 {
12079 	int c;
12080 
12081 	if (tokpushback) {
12082 		tokpushback = 0;
12083 		return lasttoken;
12084 	}
12085 	setprompt_if(needprompt, 2);
12086 	startlinno = g_parsefile->linno;
12087 	for (;;) {                      /* until token or start of word found */
12088 		c = pgetc();
12089 		if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
12090 			continue;
12091 
12092 		if (c == '#') {
12093 			while ((c = pgetc()) != '\n' && c != PEOF)
12094 				continue;
12095 			pungetc();
12096 		} else if (c == '\\') {
12097 			if (pgetc() != '\n') {
12098 				pungetc();
12099 				break; /* return readtoken1(...) */
12100 			}
12101 			nlprompt();
12102 		} else {
12103 			const char *p;
12104 
12105 			p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12106 			if (c != PEOF) {
12107 				if (c == '\n') {
12108 					nlnoprompt();
12109 				}
12110 
12111 				p = strchr(xxreadtoken_chars, c);
12112 				if (p == NULL)
12113 					break; /* return readtoken1(...) */
12114 
12115 				if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12116 					int cc = pgetc();
12117 					if (cc == c) {    /* double occurrence? */
12118 						p += xxreadtoken_doubles + 1;
12119 					} else {
12120 						pungetc();
12121 #if ENABLE_ASH_BASH_COMPAT
12122 						if (c == '&' && cc == '>') /* &> */
12123 							break; /* return readtoken1(...) */
12124 #endif
12125 					}
12126 				}
12127 			}
12128 			lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12129 			return lasttoken;
12130 		}
12131 	} /* for (;;) */
12132 
12133 	return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
12134 }
12135 #else /* old xxreadtoken */
12136 #define RETURN(token)   return lasttoken = token
12137 static int
xxreadtoken(void)12138 xxreadtoken(void)
12139 {
12140 	int c;
12141 
12142 	if (tokpushback) {
12143 		tokpushback = 0;
12144 		return lasttoken;
12145 	}
12146 	setprompt_if(needprompt, 2);
12147 	startlinno = g_parsefile->linno;
12148 	for (;;) {      /* until token or start of word found */
12149 		c = pgetc();
12150 		switch (c) {
12151 		case ' ': case '\t':
12152 		IF_ASH_ALIAS(case PEOA:)
12153 			continue;
12154 		case '#':
12155 			while ((c = pgetc()) != '\n' && c != PEOF)
12156 				continue;
12157 			pungetc();
12158 			continue;
12159 		case '\\':
12160 			if (pgetc() == '\n') {
12161 				nlprompt();
12162 				continue;
12163 			}
12164 			pungetc();
12165 			goto breakloop;
12166 		case '\n':
12167 			nlnoprompt();
12168 			RETURN(TNL);
12169 		case PEOF:
12170 			RETURN(TEOF);
12171 		case '&':
12172 			if (pgetc() == '&')
12173 				RETURN(TAND);
12174 			pungetc();
12175 			RETURN(TBACKGND);
12176 		case '|':
12177 			if (pgetc() == '|')
12178 				RETURN(TOR);
12179 			pungetc();
12180 			RETURN(TPIPE);
12181 		case ';':
12182 			if (pgetc() == ';')
12183 				RETURN(TENDCASE);
12184 			pungetc();
12185 			RETURN(TSEMI);
12186 		case '(':
12187 			RETURN(TLP);
12188 		case ')':
12189 			RETURN(TRP);
12190 		default:
12191 			goto breakloop;
12192 		}
12193 	}
12194  breakloop:
12195 	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12196 #undef RETURN
12197 }
12198 #endif /* old xxreadtoken */
12199 
12200 static int
readtoken(void)12201 readtoken(void)
12202 {
12203 	int t;
12204 	int kwd = checkkwd;
12205 #if DEBUG
12206 	smallint alreadyseen = tokpushback;
12207 #endif
12208 
12209 #if ENABLE_ASH_ALIAS
12210  top:
12211 #endif
12212 
12213 	t = xxreadtoken();
12214 
12215 	/*
12216 	 * eat newlines
12217 	 */
12218 	if (kwd & CHKNL) {
12219 		while (t == TNL) {
12220 			parseheredoc();
12221 			t = xxreadtoken();
12222 		}
12223 	}
12224 
12225 	if (t != TWORD || quoteflag) {
12226 		goto out;
12227 	}
12228 
12229 	/*
12230 	 * check for keywords
12231 	 */
12232 	if (kwd & CHKKWD) {
12233 		const char *const *pp;
12234 
12235 		pp = findkwd(wordtext);
12236 		if (pp) {
12237 			lasttoken = t = pp - tokname_array;
12238 			TRACE(("keyword '%s' recognized\n", tokname_array[t]));
12239 			goto out;
12240 		}
12241 	}
12242 
12243 	if (checkkwd & CHKALIAS) {
12244 #if ENABLE_ASH_ALIAS
12245 		struct alias *ap;
12246 		ap = lookupalias(wordtext, 1);
12247 		if (ap != NULL) {
12248 			if (*ap->val) {
12249 				pushstring(ap->val, ap);
12250 			}
12251 			goto top;
12252 		}
12253 #endif
12254 	}
12255  out:
12256 	checkkwd = 0;
12257 #if DEBUG
12258 	if (!alreadyseen)
12259 		TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12260 	else
12261 		TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12262 #endif
12263 	return t;
12264 }
12265 
12266 static int
peektoken(void)12267 peektoken(void)
12268 {
12269 	int t;
12270 
12271 	t = readtoken();
12272 	tokpushback = 1;
12273 	return t;
12274 }
12275 
12276 /*
12277  * Read and parse a command.  Returns NODE_EOF on end of file.
12278  * (NULL is a valid parse tree indicating a blank line.)
12279  */
12280 static union node *
parsecmd(int interact)12281 parsecmd(int interact)
12282 {
12283 	tokpushback = 0;
12284 	checkkwd = 0;
12285 	heredoclist = 0;
12286 	doprompt = interact;
12287 	setprompt_if(doprompt, doprompt);
12288 	needprompt = 0;
12289 	return list(1);
12290 }
12291 
12292 /*
12293  * Input any here documents.
12294  */
12295 static void
parseheredoc(void)12296 parseheredoc(void)
12297 {
12298 	struct heredoc *here;
12299 	union node *n;
12300 
12301 	here = heredoclist;
12302 	heredoclist = NULL;
12303 
12304 	while (here) {
12305 		setprompt_if(needprompt, 2);
12306 		readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
12307 				here->eofmark, here->striptabs);
12308 		n = stzalloc(sizeof(struct narg));
12309 		n->narg.type = NARG;
12310 		/*n->narg.next = NULL; - stzalloc did it */
12311 		n->narg.text = wordtext;
12312 		n->narg.backquote = backquotelist;
12313 		here->here->nhere.doc = n;
12314 		here = here->next;
12315 	}
12316 }
12317 
12318 
12319 /*
12320  * called by editline -- any expansions to the prompt should be added here.
12321  */
12322 #if ENABLE_ASH_EXPAND_PRMT
12323 static const char *
expandstr(const char * ps)12324 expandstr(const char *ps)
12325 {
12326 	union node n;
12327 	int saveprompt;
12328 
12329 	/* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12330 	 * and token processing _can_ alter it (delete NULs etc). */
12331 	setinputstring((char *)ps);
12332 
12333 	saveprompt = doprompt;
12334 	doprompt = 0;
12335 	readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
12336 	doprompt = saveprompt;
12337 
12338 	popfile();
12339 
12340 	n.narg.type = NARG;
12341 	n.narg.next = NULL;
12342 	n.narg.text = wordtext;
12343 	n.narg.backquote = backquotelist;
12344 
12345 	expandarg(&n, NULL, EXP_QUOTED);
12346 	return stackblock();
12347 }
12348 #endif
12349 
12350 /*
12351  * Execute a command or commands contained in a string.
12352  */
12353 static int
evalstring(char * s,int flags)12354 evalstring(char *s, int flags)
12355 {
12356 	struct jmploc *volatile savehandler;
12357 	struct jmploc jmploc;
12358 	int ex;
12359 
12360 	union node *n;
12361 	struct stackmark smark;
12362 	int status;
12363 
12364 	s = sstrdup(s);
12365 	setinputstring(s);
12366 	setstackmark(&smark);
12367 
12368 	status = 0;
12369 	/* On exception inside execution loop, we must popfile().
12370 	 * Try interactively:
12371 	 *	readonly a=a
12372 	 *	command eval "a=b"  # throws "is read only" error
12373 	 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12374 	 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12375 	 */
12376 	savehandler = exception_handler;
12377 	ex = setjmp(jmploc.loc);
12378 	if (ex)
12379 		goto out;
12380 	exception_handler = &jmploc;
12381 
12382 	while ((n = parsecmd(0)) != NODE_EOF) {
12383 		int i;
12384 
12385 		i = evaltree(n, flags);
12386 		if (n)
12387 			status = i;
12388 		popstackmark(&smark);
12389 		if (evalskip)
12390 			break;
12391 	}
12392  out:
12393 	popstackmark(&smark);
12394 	popfile();
12395 	stunalloc(s);
12396 
12397 	exception_handler = savehandler;
12398 	if (ex)
12399                 longjmp(exception_handler->loc, ex);
12400 
12401 	return status;
12402 }
12403 
12404 /*
12405  * The eval command.
12406  */
12407 static int FAST_FUNC
evalcmd(int argc UNUSED_PARAM,char ** argv,int flags)12408 evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
12409 {
12410 	char *p;
12411 	char *concat;
12412 
12413 	if (argv[1]) {
12414 		p = argv[1];
12415 		argv += 2;
12416 		if (argv[0]) {
12417 			STARTSTACKSTR(concat);
12418 			for (;;) {
12419 				concat = stack_putstr(p, concat);
12420 				p = *argv++;
12421 				if (p == NULL)
12422 					break;
12423 				STPUTC(' ', concat);
12424 			}
12425 			STPUTC('\0', concat);
12426 			p = grabstackstr(concat);
12427 		}
12428 		return evalstring(p, flags & EV_TESTED);
12429 	}
12430 	return 0;
12431 }
12432 
12433 /*
12434  * Read and execute commands.
12435  * "Top" is nonzero for the top level command loop;
12436  * it turns on prompting if the shell is interactive.
12437  */
12438 static int
cmdloop(int top)12439 cmdloop(int top)
12440 {
12441 	union node *n;
12442 	struct stackmark smark;
12443 	int inter;
12444 	int status = 0;
12445 	int numeof = 0;
12446 
12447 	TRACE(("cmdloop(%d) called\n", top));
12448 	for (;;) {
12449 		int skip;
12450 
12451 		setstackmark(&smark);
12452 #if JOBS
12453 		if (doing_jobctl)
12454 			showjobs(SHOW_CHANGED|SHOW_STDERR);
12455 #endif
12456 		inter = 0;
12457 		if (iflag && top) {
12458 			inter++;
12459 			chkmail();
12460 		}
12461 		n = parsecmd(inter);
12462 #if DEBUG
12463 		if (DEBUG > 2 && debug && (n != NODE_EOF))
12464 			showtree(n);
12465 #endif
12466 		if (n == NODE_EOF) {
12467 			if (!top || numeof >= 50)
12468 				break;
12469 			if (!stoppedjobs()) {
12470 				if (!Iflag)
12471 					break;
12472 				out2str("\nUse \"exit\" to leave shell.\n");
12473 			}
12474 			numeof++;
12475 		} else if (nflag == 0) {
12476 			int i;
12477 
12478 			/* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12479 			job_warning >>= 1;
12480 			numeof = 0;
12481 			i = evaltree(n, 0);
12482 			if (n)
12483 				status = i;
12484 		}
12485 		popstackmark(&smark);
12486 		skip = evalskip;
12487 
12488 		if (skip) {
12489 			evalskip &= ~SKIPFUNC;
12490 			break;
12491 		}
12492 	}
12493 	return status;
12494 }
12495 
12496 /*
12497  * Take commands from a file.  To be compatible we should do a path
12498  * search for the file, which is necessary to find sub-commands.
12499  */
12500 static char *
find_dot_file(char * name)12501 find_dot_file(char *name)
12502 {
12503 	char *fullname;
12504 	const char *path = pathval();
12505 	struct stat statb;
12506 
12507 	/* don't try this for absolute or relative paths */
12508 	if (strchr(name, '/'))
12509 		return name;
12510 
12511 	/* IIRC standards do not say whether . is to be searched.
12512 	 * And it is even smaller this way, making it unconditional for now:
12513 	 */
12514 	if (1) { /* ENABLE_ASH_BASH_COMPAT */
12515 		fullname = name;
12516 		goto try_cur_dir;
12517 	}
12518 
12519 	while ((fullname = path_advance(&path, name)) != NULL) {
12520  try_cur_dir:
12521 		if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12522 			/*
12523 			 * Don't bother freeing here, since it will
12524 			 * be freed by the caller.
12525 			 */
12526 			return fullname;
12527 		}
12528 		if (fullname != name)
12529 			stunalloc(fullname);
12530 	}
12531 
12532 	/* not found in the PATH */
12533 	ash_msg_and_raise_error("%s: not found", name);
12534 	/* NOTREACHED */
12535 }
12536 
12537 static int FAST_FUNC
dotcmd(int argc_ UNUSED_PARAM,char ** argv_ UNUSED_PARAM)12538 dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
12539 {
12540 	/* "false; . empty_file; echo $?" should print 0, not 1: */
12541 	int status = 0;
12542 	char *fullname;
12543 	char **argv;
12544 	struct strlist *sp;
12545 	volatile struct shparam saveparam;
12546 
12547 	for (sp = cmdenviron; sp; sp = sp->next)
12548 		setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
12549 
12550 	nextopt(nullstr); /* handle possible "--" */
12551 	argv = argptr;
12552 
12553 	if (!argv[0]) {
12554 		/* bash says: "bash: .: filename argument required" */
12555 		return 2; /* bash compat */
12556 	}
12557 
12558 	/* This aborts if file isn't found, which is POSIXly correct.
12559 	 * bash returns exitcode 1 instead.
12560 	 */
12561 	fullname = find_dot_file(argv[0]);
12562 	argv++;
12563 	if (argv[0]) { /* . FILE ARGS, ARGS exist */
12564 		int argc;
12565 		saveparam = shellparam;
12566 		shellparam.malloced = 0;
12567 		argc = 1;
12568 		while (argv[argc])
12569 			argc++;
12570 		shellparam.nparam = argc;
12571 		shellparam.p = argv;
12572 	};
12573 
12574 	/* This aborts if file can't be opened, which is POSIXly correct.
12575 	 * bash returns exitcode 1 instead.
12576 	 */
12577 	setinputfile(fullname, INPUT_PUSH_FILE);
12578 	commandname = fullname;
12579 	status = cmdloop(0);
12580 	popfile();
12581 
12582 	if (argv[0]) {
12583 		freeparam(&shellparam);
12584 		shellparam = saveparam;
12585 	};
12586 
12587 	return status;
12588 }
12589 
12590 static int FAST_FUNC
exitcmd(int argc UNUSED_PARAM,char ** argv)12591 exitcmd(int argc UNUSED_PARAM, char **argv)
12592 {
12593 	if (stoppedjobs())
12594 		return 0;
12595 	if (argv[1])
12596 		exitstatus = number(argv[1]);
12597 	raise_exception(EXEXIT);
12598 	/* NOTREACHED */
12599 }
12600 
12601 /*
12602  * Read a file containing shell functions.
12603  */
12604 static void
readcmdfile(char * name)12605 readcmdfile(char *name)
12606 {
12607 	setinputfile(name, INPUT_PUSH_FILE);
12608 	cmdloop(0);
12609 	popfile();
12610 }
12611 
12612 
12613 /* ============ find_command inplementation */
12614 
12615 /*
12616  * Resolve a command name.  If you change this routine, you may have to
12617  * change the shellexec routine as well.
12618  */
12619 static void
find_command(char * name,struct cmdentry * entry,int act,const char * path)12620 find_command(char *name, struct cmdentry *entry, int act, const char *path)
12621 {
12622 	struct tblentry *cmdp;
12623 	int idx;
12624 	int prev;
12625 	char *fullname;
12626 	struct stat statb;
12627 	int e;
12628 	int updatetbl;
12629 	struct builtincmd *bcmd;
12630 
12631 	/* If name contains a slash, don't use PATH or hash table */
12632 	if (strchr(name, '/') != NULL) {
12633 		entry->u.index = -1;
12634 		if (act & DO_ABS) {
12635 			while (stat(name, &statb) < 0) {
12636 #ifdef SYSV
12637 				if (errno == EINTR)
12638 					continue;
12639 #endif
12640 				entry->cmdtype = CMDUNKNOWN;
12641 				return;
12642 			}
12643 		}
12644 		entry->cmdtype = CMDNORMAL;
12645 		return;
12646 	}
12647 
12648 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12649 
12650 	updatetbl = (path == pathval());
12651 	if (!updatetbl) {
12652 		act |= DO_ALTPATH;
12653 		if (strstr(path, "%builtin") != NULL)
12654 			act |= DO_ALTBLTIN;
12655 	}
12656 
12657 	/* If name is in the table, check answer will be ok */
12658 	cmdp = cmdlookup(name, 0);
12659 	if (cmdp != NULL) {
12660 		int bit;
12661 
12662 		switch (cmdp->cmdtype) {
12663 		default:
12664 #if DEBUG
12665 			abort();
12666 #endif
12667 		case CMDNORMAL:
12668 			bit = DO_ALTPATH;
12669 			break;
12670 		case CMDFUNCTION:
12671 			bit = DO_NOFUNC;
12672 			break;
12673 		case CMDBUILTIN:
12674 			bit = DO_ALTBLTIN;
12675 			break;
12676 		}
12677 		if (act & bit) {
12678 			updatetbl = 0;
12679 			cmdp = NULL;
12680 		} else if (cmdp->rehash == 0)
12681 			/* if not invalidated by cd, we're done */
12682 			goto success;
12683 	}
12684 
12685 	/* If %builtin not in path, check for builtin next */
12686 	bcmd = find_builtin(name);
12687 	if (bcmd) {
12688 		if (IS_BUILTIN_REGULAR(bcmd))
12689 			goto builtin_success;
12690 		if (act & DO_ALTPATH) {
12691 			if (!(act & DO_ALTBLTIN))
12692 				goto builtin_success;
12693 		} else if (builtinloc <= 0) {
12694 			goto builtin_success;
12695 		}
12696 	}
12697 
12698 #if ENABLE_FEATURE_SH_STANDALONE
12699 	{
12700 		int applet_no = find_applet_by_name(name);
12701 		if (applet_no >= 0) {
12702 			entry->cmdtype = CMDNORMAL;
12703 			entry->u.index = -2 - applet_no;
12704 			return;
12705 		}
12706 	}
12707 #endif
12708 
12709 	/* We have to search path. */
12710 	prev = -1;              /* where to start */
12711 	if (cmdp && cmdp->rehash) {     /* doing a rehash */
12712 		if (cmdp->cmdtype == CMDBUILTIN)
12713 			prev = builtinloc;
12714 		else
12715 			prev = cmdp->param.index;
12716 	}
12717 
12718 	e = ENOENT;
12719 	idx = -1;
12720  loop:
12721 	while ((fullname = path_advance(&path, name)) != NULL) {
12722 		stunalloc(fullname);
12723 		/* NB: code below will still use fullname
12724 		 * despite it being "unallocated" */
12725 		idx++;
12726 		if (pathopt) {
12727 			if (prefix(pathopt, "builtin")) {
12728 				if (bcmd)
12729 					goto builtin_success;
12730 				continue;
12731 			}
12732 			if ((act & DO_NOFUNC)
12733 			 || !prefix(pathopt, "func")
12734 			) {     /* ignore unimplemented options */
12735 				continue;
12736 			}
12737 		}
12738 		/* if rehash, don't redo absolute path names */
12739 		if (fullname[0] == '/' && idx <= prev) {
12740 			if (idx < prev)
12741 				continue;
12742 			TRACE(("searchexec \"%s\": no change\n", name));
12743 			goto success;
12744 		}
12745 		while (stat(fullname, &statb) < 0) {
12746 #ifdef SYSV
12747 			if (errno == EINTR)
12748 				continue;
12749 #endif
12750 			if (errno != ENOENT && errno != ENOTDIR)
12751 				e = errno;
12752 			goto loop;
12753 		}
12754 		e = EACCES;     /* if we fail, this will be the error */
12755 		if (!S_ISREG(statb.st_mode))
12756 			continue;
12757 		if (pathopt) {          /* this is a %func directory */
12758 			stalloc(strlen(fullname) + 1);
12759 			/* NB: stalloc will return space pointed by fullname
12760 			 * (because we don't have any intervening allocations
12761 			 * between stunalloc above and this stalloc) */
12762 			readcmdfile(fullname);
12763 			cmdp = cmdlookup(name, 0);
12764 			if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12765 				ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12766 			stunalloc(fullname);
12767 			goto success;
12768 		}
12769 		TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12770 		if (!updatetbl) {
12771 			entry->cmdtype = CMDNORMAL;
12772 			entry->u.index = idx;
12773 			return;
12774 		}
12775 		INT_OFF;
12776 		cmdp = cmdlookup(name, 1);
12777 		cmdp->cmdtype = CMDNORMAL;
12778 		cmdp->param.index = idx;
12779 		INT_ON;
12780 		goto success;
12781 	}
12782 
12783 	/* We failed.  If there was an entry for this command, delete it */
12784 	if (cmdp && updatetbl)
12785 		delete_cmd_entry();
12786 	if (act & DO_ERR)
12787 		ash_msg("%s: %s", name, errmsg(e, "not found"));
12788 	entry->cmdtype = CMDUNKNOWN;
12789 	return;
12790 
12791  builtin_success:
12792 	if (!updatetbl) {
12793 		entry->cmdtype = CMDBUILTIN;
12794 		entry->u.cmd = bcmd;
12795 		return;
12796 	}
12797 	INT_OFF;
12798 	cmdp = cmdlookup(name, 1);
12799 	cmdp->cmdtype = CMDBUILTIN;
12800 	cmdp->param.cmd = bcmd;
12801 	INT_ON;
12802  success:
12803 	cmdp->rehash = 0;
12804 	entry->cmdtype = cmdp->cmdtype;
12805 	entry->u = cmdp->param;
12806 }
12807 
12808 
12809 /*
12810  * The trap builtin.
12811  */
12812 static int FAST_FUNC
trapcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)12813 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12814 {
12815 	char *action;
12816 	char **ap;
12817 	int signo, exitcode;
12818 
12819 	nextopt(nullstr);
12820 	ap = argptr;
12821 	if (!*ap) {
12822 		for (signo = 0; signo < NSIG; signo++) {
12823 			char *tr = trap_ptr[signo];
12824 			if (tr) {
12825 				/* note: bash adds "SIG", but only if invoked
12826 				 * as "bash". If called as "sh", or if set -o posix,
12827 				 * then it prints short signal names.
12828 				 * We are printing short names: */
12829 				out1fmt("trap -- %s %s\n",
12830 						single_quote(tr),
12831 						get_signame(signo));
12832 		/* trap_ptr != trap only if we are in special-cased `trap` code.
12833 		 * In this case, we will exit very soon, no need to free(). */
12834 				/* if (trap_ptr != trap && tp[0]) */
12835 				/*	free(tr); */
12836 			}
12837 		}
12838 		/*
12839 		if (trap_ptr != trap) {
12840 			free(trap_ptr);
12841 			trap_ptr = trap;
12842 		}
12843 		*/
12844 		return 0;
12845 	}
12846 
12847 	action = NULL;
12848 	if (ap[1])
12849 		action = *ap++;
12850 	exitcode = 0;
12851 	while (*ap) {
12852 		signo = get_signum(*ap);
12853 		if (signo < 0) {
12854 			/* Mimic bash message exactly */
12855 			ash_msg("%s: invalid signal specification", *ap);
12856 			exitcode = 1;
12857 			goto next;
12858 		}
12859 		INT_OFF;
12860 		if (action) {
12861 			if (LONE_DASH(action))
12862 				action = NULL;
12863 			else {
12864 				if (action[0]) /* not NULL and not "" and not "-" */
12865 					may_have_traps = 1;
12866 				action = ckstrdup(action);
12867 			}
12868 		}
12869 		free(trap[signo]);
12870 		trap[signo] = action;
12871 		if (signo != 0)
12872 			setsignal(signo);
12873 		INT_ON;
12874  next:
12875 		ap++;
12876 	}
12877 	return exitcode;
12878 }
12879 
12880 
12881 /* ============ Builtins */
12882 
12883 #if ENABLE_ASH_HELP
12884 static int FAST_FUNC
helpcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)12885 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12886 {
12887 	unsigned col;
12888 	unsigned i;
12889 
12890 	out1fmt(
12891 		"Built-in commands:\n"
12892 		"------------------\n");
12893 	for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12894 		col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12895 					builtintab[i].name + 1);
12896 		if (col > 60) {
12897 			out1fmt("\n");
12898 			col = 0;
12899 		}
12900 	}
12901 # if ENABLE_FEATURE_SH_STANDALONE
12902 	{
12903 		const char *a = applet_names;
12904 		while (*a) {
12905 			col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12906 			if (col > 60) {
12907 				out1fmt("\n");
12908 				col = 0;
12909 			}
12910 			while (*a++ != '\0')
12911 				continue;
12912 		}
12913 	}
12914 # endif
12915 	newline_and_flush(stdout);
12916 	return EXIT_SUCCESS;
12917 }
12918 #endif
12919 
12920 #if MAX_HISTORY
12921 static int FAST_FUNC
historycmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)12922 historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12923 {
12924 	show_history(line_input_state);
12925 	return EXIT_SUCCESS;
12926 }
12927 #endif
12928 
12929 /*
12930  * The export and readonly commands.
12931  */
12932 static int FAST_FUNC
exportcmd(int argc UNUSED_PARAM,char ** argv)12933 exportcmd(int argc UNUSED_PARAM, char **argv)
12934 {
12935 	struct var *vp;
12936 	char *name;
12937 	const char *p;
12938 	char **aptr;
12939 	char opt;
12940 	int flag;
12941 	int flag_off;
12942 
12943 	/* "readonly" in bash accepts, but ignores -n.
12944 	 * We do the same: it saves a conditional in nextopt's param.
12945 	 */
12946 	flag_off = 0;
12947 	while ((opt = nextopt("np")) != '\0') {
12948 		if (opt == 'n')
12949 			flag_off = VEXPORT;
12950 	}
12951 	flag = VEXPORT;
12952 	if (argv[0][0] == 'r') {
12953 		flag = VREADONLY;
12954 		flag_off = 0; /* readonly ignores -n */
12955 	}
12956 	flag_off = ~flag_off;
12957 
12958 	/*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12959 	{
12960 		aptr = argptr;
12961 		name = *aptr;
12962 		if (name) {
12963 			do {
12964 				p = strchr(name, '=');
12965 				if (p != NULL) {
12966 					p++;
12967 				} else {
12968 					vp = *findvar(hashvar(name), name);
12969 					if (vp) {
12970 						vp->flags = ((vp->flags | flag) & flag_off);
12971 						continue;
12972 					}
12973 				}
12974 				setvar(name, p, (flag & flag_off));
12975 			} while ((name = *++aptr) != NULL);
12976 			return 0;
12977 		}
12978 	}
12979 
12980 	/* No arguments. Show the list of exported or readonly vars.
12981 	 * -n is ignored.
12982 	 */
12983 	showvars(argv[0], flag, 0);
12984 	return 0;
12985 }
12986 
12987 /*
12988  * Delete a function if it exists.
12989  */
12990 static void
unsetfunc(const char * name)12991 unsetfunc(const char *name)
12992 {
12993 	struct tblentry *cmdp;
12994 
12995 	cmdp = cmdlookup(name, 0);
12996 	if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
12997 		delete_cmd_entry();
12998 }
12999 
13000 /*
13001  * The unset builtin command.  We unset the function before we unset the
13002  * variable to allow a function to be unset when there is a readonly variable
13003  * with the same name.
13004  */
13005 static int FAST_FUNC
unsetcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)13006 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13007 {
13008 	char **ap;
13009 	int i;
13010 	int flag = 0;
13011 	int ret = 0;
13012 
13013 	while ((i = nextopt("vf")) != 0) {
13014 		flag = i;
13015 	}
13016 
13017 	for (ap = argptr; *ap; ap++) {
13018 		if (flag != 'f') {
13019 			i = unsetvar(*ap);
13020 			ret |= i;
13021 			if (!(i & 2))
13022 				continue;
13023 		}
13024 		if (flag != 'v')
13025 			unsetfunc(*ap);
13026 	}
13027 	return ret & 1;
13028 }
13029 
13030 static const unsigned char timescmd_str[] ALIGN1 = {
13031 	' ',  offsetof(struct tms, tms_utime),
13032 	'\n', offsetof(struct tms, tms_stime),
13033 	' ',  offsetof(struct tms, tms_cutime),
13034 	'\n', offsetof(struct tms, tms_cstime),
13035 	0
13036 };
13037 static int FAST_FUNC
timescmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)13038 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13039 {
13040 	unsigned long clk_tck, s, t;
13041 	const unsigned char *p;
13042 	struct tms buf;
13043 
13044 	clk_tck = bb_clk_tck();
13045 	times(&buf);
13046 
13047 	p = timescmd_str;
13048 	do {
13049 		t = *(clock_t *)(((char *) &buf) + p[1]);
13050 		s = t / clk_tck;
13051 		t = t % clk_tck;
13052 		out1fmt("%lum%lu.%03lus%c",
13053 			s / 60, s % 60,
13054 			(t * 1000) / clk_tck,
13055 			p[0]);
13056 		p += 2;
13057 	} while (*p);
13058 
13059 	return 0;
13060 }
13061 
13062 #if ENABLE_FEATURE_SH_MATH
13063 /*
13064  * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
13065  * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
13066  *
13067  * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13068  */
13069 static int FAST_FUNC
letcmd(int argc UNUSED_PARAM,char ** argv)13070 letcmd(int argc UNUSED_PARAM, char **argv)
13071 {
13072 	arith_t i;
13073 
13074 	argv++;
13075 	if (!*argv)
13076 		ash_msg_and_raise_error("expression expected");
13077 	do {
13078 		i = ash_arith(*argv);
13079 	} while (*++argv);
13080 
13081 	return !i;
13082 }
13083 #endif
13084 
13085 /*
13086  * The read builtin. Options:
13087  *      -r              Do not interpret '\' specially
13088  *      -s              Turn off echo (tty only)
13089  *      -n NCHARS       Read NCHARS max
13090  *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
13091  *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
13092  *      -u FD           Read from given FD instead of fd 0
13093  * This uses unbuffered input, which may be avoidable in some cases.
13094  * TODO: bash also has:
13095  *      -a ARRAY        Read into array[0],[1],etc
13096  *      -d DELIM        End on DELIM char, not newline
13097  *      -e              Use line editing (tty only)
13098  */
13099 static int FAST_FUNC
readcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)13100 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13101 {
13102 	char *opt_n = NULL;
13103 	char *opt_p = NULL;
13104 	char *opt_t = NULL;
13105 	char *opt_u = NULL;
13106 	int read_flags = 0;
13107 	const char *r;
13108 	int i;
13109 
13110 	while ((i = nextopt("p:u:rt:n:s")) != '\0') {
13111 		switch (i) {
13112 		case 'p':
13113 			opt_p = optionarg;
13114 			break;
13115 		case 'n':
13116 			opt_n = optionarg;
13117 			break;
13118 		case 's':
13119 			read_flags |= BUILTIN_READ_SILENT;
13120 			break;
13121 		case 't':
13122 			opt_t = optionarg;
13123 			break;
13124 		case 'r':
13125 			read_flags |= BUILTIN_READ_RAW;
13126 			break;
13127 		case 'u':
13128 			opt_u = optionarg;
13129 			break;
13130 		default:
13131 			break;
13132 		}
13133 	}
13134 
13135 	/* "read -s" needs to save/restore termios, can't allow ^C
13136 	 * to jump out of it.
13137 	 */
13138 	INT_OFF;
13139 	r = shell_builtin_read(setvar0,
13140 		argptr,
13141 		bltinlookup("IFS"), /* can be NULL */
13142 		read_flags,
13143 		opt_n,
13144 		opt_p,
13145 		opt_t,
13146 		opt_u
13147 	);
13148 	INT_ON;
13149 
13150 	if ((uintptr_t)r > 1)
13151 		ash_msg_and_raise_error(r);
13152 
13153 	return (uintptr_t)r;
13154 }
13155 
13156 static int FAST_FUNC
umaskcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)13157 umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13158 {
13159 	static const char permuser[3] ALIGN1 = "ogu";
13160 
13161 	mode_t mask;
13162 	int symbolic_mode = 0;
13163 
13164 	while (nextopt("S") != '\0') {
13165 		symbolic_mode = 1;
13166 	}
13167 
13168 	INT_OFF;
13169 	mask = umask(0);
13170 	umask(mask);
13171 	INT_ON;
13172 
13173 	if (*argptr == NULL) {
13174 		if (symbolic_mode) {
13175 			char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
13176 			char *p = buf;
13177 			int i;
13178 
13179 			i = 2;
13180 			for (;;) {
13181 				*p++ = ',';
13182 				*p++ = permuser[i];
13183 				*p++ = '=';
13184 				/* mask is 0..0uuugggooo. i=2 selects uuu bits */
13185 				if (!(mask & 0400)) *p++ = 'r';
13186 				if (!(mask & 0200)) *p++ = 'w';
13187 				if (!(mask & 0100)) *p++ = 'x';
13188 				mask <<= 3;
13189 				if (--i < 0)
13190 					break;
13191 			}
13192 			*p = '\0';
13193 			puts(buf + 1);
13194 		} else {
13195 			out1fmt("%04o\n", mask);
13196 		}
13197 	} else {
13198 		char *modestr = *argptr;
13199                 /* numeric umasks are taken as-is */
13200                 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13201 		if (!isdigit(modestr[0]))
13202 			mask ^= 0777;
13203 		mask = bb_parse_mode(modestr, mask);
13204 		if ((unsigned)mask > 0777) {
13205 			ash_msg_and_raise_error("illegal mode: %s", modestr);
13206 		}
13207 		if (!isdigit(modestr[0]))
13208 			mask ^= 0777;
13209 		umask(mask);
13210 	}
13211 	return 0;
13212 }
13213 
13214 static int FAST_FUNC
ulimitcmd(int argc UNUSED_PARAM,char ** argv)13215 ulimitcmd(int argc UNUSED_PARAM, char **argv)
13216 {
13217 	return shell_builtin_ulimit(argv);
13218 }
13219 
13220 /* ============ main() and helpers */
13221 
13222 /*
13223  * Called to exit the shell.
13224  */
13225 static void
exitshell(void)13226 exitshell(void)
13227 {
13228 	struct jmploc loc;
13229 	char *p;
13230 	int status;
13231 
13232 #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13233 	save_history(line_input_state);
13234 #endif
13235 	status = exitstatus;
13236 	TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13237 	if (setjmp(loc.loc)) {
13238 		if (exception_type == EXEXIT)
13239 			status = exitstatus;
13240 		goto out;
13241 	}
13242 	exception_handler = &loc;
13243 	p = trap[0];
13244 	if (p) {
13245 		trap[0] = NULL;
13246 		evalskip = 0;
13247 		evalstring(p, 0);
13248 		/*free(p); - we'll exit soon */
13249 	}
13250  out:
13251 	/* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13252 	 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13253 	 */
13254 	setjobctl(0);
13255 	flush_stdout_stderr();
13256 	_exit(status);
13257 	/* NOTREACHED */
13258 }
13259 
13260 static void
init(void)13261 init(void)
13262 {
13263 	/* we will never free this */
13264 	basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
13265 
13266 	sigmode[SIGCHLD - 1] = S_DFL;
13267 	setsignal(SIGCHLD);
13268 
13269 	/* bash re-enables SIGHUP which is SIG_IGNed on entry.
13270 	 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13271 	 */
13272 	signal(SIGHUP, SIG_DFL);
13273 
13274 	{
13275 		char **envp;
13276 		const char *p;
13277 		struct stat st1, st2;
13278 
13279 		initvar();
13280 		for (envp = environ; envp && *envp; envp++) {
13281 			p = endofname(*envp);
13282 			if (p != *envp && *p == '=') {
13283 				setvareq(*envp, VEXPORT|VTEXTFIXED);
13284 			}
13285 		}
13286 
13287 		setvareq((char*)defoptindvar, VTEXTFIXED);
13288 
13289 		setvar0("PPID", utoa(getppid()));
13290 #if ENABLE_ASH_BASH_COMPAT
13291 		p = lookupvar("SHLVL");
13292 		setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
13293 		if (!lookupvar("HOSTNAME")) {
13294 			struct utsname uts;
13295 			uname(&uts);
13296 			setvar0("HOSTNAME", uts.nodename);
13297 		}
13298 #endif
13299 		p = lookupvar("PWD");
13300 		if (p) {
13301 			if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
13302 			 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13303 			) {
13304 				p = NULL;
13305 			}
13306 		}
13307 		setpwd(p, 0);
13308 	}
13309 }
13310 
13311 
13312 //usage:#define ash_trivial_usage
13313 //usage:	"[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
13314 //usage:#define ash_full_usage "\n\n"
13315 //usage:	"Unix shell interpreter"
13316 
13317 /*
13318  * Process the shell command line arguments.
13319  */
13320 static void
procargs(char ** argv)13321 procargs(char **argv)
13322 {
13323 	int i;
13324 	const char *xminusc;
13325 	char **xargv;
13326 
13327 	xargv = argv;
13328 	arg0 = xargv[0];
13329 	/* if (xargv[0]) - mmm, this is always true! */
13330 		xargv++;
13331 	for (i = 0; i < NOPTS; i++)
13332 		optlist[i] = 2;
13333 	argptr = xargv;
13334 	if (options(/*cmdline:*/ 1)) {
13335 		/* it already printed err message */
13336 		raise_exception(EXERROR);
13337 	}
13338 	xargv = argptr;
13339 	xminusc = minusc;
13340 	if (*xargv == NULL) {
13341 		if (xminusc)
13342 			ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13343 		sflag = 1;
13344 	}
13345 	if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13346 		iflag = 1;
13347 	if (mflag == 2)
13348 		mflag = iflag;
13349 	for (i = 0; i < NOPTS; i++)
13350 		if (optlist[i] == 2)
13351 			optlist[i] = 0;
13352 #if DEBUG == 2
13353 	debug = 1;
13354 #endif
13355 	/* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13356 	if (xminusc) {
13357 		minusc = *xargv++;
13358 		if (*xargv)
13359 			goto setarg0;
13360 	} else if (!sflag) {
13361 		setinputfile(*xargv, 0);
13362  setarg0:
13363 		arg0 = *xargv++;
13364 		commandname = arg0;
13365 	}
13366 
13367 	shellparam.p = xargv;
13368 #if ENABLE_ASH_GETOPTS
13369 	shellparam.optind = 1;
13370 	shellparam.optoff = -1;
13371 #endif
13372 	/* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13373 	while (*xargv) {
13374 		shellparam.nparam++;
13375 		xargv++;
13376 	}
13377 	optschanged();
13378 }
13379 
13380 /*
13381  * Read /etc/profile, ~/.profile, $ENV.
13382  */
13383 static void
read_profile(const char * name)13384 read_profile(const char *name)
13385 {
13386 	name = expandstr(name);
13387 	if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13388 		return;
13389 	cmdloop(0);
13390 	popfile();
13391 }
13392 
13393 /*
13394  * This routine is called when an error or an interrupt occurs in an
13395  * interactive shell and control is returned to the main command loop.
13396  * (In dash, this function is auto-generated by build machinery).
13397  */
13398 static void
reset(void)13399 reset(void)
13400 {
13401 	/* from eval.c: */
13402 	evalskip = 0;
13403 	loopnest = 0;
13404 
13405 	/* from expand.c: */
13406 	ifsfree();
13407 
13408 	/* from input.c: */
13409 	g_parsefile->left_in_buffer = 0;
13410 	g_parsefile->left_in_line = 0;      /* clear input buffer */
13411 	popallfiles();
13412 
13413 	/* from redir.c: */
13414 	while (redirlist)
13415 		popredir(/*drop:*/ 0, /*restore:*/ 0);
13416 }
13417 
13418 #if PROFILE
13419 static short profile_buf[16384];
13420 extern int etext();
13421 #endif
13422 
13423 /*
13424  * Main routine.  We initialize things, parse the arguments, execute
13425  * profiles if we're a login shell, and then call cmdloop to execute
13426  * commands.  The setjmp call sets up the location to jump to when an
13427  * exception occurs.  When an exception occurs the variable "state"
13428  * is used to figure out how far we had gotten.
13429  */
13430 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
ash_main(int argc UNUSED_PARAM,char ** argv)13431 int ash_main(int argc UNUSED_PARAM, char **argv)
13432 {
13433 	volatile smallint state;
13434 	struct jmploc jmploc;
13435 	struct stackmark smark;
13436 
13437 	/* Initialize global data */
13438 	INIT_G_misc();
13439 	INIT_G_memstack();
13440 	INIT_G_var();
13441 #if ENABLE_ASH_ALIAS
13442 	INIT_G_alias();
13443 #endif
13444 	INIT_G_cmdtable();
13445 
13446 #if PROFILE
13447 	monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13448 #endif
13449 
13450 #if ENABLE_FEATURE_EDITING
13451 	line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13452 #endif
13453 	state = 0;
13454 	if (setjmp(jmploc.loc)) {
13455 		smallint e;
13456 		smallint s;
13457 
13458 		reset();
13459 
13460 		e = exception_type;
13461 		s = state;
13462 		if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
13463 			exitshell();
13464 		}
13465 		if (e == EXINT) {
13466 			newline_and_flush(stderr);
13467 		}
13468 
13469 		popstackmark(&smark);
13470 		FORCE_INT_ON; /* enable interrupts */
13471 		if (s == 1)
13472 			goto state1;
13473 		if (s == 2)
13474 			goto state2;
13475 		if (s == 3)
13476 			goto state3;
13477 		goto state4;
13478 	}
13479 	exception_handler = &jmploc;
13480 	rootpid = getpid();
13481 
13482 	init();
13483 	setstackmark(&smark);
13484 	procargs(argv);
13485 #if DEBUG
13486 	TRACE(("Shell args: "));
13487 	trace_puts_args(argv);
13488 #endif
13489 
13490 	if (argv[0] && argv[0][0] == '-')
13491 		isloginsh = 1;
13492 	if (isloginsh) {
13493 		const char *hp;
13494 
13495 		state = 1;
13496 		read_profile("/etc/profile");
13497  state1:
13498 		state = 2;
13499 		hp = lookupvar("HOME");
13500 		if (hp)
13501 			read_profile("$HOME/.profile");
13502 	}
13503  state2:
13504 	state = 3;
13505 	if (
13506 #ifndef linux
13507 	 getuid() == geteuid() && getgid() == getegid() &&
13508 #endif
13509 	 iflag
13510 	) {
13511 		const char *shinit = lookupvar("ENV");
13512 		if (shinit != NULL && *shinit != '\0')
13513 			read_profile(shinit);
13514 	}
13515 	popstackmark(&smark);
13516  state3:
13517 	state = 4;
13518 	if (minusc) {
13519 		/* evalstring pushes parsefile stack.
13520 		 * Ensure we don't falsely claim that 0 (stdin)
13521 		 * is one of stacked source fds.
13522 		 * Testcase: ash -c 'exec 1>&0' must not complain. */
13523 		// if (!sflag) g_parsefile->pf_fd = -1;
13524 		// ^^ not necessary since now we special-case fd 0
13525 		// in is_hidden_fd() to not be considered "hidden fd"
13526 		evalstring(minusc, 0);
13527 	}
13528 
13529 	if (sflag || minusc == NULL) {
13530 #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
13531 		if (iflag) {
13532 			const char *hp = lookupvar("HISTFILE");
13533 			if (!hp) {
13534 				hp = lookupvar("HOME");
13535 				if (hp) {
13536 					hp = concat_path_file(hp, ".ash_history");
13537 					setvar0("HISTFILE", hp);
13538 					free((char*)hp);
13539 					hp = lookupvar("HISTFILE");
13540 				}
13541 			}
13542 			if (hp)
13543 				line_input_state->hist_file = hp;
13544 # if ENABLE_FEATURE_SH_HISTFILESIZE
13545 			hp = lookupvar("HISTFILESIZE");
13546 			line_input_state->max_history = size_from_HISTFILESIZE(hp);
13547 # endif
13548 		}
13549 #endif
13550  state4: /* XXX ??? - why isn't this before the "if" statement */
13551 		cmdloop(1);
13552 	}
13553 #if PROFILE
13554 	monitor(0);
13555 #endif
13556 #ifdef GPROF
13557 	{
13558 		extern void _mcleanup(void);
13559 		_mcleanup();
13560 	}
13561 #endif
13562 	TRACE(("End of main reached\n"));
13563 	exitshell();
13564 	/* NOTREACHED */
13565 }
13566 
13567 
13568 /*-
13569  * Copyright (c) 1989, 1991, 1993, 1994
13570  *      The Regents of the University of California.  All rights reserved.
13571  *
13572  * This code is derived from software contributed to Berkeley by
13573  * Kenneth Almquist.
13574  *
13575  * Redistribution and use in source and binary forms, with or without
13576  * modification, are permitted provided that the following conditions
13577  * are met:
13578  * 1. Redistributions of source code must retain the above copyright
13579  *    notice, this list of conditions and the following disclaimer.
13580  * 2. Redistributions in binary form must reproduce the above copyright
13581  *    notice, this list of conditions and the following disclaimer in the
13582  *    documentation and/or other materials provided with the distribution.
13583  * 3. Neither the name of the University nor the names of its contributors
13584  *    may be used to endorse or promote products derived from this software
13585  *    without specific prior written permission.
13586  *
13587  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13588  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13589  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13590  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13591  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13592  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13593  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13594  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13595  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13596  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13597  * SUCH DAMAGE.
13598  */
13599