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, "ed);
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 = ≈
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