docproc: avoid segfault during file closing
[busybox-git.git] / shell / ash.c
blob4ca4c6c56dfd8d68762b84eb078bb84f7feb0ff5
1 /* vi: set sw=4 ts=4: */
2 /*
3 * ash shell port for busybox
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
8 * Original BSD copyright notice is retained at the end of this file.
10 * Copyright (c) 1989, 1991, 1993, 1994
11 * The Regents of the University of California. All rights reserved.
13 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
14 * was re-ported from NetBSD and debianized.
16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
18 //config:config SHELL_ASH
19 //config: bool #hidden option
20 //config: depends on !NOMMU
21 //config:
22 //config:config ASH
23 //config: bool "ash (80 kb)"
24 //config: default y
25 //config: depends on !NOMMU
26 //config: select SHELL_ASH
27 //config: help
28 //config: The most complete and most pedantically correct shell included with
29 //config: busybox. This shell is actually a derivative of the Debian 'dash'
30 //config: shell (by Herbert Xu), which was created by porting the 'ash' shell
31 //config: (written by Kenneth Almquist) from NetBSD.
32 //config:
33 //config:# ash options
34 //config:# note: Don't remove !NOMMU part in the next line; it would break
35 //config:# menuconfig's indenting.
36 //config:if !NOMMU && (SHELL_ASH || ASH || SH_IS_ASH || BASH_IS_ASH)
37 //config:
38 //config:config ASH_OPTIMIZE_FOR_SIZE
39 //config: bool "Optimize for size instead of speed"
40 //config: default y
41 //config: depends on SHELL_ASH
42 //config:
43 //config:config ASH_INTERNAL_GLOB
44 //config: bool "Use internal glob() implementation"
45 //config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now
46 //config: depends on SHELL_ASH
47 //config: help
48 //config: Do not use glob() function from libc, use internal implementation.
49 //config: Use this if you are getting "glob.h: No such file or directory"
50 //config: or similar build errors.
51 //config: Note that as of now (2017-01), uclibc and musl glob() both have bugs
52 //config: which would break ash if you select N here.
53 //config:
54 //config:config ASH_BASH_COMPAT
55 //config: bool "bash-compatible extensions"
56 //config: default y
57 //config: depends on SHELL_ASH
58 //config:
59 //config:config ASH_BASH_SOURCE_CURDIR
60 //config: bool "'source' and '.' builtins search current directory after $PATH"
61 //config: default n # do not encourage non-standard behavior
62 //config: depends on ASH_BASH_COMPAT
63 //config: help
64 //config: This is not compliant with standards. Avoid if possible.
65 //config:
66 //config:config ASH_BASH_NOT_FOUND_HOOK
67 //config: bool "command_not_found_handle hook support"
68 //config: default y
69 //config: depends on ASH_BASH_COMPAT
70 //config: help
71 //config: Enable support for the 'command_not_found_handle' hook function,
72 //config: from GNU bash, which allows for alternative command not found
73 //config: handling.
74 //config:
75 //config:config ASH_JOB_CONTROL
76 //config: bool "Job control"
77 //config: default y
78 //config: depends on SHELL_ASH
79 //config:
80 //config:config ASH_ALIAS
81 //config: bool "Alias support"
82 //config: default y
83 //config: depends on SHELL_ASH
84 //config:
85 //config:config ASH_RANDOM_SUPPORT
86 //config: bool "Pseudorandom generator and $RANDOM variable"
87 //config: default y
88 //config: depends on SHELL_ASH
89 //config: help
90 //config: Enable pseudorandom generator and dynamic variable "$RANDOM".
91 //config: Each read of "$RANDOM" will generate a new pseudorandom value.
92 //config: You can reset the generator by using a specified start value.
93 //config: After "unset RANDOM" the generator will switch off and this
94 //config: variable will no longer have special treatment.
95 //config:
96 //config:config ASH_EXPAND_PRMT
97 //config: bool "Expand prompt string"
98 //config: default y
99 //config: depends on SHELL_ASH
100 //config: help
101 //config: $PS# may contain volatile content, such as backquote commands.
102 //config: This option recreates the prompt string from the environment
103 //config: variable each time it is displayed.
104 //config:
105 //config:config ASH_IDLE_TIMEOUT
106 //config: bool "Idle timeout variable $TMOUT"
107 //config: default y
108 //config: depends on SHELL_ASH
109 //config: help
110 //config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
111 //config:
112 //config:config ASH_MAIL
113 //config: bool "Check for new mail in interactive shell"
114 //config: default y
115 //config: depends on SHELL_ASH
116 //config: help
117 //config: Enable "check for new mail" function:
118 //config: if set, $MAIL file and $MAILPATH list of files
119 //config: are checked for mtime changes, and "you have mail"
120 //config: message is printed if change is detected.
121 //config:
122 //config:config ASH_ECHO
123 //config: bool "echo builtin"
124 //config: default y
125 //config: depends on SHELL_ASH
126 //config:
127 //config:config ASH_PRINTF
128 //config: bool "printf builtin"
129 //config: default y
130 //config: depends on SHELL_ASH
131 //config:
132 //config:config ASH_TEST
133 //config: bool "test builtin"
134 //config: default y
135 //config: depends on SHELL_ASH
136 //config:
138 ////config:config ASH_SLEEP
139 ////config: bool "sleep builtin"
140 ////config: default y
141 ////config: depends on SHELL_ASH
142 ////config:
143 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
144 //Disabled for now. Has a few annoying problems:
145 // * sleepcmd() -> sleep_main(), the parsing of bad arguments exits the shell.
146 // * sleep_for_duration() in sleep_main() has to be interruptible for
147 // ^C traps to work, which may be a problem for other users
148 // of sleep_for_duration().
149 // * BUT, if sleep_for_duration() is interruptible, then SIGCHLD interrupts it
150 // as well (try "/bin/sleep 1 & sleep 10").
151 // * sleep_main() must not allocate anything as ^C in ash longjmp's.
152 // (currently, allocations are only on error paths, in message printing).
154 //config:config ASH_HELP
155 //config: bool "help builtin"
156 //config: default y
157 //config: depends on SHELL_ASH
158 //config:
159 //config:config ASH_GETOPTS
160 //config: bool "getopts builtin"
161 //config: default y
162 //config: depends on SHELL_ASH
163 //config:
164 //config:config ASH_CMDCMD
165 //config: bool "command builtin"
166 //config: default y
167 //config: depends on SHELL_ASH
168 //config: help
169 //config: Enable support for the 'command' builtin, which allows
170 //config: you to run the specified command or builtin,
171 //config: even when there is a function with the same name.
172 //config:
173 //config:endif # ash options
175 //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
176 // APPLET_ODDNAME:name main location suid_type help
177 //applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
178 //applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
180 //kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o
181 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
184 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
185 * DEBUG=2 to compile in and turn on debugging.
186 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
187 * debugging info is written to ./trace, quit signal generates core dump.
189 #define DEBUG 0
190 /* Tweak debug output verbosity here */
191 #define DEBUG_TIME 0
192 #define DEBUG_PID 1
193 #define DEBUG_SIG 1
194 #define DEBUG_INTONOFF 0
196 #define PROFILE 0
198 #define JOBS ENABLE_ASH_JOB_CONTROL
200 #include <fnmatch.h>
201 #include <sys/times.h>
202 #include <sys/utsname.h> /* for setting $HOSTNAME */
203 #include "busybox.h" /* for applet_names */
204 #if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
205 # include "embedded_scripts.h"
206 #else
207 # define NUM_SCRIPTS 0
208 #endif
210 /* So far, all bash compat is controlled by one config option */
211 /* Separate defines document which part of code implements what */
212 /* function keyword */
213 #define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
214 #define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
215 /* &>file */
216 #define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
217 #define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
218 /* $'...' */
219 #define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
220 #define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
221 #define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
222 #define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
223 #define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
224 #define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
225 /* BASH_TEST2: [[ EXPR ]]
226 * Status of [[ support:
227 * && and || work as they should
228 * = is glob match operator, not equality operator: STR = GLOB
229 * == same as =
230 * =~ is regex match operator: STR =~ REGEX
231 * TODO:
232 * singleword+noglob expansion:
233 * v='a b'; [[ $v = 'a b' ]]; echo 0:$?
234 * [[ /bin/n* ]]; echo 0:$?
235 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
236 * ( ) < > should not have special meaning (IOW: should not require quoting)
237 * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*"
239 #define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
240 #define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
241 #define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
242 #define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
243 #define BASH_EPOCH_VARS ENABLE_ASH_BASH_COMPAT
244 #define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
245 #define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
246 #define BASH_READ_D ENABLE_ASH_BASH_COMPAT
247 #define IF_BASH_READ_D IF_ASH_BASH_COMPAT
248 #define BASH_WAIT_N ENABLE_ASH_BASH_COMPAT
249 /* <(...) and >(...) */
250 #if HAVE_DEV_FD
251 # define BASH_PROCESS_SUBST ENABLE_ASH_BASH_COMPAT
252 # define IF_BASH_PROCESS_SUBST IF_ASH_BASH_COMPAT
253 #else
254 # define BASH_PROCESS_SUBST 0
255 # define IF_BASH_PROCESS_SUBST(...)
256 #endif
258 #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
259 /* Bionic at least up to version 24 has no glob() */
260 # undef ENABLE_ASH_INTERNAL_GLOB
261 # define ENABLE_ASH_INTERNAL_GLOB 1
262 #endif
264 #if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
265 # error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
266 # error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
267 # error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
268 # error glob() should unbackslash them and match. uClibc does not unbackslash,
269 # error fails to match dirname, subsequently not expanding <pattern> in it.
270 // Testcase:
271 // if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
272 // if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
273 #endif
275 #if !ENABLE_ASH_INTERNAL_GLOB
276 # include <glob.h>
277 #endif
279 #include "unicode.h"
280 #include "shell_common.h"
281 #if ENABLE_FEATURE_SH_MATH
282 # include "math.h"
283 #else
284 typedef long arith_t;
285 # define ARITH_FMT "%ld"
286 #endif
287 #if ENABLE_ASH_RANDOM_SUPPORT
288 # include "random.h"
289 #else
290 # define CLEAR_RANDOM_T(rnd) ((void)0)
291 #endif
293 #include "NUM_APPLETS.h"
294 #if NUM_APPLETS == 1
295 /* STANDALONE does not make sense, and won't compile */
296 # undef CONFIG_FEATURE_SH_STANDALONE
297 # undef ENABLE_FEATURE_SH_STANDALONE
298 # undef IF_FEATURE_SH_STANDALONE
299 # undef IF_NOT_FEATURE_SH_STANDALONE
300 # define ENABLE_FEATURE_SH_STANDALONE 0
301 # define IF_FEATURE_SH_STANDALONE(...)
302 # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
303 #endif
305 #ifndef F_DUPFD_CLOEXEC
306 # define F_DUPFD_CLOEXEC F_DUPFD
307 #endif
308 #ifndef O_CLOEXEC
309 # define O_CLOEXEC 0
310 #endif
311 #ifndef PIPE_BUF
312 # define PIPE_BUF 4096 /* amount of buffering in a pipe */
313 #endif
315 #ifndef unlikely
316 # define unlikely(cond) (cond)
317 #endif
319 #if !BB_MMU
320 # error "Do not even bother, ash will not run on NOMMU machine"
321 #endif
323 /* ============ Hash table sizes. Configurable. */
325 #define VTABSIZE 39
326 #define ATABSIZE 39
327 #define CMDTABLESIZE 31 /* should be prime */
330 /* ============ Shell options */
332 /* If you add/change options hare, update --help text too */
333 static const char *const optletters_optnames[] ALIGN_PTR = {
334 "e" "errexit",
335 "f" "noglob",
336 /* bash has '-o ignoreeof', but no short synonym -I for it */
337 /* (in bash, set -I disables invisible variables (what's that?)) */
338 "I" "ignoreeof",
339 /* The below allowed this invocation:
340 * ash -c 'set -i; echo $-; sleep 5; echo $-'
341 * to be ^C-ed and get to interactive ash prompt.
342 * bash does not support such "set -i".
343 * In our code, this is denoted by empty long name:
345 "i" "",
346 /* (removing "i" altogether would remove it from "$-", not good) */
347 "m" "monitor",
348 "n" "noexec",
349 /* Ditto: bash has no "set -s", "set -c" */
350 "s" "",
351 "c" "",
352 "x" "xtrace",
353 "v" "verbose",
354 "C" "noclobber",
355 "a" "allexport",
356 "b" "notify",
357 "u" "nounset",
358 "E" "errtrace",
359 "\0" "vi"
360 #if BASH_PIPEFAIL
361 ,"\0" "pipefail"
362 #endif
363 #if DEBUG
364 ,"\0" "nolog"
365 ,"\0" "debug"
366 #endif
368 //bash 4.4.23 also has these opts (with these defaults):
369 //braceexpand on
370 //emacs on
371 //errtrace off
372 //functrace off
373 //hashall on
374 //histexpand off
375 //history on
376 //interactive-comments on
377 //keyword off
378 //onecmd off
379 //physical off
380 //posix off
381 //privileged off
383 #define optletters(n) optletters_optnames[n][0]
384 #define optnames(n) (optletters_optnames[n] + 1)
386 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
389 /* ============ Misc data */
391 #define msg_illnum "Illegal number: %s"
394 * We enclose jmp_buf in a structure so that we can declare pointers to
395 * jump locations. The global variable handler contains the location to
396 * jump to when an exception occurs, and the global variable exception_type
397 * contains a code identifying the exception. To implement nested
398 * exception handlers, the user should save the value of handler on entry
399 * to an inner scope, set handler to point to a jmploc structure for the
400 * inner scope, and restore handler on exit from the scope.
402 struct jmploc {
403 jmp_buf loc;
406 struct globals_misc {
407 uint8_t exitstatus; /* exit status of last command */
408 uint8_t back_exitstatus;/* exit status of backquoted command */
409 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
410 smallint inps4; /* Prevent PS4 nesting. */
411 int savestatus; /* exit status of last command outside traps */
412 int rootpid; /* pid of main shell */
413 /* shell level: 0 for the main shell, 1 for its children, and so on */
414 int shlvl;
415 #define rootshell (!shlvl)
416 int errlinno;
418 char *minusc; /* argument to -c option */
420 char *curdir; // = nullstr; /* current working directory */
421 char *physdir; // = nullstr; /* physical working directory */
423 char *arg0; /* value of $0 */
425 struct jmploc *exception_handler;
427 /*volatile*/ int suppress_int; /* counter */
428 /* ^^^^^^^ removed "volatile" since on x86, gcc turns suppress_int++
429 * into ridiculous 3-insn sequence otherwise.
430 * We don't change suppress_int asyncronously (in a signal handler),
431 * but we do read it async.
433 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
434 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
435 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
436 smallint exception_type; /* kind of exception: */
437 #define EXINT 0 /* SIGINT received */
438 #define EXERROR 1 /* a generic error */
439 #define EXEND 3 /* exit the shell */
440 #define EXEXIT 4 /* exit the shell via exitcmd */
442 char nullstr[1]; /* zero length string */
444 char optlist[NOPTS];
445 #define eflag optlist[0]
446 #define fflag optlist[1]
447 #define Iflag optlist[2]
448 #define iflag optlist[3]
449 #define mflag optlist[4]
450 #define nflag optlist[5]
451 #define sflag optlist[6]
452 #define cflag optlist[7]
453 #define xflag optlist[8]
454 #define vflag optlist[9]
455 #define Cflag optlist[10]
456 #define aflag optlist[11]
457 #define bflag optlist[12]
458 #define uflag optlist[13]
459 #define Eflag optlist[14]
460 #define viflag optlist[15]
461 #if BASH_PIPEFAIL
462 # define pipefail optlist[16]
463 #else
464 # define pipefail 0
465 #endif
466 #if DEBUG
467 # define nolog optlist[16 + BASH_PIPEFAIL]
468 # define debug optlist[17 + BASH_PIPEFAIL]
469 #endif
471 /* trap handler commands */
473 * Sigmode records the current value of the signal handlers for the various
474 * modes. A value of zero means that the current handler is not known.
475 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
477 char sigmode[NSIG - 1];
478 #define S_DFL 1 /* default signal handling (SIG_DFL) */
479 #define S_CATCH 2 /* signal is caught */
480 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
481 #define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
483 /* indicates specified signal received */
484 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
485 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
486 char *trap[NSIG + 1];
487 /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */
488 #define NTRAP_ERR NSIG
489 #define NTRAP_LAST NSIG
491 char **trap_ptr; /* used only by "trap hack" */
493 /* Rarely referenced stuff */
494 #if ENABLE_ASH_RANDOM_SUPPORT
495 random_t random_gen;
496 #endif
497 pid_t backgndpid; /* pid of last background process */
499 extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
500 #define G_misc (*ash_ptr_to_globals_misc)
501 #define exitstatus (G_misc.exitstatus )
502 #define back_exitstatus (G_misc.back_exitstatus )
503 #define job_warning (G_misc.job_warning)
504 #define inps4 (G_misc.inps4 )
505 #define savestatus (G_misc.savestatus )
506 #define rootpid (G_misc.rootpid )
507 #define shlvl (G_misc.shlvl )
508 #define errlinno (G_misc.errlinno )
509 #define minusc (G_misc.minusc )
510 #define curdir (G_misc.curdir )
511 #define physdir (G_misc.physdir )
512 #define arg0 (G_misc.arg0 )
513 #define exception_handler (G_misc.exception_handler)
514 #define exception_type (G_misc.exception_type )
515 #define suppress_int (G_misc.suppress_int )
516 #define pending_int (G_misc.pending_int )
517 #define got_sigchld (G_misc.got_sigchld )
518 #define pending_sig (G_misc.pending_sig )
519 #define nullstr (G_misc.nullstr )
520 #define optlist (G_misc.optlist )
521 #define sigmode (G_misc.sigmode )
522 #define gotsig (G_misc.gotsig )
523 #define may_have_traps (G_misc.may_have_traps )
524 #define trap (G_misc.trap )
525 #define trap_ptr (G_misc.trap_ptr )
526 #define random_gen (G_misc.random_gen )
527 #define backgndpid (G_misc.backgndpid )
528 #define INIT_G_misc() do { \
529 XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \
530 savestatus = -1; \
531 curdir = nullstr; \
532 physdir = nullstr; \
533 trap_ptr = trap; \
534 } while (0)
537 /* ============ DEBUG */
538 #if DEBUG
539 static void trace_printf(const char *fmt, ...);
540 static void trace_vprintf(const char *fmt, va_list va);
541 # define TRACE(param) trace_printf param
542 # define TRACEV(param) trace_vprintf param
543 # define close(fd) do { \
544 int dfd = (fd); \
545 if (close(dfd) < 0) \
546 bb_error_msg("bug on %d: closing %d(0x%x)", \
547 __LINE__, dfd, dfd); \
548 } while (0)
549 #else
550 # define TRACE(param)
551 # define TRACEV(param)
552 #endif
555 /* ============ Utility functions */
556 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
557 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
559 static int
560 isdigit_str9(const char *str)
562 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
563 while (--maxlen && isdigit(*str))
564 str++;
565 return (*str == '\0');
568 static const char *
569 var_end(const char *var)
571 while (*var)
572 if (*var++ == '=')
573 break;
574 return var;
578 /* ============ Parser data */
581 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
583 struct strlist {
584 struct strlist *next;
585 char *text;
588 struct alias;
590 struct strpush {
591 struct strpush *prev; /* preceding string on stack */
592 char *prev_string;
593 int prev_left_in_line;
594 #if ENABLE_ASH_ALIAS
595 struct alias *ap; /* if push was associated with an alias */
596 #endif
597 char *string; /* remember the string since it may change */
599 /* Delay freeing so we can stop nested aliases. */
600 struct strpush *spfree;
602 /* Remember last two characters for pungetc. */
603 int lastc[2];
605 /* Number of outstanding calls to pungetc. */
606 int unget;
610 * The parsefile structure pointed to by the global variable parsefile
611 * contains information about the current file being read.
613 struct parsefile {
614 struct parsefile *prev; /* preceding file on stack */
615 int linno; /* current line */
616 int pf_fd; /* file descriptor (or -1 if string) */
617 int left_in_line; /* number of chars left in this line */
618 int left_in_buffer; /* number of chars left in this buffer past the line */
619 char *next_to_pgetc; /* next char in buffer */
620 char *buf; /* input buffer */
621 struct strpush *strpush; /* for pushing strings at this level */
622 struct strpush basestrpush; /* so pushing one is fast */
624 /* Delay freeing so we can stop nested aliases. */
625 struct strpush *spfree;
627 /* Remember last two characters for pungetc. */
628 int lastc[2];
630 /* Number of outstanding calls to pungetc. */
631 int unget;
634 static struct parsefile basepf; /* top level input file */
635 static struct parsefile *g_parsefile = &basepf; /* current input file */
636 static char *commandname; /* currently executing command */
639 /* ============ Interrupts / exceptions */
641 static void exitshell(void) NORETURN;
644 * These macros allow the user to suspend the handling of interrupt signals
645 * over a period of time. This is similar to SIGHOLD or to sigblock, but
646 * much more efficient and portable. (But hacking the kernel is so much
647 * more fun than worrying about efficiency and portability. :-))
649 #if DEBUG_INTONOFF
650 # define INT_OFF do { \
651 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
652 suppress_int++; \
653 barrier(); \
654 } while (0)
655 #else
656 # define INT_OFF do { \
657 suppress_int++; \
658 barrier(); \
659 } while (0)
660 #endif
663 * Called to raise an exception. Since C doesn't include exceptions, we
664 * just do a longjmp to the exception handler. The type of exception is
665 * stored in the global variable "exception_type".
667 static void raise_exception(int) NORETURN;
668 static void
669 raise_exception(int e)
671 #if DEBUG
672 if (exception_handler == NULL)
673 abort();
674 #endif
675 INT_OFF;
676 exception_type = e;
677 longjmp(exception_handler->loc, 1);
679 #if DEBUG
680 #define raise_exception(e) do { \
681 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
682 raise_exception(e); \
683 } while (0)
684 #endif
687 * Called when a SIGINT is received. (If the user specifies
688 * that SIGINT is to be trapped or ignored using the trap builtin, then
689 * this routine is not called.) suppress_int is nonzero when interrupts
690 * are held using the INT_OFF macro. (The test for iflag is just
691 * defensive programming.)
693 static void raise_interrupt(void) NORETURN;
694 static void
695 raise_interrupt(void)
697 pending_int = 0;
698 /* Signal is not automatically unmasked after it is raised,
699 * do it ourself - unmask all signals */
700 sigprocmask_allsigs(SIG_UNBLOCK);
701 /* pending_sig = 0; - now done in signal_handler() */
703 if (!(rootshell && iflag)) {
704 /* Kill ourself with SIGINT */
705 signal(SIGINT, SIG_DFL);
706 raise(SIGINT);
708 /* bash: ^C even on empty command line sets $? */
709 exitstatus = SIGINT + 128;
710 raise_exception(EXINT);
711 /* NOTREACHED */
713 #if DEBUG
714 #define raise_interrupt() do { \
715 TRACE(("raising interrupt on line %d\n", __LINE__)); \
716 raise_interrupt(); \
717 } while (0)
718 #endif
720 static IF_NOT_ASH_OPTIMIZE_FOR_SIZE(inline) void
721 int_on(void)
723 barrier();
724 if (--suppress_int == 0 && pending_int)
725 raise_interrupt(); /* does not return */
726 barrier();
728 #if DEBUG_INTONOFF
729 # define INT_ON do { \
730 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
731 int_on(); \
732 } while (0)
733 #else
734 # define INT_ON int_on()
735 #endif
736 static IF_NOT_ASH_OPTIMIZE_FOR_SIZE(inline) void
737 force_int_on(void)
739 barrier();
740 suppress_int = 0;
741 if (pending_int)
742 raise_interrupt(); /* does not return */
743 barrier();
745 #define FORCE_INT_ON force_int_on()
747 #define SAVE_INT(v) ((v) = suppress_int)
749 #define RESTORE_INT(v) do { \
750 barrier(); \
751 suppress_int = (v); \
752 if (suppress_int == 0 && pending_int) \
753 raise_interrupt(); /* does not return */ \
754 barrier(); \
755 } while (0)
758 /* ============ Stdout/stderr output */
760 static void
761 outstr(const char *p, FILE *file)
763 INT_OFF;
764 fputs(p, file);
765 INT_ON;
768 static void
769 flush_stdout_stderr(void)
771 INT_OFF;
772 fflush_all();
773 INT_ON;
776 /* Was called outcslow(c,FILE*), but c was always '\n' */
777 static void
778 newline_and_flush(FILE *dest)
780 INT_OFF;
781 putc('\n', dest);
782 fflush(dest);
783 INT_ON;
786 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
787 static int
788 out1fmt(const char *fmt, ...)
790 va_list ap;
791 int r;
793 INT_OFF;
794 va_start(ap, fmt);
795 r = vprintf(fmt, ap);
796 va_end(ap);
797 INT_ON;
798 return r;
801 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
802 static int
803 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
805 va_list ap;
806 int ret;
808 INT_OFF;
809 va_start(ap, fmt);
810 ret = vsnprintf(outbuf, length, fmt, ap);
811 va_end(ap);
812 INT_ON;
813 return ret > (int)length ? length : ret;
816 static void
817 out1str(const char *p)
819 outstr(p, stdout);
822 static void
823 out2str(const char *p)
825 outstr(p, stderr);
826 flush_stdout_stderr();
830 /* ============ Parser structures */
832 /* control characters in argument strings */
833 #define CTL_FIRST CTLESC
834 #define CTLESC ((unsigned char)'\201') /* escape next character */
835 #define CTLVAR ((unsigned char)'\202') /* variable defn */
836 #define CTLENDVAR ((unsigned char)'\203')
837 #define CTLBACKQ ((unsigned char)'\204')
838 #define CTLARI ((unsigned char)'\206') /* arithmetic expression */
839 #define CTLENDARI ((unsigned char)'\207')
840 #define CTLQUOTEMARK ((unsigned char)'\210')
841 #define CTL_LAST CTLQUOTEMARK
842 #if BASH_PROCESS_SUBST
843 # define CTLTOPROC ((unsigned char)'\211')
844 # define CTLFROMPROC ((unsigned char)'\212')
845 # undef CTL_LAST
846 # define CTL_LAST CTLFROMPROC
847 #endif
849 /* variable substitution byte (follows CTLVAR) */
850 #define VSTYPE 0x0f /* type of variable substitution */
851 #define VSNUL 0x10 /* colon--treat the empty string as unset */
853 /* values of VSTYPE field */
854 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
855 #define VSMINUS 0x2 /* ${var-text} */
856 #define VSPLUS 0x3 /* ${var+text} */
857 #define VSQUESTION 0x4 /* ${var?message} */
858 #define VSASSIGN 0x5 /* ${var=text} */
859 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
860 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
861 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
862 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
863 #define VSLENGTH 0xa /* ${#var} */
864 #if BASH_SUBSTR
865 #define VSSUBSTR 0xc /* ${var:position:length} */
866 #endif
867 #if BASH_PATTERN_SUBST
868 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
869 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
870 #endif
872 static const char dolatstr[] ALIGN1 = {
873 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
875 #define DOLATSTRLEN 6
877 #define NCMD 0
878 #define NPIPE 1
879 #define NREDIR 2
880 #define NBACKGND 3
881 #define NSUBSHELL 4
882 #define NAND 5
883 #define NOR 6
884 #define NSEMI 7
885 #define NIF 8
886 #define NWHILE 9
887 #define NUNTIL 10
888 #define NFOR 11
889 #define NCASE 12
890 #define NCLIST 13
891 #define NDEFUN 14
892 #define NARG 15
893 #define NTO 16
894 #if BASH_REDIR_OUTPUT
895 #define NTO2 17
896 #endif
897 #define NCLOBBER 18
898 #define NFROM 19
899 #define NFROMTO 20
900 #define NAPPEND 21
901 #define NTOFD 22
902 #define NFROMFD 23
903 #define NHERE 24
904 #define NXHERE 25
905 #define NNOT 26
906 #define N_NUMBER 27
908 union node;
910 struct ncmd {
911 smallint type; /* Nxxxx */
912 int linno;
913 union node *assign;
914 union node *args;
915 union node *redirect;
918 struct npipe {
919 smallint type;
920 smallint pipe_backgnd;
921 struct nodelist *cmdlist;
924 struct nredir {
925 smallint type;
926 int linno;
927 union node *n;
928 union node *redirect;
931 struct nbinary {
932 smallint type;
933 union node *ch1;
934 union node *ch2;
937 struct nif {
938 smallint type;
939 union node *test;
940 union node *ifpart;
941 union node *elsepart;
944 struct nfor {
945 smallint type;
946 int linno;
947 union node *args;
948 union node *body;
949 char *var;
952 struct ncase {
953 smallint type;
954 int linno;
955 union node *expr;
956 union node *cases;
959 struct nclist {
960 smallint type;
961 union node *next;
962 union node *pattern;
963 union node *body;
966 struct ndefun {
967 smallint type;
968 int linno;
969 char *text;
970 union node *body;
973 struct narg {
974 smallint type;
975 union node *next;
976 char *text;
977 struct nodelist *backquote;
980 /* nfile and ndup layout must match!
981 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
982 * that it is actually NTO2 (>&file), and change its type.
984 struct nfile {
985 smallint type;
986 union node *next;
987 int fd;
988 int _unused_dupfd;
989 union node *fname;
990 char *expfname;
993 struct ndup {
994 smallint type;
995 union node *next;
996 int fd;
997 int dupfd;
998 union node *vname;
999 char *_unused_expfname;
1002 struct nhere {
1003 smallint type;
1004 union node *next;
1005 int fd;
1006 union node *doc;
1009 struct nnot {
1010 smallint type;
1011 union node *com;
1014 union node {
1015 smallint type;
1016 struct ncmd ncmd;
1017 struct npipe npipe;
1018 struct nredir nredir;
1019 struct nbinary nbinary;
1020 struct nif nif;
1021 struct nfor nfor;
1022 struct ncase ncase;
1023 struct nclist nclist;
1024 struct ndefun ndefun;
1025 struct narg narg;
1026 struct nfile nfile;
1027 struct ndup ndup;
1028 struct nhere nhere;
1029 struct nnot nnot;
1033 * NODE_EOF is returned by parsecmd when it encounters an end of file.
1034 * It must be distinct from NULL.
1036 #define NODE_EOF ((union node *) -1L)
1038 struct nodelist {
1039 struct nodelist *next;
1040 union node *n;
1043 struct funcnode {
1044 int count;
1045 union node n;
1049 * Free a parse tree.
1051 static void
1052 freefunc(struct funcnode *f)
1054 if (f && --f->count < 0)
1055 free(f);
1059 /* ============ Debugging output */
1061 #if DEBUG
1063 static FILE *tracefile;
1065 static void
1066 trace_printf(const char *fmt, ...)
1068 va_list va;
1070 if (debug != 1)
1071 return;
1072 if (DEBUG_TIME)
1073 fprintf(tracefile, "%u ", (int) time(NULL));
1074 if (DEBUG_PID)
1075 fprintf(tracefile, "[%u] ", (int) getpid());
1076 if (DEBUG_SIG)
1077 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
1078 va_start(va, fmt);
1079 vfprintf(tracefile, fmt, va);
1080 va_end(va);
1083 static void
1084 trace_vprintf(const char *fmt, va_list va)
1086 if (debug != 1)
1087 return;
1088 vfprintf(tracefile, fmt, va);
1089 fprintf(tracefile, "\n");
1092 static void
1093 trace_puts(const char *s)
1095 if (debug != 1)
1096 return;
1097 fputs(s, tracefile);
1100 static void
1101 trace_puts_quoted(char *s)
1103 char *p;
1104 char c;
1106 if (debug != 1)
1107 return;
1108 putc('"', tracefile);
1109 for (p = s; *p; p++) {
1110 switch ((unsigned char)*p) {
1111 case '\n': c = 'n'; goto backslash;
1112 case '\t': c = 't'; goto backslash;
1113 case '\r': c = 'r'; goto backslash;
1114 case '\"': c = '\"'; goto backslash;
1115 case '\\': c = '\\'; goto backslash;
1116 case CTLESC: c = 'e'; goto backslash;
1117 case CTLVAR: c = 'v'; goto backslash;
1118 case CTLBACKQ: c = 'q'; goto backslash;
1119 #if BASH_PROCESS_SUBST
1120 case CTLTOPROC: c = 'p'; goto backslash;
1121 case CTLFROMPROC: c = 'P'; goto backslash;
1122 #endif
1123 backslash:
1124 putc('\\', tracefile);
1125 putc(c, tracefile);
1126 break;
1127 default:
1128 if (*p >= ' ' && *p <= '~')
1129 putc(*p, tracefile);
1130 else {
1131 putc('\\', tracefile);
1132 putc((*p >> 6) & 03, tracefile);
1133 putc((*p >> 3) & 07, tracefile);
1134 putc(*p & 07, tracefile);
1136 break;
1139 putc('"', tracefile);
1142 static void
1143 trace_puts_args(char **ap)
1145 if (debug != 1)
1146 return;
1147 if (!*ap)
1148 return;
1149 while (1) {
1150 trace_puts_quoted(*ap);
1151 if (!*++ap) {
1152 putc('\n', tracefile);
1153 break;
1155 putc(' ', tracefile);
1159 static void
1160 opentrace(void)
1162 char s[100];
1163 #ifdef O_APPEND
1164 int flags;
1165 #endif
1167 if (debug != 1) {
1168 if (tracefile)
1169 fflush(tracefile);
1170 /* leave open because libedit might be using it */
1171 return;
1173 strcpy(s, "./trace");
1174 if (tracefile) {
1175 if (!freopen(s, "a", tracefile)) {
1176 fprintf(stderr, "Can't re-open %s\n", s);
1177 debug = 0;
1178 return;
1180 } else {
1181 tracefile = fopen(s, "a");
1182 if (tracefile == NULL) {
1183 fprintf(stderr, "Can't open %s\n", s);
1184 debug = 0;
1185 return;
1188 #ifdef O_APPEND
1189 flags = fcntl(fileno(tracefile), F_GETFL);
1190 if (flags >= 0)
1191 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1192 #endif
1193 setlinebuf(tracefile);
1194 fputs("\nTracing started.\n", tracefile);
1197 static void
1198 indent(int amount, char *pfx, FILE *fp)
1200 int i;
1202 for (i = 0; i < amount; i++) {
1203 if (pfx && i == amount - 1)
1204 fputs(pfx, fp);
1205 putc('\t', fp);
1209 /* little circular references here... */
1210 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1212 static void
1213 sharg(union node *arg, FILE *fp)
1215 char *p;
1216 struct nodelist *bqlist;
1217 unsigned char subtype;
1219 if (arg->type != NARG) {
1220 out1fmt("<node type %d>\n", arg->type);
1221 abort();
1223 bqlist = arg->narg.backquote;
1224 for (p = arg->narg.text; *p; p++) {
1225 switch ((unsigned char)*p) {
1226 case CTLESC:
1227 p++;
1228 putc(*p, fp);
1229 break;
1230 case CTLVAR:
1231 putc('$', fp);
1232 putc('{', fp);
1233 subtype = *++p;
1234 if (subtype == VSLENGTH)
1235 putc('#', fp);
1237 while (*p != '=') {
1238 putc(*p, fp);
1239 p++;
1242 if (subtype & VSNUL)
1243 putc(':', fp);
1245 switch (subtype & VSTYPE) {
1246 case VSNORMAL:
1247 putc('}', fp);
1248 break;
1249 case VSMINUS:
1250 putc('-', fp);
1251 break;
1252 case VSPLUS:
1253 putc('+', fp);
1254 break;
1255 case VSQUESTION:
1256 putc('?', fp);
1257 break;
1258 case VSASSIGN:
1259 putc('=', fp);
1260 break;
1261 case VSTRIMLEFT:
1262 putc('#', fp);
1263 break;
1264 case VSTRIMLEFTMAX:
1265 putc('#', fp);
1266 putc('#', fp);
1267 break;
1268 case VSTRIMRIGHT:
1269 putc('%', fp);
1270 break;
1271 case VSTRIMRIGHTMAX:
1272 putc('%', fp);
1273 putc('%', fp);
1274 break;
1275 case VSLENGTH:
1276 break;
1277 default:
1278 out1fmt("<subtype %d>", subtype);
1280 break;
1281 case CTLENDVAR:
1282 putc('}', fp);
1283 break;
1284 #if BASH_PROCESS_SUBST
1285 case CTLTOPROC:
1286 putc('>', fp);
1287 goto backq;
1288 case CTLFROMPROC:
1289 putc('<', fp);
1290 goto backq;
1291 #endif
1292 case CTLBACKQ:
1293 putc('$', fp);
1294 IF_BASH_PROCESS_SUBST(backq:)
1295 putc('(', fp);
1296 shtree(bqlist->n, -1, NULL, fp);
1297 putc(')', fp);
1298 break;
1299 default:
1300 putc(*p, fp);
1301 break;
1306 static void
1307 shcmd(union node *cmd, FILE *fp)
1309 union node *np;
1310 int first;
1311 const char *s;
1312 int dftfd;
1314 first = 1;
1315 for (np = cmd->ncmd.args; np; np = np->narg.next) {
1316 if (!first)
1317 putc(' ', fp);
1318 sharg(np, fp);
1319 first = 0;
1321 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1322 if (!first)
1323 putc(' ', fp);
1324 dftfd = 0;
1325 switch (np->nfile.type) {
1326 case NTO: s = ">>"+1; dftfd = 1; break;
1327 case NCLOBBER: s = ">|"; dftfd = 1; break;
1328 case NAPPEND: s = ">>"; dftfd = 1; break;
1329 #if BASH_REDIR_OUTPUT
1330 case NTO2:
1331 #endif
1332 case NTOFD: s = ">&"; dftfd = 1; break;
1333 case NFROM: s = "<"; break;
1334 case NFROMFD: s = "<&"; break;
1335 case NFROMTO: s = "<>"; break;
1336 default: s = "*error*"; break;
1338 if (np->nfile.fd != dftfd)
1339 fprintf(fp, "%d", np->nfile.fd);
1340 fputs(s, fp);
1341 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1342 fprintf(fp, "%d", np->ndup.dupfd);
1343 } else {
1344 sharg(np->nfile.fname, fp);
1346 first = 0;
1350 static void
1351 shtree(union node *n, int ind, char *pfx, FILE *fp)
1353 struct nodelist *lp;
1354 const char *s;
1356 if (n == NULL)
1357 return;
1359 indent(ind, pfx, fp);
1361 if (n == NODE_EOF) {
1362 fputs("<EOF>", fp);
1363 return;
1366 switch (n->type) {
1367 case NSEMI:
1368 s = "; ";
1369 goto binop;
1370 case NAND:
1371 s = " && ";
1372 goto binop;
1373 case NOR:
1374 s = " || ";
1375 binop:
1376 shtree(n->nbinary.ch1, ind, NULL, fp);
1377 /* if (ind < 0) */
1378 fputs(s, fp);
1379 shtree(n->nbinary.ch2, ind, NULL, fp);
1380 break;
1381 case NCMD:
1382 shcmd(n, fp);
1383 if (ind >= 0)
1384 putc('\n', fp);
1385 break;
1386 case NPIPE:
1387 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1388 shtree(lp->n, 0, NULL, fp);
1389 if (lp->next)
1390 fputs(" | ", fp);
1392 if (n->npipe.pipe_backgnd)
1393 fputs(" &", fp);
1394 if (ind >= 0)
1395 putc('\n', fp);
1396 break;
1397 default:
1398 fprintf(fp, "<node type %d>", n->type);
1399 if (ind >= 0)
1400 putc('\n', fp);
1401 break;
1405 static void
1406 showtree(union node *n)
1408 trace_puts("showtree called\n");
1409 shtree(n, 1, NULL, stderr);
1412 #endif /* DEBUG */
1415 /* ============ Message printing */
1417 static void
1418 ash_vmsg(const char *msg, va_list ap)
1420 fprintf(stderr, "%s: ", arg0);
1421 if (commandname) {
1422 if (strcmp(arg0, commandname))
1423 fprintf(stderr, "%s: ", commandname);
1424 if (!iflag || g_parsefile->pf_fd > 0)
1425 fprintf(stderr, "line %d: ", errlinno);
1427 vfprintf(stderr, msg, ap);
1428 newline_and_flush(stderr);
1432 * Exverror is called to raise the error exception. If the second argument
1433 * is not NULL then error prints an error message using printf style
1434 * formatting. It then raises the error exception.
1436 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1437 static void
1438 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1440 #if DEBUG
1441 if (msg) {
1442 TRACE(("ash_vmsg_and_raise(%d):", cond));
1443 TRACEV((msg, ap));
1444 } else
1445 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1446 if (msg)
1447 #endif
1448 ash_vmsg(msg, ap);
1450 flush_stdout_stderr();
1451 raise_exception(cond);
1452 /* NOTREACHED */
1455 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1456 static void
1457 ash_msg_and_raise_error(const char *msg, ...)
1459 va_list ap;
1461 exitstatus = 2;
1463 va_start(ap, msg);
1464 ash_vmsg_and_raise(EXERROR, msg, ap);
1465 /* NOTREACHED */
1466 va_end(ap);
1470 * 'fmt' must be a string literal.
1472 #define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
1474 static void raise_error_syntax(const char *) NORETURN;
1475 static void
1476 raise_error_syntax(const char *msg)
1478 errlinno = g_parsefile->linno;
1479 ash_msg_and_raise_error("syntax error: %s", msg);
1480 /* NOTREACHED */
1483 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1484 static void
1485 ash_msg_and_raise(int cond, const char *msg, ...)
1487 va_list ap;
1489 va_start(ap, msg);
1490 ash_vmsg_and_raise(cond, msg, ap);
1491 /* NOTREACHED */
1492 va_end(ap);
1496 * error/warning routines for external builtins
1498 static void
1499 ash_msg(const char *fmt, ...)
1501 va_list ap;
1503 va_start(ap, fmt);
1504 ash_vmsg(fmt, ap);
1505 va_end(ap);
1509 * Return a string describing an error. The returned string may be a
1510 * pointer to a static buffer that will be overwritten on the next call.
1511 * Action describes the operation that got the error.
1513 static const char *
1514 errmsg(int e, const char *em)
1516 if (e == ENOENT || e == ENOTDIR) {
1517 return em;
1519 return strerror(e);
1523 /* ============ Memory allocation */
1525 #if 0
1526 /* I consider these wrappers nearly useless:
1527 * ok, they return you to nearest exception handler, but
1528 * how much memory do you leak in the process, making
1529 * memory starvation worse?
1531 static void *
1532 ckrealloc(void * p, size_t nbytes)
1534 p = realloc(p, nbytes);
1535 if (!p)
1536 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1537 return p;
1540 static void *
1541 ckmalloc(size_t nbytes)
1543 return ckrealloc(NULL, nbytes);
1546 static void *
1547 ckzalloc(size_t nbytes)
1549 return memset(ckmalloc(nbytes), 0, nbytes);
1552 static char *
1553 ckstrdup(const char *s)
1555 char *p = strdup(s);
1556 if (!p)
1557 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1558 return p;
1560 #else
1561 /* Using bbox equivalents. They exit if out of memory */
1562 # define ckrealloc xrealloc
1563 # define ckmalloc xmalloc
1564 # define ckzalloc xzalloc
1565 # define ckstrdup xstrdup
1566 #endif
1569 * It appears that grabstackstr() will barf with such alignments
1570 * because stalloc() will return a string allocated in a new stackblock.
1572 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1573 enum {
1574 /* Most machines require the value returned from malloc to be aligned
1575 * in some way. The following macro will get this right
1576 * on many machines. */
1577 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1578 /* Minimum size of a block */
1579 MINSIZE = SHELL_ALIGN(504),
1582 struct stack_block {
1583 struct stack_block *prev;
1584 char space[MINSIZE];
1587 struct stackmark {
1588 struct stack_block *stackp;
1589 char *stacknxt;
1590 size_t stacknleft;
1594 struct globals_memstack {
1595 struct stack_block *g_stackp; // = &stackbase;
1596 char *g_stacknxt; // = stackbase.space;
1597 char *sstrend; // = stackbase.space + MINSIZE;
1598 size_t g_stacknleft; // = MINSIZE;
1599 struct stack_block stackbase;
1601 extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1602 #define G_memstack (*ash_ptr_to_globals_memstack)
1603 #define g_stackp (G_memstack.g_stackp )
1604 #define g_stacknxt (G_memstack.g_stacknxt )
1605 #define sstrend (G_memstack.sstrend )
1606 #define g_stacknleft (G_memstack.g_stacknleft)
1607 #define stackbase (G_memstack.stackbase )
1608 #define INIT_G_memstack() do { \
1609 XZALLOC_CONST_PTR(&ash_ptr_to_globals_memstack, sizeof(G_memstack)); \
1610 g_stackp = &stackbase; \
1611 g_stacknxt = stackbase.space; \
1612 g_stacknleft = MINSIZE; \
1613 sstrend = stackbase.space + MINSIZE; \
1614 } while (0)
1617 #define stackblock() ((void *)g_stacknxt)
1618 #define stackblocksize() g_stacknleft
1621 * Parse trees for commands are allocated in lifo order, so we use a stack
1622 * to make this more efficient, and also to avoid all sorts of exception
1623 * handling code to handle interrupts in the middle of a parse.
1625 * The size 504 was chosen because the Ultrix malloc handles that size
1626 * well.
1628 static void *
1629 stalloc(size_t nbytes)
1631 char *p;
1632 size_t aligned;
1634 aligned = SHELL_ALIGN(nbytes);
1635 if (aligned > g_stacknleft) {
1636 size_t len;
1637 size_t blocksize;
1638 struct stack_block *sp;
1640 blocksize = aligned;
1641 if (blocksize < MINSIZE)
1642 blocksize = MINSIZE;
1643 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1644 if (len < blocksize)
1645 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1646 INT_OFF;
1647 sp = ckmalloc(len);
1648 sp->prev = g_stackp;
1649 g_stacknxt = sp->space;
1650 g_stacknleft = blocksize;
1651 sstrend = g_stacknxt + blocksize;
1652 g_stackp = sp;
1653 INT_ON;
1655 p = g_stacknxt;
1656 g_stacknxt += aligned;
1657 g_stacknleft -= aligned;
1658 return p;
1661 static void *
1662 stzalloc(size_t nbytes)
1664 return memset(stalloc(nbytes), 0, nbytes);
1667 static void
1668 stunalloc(void *p)
1670 #if DEBUG
1671 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1672 write(STDERR_FILENO, "stunalloc\n", 10);
1673 abort();
1675 #endif
1676 g_stacknleft += g_stacknxt - (char *)p;
1677 g_stacknxt = p;
1681 * Like strdup but works with the ash stack.
1683 static char *
1684 sstrdup(const char *p)
1686 size_t len = strlen(p) + 1;
1687 return memcpy(stalloc(len), p, len);
1690 static ALWAYS_INLINE void
1691 grabstackblock(size_t len)
1693 stalloc(len);
1696 static void
1697 pushstackmark(struct stackmark *mark, size_t len)
1699 mark->stackp = g_stackp;
1700 mark->stacknxt = g_stacknxt;
1701 mark->stacknleft = g_stacknleft;
1702 grabstackblock(len);
1705 static void
1706 setstackmark(struct stackmark *mark)
1708 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1711 static void
1712 popstackmark(struct stackmark *mark)
1714 struct stack_block *sp;
1716 if (!mark->stackp)
1717 return;
1719 INT_OFF;
1720 while (g_stackp != mark->stackp) {
1721 sp = g_stackp;
1722 g_stackp = sp->prev;
1723 free(sp);
1725 g_stacknxt = mark->stacknxt;
1726 g_stacknleft = mark->stacknleft;
1727 sstrend = mark->stacknxt + mark->stacknleft;
1728 INT_ON;
1732 * When the parser reads in a string, it wants to stick the string on the
1733 * stack and only adjust the stack pointer when it knows how big the
1734 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1735 * of space on top of the stack and stackblocklen returns the length of
1736 * this block. Growstackblock will grow this space by at least one byte,
1737 * possibly moving it (like realloc). Grabstackblock actually allocates the
1738 * part of the block that has been used.
1740 static void
1741 growstackblock(size_t min)
1743 size_t newlen;
1745 newlen = g_stacknleft * 2;
1746 if (newlen < g_stacknleft)
1747 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1748 min = SHELL_ALIGN(min | 128);
1749 if (newlen < min)
1750 newlen += min;
1752 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1753 struct stack_block *sp;
1754 struct stack_block *prevstackp;
1755 size_t grosslen;
1757 INT_OFF;
1758 sp = g_stackp;
1759 prevstackp = sp->prev;
1760 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1761 sp = ckrealloc(sp, grosslen);
1762 sp->prev = prevstackp;
1763 g_stackp = sp;
1764 g_stacknxt = sp->space;
1765 g_stacknleft = newlen;
1766 sstrend = sp->space + newlen;
1767 INT_ON;
1768 } else {
1769 char *oldspace = g_stacknxt;
1770 size_t oldlen = g_stacknleft;
1771 char *p = stalloc(newlen);
1773 /* free the space we just allocated */
1774 g_stacknxt = memcpy(p, oldspace, oldlen);
1775 g_stacknleft += newlen;
1780 * The following routines are somewhat easier to use than the above.
1781 * The user declares a variable of type STACKSTR, which may be declared
1782 * to be a register. The macro STARTSTACKSTR initializes things. Then
1783 * the user uses the macro STPUTC to add characters to the string. In
1784 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1785 * grown as necessary. When the user is done, she can just leave the
1786 * string there and refer to it using stackblock(). Or she can allocate
1787 * the space for it using grabstackstr(). If it is necessary to allow
1788 * someone else to use the stack temporarily and then continue to grow
1789 * the string, the user should use grabstack to allocate the space, and
1790 * then call ungrabstr(p) to return to the previous mode of operation.
1792 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1793 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1794 * is space for at least one character.
1796 static void *
1797 growstackstr(void)
1799 size_t len = stackblocksize();
1800 growstackblock(0);
1801 return (char *)stackblock() + len;
1804 static char *
1805 growstackto(size_t len)
1807 if (stackblocksize() < len)
1808 growstackblock(len);
1809 return stackblock();
1813 * Called from CHECKSTRSPACE.
1815 static char *
1816 makestrspace(size_t newlen, char *p)
1818 size_t len = p - g_stacknxt;
1820 return growstackto(len + newlen) + len;
1823 static char *
1824 stnputs(const char *s, size_t n, char *p)
1826 p = makestrspace(n, p);
1827 p = (char *)mempcpy(p, s, n);
1828 return p;
1831 static char *
1832 stack_putstr(const char *s, char *p)
1834 return stnputs(s, strlen(s), p);
1837 static char *
1838 _STPUTC(int c, char *p)
1840 if (p == sstrend)
1841 p = growstackstr();
1842 *p++ = c;
1843 return p;
1846 #define STARTSTACKSTR(p) ((p) = stackblock())
1847 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1848 #define CHECKSTRSPACE(n, p) do { \
1849 char *q = (p); \
1850 size_t l = (n); \
1851 size_t m = sstrend - q; \
1852 if (l > m) \
1853 (p) = makestrspace(l, q); \
1854 } while (0)
1855 #define USTPUTC(c, p) (*(p)++ = (c))
1856 #define STACKSTRNUL(p) do { \
1857 if ((p) == sstrend) \
1858 (p) = growstackstr(); \
1859 *(p) = '\0'; \
1860 } while (0)
1861 #define STUNPUTC(p) (--(p))
1862 #define STTOPC(p) ((p)[-1])
1863 #define STADJUST(amount, p) ((p) += (amount))
1865 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1866 #define ungrabstackstr(s, p) stunalloc(s)
1867 #define stackstrend() ((void *)sstrend)
1870 /* ============ String helpers */
1873 * prefix -- see if pfx is a prefix of string.
1875 static ALWAYS_INLINE char *
1876 prefix(const char *string, const char *pfx)
1878 return is_prefixed_with(string, pfx);
1879 #if 0 /* dash implementation: */
1880 while (*pfx) {
1881 if (*pfx++ != *string++)
1882 return NULL;
1884 return (char *) string;
1885 #endif
1888 * Check for a valid number. This should be elsewhere.
1890 static int
1891 is_number(const char *p)
1893 do {
1894 if (!isdigit(*p))
1895 return 0;
1896 } while (*++p != '\0');
1897 return 1;
1901 * Convert a string of digits to an integer, printing an error message on
1902 * failure.
1904 static int
1905 number(const char *s)
1907 if (!is_number(s))
1908 ash_msg_and_raise_error(msg_illnum, s);
1909 return atoi(s);
1913 * Produce a single quoted string suitable as input to the shell.
1914 * The return string is allocated on the stack.
1916 static char *
1917 single_quote(const char *s)
1919 char *p;
1921 STARTSTACKSTR(p);
1923 do {
1924 char *q;
1925 size_t len;
1927 len = strchrnul(s, '\'') - s;
1929 q = p = makestrspace(len + 3, p);
1931 *q++ = '\'';
1932 q = (char *)mempcpy(q, s, len);
1933 *q++ = '\'';
1934 s += len;
1936 STADJUST(q - p, p);
1938 if (*s != '\'')
1939 break;
1940 len = 0;
1941 do len++; while (*++s == '\'');
1943 q = p = makestrspace(len + 3, p);
1945 *q++ = '"';
1946 q = (char *)mempcpy(q, s - len, len);
1947 *q++ = '"';
1949 STADJUST(q - p, p);
1950 } while (*s);
1952 USTPUTC('\0', p);
1954 return stackblock();
1958 * Produce a possibly single quoted string suitable as input to the shell.
1959 * If quoting was done, the return string is allocated on the stack,
1960 * otherwise a pointer to the original string is returned.
1962 static const char *
1963 maybe_single_quote(const char *s)
1965 const char *p = s;
1967 while (*p) {
1968 /* Assuming ACSII */
1969 /* quote ctrl_chars space !"#$%&'()* */
1970 if (*p < '+')
1971 goto need_quoting;
1972 /* quote ;<=>? */
1973 if (*p >= ';' && *p <= '?')
1974 goto need_quoting;
1975 /* quote `[\ */
1976 if (*p == '`')
1977 goto need_quoting;
1978 if (*p == '[')
1979 goto need_quoting;
1980 if (*p == '\\')
1981 goto need_quoting;
1982 /* quote {|}~ DEL and high bytes */
1983 if (*p > 'z')
1984 goto need_quoting;
1985 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1986 /* TODO: maybe avoid quoting % */
1987 p++;
1989 return s;
1991 need_quoting:
1992 return single_quote(s);
1996 /* ============ nextopt */
1998 static char **argptr; /* argument list for builtin commands */
1999 static char *optionarg; /* set by nextopt (like getopt) */
2000 static char *optptr; /* used by nextopt */
2003 * XXX - should get rid of. Have all builtins use getopt(3).
2004 * The library getopt must have the BSD extension static variable
2005 * "optreset", otherwise it can't be used within the shell safely.
2007 * Standard option processing (a la getopt) for builtin routines.
2008 * The only argument that is passed to nextopt is the option string;
2009 * the other arguments are unnecessary. It returns the character,
2010 * or '\0' on end of input.
2012 static int
2013 nextopt(const char *optstring)
2015 char *p;
2016 const char *q;
2017 char c;
2019 p = optptr;
2020 if (p == NULL || *p == '\0') {
2021 /* We ate entire "-param", take next one */
2022 p = *argptr;
2023 if (p == NULL)
2024 return '\0';
2025 if (*p != '-')
2026 return '\0';
2027 if (*++p == '\0') /* just "-" ? */
2028 return '\0';
2029 argptr++;
2030 if (LONE_DASH(p)) /* "--" ? */
2031 return '\0';
2032 /* p => next "-param" */
2034 /* p => some option char in the middle of a "-param" */
2035 c = *p++;
2036 for (q = optstring; *q != c;) {
2037 if (*q == '\0')
2038 ash_msg_and_raise_error("illegal option -%c", c);
2039 if (*++q == ':')
2040 q++;
2042 if (*++q == ':') {
2043 if (*p == '\0') {
2044 p = *argptr++;
2045 if (p == NULL)
2046 ash_msg_and_raise_error("no arg for -%c option", c);
2048 optionarg = p;
2049 p = NULL;
2051 optptr = p;
2052 return c;
2056 /* ============ Shell variables */
2058 struct shparam {
2059 int nparam; /* # of positional parameters (without $0) */
2060 #if ENABLE_ASH_GETOPTS
2061 int optind; /* next parameter to be processed by getopts */
2062 int optoff; /* used by getopts */
2063 #endif
2064 unsigned char malloced; /* if parameter list dynamically allocated */
2065 char **p; /* parameter list */
2069 * Free the list of positional parameters.
2071 static void
2072 freeparam(volatile struct shparam *param)
2074 if (param->malloced) {
2075 char **ap, **ap1;
2076 ap = ap1 = param->p;
2077 while (*ap)
2078 free(*ap++);
2079 free(ap1);
2083 #if ENABLE_ASH_GETOPTS
2084 static void FAST_FUNC getoptsreset(const char *value);
2085 #endif
2087 struct var {
2088 struct var *next; /* next entry in hash list */
2089 int flags; /* flags are defined above */
2090 const char *var_text; /* name=value */
2091 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
2092 /* the variable gets set/unset */
2095 struct localvar {
2096 struct localvar *next; /* next local variable in list */
2097 struct var *vp; /* the variable that was made local */
2098 int flags; /* saved flags */
2099 const char *text; /* saved text */
2102 /* flags */
2103 #define VEXPORT 0x01 /* variable is exported */
2104 #define VREADONLY 0x02 /* variable cannot be modified */
2105 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
2106 #define VTEXTFIXED 0x08 /* text is statically allocated */
2107 #define VSTACK 0x10 /* text is allocated on the stack */
2108 #define VUNSET 0x20 /* the variable is not set */
2109 #define VNOFUNC 0x40 /* don't call the callback function */
2110 #define VNOSET 0x80 /* do not set variable - just readonly test */
2111 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
2112 #if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2113 # define VDYNAMIC 0x200 /* dynamic variable */
2114 #else
2115 # define VDYNAMIC 0
2116 #endif
2119 /* Need to be before varinit_data[] */
2120 #if ENABLE_LOCALE_SUPPORT
2121 static void FAST_FUNC
2122 change_lc_all(const char *value)
2124 if (value && *value != '\0')
2125 setlocale(LC_ALL, value);
2127 static void FAST_FUNC
2128 change_lc_ctype(const char *value)
2130 if (value && *value != '\0')
2131 setlocale(LC_CTYPE, value);
2133 #endif
2134 #if ENABLE_ASH_MAIL
2135 static void changemail(const char *var_value) FAST_FUNC;
2136 #endif
2137 static void changepath(const char *) FAST_FUNC;
2138 #if ENABLE_ASH_RANDOM_SUPPORT
2139 static void change_random(const char *) FAST_FUNC;
2140 #endif
2141 #if BASH_EPOCH_VARS
2142 static void change_seconds(const char *) FAST_FUNC;
2143 static void change_realtime(const char *) FAST_FUNC;
2144 #endif
2146 static const struct {
2147 int flags;
2148 const char *var_text;
2149 void (*var_func)(const char *) FAST_FUNC;
2150 } varinit_data[] ALIGN_PTR = {
2152 * Note: VEXPORT would not work correctly here for NOFORK applets:
2153 * some environment strings may be constant.
2155 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
2156 #if ENABLE_ASH_MAIL
2157 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2158 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
2159 #endif
2160 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2161 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2162 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2163 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
2164 #if ENABLE_ASH_GETOPTS
2165 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
2166 #endif
2167 { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
2168 { VSTRFIXED|VTEXTFIXED , NULL /* inited to funcnamevar */, NULL },
2169 #if ENABLE_ASH_RANDOM_SUPPORT
2170 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2171 #endif
2172 #if BASH_EPOCH_VARS
2173 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHSECONDS", change_seconds },
2174 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHREALTIME", change_realtime },
2175 #endif
2176 #if ENABLE_LOCALE_SUPPORT
2177 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2178 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
2179 #endif
2180 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
2181 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
2182 #endif
2185 struct redirtab;
2187 struct globals_var {
2188 struct shparam shellparam; /* $@ current positional parameters */
2189 struct redirtab *redirlist;
2190 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
2191 struct var *vartab[VTABSIZE];
2192 struct var varinit[ARRAY_SIZE(varinit_data)];
2193 int lineno;
2194 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2195 char funcnamevar[sizeof("FUNCNAME=") + 64];
2196 char *funcname;
2197 unsigned trap_depth;
2198 bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */
2200 extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2201 #define G_var (*ash_ptr_to_globals_var)
2202 #define shellparam (G_var.shellparam )
2203 //#define redirlist (G_var.redirlist )
2204 #define preverrout_fd (G_var.preverrout_fd)
2205 #define vartab (G_var.vartab )
2206 #define varinit (G_var.varinit )
2207 #define lineno (G_var.lineno )
2208 #define linenovar (G_var.linenovar )
2209 #define funcnamevar (G_var.funcnamevar )
2210 #define funcname (G_var.funcname )
2211 #define trap_depth (G_var.trap_depth )
2212 #define in_trap_ERR (G_var.in_trap_ERR )
2213 #define vifs varinit[0]
2214 #if ENABLE_ASH_MAIL
2215 # define vmail varinit[1]
2216 # define vmpath varinit[2]
2217 #endif
2218 #define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
2219 #define vpath varinit[VAR_OFFSET1 + 1]
2220 #define vps1 varinit[VAR_OFFSET1 + 2]
2221 #define vps2 varinit[VAR_OFFSET1 + 3]
2222 #define vps4 varinit[VAR_OFFSET1 + 4]
2223 #if ENABLE_ASH_GETOPTS
2224 # define voptind varinit[VAR_OFFSET1 + 5]
2225 #endif
2226 #define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
2227 #define vlineno varinit[VAR_OFFSET2 + 5]
2228 #define vfuncname varinit[VAR_OFFSET2 + 6]
2229 #if ENABLE_ASH_RANDOM_SUPPORT
2230 # define vrandom varinit[VAR_OFFSET2 + 7]
2231 #endif
2232 #define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
2233 #if BASH_EPOCH_VARS
2234 # define vepochs varinit[VAR_OFFSET3 + 7]
2235 # define vepochr varinit[VAR_OFFSET3 + 8]
2236 #endif
2237 #define INIT_G_var() do { \
2238 unsigned i; \
2239 XZALLOC_CONST_PTR(&ash_ptr_to_globals_var, sizeof(G_var)); \
2240 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2241 varinit[i].flags = varinit_data[i].flags; \
2242 varinit[i].var_text = varinit_data[i].var_text; \
2243 varinit[i].var_func = varinit_data[i].var_func; \
2245 strcpy(linenovar, "LINENO="); \
2246 vlineno.var_text = linenovar; \
2247 strcpy(funcnamevar, "FUNCNAME="); \
2248 vfuncname.var_text = funcnamevar; \
2249 } while (0)
2252 * The following macros access the values of the above variables.
2253 * They have to skip over the name. They return the null string
2254 * for unset variables.
2256 #define ifsval() (vifs.var_text + 4)
2257 #define ifsset() ((vifs.flags & VUNSET) == 0)
2258 #if ENABLE_ASH_MAIL
2259 # define mailval() (vmail.var_text + 5)
2260 # define mpathval() (vmpath.var_text + 9)
2261 # define mpathset() ((vmpath.flags & VUNSET) == 0)
2262 #endif
2263 #define pathval() (vpath.var_text + 5)
2264 #define ps1val() (vps1.var_text + 4)
2265 #define ps2val() (vps2.var_text + 4)
2266 #define ps4val() (vps4.var_text + 4)
2267 #if ENABLE_ASH_GETOPTS
2268 # define optindval() (voptind.var_text + 7)
2269 #endif
2271 #if ENABLE_ASH_GETOPTS
2272 static void FAST_FUNC
2273 getoptsreset(const char *value)
2275 shellparam.optind = 1;
2276 if (is_number(value))
2277 shellparam.optind = number(value) ?: 1;
2278 shellparam.optoff = -1;
2280 #endif
2283 * Find the appropriate entry in the hash table from the name.
2285 static struct var **
2286 hashvar(const char *p)
2288 unsigned hashval;
2290 hashval = ((unsigned char) *p) << 4;
2291 while (*p && *p != '=')
2292 hashval += (unsigned char) *p++;
2293 return &vartab[hashval % VTABSIZE];
2296 static int
2297 vpcmp(const void *a, const void *b)
2299 return varcmp(*(const char **)a, *(const char **)b);
2303 * This routine initializes the builtin variables.
2305 static void
2306 initvar(void)
2308 struct var *vp;
2309 struct var *end;
2310 struct var **vpp;
2313 * PS1 depends on uid
2315 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2316 vps1.var_text = "PS1=\\w \\$ ";
2317 #else
2318 if (!geteuid())
2319 vps1.var_text = "PS1=# ";
2320 #endif
2321 vp = varinit;
2322 end = vp + ARRAY_SIZE(varinit);
2323 do {
2324 vpp = hashvar(vp->var_text);
2325 vp->next = *vpp;
2326 *vpp = vp;
2327 } while (++vp < end);
2330 static struct var **
2331 findvar(struct var **vpp, const char *name)
2333 for (; *vpp; vpp = &(*vpp)->next) {
2334 if (varcmp((*vpp)->var_text, name) == 0) {
2335 break;
2338 return vpp;
2342 * Find the value of a variable. Returns NULL if not set.
2344 static const char* FAST_FUNC
2345 lookupvar(const char *name)
2347 struct var *v;
2349 v = *findvar(hashvar(name), name);
2350 if (v) {
2351 #if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2353 * Dynamic variables are implemented roughly the same way they are
2354 * in bash. Namely, they're "special" so long as they aren't unset.
2355 * As soon as they're unset, they're no longer dynamic, and dynamic
2356 * lookup will no longer happen at that point. -- PFM.
2358 if (v->flags & VDYNAMIC)
2359 v->var_func(NULL);
2360 #endif
2361 if (!(v->flags & VUNSET)) {
2362 if (v->var_text == linenovar) {
2363 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2364 } else
2365 if (v->var_text == funcnamevar) {
2366 safe_strncpy(funcnamevar+9, funcname ? funcname : "", sizeof(funcnamevar)-9);
2368 return var_end(v->var_text);
2371 return NULL;
2374 #if ENABLE_UNICODE_SUPPORT
2375 static void
2376 reinit_unicode_for_ash(void)
2378 /* Unicode support should be activated even if LANG is set
2379 * _during_ shell execution, not only if it was set when
2380 * shell was started. Therefore, re-check LANG every time:
2382 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2383 || ENABLE_UNICODE_USING_LOCALE
2385 const char *s = lookupvar("LC_ALL");
2386 if (!s) s = lookupvar("LC_CTYPE");
2387 if (!s) s = lookupvar("LANG");
2388 reinit_unicode(s);
2391 #else
2392 # define reinit_unicode_for_ash() ((void)0)
2393 #endif
2396 * Search the environment of a builtin command.
2398 static ALWAYS_INLINE const char *
2399 bltinlookup(const char *name)
2401 return lookupvar(name);
2405 * Same as setvar except that the variable and value are passed in
2406 * the first argument as name=value. Since the first argument will
2407 * be actually stored in the table, it should not be a string that
2408 * will go away.
2409 * Called with interrupts off.
2411 static struct var *
2412 setvareq(char *s, int flags)
2414 struct var *vp, **vpp;
2416 vpp = hashvar(s);
2417 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2418 vpp = findvar(vpp, s);
2419 vp = *vpp;
2420 if (vp) {
2421 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2422 const char *n;
2424 if (flags & VNOSAVE)
2425 free(s);
2426 n = vp->var_text;
2427 exitstatus = 1;
2428 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2431 if (flags & VNOSET)
2432 goto out;
2434 if (vp->var_func && !(flags & VNOFUNC))
2435 vp->var_func(var_end(s));
2437 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2438 free((char*)vp->var_text);
2440 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2441 *vpp = vp->next;
2442 free(vp);
2443 out_free:
2444 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2445 free(s);
2446 goto out;
2449 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2450 #if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2451 if (flags & VUNSET)
2452 flags &= ~VDYNAMIC;
2453 #endif
2454 } else {
2455 /* variable s is not found */
2456 if (flags & VNOSET)
2457 goto out;
2458 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2459 goto out_free;
2460 vp = ckzalloc(sizeof(*vp));
2461 vp->next = *vpp;
2462 /*vp->func = NULL; - ckzalloc did it */
2463 *vpp = vp;
2465 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2466 s = ckstrdup(s);
2467 vp->var_text = s;
2468 vp->flags = flags;
2470 out:
2471 return vp;
2475 * Set the value of a variable. The flags argument is ored with the
2476 * flags of the variable. If val is NULL, the variable is unset.
2478 static struct var *
2479 setvar(const char *name, const char *val, int flags)
2481 const char *q;
2482 char *p;
2483 char *nameeq;
2484 size_t namelen;
2485 size_t vallen;
2486 struct var *vp;
2488 q = endofname(name);
2489 p = strchrnul(q, '=');
2490 namelen = p - name;
2491 if (!namelen || p != q)
2492 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2493 vallen = 0;
2494 if (val == NULL) {
2495 flags |= VUNSET;
2496 } else {
2497 vallen = strlen(val);
2500 INT_OFF;
2501 nameeq = ckzalloc(namelen + vallen + 2);
2502 p = mempcpy(nameeq, name, namelen);
2503 if (val) {
2504 *p++ = '=';
2505 strcpy(p, val);
2507 vp = setvareq(nameeq, flags | VNOSAVE);
2508 INT_ON;
2510 return vp;
2513 static void FAST_FUNC
2514 setvar0(const char *name, const char *val)
2516 setvar(name, val, 0);
2520 * Unset the specified variable.
2522 static void
2523 unsetvar(const char *s)
2525 setvar(s, NULL, 0);
2529 * Generate a list of variables satisfying the given conditions.
2531 #if !ENABLE_FEATURE_SH_NOFORK
2532 # define listvars(on, off, lp, end) listvars(on, off, end)
2533 #endif
2534 static char **
2535 listvars(int on, int off, struct strlist *lp, char ***end)
2537 struct var **vpp;
2538 struct var *vp;
2539 char **ep;
2540 int mask;
2542 STARTSTACKSTR(ep);
2543 vpp = vartab;
2544 mask = on | off;
2545 do {
2546 for (vp = *vpp; vp; vp = vp->next) {
2547 if ((vp->flags & mask) == on) {
2548 #if ENABLE_FEATURE_SH_NOFORK
2549 /* If variable with the same name is both
2550 * exported and temporarily set for a command:
2551 * export ZVAR=5
2552 * ZVAR=6 printenv
2553 * then "ZVAR=6" will be both in vartab and
2554 * lp lists. Do not pass it twice to printenv.
2556 struct strlist *lp1 = lp;
2557 while (lp1) {
2558 if (strcmp(lp1->text, vp->var_text) == 0)
2559 goto skip;
2560 lp1 = lp1->next;
2562 #endif
2563 if (ep == stackstrend())
2564 ep = growstackstr();
2565 *ep++ = (char*)vp->var_text;
2566 #if ENABLE_FEATURE_SH_NOFORK
2567 skip: ;
2568 #endif
2571 } while (++vpp < vartab + VTABSIZE);
2573 #if ENABLE_FEATURE_SH_NOFORK
2574 while (lp) {
2575 if (ep == stackstrend())
2576 ep = growstackstr();
2577 *ep++ = lp->text;
2578 lp = lp->next;
2580 #endif
2582 if (ep == stackstrend())
2583 ep = growstackstr();
2584 if (end)
2585 *end = ep;
2586 *ep++ = NULL;
2587 return grabstackstr(ep);
2591 /* ============ Path search helper */
2592 static const char *
2593 legal_pathopt(const char *opt, const char *term, int magic)
2595 switch (magic) {
2596 case 0:
2597 opt = NULL;
2598 break;
2600 case 1:
2601 opt = prefix(opt, "builtin") ?: prefix(opt, "func");
2602 break;
2604 default:
2605 opt += strcspn(opt, term);
2606 break;
2609 if (opt && *opt == '%')
2610 opt++;
2612 return opt;
2616 * The variable path (passed by reference) should be set to the start
2617 * of the path before the first call; padvance will update
2618 * this value as it proceeds. Successive calls to padvance will return
2619 * the possible path expansions in sequence. If an option (indicated by
2620 * a percent sign) appears in the path entry then the global variable
2621 * pathopt will be set to point to it; otherwise pathopt will be set to
2622 * NULL.
2624 * If magic is 0 then pathopt recognition will be disabled. If magic is
2625 * 1 we shall recognise %builtin/%func. Otherwise we shall accept any
2626 * pathopt.
2628 static const char *pathopt; /* set by padvance */
2630 static int
2631 padvance_magic(const char **path, const char *name, int magic)
2633 const char *term = "%:";
2634 const char *lpathopt;
2635 const char *p;
2636 char *q;
2637 const char *start;
2638 size_t qlen;
2639 size_t len;
2641 if (*path == NULL)
2642 return -1;
2644 lpathopt = NULL;
2645 start = *path;
2647 if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) {
2648 lpathopt = start + 1;
2649 start = p;
2650 term = ":";
2653 len = strcspn(start, term);
2654 p = start + len;
2656 if (*p == '%') {
2657 size_t extra = strchrnul(p, ':') - p;
2659 if (legal_pathopt(p + 1, term, magic))
2660 lpathopt = p + 1;
2661 else
2662 len += extra;
2664 p += extra;
2667 pathopt = lpathopt;
2668 *path = *p == ':' ? p + 1 : NULL;
2670 /* "2" is for '/' and '\0' */
2671 qlen = len + strlen(name) + 2;
2672 q = growstackto(qlen);
2674 if (len) {
2675 q = mempcpy(q, start, len);
2676 *q++ = '/';
2678 strcpy(q, name);
2680 return qlen;
2683 static int
2684 padvance(const char **path, const char *name)
2686 return padvance_magic(path, name, 1);
2690 /* ============ Prompt */
2692 static smallint doprompt; /* if set, prompt the user */
2693 static smallint needprompt; /* true if interactive and at start of line */
2695 #if ENABLE_FEATURE_EDITING
2696 static line_input_t *line_input_state;
2697 static const char *cmdedit_prompt;
2698 static void
2699 putprompt(const char *s)
2701 if (ENABLE_ASH_EXPAND_PRMT) {
2702 free((char*)cmdedit_prompt);
2703 cmdedit_prompt = ckstrdup(s);
2704 return;
2706 cmdedit_prompt = s;
2708 #else
2709 static void
2710 putprompt(const char *s)
2712 out2str(s);
2714 #endif
2716 /* expandstr() needs parsing machinery, so it is far away ahead... */
2717 static const char *expandstr(const char *ps, int syntax_type);
2718 /* Values for syntax param */
2719 #define BASESYNTAX 0 /* not in quotes */
2720 #define DQSYNTAX 1 /* in double quotes */
2721 #define SQSYNTAX 2 /* in single quotes */
2722 #define ARISYNTAX 3 /* in arithmetic */
2723 #if ENABLE_ASH_EXPAND_PRMT
2724 # define PSSYNTAX 4 /* prompt. never passed to SIT() */
2725 #endif
2726 /* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
2729 * called by editline -- any expansions to the prompt should be added here.
2731 static void
2732 setprompt_if(smallint do_set, int whichprompt)
2734 const char *prompt;
2735 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2737 if (!do_set)
2738 return;
2740 needprompt = 0;
2742 switch (whichprompt) {
2743 case 1:
2744 prompt = ps1val();
2745 break;
2746 case 2:
2747 prompt = ps2val();
2748 break;
2749 default: /* 0 */
2750 prompt = nullstr;
2752 #if ENABLE_ASH_EXPAND_PRMT
2753 pushstackmark(&smark, stackblocksize());
2754 putprompt(expandstr(prompt, PSSYNTAX));
2755 popstackmark(&smark);
2756 #else
2757 putprompt(prompt);
2758 #endif
2762 /* ============ The cd and pwd commands */
2764 #define CD_PHYSICAL 1
2765 #define CD_PRINT 2
2767 static int
2768 cdopt(void)
2770 int flags = 0;
2771 int i, j;
2773 j = 'L';
2774 while ((i = nextopt("LP")) != '\0') {
2775 if (i != j) {
2776 flags ^= CD_PHYSICAL;
2777 j = i;
2781 return flags;
2785 * Update curdir (the name of the current directory) in response to a
2786 * cd command.
2788 static const char *
2789 updatepwd(const char *dir)
2791 char *new;
2792 char *p;
2793 char *cdcomppath;
2794 const char *lim;
2796 cdcomppath = sstrdup(dir);
2797 STARTSTACKSTR(new);
2798 if (*dir != '/') {
2799 if (curdir == nullstr)
2800 return 0;
2801 new = stack_putstr(curdir, new);
2803 new = makestrspace(strlen(dir) + 2, new);
2804 lim = (char *)stackblock() + 1;
2805 if (*dir != '/') {
2806 if (new[-1] != '/')
2807 USTPUTC('/', new);
2808 if (new > lim && *lim == '/')
2809 lim++;
2810 } else {
2811 USTPUTC('/', new);
2812 cdcomppath++;
2813 if (dir[1] == '/' && dir[2] != '/') {
2814 USTPUTC('/', new);
2815 cdcomppath++;
2816 lim++;
2819 p = strtok_r(cdcomppath, "/", &cdcomppath);
2820 while (p) {
2821 switch (*p) {
2822 case '.':
2823 if (p[1] == '.' && p[2] == '\0') {
2824 while (new > lim) {
2825 STUNPUTC(new);
2826 if (new[-1] == '/')
2827 break;
2829 break;
2831 if (p[1] == '\0')
2832 break;
2833 /* fall through */
2834 default:
2835 new = stack_putstr(p, new);
2836 USTPUTC('/', new);
2838 p = strtok_r(NULL, "/", &cdcomppath);
2840 if (new > lim)
2841 STUNPUTC(new);
2842 *new = 0;
2843 return stackblock();
2847 * Find out what the current directory is. If we already know the current
2848 * directory, this routine returns immediately.
2850 static char *
2851 getpwd(void)
2853 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2854 return dir ? dir : nullstr;
2857 static void
2858 setpwd(const char *val, int setold)
2860 char *oldcur, *dir;
2862 oldcur = dir = curdir;
2864 if (setold) {
2865 setvar("OLDPWD", oldcur, VEXPORT);
2867 INT_OFF;
2868 if (physdir != nullstr) {
2869 if (physdir != oldcur)
2870 free(physdir);
2871 physdir = nullstr;
2873 if (oldcur == val || !val) {
2874 char *s = getpwd();
2875 physdir = s;
2876 if (!val)
2877 dir = s;
2878 } else
2879 dir = ckstrdup(val);
2880 if (oldcur != dir && oldcur != nullstr) {
2881 free(oldcur);
2883 curdir = dir;
2884 INT_ON;
2885 setvar("PWD", dir, VEXPORT);
2888 static void hashcd(void);
2891 * Actually do the chdir. We also call hashcd to let other routines
2892 * know that the current directory has changed.
2894 static int
2895 docd(const char *dest, int flags)
2897 const char *dir = NULL;
2898 int err;
2900 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2902 INT_OFF;
2903 if (!(flags & CD_PHYSICAL)) {
2904 dir = updatepwd(dest);
2905 if (dir)
2906 dest = dir;
2908 err = chdir(dest);
2909 if (err)
2910 goto out;
2911 setpwd(dir, 1);
2912 hashcd();
2913 out:
2914 INT_ON;
2915 return err;
2918 static int FAST_FUNC
2919 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2921 const char *dest;
2922 const char *path;
2923 const char *p;
2924 char c;
2925 struct stat statb;
2926 int flags;
2927 int len;
2929 flags = cdopt();
2930 dest = *argptr;
2931 if (!dest)
2932 dest = bltinlookup("HOME");
2933 else if (LONE_DASH(dest)) {
2934 dest = bltinlookup("OLDPWD");
2935 flags |= CD_PRINT;
2937 if (!dest)
2938 dest = nullstr;
2939 if (*dest == '/')
2940 goto step6;
2941 if (*dest == '.') {
2942 c = dest[1];
2943 dotdot:
2944 switch (c) {
2945 case '\0':
2946 case '/':
2947 goto step6;
2948 case '.':
2949 c = dest[2];
2950 if (c != '.')
2951 goto dotdot;
2954 if (!*dest)
2955 dest = ".";
2956 path = bltinlookup("CDPATH");
2957 while (p = path, (len = padvance_magic(&path, dest, 0)) >= 0) {
2958 c = *p;
2959 p = stalloc(len);
2961 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2962 if (c && c != ':')
2963 flags |= CD_PRINT;
2964 docd:
2965 if (!docd(p, flags))
2966 goto out;
2967 goto err;
2971 step6:
2972 p = dest;
2973 goto docd;
2975 err:
2976 ash_msg_and_raise_perror("can't cd to %s", dest);
2977 /* NOTREACHED */
2978 out:
2979 if (flags & CD_PRINT)
2980 out1fmt("%s\n", curdir);
2981 return 0;
2984 static int FAST_FUNC
2985 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2987 int flags;
2988 const char *dir = curdir;
2990 flags = cdopt();
2991 if (flags) {
2992 if (physdir == nullstr)
2993 setpwd(dir, 0);
2994 dir = physdir;
2996 out1fmt("%s\n", dir);
2997 return 0;
3001 /* ============ ... */
3004 #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
3006 /* Syntax classes */
3007 #define CWORD 0 /* character is nothing special */
3008 #define CNL 1 /* newline character */
3009 #define CBACK 2 /* a backslash character */
3010 #define CSQUOTE 3 /* single quote */
3011 #define CDQUOTE 4 /* double quote */
3012 #define CENDQUOTE 5 /* a terminating quote */
3013 #define CBQUOTE 6 /* backwards single quote */
3014 #define CVAR 7 /* a dollar sign */
3015 #define CENDVAR 8 /* a '}' character */
3016 #define CLP 9 /* a left paren in arithmetic */
3017 #define CRP 10 /* a right paren in arithmetic */
3018 #define CENDFILE 11 /* end of file */
3019 #define CCTL 12 /* like CWORD, except it must be escaped */
3020 #define CSPCL 13 /* these terminate a word */
3022 #define PEOF 256
3024 #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
3026 #if ENABLE_FEATURE_SH_MATH
3027 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
3028 #else
3029 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
3030 #endif
3031 static const uint16_t S_I_T[] ALIGN2 = {
3032 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 0, ' ' */
3033 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 1, \n */
3034 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 2, !*-/:=?[]~ */
3035 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 3, '"' */
3036 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 4, $ */
3037 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 5, "'" */
3038 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 6, ( */
3039 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 7, ) */
3040 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 8, \ */
3041 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 9, ` */
3042 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 10, } */
3043 #if !USE_SIT_FUNCTION
3044 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 11, PEOF */
3045 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 12, 0-9A-Za-z */
3046 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 13, CTLESC ... */
3047 #endif
3048 #undef SIT_ITEM
3050 /* Constants below must match table above */
3051 enum {
3052 CSPCL_CWORD_CWORD_CWORD , /* 0 */
3053 CNL_CNL_CNL_CNL , /* 1 */
3054 CWORD_CCTL_CCTL_CWORD , /* 2 */
3055 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 3 */
3056 CVAR_CVAR_CWORD_CVAR , /* 4 */
3057 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 5 */
3058 CSPCL_CWORD_CWORD_CLP , /* 6 */
3059 CSPCL_CWORD_CWORD_CRP , /* 7 */
3060 CBACK_CBACK_CCTL_CBACK , /* 8 */
3061 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 9 */
3062 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 10 */
3063 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 11 */
3064 CWORD_CWORD_CWORD_CWORD , /* 12 */
3065 CCTL_CCTL_CCTL_CCTL , /* 13 */
3068 /* c in SIT(c, syntax) must be an *unsigned char* or PEOF,
3069 * caller must ensure proper cast on it if c is *char_ptr!
3071 #if USE_SIT_FUNCTION
3073 static int
3074 SIT(int c, int syntax)
3076 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
3077 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
3079 * This causes '/' to be prepended with CTLESC in dquoted string,
3080 * making "./file"* treated incorrectly because we feed
3081 * ".\/file*" string to glob(), confusing it (see expandmeta func).
3082 * The "homegrown" glob implementation is okay with that,
3083 * but glibc one isn't. With '/' always treated as CWORD,
3084 * both work fine.
3086 static const uint8_t syntax_index_table[] ALIGN1 = {
3087 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
3088 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
3089 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
3090 10, 2 /* "}~" */
3092 const char *s;
3093 int indx;
3095 if (c == PEOF)
3096 return CENDFILE;
3097 /* Cast is purely for paranoia here,
3098 * just in case someone passed signed char to us */
3099 if ((unsigned char)c >= CTL_FIRST
3100 && (unsigned char)c <= CTL_LAST
3102 return CCTL;
3104 s = strchrnul(spec_symbls, c);
3105 if (*s == '\0')
3106 return CWORD;
3107 indx = syntax_index_table[s - spec_symbls];
3108 return (S_I_T[indx] >> (syntax*4)) & 0xf;
3111 #else /* !USE_SIT_FUNCTION */
3113 static const uint8_t syntax_index_table[] ALIGN1 = {
3114 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
3115 /* 0 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 1 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 2 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 3 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 4 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 5 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 6 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 7 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 8 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3125 /* 10 "\n" */ CNL_CNL_CNL_CNL,
3126 /* 11 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 12 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 13 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 14 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 15 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 16 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 17 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 18 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 19 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 20 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 21 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 22 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 23 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 24 */ CWORD_CWORD_CWORD_CWORD,
3140 /* 25 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 26 */ CWORD_CWORD_CWORD_CWORD,
3142 /* 27 */ CWORD_CWORD_CWORD_CWORD,
3143 /* 28 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 29 */ CWORD_CWORD_CWORD_CWORD,
3145 /* 30 */ CWORD_CWORD_CWORD_CWORD,
3146 /* 31 */ CWORD_CWORD_CWORD_CWORD,
3147 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
3148 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
3149 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3150 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
3151 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
3152 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
3153 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
3154 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3155 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
3156 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
3157 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
3158 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
3159 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
3160 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
3161 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
3162 /* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3163 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
3164 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
3165 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
3166 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
3167 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
3168 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
3169 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
3170 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
3171 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
3172 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
3173 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
3174 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
3175 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
3176 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
3177 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
3178 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
3179 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
3180 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
3181 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
3182 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
3183 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
3184 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
3185 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
3186 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
3187 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
3188 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
3189 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
3190 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
3191 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
3192 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
3193 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
3194 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
3195 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
3196 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3197 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3198 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3199 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3200 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3201 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3202 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3203 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3204 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3205 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3206 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3207 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3208 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3209 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3210 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3211 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3212 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3213 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3214 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3215 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3216 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3217 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3218 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3219 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3220 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3221 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3222 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3223 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3224 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3225 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3226 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3227 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3228 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3229 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3230 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3231 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3232 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3233 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3234 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3235 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3236 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3237 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3238 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3239 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3240 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3241 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3242 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3243 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3244 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3245 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3246 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3247 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3248 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3249 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3250 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3251 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3252 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3253 #if BASH_PROCESS_SUBST
3254 /* 137 CTLTOPROC */ CCTL_CCTL_CCTL_CCTL,
3255 /* 138 CTLFROMPROC */ CCTL_CCTL_CCTL_CCTL,
3256 #else
3257 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3258 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3259 #endif
3260 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3261 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3262 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3263 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3264 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3265 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3266 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3267 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3268 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3269 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3270 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3271 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3272 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3273 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3274 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3275 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3276 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3277 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3278 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3279 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3280 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3281 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3282 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3283 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3284 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3285 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3286 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3287 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3288 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3289 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3290 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3291 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3292 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3293 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3294 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3295 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3296 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3297 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3298 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3299 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3300 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3301 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3302 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3303 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3304 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3305 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3306 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3307 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3308 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3309 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3310 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3311 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3312 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3313 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3314 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3315 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3316 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3317 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3318 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3319 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3320 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3321 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3322 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3323 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3324 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3325 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3326 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3327 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3328 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3329 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3330 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3331 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3332 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3333 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3334 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3335 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3336 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3337 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3338 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3339 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3340 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3341 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3342 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3343 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3344 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3345 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3346 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3347 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3348 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3349 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3350 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3351 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3352 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3353 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3354 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3355 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3356 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3357 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3358 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3359 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3360 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3361 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3362 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3363 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3364 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3365 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3366 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3367 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3368 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3369 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3370 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3371 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3372 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3373 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3374 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3375 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3376 /* 255 */ CWORD_CWORD_CWORD_CWORD,
3377 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3380 #if 1
3381 # define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3382 #else /* debug version, caught one signed char bug */
3383 # define SIT(c, syntax) \
3384 ({ \
3385 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3386 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3387 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3388 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3389 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3391 #endif
3393 #endif /* !USE_SIT_FUNCTION */
3396 /* ============ Alias handling */
3398 #if ENABLE_ASH_ALIAS
3400 #define ALIASINUSE 1
3401 #define ALIASDEAD 2
3403 struct alias {
3404 struct alias *next;
3405 char *name;
3406 char *val;
3407 int flag;
3411 static struct alias **atab; // [ATABSIZE];
3412 #define INIT_G_alias() do { \
3413 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3414 } while (0)
3417 static struct alias **
3418 __lookupalias(const char *name)
3420 unsigned int hashval;
3421 struct alias **app;
3422 const char *p;
3423 unsigned int ch;
3425 p = name;
3427 ch = (unsigned char)*p;
3428 hashval = ch << 4;
3429 while (ch) {
3430 hashval += ch;
3431 ch = (unsigned char)*++p;
3433 app = &atab[hashval % ATABSIZE];
3435 for (; *app; app = &(*app)->next) {
3436 if (strcmp(name, (*app)->name) == 0) {
3437 break;
3441 return app;
3444 static struct alias *
3445 lookupalias(const char *name, int check)
3447 struct alias *ap = *__lookupalias(name);
3449 if (check && ap && (ap->flag & ALIASINUSE))
3450 return NULL;
3451 return ap;
3454 static struct alias *
3455 freealias(struct alias *ap)
3457 struct alias *next;
3459 if (ap->flag & ALIASINUSE) {
3460 ap->flag |= ALIASDEAD;
3461 return ap;
3464 next = ap->next;
3465 free(ap->name);
3466 free(ap->val);
3467 free(ap);
3468 return next;
3471 static void
3472 setalias(const char *name, const char *val)
3474 struct alias *ap, **app;
3476 app = __lookupalias(name);
3477 ap = *app;
3478 INT_OFF;
3479 if (ap) {
3480 if (!(ap->flag & ALIASINUSE)) {
3481 free(ap->val);
3483 ap->val = ckstrdup(val);
3484 ap->flag &= ~ALIASDEAD;
3485 } else {
3486 /* not found */
3487 ap = ckzalloc(sizeof(struct alias));
3488 ap->name = ckstrdup(name);
3489 ap->val = ckstrdup(val);
3490 /*ap->flag = 0; - ckzalloc did it */
3491 /*ap->next = NULL;*/
3492 *app = ap;
3494 INT_ON;
3497 static int
3498 unalias(const char *name)
3500 struct alias **app;
3502 app = __lookupalias(name);
3504 if (*app) {
3505 INT_OFF;
3506 *app = freealias(*app);
3507 INT_ON;
3508 return 0;
3511 return 1;
3514 static void
3515 rmaliases(void)
3517 struct alias *ap, **app;
3518 int i;
3520 INT_OFF;
3521 for (i = 0; i < ATABSIZE; i++) {
3522 app = &atab[i];
3523 for (ap = *app; ap; ap = *app) {
3524 *app = freealias(*app);
3525 if (ap == *app) {
3526 app = &ap->next;
3530 INT_ON;
3533 static void
3534 printalias(const struct alias *ap)
3536 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3540 * TODO - sort output
3542 static int FAST_FUNC
3543 aliascmd(int argc UNUSED_PARAM, char **argv)
3545 char *n, *v;
3546 int ret = 0;
3547 struct alias *ap;
3549 if (!argv[1]) {
3550 int i;
3552 for (i = 0; i < ATABSIZE; i++) {
3553 for (ap = atab[i]; ap; ap = ap->next) {
3554 printalias(ap);
3557 return 0;
3559 while ((n = *++argv) != NULL) {
3560 v = strchr(n+1, '=');
3561 if (v == NULL) { /* n+1: funny ksh stuff */
3562 ap = *__lookupalias(n);
3563 if (ap == NULL) {
3564 fprintf(stderr, "%s: %s not found\n", "alias", n);
3565 ret = 1;
3566 } else
3567 printalias(ap);
3568 } else {
3569 *v++ = '\0';
3570 setalias(n, v);
3574 return ret;
3577 static int FAST_FUNC
3578 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3580 int i;
3582 while (nextopt("a") != '\0') {
3583 rmaliases();
3584 return 0;
3586 for (i = 0; *argptr; argptr++) {
3587 if (unalias(*argptr)) {
3588 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3589 i = 1;
3593 return i;
3596 #endif /* ASH_ALIAS */
3599 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3600 #define FORK_FG 0
3601 #define FORK_BG 1
3602 #define FORK_NOJOB 2
3604 /* mode flags for showjob(s) */
3605 #define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3606 #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3607 #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
3608 #define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
3611 * A job structure contains information about a job. A job is either a
3612 * single process or a set of processes contained in a pipeline. In the
3613 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3614 * array of pids.
3616 struct procstat {
3617 pid_t ps_pid; /* process id */
3618 int ps_status; /* last process status from wait() */
3619 char *ps_cmd; /* text of command being run */
3622 struct job {
3623 struct procstat ps0; /* status of process */
3624 struct procstat *ps; /* status of processes when more than one */
3625 #if JOBS
3626 int stopstatus; /* status of a stopped job */
3627 #endif
3628 unsigned nprocs; /* number of processes */
3630 #define JOBRUNNING 0 /* at least one proc running */
3631 #define JOBSTOPPED 1 /* all procs are stopped */
3632 #define JOBDONE 2 /* all procs are completed */
3633 unsigned
3634 state: 8,
3635 #if JOBS
3636 sigint: 1, /* job was killed by SIGINT */
3637 jobctl: 1, /* job running under job control */
3638 #endif
3639 waited: 1, /* true if this entry has been waited for */
3640 used: 1, /* true if this entry is in used */
3641 changed: 1; /* true if status has changed */
3642 struct job *prev_job; /* previous job */
3645 static struct job *makejob(/*union node *,*/ int);
3646 static int forkshell(struct job *, union node *, int);
3647 static int waitforjob(struct job *);
3649 #if !JOBS
3650 enum { doing_jobctl = 0 };
3651 #define setjobctl(on) do {} while (0)
3652 #else
3653 static smallint doing_jobctl; //references:8
3654 static void setjobctl(int);
3655 #endif
3658 * Ignore a signal.
3660 static void
3661 ignoresig(int signo)
3663 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3664 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3665 /* No, need to do it */
3666 signal(signo, SIG_IGN);
3668 sigmode[signo - 1] = S_HARD_IGN;
3672 * Only one usage site - in setsignal()
3674 static void
3675 signal_handler(int signo)
3677 if (signo == SIGCHLD) {
3678 got_sigchld = 1;
3679 if (!trap[SIGCHLD])
3680 return;
3682 #if ENABLE_FEATURE_EDITING
3683 bb_got_signal = signo; /* for read_line_input: "we got a signal" */
3684 #endif
3685 gotsig[signo - 1] = 1;
3686 pending_sig = signo;
3688 if (signo == SIGINT && !trap[SIGINT]) {
3689 if (!suppress_int) {
3690 pending_sig = 0;
3691 raise_interrupt(); /* does not return */
3693 pending_int = 1;
3698 * Set the signal handler for the specified signal. The routine figures
3699 * out what it should be set to.
3701 static void
3702 setsignal(int signo)
3704 char *t;
3705 char cur_act, new_act;
3706 struct sigaction act;
3708 t = trap[signo];
3709 new_act = S_DFL;
3710 if (t != NULL) { /* trap for this sig is set */
3711 new_act = S_CATCH;
3712 if (t[0] == '\0') /* trap is "": ignore this sig */
3713 new_act = S_IGN;
3716 if (rootshell && new_act == S_DFL) {
3717 switch (signo) {
3718 case SIGINT:
3719 if (iflag || minusc || sflag == 0)
3720 new_act = S_CATCH;
3721 break;
3722 case SIGQUIT:
3723 #if DEBUG
3724 if (debug)
3725 break;
3726 #endif
3727 /* man bash:
3728 * "In all cases, bash ignores SIGQUIT. Non-builtin
3729 * commands run by bash have signal handlers
3730 * set to the values inherited by the shell
3731 * from its parent". */
3732 new_act = S_IGN;
3733 break;
3734 case SIGTERM:
3735 if (iflag)
3736 new_act = S_IGN;
3737 break;
3738 #if JOBS
3739 case SIGTSTP:
3740 case SIGTTOU:
3741 if (mflag)
3742 new_act = S_IGN;
3743 break;
3744 #endif
3747 /* if !rootshell, we reset SIGQUIT to DFL,
3748 * whereas we have to restore it to what shell got on entry.
3749 * This is handled by the fact that if signal was IGNored on entry,
3750 * then cur_act is S_HARD_IGN and we never change its sigaction
3751 * (see code below).
3754 if (signo == SIGCHLD)
3755 new_act = S_CATCH;
3757 t = &sigmode[signo - 1];
3758 cur_act = *t;
3759 if (cur_act == 0) {
3760 /* current setting is not yet known */
3761 if (sigaction(signo, NULL, &act)) {
3762 /* pretend it worked; maybe we should give a warning,
3763 * but other shells don't. We don't alter sigmode,
3764 * so we retry every time.
3765 * btw, in Linux it never fails. --vda */
3766 return;
3768 if (act.sa_handler == SIG_IGN) {
3769 cur_act = S_HARD_IGN;
3770 if (mflag
3771 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3773 cur_act = S_IGN; /* don't hard ignore these */
3776 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3777 /* installing SIG_DFL over SIG_DFL is a no-op */
3778 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3779 *t = S_DFL;
3780 return;
3783 if (cur_act == S_HARD_IGN || cur_act == new_act)
3784 return;
3786 *t = new_act;
3788 act.sa_handler = SIG_DFL;
3789 switch (new_act) {
3790 case S_CATCH:
3791 act.sa_handler = signal_handler;
3792 break;
3793 case S_IGN:
3794 act.sa_handler = SIG_IGN;
3795 break;
3797 /* flags and mask matter only if !DFL and !IGN, but we do it
3798 * for all cases for more deterministic behavior:
3800 act.sa_flags = 0; //TODO: why not SA_RESTART?
3801 sigfillset(&act.sa_mask);
3803 sigaction_set(signo, &act);
3806 /* mode flags for set_curjob */
3807 #define CUR_DELETE 2
3808 #define CUR_RUNNING 1
3809 #define CUR_STOPPED 0
3811 #if JOBS
3812 /* pgrp of shell on invocation */
3813 static int initialpgrp; //references:2
3814 static int ttyfd = -1; //5
3815 #endif
3816 /* array of jobs */
3817 static struct job *jobtab; //5
3818 /* size of array */
3819 static unsigned njobs; //4
3820 /* current job */
3821 static struct job *curjob; //lots
3823 #if 0
3824 /* Bash has a feature: it restores termios after a successful wait for
3825 * a foreground job which had at least one stopped or sigkilled member.
3826 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3827 * properly restoring tty state. Should we do this too?
3828 * A reproducer: ^Z an interactive python:
3830 * # python
3831 * Python 2.7.12 (...)
3832 * >>> ^Z
3833 * { python leaves tty in -icanon -echo state. We do survive that... }
3834 * [1]+ Stopped python
3835 * { ...however, next program (python #2) does not survive it well: }
3836 * # python
3837 * Python 2.7.12 (...)
3838 * >>> Traceback (most recent call last):
3839 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3840 * File "<stdin>", line 1, in <module>
3841 * NameError: name 'qwerty' is not defined
3843 * The implementation below is modeled on bash code and seems to work.
3844 * However, I'm not sure we should do this. For one: what if I'd fg
3845 * the stopped python instead? It'll be confused by "restored" tty state.
3847 static struct termios shell_tty_info;
3848 static void
3849 get_tty_state(void)
3851 if (rootshell && ttyfd >= 0)
3852 tcgetattr(ttyfd, &shell_tty_info);
3854 static void
3855 set_tty_state(void)
3857 /* if (rootshell) - caller ensures this */
3858 if (ttyfd >= 0)
3859 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3861 static int
3862 job_signal_status(struct job *jp)
3864 int status;
3865 unsigned i;
3866 struct procstat *ps = jp->ps;
3867 for (i = 0; i < jp->nprocs; i++) {
3868 status = ps[i].ps_status;
3869 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3870 return status;
3872 return 0;
3874 static void
3875 restore_tty_if_stopped_or_signaled(struct job *jp)
3877 //TODO: check what happens if we come from waitforjob() in expbackq()
3878 if (rootshell) {
3879 int s = job_signal_status(jp);
3880 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3881 set_tty_state();
3884 #else
3885 # define get_tty_state() ((void)0)
3886 # define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3887 #endif
3889 static void
3890 set_curjob(struct job *jp, unsigned mode)
3892 struct job *jp1;
3893 struct job **jpp, **curp;
3895 /* first remove from list */
3896 jpp = curp = &curjob;
3897 while (1) {
3898 jp1 = *jpp;
3899 if (jp1 == jp)
3900 break;
3901 jpp = &jp1->prev_job;
3903 *jpp = jp1->prev_job;
3905 /* Then re-insert in correct position */
3906 jpp = curp;
3907 switch (mode) {
3908 default:
3909 #if DEBUG
3910 abort();
3911 #endif
3912 case CUR_DELETE:
3913 /* job being deleted */
3914 break;
3915 case CUR_RUNNING:
3916 /* newly created job or backgrounded job,
3917 * put after all stopped jobs.
3919 while (1) {
3920 jp1 = *jpp;
3921 #if JOBS
3922 if (!jp1 || jp1->state != JOBSTOPPED)
3923 #endif
3924 break;
3925 jpp = &jp1->prev_job;
3927 /* FALLTHROUGH */
3928 #if JOBS
3929 case CUR_STOPPED:
3930 #endif
3931 /* newly stopped job - becomes curjob */
3932 jp->prev_job = *jpp;
3933 *jpp = jp;
3934 break;
3938 #if JOBS || DEBUG
3939 static int
3940 jobno(const struct job *jp)
3942 return jp - jobtab + 1;
3944 #endif
3947 * Convert a job name to a job structure.
3949 #if !JOBS
3950 #define getjob(name, getctl) getjob(name)
3951 #endif
3952 static struct job *
3953 getjob(const char *name, int getctl)
3955 struct job *jp;
3956 struct job *found;
3957 const char *err_msg = "%s: no such job";
3958 unsigned num;
3959 int c;
3960 const char *p;
3962 jp = curjob;
3963 p = name;
3964 if (!p)
3965 goto currentjob;
3967 if (*p != '%')
3968 goto err;
3970 c = *++p;
3971 if (!c)
3972 goto currentjob;
3974 if (!p[1]) {
3975 if (c == '+' || c == '%') {
3976 currentjob:
3977 err_msg = "No current job";
3978 goto check;
3980 if (c == '-') {
3981 if (jp)
3982 jp = jp->prev_job;
3983 err_msg = "No previous job";
3984 check:
3985 if (!jp)
3986 goto err;
3987 goto gotit;
3991 if (is_number(p)) {
3992 num = atoi(p);
3993 if (num > 0 && num <= njobs) {
3994 jp = jobtab + num - 1;
3995 if (jp->used)
3996 goto gotit;
3997 goto err;
4001 found = NULL;
4002 while (jp) {
4003 if (*p == '?'
4004 ? strstr(jp->ps[0].ps_cmd, p + 1)
4005 : prefix(jp->ps[0].ps_cmd, p)
4007 if (found)
4008 goto err;
4009 found = jp;
4010 err_msg = "%s: ambiguous";
4012 jp = jp->prev_job;
4014 if (!found)
4015 goto err;
4016 jp = found;
4018 gotit:
4019 #if JOBS
4020 err_msg = "job %s not created under job control";
4021 if (getctl && jp->jobctl == 0)
4022 goto err;
4023 #endif
4024 return jp;
4025 err:
4026 ash_msg_and_raise_error(err_msg, name);
4030 * Mark a job structure as unused.
4032 static void
4033 freejob(struct job *jp)
4035 struct procstat *ps;
4036 int i;
4038 INT_OFF;
4039 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
4040 if (ps->ps_cmd != nullstr)
4041 free(ps->ps_cmd);
4043 if (jp->ps != &jp->ps0)
4044 free(jp->ps);
4045 jp->used = 0;
4046 set_curjob(jp, CUR_DELETE);
4047 INT_ON;
4050 #if JOBS
4051 static void
4052 xtcsetpgrp(int fd, pid_t pgrp)
4054 if (tcsetpgrp(fd, pgrp))
4055 ash_msg_and_raise_perror("can't set tty process group");
4059 * Turn job control on and off.
4061 * Note: This code assumes that the third arg to ioctl is a character
4062 * pointer, which is true on Berkeley systems but not System V. Since
4063 * System V doesn't have job control yet, this isn't a problem now.
4065 * Called with interrupts off.
4067 static void
4068 setjobctl(int on)
4070 int fd;
4071 int pgrp;
4073 if (on == doing_jobctl || rootshell == 0)
4074 return;
4075 if (on) {
4076 int ofd;
4077 ofd = fd = open(_PATH_TTY, O_RDWR);
4078 if (fd < 0) {
4079 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
4080 * That sometimes helps to acquire controlling tty.
4081 * Obviously, a workaround for bugs when someone
4082 * failed to provide a controlling tty to bash! :) */
4083 fd = 2;
4084 while (!isatty(fd))
4085 if (--fd < 0)
4086 goto out;
4088 /* fd is a tty at this point */
4089 fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
4090 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
4091 close(ofd);
4092 if (fd < 0)
4093 goto out; /* F_DUPFD failed */
4094 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
4095 close_on_exec_on(fd);
4096 while (1) { /* while we are in the background */
4097 pgrp = tcgetpgrp(fd);
4098 if (pgrp < 0) {
4099 out:
4100 ash_msg("can't access tty; job control turned off");
4101 mflag = on = 0;
4102 goto close;
4104 if (pgrp == getpgrp())
4105 break;
4106 killpg(0, SIGTTIN);
4108 initialpgrp = pgrp;
4110 setsignal(SIGTSTP);
4111 setsignal(SIGTTOU);
4112 setsignal(SIGTTIN);
4113 pgrp = rootpid;
4114 setpgid(0, pgrp);
4115 xtcsetpgrp(fd, pgrp);
4116 } else {
4117 /* turning job control off */
4118 fd = ttyfd;
4119 pgrp = initialpgrp;
4120 /* was xtcsetpgrp, but this can make exiting ash
4121 * loop forever if pty is already deleted */
4122 tcsetpgrp(fd, pgrp);
4123 setpgid(0, pgrp);
4124 setsignal(SIGTSTP);
4125 setsignal(SIGTTOU);
4126 setsignal(SIGTTIN);
4127 close:
4128 if (fd >= 0)
4129 close(fd);
4130 fd = -1;
4132 ttyfd = fd;
4133 doing_jobctl = on;
4136 static int FAST_FUNC
4137 killcmd(int argc, char **argv)
4139 if (argv[1] && strcmp(argv[1], "-l") != 0) {
4140 int i = 1;
4141 do {
4142 if (argv[i][0] == '%') {
4144 * "kill %N" - job kill
4145 * Converting to pgrp / pid kill
4147 struct job *jp;
4148 char *dst;
4149 int j, n;
4151 jp = getjob(argv[i], 0);
4153 * In jobs started under job control, we signal
4154 * entire process group by kill -PGRP_ID.
4155 * This happens, f.e., in interactive shell.
4157 * Otherwise, we signal each child via
4158 * kill PID1 PID2 PID3.
4159 * Testcases:
4160 * sh -c 'sleep 1|sleep 1 & kill %1'
4161 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4162 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4164 n = jp->nprocs; /* can't be 0 (I hope) */
4165 if (jp->jobctl)
4166 n = 1;
4167 dst = alloca(n * sizeof(int)*4);
4168 argv[i] = dst;
4169 for (j = 0; j < n; j++) {
4170 struct procstat *ps = &jp->ps[j];
4171 /* Skip non-running and not-stopped members
4172 * (i.e. dead members) of the job
4174 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4175 continue;
4177 * kill_main has matching code to expect
4178 * leading space. Needed to not confuse
4179 * negative pids with "kill -SIGNAL_NO" syntax
4181 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4183 *dst = '\0';
4185 } while (argv[++i]);
4187 return kill_main(argc, argv);
4190 static void
4191 showpipe(struct job *jp /*, FILE *out*/)
4193 struct procstat *ps;
4194 struct procstat *psend;
4196 psend = jp->ps + jp->nprocs;
4197 for (ps = jp->ps + 1; ps < psend; ps++)
4198 printf(" | %s", ps->ps_cmd);
4199 newline_and_flush(stdout);
4200 flush_stdout_stderr();
4204 static int
4205 restartjob(struct job *jp, int mode)
4207 struct procstat *ps;
4208 int i;
4209 int status;
4210 pid_t pgid;
4212 INT_OFF;
4213 if (jp->state == JOBDONE)
4214 goto out;
4215 jp->state = JOBRUNNING;
4216 pgid = jp->ps[0].ps_pid;
4217 if (mode == FORK_FG) {
4218 get_tty_state();
4219 xtcsetpgrp(ttyfd, pgid);
4221 killpg(pgid, SIGCONT);
4222 ps = jp->ps;
4223 i = jp->nprocs;
4224 do {
4225 if (WIFSTOPPED(ps->ps_status)) {
4226 ps->ps_status = -1;
4228 ps++;
4229 } while (--i);
4230 out:
4231 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4232 INT_ON;
4233 return status;
4236 static int FAST_FUNC
4237 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
4239 struct job *jp;
4240 int mode;
4241 int retval;
4243 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4244 nextopt(nullstr);
4245 argv = argptr;
4246 do {
4247 jp = getjob(*argv, 1);
4248 if (mode == FORK_BG) {
4249 set_curjob(jp, CUR_RUNNING);
4250 printf("[%d] ", jobno(jp));
4252 out1str(jp->ps[0].ps_cmd);
4253 showpipe(jp /*, stdout*/);
4254 retval = restartjob(jp, mode);
4255 } while (*argv && *++argv);
4256 return retval;
4258 #endif
4260 static int
4261 sprint_status48(char *os, int status, int sigonly)
4263 char *s = os;
4264 int st;
4266 if (!WIFEXITED(status)) {
4267 #if JOBS
4268 if (WIFSTOPPED(status))
4269 st = WSTOPSIG(status);
4270 else
4271 #endif
4272 st = WTERMSIG(status);
4273 if (sigonly) {
4274 if (st == SIGINT || st == SIGPIPE)
4275 goto out;
4276 #if JOBS
4277 if (WIFSTOPPED(status))
4278 goto out;
4279 #endif
4281 st &= 0x7f;
4282 s = stpncpy(s, strsignal(st), 32);
4283 if (WCOREDUMP(status)) {
4284 s = stpcpy(s, " (core dumped)");
4286 } else if (!sigonly) {
4287 st = WEXITSTATUS(status);
4288 s += fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
4290 out:
4291 return s - os;
4294 #define DOWAIT_NONBLOCK 0
4295 #define DOWAIT_BLOCK 1
4296 #define DOWAIT_BLOCK_OR_SIG 2
4297 #if BASH_WAIT_N
4298 # define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */
4299 #endif
4301 static int
4302 waitproc(int block, int *status)
4304 sigset_t oldmask;
4305 int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
4306 int err;
4308 #if JOBS
4309 if (doing_jobctl)
4310 flags |= WUNTRACED;
4311 #endif
4313 do {
4314 got_sigchld = 0;
4316 err = waitpid(-1, status, flags);
4317 while (err < 0 && errno == EINTR);
4319 if (err || (err = -!block))
4320 break;
4322 sigfillset(&oldmask);
4323 sigprocmask2(SIG_SETMASK, &oldmask); /* mask is updated */
4324 while (!got_sigchld && !pending_sig)
4325 sigsuspend(&oldmask);
4326 sigprocmask(SIG_SETMASK, &oldmask, NULL);
4327 //simpler, but unsafe: a signal can set pending_sig after check, but before pause():
4328 //while (!got_sigchld && !pending_sig)
4329 // pause();
4331 } while (got_sigchld);
4333 return err;
4336 static int
4337 waitone(int block, struct job *job)
4339 int pid;
4340 int status;
4341 struct job *jp;
4342 struct job *thisjob = NULL;
4343 #if BASH_WAIT_N
4344 bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
4345 block = (block & ~DOWAIT_JOBSTATUS);
4346 #endif
4348 TRACE(("dowait(0x%x) called\n", block));
4350 /* It's wrong to call waitpid() outside of INT_OFF region:
4351 * signal can arrive just after syscall return and handler can
4352 * longjmp away, losing stop/exit notification processing.
4353 * Thus, for "jobs" builtin, and for waiting for a fg job,
4354 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4356 * However, for "wait" builtin it is wrong to simply call waitpid()
4357 * in INT_OFF region: "wait" needs to wait for any running job
4358 * to change state, but should exit on any trap too.
4359 * In INT_OFF region, a signal just before syscall entry can set
4360 * pending_sig variables, but we can't check them, and we would
4361 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
4363 * Because of this, we run inside INT_OFF, but use a special routine
4364 * which combines waitpid() and sigsuspend().
4365 * This is the reason why we need to have a handler for SIGCHLD:
4366 * SIG_DFL handler does not wake sigsuspend().
4368 INT_OFF;
4369 pid = waitproc(block, &status);
4370 TRACE(("wait returns pid %d, status=%d\n", pid, status));
4371 if (pid <= 0)
4372 goto out;
4374 for (jp = curjob; jp; jp = jp->prev_job) {
4375 int jobstate;
4376 struct procstat *ps;
4377 struct procstat *psend;
4378 if (jp->state == JOBDONE)
4379 continue;
4380 jobstate = JOBDONE;
4381 ps = jp->ps;
4382 psend = ps + jp->nprocs;
4383 do {
4384 if (ps->ps_pid == pid) {
4385 TRACE(("Job %d: changing status of proc %d "
4386 "from 0x%x to 0x%x\n",
4387 jobno(jp), pid, ps->ps_status, status));
4388 ps->ps_status = status;
4389 thisjob = jp;
4391 if (ps->ps_status == -1)
4392 jobstate = JOBRUNNING;
4393 #if JOBS
4394 if (jobstate == JOBRUNNING)
4395 continue;
4396 if (WIFSTOPPED(ps->ps_status)) {
4397 jp->stopstatus = ps->ps_status;
4398 jobstate = JOBSTOPPED;
4400 #endif
4401 } while (++ps < psend);
4402 if (!thisjob)
4403 continue;
4405 /* Found the job where one of its processes changed its state.
4406 * Is there at least one live and running process in this job? */
4407 if (jobstate != JOBRUNNING) {
4408 /* No. All live processes in the job are stopped
4409 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4411 thisjob->changed = 1;
4412 if (thisjob->state != jobstate) {
4413 TRACE(("Job %d: changing state from %d to %d\n",
4414 jobno(thisjob), thisjob->state, jobstate));
4415 thisjob->state = jobstate;
4416 #if JOBS
4417 if (jobstate == JOBSTOPPED)
4418 set_curjob(thisjob, CUR_STOPPED);
4419 #endif
4422 goto out;
4424 /* The process wasn't found in job list */
4425 out:
4426 INT_ON;
4428 #if BASH_WAIT_N
4429 if (want_jobexitstatus) {
4430 pid = -1;
4431 if (thisjob && thisjob->state == JOBDONE)
4432 pid = thisjob->ps[thisjob->nprocs - 1].ps_status;
4434 #endif
4435 if (thisjob && thisjob == job) {
4436 char s[48 + 1];
4437 int len;
4439 len = sprint_status48(s, status, 1);
4440 if (len) {
4441 s[len] = '\n';
4442 s[len + 1] = '\0';
4443 out2str(s);
4446 return pid;
4449 static int
4450 dowait(int block, struct job *jp)
4452 smallint gotchld = *(volatile smallint *)&got_sigchld;
4453 int rpid;
4454 int pid;
4456 if (jp && jp->state != JOBRUNNING)
4457 block = DOWAIT_NONBLOCK;
4459 if (block == DOWAIT_NONBLOCK && !gotchld)
4460 return 1;
4462 rpid = 1;
4464 do {
4465 pid = waitone(block, jp);
4466 rpid &= !!pid;
4468 if (!pid || (jp && jp->state != JOBRUNNING))
4469 block = DOWAIT_NONBLOCK;
4470 } while (pid >= 0);
4472 return rpid;
4475 #if JOBS
4476 static void
4477 showjob(struct job *jp, int mode)
4479 struct procstat *ps;
4480 struct procstat *psend;
4481 int col;
4482 int indent_col;
4483 char s[16 + 16 + 48];
4484 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4486 ps = jp->ps;
4488 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4489 /* just output process (group) id of pipeline */
4490 fprintf(out, "%d\n", ps->ps_pid);
4491 return;
4494 col = fmtstr(s, 16, "[%d] ", jobno(jp));
4495 indent_col = col;
4497 if (jp == curjob)
4498 s[col - 3] = '+';
4499 else if (curjob && jp == curjob->prev_job)
4500 s[col - 3] = '-';
4502 if (mode & SHOW_PIDS)
4503 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4505 psend = ps + jp->nprocs;
4507 if (jp->state == JOBRUNNING) {
4508 strcpy(s + col, "Running");
4509 col += sizeof("Running") - 1;
4510 } else {
4511 int status = psend[-1].ps_status;
4512 if (jp->state == JOBSTOPPED)
4513 status = jp->stopstatus;
4514 col += sprint_status48(s + col, status, 0);
4516 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
4518 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4519 * or prints several "PID | <cmdN>" lines,
4520 * depending on SHOW_PIDS bit.
4521 * We do not print status of individual processes
4522 * between PID and <cmdN>. bash does it, but not very well:
4523 * first line shows overall job status, not process status,
4524 * making it impossible to know 1st process status.
4526 goto start;
4527 do {
4528 /* for each process */
4529 s[0] = '\0';
4530 col = 33;
4531 if (mode & SHOW_PIDS)
4532 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4533 start:
4534 fprintf(out, "%s%*c%s%s",
4536 33 - col >= 0 ? 33 - col : 0, ' ',
4537 ps == jp->ps ? "" : "| ",
4538 ps->ps_cmd
4540 } while (++ps != psend);
4541 newline_and_flush(out);
4543 jp->changed = 0;
4545 if (jp->state == JOBDONE) {
4546 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4547 freejob(jp);
4552 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4553 * statuses have changed since the last call to showjobs.
4555 static void
4556 showjobs(int mode)
4558 struct job *jp;
4560 TRACE(("showjobs(0x%x) called\n", mode));
4562 /* Handle all finished jobs */
4563 dowait(DOWAIT_NONBLOCK, NULL);
4565 for (jp = curjob; jp; jp = jp->prev_job) {
4566 if (!(mode & SHOW_CHANGED) || jp->changed) {
4567 showjob(jp, mode);
4572 static int FAST_FUNC
4573 jobscmd(int argc UNUSED_PARAM, char **argv)
4575 int mode, m;
4577 mode = 0;
4578 while ((m = nextopt("lp")) != '\0') {
4579 if (m == 'l')
4580 mode |= SHOW_PIDS;
4581 else
4582 mode |= SHOW_ONLY_PGID;
4585 argv = argptr;
4586 if (*argv) {
4588 showjob(getjob(*argv, 0), mode);
4589 while (*++argv);
4590 } else {
4591 showjobs(mode);
4594 return 0;
4596 #endif /* JOBS */
4598 /* Called only on finished or stopped jobs (no members are running) */
4599 static int
4600 getstatus(struct job *job)
4602 int status;
4603 int retval;
4604 struct procstat *ps;
4606 /* Fetch last member's status */
4607 ps = job->ps + job->nprocs - 1;
4608 status = ps->ps_status;
4609 if (pipefail) {
4610 /* "set -o pipefail" mode: use last _nonzero_ status */
4611 while (status == 0 && --ps >= job->ps)
4612 status = ps->ps_status;
4615 retval = WEXITSTATUS(status);
4616 if (!WIFEXITED(status)) {
4617 #if JOBS
4618 retval = WSTOPSIG(status);
4619 if (!WIFSTOPPED(status))
4620 #endif
4622 /* XXX: limits number of signals */
4623 retval = WTERMSIG(status);
4624 #if JOBS
4625 if (retval == SIGINT)
4626 job->sigint = 1;
4627 #endif
4629 retval |= 128;
4631 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4632 jobno(job), job->nprocs, status, retval));
4633 return retval;
4636 static int FAST_FUNC
4637 waitcmd(int argc UNUSED_PARAM, char **argv)
4639 struct job *job;
4640 int retval;
4641 struct job *jp;
4642 #if BASH_WAIT_N
4643 int status;
4644 char one = nextopt("n");
4645 #else
4646 nextopt(nullstr);
4647 #endif
4648 retval = 0;
4650 argv = argptr;
4651 if (!argv[0]) {
4652 /* wait for all jobs / one job if -n */
4653 for (;;) {
4654 jp = curjob;
4655 #if BASH_WAIT_N
4656 if (one && !jp)
4657 /* exitcode of "wait -n" with nothing to wait for is 127, not 0 */
4658 retval = 127;
4659 #endif
4660 while (1) {
4661 if (!jp) /* no running procs */
4662 goto ret;
4663 if (jp->state == JOBRUNNING)
4664 break;
4665 jp->waited = 1;
4666 jp = jp->prev_job;
4668 /* man bash:
4669 * "When bash is waiting for an asynchronous command via
4670 * the wait builtin, the reception of a signal for which a trap
4671 * has been set will cause the wait builtin to return immediately
4672 * with an exit status greater than 128, immediately after which
4673 * the trap is executed."
4675 #if BASH_WAIT_N
4676 status = dowait(DOWAIT_BLOCK_OR_SIG | DOWAIT_JOBSTATUS, NULL);
4677 #else
4678 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4679 #endif
4680 /* if child sends us a signal *and immediately exits*,
4681 * dowait() returns pid > 0. Check this case,
4682 * not "if (dowait() < 0)"!
4684 if (pending_sig)
4685 goto sigout;
4686 #if BASH_WAIT_N
4687 if (one) {
4688 /* wait -n waits for one _job_, not one _process_.
4689 * date; sleep 3 & sleep 2 | sleep 1 & wait -n; date
4690 * should wait for 2 seconds. Not 1 or 3.
4692 if (status != -1 && !WIFSTOPPED(status)) {
4693 retval = WEXITSTATUS(status);
4694 if (WIFSIGNALED(status))
4695 retval = 128 | WTERMSIG(status);
4696 goto ret;
4699 #endif
4703 retval = 127;
4704 do {
4705 if (**argv != '%') {
4706 pid_t pid = number(*argv);
4707 job = curjob;
4708 while (1) {
4709 if (!job)
4710 goto repeat;
4711 if (job->ps[job->nprocs - 1].ps_pid == pid)
4712 break;
4713 job = job->prev_job;
4715 } else {
4716 job = getjob(*argv, 0);
4718 /* loop until process terminated or stopped */
4719 dowait(DOWAIT_BLOCK_OR_SIG, job);
4720 if (pending_sig)
4721 goto sigout;
4722 job->waited = 1;
4723 retval = getstatus(job);
4724 repeat: ;
4725 } while (*++argv);
4727 ret:
4728 return retval;
4729 sigout:
4730 retval = 128 | pending_sig;
4731 return retval;
4734 static struct job *
4735 growjobtab(void)
4737 size_t len;
4738 ptrdiff_t offset;
4739 struct job *jp, *jq;
4741 len = njobs * sizeof(*jp);
4742 jq = jobtab;
4743 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4745 offset = (char *)jp - (char *)jq;
4746 if (offset) {
4747 /* Relocate pointers */
4748 size_t l = len;
4750 jq = (struct job *)((char *)jq + l);
4751 while (l) {
4752 l -= sizeof(*jp);
4753 jq--;
4754 #define joff(p) ((struct job *)((char *)(p) + l))
4755 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4756 if (joff(jp)->ps == &jq->ps0)
4757 jmove(joff(jp)->ps);
4758 if (joff(jp)->prev_job)
4759 jmove(joff(jp)->prev_job);
4761 if (curjob)
4762 jmove(curjob);
4763 #undef joff
4764 #undef jmove
4767 njobs += 4;
4768 jobtab = jp;
4769 jp = (struct job *)((char *)jp + len);
4770 jq = jp + 3;
4771 do {
4772 jq->used = 0;
4773 } while (--jq >= jp);
4774 return jp;
4778 * Return a new job structure.
4779 * Called with interrupts off.
4781 static struct job *
4782 makejob(/*union node *node,*/ int nprocs)
4784 int i;
4785 struct job *jp;
4787 for (i = njobs, jp = jobtab; ; jp++) {
4788 if (--i < 0) {
4789 jp = growjobtab();
4790 break;
4792 if (jp->used == 0)
4793 break;
4794 if (jp->state != JOBDONE || !jp->waited)
4795 continue;
4796 #if JOBS
4797 if (doing_jobctl)
4798 continue;
4799 #endif
4800 freejob(jp);
4801 break;
4803 memset(jp, 0, sizeof(*jp));
4804 #if JOBS
4805 /* jp->jobctl is a bitfield.
4806 * "jp->jobctl |= doing_jobctl" likely to give awful code */
4807 if (doing_jobctl)
4808 jp->jobctl = 1;
4809 #endif
4810 jp->prev_job = curjob;
4811 curjob = jp;
4812 jp->used = 1;
4813 jp->ps = &jp->ps0;
4814 if (nprocs > 1) {
4815 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4817 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4818 jobno(jp)));
4819 return jp;
4822 #if JOBS
4824 * Return a string identifying a command (to be printed by the
4825 * jobs command).
4827 static char *cmdnextc;
4829 static void
4830 cmdputs(const char *s)
4832 static const char vstype[VSTYPE + 1][3] ALIGN1 = {
4833 "", "}", "-", "+", "?", "=",
4834 "%", "%%", "#", "##"
4835 IF_BASH_SUBSTR(, ":")
4836 IF_BASH_PATTERN_SUBST(, "/", "//")
4839 const char *p, *str;
4840 char cc[2];
4841 char *nextc;
4842 unsigned char c;
4843 unsigned char subtype = 0;
4844 int quoted = 0;
4846 cc[1] = '\0';
4847 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4848 p = s;
4849 while ((c = *p++) != '\0') {
4850 str = NULL;
4851 switch (c) {
4852 case CTLESC:
4853 c = *p++;
4854 break;
4855 case CTLVAR:
4856 subtype = *p++;
4857 if ((subtype & VSTYPE) == VSLENGTH)
4858 str = "${#";
4859 else
4860 str = "${";
4861 goto dostr;
4862 case CTLENDVAR:
4863 str = "\"}";
4864 str += !(quoted & 1);
4865 quoted >>= 1;
4866 subtype = 0;
4867 goto dostr;
4868 #if BASH_PROCESS_SUBST
4869 case CTLBACKQ:
4870 c = '$';
4871 str = "(...)";
4872 break;
4873 case CTLTOPROC:
4874 c = '>';
4875 str = "(...)";
4876 break;
4877 case CTLFROMPROC:
4878 c = '<';
4879 str = "(...)";
4880 break;
4881 #else
4882 case CTLBACKQ:
4883 str = "$(...)";
4884 goto dostr;
4885 #endif
4886 #if ENABLE_FEATURE_SH_MATH
4887 case CTLARI:
4888 str = "$((";
4889 goto dostr;
4890 case CTLENDARI:
4891 str = "))";
4892 goto dostr;
4893 #endif
4894 case CTLQUOTEMARK:
4895 quoted ^= 1;
4896 c = '"';
4897 break;
4898 case '=':
4899 if (subtype == 0)
4900 break;
4901 if ((subtype & VSTYPE) != VSNORMAL)
4902 quoted <<= 1;
4903 str = vstype[subtype & VSTYPE];
4904 if (subtype & VSNUL)
4905 c = ':';
4906 else
4907 goto checkstr;
4908 break;
4909 case '\'':
4910 case '\\':
4911 case '"':
4912 case '$':
4913 /* These can only happen inside quotes */
4914 cc[0] = c;
4915 str = cc;
4916 //FIXME:
4917 // $ true $$ &
4918 // $ <cr>
4919 // [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
4920 c = '\\';
4921 break;
4922 default:
4923 break;
4925 USTPUTC(c, nextc);
4926 checkstr:
4927 if (!str)
4928 continue;
4929 dostr:
4930 while ((c = *str++) != '\0') {
4931 USTPUTC(c, nextc);
4933 } /* while *p++ not NUL */
4935 if (quoted & 1) {
4936 USTPUTC('"', nextc);
4938 *nextc = 0;
4939 cmdnextc = nextc;
4942 /* cmdtxt() and cmdlist() call each other */
4943 static void cmdtxt(union node *n);
4945 static void
4946 cmdlist(union node *np, int sep)
4948 for (; np; np = np->narg.next) {
4949 if (!sep)
4950 cmdputs(" ");
4951 cmdtxt(np);
4952 if (sep && np->narg.next)
4953 cmdputs(" ");
4957 static void
4958 cmdtxt(union node *n)
4960 union node *np;
4961 struct nodelist *lp;
4962 const char *p;
4964 if (!n)
4965 return;
4966 switch (n->type) {
4967 default:
4968 #if DEBUG
4969 abort();
4970 #endif
4971 case NPIPE:
4972 lp = n->npipe.cmdlist;
4973 for (;;) {
4974 cmdtxt(lp->n);
4975 lp = lp->next;
4976 if (!lp)
4977 break;
4978 cmdputs(" | ");
4980 break;
4981 case NSEMI:
4982 p = "; ";
4983 goto binop;
4984 case NAND:
4985 p = " && ";
4986 goto binop;
4987 case NOR:
4988 p = " || ";
4989 binop:
4990 cmdtxt(n->nbinary.ch1);
4991 cmdputs(p);
4992 n = n->nbinary.ch2;
4993 goto donode;
4994 case NREDIR:
4995 case NBACKGND:
4996 n = n->nredir.n;
4997 goto donode;
4998 case NNOT:
4999 cmdputs("!");
5000 n = n->nnot.com;
5001 donode:
5002 cmdtxt(n);
5003 break;
5004 case NIF:
5005 cmdputs("if ");
5006 cmdtxt(n->nif.test);
5007 cmdputs("; then ");
5008 if (n->nif.elsepart) {
5009 cmdtxt(n->nif.ifpart);
5010 cmdputs("; else ");
5011 n = n->nif.elsepart;
5012 } else {
5013 n = n->nif.ifpart;
5015 p = "; fi";
5016 goto dotail;
5017 case NSUBSHELL:
5018 cmdputs("(");
5019 n = n->nredir.n;
5020 p = ")";
5021 goto dotail;
5022 case NWHILE:
5023 p = "while ";
5024 goto until;
5025 case NUNTIL:
5026 p = "until ";
5027 until:
5028 cmdputs(p);
5029 cmdtxt(n->nbinary.ch1);
5030 n = n->nbinary.ch2;
5031 p = "; done";
5032 dodo:
5033 cmdputs("; do ");
5034 dotail:
5035 cmdtxt(n);
5036 goto dotail2;
5037 case NFOR:
5038 cmdputs("for ");
5039 cmdputs(n->nfor.var);
5040 cmdputs(" in ");
5041 cmdlist(n->nfor.args, 1);
5042 n = n->nfor.body;
5043 p = "; done";
5044 goto dodo;
5045 case NDEFUN:
5046 cmdputs(n->ndefun.text);
5047 p = "() { ... }";
5048 goto dotail2;
5049 case NCMD:
5050 cmdlist(n->ncmd.args, 1);
5051 cmdlist(n->ncmd.redirect, 0);
5052 break;
5053 case NARG:
5054 p = n->narg.text;
5055 dotail2:
5056 cmdputs(p);
5057 break;
5058 case NHERE:
5059 case NXHERE:
5060 p = "<<...";
5061 goto dotail2;
5062 case NCASE:
5063 cmdputs("case ");
5064 cmdputs(n->ncase.expr->narg.text);
5065 cmdputs(" in ");
5066 for (np = n->ncase.cases; np; np = np->nclist.next) {
5067 cmdtxt(np->nclist.pattern);
5068 cmdputs(") ");
5069 cmdtxt(np->nclist.body);
5070 cmdputs(";; ");
5072 p = "esac";
5073 goto dotail2;
5074 case NTO:
5075 p = ">";
5076 goto redir;
5077 case NCLOBBER:
5078 p = ">|";
5079 goto redir;
5080 case NAPPEND:
5081 p = ">>";
5082 goto redir;
5083 #if BASH_REDIR_OUTPUT
5084 case NTO2:
5085 #endif
5086 case NTOFD:
5087 p = ">&";
5088 goto redir;
5089 case NFROM:
5090 p = "<";
5091 goto redir;
5092 case NFROMFD:
5093 p = "<&";
5094 goto redir;
5095 case NFROMTO:
5096 p = "<>";
5097 redir:
5098 cmdputs(utoa(n->nfile.fd));
5099 cmdputs(p);
5100 if (n->type == NTOFD || n->type == NFROMFD) {
5101 if (n->ndup.dupfd >= 0)
5102 cmdputs(utoa(n->ndup.dupfd));
5103 else
5104 cmdputs("-");
5105 break;
5107 n = n->nfile.fname;
5108 goto donode;
5112 static char *
5113 commandtext(union node *n)
5115 char *name;
5117 STARTSTACKSTR(cmdnextc);
5118 cmdtxt(n);
5119 name = stackblock();
5120 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
5121 return ckstrdup(name);
5123 #endif /* JOBS */
5126 * Fork off a subshell. If we are doing job control, give the subshell its
5127 * own process group. Jp is a job structure that the job is to be added to.
5128 * N is the command that will be evaluated by the child. Both jp and n may
5129 * be NULL. The mode parameter can be one of the following:
5130 * FORK_FG - Fork off a foreground process.
5131 * FORK_BG - Fork off a background process.
5132 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
5133 * process group even if job control is on.
5135 * When job control is turned off, background processes have their standard
5136 * input redirected to /dev/null (except for the second and later processes
5137 * in a pipeline).
5139 * Called with interrupts off.
5142 * Clear traps on a fork.
5144 static void
5145 clear_traps(void)
5147 char **tp;
5149 INT_OFF;
5150 for (tp = trap; tp <= &trap[NTRAP_LAST]; tp++) {
5151 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
5152 if (trap_ptr == trap)
5153 free(*tp);
5154 /* else: it "belongs" to trap_ptr vector, don't free */
5155 *tp = NULL;
5156 if ((tp - trap) != 0 && (tp - trap) < NSIG)
5157 setsignal(tp - trap);
5160 may_have_traps = 0;
5161 INT_ON;
5164 /* Lives far away from here, needed for forkchild */
5165 static void closescript(void);
5167 /* Called after fork(), in child */
5168 /* jp and n are NULL when called by openhere() for heredoc support */
5169 static NOINLINE void
5170 forkchild(struct job *jp, union node *n, int mode)
5172 int oldlvl;
5174 TRACE(("Child shell %d\n", getpid()));
5175 oldlvl = shlvl;
5176 shlvl++;
5178 /* man bash: "Non-builtin commands run by bash have signal handlers
5179 * set to the values inherited by the shell from its parent".
5180 * Do we do it correctly? */
5182 closescript();
5184 if (n && n->type == NCMD /* is it single cmd? */
5185 /* && n->ncmd.args->type == NARG - always true? */
5186 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
5187 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5188 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5190 TRACE(("Trap hack\n"));
5191 /* Awful hack for `trap` or $(trap).
5193 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5194 * contains an example where "trap" is executed in a subshell:
5196 * save_traps=$(trap)
5197 * ...
5198 * eval "$save_traps"
5200 * Standard does not say that "trap" in subshell shall print
5201 * parent shell's traps. It only says that its output
5202 * must have suitable form, but then, in the above example
5203 * (which is not supposed to be normative), it implies that.
5205 * bash (and probably other shell) does implement it
5206 * (traps are reset to defaults, but "trap" still shows them),
5207 * but as a result, "trap" logic is hopelessly messed up:
5209 * # trap
5210 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
5211 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
5212 * # true | trap <--- trap is in subshell - no output (ditto)
5213 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
5214 * trap -- 'echo Ho' SIGWINCH
5215 * # echo `(trap)` <--- in subshell in subshell - output
5216 * trap -- 'echo Ho' SIGWINCH
5217 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
5218 * trap -- 'echo Ho' SIGWINCH
5220 * The rules when to forget and when to not forget traps
5221 * get really complex and nonsensical.
5223 * Our solution: ONLY bare $(trap) or `trap` is special.
5225 /* Save trap handler strings for trap builtin to print */
5226 trap_ptr = xmemdup(trap, sizeof(trap));
5227 /* Fall through into clearing traps */
5229 clear_traps();
5230 #if JOBS
5231 /* do job control only in root shell */
5232 doing_jobctl = 0;
5233 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
5234 pid_t pgrp;
5236 if (jp->nprocs == 0)
5237 pgrp = getpid();
5238 else
5239 pgrp = jp->ps[0].ps_pid;
5240 /* this can fail because we are doing it in the parent also */
5241 setpgid(0, pgrp);
5242 if (mode == FORK_FG)
5243 xtcsetpgrp(ttyfd, pgrp);
5244 setsignal(SIGTSTP);
5245 setsignal(SIGTTOU);
5246 } else
5247 #endif
5248 if (mode == FORK_BG) {
5249 /* man bash: "When job control is not in effect,
5250 * asynchronous commands ignore SIGINT and SIGQUIT" */
5251 ignoresig(SIGINT);
5252 ignoresig(SIGQUIT);
5253 if (jp->nprocs == 0) {
5254 close(0);
5255 if (open(bb_dev_null, O_RDONLY) != 0)
5256 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
5259 if (oldlvl == 0) {
5260 if (iflag) { /* why if iflag only? */
5261 setsignal(SIGINT);
5262 setsignal(SIGTERM);
5264 /* man bash:
5265 * "In all cases, bash ignores SIGQUIT. Non-builtin
5266 * commands run by bash have signal handlers
5267 * set to the values inherited by the shell
5268 * from its parent".
5269 * Take care of the second rule: */
5270 setsignal(SIGQUIT);
5272 #if JOBS
5273 if (n && n->type == NCMD
5274 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
5276 TRACE(("Job hack\n"));
5277 /* "jobs": we do not want to clear job list for it,
5278 * instead we remove only _its_ own_ job from job list
5279 * (if it has one).
5280 * This makes "jobs .... | cat" more useful.
5282 if (jp)
5283 freejob(curjob);
5284 return;
5286 #endif
5287 for (jp = curjob; jp; jp = jp->prev_job)
5288 freejob(jp);
5291 /* Called after fork(), in parent */
5292 #if !JOBS
5293 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5294 #endif
5295 static void
5296 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5298 TRACE(("In parent shell: child = %d\n", pid));
5299 if (!jp) /* jp is NULL when called by openhere() for heredoc support */
5300 return;
5301 #if JOBS
5302 if (mode != FORK_NOJOB && jp->jobctl) {
5303 int pgrp;
5305 if (jp->nprocs == 0)
5306 pgrp = pid;
5307 else
5308 pgrp = jp->ps[0].ps_pid;
5309 /* This can fail because we are doing it in the child also */
5310 setpgid(pid, pgrp);
5312 #endif
5313 if (mode == FORK_BG) {
5314 backgndpid = pid; /* set $! */
5315 set_curjob(jp, CUR_RUNNING);
5317 if (jp) {
5318 struct procstat *ps = &jp->ps[jp->nprocs++];
5319 ps->ps_pid = pid;
5320 ps->ps_status = -1;
5321 ps->ps_cmd = nullstr;
5322 #if JOBS
5323 if (doing_jobctl && n)
5324 ps->ps_cmd = commandtext(n);
5325 #endif
5329 /* jp and n are NULL when called by openhere() for heredoc support */
5330 static int
5331 forkshell(struct job *jp, union node *n, int mode)
5333 int pid;
5335 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5336 pid = fork();
5337 if (pid < 0) {
5338 TRACE(("Fork failed, errno=%d", errno));
5339 if (jp)
5340 freejob(jp);
5341 ash_msg_and_raise_perror("can't fork");
5343 if (pid == 0) {
5344 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
5345 forkchild(jp, n, mode);
5346 } else {
5347 forkparent(jp, n, mode, pid);
5349 return pid;
5353 * Wait for job to finish.
5355 * Under job control we have the problem that while a child process
5356 * is running interrupts generated by the user are sent to the child
5357 * but not to the shell. This means that an infinite loop started by
5358 * an interactive user may be hard to kill. With job control turned off,
5359 * an interactive user may place an interactive program inside a loop.
5360 * If the interactive program catches interrupts, the user doesn't want
5361 * these interrupts to also abort the loop. The approach we take here
5362 * is to have the shell ignore interrupt signals while waiting for a
5363 * foreground process to terminate, and then send itself an interrupt
5364 * signal if the child process was terminated by an interrupt signal.
5365 * Unfortunately, some programs want to do a bit of cleanup and then
5366 * exit on interrupt; unless these processes terminate themselves by
5367 * sending a signal to themselves (instead of calling exit) they will
5368 * confuse this approach.
5370 * Called with interrupts off.
5372 static int
5373 waitforjob(struct job *jp)
5375 int st;
5377 TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
5379 /* In non-interactive shells, we _can_ get
5380 * a keyboard signal here and be EINTRed, but we just loop
5381 * inside dowait(), waiting for command to complete.
5383 * man bash:
5384 * "If bash is waiting for a command to complete and receives
5385 * a signal for which a trap has been set, the trap
5386 * will not be executed until the command completes."
5388 * Reality is that even if trap is not set, bash
5389 * will not act on the signal until command completes.
5390 * Try this. sleep5intoff.c:
5391 * #include <signal.h>
5392 * #include <unistd.h>
5393 * int main() {
5394 * sigset_t set;
5395 * sigemptyset(&set);
5396 * sigaddset(&set, SIGINT);
5397 * sigaddset(&set, SIGQUIT);
5398 * sigprocmask(SIG_BLOCK, &set, NULL);
5399 * sleep(5);
5400 * return 0;
5402 * $ bash -c './sleep5intoff; echo hi'
5403 * ^C^C^C^C <--- pressing ^C once a second
5404 * $ _
5405 * $ bash -c './sleep5intoff; echo hi'
5406 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5407 * $ _
5409 dowait(jp ? DOWAIT_BLOCK : DOWAIT_NONBLOCK, jp);
5410 if (!jp)
5411 return exitstatus;
5413 st = getstatus(jp);
5414 #if JOBS
5415 if (jp->jobctl) {
5416 xtcsetpgrp(ttyfd, rootpid);
5417 restore_tty_if_stopped_or_signaled(jp);
5420 * This is truly gross.
5421 * If we're doing job control, then we did a TIOCSPGRP which
5422 * caused us (the shell) to no longer be in the controlling
5423 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5424 * intuit from the subprocess exit status whether a SIGINT
5425 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5427 if (jp->sigint) /* TODO: do the same with all signals */
5428 raise(SIGINT); /* ... by raise(jp->sig) instead? */
5430 if (jp->state == JOBDONE)
5431 #endif
5432 freejob(jp);
5433 return st;
5437 * return 1 if there are stopped jobs, otherwise 0
5439 static int
5440 stoppedjobs(void)
5442 struct job *jp;
5443 int retval;
5445 retval = 0;
5446 if (!iflag || job_warning)
5447 goto out;
5448 jp = curjob;
5449 if (jp && jp->state == JOBSTOPPED) {
5450 out2str("You have stopped jobs.\n");
5451 job_warning = 2;
5452 retval++;
5454 out:
5455 return retval;
5460 * Code for dealing with input/output redirection.
5463 #undef EMPTY
5464 #undef CLOSED
5465 #define EMPTY -2 /* marks an unused slot in redirtab */
5466 #define CLOSED -1 /* marks a slot of previously-closed fd */
5469 * Handle here documents. Normally we fork off a process to write the
5470 * data to a pipe. If the document is short, we can stuff the data in
5471 * the pipe without forking.
5473 /* openhere needs this forward reference */
5474 static void expandhere(union node *arg);
5475 static int
5476 openhere(union node *redir)
5478 char *p;
5479 int pip[2];
5480 size_t len = 0;
5482 if (pipe(pip) < 0)
5483 ash_msg_and_raise_perror("can't create pipe");
5485 p = redir->nhere.doc->narg.text;
5486 if (redir->type == NXHERE) {
5487 expandhere(redir->nhere.doc);
5488 p = stackblock();
5491 len = strlen(p);
5492 if (len <= PIPE_BUF) {
5493 xwrite(pip[1], p, len);
5494 goto out;
5497 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5498 /* child */
5499 close(pip[0]);
5500 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5501 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5502 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5503 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5504 signal(SIGPIPE, SIG_DFL);
5505 xwrite(pip[1], p, len);
5506 _exit_SUCCESS();
5508 out:
5509 close(pip[1]);
5510 return pip[0];
5513 static int
5514 openredirect(union node *redir)
5516 struct stat sb;
5517 char *fname;
5518 int f;
5520 switch (redir->nfile.type) {
5521 /* Can't happen, our single caller does this itself */
5522 // case NTOFD:
5523 // case NFROMFD:
5524 // return -1;
5525 case NHERE:
5526 case NXHERE:
5527 return openhere(redir);
5530 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5531 * allocated space. Do it only when we know it is safe.
5533 fname = redir->nfile.expfname;
5535 switch (redir->nfile.type) {
5536 default:
5537 #if DEBUG
5538 abort();
5539 #endif
5540 case NFROM:
5541 f = open(fname, O_RDONLY);
5542 if (f < 0)
5543 goto eopen;
5544 break;
5545 case NFROMTO:
5546 f = open(fname, O_RDWR|O_CREAT, 0666);
5547 if (f < 0)
5548 goto ecreate;
5549 break;
5550 case NTO:
5551 #if BASH_REDIR_OUTPUT
5552 case NTO2:
5553 #endif
5554 /* Take care of noclobber mode. */
5555 if (Cflag) {
5556 if (stat(fname, &sb) < 0) {
5557 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5558 if (f < 0)
5559 goto ecreate;
5560 } else if (!S_ISREG(sb.st_mode)) {
5561 f = open(fname, O_WRONLY, 0666);
5562 if (f < 0)
5563 goto ecreate;
5564 if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
5565 close(f);
5566 errno = EEXIST;
5567 goto ecreate;
5569 } else {
5570 errno = EEXIST;
5571 goto ecreate;
5573 break;
5575 /* FALLTHROUGH */
5576 case NCLOBBER:
5577 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5578 if (f < 0)
5579 goto ecreate;
5580 break;
5581 case NAPPEND:
5582 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5583 if (f < 0)
5584 goto ecreate;
5585 break;
5588 return f;
5589 ecreate:
5590 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5591 eopen:
5592 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5596 * Copy a file descriptor to be >= 10. Throws exception on error.
5598 static int
5599 savefd(int from)
5601 int newfd;
5602 int err;
5604 newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
5605 err = newfd < 0 ? errno : 0;
5606 if (err != EBADF) {
5607 if (err)
5608 ash_msg_and_raise_perror("%d", from);
5609 close(from);
5610 if (F_DUPFD_CLOEXEC == F_DUPFD)
5611 close_on_exec_on(newfd);
5614 return newfd;
5616 static int
5617 dup2_or_raise(int from, int to)
5619 int newfd;
5621 newfd = (from != to) ? dup2(from, to) : to;
5622 if (newfd < 0) {
5623 /* Happens when source fd is not open: try "echo >&99" */
5624 ash_msg_and_raise_perror("%d", from);
5626 return newfd;
5628 static int
5629 dup_CLOEXEC(int fd, int avoid_fd)
5631 int newfd;
5632 repeat:
5633 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5634 if (newfd >= 0) {
5635 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
5636 close_on_exec_on(newfd);
5637 } else { /* newfd < 0 */
5638 if (errno == EBUSY)
5639 goto repeat;
5640 if (errno == EINTR)
5641 goto repeat;
5643 return newfd;
5645 static int
5646 xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5648 int newfd;
5649 repeat:
5650 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5651 if (newfd < 0) {
5652 if (errno == EBUSY)
5653 goto repeat;
5654 if (errno == EINTR)
5655 goto repeat;
5656 /* fd was not open? */
5657 if (errno == EBADF)
5658 return fd;
5659 ash_msg_and_raise_perror("%d", newfd);
5661 if (F_DUPFD_CLOEXEC == F_DUPFD)
5662 close_on_exec_on(newfd);
5663 close(fd);
5664 return newfd;
5667 /* Struct def and variable are moved down to the first usage site */
5668 struct squirrel {
5669 int orig_fd;
5670 int moved_to;
5672 struct redirtab {
5673 struct redirtab *next;
5674 int pair_count;
5675 struct squirrel two_fd[];
5677 #define redirlist (G_var.redirlist)
5679 static void
5680 add_squirrel_closed(struct redirtab *sq, int fd)
5682 int i;
5684 if (!sq)
5685 return;
5687 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5688 /* If we collide with an already moved fd... */
5689 if (fd == sq->two_fd[i].orig_fd) {
5690 /* Examples:
5691 * "echo 3>FILE 3>&- 3>FILE"
5692 * "echo 3>&- 3>FILE"
5693 * No need for last redirect to insert
5694 * another "need to close 3" indicator.
5696 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5697 return;
5700 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5701 sq->two_fd[i].orig_fd = fd;
5702 sq->two_fd[i].moved_to = CLOSED;
5705 static int
5706 save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5708 int i, new_fd;
5710 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5711 avoid_fd = 9;
5713 #if JOBS
5714 if (fd == ttyfd) {
5715 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5716 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5717 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5718 return 1; /* "we closed fd" */
5720 #endif
5721 /* Are we called from redirect(0)? E.g. redirect
5722 * in a forked child. No need to save fds,
5723 * we aren't going to use them anymore, ok to trash.
5725 if (!sq)
5726 return 0;
5728 /* If this one of script's fds? */
5729 if (fd != 0) {
5730 struct parsefile *pf = g_parsefile;
5731 while (pf) {
5732 /* We skip fd == 0 case because of the following:
5733 * $ ash # running ash interactively
5734 * $ . ./script.sh
5735 * and in script.sh: "exec 9>&0".
5736 * Even though top-level pf_fd _is_ 0,
5737 * it's still ok to use it: "read" builtin uses it,
5738 * why should we cripple "exec" builtin?
5740 if (fd == pf->pf_fd) {
5741 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5742 return 1; /* "we closed fd" */
5744 pf = pf->prev;
5748 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5750 /* First: do we collide with some already moved fds? */
5751 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5752 /* If we collide with an already moved fd... */
5753 if (fd == sq->two_fd[i].moved_to) {
5754 new_fd = dup_CLOEXEC(fd, avoid_fd);
5755 sq->two_fd[i].moved_to = new_fd;
5756 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5757 if (new_fd < 0) /* what? */
5758 xfunc_die();
5759 return 0; /* "we did not close fd" */
5761 if (fd == sq->two_fd[i].orig_fd) {
5762 /* Example: echo Hello >/dev/null 1>&2 */
5763 TRACE(("redirect_fd %d: already moved\n", fd));
5764 return 0; /* "we did not close fd" */
5768 /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5769 new_fd = dup_CLOEXEC(fd, avoid_fd);
5770 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5771 if (new_fd < 0) {
5772 if (errno != EBADF)
5773 xfunc_die();
5774 /* new_fd = CLOSED; - already is -1 */
5776 sq->two_fd[i].moved_to = new_fd;
5777 sq->two_fd[i].orig_fd = fd;
5779 /* if we move stderr, let "set -x" code know */
5780 if (fd == preverrout_fd)
5781 preverrout_fd = new_fd;
5783 return 0; /* "we did not close fd" */
5786 static int
5787 internally_opened_fd(int fd, struct redirtab *sq)
5789 int i;
5790 #if JOBS
5791 if (fd == ttyfd)
5792 return 1;
5793 #endif
5794 /* If this one of script's fds? */
5795 if (fd != 0) {
5796 struct parsefile *pf = g_parsefile;
5797 while (pf) {
5798 if (fd == pf->pf_fd)
5799 return 1;
5800 pf = pf->prev;
5804 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5805 if (fd == sq->two_fd[i].moved_to)
5806 return 1;
5808 return 0;
5812 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5813 * old file descriptors are stashed away so that the redirection can be
5814 * undone by calling popredir.
5816 /* flags passed to redirect */
5817 #define REDIR_PUSH 01 /* save previous values of file descriptors */
5818 static void
5819 redirect(union node *redir, int flags)
5821 struct redirtab *sv;
5823 if (!redir)
5824 return;
5826 sv = NULL;
5827 INT_OFF;
5828 if (flags & REDIR_PUSH)
5829 sv = redirlist;
5830 do {
5831 int fd;
5832 int newfd;
5833 int close_fd;
5834 int closed;
5836 fd = redir->nfile.fd;
5837 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5838 //bb_error_msg("doing %d > %d", fd, newfd);
5839 newfd = redir->ndup.dupfd;
5840 close_fd = -1;
5841 } else {
5842 newfd = openredirect(redir); /* always >= 0 */
5843 if (fd == newfd) {
5844 /* open() gave us precisely the fd we wanted.
5845 * This means that this fd was not busy
5846 * (not opened to anywhere).
5847 * Remember to close it on restore:
5849 add_squirrel_closed(sv, fd);
5850 continue;
5852 close_fd = newfd;
5855 if (fd == newfd)
5856 continue;
5858 /* if "N>FILE": move newfd to fd */
5859 /* if "N>&M": dup newfd to fd */
5860 /* if "N>&-": close fd (newfd is -1) */
5862 IF_BASH_REDIR_OUTPUT(redirect_more:)
5864 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5865 if (newfd == -1) {
5866 /* "N>&-" means "close me" */
5867 if (!closed) {
5868 /* ^^^ optimization: saving may already
5869 * have closed it. If not... */
5870 close(fd);
5872 } else {
5873 /* if newfd is a script fd or saved fd, simulate EBADF */
5874 if (internally_opened_fd(newfd, sv)) {
5875 errno = EBADF;
5876 ash_msg_and_raise_perror("%d", newfd);
5878 dup2_or_raise(newfd, fd);
5879 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5880 close(close_fd);
5881 #if BASH_REDIR_OUTPUT
5882 if (redir->nfile.type == NTO2 && fd == 1) {
5883 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5884 fd = 2;
5885 newfd = 1;
5886 close_fd = -1;
5887 goto redirect_more;
5889 #endif
5891 } while ((redir = redir->nfile.next) != NULL);
5892 INT_ON;
5894 //dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5895 #define REDIR_SAVEFD2 0
5896 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5897 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5898 // not only for calls with flags containing REDIR_SAVEFD2.
5899 // We do this unconditionally (see save_fd_on_redirect()).
5900 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5901 // preverrout_fd = copied_fd2;
5904 static int
5905 redirectsafe(union node *redir, int flags)
5907 int err;
5908 volatile int saveint;
5909 struct jmploc *volatile savehandler = exception_handler;
5910 struct jmploc jmploc;
5912 SAVE_INT(saveint);
5913 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5914 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
5915 if (!err) {
5916 exception_handler = &jmploc;
5917 redirect(redir, flags);
5919 exception_handler = savehandler;
5920 if (err && exception_type != EXERROR)
5921 longjmp(exception_handler->loc, 1);
5922 RESTORE_INT(saveint);
5923 return err;
5926 #if BASH_PROCESS_SUBST
5927 static void
5928 pushfd(int fd)
5930 struct redirtab *sv;
5932 sv = ckzalloc(sizeof(*sv) + sizeof(sv->two_fd[0]));
5933 sv->pair_count = 1;
5934 sv->two_fd[0].orig_fd = fd;
5935 sv->two_fd[0].moved_to = CLOSED;
5936 sv->next = redirlist;
5937 redirlist = sv;
5939 #endif
5941 static struct redirtab*
5942 pushredir(union node *redir)
5944 struct redirtab *sv;
5945 int i;
5947 if (!redir)
5948 return redirlist;
5950 i = 0;
5951 do {
5952 i++;
5953 #if BASH_REDIR_OUTPUT
5954 if (redir->nfile.type == NTO2)
5955 i++;
5956 #endif
5957 redir = redir->nfile.next;
5958 } while (redir);
5960 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5961 sv->pair_count = i;
5962 while (--i >= 0)
5963 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
5964 sv->next = redirlist;
5965 redirlist = sv;
5966 return sv->next;
5970 * Undo the effects of the last redirection.
5972 static void
5973 popredir(int drop)
5975 struct redirtab *rp;
5976 int i;
5978 if (redirlist == NULL)
5979 return;
5980 INT_OFF;
5981 rp = redirlist;
5982 for (i = 0; i < rp->pair_count; i++) {
5983 int fd = rp->two_fd[i].orig_fd;
5984 int copy = rp->two_fd[i].moved_to;
5985 if (copy == CLOSED) {
5986 if (!drop)
5987 close(fd);
5988 continue;
5990 if (copy != EMPTY) {
5991 if (!drop) {
5992 /*close(fd);*/
5993 dup2_or_raise(copy, fd);
5995 close(copy);
5998 redirlist = rp->next;
5999 free(rp);
6000 INT_ON;
6003 static void
6004 unwindredir(struct redirtab *stop)
6006 while (redirlist != stop)
6007 popredir(/*drop:*/ 0);
6011 /* ============ Routines to expand arguments to commands
6013 * We have to deal with backquotes, shell variables, and file metacharacters.
6016 #if ENABLE_FEATURE_SH_MATH
6017 static arith_t
6018 ash_arith(const char *s)
6020 arith_state_t math_state;
6021 arith_t result;
6023 math_state.lookupvar = lookupvar;
6024 math_state.setvar = setvar0;
6025 //math_state.endofname = endofname;
6027 INT_OFF;
6028 result = arith(&math_state, s);
6029 if (math_state.errmsg)
6030 ash_msg_and_raise_error(math_state.errmsg);
6031 INT_ON;
6033 return result;
6035 #endif
6036 #if BASH_SUBSTR
6037 # if ENABLE_FEATURE_SH_MATH
6038 static int substr_atoi(const char *s)
6040 arith_t t = ash_arith(s);
6041 if (sizeof(t) > sizeof(int)) {
6042 /* clamp very large or very large negative nums for ${v:N:M}:
6043 * else "${v:0:0x100000001}" would work as "${v:0:1}"
6045 if (t > INT_MAX)
6046 t = INT_MAX;
6047 if (t < INT_MIN)
6048 t = INT_MIN;
6050 return t;
6052 # else
6053 # define substr_atoi(s) number(s)
6054 # endif
6055 #endif
6058 * expandarg flags
6060 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
6061 #define EXP_TILDE 0x2 /* do normal tilde expansion */
6062 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
6063 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
6064 /* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
6065 * POSIX says for this case:
6066 * Pathname expansion shall not be performed on the word by a
6067 * non-interactive shell; an interactive shell may perform it, but shall
6068 * do so only when the expansion would result in one word.
6069 * Currently, our code complies to the above rule by never globbing
6070 * redirection filenames.
6071 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
6072 * (this means that on a typical Linux distro, bash almost always
6073 * performs globbing, and thus diverges from what we do).
6075 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
6076 #define EXP_VARTILDE2 0x20 /* expand tildes after colons only */
6077 #define EXP_WORD 0x40 /* expand word in parameter expansion */
6078 #define EXP_QUOTED 0x100 /* expand word in double quotes */
6079 #define EXP_KEEPNUL 0x200 /* do not skip NUL characters */
6080 #define EXP_DISCARD 0x400 /* discard result of expansion */
6083 * rmescape() flags
6085 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
6086 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
6087 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
6088 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
6090 /* Add CTLESC when necessary. */
6091 #define QUOTES_ESC (EXP_FULL | EXP_CASE)
6094 * Structure specifying which parts of the string should be searched
6095 * for IFS characters.
6097 struct ifsregion {
6098 struct ifsregion *next; /* next region in list */
6099 int begoff; /* offset of start of region */
6100 int endoff; /* offset of end of region */
6101 int nulonly; /* search for nul bytes only */
6104 struct arglist {
6105 struct strlist *list;
6106 struct strlist **lastp;
6109 /* output of current string */
6110 static char *expdest;
6111 /* list of back quote expressions */
6112 static struct nodelist *argbackq;
6113 /* first struct in list of ifs regions */
6114 static struct ifsregion ifsfirst;
6115 /* last struct in list */
6116 static struct ifsregion *ifslastp;
6117 /* holds expanded arg list */
6118 static struct arglist exparg;
6121 * Break the argument string into pieces based upon IFS and add the
6122 * strings to the argument list. The regions of the string to be
6123 * searched for IFS characters have been stored by recordregion.
6125 static void
6126 ifsbreakup(char *string, struct arglist *arglist)
6128 struct ifsregion *ifsp;
6129 struct strlist *sp;
6130 char *start;
6131 char *p;
6132 char *q;
6133 const char *ifs, *realifs;
6134 int ifsspc;
6135 int nulonly;
6137 start = string;
6138 if (ifslastp != NULL) {
6139 ifsspc = 0;
6140 nulonly = 0;
6141 realifs = ifsset() ? ifsval() : defifs;
6142 ifsp = &ifsfirst;
6143 do {
6144 int afternul;
6146 p = string + ifsp->begoff;
6147 afternul = nulonly;
6148 nulonly = ifsp->nulonly;
6149 ifs = nulonly ? nullstr : realifs;
6150 ifsspc = 0;
6151 while (p < string + ifsp->endoff) {
6152 q = p;
6153 if ((unsigned char)*p == CTLESC)
6154 p++;
6155 if (!strchr(ifs, *p)) {
6156 p++;
6157 continue;
6159 if (!(afternul || nulonly))
6160 ifsspc = (strchr(defifs, *p) != NULL);
6161 /* Ignore IFS whitespace at start */
6162 if (q == start && ifsspc) {
6163 p++;
6164 start = p;
6165 continue;
6167 *q = '\0';
6168 sp = stzalloc(sizeof(*sp));
6169 sp->text = start;
6170 *arglist->lastp = sp;
6171 arglist->lastp = &sp->next;
6172 p++;
6173 if (!nulonly) {
6174 for (;;) {
6175 if (p >= string + ifsp->endoff) {
6176 break;
6178 q = p;
6179 if ((unsigned char)*p == CTLESC)
6180 p++;
6181 if (strchr(ifs, *p) == NULL) {
6182 p = q;
6183 break;
6185 if (strchr(defifs, *p) == NULL) {
6186 if (ifsspc) {
6187 p++;
6188 ifsspc = 0;
6189 } else {
6190 p = q;
6191 break;
6193 } else
6194 p++;
6197 start = p;
6198 } /* while */
6199 ifsp = ifsp->next;
6200 } while (ifsp != NULL);
6201 if (nulonly)
6202 goto add;
6205 if (!*start)
6206 return;
6208 add:
6209 sp = stzalloc(sizeof(*sp));
6210 sp->text = start;
6211 *arglist->lastp = sp;
6212 arglist->lastp = &sp->next;
6215 static void
6216 ifsfree(void)
6218 struct ifsregion *p = ifsfirst.next;
6220 if (!p)
6221 goto out;
6223 INT_OFF;
6224 do {
6225 struct ifsregion *ifsp;
6226 ifsp = p->next;
6227 free(p);
6228 p = ifsp;
6229 } while (p);
6230 ifsfirst.next = NULL;
6231 INT_ON;
6232 out:
6233 ifslastp = NULL;
6236 static size_t
6237 esclen(const char *start, const char *p)
6239 size_t esc = 0;
6241 while (p > start && (unsigned char)*--p == CTLESC) {
6242 esc++;
6244 return esc;
6248 * Remove any CTLESC characters from a string.
6250 #if !BASH_PATTERN_SUBST
6251 #define rmescapes(str, flag, slash_position) \
6252 rmescapes(str, flag)
6253 #endif
6254 static char *
6255 rmescapes(char *str, int flag, int *slash_position)
6257 static const char qchars[] ALIGN1 = {
6258 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
6260 char *p, *q, *r;
6261 unsigned protect_against_glob;
6262 unsigned globbing;
6264 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
6265 if (!p)
6266 return str;
6268 q = p;
6269 r = str;
6270 if (flag & RMESCAPE_ALLOC) {
6271 size_t len = p - str;
6272 size_t fulllen = len + strlen(p) + 1;
6274 if (flag & RMESCAPE_GROW) {
6275 int strloc = str - (char *)stackblock();
6276 r = makestrspace(fulllen, expdest);
6277 /* p and str may be invalidated by makestrspace */
6278 str = (char *)stackblock() + strloc;
6279 p = str + len;
6280 } else if (flag & RMESCAPE_HEAP) {
6281 r = ckmalloc(fulllen);
6282 } else {
6283 r = stalloc(fulllen);
6285 q = r;
6286 if (len > 0) {
6287 q = (char *)mempcpy(q, str, len);
6291 globbing = flag & RMESCAPE_GLOB;
6292 protect_against_glob = globbing;
6293 while (*p) {
6294 if ((unsigned char)*p == CTLQUOTEMARK) {
6295 // Note: protect_against_glob only affect whether
6296 // CTLESC,<ch> gets converted to <ch> or to \<ch>
6297 p++;
6298 protect_against_glob = globbing;
6299 continue;
6301 if (*p == '\\') {
6302 /* naked back slash */
6303 protect_against_glob = 0;
6304 goto copy;
6306 if ((unsigned char)*p == CTLESC) {
6307 p++;
6308 #if DEBUG
6309 if (*p == '\0')
6310 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6311 #endif
6312 if (protect_against_glob) {
6314 * We used to trust glob() and fnmatch() to eat
6315 * superfluous escapes (\z where z has no
6316 * special meaning anyway). But this causes
6317 * bugs such as string of one greek letter rho
6318 * (unicode-encoded as two bytes "cf,81")
6319 * getting encoded as "cf,CTLESC,81"
6320 * and here, converted to "cf,\,81" -
6321 * which does not go well with some flavors
6322 * of fnmatch() in unicode locales
6323 * (for example, glibc <= 2.22).
6325 * Lets add "\" only on the chars which need it.
6326 * Testcases for less obvious chars are shown.
6328 if (*p == '*'
6329 || *p == '?'
6330 || *p == '['
6331 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6332 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6333 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6334 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
6335 /* Some libc support [^negate], that's why "^" also needs love */
6336 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
6338 *q++ = '\\';
6342 #if BASH_PATTERN_SUBST
6343 else if (slash_position && p == str + *slash_position) {
6344 /* stop handling globbing */
6345 globbing = 0;
6346 *slash_position = q - r;
6347 slash_position = NULL;
6349 #endif
6350 protect_against_glob = globbing;
6351 copy:
6352 *q++ = *p++;
6354 *q = '\0';
6355 if (flag & RMESCAPE_GROW) {
6356 expdest = r;
6357 STADJUST(q - r + 1, expdest);
6359 return r;
6361 #define pmatch(a, b) !fnmatch((a), (b), 0)
6364 * Prepare a pattern for a expmeta (internal glob(3)) call.
6366 * Returns an stalloced string.
6368 static char *
6369 preglob(const char *pattern, int flag)
6371 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
6375 * Put a string on the stack.
6377 static size_t
6378 memtodest(const char *p, size_t len, int flags)
6380 int syntax = flags & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6381 char *q;
6382 char *s;
6384 if (!len)
6385 return 0;
6387 q = makestrspace(len * 2, expdest);
6388 s = q;
6390 do {
6391 unsigned char c = *p++;
6392 if (c) {
6393 if (flags & QUOTES_ESC) {
6394 int n = SIT(c, syntax);
6395 if (n == CCTL
6396 || ((flags & EXP_QUOTED) && n == CBACK)
6398 USTPUTC(CTLESC, q);
6401 } else if (!(flags & EXP_KEEPNUL))
6402 continue;
6403 USTPUTC(c, q);
6404 } while (--len);
6406 expdest = q;
6407 return q - s;
6410 static size_t
6411 strtodest(const char *p, int flags)
6413 size_t len = strlen(p);
6414 memtodest(p, len, flags);
6415 return len;
6419 * Our own itoa().
6420 * cvtnum() is used even if math support is off (to prepare $? values and such).
6422 static int
6423 cvtnum(arith_t num, int flags)
6425 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
6426 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
6427 int len = (sizeof(arith_t) >= 4) ? sizeof(arith_t) * 3 : sizeof(arith_t) * 3 + 2;
6428 char buf[len];
6430 len = fmtstr(buf, len, ARITH_FMT, num);
6431 return memtodest(buf, len, flags);
6435 * Record the fact that we have to scan this region of the
6436 * string for IFS characters.
6438 static void
6439 recordregion(int start, int end, int nulonly)
6441 struct ifsregion *ifsp;
6443 if (ifslastp == NULL) {
6444 ifsp = &ifsfirst;
6445 } else {
6446 INT_OFF;
6447 ifsp = ckzalloc(sizeof(*ifsp));
6448 /*ifsp->next = NULL; - ckzalloc did it */
6449 ifslastp->next = ifsp;
6450 INT_ON;
6452 ifslastp = ifsp;
6453 ifslastp->begoff = start;
6454 ifslastp->endoff = end;
6455 ifslastp->nulonly = nulonly;
6458 static void
6459 removerecordregions(int endoff)
6461 if (ifslastp == NULL)
6462 return;
6464 if (ifsfirst.endoff > endoff) {
6465 while (ifsfirst.next) {
6466 struct ifsregion *ifsp;
6467 INT_OFF;
6468 ifsp = ifsfirst.next->next;
6469 free(ifsfirst.next);
6470 ifsfirst.next = ifsp;
6471 INT_ON;
6473 if (ifsfirst.begoff > endoff) {
6474 ifslastp = NULL;
6475 } else {
6476 ifslastp = &ifsfirst;
6477 ifsfirst.endoff = endoff;
6479 return;
6482 ifslastp = &ifsfirst;
6483 while (ifslastp->next && ifslastp->next->begoff < endoff)
6484 ifslastp = ifslastp->next;
6485 while (ifslastp->next) {
6486 struct ifsregion *ifsp;
6487 INT_OFF;
6488 ifsp = ifslastp->next->next;
6489 free(ifslastp->next);
6490 ifslastp->next = ifsp;
6491 INT_ON;
6493 if (ifslastp->endoff > endoff)
6494 ifslastp->endoff = endoff;
6497 static char *
6498 exptilde(char *startp, int flag)
6500 unsigned char c;
6501 char *name;
6502 struct passwd *pw;
6503 const char *home;
6504 char *p;
6506 p = startp;
6507 name = p + 1;
6509 while ((c = *++p) != '\0') {
6510 switch (c) {
6511 case CTLESC:
6512 return startp;
6513 case CTLQUOTEMARK:
6514 return startp;
6515 case ':':
6516 if (flag & EXP_VARTILDE)
6517 goto done;
6518 break;
6519 case '/':
6520 case CTLENDVAR:
6521 goto done;
6524 done:
6525 if (flag & EXP_DISCARD)
6526 goto out;
6527 *p = '\0';
6528 if (*name == '\0') {
6529 home = lookupvar("HOME");
6530 } else {
6531 pw = getpwnam(name);
6532 home = pw ? pw->pw_dir : NULL;
6534 *p = c;
6535 if (!home)
6536 goto lose;
6537 strtodest(home, flag | EXP_QUOTED);
6538 out:
6539 return p;
6540 lose:
6541 return startp;
6545 * Execute a command inside back quotes. If it's a builtin command, we
6546 * want to save its output in a block obtained from malloc. Otherwise
6547 * we fork off a subprocess and get the output of the command via a pipe.
6548 * Should be called with interrupts off.
6550 struct backcmd { /* result of evalbackcmd */
6551 int fd; /* file descriptor to read from */
6552 int nleft; /* number of chars in buffer */
6553 char *buf; /* buffer */
6554 struct job *jp; /* job structure for command */
6557 /* These forward decls are needed to use "eval" code for backticks handling: */
6558 /* flags in argument to evaltree */
6559 #define EV_EXIT 01 /* exit after evaluating tree */
6560 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
6561 static int evaltree(union node *, int);
6563 /* An evaltree() which is known to never return.
6564 * Used to use an alias:
6565 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6566 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6568 static ALWAYS_INLINE NORETURN void
6569 evaltreenr(union node *n, int flags)
6571 evaltree(n, flags);
6572 bb_unreachable(abort());
6573 /* NOTREACHED */
6576 static void FAST_FUNC
6577 evalbackcmd(union node *n, struct backcmd *result
6578 IF_BASH_PROCESS_SUBST(, int ctl))
6580 int pip[2];
6581 struct job *jp;
6582 #if BASH_PROCESS_SUBST
6583 /* determine end of pipe used by parent (ip) and child (ic) */
6584 const int ip = (ctl == CTLTOPROC);
6585 const int ic = !(ctl == CTLTOPROC);
6586 #else
6587 const int ctl = CTLBACKQ;
6588 const int ip = 0;
6589 const int ic = 1;
6590 #endif
6592 result->fd = -1;
6593 result->buf = NULL;
6594 result->nleft = 0;
6595 result->jp = NULL;
6596 if (n == NULL) {
6597 goto out;
6600 if (pipe(pip) < 0)
6601 ash_msg_and_raise_perror("can't create pipe");
6602 /* process substitution uses NULL job, like openhere() */
6603 jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL;
6604 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6605 /* child */
6606 FORCE_INT_ON;
6607 close(pip[ip]);
6608 /* ic is index of child end of pipe *and* fd to connect it to */
6609 if (pip[ic] != ic) {
6610 /*close(ic);*/
6611 dup2_or_raise(pip[ic], ic);
6612 close(pip[ic]);
6614 /* TODO: eflag clearing makes the following not abort:
6615 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6616 * which is what bash does (unless it is in POSIX mode).
6617 * dash deleted "eflag = 0" line in the commit
6618 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6619 * [EVAL] Don't clear eflag in evalbackcmd
6620 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6622 eflag = 0;
6623 ifsfree();
6624 evaltreenr(n, EV_EXIT);
6625 /* NOTREACHED */
6627 /* parent */
6628 #if BASH_PROCESS_SUBST
6629 if (ctl != CTLBACKQ) {
6630 int fd = fcntl(pip[ip], F_DUPFD, 64);
6631 if (fd > 0) {
6632 close(pip[ip]);
6633 pip[ip] = fd;
6635 pushfd(pip[ip]);
6637 #endif
6638 close(pip[ic]);
6639 result->fd = pip[ip];
6640 result->jp = jp;
6642 out:
6643 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6644 result->fd, result->buf, result->nleft, result->jp));
6648 * Expand stuff in backwards quotes.
6650 static void
6651 expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl))
6653 #if !BASH_PROCESS_SUBST
6654 const int ctl = CTLBACKQ;
6655 #endif
6656 struct backcmd in;
6657 int i;
6658 char buf[128];
6659 char *p;
6660 char *dest;
6661 int startloc;
6662 struct stackmark smark;
6664 if (flag & EXP_DISCARD)
6665 goto out;
6667 INT_OFF;
6668 startloc = expdest - (char *)stackblock();
6669 pushstackmark(&smark, startloc);
6670 evalbackcmd(cmd, &in IF_BASH_PROCESS_SUBST(, ctl));
6671 popstackmark(&smark);
6673 if (ctl != CTLBACKQ) {
6674 sprintf(buf, DEV_FD_PREFIX"%d", in.fd);
6675 strtodest(buf, BASESYNTAX);
6676 goto done;
6679 p = in.buf;
6680 i = in.nleft;
6681 if (i == 0)
6682 goto read;
6683 for (;;) {
6684 memtodest(p, i, flag);
6685 read:
6686 if (in.fd < 0)
6687 break;
6688 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6689 TRACE(("expbackq: read returns %d\n", i));
6690 if (i <= 0)
6691 break;
6692 p = buf;
6695 free(in.buf);
6696 if (in.fd >= 0) {
6697 close(in.fd);
6698 back_exitstatus = waitforjob(in.jp);
6700 done:
6701 INT_ON;
6703 /* Eat all trailing newlines */
6704 dest = expdest;
6705 for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';)
6706 STUNPUTC(dest);
6707 expdest = dest;
6709 if (!(flag & EXP_QUOTED))
6710 recordregion(startloc, dest - (char *)stackblock(), 0);
6711 TRACE(("evalbackq: size:%d:'%.*s'\n",
6712 (int)((dest - (char *)stackblock()) - startloc),
6713 (int)((dest - (char *)stackblock()) - startloc),
6714 stackblock() + startloc));
6716 out:
6717 argbackq = argbackq->next;
6720 /* expari needs it */
6721 static char *argstr(char *p, int flag);
6723 #if ENABLE_FEATURE_SH_MATH
6725 * Expand arithmetic expression. Backup to start of expression,
6726 * evaluate, place result in (backed up) result, adjust string position.
6728 static char *
6729 expari(char *start, int flag)
6731 struct stackmark sm;
6732 int begoff;
6733 int endoff;
6734 int len;
6735 arith_t result;
6736 char *p;
6738 p = stackblock();
6739 begoff = expdest - p;
6740 p = argstr(start, flag & EXP_DISCARD);
6742 if (flag & EXP_DISCARD)
6743 goto out;
6745 start = stackblock();
6746 endoff = expdest - start;
6747 start += begoff;
6748 STADJUST(start - expdest, expdest);
6750 removerecordregions(begoff);
6752 if (flag & QUOTES_ESC)
6753 rmescapes(start, 0, NULL);
6755 pushstackmark(&sm, endoff);
6756 result = ash_arith(start);
6757 popstackmark(&sm);
6759 len = cvtnum(result, flag);
6761 if (!(flag & EXP_QUOTED))
6762 recordregion(begoff, begoff + len, 0);
6764 out:
6765 return p;
6767 #endif
6769 /* argstr needs it */
6770 static char *evalvar(char *p, int flags);
6773 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6774 * characters to allow for further processing. Otherwise treat
6775 * $@ like $* since no splitting will be performed.
6777 static char *
6778 argstr(char *p, int flag)
6780 static const char spclchars[] ALIGN1 = {
6781 '=',
6782 ':',
6783 CTLQUOTEMARK,
6784 CTLENDVAR,
6785 CTLESC,
6786 CTLVAR,
6787 CTLBACKQ,
6788 #if BASH_PROCESS_SUBST
6789 CTLTOPROC,
6790 CTLFROMPROC,
6791 #endif
6792 #if ENABLE_FEATURE_SH_MATH
6793 CTLARI,
6794 CTLENDARI,
6795 #endif
6796 '\0'
6798 const char *reject = spclchars;
6799 int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6800 int inquotes;
6801 size_t length;
6802 int startloc;
6804 reject += !!(flag & EXP_VARTILDE2);
6805 reject += flag & EXP_VARTILDE ? 0 : 2;
6806 inquotes = 0;
6807 length = 0;
6808 if (flag & EXP_TILDE) {
6809 flag &= ~EXP_TILDE;
6810 tilde:
6811 if (*p == '~')
6812 p = exptilde(p, flag);
6814 start:
6815 startloc = expdest - (char *)stackblock();
6816 for (;;) {
6817 int end;
6818 unsigned char c;
6820 length += strcspn(p + length, reject);
6821 end = 0;
6822 c = p[length];
6823 if (!(c & 0x80)
6824 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6825 || c == CTLENDVAR
6828 * c == '=' || c == ':' || c == '\0' ||
6829 * c == CTLENDARI || c == CTLENDVAR
6831 length++;
6832 /* c == '\0' || c == CTLENDARI || c == CTLENDVAR */
6833 end = !!((c - 1) & 0x80);
6835 if (length > 0 && !(flag & EXP_DISCARD)) {
6836 int newloc;
6837 char *q;
6839 q = stnputs(p, length, expdest);
6840 q[-1] &= end - 1;
6841 expdest = q - (flag & EXP_WORD ? end : 0);
6842 newloc = q - (char *)stackblock() - end;
6843 if (breakall && !inquotes && newloc > startloc) {
6844 recordregion(startloc, newloc, 0);
6846 startloc = newloc;
6848 p += length + 1;
6849 length = 0;
6851 if (end)
6852 break;
6854 switch (c) {
6855 case '=':
6856 flag |= EXP_VARTILDE2;
6857 reject++;
6858 /* fall through */
6859 case ':':
6861 * sort of a hack - expand tildes in variable
6862 * assignments (after the first '=' and after ':'s).
6864 if (*--p == '~') {
6865 goto tilde;
6867 continue;
6868 case CTLQUOTEMARK:
6869 /* "$@" syntax adherence hack */
6870 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6871 p = evalvar(p + 1, flag | EXP_QUOTED) + 1;
6872 goto start;
6874 inquotes ^= EXP_QUOTED;
6875 addquote:
6876 if (flag & QUOTES_ESC) {
6877 p--;
6878 length++;
6879 startloc++;
6881 break;
6882 case CTLESC:
6883 startloc++;
6884 length++;
6885 goto addquote;
6886 case CTLVAR:
6887 TRACE(("argstr: evalvar('%s')\n", p));
6888 p = evalvar(p, flag | inquotes);
6889 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6890 goto start;
6891 #if BASH_PROCESS_SUBST
6892 case CTLTOPROC:
6893 case CTLFROMPROC:
6894 #endif
6895 case CTLBACKQ:
6896 expbackq(argbackq->n, flag | inquotes IF_BASH_PROCESS_SUBST(, c));
6897 goto start;
6898 #if ENABLE_FEATURE_SH_MATH
6899 case CTLARI:
6900 p = expari(p, flag | inquotes);
6901 goto start;
6902 #endif
6905 return p - 1;
6908 static char *
6909 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6910 char *pattern, int quotes, int zero)
6912 char *loc, *loc2;
6913 char c;
6915 loc = startp;
6916 loc2 = rmesc;
6917 do {
6918 int match;
6919 const char *s = loc2;
6921 c = *loc2;
6922 if (zero) {
6923 *loc2 = '\0';
6924 s = rmesc;
6926 match = pmatch(pattern, s);
6928 *loc2 = c;
6929 if (match)
6930 return loc;
6931 if (quotes && (unsigned char)*loc == CTLESC)
6932 loc++;
6933 loc++;
6934 loc2++;
6935 } while (c);
6936 return NULL;
6939 static char *
6940 scanright(char *startp, char *rmesc, char *rmescend,
6941 char *pattern, int quotes, int match_at_start)
6943 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6944 int try2optimize = match_at_start;
6945 #endif
6946 int esc = 0;
6947 char *loc;
6948 char *loc2;
6950 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6951 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6952 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6953 * Logic:
6954 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6955 * and on each iteration they go back two/one char until they reach the beginning.
6956 * We try to match "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6957 * If one of these matches, return pointer past last matched char in startp.
6959 /* TODO: document in what other circumstances we are called. */
6961 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6962 int match;
6963 char c = *loc2;
6964 const char *s = loc2;
6965 if (match_at_start) {
6966 *loc2 = '\0';
6967 s = rmesc;
6969 match = pmatch(pattern, s);
6970 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6971 *loc2 = c;
6972 if (match)
6973 return loc;
6974 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6975 if (try2optimize) {
6976 /* Maybe we can optimize this:
6977 * if pattern ends with unescaped *, we can avoid checking
6978 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6979 * it won't match truncated "raw_value_of_" strings too.
6981 unsigned plen = strlen(pattern);
6982 /* Does it end with "*"? */
6983 if (plen != 0 && pattern[--plen] == '*') {
6984 /* "xxxx*" is not escaped */
6985 /* "xxx\*" is escaped */
6986 /* "xx\\*" is not escaped */
6987 /* "x\\\*" is escaped */
6988 int slashes = 0;
6989 while (plen != 0 && pattern[--plen] == '\\')
6990 slashes++;
6991 if (!(slashes & 1))
6992 break; /* ends with unescaped "*" */
6994 try2optimize = 0;
6996 #endif
6997 loc--;
6998 if (quotes) {
6999 if (--esc < 0) {
7000 esc = esclen(startp, loc);
7002 if (esc % 2) {
7003 esc--;
7004 loc--;
7008 return NULL;
7011 static void varunset(const char *, const char *, const char *, int) NORETURN;
7012 static void
7013 varunset(const char *end, const char *var, const char *umsg, int varflags)
7015 const char *msg;
7016 const char *tail;
7018 tail = nullstr;
7019 msg = "parameter not set";
7020 if (umsg) {
7021 if ((unsigned char)*end == CTLENDVAR) {
7022 if (varflags & VSNUL)
7023 tail = " or null";
7024 } else {
7025 msg = umsg;
7028 ifsfree();
7029 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
7032 static char *
7033 subevalvar(char *start, char *str, int strloc,
7034 int startloc, int varflags, int flag)
7036 int subtype = varflags & VSTYPE;
7037 int quotes = flag & QUOTES_ESC;
7038 char *startp;
7039 char *loc;
7040 char *rmesc, *rmescend;
7041 long amount;
7042 int resetloc;
7043 int argstr_flags;
7044 IF_BASH_PATTERN_SUBST(int workloc;)
7045 IF_BASH_PATTERN_SUBST(int slash_pos;)
7046 IF_BASH_PATTERN_SUBST(char *repl;)
7047 int zero;
7048 char *(*scan)(char*, char*, char*, char*, int, int);
7049 char *p;
7051 //bb_error_msg("subevalvar(start:'%s',str:'%s',strloc:%d,startloc:%d,varflags:%x,quotes:%d)",
7052 // start, str, strloc, startloc, varflags, quotes);
7054 #if BASH_PATTERN_SUBST
7055 /* For "${v/pattern/repl}", we must find the delimiter _before_
7056 * argstr() call expands possible variable references in pattern:
7057 * think about "v=a; a=a/; echo ${v/$a/r}" case.
7059 repl = NULL;
7060 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7061 /* Find '/' and replace with NUL */
7062 repl = start;
7063 /* The pattern can't be empty.
7064 * IOW: if the first char after "${v//" is a slash,
7065 * it does not terminate the pattern - it's the first char of the pattern:
7066 * v=/dev/ram; echo ${v////-} prints -dev-ram (pattern is "/")
7067 * v=/dev/ram; echo ${v///r/-} prints /dev-am (pattern is "/r")
7069 if (*repl == '/')
7070 repl++;
7071 for (;;) {
7072 if (*repl == '\0') {
7073 repl = NULL;
7074 break;
7076 /* Skip over quoted 'str'. Example: ${var/'/'} - second / is not a separator */
7077 if ((unsigned char)*repl == CTLQUOTEMARK) {
7078 while ((unsigned char)*++repl != CTLQUOTEMARK)
7079 continue;
7081 if (*repl == '/') {
7082 *repl = '\0';
7083 break;
7085 if ((unsigned char)*repl == CTLENDVAR) { /* ${v/pattern} (no trailing /, no repl) */
7086 repl = NULL;
7087 break;
7089 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
7090 if ((unsigned char)*repl == CTLESC && repl[1])
7091 repl++;
7092 repl++;
7095 #endif
7096 argstr_flags = (flag & EXP_DISCARD) | EXP_TILDE;
7097 if (!str
7098 #if BASH_SUBSTR
7099 && subtype != VSSUBSTR
7100 #endif
7102 /* EXP_CASE keeps CTLESC's */
7103 argstr_flags |= EXP_CASE;
7105 p = argstr(start, argstr_flags);
7107 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
7108 #if BASH_PATTERN_SUBST
7109 slash_pos = -1;
7110 if (repl) {
7111 slash_pos = expdest - ((char *)stackblock() + strloc);
7112 if (!(flag & EXP_DISCARD))
7113 STPUTC('/', expdest);
7114 //bb_error_msg("repl+1:'%s'", repl + 1);
7115 p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
7116 *repl = '/';
7118 #endif
7119 if (flag & EXP_DISCARD)
7120 return p;
7122 startp = (char *)stackblock() + startloc;
7123 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
7125 switch (subtype) {
7126 case VSASSIGN:
7127 setvar0(str, startp);
7129 loc = startp;
7130 goto out;
7132 case VSQUESTION:
7133 varunset(start, str, startp, varflags);
7134 /* NOTREACHED */
7136 #if BASH_SUBSTR
7137 case VSSUBSTR: {
7138 int pos, len, orig_len;
7139 char *colon;
7140 char *vstr;
7142 loc = vstr = stackblock() + strloc;
7144 /* Read POS in ${var:POS:LEN} */
7145 colon = strchr(loc, ':');
7146 if (colon) *colon = '\0';
7147 pos = substr_atoi(loc);
7148 if (colon) *colon = ':';
7150 /* Read LEN in ${var:POS:LEN} */
7151 len = vstr - startp - 1;
7152 /* *loc != '\0', guaranteed by parser */
7153 if (quotes) {
7154 char *ptr;
7155 /* Adjust the length by the number of escapes */
7156 for (ptr = startp; ptr < (vstr - 1); ptr++) {
7157 if ((unsigned char)*ptr == CTLESC) {
7158 len--;
7159 ptr++;
7163 orig_len = len;
7164 if (*loc++ == ':') {
7165 /* ${var::LEN} */
7166 len = substr_atoi(loc);
7167 } else {
7168 /* Skip POS in ${var:POS:LEN} */
7169 len = orig_len;
7170 while (*loc && *loc != ':')
7171 loc++;
7172 if (*loc++ == ':')
7173 len = substr_atoi(loc);
7175 if (pos < 0) {
7176 /* ${VAR:$((-n)):l} starts n chars from the end */
7177 pos = orig_len + pos;
7179 if ((unsigned)pos >= orig_len) {
7180 /* apart from obvious ${VAR:999999:l},
7181 * covers ${VAR:$((-9999999)):l} - result is ""
7182 * (bash compat)
7184 pos = 0;
7185 len = 0;
7187 if (len < 0) {
7188 /* ${VAR:N:-M} sets LEN to strlen()-M */
7189 len = (orig_len - pos) + len;
7191 if ((unsigned)len > (orig_len - pos))
7192 len = orig_len - pos;
7194 if (!quotes) {
7195 /* want: loc = mempcpy(startp, startp + pos, len)
7196 * but it does not allow overlapping arguments */
7197 loc = startp;
7198 while (--len >= 0) {
7199 *loc = loc[pos];
7200 loc++;
7202 } else {
7203 for (vstr = startp; pos != 0; pos--) {
7204 if ((unsigned char)*vstr == CTLESC)
7205 vstr++;
7206 vstr++;
7208 for (loc = startp; len != 0; len--) {
7209 if ((unsigned char)*vstr == CTLESC)
7210 *loc++ = *vstr++;
7211 *loc++ = *vstr++;
7214 *loc = '\0';
7215 goto out;
7217 #endif /* BASH_SUBSTR */
7220 resetloc = expdest - (char *)stackblock();
7222 #if BASH_PATTERN_SUBST
7223 repl = NULL;
7225 /* We'll comeback here if we grow the stack while handling
7226 * a VSREPLACE or VSREPLACEALL, since our pointers into the
7227 * stack will need rebasing, and we'll need to remove our work
7228 * areas each time
7230 restart:
7231 #endif
7233 amount = expdest - ((char *)stackblock() + resetloc);
7234 STADJUST(-amount, expdest);
7235 startp = (char *)stackblock() + startloc;
7237 rmesc = startp;
7238 rmescend = (char *)stackblock() + strloc;
7239 //bb_error_msg("str7:'%s'", rmescend);
7240 if (quotes) {
7241 //TODO: how to handle slash_pos here if string changes (shortens?)
7242 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
7243 if (rmesc != startp) {
7244 rmescend = expdest;
7245 startp = (char *)stackblock() + startloc;
7248 rmescend--;
7249 str = (char *)stackblock() + strloc;
7251 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7252 * The result is a_\_z_c (not a\_\_z_c)!
7254 * The search pattern and replace string treat backslashes differently!
7255 * "&slash_pos" causes rmescapes() to work differently on the pattern
7256 * and string. It's only used on the first call.
7258 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7259 rmescapes(str, RMESCAPE_GLOB,
7260 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7263 #if BASH_PATTERN_SUBST
7264 workloc = expdest - (char *)stackblock();
7265 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7266 size_t no_meta_len, first_escaped;
7267 int len;
7268 char *idx, *end;
7270 if (!repl) {
7271 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
7272 repl = nullstr;
7273 if (slash_pos >= 0) {
7274 repl = str + slash_pos;
7275 *repl++ = '\0';
7278 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
7280 /* If there's no pattern to match, return the expansion unmolested */
7281 if (str[0] == '\0')
7282 goto out1;
7284 first_escaped = (str[0] == '\\' && str[1]);
7285 /* "first_escaped" trick allows to treat e.g. "\*no_glob_chars"
7286 * as literal too (as it is semi-common, and easy to accomodate
7287 * by just using str + 1).
7289 no_meta_len = strpbrk(str + first_escaped * 2, "*?[\\") ? 0 : strlen(str);
7290 len = 0;
7291 idx = startp;
7292 end = str - 1;
7293 while (idx <= end) {
7294 try_to_match:
7295 if (no_meta_len == 0) {
7296 /* pattern has meta chars, have to glob */
7297 loc = scanright(idx, rmesc, rmescend, str, quotes, /*match_at_start:*/ 1);
7298 } else {
7299 /* Testcase for very slow replace (performs about 22k replaces):
7300 * x=::::::::::::::::::::::
7301 * x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;echo ${#x}
7302 * echo "${x//:/|}"
7303 * To test "first_escaped" logic, replace : with *.
7305 if (strncmp(rmesc, str + first_escaped, no_meta_len - first_escaped) != 0)
7306 goto no_match;
7307 loc = idx;
7308 if (!quotes) {
7309 loc += no_meta_len - first_escaped;
7310 } else {
7311 size_t n = no_meta_len - first_escaped;
7312 do {
7313 if ((unsigned char)*loc == CTLESC)
7314 loc++;
7315 loc++;
7316 } while (--n != 0);
7319 //bb_error_msg("scanright('%s'):'%s'", str, loc);
7320 if (!loc) {
7321 char *restart_detect;
7322 no_match:
7323 /* No match, advance */
7324 restart_detect = stackblock();
7325 skip_matching:
7326 if (idx >= end)
7327 break;
7328 STPUTC(*idx, expdest);
7329 if (stackblock() != restart_detect)
7330 goto restart;
7331 if (quotes && (unsigned char)*idx == CTLESC) {
7332 idx++;
7333 len++;
7334 STPUTC(*idx, expdest);
7335 if (stackblock() != restart_detect)
7336 goto restart;
7338 idx++;
7339 len++;
7340 rmesc++;
7341 /* continue; - prone to quadratic behavior, smarter code: */
7342 if (str[0] == '*') {
7343 /* Pattern is "*foo". If "*foo" does not match "long_string",
7344 * it would never match "ong_string" etc, no point in trying.
7346 goto skip_matching;
7348 goto try_to_match;
7351 if (subtype == VSREPLACEALL) {
7352 while (idx < loc) {
7353 if (quotes && (unsigned char)*idx == CTLESC)
7354 idx++;
7355 idx++;
7356 rmesc++;
7358 } else {
7359 idx = loc;
7362 /* The STPUTC invocations above may resize and move the
7363 * stack via realloc(3). Since repl is a pointer into the
7364 * stack, we need to reconstruct it relative to stackblock().
7366 if (slash_pos >= 0)
7367 repl = (char *)stackblock() + strloc + slash_pos + 1;
7369 //bb_error_msg("repl:'%s'", repl);
7370 for (loc = (char*)repl; *loc; loc++) {
7371 char *restart_detect = stackblock();
7372 if (quotes && *loc == '\\') {
7373 STPUTC(CTLESC, expdest);
7374 if (stackblock() != restart_detect)
7375 goto restart;
7376 len++;
7378 STPUTC(*loc, expdest);
7379 if (stackblock() != restart_detect)
7380 goto restart;
7381 len++;
7384 if (subtype == VSREPLACE) {
7385 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
7386 while (*idx) {
7387 char *restart_detect = stackblock();
7388 STPUTC(*idx, expdest);
7389 if (stackblock() != restart_detect)
7390 goto restart;
7391 len++;
7392 idx++;
7394 break;
7398 /* We've put the replaced text into a buffer at workloc, now
7399 * move it to the right place and adjust the stack.
7401 STPUTC('\0', expdest);
7402 startp = (char *)stackblock() + startloc;
7403 memmove(startp, (char *)stackblock() + workloc, len + 1);
7404 //bb_error_msg("startp:'%s'", startp);
7405 loc = startp + len;
7406 goto out;
7408 #endif /* BASH_PATTERN_SUBST */
7410 subtype -= VSTRIMRIGHT;
7411 #if DEBUG
7412 if (subtype < 0 || subtype > 7)
7413 abort();
7414 #endif
7415 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
7416 zero = subtype >> 1;
7417 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7418 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7420 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7421 if (loc) {
7422 if (zero) {
7423 memmove(startp, loc, str - loc);
7424 loc = startp + (str - loc) - 1;
7426 *loc = '\0';
7427 } else
7428 loc = str - 1;
7430 out:
7431 amount = loc - expdest;
7432 STADJUST(amount, expdest);
7433 #if BASH_PATTERN_SUBST
7434 out1:
7435 #endif
7436 /* Remove any recorded regions beyond start of variable */
7437 removerecordregions(startloc);
7439 return p;
7443 * Add the value of a specialized variable to the stack string.
7444 * name parameter (examples):
7445 * ash -c 'echo $1' name:'1='
7446 * ash -c 'echo $qwe' name:'qwe='
7447 * ash -c 'echo $$' name:'$='
7448 * ash -c 'echo ${$}' name:'$='
7449 * ash -c 'echo ${$##q}' name:'$=q'
7450 * ash -c 'echo ${#$}' name:'$='
7451 * note: examples with bad shell syntax:
7452 * ash -c 'echo ${#$1}' name:'$=1'
7453 * ash -c 'echo ${#1#}' name:'1=#'
7455 static NOINLINE ssize_t
7456 varvalue(char *name, int varflags, int flags, int quoted)
7458 const char *p;
7459 int num;
7460 int i;
7461 ssize_t len = 0;
7462 int sep;
7463 int subtype = varflags & VSTYPE;
7464 int discard = (subtype == VSPLUS || subtype == VSLENGTH) | (flags & EXP_DISCARD);
7466 if (!subtype) {
7467 if (discard)
7468 return -1;
7470 ifsfree();
7471 raise_error_syntax("bad substitution");
7474 flags |= EXP_KEEPNUL;
7475 flags &= discard ? ~QUOTES_ESC : ~0;
7476 sep = (flags & EXP_FULL) << CHAR_BIT;
7478 switch (*name) {
7479 case '$':
7480 num = rootpid;
7481 goto numvar;
7482 case '?':
7483 num = exitstatus;
7484 goto numvar;
7485 case '#':
7486 num = shellparam.nparam;
7487 goto numvar;
7488 case '!':
7489 num = backgndpid;
7490 if (num == 0)
7491 return -1;
7492 numvar:
7493 len = cvtnum(num, flags);
7494 goto check_1char_name;
7495 case '-':
7496 expdest = makestrspace(NOPTS, expdest);
7497 for (i = NOPTS - 1; i >= 0; i--) {
7498 if (optlist[i] && optletters(i)) {
7499 USTPUTC(optletters(i), expdest);
7500 len++;
7503 check_1char_name:
7504 #if 0
7505 /* handles cases similar to ${#$1} */
7506 if (name[2] != '\0')
7507 raise_error_syntax("bad substitution");
7508 #endif
7509 break;
7510 case '@':
7511 if (quoted && sep)
7512 goto param;
7513 /* fall through */
7514 case '*': {
7515 char **ap;
7516 char sepc;
7517 char c;
7519 /* We will set c to 0 or ~0 depending on whether
7520 * we're doing field splitting. We won't do field
7521 * splitting if either we're quoted or sep is zero.
7523 * Instead of testing (quoted || !sep) the following
7524 * trick optimises away any branches by using the
7525 * fact that EXP_QUOTED (which is the only bit that
7526 * can be set in quoted) is the same as EXP_FULL <<
7527 * CHAR_BIT (which is the only bit that can be set
7528 * in sep).
7530 #if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7531 #error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7532 #endif
7533 c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7534 sep &= ~quoted;
7535 sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
7536 param:
7537 sepc = sep;
7538 ap = shellparam.p;
7539 if (!ap)
7540 return -1;
7541 while ((p = *ap++) != NULL) {
7542 len += strtodest(p, flags);
7544 if (*ap && sep) {
7545 len++;
7546 memtodest(&sepc, 1, flags);
7549 break;
7550 } /* case '*' */
7551 case '0':
7552 case '1':
7553 case '2':
7554 case '3':
7555 case '4':
7556 case '5':
7557 case '6':
7558 case '7':
7559 case '8':
7560 case '9':
7561 num = atoi(name); /* number(name) fails on ${N#str} etc */
7562 if (num < 0 || num > shellparam.nparam)
7563 return -1;
7564 p = num ? shellparam.p[num - 1] : arg0;
7565 goto value;
7566 default:
7567 /* NB: name has form "VAR=..." */
7568 p = lookupvar(name);
7569 value:
7570 if (!p)
7571 return -1;
7573 len = strtodest(p, flags);
7574 #if ENABLE_UNICODE_SUPPORT
7575 if (subtype == VSLENGTH && len > 0) {
7576 reinit_unicode_for_ash();
7577 if (unicode_status == UNICODE_ON) {
7578 STADJUST(-len, expdest);
7579 discard = 0;
7580 len = unicode_strlen(p);
7583 #endif
7584 break;
7587 if (discard)
7588 STADJUST(-len, expdest);
7590 return len;
7594 * Expand a variable, and return a pointer to the next character in the
7595 * input string.
7597 static char *
7598 evalvar(char *p, int flag)
7600 char varflags;
7601 char subtype;
7602 char *var;
7603 int patloc;
7604 int startloc;
7605 ssize_t varlen;
7606 int discard;
7607 int quoted;
7609 varflags = (unsigned char) *p++;
7610 subtype = varflags & VSTYPE;
7612 quoted = flag & EXP_QUOTED;
7613 var = p;
7614 startloc = expdest - (char *)stackblock();
7615 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
7617 again:
7618 varlen = varvalue(var, varflags, flag, quoted);
7619 if (varflags & VSNUL)
7620 varlen--;
7622 discard = varlen < 0 ? EXP_DISCARD : 0;
7624 switch (subtype) {
7625 case VSPLUS:
7626 discard ^= EXP_DISCARD;
7627 /* fall through */
7628 case 0:
7629 case VSMINUS:
7630 p = argstr(p, flag | EXP_TILDE | EXP_WORD | (discard ^ EXP_DISCARD));
7631 goto record;
7633 case VSASSIGN:
7634 case VSQUESTION:
7635 p = subevalvar(p, var, 0, startloc, varflags,
7636 (flag & ~QUOTES_ESC) | (discard ^ EXP_DISCARD));
7638 if ((flag | ~discard) & EXP_DISCARD)
7639 goto record;
7641 varflags &= ~VSNUL;
7642 subtype = VSNORMAL;
7643 goto again;
7646 if ((discard & ~flag) && uflag)
7647 varunset(p, var, 0, 0);
7649 if (subtype == VSLENGTH) {
7650 p++;
7651 if (flag & EXP_DISCARD)
7652 return p;
7653 cvtnum(varlen > 0 ? varlen : 0, flag);
7654 goto really_record;
7657 if (subtype == VSNORMAL)
7658 goto record;
7660 #if DEBUG
7661 switch (subtype) {
7662 case VSTRIMLEFT:
7663 case VSTRIMLEFTMAX:
7664 case VSTRIMRIGHT:
7665 case VSTRIMRIGHTMAX:
7666 #if BASH_SUBSTR
7667 case VSSUBSTR:
7668 #endif
7669 #if BASH_PATTERN_SUBST
7670 case VSREPLACE:
7671 case VSREPLACEALL:
7672 #endif
7673 break;
7674 default:
7675 abort();
7677 #endif
7679 flag |= discard;
7680 if (!(flag & EXP_DISCARD)) {
7682 * Terminate the string and start recording the pattern
7683 * right after it
7685 STPUTC('\0', expdest);
7688 patloc = expdest - (char *)stackblock();
7689 p = subevalvar(p, NULL, patloc, startloc, varflags, flag);
7691 record:
7692 if ((flag | discard) & EXP_DISCARD)
7693 return p;
7695 really_record:
7696 if (quoted) {
7697 quoted = *var == '@' && shellparam.nparam;
7698 if (!quoted)
7699 return p;
7701 recordregion(startloc, expdest - (char *)stackblock(), quoted);
7702 return p;
7706 * Add a file name to the list.
7708 static void
7709 addfname(const char *name)
7711 struct strlist *sp;
7713 sp = stzalloc(sizeof(*sp));
7714 sp->text = sstrdup(name);
7715 *exparg.lastp = sp;
7716 exparg.lastp = &sp->next;
7719 /* Avoid glob() (and thus, stat() et al) for words like "echo" */
7720 static int
7721 hasmeta(const char *p)
7723 static const char chars[] ALIGN1 = {
7724 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7727 for (;;) {
7728 p = strpbrk(p, chars);
7729 if (!p)
7730 break;
7731 switch ((unsigned char)*p) {
7732 case CTLQUOTEMARK:
7733 for (;;) {
7734 p++;
7735 if ((unsigned char)*p == CTLQUOTEMARK)
7736 break;
7737 if ((unsigned char)*p == CTLESC)
7738 p++;
7739 if (*p == '\0') /* huh? */
7740 return 0;
7742 break;
7743 case '\\':
7744 case CTLESC:
7745 p++;
7746 if (*p == '\0')
7747 return 0;
7748 break;
7749 case '[':
7750 if (!strchr(p + 1, ']')) {
7751 /* It's not a properly closed [] pattern,
7752 * but other metas may follow. Continue checking.
7753 * my[file* _is_ globbed by bash
7754 * and matches filenames like "my[file1".
7756 break;
7758 /* fallthrough */
7759 default:
7760 /* case '*': */
7761 /* case '?': */
7762 return 1;
7764 p++;
7767 return 0;
7770 /* If we want to use glob() from libc... */
7771 #if !ENABLE_ASH_INTERNAL_GLOB
7773 /* Add the result of glob() to the list */
7774 static void
7775 addglob(const glob_t *pglob)
7777 char **p = pglob->gl_pathv;
7779 do {
7780 addfname(*p);
7781 } while (*++p);
7783 static void
7784 expandmeta(struct strlist *str /*, int flag*/)
7786 /* TODO - EXP_REDIR */
7788 while (str) {
7789 char *p;
7790 glob_t pglob;
7791 int i;
7793 if (fflag)
7794 goto nometa;
7796 if (!hasmeta(str->text))
7797 goto nometa;
7799 INT_OFF;
7800 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7801 // GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7802 // GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7804 // glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7805 // if you pass it "file\?", it returns "file\?", not "file?", if no match.
7806 // Which means you need to unescape the string, right? Not so fast:
7807 // if there _is_ a file named "file\?" (with backslash), it is returned
7808 // as "file\?" too (whichever pattern you used to find it, say, "file*").
7809 // You DON'T KNOW by looking at the result whether you need to unescape it.
7811 // Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7812 // returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7813 // Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7814 // With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7815 // i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7816 // i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7817 i = glob(p, 0, NULL, &pglob);
7818 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7819 if (p != str->text)
7820 free(p);
7821 switch (i) {
7822 case 0:
7823 #if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7824 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7825 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7826 goto nometa2;
7827 #endif
7828 addglob(&pglob);
7829 globfree(&pglob);
7830 INT_ON;
7831 break;
7832 case GLOB_NOMATCH:
7833 //nometa2:
7834 globfree(&pglob);
7835 INT_ON;
7836 nometa:
7837 *exparg.lastp = str;
7838 rmescapes(str->text, 0, NULL);
7839 exparg.lastp = &str->next;
7840 break;
7841 default: /* GLOB_NOSPACE */
7842 globfree(&pglob);
7843 INT_ON;
7844 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7846 str = str->next;
7850 #else
7851 /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7854 * Do metacharacter (i.e. *, ?, [...]) expansion.
7856 typedef struct exp_t {
7857 char *dir;
7858 unsigned dir_max;
7859 } exp_t;
7860 static void
7861 expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7863 #define expdir exp->dir
7864 #define expdir_max exp->dir_max
7865 char *enddir = expdir + expdir_len;
7866 char *p;
7867 const char *cp;
7868 char *start;
7869 char *endname;
7870 int metaflag;
7871 struct stat statb;
7872 DIR *dirp;
7873 struct dirent *dp;
7874 int atend;
7875 int matchdot;
7876 int esc;
7878 metaflag = 0;
7879 start = name;
7880 for (p = name; esc = 0, *p; p += esc + 1) {
7881 if (*p == '*' || *p == '?')
7882 metaflag = 1;
7883 else if (*p == '[') {
7884 char *q = p + 1;
7885 if (*q == '!')
7886 q++;
7887 for (;;) {
7888 if (*q == '\\')
7889 q++;
7890 if (*q == '/' || *q == '\0')
7891 break;
7892 if (*++q == ']') {
7893 metaflag = 1;
7894 break;
7897 } else {
7898 if (*p == '\\' && p[1])
7899 esc++;
7900 if (p[esc] == '/') {
7901 if (metaflag)
7902 break;
7903 start = p + esc + 1;
7907 if (metaflag == 0) { /* we've reached the end of the file name */
7908 if (!expdir_len)
7909 return;
7910 p = name;
7911 do {
7912 if (*p == '\\' && p[1])
7913 p++;
7914 *enddir++ = *p;
7915 } while (*p++);
7916 if (lstat(expdir, &statb) == 0)
7917 addfname(expdir);
7918 return;
7920 endname = p;
7921 if (name < start) {
7922 p = name;
7923 do {
7924 if (*p == '\\' && p[1])
7925 p++;
7926 *enddir++ = *p++;
7927 } while (p < start);
7929 *enddir = '\0';
7930 cp = expdir;
7931 expdir_len = enddir - cp;
7932 if (!expdir_len)
7933 cp = ".";
7934 dirp = opendir(cp);
7935 if (dirp == NULL)
7936 return;
7937 if (*endname == 0) {
7938 atend = 1;
7939 } else {
7940 atend = 0;
7941 *endname = '\0';
7942 endname += esc + 1;
7944 name_len -= endname - name;
7945 matchdot = 0;
7946 p = start;
7947 if (*p == '\\')
7948 p++;
7949 if (*p == '.')
7950 matchdot++;
7951 while (!pending_int && (dp = readdir(dirp)) != NULL) {
7952 if (dp->d_name[0] == '.' && !matchdot)
7953 continue;
7954 if (pmatch(start, dp->d_name)) {
7955 if (atend) {
7956 strcpy(enddir, dp->d_name);
7957 addfname(expdir);
7958 } else {
7959 unsigned offset;
7960 unsigned len;
7962 p = stpcpy(enddir, dp->d_name);
7963 *p = '/';
7965 offset = p - expdir + 1;
7966 len = offset + name_len + NAME_MAX;
7967 if (len > expdir_max) {
7968 len += PATH_MAX;
7969 expdir = ckrealloc(expdir, len);
7970 expdir_max = len;
7973 expmeta(exp, endname, name_len, offset);
7974 enddir = expdir + expdir_len;
7978 closedir(dirp);
7979 if (!atend)
7980 endname[-esc - 1] = esc ? '\\' : '/';
7981 #undef expdir
7982 #undef expdir_max
7985 static struct strlist *
7986 msort(struct strlist *list, int len)
7988 struct strlist *p, *q = NULL;
7989 struct strlist **lpp;
7990 int half;
7991 int n;
7993 if (len <= 1)
7994 return list;
7995 half = len >> 1;
7996 p = list;
7997 for (n = half; --n >= 0;) {
7998 q = p;
7999 p = p->next;
8001 q->next = NULL; /* terminate first half of list */
8002 q = msort(list, half); /* sort first half of list */
8003 p = msort(p, len - half); /* sort second half */
8004 lpp = &list;
8005 for (;;) {
8006 #if ENABLE_LOCALE_SUPPORT
8007 if (strcoll(p->text, q->text) < 0)
8008 #else
8009 if (strcmp(p->text, q->text) < 0)
8010 #endif
8012 *lpp = p;
8013 lpp = &p->next;
8014 p = *lpp;
8015 if (p == NULL) {
8016 *lpp = q;
8017 break;
8019 } else {
8020 *lpp = q;
8021 lpp = &q->next;
8022 q = *lpp;
8023 if (q == NULL) {
8024 *lpp = p;
8025 break;
8029 return list;
8033 * Sort the results of file name expansion. It calculates the number of
8034 * strings to sort and then calls msort (short for merge sort) to do the
8035 * work.
8037 static struct strlist *
8038 expsort(struct strlist *str)
8040 int len;
8041 struct strlist *sp;
8043 len = 0;
8044 for (sp = str; sp; sp = sp->next)
8045 len++;
8046 return msort(str, len);
8049 static void
8050 expandmeta(struct strlist *str /*, int flag*/)
8052 /* TODO - EXP_REDIR */
8054 while (str) {
8055 exp_t exp;
8056 struct strlist **savelastp;
8057 struct strlist *sp;
8058 char *p;
8059 unsigned len;
8061 if (fflag)
8062 goto nometa;
8063 if (!hasmeta(str->text))
8064 goto nometa;
8065 savelastp = exparg.lastp;
8067 INT_OFF;
8068 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
8069 len = strlen(p);
8070 exp.dir_max = len + PATH_MAX;
8071 exp.dir = ckmalloc(exp.dir_max);
8073 expmeta(&exp, p, len, 0);
8074 free(exp.dir);
8075 if (p != str->text)
8076 free(p);
8077 INT_ON;
8078 if (exparg.lastp == savelastp) {
8080 * no matches
8082 nometa:
8083 *exparg.lastp = str;
8084 rmescapes(str->text, 0, NULL);
8085 exparg.lastp = &str->next;
8086 } else {
8087 *exparg.lastp = NULL;
8088 *savelastp = sp = expsort(*savelastp);
8089 while (sp->next != NULL)
8090 sp = sp->next;
8091 exparg.lastp = &sp->next;
8093 str = str->next;
8096 #endif /* ENABLE_ASH_INTERNAL_GLOB */
8099 * Perform variable substitution and command substitution on an argument,
8100 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
8101 * perform splitting and file name expansion. When arglist is NULL, perform
8102 * here document expansion.
8104 static void
8105 expandarg(union node *arg, struct arglist *arglist, int flag)
8107 struct strlist *sp;
8108 char *p;
8110 argbackq = arg->narg.backquote;
8111 STARTSTACKSTR(expdest);
8112 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
8113 argstr(arg->narg.text, flag);
8114 if (arglist == NULL) {
8115 /* here document expanded */
8116 goto out;
8118 p = grabstackstr(expdest);
8119 TRACE(("expandarg: p:'%s'\n", p));
8120 exparg.lastp = &exparg.list;
8122 * TODO - EXP_REDIR
8124 if (flag & EXP_FULL) {
8125 ifsbreakup(p, &exparg);
8126 *exparg.lastp = NULL;
8127 exparg.lastp = &exparg.list;
8128 expandmeta(exparg.list /*, flag*/);
8129 } else {
8130 sp = stzalloc(sizeof(*sp));
8131 sp->text = p;
8132 *exparg.lastp = sp;
8133 exparg.lastp = &sp->next;
8135 *exparg.lastp = NULL;
8136 if (exparg.list) {
8137 *arglist->lastp = exparg.list;
8138 arglist->lastp = exparg.lastp;
8141 out:
8142 ifsfree();
8146 * Expand shell variables and backquotes inside a here document.
8148 static void
8149 expandhere(union node *arg)
8151 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
8155 * Returns true if the pattern matches the string.
8157 static int
8158 patmatch(char *pattern, const char *string)
8160 char *p = preglob(pattern, 0);
8161 int r = pmatch(p, string);
8162 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
8163 return r;
8167 * See if a pattern matches in a case statement.
8169 static int
8170 casematch(union node *pattern, char *val)
8172 struct stackmark smark;
8173 int result;
8175 setstackmark(&smark);
8176 argbackq = pattern->narg.backquote;
8177 STARTSTACKSTR(expdest);
8178 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
8179 ifsfree();
8180 result = patmatch(stackblock(), val);
8181 popstackmark(&smark);
8182 return result;
8186 /* ============ find_command */
8188 struct builtincmd {
8189 const char *name;
8190 int (*builtin)(int, char **) FAST_FUNC;
8191 /* unsigned flags; */
8193 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
8194 /* "regular" builtins always take precedence over commands,
8195 * regardless of PATH=....%builtin... position */
8196 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
8197 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
8199 struct cmdentry {
8200 smallint cmdtype; /* CMDxxx */
8201 union param {
8202 int index;
8203 /* index >= 0 for commands without path (slashes) */
8204 /* (TODO: what exactly does the value mean? PATH position?) */
8205 /* index == -1 for commands with slashes */
8206 /* index == (-2 - applet_no) for NOFORK applets */
8207 const struct builtincmd *cmd;
8208 struct funcnode *func;
8209 } u;
8211 /* values of cmdtype */
8212 #define CMDUNKNOWN -1 /* no entry in table for command */
8213 #define CMDNORMAL 0 /* command is an executable program */
8214 #define CMDFUNCTION 1 /* command is a shell function */
8215 #define CMDBUILTIN 2 /* command is a shell builtin */
8217 /* action to find_command() */
8218 #define DO_ERR 0x01 /* prints errors */
8219 #define DO_ABS 0x02 /* checks absolute paths */
8220 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
8221 #define DO_ALTPATH 0x08 /* using alternate path */
8222 #define DO_REGBLTIN 0x10 /* regular built-ins and functions only */
8224 static void find_command(char *, struct cmdentry *, int, const char *);
8227 /* ============ Hashing commands */
8230 * When commands are first encountered, they are entered in a hash table.
8231 * This ensures that a full path search will not have to be done for them
8232 * on each invocation.
8234 * We should investigate converting to a linear search, even though that
8235 * would make the command name "hash" a misnomer.
8238 struct tblentry {
8239 struct tblentry *next; /* next entry in hash chain */
8240 union param param; /* definition of builtin function */
8241 smallint cmdtype; /* CMDxxx */
8242 char rehash; /* if set, cd done since entry created */
8243 char cmdname[1]; /* name of command */
8246 static struct tblentry **cmdtable;
8247 #define INIT_G_cmdtable() do { \
8248 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
8249 } while (0)
8251 static int builtinloc = -1; /* index in path of %builtin, or -1 */
8254 static void
8255 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
8257 #if ENABLE_FEATURE_SH_STANDALONE
8258 if (applet_no >= 0) {
8259 if (APPLET_IS_NOEXEC(applet_no)) {
8260 clearenv();
8261 while (*envp)
8262 putenv(*envp++);
8263 popredir(/*drop:*/ 1);
8264 run_noexec_applet_and_exit(applet_no, cmd, argv);
8266 /* re-exec ourselves with the new arguments */
8267 execve(bb_busybox_exec_path, argv, envp);
8268 /* If they called chroot or otherwise made the binary no longer
8269 * executable, fall through */
8271 #endif
8273 repeat:
8274 #ifdef SYSV
8275 do {
8276 execve(cmd, argv, envp);
8277 } while (errno == EINTR);
8278 #else
8279 execve(cmd, argv, envp);
8280 #endif
8282 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
8283 /* Run "cmd" as a shell script:
8284 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8285 * "If the execve() function fails with ENOEXEC, the shell
8286 * shall execute a command equivalent to having a shell invoked
8287 * with the command name as its first operand,
8288 * with any remaining arguments passed to the new shell"
8290 * That is, do not use $SHELL, user's shell, or /bin/sh;
8291 * just call ourselves.
8293 * Note that bash reads ~80 chars of the file, and if it sees
8294 * a zero byte before it sees newline, it doesn't try to
8295 * interpret it, but fails with "cannot execute binary file"
8296 * message and exit code 126. For one, this prevents attempts
8297 * to interpret foreign ELF binaries as shell scripts.
8299 argv[0] = (char*) cmd;
8300 cmd = bb_busybox_exec_path;
8301 /* NB: this is only possible because all callers of shellexec()
8302 * ensure that the argv[-1] slot exists!
8304 argv--;
8305 argv[0] = (char*) "ash";
8306 goto repeat;
8311 * Exec a program. Never returns. If you change this routine, you may
8312 * have to change the find_command routine as well.
8313 * argv[-1] must exist and be writable! See tryexec() for why.
8315 static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8316 static void shellexec(char *prog, char **argv, const char *path, int idx)
8318 char *cmdname;
8319 int e;
8320 char **envp;
8321 int exerrno;
8322 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
8324 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
8325 if (strchr(prog, '/') != NULL
8326 #if ENABLE_FEATURE_SH_STANDALONE
8327 || (applet_no = find_applet_by_name(prog)) >= 0
8328 #endif
8330 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
8331 if (applet_no >= 0) {
8332 /* We tried execing ourself, but it didn't work.
8333 * Maybe /proc/self/exe doesn't exist?
8334 * Try $PATH search.
8336 goto try_PATH;
8338 e = errno;
8339 } else {
8340 try_PATH:
8341 e = ENOENT;
8342 while (padvance(&path, argv[0]) >= 0) {
8343 cmdname = stackblock();
8344 if (--idx < 0 && pathopt == NULL) {
8345 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
8346 if (errno != ENOENT && errno != ENOTDIR)
8347 e = errno;
8352 /* Map to POSIX errors */
8353 switch (e) {
8354 default:
8355 exerrno = 126;
8356 break;
8357 case ELOOP:
8358 case ENAMETOOLONG:
8359 case ENOENT:
8360 case ENOTDIR:
8361 exerrno = 127;
8362 break;
8364 exitstatus = exerrno;
8365 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
8366 prog, e, suppress_int));
8367 ash_msg_and_raise(EXEND, "%s: %s", prog, errmsg(e, "not found"));
8368 /* NOTREACHED */
8371 static void
8372 printentry(struct tblentry *cmdp)
8374 int idx;
8375 const char *path;
8376 char *name;
8378 idx = cmdp->param.index;
8379 path = pathval();
8380 do {
8381 padvance(&path, cmdp->cmdname);
8382 } while (--idx >= 0);
8383 name = stackblock();
8384 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8388 * Clear out command entries.
8390 static void
8391 clearcmdentry(void)
8393 struct tblentry **tblp;
8394 struct tblentry **pp;
8395 struct tblentry *cmdp;
8397 INT_OFF;
8398 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8399 pp = tblp;
8400 while ((cmdp = *pp) != NULL) {
8401 if (cmdp->cmdtype == CMDNORMAL
8402 || (cmdp->cmdtype == CMDBUILTIN
8403 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8404 && builtinloc > 0
8407 *pp = cmdp->next;
8408 free(cmdp);
8409 } else {
8410 pp = &cmdp->next;
8414 INT_ON;
8418 * Locate a command in the command hash table. If "add" is nonzero,
8419 * add the command to the table if it is not already present. The
8420 * variable "lastcmdentry" is set to point to the address of the link
8421 * pointing to the entry, so that delete_cmd_entry can delete the
8422 * entry.
8424 * Interrupts must be off if called with add != 0.
8426 static struct tblentry **lastcmdentry;
8428 static struct tblentry *
8429 cmdlookup(const char *name, int add)
8431 unsigned int hashval;
8432 const char *p;
8433 struct tblentry *cmdp;
8434 struct tblentry **pp;
8436 p = name;
8437 hashval = (unsigned char)*p << 4;
8438 while (*p)
8439 hashval += (unsigned char)*p++;
8440 hashval &= 0x7FFF;
8441 pp = &cmdtable[hashval % CMDTABLESIZE];
8442 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8443 if (strcmp(cmdp->cmdname, name) == 0)
8444 break;
8445 pp = &cmdp->next;
8447 if (add && cmdp == NULL) {
8448 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8449 + strlen(name)
8450 /* + 1 - already done because
8451 * tblentry::cmdname is char[1] */);
8452 /*cmdp->next = NULL; - ckzalloc did it */
8453 cmdp->cmdtype = CMDUNKNOWN;
8454 strcpy(cmdp->cmdname, name);
8456 lastcmdentry = pp;
8457 return cmdp;
8461 * Delete the command entry returned on the last lookup.
8463 static void
8464 delete_cmd_entry(void)
8466 struct tblentry *cmdp;
8468 INT_OFF;
8469 cmdp = *lastcmdentry;
8470 *lastcmdentry = cmdp->next;
8471 if (cmdp->cmdtype == CMDFUNCTION)
8472 freefunc(cmdp->param.func);
8473 free(cmdp);
8474 INT_ON;
8478 * Add a new command entry, replacing any existing command entry for
8479 * the same name - except special builtins.
8481 static void
8482 addcmdentry(char *name, struct cmdentry *entry)
8484 struct tblentry *cmdp;
8486 cmdp = cmdlookup(name, 1);
8487 if (cmdp->cmdtype == CMDFUNCTION) {
8488 freefunc(cmdp->param.func);
8490 cmdp->cmdtype = entry->cmdtype;
8491 cmdp->param = entry->u;
8492 cmdp->rehash = 0;
8495 static int FAST_FUNC
8496 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8498 struct tblentry **pp;
8499 struct tblentry *cmdp;
8500 int c;
8501 struct cmdentry entry;
8502 char *name;
8504 if (nextopt("r") != '\0') {
8505 clearcmdentry();
8506 return 0;
8509 if (*argptr == NULL) {
8510 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8511 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8512 if (cmdp->cmdtype == CMDNORMAL)
8513 printentry(cmdp);
8516 return 0;
8519 c = 0;
8520 while ((name = *argptr) != NULL) {
8521 cmdp = cmdlookup(name, 0);
8522 if (cmdp != NULL
8523 && (cmdp->cmdtype == CMDNORMAL
8524 || (cmdp->cmdtype == CMDBUILTIN
8525 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8526 && builtinloc > 0
8530 delete_cmd_entry();
8532 find_command(name, &entry, DO_ERR, pathval());
8533 if (entry.cmdtype == CMDUNKNOWN)
8534 c = 1;
8535 argptr++;
8537 return c;
8541 * Called when a cd is done. Marks all commands so the next time they
8542 * are executed they will be rehashed.
8544 static void
8545 hashcd(void)
8547 struct tblentry **pp;
8548 struct tblentry *cmdp;
8550 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8551 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8552 if (cmdp->cmdtype == CMDNORMAL
8553 || (cmdp->cmdtype == CMDBUILTIN
8554 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8555 && builtinloc > 0)
8557 cmdp->rehash = 1;
8564 * Fix command hash table when PATH changed.
8565 * Called before PATH is changed. The argument is the new value of PATH;
8566 * pathval() still returns the old value at this point.
8567 * Called with interrupts off.
8569 static void FAST_FUNC
8570 changepath(const char *newval)
8572 const char *new;
8573 int idx;
8574 int bltin;
8576 new = newval;
8577 idx = 0;
8578 bltin = -1;
8579 for (;;) {
8580 if (*new == '%' && prefix(new + 1, "builtin")) {
8581 bltin = idx;
8582 break;
8584 new = strchr(new, ':');
8585 if (!new)
8586 break;
8587 idx++;
8588 new++;
8590 builtinloc = bltin;
8591 clearcmdentry();
8593 enum {
8594 TEOF,
8595 TNL,
8596 TREDIR,
8597 TWORD,
8598 TSEMI,
8599 TBACKGND,
8600 TAND,
8601 TOR,
8602 TPIPE,
8603 TLP,
8604 TRP,
8605 TENDCASE,
8606 TENDBQUOTE,
8607 TNOT,
8608 TCASE,
8609 TDO,
8610 TDONE,
8611 TELIF,
8612 TELSE,
8613 TESAC,
8614 TFI,
8615 TFOR,
8616 #if BASH_FUNCTION
8617 TFUNCTION,
8618 #endif
8619 TIF,
8620 TIN,
8621 TTHEN,
8622 TUNTIL,
8623 TWHILE,
8624 TBEGIN,
8625 TEND
8627 typedef smallint token_id_t;
8629 /* Nth bit indicates if token marks the end of a list */
8630 enum {
8631 tokendlist = 0
8632 /* 0 */ | (1u << TEOF)
8633 /* 1 */ | (0u << TNL)
8634 /* 2 */ | (0u << TREDIR)
8635 /* 3 */ | (0u << TWORD)
8636 /* 4 */ | (0u << TSEMI)
8637 /* 5 */ | (0u << TBACKGND)
8638 /* 6 */ | (0u << TAND)
8639 /* 7 */ | (0u << TOR)
8640 /* 8 */ | (0u << TPIPE)
8641 /* 9 */ | (0u << TLP)
8642 /* 10 */ | (1u << TRP)
8643 /* 11 */ | (1u << TENDCASE)
8644 /* 12 */ | (1u << TENDBQUOTE)
8645 /* 13 */ | (0u << TNOT)
8646 /* 14 */ | (0u << TCASE)
8647 /* 15 */ | (1u << TDO)
8648 /* 16 */ | (1u << TDONE)
8649 /* 17 */ | (1u << TELIF)
8650 /* 18 */ | (1u << TELSE)
8651 /* 19 */ | (1u << TESAC)
8652 /* 20 */ | (1u << TFI)
8653 /* 21 */ | (0u << TFOR)
8654 #if BASH_FUNCTION
8655 /* 22 */ | (0u << TFUNCTION)
8656 #endif
8657 /* 23 */ | (0u << TIF)
8658 /* 24 */ | (0u << TIN)
8659 /* 25 */ | (1u << TTHEN)
8660 /* 26 */ | (0u << TUNTIL)
8661 /* 27 */ | (0u << TWHILE)
8662 /* 28 */ | (0u << TBEGIN)
8663 /* 29 */ | (1u << TEND)
8664 , /* thus far 29 bits used */
8667 static const char *const tokname_array[] ALIGN_PTR = {
8668 "end of file",
8669 "newline",
8670 "redirection",
8671 "word",
8672 ";",
8673 "&",
8674 "&&",
8675 "||",
8676 "|",
8677 "(",
8678 ")",
8679 ";;",
8680 "`",
8681 #define KWDOFFSET 13
8682 /* the following are keywords */
8683 "!",
8684 "case",
8685 "do",
8686 "done",
8687 "elif",
8688 "else",
8689 "esac",
8690 "fi",
8691 "for",
8692 #if BASH_FUNCTION
8693 "function",
8694 #endif
8695 "if",
8696 "in",
8697 "then",
8698 "until",
8699 "while",
8700 "{",
8701 "}",
8704 /* Wrapper around strcmp for qsort/bsearch/... */
8705 static int
8706 pstrcmp(const void *a, const void *b)
8708 return strcmp((char*)a, *(char**)b);
8711 static const char *const *
8712 findkwd(const char *s)
8714 return bsearch(s, tokname_array + KWDOFFSET,
8715 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8716 sizeof(tokname_array[0]), pstrcmp);
8720 * Locate and print what a word is...
8722 static int
8723 describe_command(char *command, const char *path, int describe_command_verbose)
8725 struct cmdentry entry;
8726 #if ENABLE_ASH_ALIAS
8727 const struct alias *ap;
8728 #endif
8730 if (describe_command_verbose) {
8731 out1str(command);
8734 /* First look at the keywords */
8735 if (findkwd(command)) {
8736 out1str(describe_command_verbose ? " is a shell keyword" : command);
8737 goto out;
8740 #if ENABLE_ASH_ALIAS
8741 /* Then look at the aliases */
8742 ap = lookupalias(command, 0);
8743 if (ap != NULL) {
8744 if (!describe_command_verbose) {
8745 out1str("alias ");
8746 printalias(ap);
8747 return 0;
8749 out1fmt(" is an alias for %s", ap->val);
8750 goto out;
8752 #endif
8753 /* Brute force */
8754 path = path ? path : pathval();
8755 find_command(command, &entry, DO_ABS, path);
8757 switch (entry.cmdtype) {
8758 case CMDNORMAL: {
8759 int j = entry.u.index;
8760 char *p;
8761 if (j < 0) {
8762 p = command;
8763 } else {
8764 do {
8765 padvance(&path, command);
8766 } while (--j >= 0);
8767 p = stackblock();
8769 if (describe_command_verbose) {
8770 out1fmt(" is %s", p);
8771 } else {
8772 out1str(p);
8774 break;
8777 case CMDFUNCTION:
8778 if (describe_command_verbose) {
8779 /*out1str(" is a shell function");*/
8780 out1str(" is a function"); /* bash says this */
8781 } else {
8782 out1str(command);
8784 break;
8786 case CMDBUILTIN:
8787 if (describe_command_verbose) {
8788 out1fmt(" is a %sshell builtin",
8789 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8790 "special " : nullstr
8792 } else {
8793 out1str(command);
8795 break;
8797 default:
8798 if (describe_command_verbose) {
8799 out1str(": not found\n");
8801 return 127;
8803 out:
8804 out1str("\n");
8805 return 0;
8808 static int FAST_FUNC
8809 typecmd(int argc UNUSED_PARAM, char **argv)
8811 int i = 1;
8812 int err = 0;
8813 int verbose = 1;
8815 /* type -p ... ? (we don't bother checking for 'p') */
8816 if (argv[1] && argv[1][0] == '-') {
8817 i++;
8818 verbose = 0;
8820 while (argv[i]) {
8821 err |= describe_command(argv[i++], NULL, verbose);
8823 return err;
8826 static struct strlist *
8827 fill_arglist(struct arglist *arglist, union node **argpp)
8829 struct strlist **lastp = arglist->lastp;
8830 union node *argp;
8832 while ((argp = *argpp) != NULL) {
8833 expandarg(argp, arglist, EXP_FULL | EXP_TILDE);
8834 *argpp = argp->narg.next;
8835 if (*lastp)
8836 break;
8839 return *lastp;
8842 #if ENABLE_ASH_CMDCMD
8843 /* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8844 static int
8845 parse_command_args(struct arglist *arglist, union node **argpp, const char **path)
8847 struct strlist *sp = arglist->list;
8848 char *cp, c;
8850 for (;;) {
8851 sp = sp->next ? sp->next : fill_arglist(arglist, argpp);
8852 if (!sp)
8853 return 0;
8854 cp = sp->text;
8855 if (*cp++ != '-')
8856 break;
8857 c = *cp++;
8858 if (!c)
8859 break;
8860 if (c == '-' && !*cp) {
8861 if (!sp->next && !fill_arglist(arglist, argpp))
8862 return 0;
8863 sp = sp->next;
8864 break;
8866 do {
8867 switch (c) {
8868 case 'p':
8869 *path = bb_default_path;
8870 break;
8871 default:
8872 /* run 'typecmd' for other options */
8873 return 0;
8875 c = *cp++;
8876 } while (c);
8879 arglist->list = sp;
8880 return DO_NOFUNC;
8883 static int FAST_FUNC
8884 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8886 char *cmd;
8887 int c;
8888 enum {
8889 VERIFY_BRIEF = 1,
8890 VERIFY_VERBOSE = 2,
8891 } verify = 0;
8892 const char *path = NULL;
8894 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8895 * never reaches this function.
8898 while ((c = nextopt("pvV")) != '\0')
8899 if (c == 'V')
8900 verify |= VERIFY_VERBOSE;
8901 else if (c == 'v')
8902 /*verify |= VERIFY_BRIEF*/;
8903 #if DEBUG
8904 else if (c != 'p')
8905 abort();
8906 #endif
8907 else
8908 path = bb_default_path;
8910 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8911 cmd = *argptr;
8912 if (/*verify && */ cmd)
8913 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8915 return 0;
8917 #endif
8920 /*static int funcblocksize; // size of structures in function */
8921 /*static int funcstringsize; // size of strings in node */
8922 static void *funcblock; /* block to allocate function from */
8923 static char *funcstring_end; /* end of block to allocate strings from */
8925 static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8926 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8927 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8928 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8929 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8930 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8931 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8932 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8933 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8934 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8935 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8936 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8937 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8938 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8939 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8940 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8941 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8942 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8943 #if BASH_REDIR_OUTPUT
8944 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
8945 #endif
8946 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8947 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8948 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8949 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8950 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8951 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8952 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8953 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8954 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8957 static int calcsize(int funcblocksize, union node *n);
8959 static int
8960 sizenodelist(int funcblocksize, struct nodelist *lp)
8962 while (lp) {
8963 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8964 funcblocksize = calcsize(funcblocksize, lp->n);
8965 lp = lp->next;
8967 return funcblocksize;
8970 static int
8971 calcsize(int funcblocksize, union node *n)
8973 if (n == NULL)
8974 return funcblocksize;
8975 funcblocksize += nodesize[n->type];
8976 switch (n->type) {
8977 case NCMD:
8978 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8979 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8980 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8981 break;
8982 case NPIPE:
8983 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8984 break;
8985 case NREDIR:
8986 case NBACKGND:
8987 case NSUBSHELL:
8988 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8989 funcblocksize = calcsize(funcblocksize, n->nredir.n);
8990 break;
8991 case NAND:
8992 case NOR:
8993 case NSEMI:
8994 case NWHILE:
8995 case NUNTIL:
8996 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8997 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
8998 break;
8999 case NIF:
9000 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
9001 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
9002 funcblocksize = calcsize(funcblocksize, n->nif.test);
9003 break;
9004 case NFOR:
9005 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
9006 funcblocksize = calcsize(funcblocksize, n->nfor.body);
9007 funcblocksize = calcsize(funcblocksize, n->nfor.args);
9008 break;
9009 case NCASE:
9010 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
9011 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
9012 break;
9013 case NCLIST:
9014 funcblocksize = calcsize(funcblocksize, n->nclist.body);
9015 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
9016 funcblocksize = calcsize(funcblocksize, n->nclist.next);
9017 break;
9018 case NDEFUN:
9019 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
9020 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
9021 break;
9022 case NARG:
9023 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
9024 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
9025 funcblocksize = calcsize(funcblocksize, n->narg.next);
9026 break;
9027 case NTO:
9028 #if BASH_REDIR_OUTPUT
9029 case NTO2:
9030 #endif
9031 case NCLOBBER:
9032 case NFROM:
9033 case NFROMTO:
9034 case NAPPEND:
9035 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
9036 funcblocksize = calcsize(funcblocksize, n->nfile.next);
9037 break;
9038 case NTOFD:
9039 case NFROMFD:
9040 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
9041 funcblocksize = calcsize(funcblocksize, n->ndup.next);
9042 break;
9043 case NHERE:
9044 case NXHERE:
9045 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
9046 funcblocksize = calcsize(funcblocksize, n->nhere.next);
9047 break;
9048 case NNOT:
9049 funcblocksize = calcsize(funcblocksize, n->nnot.com);
9050 break;
9052 return funcblocksize;
9055 static char *
9056 nodeckstrdup(char *s)
9058 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
9059 return strcpy(funcstring_end, s);
9062 static union node *copynode(union node *);
9064 static struct nodelist *
9065 copynodelist(struct nodelist *lp)
9067 struct nodelist *start;
9068 struct nodelist **lpp;
9070 lpp = &start;
9071 while (lp) {
9072 *lpp = funcblock;
9073 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
9074 (*lpp)->n = copynode(lp->n);
9075 lp = lp->next;
9076 lpp = &(*lpp)->next;
9078 *lpp = NULL;
9079 return start;
9082 static union node *
9083 copynode(union node *n)
9085 union node *new;
9087 if (n == NULL)
9088 return NULL;
9089 new = funcblock;
9090 funcblock = (char *) funcblock + nodesize[n->type];
9092 switch (n->type) {
9093 case NCMD:
9094 new->ncmd.redirect = copynode(n->ncmd.redirect);
9095 new->ncmd.args = copynode(n->ncmd.args);
9096 new->ncmd.assign = copynode(n->ncmd.assign);
9097 new->ncmd.linno = n->ncmd.linno;
9098 break;
9099 case NPIPE:
9100 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
9101 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
9102 break;
9103 case NREDIR:
9104 case NBACKGND:
9105 case NSUBSHELL:
9106 new->nredir.redirect = copynode(n->nredir.redirect);
9107 new->nredir.n = copynode(n->nredir.n);
9108 new->nredir.linno = n->nredir.linno;
9109 break;
9110 case NAND:
9111 case NOR:
9112 case NSEMI:
9113 case NWHILE:
9114 case NUNTIL:
9115 new->nbinary.ch2 = copynode(n->nbinary.ch2);
9116 new->nbinary.ch1 = copynode(n->nbinary.ch1);
9117 break;
9118 case NIF:
9119 new->nif.elsepart = copynode(n->nif.elsepart);
9120 new->nif.ifpart = copynode(n->nif.ifpart);
9121 new->nif.test = copynode(n->nif.test);
9122 break;
9123 case NFOR:
9124 new->nfor.var = nodeckstrdup(n->nfor.var);
9125 new->nfor.body = copynode(n->nfor.body);
9126 new->nfor.args = copynode(n->nfor.args);
9127 new->nfor.linno = n->nfor.linno;
9128 break;
9129 case NCASE:
9130 new->ncase.cases = copynode(n->ncase.cases);
9131 new->ncase.expr = copynode(n->ncase.expr);
9132 new->ncase.linno = n->ncase.linno;
9133 break;
9134 case NCLIST:
9135 new->nclist.body = copynode(n->nclist.body);
9136 new->nclist.pattern = copynode(n->nclist.pattern);
9137 new->nclist.next = copynode(n->nclist.next);
9138 break;
9139 case NDEFUN:
9140 new->ndefun.body = copynode(n->ndefun.body);
9141 new->ndefun.text = nodeckstrdup(n->ndefun.text);
9142 new->ndefun.linno = n->ndefun.linno;
9143 break;
9144 case NARG:
9145 new->narg.backquote = copynodelist(n->narg.backquote);
9146 new->narg.text = nodeckstrdup(n->narg.text);
9147 new->narg.next = copynode(n->narg.next);
9148 break;
9149 case NTO:
9150 #if BASH_REDIR_OUTPUT
9151 case NTO2:
9152 #endif
9153 case NCLOBBER:
9154 case NFROM:
9155 case NFROMTO:
9156 case NAPPEND:
9157 new->nfile.fname = copynode(n->nfile.fname);
9158 new->nfile.fd = n->nfile.fd;
9159 new->nfile.next = copynode(n->nfile.next);
9160 break;
9161 case NTOFD:
9162 case NFROMFD:
9163 new->ndup.vname = copynode(n->ndup.vname);
9164 new->ndup.dupfd = n->ndup.dupfd;
9165 new->ndup.fd = n->ndup.fd;
9166 new->ndup.next = copynode(n->ndup.next);
9167 break;
9168 case NHERE:
9169 case NXHERE:
9170 new->nhere.doc = copynode(n->nhere.doc);
9171 new->nhere.fd = n->nhere.fd;
9172 new->nhere.next = copynode(n->nhere.next);
9173 break;
9174 case NNOT:
9175 new->nnot.com = copynode(n->nnot.com);
9176 break;
9178 new->type = n->type;
9179 return new;
9183 * Make a copy of a parse tree.
9185 static struct funcnode *
9186 copyfunc(union node *n)
9188 struct funcnode *f;
9189 size_t blocksize;
9191 /*funcstringsize = 0;*/
9192 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
9193 f = ckzalloc(blocksize /* + funcstringsize */);
9194 funcblock = (char *) f + offsetof(struct funcnode, n);
9195 funcstring_end = (char *) f + blocksize;
9196 copynode(n);
9197 /* f->count = 0; - ckzalloc did it */
9198 return f;
9202 * Define a shell function.
9204 static void
9205 defun(union node *func)
9207 struct cmdentry entry;
9209 INT_OFF;
9210 entry.cmdtype = CMDFUNCTION;
9211 entry.u.func = copyfunc(func);
9212 addcmdentry(func->ndefun.text, &entry);
9213 INT_ON;
9216 /* Reasons for skipping commands (see comment on breakcmd routine) */
9217 #define SKIPBREAK (1 << 0)
9218 #define SKIPCONT (1 << 1)
9219 #define SKIPFUNC (1 << 2)
9220 #define SKIPFUNCDEF (1 << 3)
9221 static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
9222 static int skipcount; /* number of levels to skip */
9223 static int loopnest; /* current loop nesting level */
9224 static int funcline; /* starting line number of current function, or 0 if not in a function */
9226 /* Forward decl way out to parsing code - dotrap needs it */
9227 static int evalstring(char *s, int flags);
9229 /* Called to execute a trap.
9230 * Single callsite - at the end of evaltree().
9231 * If we return non-zero, evaltree raises EXEXIT exception.
9233 * Perhaps we should avoid entering new trap handlers
9234 * while we are executing a trap handler. [is it a TODO?]
9236 static void
9237 dotrap(void)
9239 uint8_t *g;
9240 int sig;
9241 int status, last_status;
9243 if (!pending_sig)
9244 return;
9246 status = savestatus;
9247 last_status = status;
9248 if (status < 0) {
9249 status = exitstatus;
9250 savestatus = status;
9252 pending_sig = 0;
9253 barrier();
9255 TRACE(("dotrap entered\n"));
9256 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
9257 char *p;
9259 if (!*g)
9260 continue;
9262 if (evalskip) {
9263 pending_sig = sig;
9264 break;
9267 p = trap[sig];
9268 /* non-trapped SIGINT is handled separately by raise_interrupt,
9269 * don't upset it by resetting gotsig[SIGINT-1] */
9270 if (sig == SIGINT && !p)
9271 continue;
9273 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
9274 *g = 0;
9275 if (!p)
9276 continue;
9277 trap_depth++;
9278 evalstring(p, 0);
9279 trap_depth--;
9280 if (evalskip != SKIPFUNC)
9281 exitstatus = status;
9284 savestatus = last_status;
9285 TRACE(("dotrap returns\n"));
9288 /* forward declarations - evaluation is fairly recursive business... */
9289 static int evalloop(union node *, int);
9290 static int evalfor(union node *, int);
9291 static int evalcase(union node *, int);
9292 static int evalsubshell(union node *, int);
9293 static void expredir(union node *);
9294 static int evalpipe(union node *, int);
9295 static int evalcommand(union node *, int);
9296 static int evalbltin(const struct builtincmd *, int, char **, int);
9297 static void prehash(union node *);
9300 * Evaluate a parse tree. The value is left in the global variable
9301 * exitstatus.
9303 static int
9304 evaltree(union node *n, int flags)
9306 int checkexit = 0;
9307 int (*evalfn)(union node *, int);
9308 struct stackmark smark;
9309 int status = 0;
9311 setstackmark(&smark);
9313 if (nflag)
9314 goto out;
9316 if (n == NULL) {
9317 TRACE(("evaltree(NULL) called\n"));
9318 goto out;
9320 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
9322 dotrap();
9324 switch (n->type) {
9325 default:
9326 #if DEBUG
9327 out1fmt("Node type = %d\n", n->type);
9328 fflush_all();
9329 break;
9330 #endif
9331 case NNOT:
9332 status = !evaltree(n->nnot.com, EV_TESTED);
9333 goto setstatus;
9334 case NREDIR:
9335 errlinno = lineno = n->nredir.linno;
9336 expredir(n->nredir.redirect);
9337 pushredir(n->nredir.redirect);
9338 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9339 if (!status) {
9340 status = evaltree(n->nredir.n, flags & EV_TESTED);
9342 if (n->nredir.redirect)
9343 popredir(/*drop:*/ 0);
9344 goto setstatus;
9345 case NCMD:
9346 evalfn = evalcommand;
9347 checkexit:
9348 checkexit = ~flags & EV_TESTED;
9349 goto calleval;
9350 case NFOR:
9351 evalfn = evalfor;
9352 goto calleval;
9353 case NWHILE:
9354 case NUNTIL:
9355 evalfn = evalloop;
9356 goto calleval;
9357 case NSUBSHELL:
9358 case NBACKGND:
9359 evalfn = evalsubshell;
9360 goto checkexit;
9361 case NPIPE:
9362 evalfn = evalpipe;
9363 goto checkexit;
9364 case NCASE:
9365 evalfn = evalcase;
9366 goto calleval;
9367 case NAND:
9368 case NOR:
9369 case NSEMI: {
9370 #if NAND + 1 != NOR
9371 #error NAND + 1 != NOR
9372 #endif
9373 #if NOR + 1 != NSEMI
9374 #error NOR + 1 != NSEMI
9375 #endif
9376 unsigned is_or = n->type - NAND;
9377 status = evaltree(
9378 n->nbinary.ch1,
9379 (flags | ((is_or >> 1) - 1)) & EV_TESTED
9381 if ((!status) == is_or || evalskip)
9382 break;
9383 n = n->nbinary.ch2;
9384 evaln:
9385 evalfn = evaltree;
9386 calleval:
9387 status = evalfn(n, flags);
9388 goto setstatus;
9390 case NIF:
9391 status = evaltree(n->nif.test, EV_TESTED);
9392 if (evalskip)
9393 break;
9394 if (!status) {
9395 n = n->nif.ifpart;
9396 goto evaln;
9397 } else if (n->nif.elsepart) {
9398 n = n->nif.elsepart;
9399 goto evaln;
9401 status = 0;
9402 goto setstatus;
9403 case NDEFUN:
9404 defun(n);
9405 /* Not necessary. To test it:
9406 * "false; f() { qwerty; }; echo $?" should print 0.
9408 /* status = 0; */
9409 setstatus:
9410 exitstatus = status;
9411 break;
9413 out:
9414 /* Order of checks below is important:
9415 * signal handlers trigger before exit caused by "set -e".
9417 dotrap();
9419 if (checkexit && status) {
9420 if (trap[NTRAP_ERR] && !in_trap_ERR) {
9421 int err;
9422 struct jmploc *volatile savehandler = exception_handler;
9423 struct jmploc jmploc;
9425 in_trap_ERR = 1;
9426 trap_depth++;
9427 err = setjmp(jmploc.loc);
9428 if (!err) {
9429 exception_handler = &jmploc;
9430 savestatus = exitstatus;
9431 evalstring(trap[NTRAP_ERR], 0);
9433 trap_depth--;
9434 in_trap_ERR = 0;
9436 exception_handler = savehandler;
9437 if (err && exception_type != EXERROR)
9438 longjmp(exception_handler->loc, 1);
9440 exitstatus = savestatus;
9442 if (eflag)
9443 goto exexit;
9445 if (flags & EV_EXIT) {
9446 exexit:
9447 raise_exception(EXEND); /* does not return */
9450 popstackmark(&smark);
9451 TRACE(("leaving evaltree (no interrupts)\n"));
9452 return exitstatus;
9455 static int
9456 skiploop(void)
9458 int skip = evalskip;
9460 switch (skip) {
9461 case 0:
9462 break;
9463 case SKIPBREAK:
9464 case SKIPCONT:
9465 if (--skipcount <= 0) {
9466 evalskip = 0;
9467 break;
9469 skip = SKIPBREAK;
9470 break;
9472 return skip;
9475 static int
9476 evalloop(union node *n, int flags)
9478 int skip;
9479 int status;
9481 loopnest++;
9482 status = 0;
9483 flags &= EV_TESTED;
9484 do {
9485 int i;
9487 i = evaltree(n->nbinary.ch1, EV_TESTED);
9488 skip = skiploop();
9489 if (skip == SKIPFUNC)
9490 status = i;
9491 if (skip)
9492 continue;
9493 if (n->type != NWHILE)
9494 i = !i;
9495 if (i != 0)
9496 break;
9497 status = evaltree(n->nbinary.ch2, flags);
9498 skip = skiploop();
9499 } while (!(skip & ~SKIPCONT));
9500 loopnest--;
9502 return status;
9505 static int
9506 evalfor(union node *n, int flags)
9508 struct arglist arglist;
9509 union node *argp;
9510 struct strlist *sp;
9511 int status = 0;
9513 errlinno = lineno = n->ncase.linno;
9515 arglist.list = NULL;
9516 arglist.lastp = &arglist.list;
9517 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
9518 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9520 *arglist.lastp = NULL;
9522 loopnest++;
9523 flags &= EV_TESTED;
9524 for (sp = arglist.list; sp; sp = sp->next) {
9525 setvar0(n->nfor.var, sp->text);
9526 status = evaltree(n->nfor.body, flags);
9527 if (skiploop() & ~SKIPCONT)
9528 break;
9530 loopnest--;
9532 return status;
9535 static int
9536 evalcase(union node *n, int flags)
9538 union node *cp;
9539 union node *patp;
9540 struct arglist arglist;
9541 int status = 0;
9543 errlinno = lineno = n->ncase.linno;
9545 arglist.list = NULL;
9546 arglist.lastp = &arglist.list;
9547 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
9548 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9549 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
9550 if (casematch(patp, arglist.list->text)) {
9551 /* Ensure body is non-empty as otherwise
9552 * EV_EXIT may prevent us from setting the
9553 * exit status.
9555 if (evalskip == 0 && cp->nclist.body) {
9556 status = evaltree(cp->nclist.body, flags);
9558 goto out;
9562 out:
9563 return status;
9567 * Kick off a subshell to evaluate a tree.
9569 static int
9570 evalsubshell(union node *n, int flags)
9572 struct job *jp;
9573 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9574 int status;
9576 errlinno = lineno = n->nredir.linno;
9578 expredir(n->nredir.redirect);
9579 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9580 goto nofork;
9581 INT_OFF;
9582 if (backgnd == FORK_FG)
9583 get_tty_state();
9584 jp = makejob(/*n,*/ 1);
9585 if (forkshell(jp, n, backgnd) == 0) {
9586 /* child */
9587 INT_ON;
9588 flags |= EV_EXIT;
9589 if (backgnd)
9590 flags &= ~EV_TESTED;
9591 nofork:
9592 redirect(n->nredir.redirect, 0);
9593 evaltreenr(n->nredir.n, flags);
9594 /* never returns */
9596 /* parent */
9597 status = 0;
9598 if (backgnd == FORK_FG)
9599 status = waitforjob(jp);
9600 INT_ON;
9601 return status;
9605 * Compute the names of the files in a redirection list.
9607 static void fixredir(union node *, const char *, int);
9608 static void
9609 expredir(union node *n)
9611 union node *redir;
9613 for (redir = n; redir; redir = redir->nfile.next) {
9614 struct arglist fn;
9616 fn.list = NULL;
9617 fn.lastp = &fn.list;
9618 switch (redir->type) {
9619 case NFROMTO:
9620 case NFROM:
9621 case NTO:
9622 #if BASH_REDIR_OUTPUT
9623 case NTO2:
9624 #endif
9625 case NCLOBBER:
9626 case NAPPEND:
9627 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
9628 TRACE(("expredir expanded to '%s'\n", fn.list->text));
9629 #if BASH_REDIR_OUTPUT
9630 store_expfname:
9631 #endif
9632 #if 0
9633 // By the design of stack allocator, the loop of this kind:
9634 // while true; do while true; do break; done </dev/null; done
9635 // will look like a memory leak: ash plans to free expfname's
9636 // of "/dev/null" as soon as it finishes running the loop
9637 // (in this case, never).
9638 // This "fix" is wrong:
9639 if (redir->nfile.expfname)
9640 stunalloc(redir->nfile.expfname);
9641 // It results in corrupted state of stacked allocations.
9642 #endif
9643 redir->nfile.expfname = fn.list->text;
9644 break;
9645 case NFROMFD:
9646 case NTOFD: /* >& */
9647 if (redir->ndup.vname) {
9648 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
9649 if (fn.list == NULL)
9650 ash_msg_and_raise_error("redir error");
9651 #if BASH_REDIR_OUTPUT
9652 if (!isdigit_str9(fn.list->text)) {
9653 /* >&file, not >&fd */
9654 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9655 ash_msg_and_raise_error("redir error");
9656 redir->type = NTO2;
9657 goto store_expfname;
9659 #endif
9660 fixredir(redir, fn.list->text, 1);
9662 break;
9668 * Evaluate a pipeline. All the processes in the pipeline are children
9669 * of the process creating the pipeline. (This differs from some versions
9670 * of the shell, which make the last process in a pipeline the parent
9671 * of all the rest.)
9673 static int
9674 evalpipe(union node *n, int flags)
9676 struct job *jp;
9677 struct nodelist *lp;
9678 int pipelen;
9679 int prevfd;
9680 int pip[2];
9681 int status = 0;
9683 TRACE(("evalpipe(0x%lx) called\n", (long)n));
9684 pipelen = 0;
9685 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
9686 pipelen++;
9687 flags |= EV_EXIT;
9688 INT_OFF;
9689 if (n->npipe.pipe_backgnd == 0)
9690 get_tty_state();
9691 jp = makejob(/*n,*/ pipelen);
9692 prevfd = -1;
9693 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
9694 prehash(lp->n);
9695 pip[1] = -1;
9696 if (lp->next) {
9697 if (pipe(pip) < 0) {
9698 close(prevfd);
9699 ash_msg_and_raise_perror("can't create pipe");
9702 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9703 /* child */
9704 INT_ON;
9705 if (pip[1] >= 0) {
9706 close(pip[0]);
9708 if (prevfd > 0) {
9709 dup2(prevfd, 0);
9710 close(prevfd);
9712 if (pip[1] > 1) {
9713 dup2(pip[1], 1);
9714 close(pip[1]);
9716 evaltreenr(lp->n, flags);
9717 /* never returns */
9719 /* parent */
9720 if (prevfd >= 0)
9721 close(prevfd);
9722 prevfd = pip[0];
9723 /* Don't want to trigger debugging */
9724 if (pip[1] != -1)
9725 close(pip[1]);
9727 if (n->npipe.pipe_backgnd == 0) {
9728 status = waitforjob(jp);
9729 TRACE(("evalpipe: job done exit status %d\n", status));
9731 INT_ON;
9733 return status;
9736 /* setinteractive needs this forward reference */
9737 #if ENABLE_FEATURE_TAB_COMPLETION
9738 static const char *ash_command_name(int i) FAST_FUNC;
9739 #endif
9742 * Controls whether the shell is interactive or not.
9744 static void
9745 setinteractive(int on)
9747 static smallint is_interactive;
9749 if (++on == is_interactive)
9750 return;
9751 is_interactive = on;
9752 setsignal(SIGINT);
9753 setsignal(SIGQUIT);
9754 setsignal(SIGTERM);
9755 if (is_interactive > 1) {
9756 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
9757 /* Looks like they want an interactive shell */
9758 static smallint did_banner;
9760 if (!did_banner) {
9761 /* note: ash and hush share this string */
9762 out1fmt("\n\n%s %s\n"
9763 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9764 "\n",
9765 bb_banner,
9766 "built-in shell (ash)"
9768 did_banner = 1;
9770 #endif
9771 #if ENABLE_FEATURE_EDITING
9772 if (!line_input_state) {
9773 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
9774 # if ENABLE_FEATURE_TAB_COMPLETION
9775 line_input_state->get_exe_name = ash_command_name;
9776 # endif
9777 # if EDITING_HAS_sh_get_var
9778 line_input_state->sh_get_var = lookupvar;
9779 # endif
9781 #endif
9785 static void
9786 optschanged(void)
9788 #if DEBUG
9789 opentrace();
9790 #endif
9791 setinteractive(iflag);
9792 setjobctl(mflag);
9793 #if ENABLE_FEATURE_EDITING_VI
9794 if (line_input_state) {
9795 if (viflag)
9796 line_input_state->flags |= VI_MODE;
9797 else
9798 line_input_state->flags &= ~VI_MODE;
9800 #else
9801 viflag = 0; /* forcibly keep the option off */
9802 #endif
9805 struct localvar_list {
9806 struct localvar_list *next;
9807 struct localvar *lv;
9810 static struct localvar_list *localvar_stack;
9813 * Called after a function returns.
9814 * Interrupts must be off.
9816 static void
9817 poplocalvars(int keep)
9819 struct localvar_list *ll;
9820 struct localvar *lvp, *next;
9821 struct var *vp;
9823 INT_OFF;
9824 ll = localvar_stack;
9825 localvar_stack = ll->next;
9827 next = ll->lv;
9828 free(ll);
9830 while ((lvp = next) != NULL) {
9831 next = lvp->next;
9832 vp = lvp->vp;
9833 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9834 if (keep) {
9835 int bits = VSTRFIXED;
9837 if (lvp->flags != VUNSET) {
9838 if (vp->var_text == lvp->text)
9839 bits |= VTEXTFIXED;
9840 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9841 free((char*)lvp->text);
9844 vp->flags &= ~bits;
9845 vp->flags |= (lvp->flags & bits);
9847 if ((vp->flags &
9848 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9849 unsetvar(vp->var_text);
9850 } else if (vp == NULL) { /* $- saved */
9851 memcpy(optlist, lvp->text, sizeof(optlist));
9852 free((char*)lvp->text);
9853 optschanged();
9854 } else if (lvp->flags == VUNSET) {
9855 vp->flags &= ~(VSTRFIXED|VREADONLY);
9856 unsetvar(vp->var_text);
9857 } else {
9858 if (vp->var_func)
9859 vp->var_func(var_end(lvp->text));
9860 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9861 free((char*)vp->var_text);
9862 vp->flags = lvp->flags;
9863 vp->var_text = lvp->text;
9865 free(lvp);
9867 INT_ON;
9871 * Create a new localvar environment.
9873 static struct localvar_list *
9874 pushlocalvars(int push)
9876 struct localvar_list *ll;
9877 struct localvar_list *top;
9879 top = localvar_stack;
9880 if (!push)
9881 goto out;
9883 INT_OFF;
9884 ll = ckzalloc(sizeof(*ll));
9885 /*ll->lv = NULL; - zalloc did it */
9886 ll->next = top;
9887 localvar_stack = ll;
9888 INT_ON;
9889 out:
9890 return top;
9893 static void
9894 unwindlocalvars(struct localvar_list *stop)
9896 while (localvar_stack != stop)
9897 poplocalvars(0);
9900 static int
9901 evalfun(struct funcnode *func, int argc, char **argv, int flags)
9903 volatile struct shparam saveparam;
9904 struct jmploc *volatile savehandler;
9905 struct jmploc jmploc;
9906 int e;
9907 int savelineno;
9908 int savefuncline;
9909 char *savefuncname;
9910 char *savetrap = NULL;
9912 if (!Eflag) {
9913 savetrap = trap[NTRAP_ERR];
9914 trap[NTRAP_ERR] = NULL;
9916 savelineno = lineno;
9917 saveparam = shellparam;
9918 savefuncline = funcline;
9919 savefuncname = funcname;
9920 savehandler = exception_handler;
9921 e = setjmp(jmploc.loc);
9922 if (e) {
9923 goto funcdone;
9925 INT_OFF;
9926 exception_handler = &jmploc;
9927 shellparam.malloced = 0;
9928 func->count++;
9929 funcname = func->n.ndefun.text;
9930 funcline = func->n.ndefun.linno;
9931 INT_ON;
9932 shellparam.nparam = argc - 1;
9933 shellparam.p = argv + 1;
9934 #if ENABLE_ASH_GETOPTS
9935 shellparam.optind = 1;
9936 shellparam.optoff = -1;
9937 #endif
9938 evaltree(func->n.ndefun.body, flags & EV_TESTED);
9939 funcdone:
9940 INT_OFF;
9941 funcname = savefuncname;
9942 if (savetrap) {
9943 if (!trap[NTRAP_ERR])
9944 trap[NTRAP_ERR] = savetrap;
9945 else
9946 free(savetrap);
9948 funcline = savefuncline;
9949 lineno = savelineno;
9950 freefunc(func);
9951 freeparam(&shellparam);
9952 shellparam = saveparam;
9953 exception_handler = savehandler;
9954 INT_ON;
9955 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
9956 return e;
9960 * Make a variable a local variable. When a variable is made local, it's
9961 * value and flags are saved in a localvar structure. The saved values
9962 * will be restored when the shell function returns. We handle the name
9963 * "-" as a special case: it makes changes to "set +-options" local
9964 * (options will be restored on return from the function).
9966 static void
9967 mklocal(char *name, int flags)
9969 struct localvar *lvp;
9970 struct var **vpp;
9971 struct var *vp;
9972 char *eq = strchr(name, '=');
9974 INT_OFF;
9975 /* Cater for duplicate "local". Examples:
9976 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9977 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9979 lvp = localvar_stack->lv;
9980 while (lvp) {
9981 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9982 if (eq)
9983 setvareq(name, 0);
9984 /* else:
9985 * it's a duplicate "local VAR" declaration, do nothing
9987 goto ret;
9989 lvp = lvp->next;
9992 lvp = ckzalloc(sizeof(*lvp));
9993 if (LONE_DASH(name)) {
9994 char *p;
9995 p = ckmalloc(sizeof(optlist));
9996 lvp->text = memcpy(p, optlist, sizeof(optlist));
9997 vp = NULL;
9998 } else {
9999 vpp = hashvar(name);
10000 vp = *findvar(vpp, name);
10001 if (vp == NULL) {
10002 /* variable did not exist yet */
10003 if (eq)
10004 vp = setvareq(name, VSTRFIXED | flags);
10005 else
10006 vp = setvar(name, NULL, VSTRFIXED | flags);
10007 lvp->flags = VUNSET;
10008 } else {
10009 lvp->text = vp->var_text;
10010 lvp->flags = vp->flags;
10011 /* make sure neither "struct var" nor string gets freed
10012 * during (un)setting:
10014 vp->flags |= VSTRFIXED|VTEXTFIXED;
10015 if (eq)
10016 setvareq(name, flags);
10017 else
10018 /* "local VAR" unsets VAR: */
10019 unsetvar(name);
10022 lvp->vp = vp;
10023 lvp->next = localvar_stack->lv;
10024 localvar_stack->lv = lvp;
10025 ret:
10026 INT_ON;
10030 * The "local" command.
10032 static int FAST_FUNC
10033 localcmd(int argc UNUSED_PARAM, char **argv)
10035 char *name;
10037 if (!localvar_stack)
10038 ash_msg_and_raise_error("not in a function");
10040 argv = argptr;
10041 while ((name = *argv++) != NULL) {
10042 mklocal(name, 0);
10044 return 0;
10047 static int FAST_FUNC
10048 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10050 return 1;
10053 static int FAST_FUNC
10054 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10056 return 0;
10059 static int FAST_FUNC
10060 execcmd(int argc UNUSED_PARAM, char **argv)
10062 optionarg = NULL;
10063 while (nextopt("a:") != '\0')
10064 /* nextopt() sets optionarg to "-a ARGV0" */;
10066 argv = argptr;
10067 if (argv[0]) {
10068 char *prog;
10070 iflag = 0; /* exit on error */
10071 mflag = 0;
10072 optschanged();
10073 /* We should set up signals for "exec CMD"
10074 * the same way as for "CMD" without "exec".
10075 * But optschanged->setinteractive->setsignal
10076 * still thought we are a root shell. Therefore, for example,
10077 * SIGQUIT is still set to IGN. Fix it:
10079 shlvl++;
10080 setsignal(SIGQUIT);
10081 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
10082 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
10083 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
10085 prog = argv[0];
10086 if (optionarg)
10087 argv[0] = optionarg;
10088 shellexec(prog, argv, pathval(), 0);
10089 /* NOTREACHED */
10091 return 0;
10095 * The return command.
10097 static int FAST_FUNC
10098 returncmd(int argc UNUSED_PARAM, char **argv)
10100 int skip;
10101 int status;
10104 * If called outside a function, do what ksh does;
10105 * skip the rest of the file.
10107 if (argv[1]) {
10108 skip = SKIPFUNC;
10109 status = number(argv[1]);
10110 } else {
10111 skip = SKIPFUNCDEF;
10112 status = exitstatus;
10114 evalskip = skip;
10116 return status;
10119 /* Forward declarations for builtintab[] */
10120 static int breakcmd(int, char **) FAST_FUNC;
10121 static int dotcmd(int, char **) FAST_FUNC;
10122 static int evalcmd(int, char **, int) FAST_FUNC;
10123 static int exitcmd(int, char **) FAST_FUNC;
10124 static int exportcmd(int, char **) FAST_FUNC;
10125 #if ENABLE_ASH_GETOPTS
10126 static int getoptscmd(int, char **) FAST_FUNC;
10127 #endif
10128 #if ENABLE_ASH_HELP
10129 static int helpcmd(int, char **) FAST_FUNC;
10130 #endif
10131 #if MAX_HISTORY
10132 static int historycmd(int, char **) FAST_FUNC;
10133 #endif
10134 #if ENABLE_FEATURE_SH_MATH
10135 static int letcmd(int, char **) FAST_FUNC;
10136 #endif
10137 static int readcmd(int, char **) FAST_FUNC;
10138 static int setcmd(int, char **) FAST_FUNC;
10139 static int shiftcmd(int, char **) FAST_FUNC;
10140 static int timescmd(int, char **) FAST_FUNC;
10141 static int trapcmd(int, char **) FAST_FUNC;
10142 static int umaskcmd(int, char **) FAST_FUNC;
10143 static int unsetcmd(int, char **) FAST_FUNC;
10144 static int ulimitcmd(int, char **) FAST_FUNC;
10146 #define BUILTIN_NOSPEC "0"
10147 #define BUILTIN_SPECIAL "1"
10148 #define BUILTIN_REGULAR "2"
10149 #define BUILTIN_SPEC_REG "3"
10150 #define BUILTIN_ASSIGN "4"
10151 #define BUILTIN_SPEC_ASSG "5"
10152 #define BUILTIN_REG_ASSG "6"
10153 #define BUILTIN_SPEC_REG_ASSG "7"
10155 /* Stubs for calling non-FAST_FUNC's */
10156 #if ENABLE_ASH_ECHO
10157 static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
10158 #endif
10159 #if ENABLE_ASH_PRINTF
10160 static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
10161 #endif
10162 #if ENABLE_ASH_TEST || BASH_TEST2
10163 static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
10164 #endif
10165 #if ENABLE_ASH_SLEEP
10166 static int FAST_FUNC sleepcmd(int argc, char **argv) { return sleep_main(argc, argv); }
10167 #endif
10169 /* Keep these in proper order since it is searched via bsearch() */
10170 static const struct builtincmd builtintab[] = {
10171 { BUILTIN_SPEC_REG "." , dotcmd },
10172 { BUILTIN_SPEC_REG ":" , truecmd },
10173 #if ENABLE_ASH_TEST
10174 { BUILTIN_REGULAR "[" , testcmd },
10175 #endif
10176 #if BASH_TEST2
10177 { BUILTIN_REGULAR "[[" , testcmd },
10178 #endif
10179 #if ENABLE_ASH_ALIAS
10180 { BUILTIN_REG_ASSG "alias" , aliascmd },
10181 #endif
10182 #if JOBS
10183 { BUILTIN_REGULAR "bg" , fg_bgcmd },
10184 #endif
10185 { BUILTIN_SPEC_REG "break" , breakcmd },
10186 { BUILTIN_REGULAR "cd" , cdcmd },
10187 { BUILTIN_NOSPEC "chdir" , cdcmd },
10188 #if ENABLE_ASH_CMDCMD
10189 { BUILTIN_REGULAR "command" , commandcmd },
10190 #endif
10191 { BUILTIN_SPEC_REG "continue", breakcmd },
10192 #if ENABLE_ASH_ECHO
10193 { BUILTIN_REGULAR "echo" , echocmd },
10194 #endif
10195 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
10196 { BUILTIN_SPEC_REG "exec" , execcmd },
10197 { BUILTIN_SPEC_REG "exit" , exitcmd },
10198 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
10199 { BUILTIN_REGULAR "false" , falsecmd },
10200 #if JOBS
10201 { BUILTIN_REGULAR "fg" , fg_bgcmd },
10202 #endif
10203 #if ENABLE_ASH_GETOPTS
10204 { BUILTIN_REGULAR "getopts" , getoptscmd },
10205 #endif
10206 { BUILTIN_REGULAR "hash" , hashcmd },
10207 #if ENABLE_ASH_HELP
10208 { BUILTIN_NOSPEC "help" , helpcmd },
10209 #endif
10210 #if MAX_HISTORY
10211 { BUILTIN_NOSPEC "history" , historycmd },
10212 #endif
10213 #if JOBS
10214 { BUILTIN_REGULAR "jobs" , jobscmd },
10215 { BUILTIN_REGULAR "kill" , killcmd },
10216 #endif
10217 #if ENABLE_FEATURE_SH_MATH
10218 { BUILTIN_NOSPEC "let" , letcmd },
10219 #endif
10220 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
10221 #if ENABLE_ASH_PRINTF
10222 { BUILTIN_REGULAR "printf" , printfcmd },
10223 #endif
10224 { BUILTIN_REGULAR "pwd" , pwdcmd },
10225 { BUILTIN_REGULAR "read" , readcmd },
10226 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
10227 { BUILTIN_SPEC_REG "return" , returncmd },
10228 { BUILTIN_SPEC_REG "set" , setcmd },
10229 { BUILTIN_SPEC_REG "shift" , shiftcmd },
10230 #if ENABLE_ASH_SLEEP
10231 { BUILTIN_REGULAR "sleep" , sleepcmd },
10232 #endif
10233 #if BASH_SOURCE
10234 { BUILTIN_SPEC_REG "source" , dotcmd },
10235 #endif
10236 #if ENABLE_ASH_TEST
10237 { BUILTIN_REGULAR "test" , testcmd },
10238 #endif
10239 { BUILTIN_SPEC_REG "times" , timescmd },
10240 { BUILTIN_SPEC_REG "trap" , trapcmd },
10241 { BUILTIN_REGULAR "true" , truecmd },
10242 { BUILTIN_REGULAR "type" , typecmd },
10243 { BUILTIN_REGULAR "ulimit" , ulimitcmd },
10244 { BUILTIN_REGULAR "umask" , umaskcmd },
10245 #if ENABLE_ASH_ALIAS
10246 { BUILTIN_REGULAR "unalias" , unaliascmd },
10247 #endif
10248 { BUILTIN_SPEC_REG "unset" , unsetcmd },
10249 { BUILTIN_REGULAR "wait" , waitcmd },
10252 /* Should match the above table! */
10253 #define COMMANDCMD (builtintab + \
10254 /* . : */ 2 + \
10255 /* [ */ 1 * ENABLE_ASH_TEST + \
10256 /* [[ */ 1 * BASH_TEST2 + \
10257 /* alias */ 1 * ENABLE_ASH_ALIAS + \
10258 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
10259 /* break cd cddir */ 3)
10260 #define EVALCMD (COMMANDCMD + \
10261 /* command */ 1 * ENABLE_ASH_CMDCMD + \
10262 /* continue */ 1 + \
10263 /* echo */ 1 * ENABLE_ASH_ECHO + \
10265 #define EXECCMD (EVALCMD + \
10266 /* eval */ 1)
10269 * Search the table of builtin commands.
10271 static int
10272 pstrcmp1(const void *a, const void *b)
10274 return strcmp((char*)a, *(char**)b + 1);
10276 static struct builtincmd *
10277 find_builtin(const char *name)
10279 struct builtincmd *bp;
10281 bp = bsearch(
10282 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
10283 pstrcmp1
10285 return bp;
10288 #if ENABLE_FEATURE_TAB_COMPLETION
10289 static const char * FAST_FUNC
10290 ash_command_name(int i)
10292 int n;
10294 if (/*i >= 0 &&*/ i < ARRAY_SIZE(builtintab))
10295 return builtintab[i].name + 1;
10296 i -= ARRAY_SIZE(builtintab);
10298 for (n = 0; n < CMDTABLESIZE; n++) {
10299 struct tblentry *cmdp;
10300 for (cmdp = cmdtable[n]; cmdp; cmdp = cmdp->next) {
10301 if (cmdp->cmdtype == CMDFUNCTION && --i < 0)
10302 return cmdp->cmdname;
10306 # if ENABLE_ASH_ALIAS
10307 for (n = 0; n < ATABSIZE; n++) {
10308 struct alias *ap;
10309 for (ap = atab[n]; ap; ap = ap->next) {
10310 if (--i < 0)
10311 return ap->name;
10314 #endif
10316 return NULL;
10318 #endif
10321 * Execute a simple command.
10323 static void unwindfiles(struct parsefile *stop);
10324 static int
10325 isassignment(const char *p)
10327 const char *q = endofname(p);
10328 if (p == q)
10329 return 0;
10330 return *q == '=';
10332 static int FAST_FUNC
10333 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10335 /* Preserve exitstatus of a previous possible redirection
10336 * as POSIX mandates */
10337 return back_exitstatus;
10339 static int
10340 evalcommand(union node *cmd, int flags)
10342 static const struct builtincmd null_bltin = {
10343 BUILTIN_REGULAR "", bltincmd
10345 struct localvar_list *localvar_stop;
10346 struct parsefile *file_stop;
10347 struct redirtab *redir_stop;
10348 union node *argp;
10349 struct arglist arglist;
10350 struct arglist varlist;
10351 char **argv;
10352 int argc;
10353 struct strlist *osp;
10354 const struct strlist *sp;
10355 struct cmdentry cmdentry;
10356 struct job *jp;
10357 char *lastarg;
10358 const char *path;
10359 int spclbltin;
10360 int cmd_flag;
10361 int status;
10362 char **nargv;
10363 smallint cmd_is_exec;
10364 int vflags;
10365 int vlocal;
10367 errlinno = lineno = cmd->ncmd.linno;
10369 /* First expand the arguments. */
10370 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
10371 #if BASH_PROCESS_SUBST
10372 redir_stop = redirlist;
10373 #endif
10374 file_stop = g_parsefile;
10375 back_exitstatus = 0;
10377 cmdentry.cmdtype = CMDBUILTIN;
10378 cmdentry.u.cmd = &null_bltin;
10379 varlist.lastp = &varlist.list;
10380 *varlist.lastp = NULL;
10381 arglist.lastp = &arglist.list;
10382 *arglist.lastp = NULL;
10384 cmd_flag = 0;
10385 cmd_is_exec = 0;
10386 spclbltin = -1;
10387 vflags = 0;
10388 vlocal = 0;
10389 path = NULL;
10391 argc = 0;
10392 argp = cmd->ncmd.args;
10393 osp = fill_arglist(&arglist, &argp);
10394 if (osp) {
10395 int pseudovarflag = 0;
10397 for (;;) {
10398 find_command(arglist.list->text, &cmdentry,
10399 cmd_flag | DO_REGBLTIN, pathval());
10401 vlocal++;
10403 /* implement bltin and command here */
10404 if (cmdentry.cmdtype != CMDBUILTIN)
10405 break;
10407 pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
10408 if (spclbltin < 0) {
10409 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10410 vlocal = !spclbltin;
10412 cmd_is_exec = cmdentry.u.cmd == EXECCMD;
10413 #if ENABLE_ASH_CMDCMD
10414 if (cmdentry.u.cmd != COMMANDCMD)
10415 break;
10417 cmd_flag = parse_command_args(&arglist, &argp, &path);
10418 if (!cmd_flag)
10419 #endif
10420 break;
10423 for (; argp; argp = argp->narg.next)
10424 expandarg(argp, &arglist,
10425 pseudovarflag &&
10426 isassignment(argp->narg.text) ?
10427 EXP_VARTILDE : EXP_FULL | EXP_TILDE);
10429 for (sp = arglist.list; sp; sp = sp->next)
10430 argc++;
10432 if (cmd_is_exec && argc > 1)
10433 vflags = VEXPORT;
10436 localvar_stop = pushlocalvars(vlocal);
10438 /* Reserve one extra spot at the front for shellexec. */
10439 nargv = stalloc(sizeof(char *) * (argc + 2));
10440 argv = ++nargv;
10441 for (sp = arglist.list; sp; sp = sp->next) {
10442 TRACE(("evalcommand arg: %s\n", sp->text));
10443 *nargv++ = sp->text;
10445 *nargv = NULL;
10447 lastarg = NULL;
10448 if (iflag && funcline == 0 && argc > 0)
10449 lastarg = nargv[-1];
10451 expredir(cmd->ncmd.redirect);
10452 #if !BASH_PROCESS_SUBST
10453 redir_stop = pushredir(cmd->ncmd.redirect);
10454 #else
10455 pushredir(cmd->ncmd.redirect);
10456 #endif
10457 preverrout_fd = 2;
10458 if (BASH_XTRACEFD && xflag) {
10459 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10460 * we do not emulate this. We only use its value.
10462 const char *xtracefd = lookupvar("BASH_XTRACEFD");
10463 if (xtracefd && is_number(xtracefd))
10464 preverrout_fd = atoi(xtracefd);
10467 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10469 if (status) {
10470 bail:
10471 exitstatus = status;
10473 /* We have a redirection error. */
10474 if (spclbltin > 0)
10475 raise_exception(EXERROR); /* does not return */
10477 goto out;
10480 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10481 struct strlist **spp;
10483 spp = varlist.lastp;
10484 expandarg(argp, &varlist, EXP_VARTILDE);
10486 if (vlocal)
10487 mklocal((*spp)->text, VEXPORT);
10488 else
10489 setvareq((*spp)->text, vflags);
10492 /* Print the command if xflag is set. */
10493 if (xflag && !inps4) {
10494 const char *pfx = "";
10496 inps4 = 1;
10497 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
10498 inps4 = 0;
10500 sp = varlist.list;
10501 while (sp) {
10502 char *varval = sp->text;
10503 char *eq = strchrnul(varval, '=');
10504 if (*eq)
10505 eq++;
10506 fdprintf(preverrout_fd, "%s%.*s%s",
10507 pfx,
10508 (int)(eq - varval), varval,
10509 maybe_single_quote(eq)
10511 sp = sp->next;
10512 pfx = " ";
10515 sp = arglist.list;
10516 while (sp) {
10517 fdprintf(preverrout_fd, "%s%s",
10518 pfx,
10519 /* always quote if matches reserved word: */
10520 findkwd(sp->text)
10521 ? single_quote(sp->text)
10522 : maybe_single_quote(sp->text)
10524 sp = sp->next;
10525 pfx = " ";
10527 safe_write(preverrout_fd, "\n", 1);
10530 /* Now locate the command. */
10531 if (cmdentry.cmdtype != CMDBUILTIN
10532 || !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
10534 path = path ? path : pathval();
10535 find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path);
10538 jp = NULL;
10540 /* Execute the command. */
10541 switch (cmdentry.cmdtype) {
10542 case CMDUNKNOWN:
10543 status = 127;
10544 flush_stdout_stderr();
10545 goto bail;
10547 default: {
10549 #if ENABLE_FEATURE_SH_STANDALONE \
10550 && ENABLE_FEATURE_SH_NOFORK \
10551 && NUM_APPLETS > 1
10552 /* (1) BUG: if variables are set, we need to fork, or save/restore them
10553 * around run_nofork_applet() call.
10554 * (2) Should this check also be done in forkshell()?
10555 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10557 /* find_command() encodes applet_no as (-2 - applet_no) */
10558 int applet_no = (- cmdentry.u.index - 2);
10559 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10560 char **sv_environ;
10562 INT_OFF;
10563 sv_environ = environ;
10564 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
10566 * Run <applet>_main().
10567 * Signals (^C) can't interrupt here.
10568 * Otherwise we can mangle stdio or malloc internal state.
10569 * This makes applets which can run for a long time
10570 * and/or wait for user input ineligible for NOFORK:
10571 * for example, "yes" or "rm" (rm -i waits for input).
10573 exitstatus = run_nofork_applet(applet_no, argv);
10574 environ = sv_environ;
10576 * Try enabling NOFORK for "yes" applet.
10577 * ^C _will_ stop it (write returns EINTR),
10578 * but this causes stdout FILE to be stuck
10579 * and needing clearerr(). What if other applets
10580 * also can get EINTRs? Do we need to switch
10581 * our signals to SA_RESTART?
10583 /*clearerr(stdout);*/
10584 INT_ON;
10585 break;
10587 #endif
10588 /* Can we avoid forking? For example, very last command
10589 * in a script or a subshell does not need forking,
10590 * we can just exec it.
10592 if (!(flags & EV_EXIT) || may_have_traps) {
10593 /* No, forking off a child is necessary */
10594 INT_OFF;
10595 get_tty_state();
10596 jp = makejob(/*cmd,*/ 1);
10597 if (forkshell(jp, cmd, FORK_FG) != 0) {
10598 /* parent */
10599 break;
10601 /* child */
10602 FORCE_INT_ON;
10603 /* fall through to exec'ing external program */
10605 shellexec(argv[0], argv, path, cmdentry.u.index);
10606 /* NOTREACHED */
10607 } /* default */
10608 case CMDBUILTIN:
10609 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
10610 && !(exception_type == EXERROR && spclbltin <= 0)
10612 raise:
10613 longjmp(exception_handler->loc, 1);
10615 break;
10617 case CMDFUNCTION:
10618 if (evalfun(cmdentry.u.func, argc, argv, flags))
10619 goto raise;
10620 break;
10621 } /* switch */
10623 status = waitforjob(jp);
10624 if (jp)
10625 TRACE(("forked child exited with %d\n", status));
10626 FORCE_INT_ON;
10628 out:
10629 if (cmd->ncmd.redirect)
10630 popredir(/*drop:*/ cmd_is_exec);
10631 unwindredir(redir_stop);
10632 unwindfiles(file_stop);
10633 unwindlocalvars(localvar_stop);
10634 if (lastarg) {
10635 /* dsl: I think this is intended to be used to support
10636 * '_' in 'vi' command mode during line editing...
10637 * However I implemented that within libedit itself.
10639 setvar0("_", lastarg);
10642 return status;
10645 static int
10646 evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
10648 char *volatile savecmdname;
10649 struct jmploc *volatile savehandler;
10650 struct jmploc jmploc;
10651 int status;
10652 int i;
10654 savecmdname = commandname;
10655 savehandler = exception_handler;
10656 i = setjmp(jmploc.loc);
10657 if (i)
10658 goto cmddone;
10659 exception_handler = &jmploc;
10660 commandname = argv[0];
10661 argptr = argv + 1;
10662 optptr = NULL; /* initialize nextopt */
10663 if (cmd == EVALCMD)
10664 status = evalcmd(argc, argv, flags);
10665 else
10666 status = (*cmd->builtin)(argc, argv);
10667 flush_stdout_stderr();
10668 status |= ferror(stdout);
10669 exitstatus = status;
10670 cmddone:
10671 clearerr(stdout);
10672 commandname = savecmdname;
10673 exception_handler = savehandler;
10675 return i;
10678 static int
10679 goodname(const char *p)
10681 return endofname(p)[0] == '\0';
10686 * Search for a command. This is called before we fork so that the
10687 * location of the command will be available in the parent as well as
10688 * the child. The check for "goodname" is an overly conservative
10689 * check that the name will not be subject to expansion.
10691 static void
10692 prehash(union node *n)
10694 struct cmdentry entry;
10696 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10697 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
10701 /* ============ Builtin commands
10703 * Builtin commands whose functions are closely tied to evaluation
10704 * are implemented here.
10708 * Handle break and continue commands. Break, continue, and return are
10709 * all handled by setting the evalskip flag. The evaluation routines
10710 * above all check this flag, and if it is set they start skipping
10711 * commands rather than executing them. The variable skipcount is
10712 * the number of loops to break/continue, or the number of function
10713 * levels to return. (The latter is always 1.) It should probably
10714 * be an error to break out of more loops than exist, but it isn't
10715 * in the standard shell so we don't make it one here.
10717 static int FAST_FUNC
10718 breakcmd(int argc UNUSED_PARAM, char **argv)
10720 int n = argv[1] ? number(argv[1]) : 1;
10722 if (n <= 0)
10723 ash_msg_and_raise_error(msg_illnum, argv[1]);
10724 if (n > loopnest)
10725 n = loopnest;
10726 if (n > 0) {
10727 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
10728 skipcount = n;
10730 return 0;
10735 * This implements the input routines used by the parser.
10738 enum {
10739 INPUT_PUSH_FILE = 1,
10740 INPUT_NOFILE_OK = 2,
10743 static smallint checkkwd;
10744 /* values of checkkwd variable */
10745 #define CHKALIAS 0x1
10746 #define CHKKWD 0x2
10747 #define CHKNL 0x4
10748 #define CHKEOFMARK 0x8
10751 * Push a string back onto the input at this current parsefile level.
10752 * We handle aliases this way.
10754 #if !ENABLE_ASH_ALIAS
10755 #define pushstring(s, ap) pushstring(s)
10756 #endif
10757 static void
10758 pushstring(char *s, struct alias *ap)
10760 struct strpush *sp;
10761 int len;
10763 len = strlen(s);
10764 INT_OFF;
10765 if (g_parsefile->strpush || g_parsefile->spfree) {
10766 sp = ckzalloc(sizeof(*sp));
10767 sp->prev = g_parsefile->strpush;
10768 } else {
10769 sp = &(g_parsefile->basestrpush);
10771 g_parsefile->strpush = sp;
10772 sp->prev_string = g_parsefile->next_to_pgetc;
10773 sp->prev_left_in_line = g_parsefile->left_in_line;
10774 sp->unget = g_parsefile->unget;
10775 sp->spfree = g_parsefile->spfree;
10776 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
10777 #if ENABLE_ASH_ALIAS
10778 sp->ap = ap;
10779 if (ap) {
10780 ap->flag |= ALIASINUSE;
10781 sp->string = s;
10783 #endif
10784 g_parsefile->next_to_pgetc = s;
10785 g_parsefile->left_in_line = len;
10786 g_parsefile->unget = 0;
10787 g_parsefile->spfree = NULL;
10788 INT_ON;
10791 static void popstring(void)
10793 struct strpush *sp = g_parsefile->strpush;
10795 INT_OFF;
10796 #if ENABLE_ASH_ALIAS
10797 if (sp->ap) {
10798 if (g_parsefile->next_to_pgetc[-1] == ' '
10799 || g_parsefile->next_to_pgetc[-1] == '\t'
10801 checkkwd |= CHKALIAS;
10803 if (sp->string != sp->ap->val) {
10804 free(sp->string);
10807 #endif
10808 g_parsefile->next_to_pgetc = sp->prev_string;
10809 g_parsefile->left_in_line = sp->prev_left_in_line;
10810 g_parsefile->unget = sp->unget;
10811 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
10812 g_parsefile->strpush = sp->prev;
10813 g_parsefile->spfree = sp;
10814 INT_ON;
10817 static int
10818 preadfd(void)
10820 int nr;
10821 char *buf = g_parsefile->buf;
10823 g_parsefile->next_to_pgetc = buf;
10824 #if ENABLE_FEATURE_EDITING
10825 /* retry: */
10826 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10827 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10828 else {
10829 # if ENABLE_ASH_IDLE_TIMEOUT
10830 int timeout = -1;
10831 const char *tmout_var = lookupvar("TMOUT");
10832 if (tmout_var) {
10833 timeout = atoi(tmout_var) * 1000;
10834 if (timeout <= 0)
10835 timeout = -1;
10837 line_input_state->timeout = timeout;
10838 # endif
10839 # if ENABLE_FEATURE_TAB_COMPLETION
10840 line_input_state->path_lookup = pathval();
10841 # endif
10842 reinit_unicode_for_ash();
10843 again:
10844 /* For shell, LI_INTERRUPTIBLE is set:
10845 * read_line_input will abort on either
10846 * getting EINTR in poll() and bb_got_signal became != 0,
10847 * or if it sees bb_got_signal != 0
10848 * (IOW: if signal arrives before poll() is reached).
10849 * Interactive testcases:
10850 * (while kill -INT $$; do sleep 1; done) &
10851 * #^^^ prints ^C, prints prompt, repeats
10852 * trap 'echo I' int; (while kill -INT $$; do sleep 1; done) &
10853 * #^^^ prints ^C, prints "I", prints prompt, repeats
10854 * trap 'echo T' term; (while kill $$; do sleep 1; done) &
10855 * #^^^ prints "T", prints prompt, repeats
10856 * #(bash 5.0.17 exits after first "T", looks like a bug)
10858 bb_got_signal = 0;
10859 INT_OFF; /* no longjmp'ing out of read_line_input please */
10860 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10861 if (bb_got_signal == SIGINT)
10862 write(STDOUT_FILENO, "^C\n", 3);
10863 INT_ON; /* here non-blocked SIGINT will longjmp */
10864 if (nr == 0) {
10865 /* ^C pressed, "convert" to SIGINT */
10866 write(STDOUT_FILENO, "^C\n", 3);
10867 raise(SIGINT); /* here non-blocked SIGINT will longjmp */
10868 /* raise(SIGINT) did not work! (e.g. if SIGINT
10869 * is SIG_IGNed on startup, it stays SIG_IGNed)
10871 if (trap[SIGINT]) {
10872 empty_line_input:
10873 buf[0] = '\n';
10874 buf[1] = '\0';
10875 return 1;
10877 exitstatus = 128 + SIGINT;
10878 /* bash behavior on ^C + ignored SIGINT: */
10879 goto again;
10881 if (nr < 0) {
10882 if (errno == 0) {
10883 /* ^D pressed */
10884 nr = 0;
10886 else if (errno == EINTR) { /* got signal? */
10887 if (bb_got_signal != SIGINT)
10888 write(STDOUT_FILENO, "\n", 1);
10889 goto empty_line_input;
10891 # if ENABLE_ASH_IDLE_TIMEOUT
10892 else if (errno == EAGAIN && timeout > 0) {
10893 puts("\007timed out waiting for input: auto-logout");
10894 exitshell();
10896 # endif
10899 #else
10900 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10901 #endif
10903 #if 0 /* disabled: nonblock_immune_read() handles this problem */
10904 if (nr < 0) {
10905 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10906 int flags = fcntl(0, F_GETFL);
10907 if (flags >= 0 && (flags & O_NONBLOCK)) {
10908 flags &= ~O_NONBLOCK;
10909 if (fcntl(0, F_SETFL, flags) >= 0) {
10910 out2str("sh: turning off NDELAY mode\n");
10911 goto retry;
10916 #endif
10917 return nr;
10921 * Refill the input buffer and return the next input character:
10923 * 1) If a string was pushed back on the input, pop it;
10924 * 2) If we are reading from a string we can't refill the buffer, return EOF.
10925 * 3) If there is more stuff in this buffer, use it else call read to fill it.
10926 * 4) Process input up to the next newline, deleting nul characters.
10928 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10929 #define pgetc_debug(...) ((void)0)
10930 static int __pgetc(void);
10931 static int
10932 preadbuffer(void)
10934 char *q;
10935 int more;
10937 if (unlikely(g_parsefile->strpush)) {
10938 popstring();
10939 return __pgetc();
10942 if (g_parsefile->buf == NULL) {
10943 pgetc_debug("preadbuffer PEOF1");
10944 return PEOF;
10947 more = g_parsefile->left_in_buffer;
10948 if (more <= 0) {
10949 flush_stdout_stderr();
10950 again:
10951 more = preadfd();
10952 if (more <= 0) {
10953 g_parsefile->left_in_buffer = g_parsefile->left_in_line = 0;
10954 pgetc_debug("preadbuffer PEOF2");
10955 return PEOF;
10959 /* Find out where's the end of line.
10960 * Set g_parsefile->left_in_line
10961 * and g_parsefile->left_in_buffer acordingly.
10962 * NUL chars are deleted.
10964 q = g_parsefile->next_to_pgetc;
10965 for (;;) {
10966 char c;
10968 more--;
10970 c = *q;
10971 if (c == '\0') {
10972 memmove(q, q + 1, more);
10973 } else {
10974 q++;
10975 if (c == '\n') {
10976 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10977 break;
10981 if (more <= 0) {
10982 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10983 if (g_parsefile->left_in_line < 0)
10984 goto again;
10985 break;
10988 g_parsefile->left_in_buffer = more;
10990 if (vflag) {
10991 char save = *q;
10992 *q = '\0';
10993 out2str(g_parsefile->next_to_pgetc);
10994 *q = save;
10997 pgetc_debug("preadbuffer at %d:%p'%s'",
10998 g_parsefile->left_in_line,
10999 g_parsefile->next_to_pgetc,
11000 g_parsefile->next_to_pgetc);
11001 return (unsigned char)*g_parsefile->next_to_pgetc++;
11004 static void
11005 nlprompt(void)
11007 if (trap_depth == 0)
11008 g_parsefile->linno++;
11009 setprompt_if(doprompt, 2);
11011 static void
11012 nlnoprompt(void)
11014 if (trap_depth == 0)
11015 g_parsefile->linno++;
11016 needprompt = doprompt;
11019 static void freestrings(struct strpush *sp)
11021 INT_OFF;
11022 do {
11023 struct strpush *psp;
11024 #if ENABLE_ASH_ALIAS
11025 if (sp->ap) {
11026 sp->ap->flag &= ~ALIASINUSE;
11027 if (sp->ap->flag & ALIASDEAD) {
11028 unalias(sp->ap->name);
11031 #endif
11032 psp = sp;
11033 sp = sp->spfree;
11035 if (psp != &(g_parsefile->basestrpush))
11036 free(psp);
11037 } while (sp);
11039 g_parsefile->spfree = NULL;
11040 INT_ON;
11043 static int __pgetc(void)
11045 int c;
11047 pgetc_debug("pgetc at %d:%p'%s'",
11048 g_parsefile->left_in_line,
11049 g_parsefile->next_to_pgetc,
11050 g_parsefile->next_to_pgetc);
11051 if (g_parsefile->unget)
11052 return g_parsefile->lastc[--g_parsefile->unget];
11054 if (--g_parsefile->left_in_line >= 0)
11055 c = (unsigned char)*g_parsefile->next_to_pgetc++;
11056 else
11057 c = preadbuffer();
11059 g_parsefile->lastc[1] = g_parsefile->lastc[0];
11060 g_parsefile->lastc[0] = c;
11062 return c;
11066 * Read a character from the script, returning PEOF on end of file.
11067 * Nul characters in the input are silently discarded.
11069 static int pgetc(void)
11071 struct strpush *sp = g_parsefile->spfree;
11073 if (unlikely(sp))
11074 freestrings(sp);
11076 return __pgetc();
11080 * Undo a call to pgetc. Only two characters may be pushed back.
11081 * PEOF may be pushed back.
11083 static void
11084 pungetc(void)
11086 g_parsefile->unget++;
11089 /* This one eats backslash+newline */
11090 static int
11091 pgetc_eatbnl(void)
11093 int c;
11095 while ((c = pgetc()) == '\\') {
11096 if (pgetc() != '\n') {
11097 pungetc();
11098 break;
11101 nlprompt();
11104 return c;
11107 struct synstack {
11108 smalluint syntax;
11109 uint8_t innerdq :1;
11110 uint8_t varpushed :1;
11111 uint8_t dblquote :1;
11112 int varnest; /* levels of variables expansion */
11113 int dqvarnest; /* levels of variables expansion within double quotes */
11114 int parenlevel; /* levels of parens in arithmetic */
11115 struct synstack *prev;
11116 struct synstack *next;
11119 static int
11120 pgetc_top(struct synstack *stack)
11122 return stack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl();
11125 static void
11126 synstack_push(struct synstack **stack, struct synstack *next, int syntax)
11128 memset(next, 0, sizeof(*next));
11129 next->syntax = syntax;
11130 next->next = *stack;
11131 (*stack)->prev = next;
11132 *stack = next;
11135 static ALWAYS_INLINE void
11136 synstack_pop(struct synstack **stack)
11138 *stack = (*stack)->next;
11142 * To handle the "." command, a stack of input files is used. Pushfile
11143 * adds a new entry to the stack and popfile restores the previous level.
11145 static void
11146 pushfile(void)
11148 struct parsefile *pf;
11150 pf = ckzalloc(sizeof(*pf));
11151 pf->prev = g_parsefile;
11152 pf->pf_fd = -1;
11153 /*pf->strpush = NULL; - ckzalloc did it */
11154 /*pf->spfree = NULL;*/
11155 /*pf->basestrpush.prev = NULL;*/
11156 /*pf->unget = 0;*/
11157 g_parsefile = pf;
11160 static void
11161 popfile(void)
11163 struct parsefile *pf = g_parsefile;
11165 if (pf == &basepf)
11166 return;
11168 INT_OFF;
11169 if (pf->pf_fd >= 0)
11170 close(pf->pf_fd);
11171 free(pf->buf);
11172 if (g_parsefile->spfree)
11173 freestrings(g_parsefile->spfree);
11174 while (pf->strpush) {
11175 popstring();
11176 freestrings(g_parsefile->spfree);
11178 g_parsefile = pf->prev;
11179 free(pf);
11180 INT_ON;
11183 static void
11184 unwindfiles(struct parsefile *stop)
11186 while (g_parsefile != stop)
11187 popfile();
11191 * Return to top level.
11193 static void
11194 popallfiles(void)
11196 unwindfiles(&basepf);
11200 * Close the file(s) that the shell is reading commands from. Called
11201 * after a fork is done.
11203 static void
11204 closescript(void)
11206 popallfiles();
11207 if (g_parsefile->pf_fd > 0) {
11208 close(g_parsefile->pf_fd);
11209 g_parsefile->pf_fd = 0;
11214 * Like setinputfile, but takes an open file descriptor. Call this with
11215 * interrupts off.
11217 static void
11218 setinputfd(int fd, int push)
11220 if (push) {
11221 pushfile();
11222 g_parsefile->buf = NULL;
11224 g_parsefile->pf_fd = fd;
11225 if (g_parsefile->buf == NULL)
11226 g_parsefile->buf = ckmalloc(IBUFSIZ);
11227 g_parsefile->left_in_buffer = 0;
11228 g_parsefile->left_in_line = 0;
11229 g_parsefile->linno = 1;
11233 * Set the input to take input from a file. If push is set, push the
11234 * old input onto the stack first.
11236 static int
11237 setinputfile(const char *fname, int flags)
11239 int fd;
11241 INT_OFF;
11242 fd = open(fname, O_RDONLY | O_CLOEXEC);
11243 if (fd < 0) {
11244 if (flags & INPUT_NOFILE_OK)
11245 goto out;
11246 exitstatus = 127;
11247 ash_msg_and_raise_perror("can't open '%s'", fname);
11249 if (fd < 10)
11250 fd = savefd(fd);
11251 else if (O_CLOEXEC == 0) /* old libc */
11252 close_on_exec_on(fd);
11254 setinputfd(fd, flags & INPUT_PUSH_FILE);
11255 out:
11256 INT_ON;
11257 return fd;
11261 * Like setinputfile, but takes input from a string.
11263 static void
11264 setinputstring(char *string)
11266 INT_OFF;
11267 pushfile();
11268 g_parsefile->next_to_pgetc = string;
11269 g_parsefile->left_in_line = strlen(string);
11270 g_parsefile->buf = NULL;
11271 g_parsefile->linno = lineno;
11272 INT_ON;
11277 * Routines to check for mail.
11280 #if ENABLE_ASH_MAIL
11282 /* Hash of mtimes of mailboxes */
11283 /* Cleared to 0 if MAIL or MAILPATH is changed */
11284 static unsigned mailtime_hash;
11287 * Print appropriate message(s) if mail has arrived.
11288 * If mailtime_hash is zero,
11289 * then the value of MAIL has changed,
11290 * so we just update the hash value.
11292 static void
11293 chkmail(void)
11295 const char *mpath;
11296 char *p;
11297 char *q;
11298 unsigned new_hash;
11299 struct stackmark smark;
11300 struct stat statb;
11302 setstackmark(&smark);
11303 mpath = mpathset() ? mpathval() : mailval();
11304 new_hash = 0;
11305 for (;;) {
11306 int len;
11308 len = padvance_magic(&mpath, nullstr, 2);
11309 if (len < 0)
11310 break;
11311 p = stackblock();
11312 if (*p == '\0')
11313 continue;
11314 for (q = p; *q; q++)
11315 continue;
11316 #if DEBUG
11317 if (q[-1] != '/')
11318 abort();
11319 #endif
11320 q[-1] = '\0'; /* delete trailing '/' */
11321 if (stat(p, &statb) < 0) {
11322 continue;
11324 /* Very simplistic "hash": just a sum of all mtimes */
11325 new_hash += (unsigned)statb.st_mtime;
11327 if (mailtime_hash != new_hash) {
11328 if (mailtime_hash != 0)
11329 out2str("you have mail\n");
11330 mailtime_hash = new_hash;
11332 popstackmark(&smark);
11335 static void FAST_FUNC
11336 changemail(const char *val UNUSED_PARAM)
11338 mailtime_hash = 0;
11341 #else
11343 # define chkmail() ((void)0)
11345 #endif /* ASH_MAIL */
11348 /* ============ ??? */
11351 * Set the shell parameters.
11353 static void
11354 setparam(char **argv)
11356 char **newparam;
11357 char **ap;
11358 int nparam;
11360 for (nparam = 0; argv[nparam]; nparam++)
11361 continue;
11362 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
11363 while (*argv) {
11364 *ap++ = ckstrdup(*argv++);
11366 *ap = NULL;
11367 freeparam(&shellparam);
11368 shellparam.malloced = 1;
11369 shellparam.nparam = nparam;
11370 shellparam.p = newparam;
11371 #if ENABLE_ASH_GETOPTS
11372 shellparam.optind = 1;
11373 shellparam.optoff = -1;
11374 #endif
11378 * Process shell options. The global variable argptr contains a pointer
11379 * to the argument list; we advance it past the options.
11381 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
11382 * For a non-interactive shell, an error condition encountered
11383 * by a special built-in ... shall cause the shell to write a diagnostic message
11384 * to standard error and exit as shown in the following table:
11385 * Error Special Built-In
11386 * ...
11387 * Utility syntax error (option or operand error) Shall exit
11388 * ...
11389 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
11390 * we see that bash does not do that (set "finishes" with error code 1 instead,
11391 * and shell continues), and people rely on this behavior!
11392 * Testcase:
11393 * set -o barfoo 2>/dev/null
11394 * echo $?
11396 * Oh well. Let's mimic that.
11398 static int
11399 plus_minus_o(char *name, int val)
11401 int i;
11403 if (name) {
11404 for (i = 0; i < NOPTS; i++) {
11405 if (strcmp(name, optnames(i)) == 0) {
11406 optlist[i] = val;
11407 return 0;
11410 ash_msg("illegal option %co %s", val ? '-' : '+', name);
11411 return 1;
11413 for (i = 0; i < NOPTS; i++) {
11414 if (optnames(i)[0] == '\0')
11415 continue;
11416 if (val) {
11417 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11418 } else {
11419 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11422 return 0;
11424 static void
11425 setoption(int flag, int val)
11427 int i;
11429 for (i = 0; i < NOPTS; i++) {
11430 if (optletters(i) == flag && optnames(i)[0] != '\0') {
11431 optlist[i] = val;
11432 return;
11435 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
11436 /* NOTREACHED */
11438 /* If login_sh is not NULL, we are called to parse command line opts,
11439 * not "set -opts"
11441 static int
11442 options(int *login_sh)
11444 char *p;
11445 int val;
11446 int c;
11448 if (login_sh != NULL) /* if we came from startup code */
11449 minusc = NULL;
11450 while ((p = *argptr) != NULL) {
11451 c = *p++;
11452 if (c != '-' && c != '+')
11453 break;
11454 argptr++;
11455 val = 0; /* val = 0 if c == '+' */
11456 if (c == '-') {
11457 val = 1;
11458 if (p[0] == '\0' || LONE_DASH(p)) {
11459 if (login_sh == NULL) { /* we came from setcmd() */
11460 /* "-" means turn off -x and -v */
11461 if (p[0] == '\0')
11462 xflag = vflag = 0;
11463 /* "--" means reset params */
11464 else if (*argptr == NULL)
11465 setparam(argptr);
11467 break; /* "-" or "--" terminates options */
11470 /* first char was + or - */
11471 while ((c = *p++) != '\0') {
11472 if (login_sh != NULL) { /* if we came from startup code */
11473 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
11474 if (c == 'c') {
11475 minusc = p; /* command is after shell args */
11476 cflag = 1;
11477 continue;
11479 if (c == 's') { /* -s, +s */
11480 sflag = 1;
11481 continue;
11483 if (c == 'i') { /* -i, +i */
11484 iflag = 1;
11485 continue;
11487 if (c == 'l') {
11488 *login_sh = 1; /* -l or +l == --login */
11489 continue;
11491 /* bash does not accept +-login, we also won't */
11492 if (val && (c == '-')) { /* long options */
11493 if (strcmp(p, "login") == 0) {
11494 *login_sh = 1;
11496 /* TODO: --noprofile: e.g. if I want to run emergency shell from sulogin,
11497 * I want minimal/no shell init scripts - but it insists on running it as "-ash"...
11499 break;
11502 if (c == 'o') {
11503 if (plus_minus_o(*argptr, val)) {
11504 /* it already printed err message */
11505 return 1; /* error */
11507 if (*argptr)
11508 argptr++;
11509 } else {
11510 setoption(c, val);
11514 return 0;
11518 * The shift builtin command.
11520 static int FAST_FUNC
11521 shiftcmd(int argc UNUSED_PARAM, char **argv)
11523 int n;
11524 char **ap1, **ap2;
11526 n = 1;
11527 if (argv[1])
11528 n = number(argv[1]);
11529 if (n > shellparam.nparam)
11530 return 1;
11531 INT_OFF;
11532 shellparam.nparam -= n;
11533 for (ap1 = shellparam.p; --n >= 0; ap1++) {
11534 if (shellparam.malloced)
11535 free(*ap1);
11537 ap2 = shellparam.p;
11538 while ((*ap2++ = *ap1++) != NULL)
11539 continue;
11540 #if ENABLE_ASH_GETOPTS
11541 shellparam.optind = 1;
11542 shellparam.optoff = -1;
11543 #endif
11544 INT_ON;
11545 return 0;
11549 * POSIX requires that 'set' (but not export or readonly) output the
11550 * variables in lexicographic order - by the locale's collating order (sigh).
11551 * Maybe we could keep them in an ordered balanced binary tree
11552 * instead of hashed lists.
11553 * For now just roll 'em through qsort for printing...
11555 static int
11556 showvars(const char *sep_prefix, int on, int off)
11558 const char *sep;
11559 char **ep, **epend;
11561 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
11562 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11564 sep = *sep_prefix ? " " : sep_prefix;
11566 for (; ep < epend; ep++) {
11567 const char *p;
11568 const char *q;
11570 p = endofname(*ep);
11571 /* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11572 * makes "export -p" to have output not suitable for "eval":
11573 * import os
11574 * os.environ["test-test"]="test"
11575 * if os.fork() == 0:
11576 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11577 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11579 q = nullstr;
11580 if (*p == '=')
11581 q = single_quote(++p);
11582 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11584 return 0;
11588 * The set command builtin.
11590 static int FAST_FUNC
11591 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11593 int retval;
11595 if (!argv[1])
11596 return showvars(nullstr, 0, VUNSET);
11598 INT_OFF;
11599 retval = options(/*login_sh:*/ NULL);
11600 if (retval == 0) { /* if no parse error... */
11601 optschanged();
11602 if (*argptr != NULL) {
11603 setparam(argptr);
11606 INT_ON;
11607 return retval;
11610 #if ENABLE_ASH_RANDOM_SUPPORT
11611 static void FAST_FUNC
11612 change_random(const char *value)
11614 uint32_t t;
11616 if (value == NULL) {
11617 /* "get", generate */
11618 t = next_random(&random_gen);
11619 /* set without recursion */
11620 setvar(vrandom.var_text, utoa(t), VNOFUNC);
11621 vrandom.flags &= ~VNOFUNC;
11622 } else {
11623 /* set/reset */
11624 t = strtoul(value, NULL, 10);
11625 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
11628 #endif
11630 #if BASH_EPOCH_VARS
11631 static void FAST_FUNC
11632 change_epoch(struct var *vepoch, const char *fmt)
11634 struct timeval tv;
11635 char buffer[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
11637 xgettimeofday(&tv);
11638 sprintf(buffer, fmt, (unsigned long long)tv.tv_sec, (unsigned)tv.tv_usec);
11639 setvar(vepoch->var_text, buffer, VNOFUNC);
11640 vepoch->flags &= ~VNOFUNC;
11643 static void FAST_FUNC
11644 change_seconds(const char *value UNUSED_PARAM)
11646 change_epoch(&vepochs, "%llu");
11649 static void FAST_FUNC
11650 change_realtime(const char *value UNUSED_PARAM)
11652 change_epoch(&vepochr, "%llu.%06u");
11654 #endif
11656 #if ENABLE_ASH_GETOPTS
11657 static int
11658 getopts(char *optstr, char *optvar, char **optfirst)
11660 char *p, *q;
11661 char c = '?';
11662 int done = 0;
11663 char sbuf[2];
11664 char **optnext;
11665 int ind = shellparam.optind;
11666 int off = shellparam.optoff;
11668 sbuf[1] = '\0';
11670 shellparam.optind = -1;
11671 optnext = optfirst + ind - 1;
11673 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
11674 p = NULL;
11675 else
11676 p = optnext[-1] + off;
11677 if (p == NULL || *p == '\0') {
11678 /* Current word is done, advance */
11679 p = *optnext;
11680 if (p == NULL || *p != '-' || *++p == '\0') {
11681 atend:
11682 unsetvar("OPTARG");
11683 p = NULL;
11684 done = 1;
11685 goto out;
11687 optnext++;
11688 if (LONE_DASH(p)) /* check for "--" */
11689 goto atend;
11692 c = *p++;
11693 for (q = optstr; *q != c;) {
11694 if (*q == '\0') {
11695 /* OPTERR is a bashism */
11696 const char *cp = lookupvar("OPTERR");
11697 if ((cp && LONE_CHAR(cp, '0'))
11698 || (optstr[0] == ':')
11700 sbuf[0] = c;
11701 /*sbuf[1] = '\0'; - already is */
11702 setvar0("OPTARG", sbuf);
11703 } else {
11704 fprintf(stderr, "Illegal option -%c\n", c);
11705 unsetvar("OPTARG");
11707 c = '?';
11708 goto out;
11710 if (*++q == ':')
11711 q++;
11714 if (*++q == ':') {
11715 if (*p == '\0' && (p = *optnext) == NULL) {
11716 /* OPTERR is a bashism */
11717 const char *cp = lookupvar("OPTERR");
11718 if ((cp && LONE_CHAR(cp, '0'))
11719 || (optstr[0] == ':')
11721 sbuf[0] = c;
11722 /*sbuf[1] = '\0'; - already is */
11723 setvar0("OPTARG", sbuf);
11724 c = ':';
11725 } else {
11726 fprintf(stderr, "No arg for -%c option\n", c);
11727 unsetvar("OPTARG");
11728 c = '?';
11730 goto out;
11733 if (p == *optnext)
11734 optnext++;
11735 setvar0("OPTARG", p);
11736 p = NULL;
11737 } else
11738 setvar0("OPTARG", nullstr);
11739 out:
11740 ind = optnext - optfirst + 1;
11741 setvar("OPTIND", itoa(ind), VNOFUNC);
11742 sbuf[0] = c;
11743 /*sbuf[1] = '\0'; - already is */
11744 setvar0(optvar, sbuf);
11746 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11747 shellparam.optind = ind;
11749 return done;
11753 * The getopts builtin. Shellparam.optnext points to the next argument
11754 * to be processed. Shellparam.optptr points to the next character to
11755 * be processed in the current argument. If shellparam.optnext is NULL,
11756 * then it's the first time getopts has been called.
11758 static int FAST_FUNC
11759 getoptscmd(int argc, char **argv)
11761 char **optbase;
11763 if (argc < 3)
11764 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
11765 if (argc == 3) {
11766 optbase = shellparam.p;
11767 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
11768 shellparam.optind = 1;
11769 shellparam.optoff = -1;
11771 } else {
11772 optbase = &argv[3];
11773 if ((unsigned)shellparam.optind > argc - 2) {
11774 shellparam.optind = 1;
11775 shellparam.optoff = -1;
11779 return getopts(argv[1], argv[2], optbase);
11781 #endif /* ASH_GETOPTS */
11784 /* ============ Shell parser */
11786 struct heredoc {
11787 struct heredoc *next; /* next here document in list */
11788 union node *here; /* redirection node */
11789 char *eofmark; /* string indicating end of input */
11790 smallint striptabs; /* if set, strip leading tabs */
11793 static smallint tokpushback; /* last token pushed back */
11794 static smallint quoteflag; /* set if (part of) last token was quoted */
11795 static token_id_t lasttoken; /* last token read (integer id Txxx) */
11796 static struct heredoc *heredoclist; /* list of here documents to read */
11797 static char *wordtext; /* text of last word returned by readtoken */
11798 static struct nodelist *backquotelist;
11799 static union node *redirnode;
11800 static struct heredoc *heredoc;
11802 static const char *
11803 tokname(char *buf, int tok)
11805 if (tok < TSEMI)
11806 return tokname_array[tok];
11807 sprintf(buf, "\"%s\"", tokname_array[tok]);
11808 return buf;
11811 /* raise_error_unexpected_syntax:
11812 * Called when an unexpected token is read during the parse. The argument
11813 * is the token that is expected, or -1 if more than one type of token can
11814 * occur at this point.
11816 static void raise_error_unexpected_syntax(int) NORETURN;
11817 static void
11818 raise_error_unexpected_syntax(int token)
11820 char msg[64];
11821 char buf[16];
11822 int l;
11824 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
11825 if (token >= 0)
11826 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
11827 raise_error_syntax(msg);
11828 /* NOTREACHED */
11831 /* parsing is heavily cross-recursive, need these forward decls */
11832 static union node *andor(void);
11833 static union node *pipeline(void);
11834 static union node *parse_command(void);
11835 static void parseheredoc(void);
11836 static int readtoken(void);
11838 static union node *
11839 list(int nlflag)
11841 int chknl = nlflag & 1 ? 0 : CHKNL;
11842 union node *n1, *n2, *n3;
11843 int tok;
11845 n1 = NULL;
11846 for (;;) {
11847 checkkwd = chknl | CHKKWD | CHKALIAS;
11848 tok = readtoken();
11849 switch (tok) {
11850 case TNL:
11851 parseheredoc();
11852 return n1;
11854 case TEOF:
11855 if (!n1 && !chknl)
11856 n1 = NODE_EOF;
11857 out_eof:
11858 parseheredoc();
11859 tokpushback++;
11860 lasttoken = TEOF;
11861 return n1;
11864 tokpushback++;
11865 if (nlflag == 2 && ((1 << tok) & tokendlist))
11866 return n1;
11867 nlflag |= 2;
11869 n2 = andor();
11870 tok = readtoken();
11871 if (tok == TBACKGND) {
11872 if (n2->type == NPIPE) {
11873 n2->npipe.pipe_backgnd = 1;
11874 } else {
11875 if (n2->type != NREDIR) {
11876 n3 = stzalloc(sizeof(struct nredir));
11877 n3->nredir.n = n2;
11878 /*n3->nredir.redirect = NULL; - stzalloc did it */
11879 n2 = n3;
11881 n2->type = NBACKGND;
11884 if (n1 == NULL) {
11885 n1 = n2;
11886 } else {
11887 n3 = stzalloc(sizeof(struct nbinary));
11888 n3->type = NSEMI;
11889 n3->nbinary.ch1 = n1;
11890 n3->nbinary.ch2 = n2;
11891 n1 = n3;
11893 switch (tok) {
11894 case TEOF:
11895 goto out_eof;
11896 case TNL:
11897 tokpushback = 1;
11898 /* fall through */
11899 case TBACKGND:
11900 case TSEMI:
11901 break;
11902 default:
11903 if (!chknl)
11904 raise_error_unexpected_syntax(-1);
11905 tokpushback = 1;
11906 return n1;
11911 static union node *
11912 andor(void)
11914 union node *n1, *n2, *n3;
11915 int t;
11917 n1 = pipeline();
11918 for (;;) {
11919 t = readtoken();
11920 if (t == TAND) {
11921 t = NAND;
11922 } else if (t == TOR) {
11923 t = NOR;
11924 } else {
11925 tokpushback = 1;
11926 return n1;
11928 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11929 n2 = pipeline();
11930 n3 = stzalloc(sizeof(struct nbinary));
11931 n3->type = t;
11932 n3->nbinary.ch1 = n1;
11933 n3->nbinary.ch2 = n2;
11934 n1 = n3;
11938 static union node *
11939 pipeline(void)
11941 union node *n1, *n2, *pipenode;
11942 struct nodelist *lp, *prev;
11943 int negate;
11945 negate = 0;
11946 TRACE(("pipeline: entered\n"));
11947 if (readtoken() == TNOT) {
11948 negate = !negate;
11949 checkkwd = CHKKWD | CHKALIAS;
11950 } else
11951 tokpushback = 1;
11952 n1 = parse_command();
11953 if (readtoken() == TPIPE) {
11954 pipenode = stzalloc(sizeof(struct npipe));
11955 pipenode->type = NPIPE;
11956 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
11957 lp = stzalloc(sizeof(struct nodelist));
11958 pipenode->npipe.cmdlist = lp;
11959 lp->n = n1;
11960 do {
11961 prev = lp;
11962 lp = stzalloc(sizeof(struct nodelist));
11963 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11964 lp->n = parse_command();
11965 prev->next = lp;
11966 } while (readtoken() == TPIPE);
11967 lp->next = NULL;
11968 n1 = pipenode;
11970 tokpushback = 1;
11971 if (negate) {
11972 n2 = stzalloc(sizeof(struct nnot));
11973 n2->type = NNOT;
11974 n2->nnot.com = n1;
11975 return n2;
11977 return n1;
11980 static union node *
11981 makename(void)
11983 union node *n;
11985 n = stzalloc(sizeof(struct narg));
11986 n->type = NARG;
11987 /*n->narg.next = NULL; - stzalloc did it */
11988 n->narg.text = wordtext;
11989 n->narg.backquote = backquotelist;
11990 return n;
11993 static void
11994 fixredir(union node *n, const char *text, int err)
11996 int fd;
11998 TRACE(("Fix redir %s %d\n", text, err));
11999 if (!err)
12000 n->ndup.vname = NULL;
12002 fd = bb_strtou(text, NULL, 10);
12003 if (!errno && fd >= 0)
12004 n->ndup.dupfd = fd;
12005 else if (LONE_DASH(text))
12006 n->ndup.dupfd = -1;
12007 else {
12008 if (err)
12009 raise_error_syntax("bad fd number");
12010 n->ndup.vname = makename();
12014 static void
12015 parsefname(void)
12017 union node *n = redirnode;
12019 if (n->type == NHERE)
12020 checkkwd = CHKEOFMARK;
12021 if (readtoken() != TWORD)
12022 raise_error_unexpected_syntax(-1);
12023 if (n->type == NHERE) {
12024 struct heredoc *here = heredoc;
12025 struct heredoc *p;
12027 if (quoteflag == 0)
12028 n->type = NXHERE;
12029 TRACE(("Here document %d\n", n->type));
12030 rmescapes(wordtext, 0, NULL);
12031 here->eofmark = wordtext;
12032 here->next = NULL;
12033 if (heredoclist == NULL)
12034 heredoclist = here;
12035 else {
12036 for (p = heredoclist; p->next; p = p->next)
12037 continue;
12038 p->next = here;
12040 } else if (n->type == NTOFD || n->type == NFROMFD) {
12041 fixredir(n, wordtext, 0);
12042 } else {
12043 n->nfile.fname = makename();
12047 static union node *
12048 simplecmd(void)
12050 union node *args, **app;
12051 union node *n = NULL;
12052 union node *vars, **vpp;
12053 union node **rpp, *redir;
12054 int savecheckkwd;
12055 int savelinno;
12056 #if BASH_TEST2
12057 smallint double_brackets_flag = 0;
12058 #endif
12059 IF_BASH_FUNCTION(smallint function_flag = 0;)
12061 args = NULL;
12062 app = &args;
12063 vars = NULL;
12064 vpp = &vars;
12065 redir = NULL;
12066 rpp = &redir;
12068 savecheckkwd = CHKALIAS;
12069 savelinno = g_parsefile->linno;
12070 for (;;) {
12071 int t;
12072 checkkwd = savecheckkwd;
12073 t = readtoken();
12074 switch (t) {
12075 #if BASH_FUNCTION
12076 case TFUNCTION:
12077 if (readtoken() != TWORD)
12078 raise_error_unexpected_syntax(TWORD);
12079 tokpushback = 1;
12080 function_flag = 1;
12081 break;
12082 #endif
12083 #if BASH_TEST2
12084 case TAND: /* "&&" */
12085 case TOR: /* "||" */
12086 if (!double_brackets_flag) {
12087 tokpushback = 1;
12088 goto out;
12090 /* pass "&&" or "||" to [[ ]] as literal args */
12091 wordtext = (char *) (t == TAND ? "&&" : "||");
12092 #endif
12093 case TWORD:
12094 n = stzalloc(sizeof(struct narg));
12095 n->type = NARG;
12096 /*n->narg.next = NULL; - stzalloc did it */
12097 n->narg.text = wordtext;
12098 #if BASH_TEST2
12099 if (strcmp("[[", wordtext) == 0)
12100 double_brackets_flag = 1;
12101 else if (strcmp("]]", wordtext) == 0)
12102 double_brackets_flag = 0;
12103 #endif
12104 n->narg.backquote = backquotelist;
12105 if (savecheckkwd && isassignment(wordtext)) {
12106 *vpp = n;
12107 vpp = &n->narg.next;
12108 } else {
12109 *app = n;
12110 app = &n->narg.next;
12111 savecheckkwd = 0;
12113 #if BASH_FUNCTION
12114 if (function_flag) {
12115 checkkwd = CHKNL | CHKKWD;
12116 t = readtoken();
12117 tokpushback = 1;
12118 switch (t) {
12119 case TBEGIN:
12120 case TIF:
12121 case TCASE:
12122 case TUNTIL:
12123 case TWHILE:
12124 case TFOR:
12125 goto do_func;
12126 case TLP:
12127 function_flag = 0;
12128 break;
12129 # if BASH_TEST2
12130 case TWORD:
12131 if (strcmp("[[", wordtext) == 0)
12132 goto do_func;
12133 /* fall through */
12134 # endif
12135 default:
12136 raise_error_unexpected_syntax(-1);
12139 #endif
12140 break;
12141 case TREDIR:
12142 *rpp = n = redirnode;
12143 rpp = &n->nfile.next;
12144 parsefname(); /* read name of redirection file */
12145 break;
12146 case TLP:
12147 IF_BASH_FUNCTION(do_func:)
12148 if (args && app == &args->narg.next
12149 && !vars && !redir
12151 // struct builtincmd *bcmd;
12152 // const char *name;
12154 /* We have a function */
12155 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
12156 raise_error_unexpected_syntax(TRP);
12157 //bash allows functions named "123", "..", "return"!
12158 // name = n->narg.text;
12159 // if (!goodname(name)
12160 // || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
12161 // ) {
12162 // raise_error_syntax("bad function name");
12163 // }
12164 n->type = NDEFUN;
12165 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12166 n->ndefun.text = n->narg.text;
12167 n->ndefun.linno = g_parsefile->linno;
12168 n->ndefun.body = parse_command();
12169 return n;
12171 IF_BASH_FUNCTION(function_flag = 0;)
12172 /* fall through */
12173 default:
12174 tokpushback = 1;
12175 goto out;
12178 out:
12179 *app = NULL;
12180 *vpp = NULL;
12181 *rpp = NULL;
12182 n = stzalloc(sizeof(struct ncmd));
12183 if (NCMD != 0)
12184 n->type = NCMD;
12185 n->ncmd.linno = savelinno;
12186 n->ncmd.args = args;
12187 n->ncmd.assign = vars;
12188 n->ncmd.redirect = redir;
12189 return n;
12192 static union node *
12193 parse_command(void)
12195 union node *n1, *n2;
12196 union node *ap, **app;
12197 union node *cp, **cpp;
12198 union node *redir, **rpp;
12199 union node **rpp2;
12200 int t;
12201 int savelinno;
12203 redir = NULL;
12204 rpp2 = &redir;
12206 savelinno = g_parsefile->linno;
12208 switch (readtoken()) {
12209 default:
12210 raise_error_unexpected_syntax(-1);
12211 /* NOTREACHED */
12212 case TIF:
12213 n1 = stzalloc(sizeof(struct nif));
12214 n1->type = NIF;
12215 n1->nif.test = list(0);
12216 if (readtoken() != TTHEN)
12217 raise_error_unexpected_syntax(TTHEN);
12218 n1->nif.ifpart = list(0);
12219 n2 = n1;
12220 while (readtoken() == TELIF) {
12221 n2->nif.elsepart = stzalloc(sizeof(struct nif));
12222 n2 = n2->nif.elsepart;
12223 n2->type = NIF;
12224 n2->nif.test = list(0);
12225 if (readtoken() != TTHEN)
12226 raise_error_unexpected_syntax(TTHEN);
12227 n2->nif.ifpart = list(0);
12229 if (lasttoken == TELSE)
12230 n2->nif.elsepart = list(0);
12231 else {
12232 n2->nif.elsepart = NULL;
12233 tokpushback = 1;
12235 t = TFI;
12236 break;
12237 case TWHILE:
12238 case TUNTIL: {
12239 int got;
12240 n1 = stzalloc(sizeof(struct nbinary));
12241 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
12242 n1->nbinary.ch1 = list(0);
12243 got = readtoken();
12244 if (got != TDO) {
12245 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
12246 got == TWORD ? wordtext : ""));
12247 raise_error_unexpected_syntax(TDO);
12249 n1->nbinary.ch2 = list(0);
12250 t = TDONE;
12251 break;
12253 case TFOR:
12254 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
12255 raise_error_syntax("bad for loop variable");
12256 n1 = stzalloc(sizeof(struct nfor));
12257 n1->type = NFOR;
12258 n1->nfor.linno = savelinno;
12259 n1->nfor.var = wordtext;
12260 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12261 if (readtoken() == TIN) {
12262 app = &ap;
12263 while (readtoken() == TWORD) {
12264 n2 = stzalloc(sizeof(struct narg));
12265 n2->type = NARG;
12266 /*n2->narg.next = NULL; - stzalloc did it */
12267 n2->narg.text = wordtext;
12268 n2->narg.backquote = backquotelist;
12269 *app = n2;
12270 app = &n2->narg.next;
12272 *app = NULL;
12273 n1->nfor.args = ap;
12274 if (lasttoken != TNL && lasttoken != TSEMI)
12275 raise_error_unexpected_syntax(-1);
12276 } else {
12277 n2 = stzalloc(sizeof(struct narg));
12278 n2->type = NARG;
12279 /*n2->narg.next = NULL; - stzalloc did it */
12280 n2->narg.text = (char *)dolatstr;
12281 /*n2->narg.backquote = NULL;*/
12282 n1->nfor.args = n2;
12284 * Newline or semicolon here is optional (but note
12285 * that the original Bourne shell only allowed NL).
12287 if (lasttoken != TSEMI)
12288 tokpushback = 1;
12290 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12291 if (readtoken() != TDO)
12292 raise_error_unexpected_syntax(TDO);
12293 n1->nfor.body = list(0);
12294 t = TDONE;
12295 break;
12296 case TCASE:
12297 n1 = stzalloc(sizeof(struct ncase));
12298 n1->type = NCASE;
12299 n1->ncase.linno = savelinno;
12300 if (readtoken() != TWORD)
12301 raise_error_unexpected_syntax(TWORD);
12302 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
12303 n2->type = NARG;
12304 /*n2->narg.next = NULL; - stzalloc did it */
12305 n2->narg.text = wordtext;
12306 n2->narg.backquote = backquotelist;
12307 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12308 if (readtoken() != TIN)
12309 raise_error_unexpected_syntax(TIN);
12310 cpp = &n1->ncase.cases;
12311 next_case:
12312 checkkwd = CHKNL | CHKKWD;
12313 t = readtoken();
12314 while (t != TESAC) {
12315 if (lasttoken == TLP)
12316 readtoken();
12317 *cpp = cp = stzalloc(sizeof(struct nclist));
12318 cp->type = NCLIST;
12319 app = &cp->nclist.pattern;
12320 for (;;) {
12321 *app = ap = stzalloc(sizeof(struct narg));
12322 ap->type = NARG;
12323 /*ap->narg.next = NULL; - stzalloc did it */
12324 ap->narg.text = wordtext;
12325 ap->narg.backquote = backquotelist;
12326 if (readtoken() != TPIPE)
12327 break;
12328 app = &ap->narg.next;
12329 readtoken();
12331 //ap->narg.next = NULL;
12332 if (lasttoken != TRP)
12333 raise_error_unexpected_syntax(TRP);
12334 cp->nclist.body = list(2);
12336 cpp = &cp->nclist.next;
12338 checkkwd = CHKNL | CHKKWD;
12339 t = readtoken();
12340 if (t != TESAC) {
12341 if (t != TENDCASE)
12342 raise_error_unexpected_syntax(TENDCASE);
12343 goto next_case;
12346 *cpp = NULL;
12347 goto redir;
12348 case TLP:
12349 n1 = stzalloc(sizeof(struct nredir));
12350 n1->type = NSUBSHELL;
12351 n1->nredir.linno = savelinno;
12352 n1->nredir.n = list(0);
12353 /*n1->nredir.redirect = NULL; - stzalloc did it */
12354 t = TRP;
12355 break;
12356 case TBEGIN:
12357 n1 = list(0);
12358 t = TEND;
12359 break;
12360 IF_BASH_FUNCTION(case TFUNCTION:)
12361 case TWORD:
12362 case TREDIR:
12363 tokpushback = 1;
12364 return simplecmd();
12367 if (readtoken() != t)
12368 raise_error_unexpected_syntax(t);
12370 redir:
12371 /* Now check for redirection which may follow command */
12372 checkkwd = CHKKWD | CHKALIAS;
12373 rpp = rpp2;
12374 while (readtoken() == TREDIR) {
12375 *rpp = n2 = redirnode;
12376 rpp = &n2->nfile.next;
12377 parsefname();
12379 tokpushback = 1;
12380 *rpp = NULL;
12381 if (redir) {
12382 if (n1->type != NSUBSHELL) {
12383 n2 = stzalloc(sizeof(struct nredir));
12384 n2->type = NREDIR;
12385 n2->nredir.linno = savelinno;
12386 n2->nredir.n = n1;
12387 n1 = n2;
12389 n1->nredir.redirect = redir;
12391 return n1;
12394 #if BASH_DOLLAR_SQUOTE
12395 static int
12396 decode_dollar_squote(void)
12398 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
12399 int c, cnt;
12400 char *p;
12401 char buf[4];
12403 c = pgetc();
12404 p = strchr(C_escapes, c);
12405 if (p) {
12406 buf[0] = c;
12407 p = buf;
12408 cnt = 3;
12409 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
12410 do {
12411 c = pgetc();
12412 *++p = c;
12413 } while ((unsigned char)(c - '0') <= 7 && --cnt);
12414 pungetc();
12415 } else if (c == 'x') { /* \xHH */
12416 do {
12417 c = pgetc();
12418 *++p = c;
12419 } while (isxdigit(c) && --cnt);
12420 pungetc();
12421 if (cnt == 3) { /* \x but next char is "bad" */
12422 c = 'x';
12423 goto unrecognized;
12425 } else { /* simple seq like \\ or \t */
12426 p++;
12428 *p = '\0';
12429 p = buf;
12430 c = bb_process_escape_sequence((void*)&p);
12431 } else { /* unrecognized "\z": print both chars unless ' or " */
12432 if (c != '\'' && c != '"') {
12433 unrecognized:
12434 c |= 0x100; /* "please encode \, then me" */
12437 return c;
12439 #endif
12441 /* Used by expandstr to get here-doc like behaviour. */
12442 #define FAKEEOFMARK ((char*)(uintptr_t)1)
12444 static ALWAYS_INLINE int
12445 realeofmark(const char *eofmark)
12447 return eofmark && eofmark != FAKEEOFMARK;
12451 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
12452 * is not NULL, read a here document. In the latter case, eofmark is the
12453 * word which marks the end of the document and striptabs is true if
12454 * leading tabs should be stripped from the document. The argument c
12455 * is the first character of the input token or document.
12457 * Because C does not have internal subroutines, I have simulated them
12458 * using goto's to implement the subroutine linkage. The following macros
12459 * will run code that appears at the end of readtoken1.
12461 #define CHECKEND() {goto checkend; checkend_return:;}
12462 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
12463 #define PARSESUB() {goto parsesub; parsesub_return:;}
12464 #define PARSEBACKQOLD() {style = OLD; goto parsebackq; parsebackq_oldreturn:;}
12465 #define PARSEBACKQNEW() {style = NEW; goto parsebackq; parsebackq_newreturn:;}
12466 #define PARSEPROCSUB() {style = PSUB; goto parsebackq; parsebackq_psreturn:;}
12467 #define PARSEARITH() {goto parsearith; parsearith_return:;}
12468 static int
12469 readtoken1(int c, int syntax, char *eofmark, int striptabs)
12471 /* NB: syntax parameter fits into smallint */
12472 /* c parameter is an unsigned char or PEOF */
12473 char *out;
12474 size_t len;
12475 struct nodelist *bqlist;
12476 smallint quotef;
12477 smallint style;
12478 enum { OLD, NEW, PSUB };
12479 #define oldstyle (style == OLD)
12480 smallint pssyntax; /* we are expanding a prompt string */
12481 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
12482 /* syntax stack */
12483 struct synstack synbase = { };
12484 struct synstack *synstack = &synbase;
12486 #if ENABLE_ASH_EXPAND_PRMT
12487 pssyntax = (syntax == PSSYNTAX);
12488 if (pssyntax)
12489 syntax = DQSYNTAX;
12490 #else
12491 pssyntax = 0; /* constant */
12492 #endif
12493 synstack->syntax = syntax;
12495 if (syntax == DQSYNTAX)
12496 synstack->dblquote = 1;
12497 quotef = 0;
12498 bqlist = NULL;
12500 STARTSTACKSTR(out);
12501 loop:
12502 /* For each line, until end of word */
12503 CHECKEND(); /* set c to PEOF if at end of here document */
12504 for (;;) { /* until end of line or end of word */
12505 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
12506 switch (SIT(c, synstack->syntax)) {
12507 case CNL: /* '\n' */
12508 if (synstack->syntax == BASESYNTAX
12509 && !synstack->varnest
12511 goto endword; /* exit outer loop */
12513 USTPUTC(c, out);
12514 nlprompt();
12515 c = pgetc_top(synstack);
12516 goto loop; /* continue outer loop */
12517 case CWORD:
12518 USTPUTC(c, out);
12519 break;
12520 case CCTL:
12521 #if BASH_DOLLAR_SQUOTE
12522 if (c == '\\' && bash_dollar_squote) {
12523 c = decode_dollar_squote();
12524 if (c == '\0') {
12525 /* skip $'\000', $'\x00' (like bash) */
12526 break;
12528 if (c & 0x100) {
12529 /* Unknown escape. Encode as '\z' */
12530 c = (unsigned char)c;
12531 if (eofmark == NULL || synstack->dblquote)
12532 USTPUTC(CTLESC, out);
12533 USTPUTC('\\', out);
12536 #endif
12537 if (!eofmark || synstack->dblquote || synstack->varnest)
12538 USTPUTC(CTLESC, out);
12539 USTPUTC(c, out);
12540 break;
12541 case CBACK: /* backslash */
12542 c = pgetc();
12543 if (c == PEOF) {
12544 USTPUTC(CTLESC, out);
12545 USTPUTC('\\', out);
12546 pungetc();
12547 } else {
12548 if (pssyntax && c == '$') {
12549 USTPUTC(CTLESC, out);
12550 USTPUTC('\\', out);
12552 /* Backslash is retained if we are in "str"
12553 * and next char isn't dquote-special.
12555 if (synstack->dblquote
12556 && c != '\\'
12557 && c != '`'
12558 && c != '$'
12559 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12560 && (c != '}' || !synstack->varnest)
12562 USTPUTC(CTLESC, out); /* protect '\' from glob */
12563 USTPUTC('\\', out);
12565 USTPUTC(CTLESC, out);
12566 USTPUTC(c, out);
12567 quotef = 1;
12569 break;
12570 case CSQUOTE:
12571 synstack->syntax = SQSYNTAX;
12572 quotemark:
12573 if (eofmark == NULL) {
12574 USTPUTC(CTLQUOTEMARK, out);
12576 break;
12577 case CDQUOTE:
12578 synstack->syntax = DQSYNTAX;
12579 synstack->dblquote = 1;
12580 toggledq:
12581 if (synstack->varnest)
12582 synstack->innerdq ^= 1;
12583 goto quotemark;
12584 case CENDQUOTE:
12585 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
12586 if (eofmark != NULL && synstack->varnest == 0) {
12587 USTPUTC(c, out);
12588 break;
12591 if (synstack->dqvarnest == 0) {
12592 synstack->syntax = BASESYNTAX;
12593 synstack->dblquote = 0;
12596 quotef = 1;
12598 if (c == '"')
12599 goto toggledq;
12601 goto quotemark;
12602 case CVAR: /* '$' */
12603 PARSESUB(); /* parse substitution */
12604 break;
12605 case CENDVAR: /* '}' */
12606 if (!synstack->innerdq && synstack->varnest > 0) {
12607 if (!--synstack->varnest && synstack->varpushed)
12608 synstack_pop(&synstack);
12609 else if (synstack->dqvarnest > 0)
12610 synstack->dqvarnest--;
12611 c = CTLENDVAR;
12613 USTPUTC(c, out);
12614 break;
12615 #if ENABLE_FEATURE_SH_MATH
12616 case CLP: /* '(' in arithmetic */
12617 synstack->parenlevel++;
12618 USTPUTC(c, out);
12619 break;
12620 case CRP: /* ')' in arithmetic */
12621 if (synstack->parenlevel > 0) {
12622 synstack->parenlevel--;
12623 } else {
12624 if (pgetc_eatbnl() == ')') {
12625 c = CTLENDARI;
12626 synstack_pop(&synstack);
12627 } else {
12629 * unbalanced parens
12630 * (don't 2nd guess - no error)
12632 pungetc();
12635 USTPUTC(c, out);
12636 break;
12637 #endif
12638 case CBQUOTE: /* '`' */
12639 if (checkkwd & CHKEOFMARK) {
12640 quotef = 1;
12641 USTPUTC('`', out);
12642 break;
12645 PARSEBACKQOLD();
12646 break;
12647 case CENDFILE:
12648 goto endword; /* exit outer loop */
12649 default:
12650 if (synstack->varnest == 0) {
12651 #if BASH_REDIR_OUTPUT
12652 if (c == '&') {
12653 //Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
12654 if (pgetc() == '>')
12655 c = 0x100 + '>'; /* flag &> */
12656 pungetc();
12658 #endif
12659 #if BASH_PROCESS_SUBST
12660 if (c == '<' || c == '>') {
12661 if (pgetc() == '(') {
12662 PARSEPROCSUB();
12663 break;
12665 pungetc();
12667 #endif
12668 goto endword; /* exit outer loop */
12670 USTPUTC(c, out);
12672 c = pgetc_top(synstack);
12673 } /* for (;;) */
12674 endword:
12676 #if ENABLE_FEATURE_SH_MATH
12677 if (synstack->syntax == ARISYNTAX)
12678 raise_error_syntax("missing '))'");
12679 #endif
12680 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
12681 raise_error_syntax("unterminated quoted string");
12682 if (synstack->varnest != 0) {
12683 /* { */
12684 raise_error_syntax("missing '}'");
12686 USTPUTC('\0', out);
12687 len = out - (char *)stackblock();
12688 out = stackblock();
12689 if (eofmark == NULL) {
12690 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
12691 && quotef == 0
12693 if (isdigit_str9(out)) {
12694 PARSEREDIR(); /* passed as params: out, c */
12695 lasttoken = TREDIR;
12696 return lasttoken;
12698 /* else: non-number X seen, interpret it
12699 * as "NNNX>file" = "NNNX >file" */
12701 pungetc();
12703 quoteflag = quotef;
12704 backquotelist = bqlist;
12705 grabstackblock(len);
12706 wordtext = out;
12707 lasttoken = TWORD;
12708 return lasttoken;
12709 /* end of readtoken routine */
12712 * Check to see whether we are at the end of the here document. When this
12713 * is called, c is set to the first character of the next input line. If
12714 * we are at the end of the here document, this routine sets the c to PEOF.
12716 checkend: {
12717 if (realeofmark(eofmark)) {
12718 int markloc;
12719 char *p;
12721 if (striptabs) {
12722 while (c == '\t')
12723 c = pgetc();
12726 markloc = out - (char *)stackblock();
12727 for (p = eofmark; STPUTC(c, out), *p; p++) {
12728 if (c != *p)
12729 goto more_heredoc;
12730 /* FIXME: fails for backslash-newlined terminator:
12731 * cat <<EOF
12732 * ...
12733 * EO\
12735 * (see heredoc_bkslash_newline2.tests)
12737 c = pgetc();
12740 if (c == '\n' || c == PEOF) {
12741 c = PEOF;
12742 if (trap_depth == 0)
12743 g_parsefile->linno++;
12744 needprompt = doprompt;
12745 } else {
12746 int len_here;
12748 more_heredoc:
12749 p = (char *)stackblock() + markloc + 1;
12750 len_here = out - p;
12752 if (len_here) {
12753 len_here -= (c >= PEOF);
12754 c = p[-1];
12756 if (len_here) {
12757 char *str;
12759 str = alloca(len_here + 1);
12760 *(char *)mempcpy(str, p, len_here) = '\0';
12762 pushstring(str, NULL);
12767 STADJUST((char *)stackblock() + markloc - out, out);
12769 goto checkend_return;
12773 * Parse a redirection operator. The variable "out" points to a string
12774 * specifying the fd to be redirected. The variable "c" contains the
12775 * first character of the redirection operator.
12777 parseredir: {
12778 /* out is already checked to be a valid number or "" */
12779 int fd = (*out == '\0' ? -1 : atoi(out));
12780 union node *np;
12782 np = stzalloc(sizeof(struct nfile));
12783 if (c == '>') {
12784 np->nfile.fd = 1;
12785 c = pgetc_eatbnl();
12786 if (c == '>')
12787 np->type = NAPPEND;
12788 else if (c == '|')
12789 np->type = NCLOBBER;
12790 else if (c == '&')
12791 np->type = NTOFD;
12792 /* it also can be NTO2 (>&file), but we can't figure it out yet */
12793 else {
12794 np->type = NTO;
12795 pungetc();
12798 #if BASH_REDIR_OUTPUT
12799 else if (c == 0x100 + '>') { /* this flags &> redirection */
12800 np->nfile.fd = 1;
12801 pgetc(); /* this is '>', no need to check */
12802 np->type = NTO2;
12804 #endif
12805 else { /* c == '<' */
12806 /*np->nfile.fd = 0; - stzalloc did it */
12807 c = pgetc_eatbnl();
12808 switch (c) {
12809 case '<':
12810 if (sizeof(struct nfile) != sizeof(struct nhere)) {
12811 np = stzalloc(sizeof(struct nhere));
12812 /*np->nfile.fd = 0; - stzalloc did it */
12814 np->type = NHERE;
12815 heredoc = stzalloc(sizeof(struct heredoc));
12816 heredoc->here = np;
12817 c = pgetc_eatbnl();
12818 if (c == '-') {
12819 heredoc->striptabs = 1;
12820 } else {
12821 /*heredoc->striptabs = 0; - stzalloc did it */
12822 pungetc();
12824 break;
12826 case '&':
12827 np->type = NFROMFD;
12828 break;
12830 case '>':
12831 np->type = NFROMTO;
12832 break;
12834 default:
12835 np->type = NFROM;
12836 pungetc();
12837 break;
12840 if (fd >= 0)
12841 np->nfile.fd = fd;
12842 redirnode = np;
12843 goto parseredir_return;
12847 * Parse a substitution. At this point, we have read the dollar sign
12848 * and nothing else.
12851 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12852 * (assuming ascii char codes, as the original implementation did) */
12853 #define is_special(c) \
12854 (((unsigned)(c) - 33 < 32) \
12855 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
12856 parsesub: {
12857 unsigned char subtype;
12858 int typeloc;
12860 c = pgetc_eatbnl();
12861 if ((checkkwd & CHKEOFMARK)
12862 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
12864 #if BASH_DOLLAR_SQUOTE
12865 if (synstack->syntax != DQSYNTAX && c == '\'')
12866 bash_dollar_squote = 1;
12867 else
12868 #endif
12869 USTPUTC('$', out);
12870 pungetc();
12871 } else if (c == '(') {
12872 /* $(command) or $((arith)) */
12873 if (pgetc_eatbnl() == '(') {
12874 #if ENABLE_FEATURE_SH_MATH
12875 PARSEARITH();
12876 #else
12877 raise_error_syntax("support for $((arith)) is disabled");
12878 #endif
12879 } else {
12880 pungetc();
12881 PARSEBACKQNEW();
12883 } else {
12884 /* $VAR, $<specialchar>, ${...}, or PEOF */
12885 smalluint newsyn = synstack->syntax;
12887 USTPUTC(CTLVAR, out);
12888 typeloc = out - (char *)stackblock();
12889 STADJUST(1, out);
12890 subtype = VSNORMAL;
12891 if (c == '{') {
12892 c = pgetc_eatbnl();
12893 subtype = 0;
12895 varname:
12896 if (is_name(c)) {
12897 /* $[{[#]]NAME[}] */
12898 do {
12899 STPUTC(c, out);
12900 c = pgetc_eatbnl();
12901 } while (is_in_name(c));
12902 } else if (isdigit(c)) {
12903 /* $[{[#]]NUM[}] */
12904 do {
12905 STPUTC(c, out);
12906 c = pgetc_eatbnl();
12907 } while ((subtype == 0 || subtype == VSLENGTH) && isdigit(c));
12908 } else if (c != '}') {
12909 /* $[{[#]]<specialchar>[}] */
12910 int cc = c;
12912 c = pgetc_eatbnl();
12913 if (!subtype && cc == '#') {
12914 subtype = VSLENGTH;
12915 if (c == '_' || isalnum(c))
12916 goto varname;
12917 cc = c;
12918 c = pgetc_eatbnl();
12919 if (cc == '}' || c != '}') {
12920 pungetc();
12921 subtype = 0;
12922 c = cc;
12923 cc = '#';
12927 if (!is_special(cc)) {
12928 if (subtype == VSLENGTH)
12929 subtype = 0;
12930 goto badsub;
12933 USTPUTC(cc, out);
12934 } else
12935 goto badsub;
12937 if (subtype == 0) {
12938 static const char types[] ALIGN1 = "}-+?=";
12939 /* ${VAR...} but not $VAR or ${#VAR} */
12940 /* c == first char after VAR */
12941 int cc = c;
12943 switch (c) {
12944 case ':':
12945 c = pgetc_eatbnl();
12946 #if BASH_SUBSTR
12947 /* This check is only needed to not misinterpret
12948 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12949 * constructs.
12951 if (!strchr(types, c)) {
12952 subtype = VSSUBSTR;
12953 pungetc();
12954 break; /* "goto badsub" is bigger (!) */
12956 #endif
12957 subtype = VSNUL;
12958 /*FALLTHROUGH*/
12959 default: {
12960 const char *p = strchr(types, c);
12961 if (p == NULL)
12962 break;
12963 subtype |= p - types + VSNORMAL;
12964 break;
12966 case '%':
12967 case '#':
12968 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12969 c = pgetc_eatbnl();
12970 if (c == cc)
12971 subtype++;
12972 else
12973 pungetc();
12975 newsyn = BASESYNTAX;
12976 break;
12977 #if BASH_PATTERN_SUBST
12978 case '/':
12979 /* ${v/[/]pattern/repl} */
12980 //TODO: encode pattern and repl separately.
12981 // Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12982 // are broken (should print "ONE")
12983 subtype = VSREPLACE;
12984 newsyn = BASESYNTAX;
12985 c = pgetc_eatbnl();
12986 if (c != '/')
12987 goto badsub;
12988 subtype++; /* VSREPLACEALL */
12989 break;
12990 #endif
12992 } else {
12993 if (subtype == VSLENGTH && c != '}')
12994 subtype = 0;
12995 badsub:
12996 pungetc();
12999 if (newsyn == ARISYNTAX)
13000 newsyn = DQSYNTAX;
13002 if ((newsyn != synstack->syntax || synstack->innerdq)
13003 && subtype != VSNORMAL
13005 synstack_push(&synstack,
13006 synstack->prev ?: alloca(sizeof(*synstack)),
13007 newsyn);
13009 synstack->varpushed = 1;
13010 synstack->dblquote = newsyn != BASESYNTAX;
13013 ((unsigned char *)stackblock())[typeloc] = subtype;
13014 if (subtype != VSNORMAL) {
13015 synstack->varnest++;
13016 if (synstack->dblquote)
13017 synstack->dqvarnest++;
13019 STPUTC('=', out);
13021 goto parsesub_return;
13025 * Called to parse command substitutions. Newstyle is set if the command
13026 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
13027 * list of commands (passed by reference), and savelen is the number of
13028 * characters on the top of the stack which must be preserved.
13030 parsebackq: {
13031 struct nodelist **nlpp;
13032 union node *n;
13033 char *str;
13034 size_t savelen;
13035 struct heredoc *saveheredoclist;
13036 smallint saveprompt = 0;
13038 str = NULL;
13039 savelen = out - (char *)stackblock();
13040 if (savelen > 0) {
13042 * FIXME: this can allocate very large block on stack and SEGV.
13043 * Example:
13044 * echo "..<100kbytes>..`true` $(true) `true` ..."
13045 * allocates 100kb for every command subst. With about
13046 * a hundred command substitutions stack overflows.
13047 * With larger prepended string, SEGV happens sooner.
13049 str = alloca(savelen);
13050 memcpy(str, stackblock(), savelen);
13053 if (oldstyle) {
13054 /* We must read until the closing backquote, giving special
13055 * treatment to some slashes, and then push the string and
13056 * reread it as input, interpreting it normally.
13058 char *pout;
13059 size_t psavelen;
13060 char *pstr;
13062 STARTSTACKSTR(pout);
13063 for (;;) {
13064 int pc;
13066 setprompt_if(needprompt, 2);
13067 pc = pgetc_eatbnl();
13068 switch (pc) {
13069 case '`':
13070 goto done;
13072 case '\\':
13073 pc = pgetc(); /* not pgetc_eatbnl! */
13074 if (pc != '\\' && pc != '`' && pc != '$'
13075 && (!synstack->dblquote || pc != '"')
13077 STPUTC('\\', pout);
13079 break;
13081 case PEOF:
13082 raise_error_syntax("EOF in backquote substitution");
13084 case '\n':
13085 nlnoprompt();
13086 break;
13088 default:
13089 break;
13091 STPUTC(pc, pout);
13093 done:
13094 STPUTC('\0', pout);
13095 psavelen = pout - (char *)stackblock();
13096 if (psavelen > 0) {
13097 pstr = grabstackstr(pout);
13098 setinputstring(pstr);
13101 nlpp = &bqlist;
13102 while (*nlpp)
13103 nlpp = &(*nlpp)->next;
13104 *nlpp = stzalloc(sizeof(**nlpp));
13105 /* (*nlpp)->next = NULL; - stzalloc did it */
13107 saveheredoclist = heredoclist;
13108 heredoclist = NULL;
13110 if (oldstyle) {
13111 saveprompt = doprompt;
13112 doprompt = 0;
13115 n = list(2);
13117 if (oldstyle)
13118 doprompt = saveprompt;
13119 else {
13120 if (readtoken() != TRP)
13121 raise_error_unexpected_syntax(TRP);
13122 setinputstring(nullstr);
13125 parseheredoc();
13126 heredoclist = saveheredoclist;
13128 (*nlpp)->n = n;
13129 /* Start reading from old file again. */
13130 popfile();
13131 /* Ignore any pushed back tokens left from the backquote parsing. */
13132 if (oldstyle)
13133 tokpushback = 0;
13134 out = growstackto(savelen + 1);
13135 if (str) {
13136 memcpy(out, str, savelen);
13137 STADJUST(savelen, out);
13139 #if BASH_PROCESS_SUBST
13140 if (style == PSUB)
13141 USTPUTC(c == '<' ? CTLFROMPROC : CTLTOPROC, out);
13142 else
13143 #endif
13144 USTPUTC(CTLBACKQ, out);
13145 if (oldstyle)
13146 goto parsebackq_oldreturn;
13147 #if BASH_PROCESS_SUBST
13148 else if (style == PSUB)
13149 goto parsebackq_psreturn;
13150 #endif
13151 goto parsebackq_newreturn;
13154 #if ENABLE_FEATURE_SH_MATH
13156 * Parse an arithmetic expansion (indicate start of one and set state)
13158 parsearith: {
13160 synstack_push(&synstack,
13161 synstack->prev ?: alloca(sizeof(*synstack)),
13162 ARISYNTAX);
13163 synstack->dblquote = 1;
13164 USTPUTC(CTLARI, out);
13165 goto parsearith_return;
13167 #endif
13168 } /* end of readtoken */
13171 * Read the next input token.
13172 * If the token is a word, we set backquotelist to the list of cmds in
13173 * backquotes. We set quoteflag to true if any part of the word was
13174 * quoted.
13175 * If the token is TREDIR, then we set redirnode to a structure containing
13176 * the redirection.
13178 * [Change comment: here documents and internal procedures]
13179 * [Readtoken shouldn't have any arguments. Perhaps we should make the
13180 * word parsing code into a separate routine. In this case, readtoken
13181 * doesn't need to have any internal procedures, but parseword does.
13182 * We could also make parseoperator in essence the main routine, and
13183 * have parseword (readtoken1?) handle both words and redirection.]
13185 #define NEW_xxreadtoken
13186 #ifdef NEW_xxreadtoken
13187 /* singles must be first! */
13188 static const char xxreadtoken_chars[7] ALIGN1 = {
13189 '\n', '(', ')', /* singles */
13190 '&', '|', ';', /* doubles */
13194 #define xxreadtoken_singles 3
13195 #define xxreadtoken_doubles 3
13197 static const char xxreadtoken_tokens[] ALIGN1 = {
13198 TNL, TLP, TRP, /* only single occurrence allowed */
13199 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
13200 TEOF, /* corresponds to trailing nul */
13201 TAND, TOR, TENDCASE /* if double occurrence */
13204 static int
13205 xxreadtoken(void)
13207 int c;
13209 if (tokpushback) {
13210 tokpushback = 0;
13211 return lasttoken;
13213 setprompt_if(needprompt, 2);
13214 for (;;) { /* until token or start of word found */
13215 c = pgetc_eatbnl();
13216 if (c == ' ' || c == '\t')
13217 continue;
13219 if (c == '#') {
13220 while ((c = pgetc()) != '\n' && c != PEOF)
13221 continue;
13222 pungetc();
13223 } else if (c == '\\') {
13224 break; /* return readtoken1(...) */
13225 } else {
13226 const char *p;
13228 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
13229 if (c != PEOF) {
13230 if (c == '\n') {
13231 nlnoprompt();
13234 p = strchr(xxreadtoken_chars, c);
13235 if (p == NULL)
13236 break; /* return readtoken1(...) */
13238 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
13239 int cc = pgetc_eatbnl();
13240 if (cc == c) { /* double occurrence? */
13241 p += xxreadtoken_doubles + 1;
13242 } else {
13243 pungetc();
13244 #if BASH_REDIR_OUTPUT
13245 if (c == '&' && cc == '>') /* &> */
13246 break; /* return readtoken1(...) */
13247 #endif
13251 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
13252 return lasttoken;
13254 } /* for (;;) */
13256 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
13258 #else /* old xxreadtoken */
13259 #define RETURN(token) return lasttoken = token
13260 static int
13261 xxreadtoken(void)
13263 int c;
13265 if (tokpushback) {
13266 tokpushback = 0;
13267 return lasttoken;
13269 setprompt_if(needprompt, 2);
13270 for (;;) { /* until token or start of word found */
13271 c = pgetc_eatbnl();
13272 switch (c) {
13273 case ' ': case '\t':
13274 continue;
13275 case '#':
13276 while ((c = pgetc()) != '\n' && c != PEOF)
13277 continue;
13278 pungetc();
13279 continue;
13280 case '\n':
13281 nlnoprompt();
13282 RETURN(TNL);
13283 case PEOF:
13284 RETURN(TEOF);
13285 case '&':
13286 if (pgetc_eatbnl() == '&')
13287 RETURN(TAND);
13288 pungetc();
13289 RETURN(TBACKGND);
13290 case '|':
13291 if (pgetc_eatbnl() == '|')
13292 RETURN(TOR);
13293 pungetc();
13294 RETURN(TPIPE);
13295 case ';':
13296 if (pgetc_eatbnl() == ';')
13297 RETURN(TENDCASE);
13298 pungetc();
13299 RETURN(TSEMI);
13300 case '(':
13301 RETURN(TLP);
13302 case ')':
13303 RETURN(TRP);
13305 break;
13307 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
13308 #undef RETURN
13310 #endif /* old xxreadtoken */
13312 static int
13313 readtoken(void)
13315 int t;
13316 int kwd = checkkwd;
13317 #if DEBUG
13318 smallint alreadyseen = tokpushback;
13319 #endif
13321 #if ENABLE_ASH_ALIAS
13322 top:
13323 #endif
13325 t = xxreadtoken();
13328 * eat newlines
13330 if (kwd & CHKNL) {
13331 while (t == TNL) {
13332 parseheredoc();
13333 checkkwd = 0;
13334 t = xxreadtoken();
13338 kwd |= checkkwd;
13339 checkkwd = 0;
13341 if (t != TWORD || quoteflag) {
13342 goto out;
13346 * check for keywords
13348 if (kwd & CHKKWD) {
13349 const char *const *pp;
13351 pp = findkwd(wordtext);
13352 if (pp) {
13353 lasttoken = t = pp - tokname_array;
13354 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
13355 goto out;
13359 if (kwd & CHKALIAS) {
13360 #if ENABLE_ASH_ALIAS
13361 struct alias *ap;
13362 ap = lookupalias(wordtext, 1);
13363 if (ap != NULL) {
13364 if (*ap->val) {
13365 pushstring(ap->val, ap);
13367 goto top;
13369 #endif
13371 out:
13372 #if DEBUG
13373 if (!alreadyseen)
13374 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13375 else
13376 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13377 #endif
13378 return t;
13382 * Read and parse a command. Returns NODE_EOF on end of file.
13383 * (NULL is a valid parse tree indicating a blank line.)
13385 static union node *
13386 parsecmd(int interact)
13388 tokpushback = 0;
13389 checkkwd = 0;
13390 heredoclist = 0;
13391 doprompt = interact;
13392 setprompt_if(doprompt, doprompt);
13393 needprompt = 0;
13394 return list(1);
13398 * Input any here documents.
13400 static void
13401 parseheredoc(void)
13403 struct heredoc *here;
13404 union node *n;
13406 here = heredoclist;
13407 heredoclist = NULL;
13409 while (here) {
13410 tokpushback = 0;
13411 setprompt_if(needprompt, 2);
13412 if (here->here->type == NHERE)
13413 readtoken1(pgetc(), SQSYNTAX, here->eofmark, here->striptabs);
13414 else
13415 readtoken1(pgetc_eatbnl(), DQSYNTAX, here->eofmark, here->striptabs);
13416 n = stzalloc(sizeof(struct narg));
13417 n->narg.type = NARG;
13418 /*n->narg.next = NULL; - stzalloc did it */
13419 n->narg.text = wordtext;
13420 n->narg.backquote = backquotelist;
13421 here->here->nhere.doc = n;
13422 here = here->next;
13427 static const char *
13428 expandstr(const char *ps, int syntax_type)
13430 struct parsefile *file_stop;
13431 struct jmploc *volatile savehandler;
13432 struct heredoc *saveheredoclist;
13433 const char *result;
13434 int saveprompt;
13435 struct jmploc jmploc;
13436 union node n;
13437 int err;
13439 file_stop = g_parsefile;
13441 /* XXX Fix (char *) cast. */
13442 setinputstring((char *)ps);
13444 saveheredoclist = heredoclist;
13445 heredoclist = NULL;
13446 saveprompt = doprompt;
13447 doprompt = 0;
13448 result = ps;
13449 savehandler = exception_handler;
13450 err = setjmp(jmploc.loc);
13451 if (err)
13452 goto out;
13454 /* readtoken1() might die horribly.
13455 * Try a prompt with syntactically wrong command:
13456 * PS1='$(date "+%H:%M:%S) > '
13458 exception_handler = &jmploc;
13459 readtoken1(pgetc_eatbnl(), syntax_type, FAKEEOFMARK, 0);
13461 n.narg.type = NARG;
13462 n.narg.next = NULL;
13463 n.narg.text = wordtext;
13464 n.narg.backquote = backquotelist;
13466 /* expandarg() might fail too:
13467 * PS1='$((123+))'
13469 expandarg(&n, NULL, EXP_QUOTED);
13470 result = stackblock();
13472 out:
13473 exception_handler = savehandler;
13474 if (err && exception_type != EXERROR)
13475 longjmp(exception_handler->loc, 1);
13477 doprompt = saveprompt;
13478 /* Try: PS1='`xxx(`' */
13479 unwindfiles(file_stop);
13480 heredoclist = saveheredoclist;
13482 return result;
13485 static inline int
13486 parser_eof(void)
13488 return tokpushback && lasttoken == TEOF;
13492 * Execute a command or commands contained in a string.
13494 static int
13495 evalstring(char *s, int flags)
13497 struct jmploc *volatile savehandler;
13498 struct jmploc jmploc;
13499 int ex;
13501 union node *n;
13502 struct stackmark smark;
13503 int status;
13505 s = sstrdup(s);
13506 setinputstring(s);
13507 setstackmark(&smark);
13509 status = 0;
13510 /* On exception inside execution loop, we must popfile().
13511 * Try interactively:
13512 * readonly a=a
13513 * command eval "a=b" # throws "is read only" error
13514 * "command BLTIN" is not supposed to abort (even in non-interactive use).
13515 * But if we skip popfile(), we hit EOF in eval's string, and exit.
13517 savehandler = exception_handler;
13518 ex = setjmp(jmploc.loc);
13519 if (ex)
13520 goto out;
13521 exception_handler = &jmploc;
13523 while ((n = parsecmd(0)) != NODE_EOF) {
13524 int i;
13526 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
13527 if (n)
13528 status = i;
13529 popstackmark(&smark);
13530 if (evalskip)
13531 break;
13533 out:
13534 popstackmark(&smark);
13535 popfile();
13536 stunalloc(s);
13538 exception_handler = savehandler;
13539 if (ex)
13540 longjmp(exception_handler->loc, ex);
13542 return status;
13546 * The eval command.
13548 static int FAST_FUNC
13549 evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
13551 char *p;
13552 char *concat;
13554 if (argv[1]) {
13555 p = argv[1];
13556 argv += 2;
13557 if (argv[0]) {
13558 STARTSTACKSTR(concat);
13559 for (;;) {
13560 concat = stack_putstr(p, concat);
13561 p = *argv++;
13562 if (p == NULL)
13563 break;
13564 STPUTC(' ', concat);
13566 STPUTC('\0', concat);
13567 p = grabstackstr(concat);
13569 return evalstring(p, flags & EV_TESTED);
13571 return 0;
13575 * Read and execute commands.
13576 * "Top" is nonzero for the top level command loop;
13577 * it turns on prompting if the shell is interactive.
13579 static int
13580 cmdloop(int top)
13582 union node *n;
13583 struct stackmark smark;
13584 int inter;
13585 int status = 0;
13586 int numeof = 0;
13588 TRACE(("cmdloop(%d) called\n", top));
13589 for (;;) {
13590 int skip;
13592 setstackmark(&smark);
13593 #if JOBS
13594 if (doing_jobctl)
13595 showjobs(SHOW_CHANGED|SHOW_STDERR);
13596 #endif
13597 inter = 0;
13598 if (iflag && top) {
13599 inter++;
13600 chkmail();
13602 n = parsecmd(inter);
13603 #if DEBUG
13604 if (DEBUG > 2 && debug && (n != NODE_EOF))
13605 showtree(n);
13606 #endif
13607 if (n == NODE_EOF) {
13608 if (!top || numeof >= 50)
13609 break;
13610 if (!stoppedjobs()) {
13611 if (!iflag)
13612 break;
13613 if (!Iflag) {
13614 newline_and_flush(stderr);
13615 break;
13617 /* "set -o ignoreeof" active, do not exit command loop on ^D */
13618 out2str("\nUse \"exit\" to leave shell.\n");
13620 numeof++;
13621 } else {
13622 int i;
13624 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13625 job_warning >>= 1;
13626 numeof = 0;
13627 i = evaltree(n, 0);
13628 if (n)
13629 status = i;
13631 popstackmark(&smark);
13632 skip = evalskip;
13634 if (skip) {
13635 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
13636 break;
13639 return status;
13643 * Take commands from a file. To be compatible we should do a path
13644 * search for the file, which is necessary to find sub-commands.
13646 static char *
13647 find_dot_file(char *basename)
13649 char *fullname;
13650 const char *path;
13651 struct stat statb;
13652 int len;
13654 /* don't try this for absolute or relative paths */
13655 if (strchr(basename, '/'))
13656 return basename;
13658 path = pathval();
13659 while ((len = padvance(&path, basename)) >= 0) {
13660 fullname = stackblock();
13661 if ((!pathopt || *pathopt == 'f')
13662 && !stat(fullname, &statb) && S_ISREG(statb.st_mode)
13664 /* This will be freed by the caller. */
13665 return stalloc(len);
13668 /* not found in PATH */
13670 #if ENABLE_ASH_BASH_SOURCE_CURDIR
13671 return basename;
13672 #else
13673 ash_msg_and_raise_error("%s: not found", basename);
13674 /* NOTREACHED */
13675 #endif
13678 static int FAST_FUNC
13679 dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
13681 /* "false; . empty_file; echo $?" should print 0, not 1: */
13682 int status = 0;
13683 char *fullname;
13684 char **argv;
13685 char *args_need_save;
13686 volatile struct shparam saveparam;
13688 //???
13689 // struct strlist *sp;
13690 // for (sp = cmdenviron; sp; sp = sp->next)
13691 // setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
13693 nextopt(nullstr); /* handle possible "--" */
13694 argv = argptr;
13696 if (!argv[0]) {
13697 /* bash says: "bash: .: filename argument required" */
13698 return 2; /* bash compat */
13701 /* This aborts if file isn't found, which is POSIXly correct.
13702 * bash returns exitcode 1 instead.
13704 fullname = find_dot_file(argv[0]);
13705 argv++;
13706 args_need_save = argv[0];
13707 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
13708 int argc;
13709 saveparam = shellparam;
13710 shellparam.malloced = 0;
13711 argc = 1;
13712 while (argv[argc])
13713 argc++;
13714 shellparam.nparam = argc;
13715 shellparam.p = argv;
13718 /* This aborts if file can't be opened, which is POSIXly correct.
13719 * bash returns exitcode 1 instead.
13721 setinputfile(fullname, INPUT_PUSH_FILE);
13722 commandname = fullname;
13723 status = cmdloop(0);
13724 popfile();
13726 if (args_need_save) {
13727 freeparam(&shellparam);
13728 shellparam = saveparam;
13731 return status;
13734 static int FAST_FUNC
13735 exitcmd(int argc UNUSED_PARAM, char **argv)
13737 if (stoppedjobs())
13738 return 0;
13740 if (argv[1])
13741 savestatus = number(argv[1]);
13743 //TODO: this script
13744 // trap 'echo trap:$FUNCNAME' EXIT
13745 // f() { exit; }
13746 // f
13747 //prints "trap:f" in bash. We can call exitshell() here to achieve this.
13748 //For now, keeping dash code:
13749 raise_exception(EXEXIT);
13750 /* NOTREACHED */
13754 * Read a file containing shell functions.
13756 static void
13757 readcmdfile(char *name)
13759 setinputfile(name, INPUT_PUSH_FILE);
13760 cmdloop(0);
13761 popfile();
13765 /* ============ find_command inplementation */
13768 * Resolve a command name. If you change this routine, you may have to
13769 * change the shellexec routine as well.
13771 static void
13772 find_command(char *name, struct cmdentry *entry, int act, const char *path)
13774 struct tblentry *cmdp;
13775 int idx;
13776 int prev;
13777 char *fullname;
13778 struct stat statb;
13779 int e;
13780 int updatetbl;
13781 struct builtincmd *bcmd;
13782 int len;
13784 /* If name contains a slash, don't use PATH or hash table */
13785 if (strchr(name, '/') != NULL) {
13786 entry->u.index = -1;
13787 if (act & DO_ABS) {
13788 while (stat(name, &statb) < 0) {
13789 #ifdef SYSV
13790 if (errno == EINTR)
13791 continue;
13792 #endif
13793 entry->cmdtype = CMDUNKNOWN;
13794 return;
13797 entry->cmdtype = CMDNORMAL;
13798 return;
13801 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
13803 updatetbl = (path == pathval());
13804 if (!updatetbl)
13805 act |= DO_ALTPATH;
13807 /* If name is in the table, check answer will be ok */
13808 cmdp = cmdlookup(name, 0);
13809 if (cmdp != NULL) {
13810 int bit;
13812 switch (cmdp->cmdtype) {
13813 default:
13814 #if DEBUG
13815 abort();
13816 #endif
13817 case CMDNORMAL:
13818 bit = DO_ALTPATH | DO_REGBLTIN;
13819 break;
13820 case CMDFUNCTION:
13821 bit = DO_NOFUNC;
13822 break;
13823 case CMDBUILTIN:
13824 bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
13825 break;
13827 if (act & bit) {
13828 if (act & bit & DO_REGBLTIN)
13829 goto fail;
13831 updatetbl = 0;
13832 cmdp = NULL;
13833 } else if (cmdp->rehash == 0)
13834 /* if not invalidated by cd, we're done */
13835 goto success;
13838 /* If %builtin not in path, check for builtin next */
13839 bcmd = find_builtin(name);
13840 if (bcmd) {
13841 if (IS_BUILTIN_REGULAR(bcmd))
13842 goto builtin_success;
13843 if (act & DO_ALTPATH)
13844 goto builtin_success;
13845 if (builtinloc <= 0)
13846 goto builtin_success;
13849 if (act & DO_REGBLTIN)
13850 goto fail;
13852 #if ENABLE_FEATURE_SH_STANDALONE
13854 int applet_no = find_applet_by_name(name);
13855 if (applet_no >= 0) {
13856 entry->cmdtype = CMDNORMAL;
13857 entry->u.index = -2 - applet_no;
13858 return;
13861 #endif
13863 /* We have to search path. */
13864 prev = -1; /* where to start */
13865 if (cmdp && cmdp->rehash) { /* doing a rehash */
13866 if (cmdp->cmdtype == CMDBUILTIN)
13867 prev = builtinloc;
13868 else
13869 prev = cmdp->param.index;
13872 e = ENOENT;
13873 idx = -1;
13874 loop:
13875 while ((len = padvance(&path, name)) >= 0) {
13876 const char *lpathopt = pathopt;
13878 fullname = stackblock();
13879 idx++;
13880 if (lpathopt) {
13881 if (*lpathopt == 'b') {
13882 if (bcmd)
13883 goto builtin_success;
13884 continue;
13885 } else if (!(act & DO_NOFUNC)) {
13886 /* handled below */
13887 } else {
13888 /* ignore unimplemented options */
13889 continue;
13892 /* if rehash, don't redo absolute path names */
13893 if (fullname[0] == '/' && idx <= prev) {
13894 if (idx < prev)
13895 continue;
13896 TRACE(("searchexec \"%s\": no change\n", name));
13897 goto success;
13899 while (stat(fullname, &statb) < 0) {
13900 #ifdef SYSV
13901 if (errno == EINTR)
13902 continue;
13903 #endif
13904 if (errno != ENOENT && errno != ENOTDIR)
13905 e = errno;
13906 goto loop;
13908 e = EACCES; /* if we fail, this will be the error */
13909 if (!S_ISREG(statb.st_mode))
13910 continue;
13911 if (lpathopt) { /* this is a %func directory */
13912 stalloc(len);
13913 /* NB: stalloc will return space pointed by fullname
13914 * (because we don't have any intervening allocations
13915 * between stunalloc above and this stalloc) */
13916 readcmdfile(fullname);
13917 cmdp = cmdlookup(name, 0);
13918 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13919 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13920 stunalloc(fullname);
13921 goto success;
13923 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13924 if (!updatetbl) {
13925 entry->cmdtype = CMDNORMAL;
13926 entry->u.index = idx;
13927 return;
13929 INT_OFF;
13930 cmdp = cmdlookup(name, 1);
13931 cmdp->cmdtype = CMDNORMAL;
13932 cmdp->param.index = idx;
13933 INT_ON;
13934 goto success;
13937 /* We failed. If there was an entry for this command, delete it */
13938 if (cmdp && updatetbl)
13939 delete_cmd_entry();
13940 if (act & DO_ERR) {
13941 #if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13942 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13943 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13944 char *argv[3];
13945 argv[0] = (char*) "command_not_found_handle";
13946 argv[1] = name;
13947 argv[2] = NULL;
13948 evalfun(hookp->param.func, 2, argv, 0);
13949 entry->cmdtype = CMDUNKNOWN;
13950 return;
13952 #endif
13953 ash_msg("%s: %s", name, errmsg(e, "not found"));
13955 fail:
13956 entry->cmdtype = CMDUNKNOWN;
13957 return;
13959 builtin_success:
13960 if (!updatetbl) {
13961 entry->cmdtype = CMDBUILTIN;
13962 entry->u.cmd = bcmd;
13963 return;
13965 INT_OFF;
13966 cmdp = cmdlookup(name, 1);
13967 cmdp->cmdtype = CMDBUILTIN;
13968 cmdp->param.cmd = bcmd;
13969 INT_ON;
13970 success:
13971 cmdp->rehash = 0;
13972 entry->cmdtype = cmdp->cmdtype;
13973 entry->u = cmdp->param;
13978 * The trap builtin.
13980 static int FAST_FUNC
13981 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13983 char *action;
13984 char **ap;
13985 int signo, exitcode;
13987 nextopt(nullstr);
13988 ap = argptr;
13989 if (!*ap) {
13990 for (signo = 0; signo <= NTRAP_LAST; signo++) {
13991 char *tr = trap_ptr[signo];
13992 if (tr) {
13993 /* note: bash adds "SIG", but only if invoked
13994 * as "bash". If called as "sh", or if set -o posix,
13995 * then it prints short signal names.
13996 * We are printing short names: */
13997 out1fmt("trap -- %s %s\n",
13998 single_quote(tr),
13999 (signo == NTRAP_ERR) ? "ERR" : get_signame(signo));
14000 /* trap_ptr != trap only if we are in special-cased `trap` code.
14001 * In this case, we will exit very soon, no need to free(). */
14002 /* if (trap_ptr != trap && tp[0]) */
14003 /* free(tr); */
14007 if (trap_ptr != trap) {
14008 free(trap_ptr);
14009 trap_ptr = trap;
14012 return 0;
14015 /* Why the second check?
14016 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
14017 * In this case, NUM is signal no, not an action.
14019 action = NULL;
14020 if (ap[1] && !is_number(ap[0]))
14021 action = *ap++;
14023 exitcode = 0;
14024 while (*ap) {
14025 signo = strcmp(*ap, "ERR") == 0 ? NTRAP_ERR : get_signum(*ap);
14026 if (signo < 0) {
14027 /* Mimic bash message exactly */
14028 ash_msg("%s: invalid signal specification", *ap);
14029 exitcode = 1;
14030 goto next;
14032 INT_OFF;
14033 if (action) {
14034 if (LONE_DASH(action))
14035 action = NULL;
14036 else {
14037 if (action[0]) /* not NULL and not "" and not "-" */
14038 may_have_traps = 1;
14039 action = ckstrdup(action);
14042 free(trap[signo]);
14043 trap[signo] = action;
14044 if (signo != 0 && signo < NSIG)
14045 setsignal(signo);
14046 INT_ON;
14047 next:
14048 ap++;
14050 return exitcode;
14054 /* ============ Builtins */
14056 #if ENABLE_ASH_HELP
14057 static int FAST_FUNC
14058 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14060 unsigned col;
14061 unsigned i;
14063 out1fmt(
14064 "Built-in commands:\n"
14065 "------------------\n");
14066 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
14067 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
14068 builtintab[i].name + 1);
14069 if (col > 60) {
14070 out1fmt("\n");
14071 col = 0;
14074 # if ENABLE_FEATURE_SH_STANDALONE
14076 const char *a = applet_names;
14077 while (*a) {
14078 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
14079 if (col > 60) {
14080 out1fmt("\n");
14081 col = 0;
14083 while (*a++ != '\0')
14084 continue;
14087 # endif
14088 newline_and_flush(stdout);
14089 return EXIT_SUCCESS;
14091 #endif
14093 #if MAX_HISTORY
14094 static int FAST_FUNC
14095 historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14097 show_history(line_input_state);
14098 return EXIT_SUCCESS;
14100 #endif
14103 * The export and readonly commands.
14105 static int FAST_FUNC
14106 exportcmd(int argc UNUSED_PARAM, char **argv)
14108 struct var *vp;
14109 char *name;
14110 const char *p;
14111 char **aptr;
14112 char opt;
14113 int flag;
14114 int flag_off;
14116 /* "readonly" in bash accepts, but ignores -n.
14117 * We do the same: it saves a conditional in nextopt's param.
14119 flag_off = 0;
14120 while ((opt = nextopt("np")) != '\0') {
14121 if (opt == 'n')
14122 flag_off = VEXPORT;
14124 flag = VEXPORT;
14125 if (argv[0][0] == 'r') {
14126 flag = VREADONLY;
14127 flag_off = 0; /* readonly ignores -n */
14129 flag_off = ~flag_off;
14131 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
14133 aptr = argptr;
14134 name = *aptr;
14135 if (name) {
14136 do {
14137 p = strchr(name, '=');
14138 if (p != NULL) {
14139 p++;
14140 } else {
14141 vp = *findvar(hashvar(name), name);
14142 if (vp) {
14143 vp->flags = ((vp->flags | flag) & flag_off);
14144 continue;
14147 setvar(name, p, (flag & flag_off));
14148 } while ((name = *++aptr) != NULL);
14149 return 0;
14153 /* No arguments. Show the list of exported or readonly vars.
14154 * -n is ignored.
14156 showvars(argv[0], flag, 0);
14157 return 0;
14161 * Delete a function if it exists.
14163 static void
14164 unsetfunc(const char *name)
14166 struct tblentry *cmdp;
14168 cmdp = cmdlookup(name, 0);
14169 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
14170 delete_cmd_entry();
14174 * The unset builtin command. We unset the function before we unset the
14175 * variable to allow a function to be unset when there is a readonly variable
14176 * with the same name.
14178 static int FAST_FUNC
14179 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14181 char **ap;
14182 int i;
14183 int flag = 0;
14185 while ((i = nextopt("vf")) != 0) {
14186 flag = i;
14189 for (ap = argptr; *ap; ap++) {
14190 if (flag != 'f') {
14191 unsetvar(*ap);
14192 continue;
14194 if (flag != 'v')
14195 unsetfunc(*ap);
14197 return 0;
14200 static const unsigned char timescmd_str[] ALIGN1 = {
14201 ' ', offsetof(struct tms, tms_utime),
14202 '\n', offsetof(struct tms, tms_stime),
14203 ' ', offsetof(struct tms, tms_cutime),
14204 '\n', offsetof(struct tms, tms_cstime),
14207 static int FAST_FUNC
14208 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14210 unsigned clk_tck;
14211 const unsigned char *p;
14212 struct tms buf;
14214 clk_tck = bb_clk_tck();
14216 times(&buf);
14217 p = timescmd_str;
14218 do {
14219 unsigned sec, frac;
14220 unsigned long t;
14221 t = *(clock_t *)(((char *) &buf) + p[1]);
14222 sec = t / clk_tck;
14223 frac = t % clk_tck;
14224 out1fmt("%um%u.%03us%c",
14225 sec / 60, sec % 60,
14226 (frac * 1000) / clk_tck,
14227 p[0]);
14228 p += 2;
14229 } while (*p);
14231 return 0;
14234 #if ENABLE_FEATURE_SH_MATH
14236 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
14237 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
14239 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
14241 static int FAST_FUNC
14242 letcmd(int argc UNUSED_PARAM, char **argv)
14244 arith_t i;
14246 argv++;
14247 if (!*argv)
14248 ash_msg_and_raise_error("expression expected");
14249 do {
14250 i = ash_arith(*argv);
14251 } while (*++argv);
14253 return !i;
14255 #endif
14258 * The read builtin. Options:
14259 * -r Do not interpret '\' specially
14260 * -s Turn off echo (tty only)
14261 * -n NCHARS Read NCHARS max
14262 * -p PROMPT Display PROMPT on stderr (if input is from tty)
14263 * -t SECONDS Timeout after SECONDS (tty or pipe only)
14264 * -u FD Read from given FD instead of fd 0
14265 * -d DELIM End on DELIM char, not newline
14266 * This uses unbuffered input, which may be avoidable in some cases.
14267 * TODO: bash also has:
14268 * -a ARRAY Read into array[0],[1],etc
14269 * -e Use line editing (tty only)
14271 static int FAST_FUNC
14272 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14274 struct builtin_read_params params;
14275 const char *r;
14276 int i;
14278 memset(&params, 0, sizeof(params));
14280 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
14281 switch (i) {
14282 case 'p':
14283 params.opt_p = optionarg;
14284 break;
14285 case 'n':
14286 params.opt_n = optionarg;
14287 break;
14288 case 's':
14289 params.read_flags |= BUILTIN_READ_SILENT;
14290 break;
14291 case 't':
14292 params.opt_t = optionarg;
14293 break;
14294 case 'r':
14295 params.read_flags |= BUILTIN_READ_RAW;
14296 break;
14297 case 'u':
14298 params.opt_u = optionarg;
14299 break;
14300 #if BASH_READ_D
14301 case 'd':
14302 params.opt_d = optionarg;
14303 break;
14304 #endif
14305 default:
14306 break;
14310 if (!ENABLE_ASH_BASH_COMPAT && !argptr) {
14311 bb_simple_error_msg("read: need variable name");
14312 return 1;
14314 params.argv = argptr;
14315 params.setvar = setvar0;
14316 params.ifs = bltinlookup("IFS"); /* can be NULL */
14318 /* "read -s" needs to save/restore termios, can't allow ^C
14319 * to jump out of it.
14321 again:
14322 INT_OFF;
14323 r = shell_builtin_read(&params);
14324 INT_ON;
14326 if ((uintptr_t)r == 1 && errno == EINTR) {
14327 /* To get SIGCHLD: sleep 1 & read x; echo $x
14328 * Correct behavior is to not exit "read"
14330 if (pending_sig == 0)
14331 goto again;
14334 if ((uintptr_t)r > 1)
14335 ash_msg_and_raise_error(r);
14337 return (uintptr_t)r;
14340 static int FAST_FUNC
14341 umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14343 static const char permuser[3] ALIGN1 = "ogu";
14345 mode_t mask;
14346 int symbolic_mode = 0;
14348 while (nextopt("S") != '\0') {
14349 symbolic_mode = 1;
14352 INT_OFF;
14353 mask = umask(0);
14354 umask(mask);
14355 INT_ON;
14357 if (*argptr == NULL) {
14358 if (symbolic_mode) {
14359 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
14360 char *p = buf;
14361 int i;
14363 i = 2;
14364 for (;;) {
14365 *p++ = ',';
14366 *p++ = permuser[i];
14367 *p++ = '=';
14368 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
14369 if (!(mask & 0400)) *p++ = 'r';
14370 if (!(mask & 0200)) *p++ = 'w';
14371 if (!(mask & 0100)) *p++ = 'x';
14372 mask <<= 3;
14373 if (--i < 0)
14374 break;
14376 *p = '\0';
14377 puts(buf + 1);
14378 } else {
14379 out1fmt("%04o\n", mask);
14381 } else {
14382 char *modestr = *argptr;
14383 /* numeric umasks are taken as-is */
14384 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
14385 if (!isdigit(modestr[0]))
14386 mask ^= 0777;
14387 mask = bb_parse_mode(modestr, mask);
14388 if ((unsigned)mask > 0777) {
14389 ash_msg_and_raise_error("illegal mode: %s", modestr);
14391 if (!isdigit(modestr[0]))
14392 mask ^= 0777;
14393 umask(mask);
14395 return 0;
14398 static int FAST_FUNC
14399 ulimitcmd(int argc UNUSED_PARAM, char **argv)
14401 return shell_builtin_ulimit(argv);
14404 /* ============ main() and helpers */
14407 * This routine is called when an error or an interrupt occurs in an
14408 * interactive shell and control is returned to the main command loop
14409 * but prior to exitshell.
14411 static void
14412 exitreset(void)
14414 /* from eval.c: */
14415 if (savestatus >= 0) {
14416 if (exception_type == EXEXIT || evalskip == SKIPFUNCDEF)
14417 exitstatus = savestatus;
14418 savestatus = -1;
14420 evalskip = 0;
14421 loopnest = 0;
14422 inps4 = 0;
14424 /* from expand.c: */
14425 ifsfree();
14427 /* from redir.c: */
14428 unwindredir(NULL);
14432 * This routine is called when an error or an interrupt occurs in an
14433 * interactive shell and control is returned to the main command loop.
14434 * (In dash, this function is auto-generated by build machinery).
14436 static void
14437 reset(void)
14439 /* from input.c: */
14440 g_parsefile->left_in_buffer = 0;
14441 g_parsefile->left_in_line = 0; /* clear input buffer */
14442 g_parsefile->unget = 0;
14443 popallfiles();
14445 /* from var.c: */
14446 unwindlocalvars(NULL);
14450 * Called to exit the shell.
14452 static void
14453 exitshell(void)
14455 struct jmploc loc;
14456 char *p;
14458 #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
14459 save_history(line_input_state); /* may be NULL */
14460 #endif
14461 savestatus = exitstatus;
14462 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
14463 if (setjmp(loc.loc))
14464 goto out;
14465 exception_handler = &loc;
14466 p = trap[0];
14467 if (p) {
14468 trap[0] = NULL;
14469 evalskip = 0;
14470 trap_depth++;
14471 evalstring(p, 0);
14472 trap_depth--;
14473 evalskip = SKIPFUNCDEF;
14474 /*free(p); - we'll exit soon */
14476 out:
14477 exitreset();
14478 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14479 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
14481 setjobctl(0);
14482 flush_stdout_stderr();
14483 _exit(exitstatus);
14484 /* NOTREACHED */
14487 /* Don't inline: conserve stack of caller from having our locals too */
14488 static NOINLINE void
14489 init(void)
14491 /* we will never free this */
14492 basepf.next_to_pgetc = basepf.buf = ckzalloc(IBUFSIZ);
14493 basepf.linno = 1;
14495 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
14496 setsignal(SIGCHLD);
14499 char **envp;
14500 const char *p;
14502 initvar();
14503 for (envp = environ; envp && *envp; envp++) {
14504 /* Used to have
14505 * p = endofname(*envp);
14506 * if (p != *envp && *p == '=') {
14507 * here to weed out badly-named variables, but this breaks
14508 * scenarios where people do want them passed to children:
14509 * import os
14510 * os.environ["test-test"]="test"
14511 * if os.fork() == 0:
14512 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
14513 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
14515 if (strchr(*envp, '=')) {
14516 setvareq(*envp, VEXPORT|VTEXTFIXED);
14520 setvareq((char*)defifsvar, VTEXTFIXED);
14521 setvareq((char*)defoptindvar, VTEXTFIXED);
14523 setvar0("PPID", utoa(getppid()));
14524 #if BASH_SHLVL_VAR
14525 p = lookupvar("SHLVL");
14526 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
14527 #endif
14528 #if BASH_HOSTNAME_VAR
14529 if (!lookupvar("HOSTNAME")) {
14530 struct utsname uts;
14531 uname(&uts);
14532 setvar0("HOSTNAME", uts.nodename);
14534 #endif
14535 p = lookupvar("PWD");
14536 if (p) {
14537 struct stat st1, st2;
14538 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
14539 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14541 p = NULL;
14544 setpwd(p, 0);
14549 //usage:#define ash_trivial_usage
14550 //usage: "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]"
14551 //////// comes from ^^^^^^^^^^optletters
14552 //usage:#define ash_full_usage "\n\n"
14553 //usage: "Unix shell interpreter"
14556 * Process the shell command line arguments.
14558 static int
14559 procargs(char **argv)
14561 int i;
14562 const char *xminusc;
14563 char **xargv;
14564 int login_sh;
14566 xargv = argv;
14567 login_sh = xargv[0] && xargv[0][0] == '-';
14568 #if NUM_SCRIPTS > 0
14569 if (minusc)
14570 goto setarg0;
14571 #endif
14572 arg0 = xargv[0];
14573 /* if (xargv[0]) - mmm, this is always true! */
14574 xargv++;
14575 argptr = xargv;
14576 for (i = 0; i < NOPTS; i++)
14577 optlist[i] = 2;
14578 if (options(&login_sh)) {
14579 /* it already printed err message */
14580 raise_exception(EXERROR); /* does not return */
14582 xargv = argptr;
14583 xminusc = minusc;
14584 if (*xargv == NULL) {
14585 if (xminusc)
14586 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14587 sflag = 1;
14589 if (iflag == 2 /* no explicit -i given */
14590 && sflag == 1 /* -s given (or implied) */
14591 && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */
14592 && isatty(0) && isatty(1) /* we are on tty */
14594 iflag = 1;
14596 if (mflag == 2)
14597 mflag = iflag;
14598 /* Unset options which weren't explicitly set or unset */
14599 for (i = 0; i < NOPTS; i++)
14600 optlist[i] &= 1; /* same effect as "if (optlist[i] == 2) optlist[i] = 0;" */
14601 #if DEBUG == 2
14602 debug = 1;
14603 #endif
14604 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
14605 if (xminusc) {
14606 minusc = *xargv++;
14607 if (*xargv)
14608 goto setarg0;
14609 } else if (!sflag) {
14610 setinputfile(*xargv, 0);
14611 setarg0:
14612 arg0 = *xargv++;
14613 commandname = arg0;
14616 shellparam.p = xargv;
14617 #if ENABLE_ASH_GETOPTS
14618 shellparam.optind = 1;
14619 shellparam.optoff = -1;
14620 #endif
14621 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
14622 while (*xargv) {
14623 shellparam.nparam++;
14624 xargv++;
14627 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
14628 * Try:
14629 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
14630 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
14631 * NB: must do it before setting up signals (in optschanged())
14632 * and reading .profile etc (after we return from here):
14634 if (iflag)
14635 signal(SIGHUP, SIG_DFL);
14637 optschanged();
14639 return login_sh;
14643 * Read /etc/profile, ~/.profile, $ENV.
14645 static void
14646 read_profile(const char *name)
14648 name = expandstr(name, DQSYNTAX);
14649 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14650 return;
14651 cmdloop(0);
14652 popfile();
14655 #if PROFILE
14656 static short profile_buf[16384];
14657 extern int etext();
14658 #endif
14661 * Main routine. We initialize things, parse the arguments, execute
14662 * profiles if we're a login shell, and then call cmdloop to execute
14663 * commands. The setjmp call sets up the location to jump to when an
14664 * exception occurs. When an exception occurs the variable "state"
14665 * is used to figure out how far we had gotten.
14667 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14668 #if NUM_SCRIPTS > 0
14669 int ash_main(int argc, char **argv)
14670 #else
14671 int ash_main(int argc UNUSED_PARAM, char **argv)
14672 #endif
14673 /* note: 'argc' is used only if embedded scripts are enabled */
14675 volatile smallint state;
14676 struct jmploc jmploc;
14677 struct stackmark smark;
14678 int login_sh;
14680 /* Initialize global data */
14681 INIT_G_misc();
14682 INIT_G_memstack();
14683 INIT_G_var();
14684 #if ENABLE_ASH_ALIAS
14685 INIT_G_alias();
14686 #endif
14687 INIT_G_cmdtable();
14689 #if PROFILE
14690 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14691 #endif
14693 state = 0;
14694 if (setjmp(jmploc.loc)) {
14695 smallint e;
14696 smallint s;
14698 exitreset();
14700 e = exception_type;
14701 s = state;
14702 if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
14703 exitshell();
14706 reset();
14708 if (e == EXINT) {
14709 newline_and_flush(stderr);
14712 popstackmark(&smark);
14713 FORCE_INT_ON; /* enable interrupts */
14714 if (s == 1)
14715 goto state1;
14716 if (s == 2)
14717 goto state2;
14718 if (s == 3)
14719 goto state3;
14720 goto state4;
14722 exception_handler = &jmploc;
14723 rootpid = getpid();
14725 init();
14726 setstackmark(&smark);
14728 #if NUM_SCRIPTS > 0
14729 if (argc < 0)
14730 /* Non-NULL minusc tells procargs that an embedded script is being run */
14731 minusc = get_script_content(-argc - 1);
14732 #endif
14733 login_sh = procargs(argv);
14734 #if DEBUG
14735 TRACE(("Shell args: "));
14736 trace_puts_args(argv);
14737 #endif
14739 if (login_sh) {
14740 const char *hp;
14742 state = 1;
14743 read_profile("/etc/profile");
14744 state1:
14745 state = 2;
14746 hp = lookupvar("HOME");
14747 if (hp)
14748 read_profile("$HOME/.profile");
14750 state2:
14751 state = 3;
14752 if (iflag
14753 #ifndef linux
14754 && getuid() == geteuid() && getgid() == getegid()
14755 #endif
14757 const char *shinit = lookupvar("ENV");
14758 if (shinit != NULL && *shinit != '\0')
14759 read_profile(shinit);
14761 popstackmark(&smark);
14762 state3:
14763 state = 4;
14764 if (minusc) {
14765 /* evalstring pushes parsefile stack.
14766 * Ensure we don't falsely claim that 0 (stdin)
14767 * is one of stacked source fds.
14768 * Testcase: ash -c 'exec 1>&0' must not complain. */
14770 // if (!sflag) g_parsefile->pf_fd = -1;
14771 // ^^ not necessary since now we special-case fd 0
14772 // in save_fd_on_redirect()
14774 lineno = 0; // bash compat
14775 // dash: evalstring(minusc, sflag ? 0 : EV_EXIT);
14776 // The above makes
14777 // ash -sc 'echo $-'
14778 // continue reading input from stdin after running 'echo'.
14779 // bash does not do this: it prints "hBcs" and exits.
14780 evalstring(minusc, EV_EXIT);
14783 if (sflag || minusc == NULL) {
14784 #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
14785 if (line_input_state) {
14786 const char *hp = lookupvar("HISTFILE");
14787 if (!hp) {
14788 hp = lookupvar("HOME");
14789 if (hp) {
14790 INT_OFF;
14791 hp = concat_path_file(hp, ".ash_history");
14792 setvar0("HISTFILE", hp);
14793 free((char*)hp);
14794 INT_ON;
14795 hp = lookupvar("HISTFILE");
14798 if (hp)
14799 line_input_state->hist_file = xstrdup(hp);
14800 # if ENABLE_FEATURE_SH_HISTFILESIZE
14801 hp = lookupvar("HISTFILESIZE");
14802 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14803 # endif
14805 #endif
14806 state4: /* XXX ??? - why isn't this before the "if" statement */
14807 cmdloop(1);
14809 #if PROFILE
14810 monitor(0);
14811 #endif
14812 #ifdef GPROF
14814 extern void _mcleanup(void);
14815 _mcleanup();
14817 #endif
14818 TRACE(("End of main reached\n"));
14819 exitshell();
14820 /* NOTREACHED */
14825 * Copyright (c) 1989, 1991, 1993, 1994
14826 * The Regents of the University of California. All rights reserved.
14828 * This code is derived from software contributed to Berkeley by
14829 * Kenneth Almquist.
14831 * Redistribution and use in source and binary forms, with or without
14832 * modification, are permitted provided that the following conditions
14833 * are met:
14834 * 1. Redistributions of source code must retain the above copyright
14835 * notice, this list of conditions and the following disclaimer.
14836 * 2. Redistributions in binary form must reproduce the above copyright
14837 * notice, this list of conditions and the following disclaimer in the
14838 * documentation and/or other materials provided with the distribution.
14839 * 3. Neither the name of the University nor the names of its contributors
14840 * may be used to endorse or promote products derived from this software
14841 * without specific prior written permission.
14843 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
14844 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14845 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14846 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14847 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14848 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14849 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14850 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14851 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14852 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14853 * SUCH DAMAGE.