1 /* vi: set sw=4 ts=4: */
2 /*
3 * ash shell port for busybox
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Original BSD copyright notice is retained at the end of this file.
9 *
10 * Copyright (c) 1989, 1991, 1993, 1994
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
14 * was re-ported from NetBSD and debianized.
15 *
16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
17 */
18 //config:config SHELL_ASH
19 //config: bool #hidden option
20 //config: depends on !NOMMU
21 //config:
22 //config:config ASH
23 //config: bool "ash (78 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:
137 //config:config ASH_HELP
138 //config: bool "help builtin"
139 //config: default y
140 //config: depends on SHELL_ASH
141 //config:
142 //config:config ASH_GETOPTS
143 //config: bool "getopts builtin"
144 //config: default y
145 //config: depends on SHELL_ASH
146 //config:
147 //config:config ASH_CMDCMD
148 //config: bool "command builtin"
149 //config: default y
150 //config: depends on SHELL_ASH
151 //config: help
152 //config: Enable support for the 'command' builtin, which allows
153 //config: you to run the specified command or builtin,
154 //config: even when there is a function with the same name.
155 //config:
156 //config:endif # ash options
157
158 //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
159 // APPLET_ODDNAME:name main location suid_type help
160 //applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
161 //applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
162
163 //kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o
164 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
165
166 /*
167 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
168 * DEBUG=2 to compile in and turn on debugging.
169 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
170 * debugging info is written to ./trace, quit signal generates core dump.
171 */
172 #define DEBUG 0
173 /* Tweak debug output verbosity here */
174 #define DEBUG_TIME 0
175 #define DEBUG_PID 1
176 #define DEBUG_SIG 1
177 #define DEBUG_INTONOFF 0
178
179 #define PROFILE 0
180
181 #define JOBS ENABLE_ASH_JOB_CONTROL
182
183 #include <fnmatch.h>
184 #include <sys/times.h>
185 #include <sys/utsname.h> /* for setting $HOSTNAME */
186 #include "busybox.h" /* for applet_names */
187 #if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
188 # include "embedded_scripts.h"
189 #else
190 # define NUM_SCRIPTS 0
191 #endif
192
193 /* So far, all bash compat is controlled by one config option */
194 /* Separate defines document which part of code implements what */
195 /* function keyword */
196 #define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
197 #define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
198 /* &>file */
199 #define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
200 #define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
201 /* $'...' */
202 #define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
203 #define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
204 #define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
205 #define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
206 #define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
207 #define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
208 /* BASH_TEST2: [[ EXPR ]]
209 * Status of [[ support:
210 * && and || work as they should
211 * = is glob match operator, not equality operator: STR = GLOB
212 * == same as =
213 * =~ is regex match operator: STR =~ REGEX
214 * TODO:
215 * singleword+noglob expansion:
216 * v='a b'; [[ $v = 'a b' ]]; echo 0:$?
217 * [[ /bin/n* ]]; echo 0:$?
218 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
219 * ( ) < > should not have special meaning (IOW: should not require quoting)
220 * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*"
221 */
222 #define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
223 #define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
224 #define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
225 #define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
226 #define BASH_EPOCH_VARS ENABLE_ASH_BASH_COMPAT
227 #define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
228 #define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
229 #define BASH_READ_D ENABLE_ASH_BASH_COMPAT
230 #define IF_BASH_READ_D IF_ASH_BASH_COMPAT
231 #define BASH_WAIT_N ENABLE_ASH_BASH_COMPAT
232 /* <(...) and >(...) */
233 #if HAVE_DEV_FD
234 # define BASH_PROCESS_SUBST ENABLE_ASH_BASH_COMPAT
235 # define IF_BASH_PROCESS_SUBST IF_ASH_BASH_COMPAT
236 #else
237 # define BASH_PROCESS_SUBST 0
238 # define IF_BASH_PROCESS_SUBST(...)
239 #endif
240
241 #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
242 /* Bionic at least up to version 24 has no glob() */
243 # undef ENABLE_ASH_INTERNAL_GLOB
244 # define ENABLE_ASH_INTERNAL_GLOB 1
245 #endif
246
247 #if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
248 # error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
249 # error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
250 # error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
251 # error glob() should unbackslash them and match. uClibc does not unbackslash,
252 # error fails to match dirname, subsequently not expanding <pattern> in it.
253 // Testcase:
254 // if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
255 // if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
256 #endif
257
258 #if !ENABLE_ASH_INTERNAL_GLOB
259 # include <glob.h>
260 #endif
261
262 #include "unicode.h"
263 #include "shell_common.h"
264 #if ENABLE_FEATURE_SH_MATH
265 # include "math.h"
266 #else
267 typedef long arith_t;
268 # define ARITH_FMT "%ld"
269 #endif
270 #if ENABLE_ASH_RANDOM_SUPPORT
271 # include "random.h"
272 #else
273 # define CLEAR_RANDOM_T(rnd) ((void)0)
274 #endif
275
276 #include "NUM_APPLETS.h"
277 #if NUM_APPLETS == 1
278 /* STANDALONE does not make sense, and won't compile */
279 # undef CONFIG_FEATURE_SH_STANDALONE
280 # undef ENABLE_FEATURE_SH_STANDALONE
281 # undef IF_FEATURE_SH_STANDALONE
282 # undef IF_NOT_FEATURE_SH_STANDALONE
283 # define ENABLE_FEATURE_SH_STANDALONE 0
284 # define IF_FEATURE_SH_STANDALONE(...)
285 # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
286 #endif
287
288 #ifndef F_DUPFD_CLOEXEC
289 # define F_DUPFD_CLOEXEC F_DUPFD
290 #endif
291 #ifndef O_CLOEXEC
292 # define O_CLOEXEC 0
293 #endif
294 #ifndef PIPE_BUF
295 # define PIPE_BUF 4096 /* amount of buffering in a pipe */
296 #endif
297
298 #ifndef unlikely
299 # define unlikely(cond) (cond)
300 #endif
301
302 #if !BB_MMU
303 # error "Do not even bother, ash will not run on NOMMU machine"
304 #endif
305
306 /* ============ Hash table sizes. Configurable. */
307
308 #define VTABSIZE 39
309 #define ATABSIZE 39
310 #define CMDTABLESIZE 31 /* should be prime */
311
312
313 /* ============ Shell options */
314
315 /* If you add/change options hare, update --help text too */
316 static const char *const optletters_optnames[] = {
317 "e" "errexit",
318 "f" "noglob",
319 /* bash has '-o ignoreeof', but no short synonym -I for it */
320 /* (in bash, set -I disables invisible variables (what's that?)) */
321 "I" "ignoreeof",
322 /* The below allowed this invocation:
323 * ash -c 'set -i; echo $-; sleep 5; echo $-'
324 * to be ^C-ed and get to interactive ash prompt.
325 * bash does not support such "set -i".
326 * In our code, this is denoted by empty long name:
327 */
328 "i" "",
329 /* (removing "i" altogether would remove it from "$-", not good) */
330 "m" "monitor",
331 "n" "noexec",
332 /* Ditto: bash has no "set -s", "set -c" */
333 "s" "",
334 "c" "",
335 "x" "xtrace",
336 "v" "verbose",
337 "C" "noclobber",
338 "a" "allexport",
339 "b" "notify",
340 "u" "nounset",
341 "E" "errtrace",
342 "\0" "vi"
343 #if BASH_PIPEFAIL
344 ,"\0" "pipefail"
345 #endif
346 #if DEBUG
347 ,"\0" "nolog"
348 ,"\0" "debug"
349 #endif
350 };
351 //bash 4.4.23 also has these opts (with these defaults):
352 //braceexpand on
353 //emacs on
354 //errtrace off
355 //functrace off
356 //hashall on
357 //histexpand off
358 //history on
359 //interactive-comments on
360 //keyword off
361 //onecmd off
362 //physical off
363 //posix off
364 //privileged off
365
366 #define optletters(n) optletters_optnames[n][0]
367 #define optnames(n) (optletters_optnames[n] + 1)
368
369 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
370
371
372 /* ============ Misc data */
373
374 #define msg_illnum "Illegal number: %s"
375
376 /*
377 * We enclose jmp_buf in a structure so that we can declare pointers to
378 * jump locations. The global variable handler contains the location to
379 * jump to when an exception occurs, and the global variable exception_type
380 * contains a code identifying the exception. To implement nested
381 * exception handlers, the user should save the value of handler on entry
382 * to an inner scope, set handler to point to a jmploc structure for the
383 * inner scope, and restore handler on exit from the scope.
384 */
385 struct jmploc {
386 jmp_buf loc;
387 };
388
389 struct globals_misc {
390 uint8_t exitstatus; /* exit status of last command */
391 uint8_t back_exitstatus;/* exit status of backquoted command */
392 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
393 smallint inps4; /* Prevent PS4 nesting. */
394 int savestatus; /* exit status of last command outside traps */
395 int rootpid; /* pid of main shell */
396 /* shell level: 0 for the main shell, 1 for its children, and so on */
397 int shlvl;
398 #define rootshell (!shlvl)
399 int errlinno;
400
401 char *minusc; /* argument to -c option */
402
403 char *curdir; // = nullstr; /* current working directory */
404 char *physdir; // = nullstr; /* physical working directory */
405
406 char *arg0; /* value of $0 */
407
408 struct jmploc *exception_handler;
409
410 volatile int suppress_int; /* counter */
411 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
412 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
413 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
414 smallint exception_type; /* kind of exception: */
415 #define EXINT 0 /* SIGINT received */
416 #define EXERROR 1 /* a generic error */
417 #define EXEND 3 /* exit the shell */
418 #define EXEXIT 4 /* exit the shell via exitcmd */
419
420 char nullstr[1]; /* zero length string */
421
422 char optlist[NOPTS];
423 #define eflag optlist[0]
424 #define fflag optlist[1]
425 #define Iflag optlist[2]
426 #define iflag optlist[3]
427 #define mflag optlist[4]
428 #define nflag optlist[5]
429 #define sflag optlist[6]
430 #define cflag optlist[7]
431 #define xflag optlist[8]
432 #define vflag optlist[9]
433 #define Cflag optlist[10]
434 #define aflag optlist[11]
435 #define bflag optlist[12]
436 #define uflag optlist[13]
437 #define Eflag optlist[14]
438 #define viflag optlist[15]
439 #if BASH_PIPEFAIL
440 # define pipefail optlist[16]
441 #else
442 # define pipefail 0
443 #endif
444 #if DEBUG
445 # define nolog optlist[16 + BASH_PIPEFAIL]
446 # define debug optlist[17 + BASH_PIPEFAIL]
447 #endif
448
449 /* trap handler commands */
450 /*
451 * Sigmode records the current value of the signal handlers for the various
452 * modes. A value of zero means that the current handler is not known.
453 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
454 */
455 char sigmode[NSIG - 1];
456 #define S_DFL 1 /* default signal handling (SIG_DFL) */
457 #define S_CATCH 2 /* signal is caught */
458 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
459 #define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
460
461 /* indicates specified signal received */
462 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
463 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
464 char *trap[NSIG + 1];
465 /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */
466 #define NTRAP_ERR NSIG
467 #define NTRAP_LAST NSIG
468
469 char **trap_ptr; /* used only by "trap hack" */
470
471 /* Rarely referenced stuff */
472 #if ENABLE_ASH_RANDOM_SUPPORT
473 random_t random_gen;
474 #endif
475 pid_t backgndpid; /* pid of last background process */
476 };
477 extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
478 #define G_misc (*ash_ptr_to_globals_misc)
479 #define exitstatus (G_misc.exitstatus )
480 #define back_exitstatus (G_misc.back_exitstatus )
481 #define job_warning (G_misc.job_warning)
482 #define inps4 (G_misc.inps4 )
483 #define savestatus (G_misc.savestatus )
484 #define rootpid (G_misc.rootpid )
485 #define shlvl (G_misc.shlvl )
486 #define errlinno (G_misc.errlinno )
487 #define minusc (G_misc.minusc )
488 #define curdir (G_misc.curdir )
489 #define physdir (G_misc.physdir )
490 #define arg0 (G_misc.arg0 )
491 #define exception_handler (G_misc.exception_handler)
492 #define exception_type (G_misc.exception_type )
493 #define suppress_int (G_misc.suppress_int )
494 #define pending_int (G_misc.pending_int )
495 #define got_sigchld (G_misc.got_sigchld )
496 #define pending_sig (G_misc.pending_sig )
497 #define nullstr (G_misc.nullstr )
498 #define optlist (G_misc.optlist )
499 #define sigmode (G_misc.sigmode )
500 #define gotsig (G_misc.gotsig )
501 #define may_have_traps (G_misc.may_have_traps )
502 #define trap (G_misc.trap )
503 #define trap_ptr (G_misc.trap_ptr )
504 #define random_gen (G_misc.random_gen )
505 #define backgndpid (G_misc.backgndpid )
506 #define INIT_G_misc() do { \
507 XZALLOC_CONST_PTR(&ash_ptr_to_globals_misc, sizeof(G_misc)); \
508 savestatus = -1; \
509 curdir = nullstr; \
510 physdir = nullstr; \
511 trap_ptr = trap; \
512 } while (0)
513
514
515 /* ============ DEBUG */
516 #if DEBUG
517 static void trace_printf(const char *fmt, ...);
518 static void trace_vprintf(const char *fmt, va_list va);
519 # define TRACE(param) trace_printf param
520 # define TRACEV(param) trace_vprintf param
521 # define close(fd) do { \
522 int dfd = (fd); \
523 if (close(dfd) < 0) \
524 bb_error_msg("bug on %d: closing %d(0x%x)", \
525 __LINE__, dfd, dfd); \
526 } while (0)
527 #else
528 # define TRACE(param)
529 # define TRACEV(param)
530 #endif
531
532
533 /* ============ Utility functions */
534 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
535 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
536
537 static int
isdigit_str9(const char * str)538 isdigit_str9(const char *str)
539 {
540 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
541 while (--maxlen && isdigit(*str))
542 str++;
543 return (*str == '\0');
544 }
545
546 static const char *
var_end(const char * var)547 var_end(const char *var)
548 {
549 while (*var)
550 if (*var++ == '=')
551 break;
552 return var;
553 }
554
555
556 /* ============ Parser data */
557
558 /*
559 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
560 */
561 struct strlist {
562 struct strlist *next;
563 char *text;
564 };
565
566 struct alias;
567
568 struct strpush {
569 struct strpush *prev; /* preceding string on stack */
570 char *prev_string;
571 int prev_left_in_line;
572 #if ENABLE_ASH_ALIAS
573 struct alias *ap; /* if push was associated with an alias */
574 #endif
575 char *string; /* remember the string since it may change */
576
577 /* Delay freeing so we can stop nested aliases. */
578 struct strpush *spfree;
579
580 /* Remember last two characters for pungetc. */
581 int lastc[2];
582
583 /* Number of outstanding calls to pungetc. */
584 int unget;
585 };
586
587 /*
588 * The parsefile structure pointed to by the global variable parsefile
589 * contains information about the current file being read.
590 */
591 struct parsefile {
592 struct parsefile *prev; /* preceding file on stack */
593 int linno; /* current line */
594 int pf_fd; /* file descriptor (or -1 if string) */
595 int left_in_line; /* number of chars left in this line */
596 int left_in_buffer; /* number of chars left in this buffer past the line */
597 char *next_to_pgetc; /* next char in buffer */
598 char *buf; /* input buffer */
599 struct strpush *strpush; /* for pushing strings at this level */
600 struct strpush basestrpush; /* so pushing one is fast */
601
602 /* Delay freeing so we can stop nested aliases. */
603 struct strpush *spfree;
604
605 /* Remember last two characters for pungetc. */
606 int lastc[2];
607
608 /* Number of outstanding calls to pungetc. */
609 int unget;
610 };
611
612 static struct parsefile basepf; /* top level input file */
613 static struct parsefile *g_parsefile = &basepf; /* current input file */
614 static char *commandname; /* currently executing command */
615
616
617 /* ============ Interrupts / exceptions */
618
619 static void exitshell(void) NORETURN;
620
621 /*
622 * These macros allow the user to suspend the handling of interrupt signals
623 * over a period of time. This is similar to SIGHOLD or to sigblock, but
624 * much more efficient and portable. (But hacking the kernel is so much
625 * more fun than worrying about efficiency and portability. :-))
626 */
627 #if DEBUG_INTONOFF
628 # define INT_OFF do { \
629 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
630 suppress_int++; \
631 barrier(); \
632 } while (0)
633 #else
634 # define INT_OFF do { \
635 suppress_int++; \
636 barrier(); \
637 } while (0)
638 #endif
639
640 /*
641 * Called to raise an exception. Since C doesn't include exceptions, we
642 * just do a longjmp to the exception handler. The type of exception is
643 * stored in the global variable "exception_type".
644 */
645 static void raise_exception(int) NORETURN;
646 static void
raise_exception(int e)647 raise_exception(int e)
648 {
649 #if DEBUG
650 if (exception_handler == NULL)
651 abort();
652 #endif
653 INT_OFF;
654 exception_type = e;
655 longjmp(exception_handler->loc, 1);
656 }
657 #if DEBUG
658 #define raise_exception(e) do { \
659 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
660 raise_exception(e); \
661 } while (0)
662 #endif
663
664 /*
665 * Called when a SIGINT is received. (If the user specifies
666 * that SIGINT is to be trapped or ignored using the trap builtin, then
667 * this routine is not called.) Suppressint is nonzero when interrupts
668 * are held using the INT_OFF macro. (The test for iflag is just
669 * defensive programming.)
670 */
671 static void raise_interrupt(void) NORETURN;
672 static void
raise_interrupt(void)673 raise_interrupt(void)
674 {
675 pending_int = 0;
676 /* Signal is not automatically unmasked after it is raised,
677 * do it ourself - unmask all signals */
678 sigprocmask_allsigs(SIG_UNBLOCK);
679 /* pending_sig = 0; - now done in signal_handler() */
680
681 if (!(rootshell && iflag)) {
682 /* Kill ourself with SIGINT */
683 signal(SIGINT, SIG_DFL);
684 raise(SIGINT);
685 }
686 /* bash: ^C even on empty command line sets $? */
687 exitstatus = SIGINT + 128;
688 raise_exception(EXINT);
689 /* NOTREACHED */
690 }
691 #if DEBUG
692 #define raise_interrupt() do { \
693 TRACE(("raising interrupt on line %d\n", __LINE__)); \
694 raise_interrupt(); \
695 } while (0)
696 #endif
697
IF_ASH_OPTIMIZE_FOR_SIZE(inline)698 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
699 int_on(void)
700 {
701 barrier();
702 if (--suppress_int == 0 && pending_int) {
703 raise_interrupt();
704 }
705 }
706 #if DEBUG_INTONOFF
707 # define INT_ON do { \
708 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
709 int_on(); \
710 } while (0)
711 #else
712 # define INT_ON int_on()
713 #endif
IF_ASH_OPTIMIZE_FOR_SIZE(inline)714 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
715 force_int_on(void)
716 {
717 barrier();
718 suppress_int = 0;
719 if (pending_int)
720 raise_interrupt();
721 }
722 #define FORCE_INT_ON force_int_on()
723
724 #define SAVE_INT(v) ((v) = suppress_int)
725
726 #define RESTORE_INT(v) do { \
727 barrier(); \
728 suppress_int = (v); \
729 if (suppress_int == 0 && pending_int) \
730 raise_interrupt(); \
731 } while (0)
732
733
734 /* ============ Stdout/stderr output */
735
736 static void
outstr(const char * p,FILE * file)737 outstr(const char *p, FILE *file)
738 {
739 INT_OFF;
740 fputs(p, file);
741 INT_ON;
742 }
743
744 static void
flush_stdout_stderr(void)745 flush_stdout_stderr(void)
746 {
747 INT_OFF;
748 fflush_all();
749 INT_ON;
750 }
751
752 /* Was called outcslow(c,FILE*), but c was always '\n' */
753 static void
newline_and_flush(FILE * dest)754 newline_and_flush(FILE *dest)
755 {
756 INT_OFF;
757 putc('\n', dest);
758 fflush(dest);
759 INT_ON;
760 }
761
762 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
763 static int
out1fmt(const char * fmt,...)764 out1fmt(const char *fmt, ...)
765 {
766 va_list ap;
767 int r;
768
769 INT_OFF;
770 va_start(ap, fmt);
771 r = vprintf(fmt, ap);
772 va_end(ap);
773 INT_ON;
774 return r;
775 }
776
777 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
778 static int
fmtstr(char * outbuf,size_t length,const char * fmt,...)779 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
780 {
781 va_list ap;
782 int ret;
783
784 INT_OFF;
785 va_start(ap, fmt);
786 ret = vsnprintf(outbuf, length, fmt, ap);
787 va_end(ap);
788 INT_ON;
789 return ret > (int)length ? length : ret;
790 }
791
792 static void
out1str(const char * p)793 out1str(const char *p)
794 {
795 outstr(p, stdout);
796 }
797
798 static void
out2str(const char * p)799 out2str(const char *p)
800 {
801 outstr(p, stderr);
802 flush_stdout_stderr();
803 }
804
805
806 /* ============ Parser structures */
807
808 /* control characters in argument strings */
809 #define CTL_FIRST CTLESC
810 #define CTLESC ((unsigned char)'\201') /* escape next character */
811 #define CTLVAR ((unsigned char)'\202') /* variable defn */
812 #define CTLENDVAR ((unsigned char)'\203')
813 #define CTLBACKQ ((unsigned char)'\204')
814 #define CTLARI ((unsigned char)'\206') /* arithmetic expression */
815 #define CTLENDARI ((unsigned char)'\207')
816 #define CTLQUOTEMARK ((unsigned char)'\210')
817 #define CTL_LAST CTLQUOTEMARK
818 #if BASH_PROCESS_SUBST
819 # define CTLTOPROC ((unsigned char)'\211')
820 # define CTLFROMPROC ((unsigned char)'\212')
821 # undef CTL_LAST
822 # define CTL_LAST CTLFROMPROC
823 #endif
824
825 /* variable substitution byte (follows CTLVAR) */
826 #define VSTYPE 0x0f /* type of variable substitution */
827 #define VSNUL 0x10 /* colon--treat the empty string as unset */
828
829 /* values of VSTYPE field */
830 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
831 #define VSMINUS 0x2 /* ${var-text} */
832 #define VSPLUS 0x3 /* ${var+text} */
833 #define VSQUESTION 0x4 /* ${var?message} */
834 #define VSASSIGN 0x5 /* ${var=text} */
835 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
836 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
837 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
838 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
839 #define VSLENGTH 0xa /* ${#var} */
840 #if BASH_SUBSTR
841 #define VSSUBSTR 0xc /* ${var:position:length} */
842 #endif
843 #if BASH_PATTERN_SUBST
844 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
845 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
846 #endif
847
848 static const char dolatstr[] ALIGN1 = {
849 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
850 };
851 #define DOLATSTRLEN 6
852
853 #define NCMD 0
854 #define NPIPE 1
855 #define NREDIR 2
856 #define NBACKGND 3
857 #define NSUBSHELL 4
858 #define NAND 5
859 #define NOR 6
860 #define NSEMI 7
861 #define NIF 8
862 #define NWHILE 9
863 #define NUNTIL 10
864 #define NFOR 11
865 #define NCASE 12
866 #define NCLIST 13
867 #define NDEFUN 14
868 #define NARG 15
869 #define NTO 16
870 #if BASH_REDIR_OUTPUT
871 #define NTO2 17
872 #endif
873 #define NCLOBBER 18
874 #define NFROM 19
875 #define NFROMTO 20
876 #define NAPPEND 21
877 #define NTOFD 22
878 #define NFROMFD 23
879 #define NHERE 24
880 #define NXHERE 25
881 #define NNOT 26
882 #define N_NUMBER 27
883
884 union node;
885
886 struct ncmd {
887 smallint type; /* Nxxxx */
888 int linno;
889 union node *assign;
890 union node *args;
891 union node *redirect;
892 };
893
894 struct npipe {
895 smallint type;
896 smallint pipe_backgnd;
897 struct nodelist *cmdlist;
898 };
899
900 struct nredir {
901 smallint type;
902 int linno;
903 union node *n;
904 union node *redirect;
905 };
906
907 struct nbinary {
908 smallint type;
909 union node *ch1;
910 union node *ch2;
911 };
912
913 struct nif {
914 smallint type;
915 union node *test;
916 union node *ifpart;
917 union node *elsepart;
918 };
919
920 struct nfor {
921 smallint type;
922 int linno;
923 union node *args;
924 union node *body;
925 char *var;
926 };
927
928 struct ncase {
929 smallint type;
930 int linno;
931 union node *expr;
932 union node *cases;
933 };
934
935 struct nclist {
936 smallint type;
937 union node *next;
938 union node *pattern;
939 union node *body;
940 };
941
942 struct ndefun {
943 smallint type;
944 int linno;
945 char *text;
946 union node *body;
947 };
948
949 struct narg {
950 smallint type;
951 union node *next;
952 char *text;
953 struct nodelist *backquote;
954 };
955
956 /* nfile and ndup layout must match!
957 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
958 * that it is actually NTO2 (>&file), and change its type.
959 */
960 struct nfile {
961 smallint type;
962 union node *next;
963 int fd;
964 int _unused_dupfd;
965 union node *fname;
966 char *expfname;
967 };
968
969 struct ndup {
970 smallint type;
971 union node *next;
972 int fd;
973 int dupfd;
974 union node *vname;
975 char *_unused_expfname;
976 };
977
978 struct nhere {
979 smallint type;
980 union node *next;
981 int fd;
982 union node *doc;
983 };
984
985 struct nnot {
986 smallint type;
987 union node *com;
988 };
989
990 union node {
991 smallint type;
992 struct ncmd ncmd;
993 struct npipe npipe;
994 struct nredir nredir;
995 struct nbinary nbinary;
996 struct nif nif;
997 struct nfor nfor;
998 struct ncase ncase;
999 struct nclist nclist;
1000 struct ndefun ndefun;
1001 struct narg narg;
1002 struct nfile nfile;
1003 struct ndup ndup;
1004 struct nhere nhere;
1005 struct nnot nnot;
1006 };
1007
1008 /*
1009 * NODE_EOF is returned by parsecmd when it encounters an end of file.
1010 * It must be distinct from NULL.
1011 */
1012 #define NODE_EOF ((union node *) -1L)
1013
1014 struct nodelist {
1015 struct nodelist *next;
1016 union node *n;
1017 };
1018
1019 struct funcnode {
1020 int count;
1021 union node n;
1022 };
1023
1024 /*
1025 * Free a parse tree.
1026 */
1027 static void
freefunc(struct funcnode * f)1028 freefunc(struct funcnode *f)
1029 {
1030 if (f && --f->count < 0)
1031 free(f);
1032 }
1033
1034
1035 /* ============ Debugging output */
1036
1037 #if DEBUG
1038
1039 static FILE *tracefile;
1040
1041 static void
trace_printf(const char * fmt,...)1042 trace_printf(const char *fmt, ...)
1043 {
1044 va_list va;
1045
1046 if (debug != 1)
1047 return;
1048 if (DEBUG_TIME)
1049 fprintf(tracefile, "%u ", (int) time(NULL));
1050 if (DEBUG_PID)
1051 fprintf(tracefile, "[%u] ", (int) getpid());
1052 if (DEBUG_SIG)
1053 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
1054 va_start(va, fmt);
1055 vfprintf(tracefile, fmt, va);
1056 va_end(va);
1057 }
1058
1059 static void
trace_vprintf(const char * fmt,va_list va)1060 trace_vprintf(const char *fmt, va_list va)
1061 {
1062 if (debug != 1)
1063 return;
1064 vfprintf(tracefile, fmt, va);
1065 fprintf(tracefile, "\n");
1066 }
1067
1068 static void
trace_puts(const char * s)1069 trace_puts(const char *s)
1070 {
1071 if (debug != 1)
1072 return;
1073 fputs(s, tracefile);
1074 }
1075
1076 static void
trace_puts_quoted(char * s)1077 trace_puts_quoted(char *s)
1078 {
1079 char *p;
1080 char c;
1081
1082 if (debug != 1)
1083 return;
1084 putc('"', tracefile);
1085 for (p = s; *p; p++) {
1086 switch ((unsigned char)*p) {
1087 case '\n': c = 'n'; goto backslash;
1088 case '\t': c = 't'; goto backslash;
1089 case '\r': c = 'r'; goto backslash;
1090 case '\"': c = '\"'; goto backslash;
1091 case '\\': c = '\\'; goto backslash;
1092 case CTLESC: c = 'e'; goto backslash;
1093 case CTLVAR: c = 'v'; goto backslash;
1094 case CTLBACKQ: c = 'q'; goto backslash;
1095 #if BASH_PROCESS_SUBST
1096 case CTLTOPROC: c = 'p'; goto backslash;
1097 case CTLFROMPROC: c = 'P'; goto backslash;
1098 #endif
1099 backslash:
1100 putc('\\', tracefile);
1101 putc(c, tracefile);
1102 break;
1103 default:
1104 if (*p >= ' ' && *p <= '~')
1105 putc(*p, tracefile);
1106 else {
1107 putc('\\', tracefile);
1108 putc((*p >> 6) & 03, tracefile);
1109 putc((*p >> 3) & 07, tracefile);
1110 putc(*p & 07, tracefile);
1111 }
1112 break;
1113 }
1114 }
1115 putc('"', tracefile);
1116 }
1117
1118 static void
trace_puts_args(char ** ap)1119 trace_puts_args(char **ap)
1120 {
1121 if (debug != 1)
1122 return;
1123 if (!*ap)
1124 return;
1125 while (1) {
1126 trace_puts_quoted(*ap);
1127 if (!*++ap) {
1128 putc('\n', tracefile);
1129 break;
1130 }
1131 putc(' ', tracefile);
1132 }
1133 }
1134
1135 static void
opentrace(void)1136 opentrace(void)
1137 {
1138 char s[100];
1139 #ifdef O_APPEND
1140 int flags;
1141 #endif
1142
1143 if (debug != 1) {
1144 if (tracefile)
1145 fflush(tracefile);
1146 /* leave open because libedit might be using it */
1147 return;
1148 }
1149 strcpy(s, "./trace");
1150 if (tracefile) {
1151 if (!freopen(s, "a", tracefile)) {
1152 fprintf(stderr, "Can't re-open %s\n", s);
1153 debug = 0;
1154 return;
1155 }
1156 } else {
1157 tracefile = fopen(s, "a");
1158 if (tracefile == NULL) {
1159 fprintf(stderr, "Can't open %s\n", s);
1160 debug = 0;
1161 return;
1162 }
1163 }
1164 #ifdef O_APPEND
1165 flags = fcntl(fileno(tracefile), F_GETFL);
1166 if (flags >= 0)
1167 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1168 #endif
1169 setlinebuf(tracefile);
1170 fputs("\nTracing started.\n", tracefile);
1171 }
1172
1173 static void
indent(int amount,char * pfx,FILE * fp)1174 indent(int amount, char *pfx, FILE *fp)
1175 {
1176 int i;
1177
1178 for (i = 0; i < amount; i++) {
1179 if (pfx && i == amount - 1)
1180 fputs(pfx, fp);
1181 putc('\t', fp);
1182 }
1183 }
1184
1185 /* little circular references here... */
1186 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1187
1188 static void
sharg(union node * arg,FILE * fp)1189 sharg(union node *arg, FILE *fp)
1190 {
1191 char *p;
1192 struct nodelist *bqlist;
1193 unsigned char subtype;
1194
1195 if (arg->type != NARG) {
1196 out1fmt("<node type %d>\n", arg->type);
1197 abort();
1198 }
1199 bqlist = arg->narg.backquote;
1200 for (p = arg->narg.text; *p; p++) {
1201 switch ((unsigned char)*p) {
1202 case CTLESC:
1203 p++;
1204 putc(*p, fp);
1205 break;
1206 case CTLVAR:
1207 putc('$', fp);
1208 putc('{', fp);
1209 subtype = *++p;
1210 if (subtype == VSLENGTH)
1211 putc('#', fp);
1212
1213 while (*p != '=') {
1214 putc(*p, fp);
1215 p++;
1216 }
1217
1218 if (subtype & VSNUL)
1219 putc(':', fp);
1220
1221 switch (subtype & VSTYPE) {
1222 case VSNORMAL:
1223 putc('}', fp);
1224 break;
1225 case VSMINUS:
1226 putc('-', fp);
1227 break;
1228 case VSPLUS:
1229 putc('+', fp);
1230 break;
1231 case VSQUESTION:
1232 putc('?', fp);
1233 break;
1234 case VSASSIGN:
1235 putc('=', fp);
1236 break;
1237 case VSTRIMLEFT:
1238 putc('#', fp);
1239 break;
1240 case VSTRIMLEFTMAX:
1241 putc('#', fp);
1242 putc('#', fp);
1243 break;
1244 case VSTRIMRIGHT:
1245 putc('%', fp);
1246 break;
1247 case VSTRIMRIGHTMAX:
1248 putc('%', fp);
1249 putc('%', fp);
1250 break;
1251 case VSLENGTH:
1252 break;
1253 default:
1254 out1fmt("<subtype %d>", subtype);
1255 }
1256 break;
1257 case CTLENDVAR:
1258 putc('}', fp);
1259 break;
1260 #if BASH_PROCESS_SUBST
1261 case CTLTOPROC:
1262 putc('>', fp);
1263 goto backq;
1264 case CTLFROMPROC:
1265 putc('<', fp);
1266 goto backq;
1267 #endif
1268 case CTLBACKQ:
1269 putc('$', fp);
1270 IF_BASH_PROCESS_SUBST(backq:)
1271 putc('(', fp);
1272 shtree(bqlist->n, -1, NULL, fp);
1273 putc(')', fp);
1274 break;
1275 default:
1276 putc(*p, fp);
1277 break;
1278 }
1279 }
1280 }
1281
1282 static void
shcmd(union node * cmd,FILE * fp)1283 shcmd(union node *cmd, FILE *fp)
1284 {
1285 union node *np;
1286 int first;
1287 const char *s;
1288 int dftfd;
1289
1290 first = 1;
1291 for (np = cmd->ncmd.args; np; np = np->narg.next) {
1292 if (!first)
1293 putc(' ', fp);
1294 sharg(np, fp);
1295 first = 0;
1296 }
1297 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1298 if (!first)
1299 putc(' ', fp);
1300 dftfd = 0;
1301 switch (np->nfile.type) {
1302 case NTO: s = ">>"+1; dftfd = 1; break;
1303 case NCLOBBER: s = ">|"; dftfd = 1; break;
1304 case NAPPEND: s = ">>"; dftfd = 1; break;
1305 #if BASH_REDIR_OUTPUT
1306 case NTO2:
1307 #endif
1308 case NTOFD: s = ">&"; dftfd = 1; break;
1309 case NFROM: s = "<"; break;
1310 case NFROMFD: s = "<&"; break;
1311 case NFROMTO: s = "<>"; break;
1312 default: s = "*error*"; break;
1313 }
1314 if (np->nfile.fd != dftfd)
1315 fprintf(fp, "%d", np->nfile.fd);
1316 fputs(s, fp);
1317 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1318 fprintf(fp, "%d", np->ndup.dupfd);
1319 } else {
1320 sharg(np->nfile.fname, fp);
1321 }
1322 first = 0;
1323 }
1324 }
1325
1326 static void
shtree(union node * n,int ind,char * pfx,FILE * fp)1327 shtree(union node *n, int ind, char *pfx, FILE *fp)
1328 {
1329 struct nodelist *lp;
1330 const char *s;
1331
1332 if (n == NULL)
1333 return;
1334
1335 indent(ind, pfx, fp);
1336
1337 if (n == NODE_EOF) {
1338 fputs("<EOF>", fp);
1339 return;
1340 }
1341
1342 switch (n->type) {
1343 case NSEMI:
1344 s = "; ";
1345 goto binop;
1346 case NAND:
1347 s = " && ";
1348 goto binop;
1349 case NOR:
1350 s = " || ";
1351 binop:
1352 shtree(n->nbinary.ch1, ind, NULL, fp);
1353 /* if (ind < 0) */
1354 fputs(s, fp);
1355 shtree(n->nbinary.ch2, ind, NULL, fp);
1356 break;
1357 case NCMD:
1358 shcmd(n, fp);
1359 if (ind >= 0)
1360 putc('\n', fp);
1361 break;
1362 case NPIPE:
1363 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1364 shtree(lp->n, 0, NULL, fp);
1365 if (lp->next)
1366 fputs(" | ", fp);
1367 }
1368 if (n->npipe.pipe_backgnd)
1369 fputs(" &", fp);
1370 if (ind >= 0)
1371 putc('\n', fp);
1372 break;
1373 default:
1374 fprintf(fp, "<node type %d>", n->type);
1375 if (ind >= 0)
1376 putc('\n', fp);
1377 break;
1378 }
1379 }
1380
1381 static void
showtree(union node * n)1382 showtree(union node *n)
1383 {
1384 trace_puts("showtree called\n");
1385 shtree(n, 1, NULL, stderr);
1386 }
1387
1388 #endif /* DEBUG */
1389
1390
1391 /* ============ Message printing */
1392
1393 static void
ash_vmsg(const char * msg,va_list ap)1394 ash_vmsg(const char *msg, va_list ap)
1395 {
1396 fprintf(stderr, "%s: ", arg0);
1397 if (commandname) {
1398 if (strcmp(arg0, commandname))
1399 fprintf(stderr, "%s: ", commandname);
1400 if (!iflag || g_parsefile->pf_fd > 0)
1401 fprintf(stderr, "line %d: ", errlinno);
1402 }
1403 vfprintf(stderr, msg, ap);
1404 newline_and_flush(stderr);
1405 }
1406
1407 /*
1408 * Exverror is called to raise the error exception. If the second argument
1409 * is not NULL then error prints an error message using printf style
1410 * formatting. It then raises the error exception.
1411 */
1412 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1413 static void
ash_vmsg_and_raise(int cond,const char * msg,va_list ap)1414 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1415 {
1416 #if DEBUG
1417 if (msg) {
1418 TRACE(("ash_vmsg_and_raise(%d):", cond));
1419 TRACEV((msg, ap));
1420 } else
1421 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1422 if (msg)
1423 #endif
1424 ash_vmsg(msg, ap);
1425
1426 flush_stdout_stderr();
1427 raise_exception(cond);
1428 /* NOTREACHED */
1429 }
1430
1431 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1432 static void
ash_msg_and_raise_error(const char * msg,...)1433 ash_msg_and_raise_error(const char *msg, ...)
1434 {
1435 va_list ap;
1436
1437 exitstatus = 2;
1438
1439 va_start(ap, msg);
1440 ash_vmsg_and_raise(EXERROR, msg, ap);
1441 /* NOTREACHED */
1442 va_end(ap);
1443 }
1444
1445 /*
1446 * 'fmt' must be a string literal.
1447 */
1448 #define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
1449
1450 static void raise_error_syntax(const char *) NORETURN;
1451 static void
raise_error_syntax(const char * msg)1452 raise_error_syntax(const char *msg)
1453 {
1454 errlinno = g_parsefile->linno;
1455 ash_msg_and_raise_error("syntax error: %s", msg);
1456 /* NOTREACHED */
1457 }
1458
1459 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1460 static void
ash_msg_and_raise(int cond,const char * msg,...)1461 ash_msg_and_raise(int cond, const char *msg, ...)
1462 {
1463 va_list ap;
1464
1465 va_start(ap, msg);
1466 ash_vmsg_and_raise(cond, msg, ap);
1467 /* NOTREACHED */
1468 va_end(ap);
1469 }
1470
1471 /*
1472 * error/warning routines for external builtins
1473 */
1474 static void
ash_msg(const char * fmt,...)1475 ash_msg(const char *fmt, ...)
1476 {
1477 va_list ap;
1478
1479 va_start(ap, fmt);
1480 ash_vmsg(fmt, ap);
1481 va_end(ap);
1482 }
1483
1484 /*
1485 * Return a string describing an error. The returned string may be a
1486 * pointer to a static buffer that will be overwritten on the next call.
1487 * Action describes the operation that got the error.
1488 */
1489 static const char *
errmsg(int e,const char * em)1490 errmsg(int e, const char *em)
1491 {
1492 if (e == ENOENT || e == ENOTDIR) {
1493 return em;
1494 }
1495 return strerror(e);
1496 }
1497
1498
1499 /* ============ Memory allocation */
1500
1501 #if 0
1502 /* I consider these wrappers nearly useless:
1503 * ok, they return you to nearest exception handler, but
1504 * how much memory do you leak in the process, making
1505 * memory starvation worse?
1506 */
1507 static void *
1508 ckrealloc(void * p, size_t nbytes)
1509 {
1510 p = realloc(p, nbytes);
1511 if (!p)
1512 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1513 return p;
1514 }
1515
1516 static void *
1517 ckmalloc(size_t nbytes)
1518 {
1519 return ckrealloc(NULL, nbytes);
1520 }
1521
1522 static void *
1523 ckzalloc(size_t nbytes)
1524 {
1525 return memset(ckmalloc(nbytes), 0, nbytes);
1526 }
1527
1528 static char *
1529 ckstrdup(const char *s)
1530 {
1531 char *p = strdup(s);
1532 if (!p)
1533 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1534 return p;
1535 }
1536 #else
1537 /* Using bbox equivalents. They exit if out of memory */
1538 # define ckrealloc xrealloc
1539 # define ckmalloc xmalloc
1540 # define ckzalloc xzalloc
1541 # define ckstrdup xstrdup
1542 #endif
1543
1544 /*
1545 * It appears that grabstackstr() will barf with such alignments
1546 * because stalloc() will return a string allocated in a new stackblock.
1547 */
1548 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1549 enum {
1550 /* Most machines require the value returned from malloc to be aligned
1551 * in some way. The following macro will get this right
1552 * on many machines. */
1553 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1554 /* Minimum size of a block */
1555 MINSIZE = SHELL_ALIGN(504),
1556 };
1557
1558 struct stack_block {
1559 struct stack_block *prev;
1560 char space[MINSIZE];
1561 };
1562
1563 struct stackmark {
1564 struct stack_block *stackp;
1565 char *stacknxt;
1566 size_t stacknleft;
1567 };
1568
1569
1570 struct globals_memstack {
1571 struct stack_block *g_stackp; // = &stackbase;
1572 char *g_stacknxt; // = stackbase.space;
1573 char *sstrend; // = stackbase.space + MINSIZE;
1574 size_t g_stacknleft; // = MINSIZE;
1575 struct stack_block stackbase;
1576 };
1577 extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1578 #define G_memstack (*ash_ptr_to_globals_memstack)
1579 #define g_stackp (G_memstack.g_stackp )
1580 #define g_stacknxt (G_memstack.g_stacknxt )
1581 #define sstrend (G_memstack.sstrend )
1582 #define g_stacknleft (G_memstack.g_stacknleft)
1583 #define stackbase (G_memstack.stackbase )
1584 #define INIT_G_memstack() do { \
1585 XZALLOC_CONST_PTR(&ash_ptr_to_globals_memstack, sizeof(G_memstack)); \
1586 g_stackp = &stackbase; \
1587 g_stacknxt = stackbase.space; \
1588 g_stacknleft = MINSIZE; \
1589 sstrend = stackbase.space + MINSIZE; \
1590 } while (0)
1591
1592
1593 #define stackblock() ((void *)g_stacknxt)
1594 #define stackblocksize() g_stacknleft
1595
1596 /*
1597 * Parse trees for commands are allocated in lifo order, so we use a stack
1598 * to make this more efficient, and also to avoid all sorts of exception
1599 * handling code to handle interrupts in the middle of a parse.
1600 *
1601 * The size 504 was chosen because the Ultrix malloc handles that size
1602 * well.
1603 */
1604 static void *
stalloc(size_t nbytes)1605 stalloc(size_t nbytes)
1606 {
1607 char *p;
1608 size_t aligned;
1609
1610 aligned = SHELL_ALIGN(nbytes);
1611 if (aligned > g_stacknleft) {
1612 size_t len;
1613 size_t blocksize;
1614 struct stack_block *sp;
1615
1616 blocksize = aligned;
1617 if (blocksize < MINSIZE)
1618 blocksize = MINSIZE;
1619 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1620 if (len < blocksize)
1621 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1622 INT_OFF;
1623 sp = ckmalloc(len);
1624 sp->prev = g_stackp;
1625 g_stacknxt = sp->space;
1626 g_stacknleft = blocksize;
1627 sstrend = g_stacknxt + blocksize;
1628 g_stackp = sp;
1629 INT_ON;
1630 }
1631 p = g_stacknxt;
1632 g_stacknxt += aligned;
1633 g_stacknleft -= aligned;
1634 return p;
1635 }
1636
1637 static void *
stzalloc(size_t nbytes)1638 stzalloc(size_t nbytes)
1639 {
1640 return memset(stalloc(nbytes), 0, nbytes);
1641 }
1642
1643 static void
stunalloc(void * p)1644 stunalloc(void *p)
1645 {
1646 #if DEBUG
1647 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1648 write(STDERR_FILENO, "stunalloc\n", 10);
1649 abort();
1650 }
1651 #endif
1652 g_stacknleft += g_stacknxt - (char *)p;
1653 g_stacknxt = p;
1654 }
1655
1656 /*
1657 * Like strdup but works with the ash stack.
1658 */
1659 static char *
sstrdup(const char * p)1660 sstrdup(const char *p)
1661 {
1662 size_t len = strlen(p) + 1;
1663 return memcpy(stalloc(len), p, len);
1664 }
1665
1666 static ALWAYS_INLINE void
grabstackblock(size_t len)1667 grabstackblock(size_t len)
1668 {
1669 stalloc(len);
1670 }
1671
1672 static void
pushstackmark(struct stackmark * mark,size_t len)1673 pushstackmark(struct stackmark *mark, size_t len)
1674 {
1675 mark->stackp = g_stackp;
1676 mark->stacknxt = g_stacknxt;
1677 mark->stacknleft = g_stacknleft;
1678 grabstackblock(len);
1679 }
1680
1681 static void
setstackmark(struct stackmark * mark)1682 setstackmark(struct stackmark *mark)
1683 {
1684 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1685 }
1686
1687 static void
popstackmark(struct stackmark * mark)1688 popstackmark(struct stackmark *mark)
1689 {
1690 struct stack_block *sp;
1691
1692 if (!mark->stackp)
1693 return;
1694
1695 INT_OFF;
1696 while (g_stackp != mark->stackp) {
1697 sp = g_stackp;
1698 g_stackp = sp->prev;
1699 free(sp);
1700 }
1701 g_stacknxt = mark->stacknxt;
1702 g_stacknleft = mark->stacknleft;
1703 sstrend = mark->stacknxt + mark->stacknleft;
1704 INT_ON;
1705 }
1706
1707 /*
1708 * When the parser reads in a string, it wants to stick the string on the
1709 * stack and only adjust the stack pointer when it knows how big the
1710 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1711 * of space on top of the stack and stackblocklen returns the length of
1712 * this block. Growstackblock will grow this space by at least one byte,
1713 * possibly moving it (like realloc). Grabstackblock actually allocates the
1714 * part of the block that has been used.
1715 */
1716 static void
growstackblock(size_t min)1717 growstackblock(size_t min)
1718 {
1719 size_t newlen;
1720
1721 newlen = g_stacknleft * 2;
1722 if (newlen < g_stacknleft)
1723 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1724 min = SHELL_ALIGN(min | 128);
1725 if (newlen < min)
1726 newlen += min;
1727
1728 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1729 struct stack_block *sp;
1730 struct stack_block *prevstackp;
1731 size_t grosslen;
1732
1733 INT_OFF;
1734 sp = g_stackp;
1735 prevstackp = sp->prev;
1736 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1737 sp = ckrealloc(sp, grosslen);
1738 sp->prev = prevstackp;
1739 g_stackp = sp;
1740 g_stacknxt = sp->space;
1741 g_stacknleft = newlen;
1742 sstrend = sp->space + newlen;
1743 INT_ON;
1744 } else {
1745 char *oldspace = g_stacknxt;
1746 size_t oldlen = g_stacknleft;
1747 char *p = stalloc(newlen);
1748
1749 /* free the space we just allocated */
1750 g_stacknxt = memcpy(p, oldspace, oldlen);
1751 g_stacknleft += newlen;
1752 }
1753 }
1754
1755 /*
1756 * The following routines are somewhat easier to use than the above.
1757 * The user declares a variable of type STACKSTR, which may be declared
1758 * to be a register. The macro STARTSTACKSTR initializes things. Then
1759 * the user uses the macro STPUTC to add characters to the string. In
1760 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1761 * grown as necessary. When the user is done, she can just leave the
1762 * string there and refer to it using stackblock(). Or she can allocate
1763 * the space for it using grabstackstr(). If it is necessary to allow
1764 * someone else to use the stack temporarily and then continue to grow
1765 * the string, the user should use grabstack to allocate the space, and
1766 * then call ungrabstr(p) to return to the previous mode of operation.
1767 *
1768 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1769 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1770 * is space for at least one character.
1771 */
1772 static void *
growstackstr(void)1773 growstackstr(void)
1774 {
1775 size_t len = stackblocksize();
1776 growstackblock(0);
1777 return (char *)stackblock() + len;
1778 }
1779
1780 static char *
growstackto(size_t len)1781 growstackto(size_t len)
1782 {
1783 if (stackblocksize() < len)
1784 growstackblock(len);
1785 return stackblock();
1786 }
1787
1788 /*
1789 * Called from CHECKSTRSPACE.
1790 */
1791 static char *
makestrspace(size_t newlen,char * p)1792 makestrspace(size_t newlen, char *p)
1793 {
1794 size_t len = p - g_stacknxt;
1795
1796 return growstackto(len + newlen) + len;
1797 }
1798
1799 static char *
stnputs(const char * s,size_t n,char * p)1800 stnputs(const char *s, size_t n, char *p)
1801 {
1802 p = makestrspace(n, p);
1803 p = (char *)mempcpy(p, s, n);
1804 return p;
1805 }
1806
1807 static char *
stack_putstr(const char * s,char * p)1808 stack_putstr(const char *s, char *p)
1809 {
1810 return stnputs(s, strlen(s), p);
1811 }
1812
1813 static char *
_STPUTC(int c,char * p)1814 _STPUTC(int c, char *p)
1815 {
1816 if (p == sstrend)
1817 p = growstackstr();
1818 *p++ = c;
1819 return p;
1820 }
1821
1822 #define STARTSTACKSTR(p) ((p) = stackblock())
1823 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1824 #define CHECKSTRSPACE(n, p) do { \
1825 char *q = (p); \
1826 size_t l = (n); \
1827 size_t m = sstrend - q; \
1828 if (l > m) \
1829 (p) = makestrspace(l, q); \
1830 } while (0)
1831 #define USTPUTC(c, p) (*(p)++ = (c))
1832 #define STACKSTRNUL(p) do { \
1833 if ((p) == sstrend) \
1834 (p) = growstackstr(); \
1835 *(p) = '\0'; \
1836 } while (0)
1837 #define STUNPUTC(p) (--(p))
1838 #define STTOPC(p) ((p)[-1])
1839 #define STADJUST(amount, p) ((p) += (amount))
1840
1841 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1842 #define ungrabstackstr(s, p) stunalloc(s)
1843 #define stackstrend() ((void *)sstrend)
1844
1845
1846 /* ============ String helpers */
1847
1848 /*
1849 * prefix -- see if pfx is a prefix of string.
1850 */
1851 static char *
prefix(const char * string,const char * pfx)1852 prefix(const char *string, const char *pfx)
1853 {
1854 while (*pfx) {
1855 if (*pfx++ != *string++)
1856 return NULL;
1857 }
1858 return (char *) string;
1859 }
1860
1861 /*
1862 * Check for a valid number. This should be elsewhere.
1863 */
1864 static int
is_number(const char * p)1865 is_number(const char *p)
1866 {
1867 do {
1868 if (!isdigit(*p))
1869 return 0;
1870 } while (*++p != '\0');
1871 return 1;
1872 }
1873
1874 /*
1875 * Convert a string of digits to an integer, printing an error message on
1876 * failure.
1877 */
1878 static int
number(const char * s)1879 number(const char *s)
1880 {
1881 if (!is_number(s))
1882 ash_msg_and_raise_error(msg_illnum, s);
1883 return atoi(s);
1884 }
1885
1886 /*
1887 * Produce a single quoted string suitable as input to the shell.
1888 * The return string is allocated on the stack.
1889 */
1890 static char *
single_quote(const char * s)1891 single_quote(const char *s)
1892 {
1893 char *p;
1894
1895 STARTSTACKSTR(p);
1896
1897 do {
1898 char *q;
1899 size_t len;
1900
1901 len = strchrnul(s, '\'') - s;
1902
1903 q = p = makestrspace(len + 3, p);
1904
1905 *q++ = '\'';
1906 q = (char *)mempcpy(q, s, len);
1907 *q++ = '\'';
1908 s += len;
1909
1910 STADJUST(q - p, p);
1911
1912 if (*s != '\'')
1913 break;
1914 len = 0;
1915 do len++; while (*++s == '\'');
1916
1917 q = p = makestrspace(len + 3, p);
1918
1919 *q++ = '"';
1920 q = (char *)mempcpy(q, s - len, len);
1921 *q++ = '"';
1922
1923 STADJUST(q - p, p);
1924 } while (*s);
1925
1926 USTPUTC('\0', p);
1927
1928 return stackblock();
1929 }
1930
1931 /*
1932 * Produce a possibly single quoted string suitable as input to the shell.
1933 * If quoting was done, the return string is allocated on the stack,
1934 * otherwise a pointer to the original string is returned.
1935 */
1936 static const char *
maybe_single_quote(const char * s)1937 maybe_single_quote(const char *s)
1938 {
1939 const char *p = s;
1940
1941 while (*p) {
1942 /* Assuming ACSII */
1943 /* quote ctrl_chars space !"#$%&'()* */
1944 if (*p < '+')
1945 goto need_quoting;
1946 /* quote ;<=>? */
1947 if (*p >= ';' && *p <= '?')
1948 goto need_quoting;
1949 /* quote `[\ */
1950 if (*p == '`')
1951 goto need_quoting;
1952 if (*p == '[')
1953 goto need_quoting;
1954 if (*p == '\\')
1955 goto need_quoting;
1956 /* quote {|}~ DEL and high bytes */
1957 if (*p > 'z')
1958 goto need_quoting;
1959 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1960 /* TODO: maybe avoid quoting % */
1961 p++;
1962 }
1963 return s;
1964
1965 need_quoting:
1966 return single_quote(s);
1967 }
1968
1969
1970 /* ============ nextopt */
1971
1972 static char **argptr; /* argument list for builtin commands */
1973 static char *optionarg; /* set by nextopt (like getopt) */
1974 static char *optptr; /* used by nextopt */
1975
1976 /*
1977 * XXX - should get rid of. Have all builtins use getopt(3).
1978 * The library getopt must have the BSD extension static variable
1979 * "optreset", otherwise it can't be used within the shell safely.
1980 *
1981 * Standard option processing (a la getopt) for builtin routines.
1982 * The only argument that is passed to nextopt is the option string;
1983 * the other arguments are unnecessary. It returns the character,
1984 * or '\0' on end of input.
1985 */
1986 static int
nextopt(const char * optstring)1987 nextopt(const char *optstring)
1988 {
1989 char *p;
1990 const char *q;
1991 char c;
1992
1993 p = optptr;
1994 if (p == NULL || *p == '\0') {
1995 /* We ate entire "-param", take next one */
1996 p = *argptr;
1997 if (p == NULL)
1998 return '\0';
1999 if (*p != '-')
2000 return '\0';
2001 if (*++p == '\0') /* just "-" ? */
2002 return '\0';
2003 argptr++;
2004 if (LONE_DASH(p)) /* "--" ? */
2005 return '\0';
2006 /* p => next "-param" */
2007 }
2008 /* p => some option char in the middle of a "-param" */
2009 c = *p++;
2010 for (q = optstring; *q != c;) {
2011 if (*q == '\0')
2012 ash_msg_and_raise_error("illegal option -%c", c);
2013 if (*++q == ':')
2014 q++;
2015 }
2016 if (*++q == ':') {
2017 if (*p == '\0') {
2018 p = *argptr++;
2019 if (p == NULL)
2020 ash_msg_and_raise_error("no arg for -%c option", c);
2021 }
2022 optionarg = p;
2023 p = NULL;
2024 }
2025 optptr = p;
2026 return c;
2027 }
2028
2029
2030 /* ============ Shell variables */
2031
2032 struct shparam {
2033 int nparam; /* # of positional parameters (without $0) */
2034 #if ENABLE_ASH_GETOPTS
2035 int optind; /* next parameter to be processed by getopts */
2036 int optoff; /* used by getopts */
2037 #endif
2038 unsigned char malloced; /* if parameter list dynamically allocated */
2039 char **p; /* parameter list */
2040 };
2041
2042 /*
2043 * Free the list of positional parameters.
2044 */
2045 static void
freeparam(volatile struct shparam * param)2046 freeparam(volatile struct shparam *param)
2047 {
2048 if (param->malloced) {
2049 char **ap, **ap1;
2050 ap = ap1 = param->p;
2051 while (*ap)
2052 free(*ap++);
2053 free(ap1);
2054 }
2055 }
2056
2057 #if ENABLE_ASH_GETOPTS
2058 static void FAST_FUNC getoptsreset(const char *value);
2059 #endif
2060
2061 struct var {
2062 struct var *next; /* next entry in hash list */
2063 int flags; /* flags are defined above */
2064 const char *var_text; /* name=value */
2065 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
2066 /* the variable gets set/unset */
2067 };
2068
2069 struct localvar {
2070 struct localvar *next; /* next local variable in list */
2071 struct var *vp; /* the variable that was made local */
2072 int flags; /* saved flags */
2073 const char *text; /* saved text */
2074 };
2075
2076 /* flags */
2077 #define VEXPORT 0x01 /* variable is exported */
2078 #define VREADONLY 0x02 /* variable cannot be modified */
2079 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
2080 #define VTEXTFIXED 0x08 /* text is statically allocated */
2081 #define VSTACK 0x10 /* text is allocated on the stack */
2082 #define VUNSET 0x20 /* the variable is not set */
2083 #define VNOFUNC 0x40 /* don't call the callback function */
2084 #define VNOSET 0x80 /* do not set variable - just readonly test */
2085 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
2086 #if ENABLE_ASH_RANDOM_SUPPORT
2087 # define VDYNAMIC 0x200 /* dynamic variable */
2088 #else
2089 # define VDYNAMIC 0
2090 #endif
2091
2092
2093 /* Need to be before varinit_data[] */
2094 #if ENABLE_LOCALE_SUPPORT
2095 static void FAST_FUNC
change_lc_all(const char * value)2096 change_lc_all(const char *value)
2097 {
2098 if (value && *value != '\0')
2099 setlocale(LC_ALL, value);
2100 }
2101 static void FAST_FUNC
change_lc_ctype(const char * value)2102 change_lc_ctype(const char *value)
2103 {
2104 if (value && *value != '\0')
2105 setlocale(LC_CTYPE, value);
2106 }
2107 #endif
2108 #if ENABLE_ASH_MAIL
2109 static void chkmail(void);
2110 static void changemail(const char *var_value) FAST_FUNC;
2111 #else
2112 # define chkmail() ((void)0)
2113 #endif
2114 static void changepath(const char *) FAST_FUNC;
2115 #if ENABLE_ASH_RANDOM_SUPPORT
2116 static void change_random(const char *) FAST_FUNC;
2117 #endif
2118 #if BASH_EPOCH_VARS
2119 static void change_seconds(const char *) FAST_FUNC;
2120 static void change_realtime(const char *) FAST_FUNC;
2121 #endif
2122
2123 static const struct {
2124 int flags;
2125 const char *var_text;
2126 void (*var_func)(const char *) FAST_FUNC;
2127 } varinit_data[] ALIGN_PTR = {
2128 /*
2129 * Note: VEXPORT would not work correctly here for NOFORK applets:
2130 * some environment strings may be constant.
2131 */
2132 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
2133 #if ENABLE_ASH_MAIL
2134 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2135 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
2136 #endif
2137 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2138 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2139 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2140 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
2141 #if ENABLE_ASH_GETOPTS
2142 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
2143 #endif
2144 { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
2145 { VSTRFIXED|VTEXTFIXED , NULL /* inited to funcnamevar */, NULL },
2146 #if ENABLE_ASH_RANDOM_SUPPORT
2147 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2148 #endif
2149 #if BASH_EPOCH_VARS
2150 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHSECONDS", change_seconds },
2151 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHREALTIME", change_realtime },
2152 #endif
2153 #if ENABLE_LOCALE_SUPPORT
2154 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2155 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
2156 #endif
2157 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
2158 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
2159 #endif
2160 };
2161
2162 struct redirtab;
2163
2164 struct globals_var {
2165 struct shparam shellparam; /* $@ current positional parameters */
2166 struct redirtab *redirlist;
2167 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
2168 struct var *vartab[VTABSIZE];
2169 struct var varinit[ARRAY_SIZE(varinit_data)];
2170 int lineno;
2171 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2172 char funcnamevar[sizeof("FUNCNAME=") + 64];
2173 char *funcname;
2174 unsigned trap_depth;
2175 bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */
2176 };
2177 extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2178 #define G_var (*ash_ptr_to_globals_var)
2179 #define shellparam (G_var.shellparam )
2180 //#define redirlist (G_var.redirlist )
2181 #define preverrout_fd (G_var.preverrout_fd)
2182 #define vartab (G_var.vartab )
2183 #define varinit (G_var.varinit )
2184 #define lineno (G_var.lineno )
2185 #define linenovar (G_var.linenovar )
2186 #define funcnamevar (G_var.funcnamevar )
2187 #define funcname (G_var.funcname )
2188 #define trap_depth (G_var.trap_depth )
2189 #define in_trap_ERR (G_var.in_trap_ERR )
2190 #define vifs varinit[0]
2191 #if ENABLE_ASH_MAIL
2192 # define vmail varinit[1]
2193 # define vmpath varinit[2]
2194 #endif
2195 #define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
2196 #define vpath varinit[VAR_OFFSET1 + 1]
2197 #define vps1 varinit[VAR_OFFSET1 + 2]
2198 #define vps2 varinit[VAR_OFFSET1 + 3]
2199 #define vps4 varinit[VAR_OFFSET1 + 4]
2200 #if ENABLE_ASH_GETOPTS
2201 # define voptind varinit[VAR_OFFSET1 + 5]
2202 #endif
2203 #define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
2204 #define vlineno varinit[VAR_OFFSET2 + 5]
2205 #define vfuncname varinit[VAR_OFFSET2 + 6]
2206 #if ENABLE_ASH_RANDOM_SUPPORT
2207 # define vrandom varinit[VAR_OFFSET2 + 7]
2208 #endif
2209 #define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
2210 #if BASH_EPOCH_VARS
2211 # define vepochs varinit[VAR_OFFSET3 + 7]
2212 # define vepochr varinit[VAR_OFFSET3 + 8]
2213 #endif
2214 #define INIT_G_var() do { \
2215 unsigned i; \
2216 XZALLOC_CONST_PTR(&ash_ptr_to_globals_var, sizeof(G_var)); \
2217 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2218 varinit[i].flags = varinit_data[i].flags; \
2219 varinit[i].var_text = varinit_data[i].var_text; \
2220 varinit[i].var_func = varinit_data[i].var_func; \
2221 } \
2222 strcpy(linenovar, "LINENO="); \
2223 vlineno.var_text = linenovar; \
2224 strcpy(funcnamevar, "FUNCNAME="); \
2225 vfuncname.var_text = funcnamevar; \
2226 } while (0)
2227
2228 /*
2229 * The following macros access the values of the above variables.
2230 * They have to skip over the name. They return the null string
2231 * for unset variables.
2232 */
2233 #define ifsval() (vifs.var_text + 4)
2234 #define ifsset() ((vifs.flags & VUNSET) == 0)
2235 #if ENABLE_ASH_MAIL
2236 # define mailval() (vmail.var_text + 5)
2237 # define mpathval() (vmpath.var_text + 9)
2238 # define mpathset() ((vmpath.flags & VUNSET) == 0)
2239 #endif
2240 #define pathval() (vpath.var_text + 5)
2241 #define ps1val() (vps1.var_text + 4)
2242 #define ps2val() (vps2.var_text + 4)
2243 #define ps4val() (vps4.var_text + 4)
2244 #if ENABLE_ASH_GETOPTS
2245 # define optindval() (voptind.var_text + 7)
2246 #endif
2247
2248 #if ENABLE_ASH_GETOPTS
2249 static void FAST_FUNC
getoptsreset(const char * value)2250 getoptsreset(const char *value)
2251 {
2252 shellparam.optind = 1;
2253 if (is_number(value))
2254 shellparam.optind = number(value) ?: 1;
2255 shellparam.optoff = -1;
2256 }
2257 #endif
2258
2259 /*
2260 * Compares two strings up to the first = or '\0'. The first
2261 * string must be terminated by '='; the second may be terminated by
2262 * either '=' or '\0'.
2263 */
2264 static int
varcmp(const char * p,const char * q)2265 varcmp(const char *p, const char *q)
2266 {
2267 int c, d;
2268
2269 while ((c = *p) == (d = *q)) {
2270 if (c == '\0' || c == '=')
2271 goto out;
2272 p++;
2273 q++;
2274 }
2275 if (c == '=')
2276 c = '\0';
2277 if (d == '=')
2278 d = '\0';
2279 out:
2280 return c - d;
2281 }
2282
2283 /*
2284 * Find the appropriate entry in the hash table from the name.
2285 */
2286 static struct var **
hashvar(const char * p)2287 hashvar(const char *p)
2288 {
2289 unsigned hashval;
2290
2291 hashval = ((unsigned char) *p) << 4;
2292 while (*p && *p != '=')
2293 hashval += (unsigned char) *p++;
2294 return &vartab[hashval % VTABSIZE];
2295 }
2296
2297 static int
vpcmp(const void * a,const void * b)2298 vpcmp(const void *a, const void *b)
2299 {
2300 return varcmp(*(const char **)a, *(const char **)b);
2301 }
2302
2303 /*
2304 * This routine initializes the builtin variables.
2305 */
2306 static void
initvar(void)2307 initvar(void)
2308 {
2309 struct var *vp;
2310 struct var *end;
2311 struct var **vpp;
2312
2313 /*
2314 * PS1 depends on uid
2315 */
2316 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2317 vps1.var_text = "PS1=\\w \\$ ";
2318 #else
2319 if (!geteuid())
2320 vps1.var_text = "PS1=# ";
2321 #endif
2322 vp = varinit;
2323 end = vp + ARRAY_SIZE(varinit);
2324 do {
2325 vpp = hashvar(vp->var_text);
2326 vp->next = *vpp;
2327 *vpp = vp;
2328 } while (++vp < end);
2329 }
2330
2331 static struct var **
findvar(struct var ** vpp,const char * name)2332 findvar(struct var **vpp, const char *name)
2333 {
2334 for (; *vpp; vpp = &(*vpp)->next) {
2335 if (varcmp((*vpp)->var_text, name) == 0) {
2336 break;
2337 }
2338 }
2339 return vpp;
2340 }
2341
2342 /*
2343 * Find the value of a variable. Returns NULL if not set.
2344 */
2345 static const char* FAST_FUNC
lookupvar(const char * name)2346 lookupvar(const char *name)
2347 {
2348 struct var *v;
2349
2350 v = *findvar(hashvar(name), name);
2351 if (v) {
2352 #if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2353 /*
2354 * Dynamic variables are implemented roughly the same way they are
2355 * in bash. Namely, they're "special" so long as they aren't unset.
2356 * As soon as they're unset, they're no longer dynamic, and dynamic
2357 * lookup will no longer happen at that point. -- PFM.
2358 */
2359 if (v->flags & VDYNAMIC)
2360 v->var_func(NULL);
2361 #endif
2362 if (!(v->flags & VUNSET)) {
2363 if (v->var_text == linenovar) {
2364 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2365 } else
2366 if (v->var_text == funcnamevar) {
2367 safe_strncpy(funcnamevar+9, funcname ? funcname : "", sizeof(funcnamevar)-9);
2368 }
2369 return var_end(v->var_text);
2370 }
2371 }
2372 return NULL;
2373 }
2374
2375 #if ENABLE_UNICODE_SUPPORT
2376 static void
reinit_unicode_for_ash(void)2377 reinit_unicode_for_ash(void)
2378 {
2379 /* Unicode support should be activated even if LANG is set
2380 * _during_ shell execution, not only if it was set when
2381 * shell was started. Therefore, re-check LANG every time:
2382 */
2383 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2384 || ENABLE_UNICODE_USING_LOCALE
2385 ) {
2386 const char *s = lookupvar("LC_ALL");
2387 if (!s) s = lookupvar("LC_CTYPE");
2388 if (!s) s = lookupvar("LANG");
2389 reinit_unicode(s);
2390 }
2391 }
2392 #else
2393 # define reinit_unicode_for_ash() ((void)0)
2394 #endif
2395
2396 /*
2397 * Search the environment of a builtin command.
2398 */
2399 static ALWAYS_INLINE const char *
bltinlookup(const char * name)2400 bltinlookup(const char *name)
2401 {
2402 return lookupvar(name);
2403 }
2404
2405 /*
2406 * Same as setvar except that the variable and value are passed in
2407 * the first argument as name=value. Since the first argument will
2408 * be actually stored in the table, it should not be a string that
2409 * will go away.
2410 * Called with interrupts off.
2411 */
2412 static struct var *
setvareq(char * s,int flags)2413 setvareq(char *s, int flags)
2414 {
2415 struct var *vp, **vpp;
2416
2417 vpp = hashvar(s);
2418 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2419 vpp = findvar(vpp, s);
2420 vp = *vpp;
2421 if (vp) {
2422 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2423 const char *n;
2424
2425 if (flags & VNOSAVE)
2426 free(s);
2427 n = vp->var_text;
2428 exitstatus = 1;
2429 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2430 }
2431
2432 if (flags & VNOSET)
2433 goto out;
2434
2435 if (vp->var_func && !(flags & VNOFUNC))
2436 vp->var_func(var_end(s));
2437
2438 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2439 free((char*)vp->var_text);
2440
2441 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2442 *vpp = vp->next;
2443 free(vp);
2444 out_free:
2445 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2446 free(s);
2447 goto out;
2448 }
2449
2450 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2451 #if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
2452 if (flags & VUNSET)
2453 flags &= ~VDYNAMIC;
2454 #endif
2455 } else {
2456 /* variable s is not found */
2457 if (flags & VNOSET)
2458 goto out;
2459 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2460 goto out_free;
2461 vp = ckzalloc(sizeof(*vp));
2462 vp->next = *vpp;
2463 /*vp->func = NULL; - ckzalloc did it */
2464 *vpp = vp;
2465 }
2466 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2467 s = ckstrdup(s);
2468 vp->var_text = s;
2469 vp->flags = flags;
2470
2471 out:
2472 return vp;
2473 }
2474
2475 /*
2476 * Set the value of a variable. The flags argument is ored with the
2477 * flags of the variable. If val is NULL, the variable is unset.
2478 */
2479 static struct var *
setvar(const char * name,const char * val,int flags)2480 setvar(const char *name, const char *val, int flags)
2481 {
2482 const char *q;
2483 char *p;
2484 char *nameeq;
2485 size_t namelen;
2486 size_t vallen;
2487 struct var *vp;
2488
2489 q = endofname(name);
2490 p = strchrnul(q, '=');
2491 namelen = p - name;
2492 if (!namelen || p != q)
2493 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2494 vallen = 0;
2495 if (val == NULL) {
2496 flags |= VUNSET;
2497 } else {
2498 vallen = strlen(val);
2499 }
2500
2501 INT_OFF;
2502 nameeq = ckzalloc(namelen + vallen + 2);
2503 p = mempcpy(nameeq, name, namelen);
2504 if (val) {
2505 *p++ = '=';
2506 memcpy(p, val, vallen);
2507 }
2508 vp = setvareq(nameeq, flags | VNOSAVE);
2509 INT_ON;
2510
2511 return vp;
2512 }
2513
2514 static void FAST_FUNC
setvar0(const char * name,const char * val)2515 setvar0(const char *name, const char *val)
2516 {
2517 setvar(name, val, 0);
2518 }
2519
2520 /*
2521 * Unset the specified variable.
2522 */
2523 static void
unsetvar(const char * s)2524 unsetvar(const char *s)
2525 {
2526 setvar(s, NULL, 0);
2527 }
2528
2529 /*
2530 * Generate a list of variables satisfying the given conditions.
2531 */
2532 #if !ENABLE_FEATURE_SH_NOFORK
2533 # define listvars(on, off, lp, end) listvars(on, off, end)
2534 #endif
2535 static char **
listvars(int on,int off,struct strlist * lp,char *** end)2536 listvars(int on, int off, struct strlist *lp, char ***end)
2537 {
2538 struct var **vpp;
2539 struct var *vp;
2540 char **ep;
2541 int mask;
2542
2543 STARTSTACKSTR(ep);
2544 vpp = vartab;
2545 mask = on | off;
2546 do {
2547 for (vp = *vpp; vp; vp = vp->next) {
2548 if ((vp->flags & mask) == on) {
2549 #if ENABLE_FEATURE_SH_NOFORK
2550 /* If variable with the same name is both
2551 * exported and temporarily set for a command:
2552 * export ZVAR=5
2553 * ZVAR=6 printenv
2554 * then "ZVAR=6" will be both in vartab and
2555 * lp lists. Do not pass it twice to printenv.
2556 */
2557 struct strlist *lp1 = lp;
2558 while (lp1) {
2559 if (strcmp(lp1->text, vp->var_text) == 0)
2560 goto skip;
2561 lp1 = lp1->next;
2562 }
2563 #endif
2564 if (ep == stackstrend())
2565 ep = growstackstr();
2566 *ep++ = (char*)vp->var_text;
2567 #if ENABLE_FEATURE_SH_NOFORK
2568 skip: ;
2569 #endif
2570 }
2571 }
2572 } while (++vpp < vartab + VTABSIZE);
2573
2574 #if ENABLE_FEATURE_SH_NOFORK
2575 while (lp) {
2576 if (ep == stackstrend())
2577 ep = growstackstr();
2578 *ep++ = lp->text;
2579 lp = lp->next;
2580 }
2581 #endif
2582
2583 if (ep == stackstrend())
2584 ep = growstackstr();
2585 if (end)
2586 *end = ep;
2587 *ep++ = NULL;
2588 return grabstackstr(ep);
2589 }
2590
2591
2592 /* ============ Path search helper */
2593 static const char *
legal_pathopt(const char * opt,const char * term,int magic)2594 legal_pathopt(const char *opt, const char *term, int magic)
2595 {
2596 switch (magic) {
2597 case 0:
2598 opt = NULL;
2599 break;
2600
2601 case 1:
2602 opt = prefix(opt, "builtin") ?: prefix(opt, "func");
2603 break;
2604
2605 default:
2606 opt += strcspn(opt, term);
2607 break;
2608 }
2609
2610 if (opt && *opt == '%')
2611 opt++;
2612
2613 return opt;
2614 }
2615
2616 /*
2617 * The variable path (passed by reference) should be set to the start
2618 * of the path before the first call; padvance will update
2619 * this value as it proceeds. Successive calls to padvance will return
2620 * the possible path expansions in sequence. If an option (indicated by
2621 * a percent sign) appears in the path entry then the global variable
2622 * pathopt will be set to point to it; otherwise pathopt will be set to
2623 * NULL.
2624 *
2625 * If magic is 0 then pathopt recognition will be disabled. If magic is
2626 * 1 we shall recognise %builtin/%func. Otherwise we shall accept any
2627 * pathopt.
2628 */
2629 static const char *pathopt; /* set by padvance */
2630
2631 static int
padvance_magic(const char ** path,const char * name,int magic)2632 padvance_magic(const char **path, const char *name, int magic)
2633 {
2634 const char *term = "%:";
2635 const char *lpathopt;
2636 const char *p;
2637 char *q;
2638 const char *start;
2639 size_t qlen;
2640 size_t len;
2641
2642 if (*path == NULL)
2643 return -1;
2644
2645 lpathopt = NULL;
2646 start = *path;
2647
2648 if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) {
2649 lpathopt = start + 1;
2650 start = p;
2651 term = ":";
2652 }
2653
2654 len = strcspn(start, term);
2655 p = start + len;
2656
2657 if (*p == '%') {
2658 size_t extra = strchrnul(p, ':') - p;
2659
2660 if (legal_pathopt(p + 1, term, magic))
2661 lpathopt = p + 1;
2662 else
2663 len += extra;
2664
2665 p += extra;
2666 }
2667
2668 pathopt = lpathopt;
2669 *path = *p == ':' ? p + 1 : NULL;
2670
2671 /* "2" is for '/' and '\0' */
2672 qlen = len + strlen(name) + 2;
2673 q = growstackto(qlen);
2674
2675 if (len) {
2676 q = mempcpy(q, start, len);
2677 *q++ = '/';
2678 }
2679 strcpy(q, name);
2680
2681 return qlen;
2682 }
2683
2684 static int
padvance(const char ** path,const char * name)2685 padvance(const char **path, const char *name)
2686 {
2687 return padvance_magic(path, name, 1);
2688 }
2689
2690
2691 /* ============ Prompt */
2692
2693 static smallint doprompt; /* if set, prompt the user */
2694 static smallint needprompt; /* true if interactive and at start of line */
2695
2696 #if ENABLE_FEATURE_EDITING
2697 static line_input_t *line_input_state;
2698 static const char *cmdedit_prompt;
2699 static void
putprompt(const char * s)2700 putprompt(const char *s)
2701 {
2702 if (ENABLE_ASH_EXPAND_PRMT) {
2703 free((char*)cmdedit_prompt);
2704 cmdedit_prompt = ckstrdup(s);
2705 return;
2706 }
2707 cmdedit_prompt = s;
2708 }
2709 #else
2710 static void
putprompt(const char * s)2711 putprompt(const char *s)
2712 {
2713 out2str(s);
2714 }
2715 #endif
2716
2717 /* expandstr() needs parsing machinery, so it is far away ahead... */
2718 static const char *expandstr(const char *ps, int syntax_type);
2719 /* Values for syntax param */
2720 #define BASESYNTAX 0 /* not in quotes */
2721 #define DQSYNTAX 1 /* in double quotes */
2722 #define SQSYNTAX 2 /* in single quotes */
2723 #define ARISYNTAX 3 /* in arithmetic */
2724 #if ENABLE_ASH_EXPAND_PRMT
2725 # define PSSYNTAX 4 /* prompt. never passed to SIT() */
2726 #endif
2727 /* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
2728
2729 /*
2730 * called by editline -- any expansions to the prompt should be added here.
2731 */
2732 static void
setprompt_if(smallint do_set,int whichprompt)2733 setprompt_if(smallint do_set, int whichprompt)
2734 {
2735 const char *prompt;
2736 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2737
2738 if (!do_set)
2739 return;
2740
2741 needprompt = 0;
2742
2743 switch (whichprompt) {
2744 case 1:
2745 prompt = ps1val();
2746 break;
2747 case 2:
2748 prompt = ps2val();
2749 break;
2750 default: /* 0 */
2751 prompt = nullstr;
2752 }
2753 #if ENABLE_ASH_EXPAND_PRMT
2754 pushstackmark(&smark, stackblocksize());
2755 putprompt(expandstr(prompt, PSSYNTAX));
2756 popstackmark(&smark);
2757 #else
2758 putprompt(prompt);
2759 #endif
2760 }
2761
2762
2763 /* ============ The cd and pwd commands */
2764
2765 #define CD_PHYSICAL 1
2766 #define CD_PRINT 2
2767
2768 static int
cdopt(void)2769 cdopt(void)
2770 {
2771 int flags = 0;
2772 int i, j;
2773
2774 j = 'L';
2775 while ((i = nextopt("LP")) != '\0') {
2776 if (i != j) {
2777 flags ^= CD_PHYSICAL;
2778 j = i;
2779 }
2780 }
2781
2782 return flags;
2783 }
2784
2785 /*
2786 * Update curdir (the name of the current directory) in response to a
2787 * cd command.
2788 */
2789 static const char *
updatepwd(const char * dir)2790 updatepwd(const char *dir)
2791 {
2792 char *new;
2793 char *p;
2794 char *cdcomppath;
2795 const char *lim;
2796
2797 cdcomppath = sstrdup(dir);
2798 STARTSTACKSTR(new);
2799 if (*dir != '/') {
2800 if (curdir == nullstr)
2801 return 0;
2802 new = stack_putstr(curdir, new);
2803 }
2804 new = makestrspace(strlen(dir) + 2, new);
2805 lim = (char *)stackblock() + 1;
2806 if (*dir != '/') {
2807 if (new[-1] != '/')
2808 USTPUTC('/', new);
2809 if (new > lim && *lim == '/')
2810 lim++;
2811 } else {
2812 USTPUTC('/', new);
2813 cdcomppath++;
2814 if (dir[1] == '/' && dir[2] != '/') {
2815 USTPUTC('/', new);
2816 cdcomppath++;
2817 lim++;
2818 }
2819 }
2820 p = strtok_r(cdcomppath, "/", &cdcomppath);
2821 while (p) {
2822 switch (*p) {
2823 case '.':
2824 if (p[1] == '.' && p[2] == '\0') {
2825 while (new > lim) {
2826 STUNPUTC(new);
2827 if (new[-1] == '/')
2828 break;
2829 }
2830 break;
2831 }
2832 if (p[1] == '\0')
2833 break;
2834 /* fall through */
2835 default:
2836 new = stack_putstr(p, new);
2837 USTPUTC('/', new);
2838 }
2839 p = strtok_r(NULL, "/", &cdcomppath);
2840 }
2841 if (new > lim)
2842 STUNPUTC(new);
2843 *new = 0;
2844 return stackblock();
2845 }
2846
2847 /*
2848 * Find out what the current directory is. If we already know the current
2849 * directory, this routine returns immediately.
2850 */
2851 static char *
getpwd(void)2852 getpwd(void)
2853 {
2854 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2855 return dir ? dir : nullstr;
2856 }
2857
2858 static void
setpwd(const char * val,int setold)2859 setpwd(const char *val, int setold)
2860 {
2861 char *oldcur, *dir;
2862
2863 oldcur = dir = curdir;
2864
2865 if (setold) {
2866 setvar("OLDPWD", oldcur, VEXPORT);
2867 }
2868 INT_OFF;
2869 if (physdir != nullstr) {
2870 if (physdir != oldcur)
2871 free(physdir);
2872 physdir = nullstr;
2873 }
2874 if (oldcur == val || !val) {
2875 char *s = getpwd();
2876 physdir = s;
2877 if (!val)
2878 dir = s;
2879 } else
2880 dir = ckstrdup(val);
2881 if (oldcur != dir && oldcur != nullstr) {
2882 free(oldcur);
2883 }
2884 curdir = dir;
2885 INT_ON;
2886 setvar("PWD", dir, VEXPORT);
2887 }
2888
2889 static void hashcd(void);
2890
2891 /*
2892 * Actually do the chdir. We also call hashcd to let other routines
2893 * know that the current directory has changed.
2894 */
2895 static int
docd(const char * dest,int flags)2896 docd(const char *dest, int flags)
2897 {
2898 const char *dir = NULL;
2899 int err;
2900
2901 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2902
2903 INT_OFF;
2904 if (!(flags & CD_PHYSICAL)) {
2905 dir = updatepwd(dest);
2906 if (dir)
2907 dest = dir;
2908 }
2909 err = chdir(dest);
2910 if (err)
2911 goto out;
2912 setpwd(dir, 1);
2913 hashcd();
2914 out:
2915 INT_ON;
2916 return err;
2917 }
2918
2919 static int FAST_FUNC
cdcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)2920 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2921 {
2922 const char *dest;
2923 const char *path;
2924 const char *p;
2925 char c;
2926 struct stat statb;
2927 int flags;
2928 int len;
2929
2930 flags = cdopt();
2931 dest = *argptr;
2932 if (!dest)
2933 dest = bltinlookup("HOME");
2934 else if (LONE_DASH(dest)) {
2935 dest = bltinlookup("OLDPWD");
2936 flags |= CD_PRINT;
2937 }
2938 if (!dest)
2939 dest = nullstr;
2940 if (*dest == '/')
2941 goto step6;
2942 if (*dest == '.') {
2943 c = dest[1];
2944 dotdot:
2945 switch (c) {
2946 case '\0':
2947 case '/':
2948 goto step6;
2949 case '.':
2950 c = dest[2];
2951 if (c != '.')
2952 goto dotdot;
2953 }
2954 }
2955 if (!*dest)
2956 dest = ".";
2957 path = bltinlookup("CDPATH");
2958 while (p = path, (len = padvance(&path, dest)) >= 0) {
2959 c = *p;
2960 p = stalloc(len);
2961
2962 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2963 if (c && c != ':')
2964 flags |= CD_PRINT;
2965 docd:
2966 if (!docd(p, flags))
2967 goto out;
2968 goto err;
2969 }
2970 }
2971
2972 step6:
2973 p = dest;
2974 goto docd;
2975
2976 err:
2977 ash_msg_and_raise_perror("can't cd to %s", dest);
2978 /* NOTREACHED */
2979 out:
2980 if (flags & CD_PRINT)
2981 out1fmt("%s\n", curdir);
2982 return 0;
2983 }
2984
2985 static int FAST_FUNC
pwdcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)2986 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2987 {
2988 int flags;
2989 const char *dir = curdir;
2990
2991 flags = cdopt();
2992 if (flags) {
2993 if (physdir == nullstr)
2994 setpwd(dir, 0);
2995 dir = physdir;
2996 }
2997 out1fmt("%s\n", dir);
2998 return 0;
2999 }
3000
3001
3002 /* ============ ... */
3003
3004
3005 #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
3006
3007 /* Syntax classes */
3008 #define CWORD 0 /* character is nothing special */
3009 #define CNL 1 /* newline character */
3010 #define CBACK 2 /* a backslash character */
3011 #define CSQUOTE 3 /* single quote */
3012 #define CDQUOTE 4 /* double quote */
3013 #define CENDQUOTE 5 /* a terminating quote */
3014 #define CBQUOTE 6 /* backwards single quote */
3015 #define CVAR 7 /* a dollar sign */
3016 #define CENDVAR 8 /* a '}' character */
3017 #define CLP 9 /* a left paren in arithmetic */
3018 #define CRP 10 /* a right paren in arithmetic */
3019 #define CENDFILE 11 /* end of file */
3020 #define CCTL 12 /* like CWORD, except it must be escaped */
3021 #define CSPCL 13 /* these terminate a word */
3022
3023 #define PEOF 256
3024
3025 #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
3026
3027 #if ENABLE_FEATURE_SH_MATH
3028 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
3029 #else
3030 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
3031 #endif
3032 static const uint16_t S_I_T[] ALIGN2 = {
3033 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 0, ' ' */
3034 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 1, \n */
3035 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 2, !*-/:=?[]~ */
3036 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 3, '"' */
3037 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 4, $ */
3038 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 5, "'" */
3039 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 6, ( */
3040 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 7, ) */
3041 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 8, \ */
3042 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 9, ` */
3043 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 10, } */
3044 #if !USE_SIT_FUNCTION
3045 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 11, PEOF */
3046 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 12, 0-9A-Za-z */
3047 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 13, CTLESC ... */
3048 #endif
3049 #undef SIT_ITEM
3050 };
3051 /* Constants below must match table above */
3052 enum {
3053 CSPCL_CWORD_CWORD_CWORD , /* 0 */
3054 CNL_CNL_CNL_CNL , /* 1 */
3055 CWORD_CCTL_CCTL_CWORD , /* 2 */
3056 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 3 */
3057 CVAR_CVAR_CWORD_CVAR , /* 4 */
3058 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 5 */
3059 CSPCL_CWORD_CWORD_CLP , /* 6 */
3060 CSPCL_CWORD_CWORD_CRP , /* 7 */
3061 CBACK_CBACK_CCTL_CBACK , /* 8 */
3062 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 9 */
3063 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 10 */
3064 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 11 */
3065 CWORD_CWORD_CWORD_CWORD , /* 12 */
3066 CCTL_CCTL_CCTL_CCTL , /* 13 */
3067 };
3068
3069 /* c in SIT(c, syntax) must be an *unsigned char* or PEOF,
3070 * caller must ensure proper cast on it if c is *char_ptr!
3071 */
3072 #if USE_SIT_FUNCTION
3073
3074 static int
SIT(int c,int syntax)3075 SIT(int c, int syntax)
3076 {
3077 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
3078 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
3079 /*
3080 * This causes '/' to be prepended with CTLESC in dquoted string,
3081 * making "./file"* treated incorrectly because we feed
3082 * ".\/file*" string to glob(), confusing it (see expandmeta func).
3083 * The "homegrown" glob implementation is okay with that,
3084 * but glibc one isn't. With '/' always treated as CWORD,
3085 * both work fine.
3086 */
3087 static const uint8_t syntax_index_table[] ALIGN1 = {
3088 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
3089 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
3090 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
3091 10, 2 /* "}~" */
3092 };
3093 const char *s;
3094 int indx;
3095
3096 if (c == PEOF)
3097 return CENDFILE;
3098 /* Cast is purely for paranoia here,
3099 * just in case someone passed signed char to us */
3100 if ((unsigned char)c >= CTL_FIRST
3101 && (unsigned char)c <= CTL_LAST
3102 ) {
3103 return CCTL;
3104 }
3105 s = strchrnul(spec_symbls, c);
3106 if (*s == '\0')
3107 return CWORD;
3108 indx = syntax_index_table[s - spec_symbls];
3109 return (S_I_T[indx] >> (syntax*4)) & 0xf;
3110 }
3111
3112 #else /* !USE_SIT_FUNCTION */
3113
3114 static const uint8_t syntax_index_table[] ALIGN1 = {
3115 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
3116 /* 0 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 1 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 2 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 3 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 4 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 5 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 6 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 7 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 8 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3126 /* 10 "\n" */ CNL_CNL_CNL_CNL,
3127 /* 11 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 12 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 13 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 14 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 15 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 16 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 17 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 18 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 19 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 20 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 21 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 22 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 23 */ CWORD_CWORD_CWORD_CWORD,
3140 /* 24 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 25 */ CWORD_CWORD_CWORD_CWORD,
3142 /* 26 */ CWORD_CWORD_CWORD_CWORD,
3143 /* 27 */ CWORD_CWORD_CWORD_CWORD,
3144 /* 28 */ CWORD_CWORD_CWORD_CWORD,
3145 /* 29 */ CWORD_CWORD_CWORD_CWORD,
3146 /* 30 */ CWORD_CWORD_CWORD_CWORD,
3147 /* 31 */ CWORD_CWORD_CWORD_CWORD,
3148 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
3149 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
3150 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3151 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
3152 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
3153 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
3154 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
3155 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3156 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
3157 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
3158 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
3159 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
3160 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
3161 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
3162 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
3163 /* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3164 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
3165 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
3166 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
3167 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
3168 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
3169 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
3170 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
3171 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
3172 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
3173 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
3174 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
3175 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
3176 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
3177 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
3178 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
3179 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
3180 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
3181 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
3182 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
3183 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
3184 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
3185 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
3186 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
3187 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
3188 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
3189 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
3190 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
3191 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
3192 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
3193 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
3194 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
3195 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
3196 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
3197 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3198 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3199 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3200 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3201 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3202 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3203 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3204 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3205 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3206 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3207 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3208 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3209 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3210 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3211 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3212 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3213 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3214 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3215 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3216 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3217 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3218 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3219 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3220 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3221 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3222 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3223 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3224 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3225 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3226 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3227 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3228 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3229 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3230 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3231 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3232 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3233 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3234 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3235 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3236 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3237 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3238 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3239 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3240 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3241 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3242 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3243 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3244 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3245 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3246 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3247 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3248 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3249 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3250 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3251 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3252 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3253 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3254 #if BASH_PROCESS_SUBST
3255 /* 137 CTLTOPROC */ CCTL_CCTL_CCTL_CCTL,
3256 /* 138 CTLFROMPROC */ CCTL_CCTL_CCTL_CCTL,
3257 #else
3258 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3259 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3260 #endif
3261 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3262 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3263 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3264 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3265 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3266 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3267 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3268 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3269 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3270 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3271 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3272 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3273 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3274 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3275 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3276 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3277 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3278 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3279 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3280 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3281 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3282 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3283 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3284 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3285 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3286 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3287 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3288 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3289 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3290 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3291 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3292 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3293 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3294 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3295 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3296 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3297 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3298 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3299 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3300 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3301 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3302 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3303 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3304 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3305 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3306 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3307 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3308 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3309 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3310 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3311 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3312 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3313 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3314 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3315 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3316 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3317 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3318 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3319 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3320 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3321 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3322 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3323 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3324 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3325 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3326 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3327 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3328 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3329 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3330 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3331 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3332 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3333 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3334 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3335 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3336 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3337 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3338 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3339 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3340 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3341 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3342 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3343 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3344 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3345 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3346 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3347 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3348 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3349 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3350 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3351 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3352 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3353 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3354 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3355 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3356 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3357 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3358 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3359 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3360 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3361 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3362 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3363 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3364 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3365 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3366 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3367 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3368 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3369 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3370 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3371 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3372 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3373 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3374 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3375 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3376 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3377 /* 255 */ CWORD_CWORD_CWORD_CWORD,
3378 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3379 };
3380
3381 #if 1
3382 # define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3383 #else /* debug version, caught one signed char bug */
3384 # define SIT(c, syntax) \
3385 ({ \
3386 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3387 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3388 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
3389 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3390 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3391 })
3392 #endif
3393
3394 #endif /* !USE_SIT_FUNCTION */
3395
3396
3397 /* ============ Alias handling */
3398
3399 #if ENABLE_ASH_ALIAS
3400
3401 #define ALIASINUSE 1
3402 #define ALIASDEAD 2
3403
3404 struct alias {
3405 struct alias *next;
3406 char *name;
3407 char *val;
3408 int flag;
3409 };
3410
3411
3412 static struct alias **atab; // [ATABSIZE];
3413 #define INIT_G_alias() do { \
3414 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3415 } while (0)
3416
3417
3418 static struct alias **
__lookupalias(const char * name)3419 __lookupalias(const char *name)
3420 {
3421 unsigned int hashval;
3422 struct alias **app;
3423 const char *p;
3424 unsigned int ch;
3425
3426 p = name;
3427
3428 ch = (unsigned char)*p;
3429 hashval = ch << 4;
3430 while (ch) {
3431 hashval += ch;
3432 ch = (unsigned char)*++p;
3433 }
3434 app = &atab[hashval % ATABSIZE];
3435
3436 for (; *app; app = &(*app)->next) {
3437 if (strcmp(name, (*app)->name) == 0) {
3438 break;
3439 }
3440 }
3441
3442 return app;
3443 }
3444
3445 static struct alias *
lookupalias(const char * name,int check)3446 lookupalias(const char *name, int check)
3447 {
3448 struct alias *ap = *__lookupalias(name);
3449
3450 if (check && ap && (ap->flag & ALIASINUSE))
3451 return NULL;
3452 return ap;
3453 }
3454
3455 static struct alias *
freealias(struct alias * ap)3456 freealias(struct alias *ap)
3457 {
3458 struct alias *next;
3459
3460 if (ap->flag & ALIASINUSE) {
3461 ap->flag |= ALIASDEAD;
3462 return ap;
3463 }
3464
3465 next = ap->next;
3466 free(ap->name);
3467 free(ap->val);
3468 free(ap);
3469 return next;
3470 }
3471
3472 static void
setalias(const char * name,const char * val)3473 setalias(const char *name, const char *val)
3474 {
3475 struct alias *ap, **app;
3476
3477 app = __lookupalias(name);
3478 ap = *app;
3479 INT_OFF;
3480 if (ap) {
3481 if (!(ap->flag & ALIASINUSE)) {
3482 free(ap->val);
3483 }
3484 ap->val = ckstrdup(val);
3485 ap->flag &= ~ALIASDEAD;
3486 } else {
3487 /* not found */
3488 ap = ckzalloc(sizeof(struct alias));
3489 ap->name = ckstrdup(name);
3490 ap->val = ckstrdup(val);
3491 /*ap->flag = 0; - ckzalloc did it */
3492 /*ap->next = NULL;*/
3493 *app = ap;
3494 }
3495 INT_ON;
3496 }
3497
3498 static int
unalias(const char * name)3499 unalias(const char *name)
3500 {
3501 struct alias **app;
3502
3503 app = __lookupalias(name);
3504
3505 if (*app) {
3506 INT_OFF;
3507 *app = freealias(*app);
3508 INT_ON;
3509 return 0;
3510 }
3511
3512 return 1;
3513 }
3514
3515 static void
rmaliases(void)3516 rmaliases(void)
3517 {
3518 struct alias *ap, **app;
3519 int i;
3520
3521 INT_OFF;
3522 for (i = 0; i < ATABSIZE; i++) {
3523 app = &atab[i];
3524 for (ap = *app; ap; ap = *app) {
3525 *app = freealias(*app);
3526 if (ap == *app) {
3527 app = &ap->next;
3528 }
3529 }
3530 }
3531 INT_ON;
3532 }
3533
3534 static void
printalias(const struct alias * ap)3535 printalias(const struct alias *ap)
3536 {
3537 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3538 }
3539
3540 /*
3541 * TODO - sort output
3542 */
3543 static int FAST_FUNC
aliascmd(int argc UNUSED_PARAM,char ** argv)3544 aliascmd(int argc UNUSED_PARAM, char **argv)
3545 {
3546 char *n, *v;
3547 int ret = 0;
3548 struct alias *ap;
3549
3550 if (!argv[1]) {
3551 int i;
3552
3553 for (i = 0; i < ATABSIZE; i++) {
3554 for (ap = atab[i]; ap; ap = ap->next) {
3555 printalias(ap);
3556 }
3557 }
3558 return 0;
3559 }
3560 while ((n = *++argv) != NULL) {
3561 v = strchr(n+1, '=');
3562 if (v == NULL) { /* n+1: funny ksh stuff */
3563 ap = *__lookupalias(n);
3564 if (ap == NULL) {
3565 fprintf(stderr, "%s: %s not found\n", "alias", n);
3566 ret = 1;
3567 } else
3568 printalias(ap);
3569 } else {
3570 *v++ = '\0';
3571 setalias(n, v);
3572 }
3573 }
3574
3575 return ret;
3576 }
3577
3578 static int FAST_FUNC
unaliascmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)3579 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3580 {
3581 int i;
3582
3583 while (nextopt("a") != '\0') {
3584 rmaliases();
3585 return 0;
3586 }
3587 for (i = 0; *argptr; argptr++) {
3588 if (unalias(*argptr)) {
3589 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3590 i = 1;
3591 }
3592 }
3593
3594 return i;
3595 }
3596
3597 #endif /* ASH_ALIAS */
3598
3599
3600 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3601 #define FORK_FG 0
3602 #define FORK_BG 1
3603 #define FORK_NOJOB 2
3604
3605 /* mode flags for showjob(s) */
3606 #define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3607 #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3608 #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
3609 #define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
3610
3611 /*
3612 * A job structure contains information about a job. A job is either a
3613 * single process or a set of processes contained in a pipeline. In the
3614 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3615 * array of pids.
3616 */
3617 struct procstat {
3618 pid_t ps_pid; /* process id */
3619 int ps_status; /* last process status from wait() */
3620 char *ps_cmd; /* text of command being run */
3621 };
3622
3623 struct job {
3624 struct procstat ps0; /* status of process */
3625 struct procstat *ps; /* status of processes when more than one */
3626 #if JOBS
3627 int stopstatus; /* status of a stopped job */
3628 #endif
3629 unsigned nprocs; /* number of processes */
3630
3631 #define JOBRUNNING 0 /* at least one proc running */
3632 #define JOBSTOPPED 1 /* all procs are stopped */
3633 #define JOBDONE 2 /* all procs are completed */
3634 unsigned
3635 state: 8,
3636 #if JOBS
3637 sigint: 1, /* job was killed by SIGINT */
3638 jobctl: 1, /* job running under job control */
3639 #endif
3640 waited: 1, /* true if this entry has been waited for */
3641 used: 1, /* true if this entry is in used */
3642 changed: 1; /* true if status has changed */
3643 struct job *prev_job; /* previous job */
3644 };
3645
3646 static struct job *makejob(/*union node *,*/ int);
3647 static int forkshell(struct job *, union node *, int);
3648 static int waitforjob(struct job *);
3649
3650 #if !JOBS
3651 enum { doing_jobctl = 0 };
3652 #define setjobctl(on) do {} while (0)
3653 #else
3654 static smallint doing_jobctl; //references:8
3655 static void setjobctl(int);
3656 #endif
3657
3658 /*
3659 * Ignore a signal.
3660 */
3661 static void
ignoresig(int signo)3662 ignoresig(int signo)
3663 {
3664 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3665 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3666 /* No, need to do it */
3667 signal(signo, SIG_IGN);
3668 }
3669 sigmode[signo - 1] = S_HARD_IGN;
3670 }
3671
3672 /*
3673 * Only one usage site - in setsignal()
3674 */
3675 static void
signal_handler(int signo)3676 signal_handler(int signo)
3677 {
3678 if (signo == SIGCHLD) {
3679 got_sigchld = 1;
3680 if (!trap[SIGCHLD])
3681 return;
3682 }
3683
3684 gotsig[signo - 1] = 1;
3685 pending_sig = signo;
3686
3687 if (signo == SIGINT && !trap[SIGINT]) {
3688 if (!suppress_int) {
3689 pending_sig = 0;
3690 raise_interrupt(); /* does not return */
3691 }
3692 pending_int = 1;
3693 }
3694 }
3695
3696 /*
3697 * Set the signal handler for the specified signal. The routine figures
3698 * out what it should be set to.
3699 */
3700 static void
setsignal(int signo)3701 setsignal(int signo)
3702 {
3703 char *t;
3704 char cur_act, new_act;
3705 struct sigaction act;
3706
3707 t = trap[signo];
3708 new_act = S_DFL;
3709 if (t != NULL) { /* trap for this sig is set */
3710 new_act = S_CATCH;
3711 if (t[0] == '\0') /* trap is "": ignore this sig */
3712 new_act = S_IGN;
3713 }
3714
3715 if (rootshell && new_act == S_DFL) {
3716 switch (signo) {
3717 case SIGINT:
3718 if (iflag || minusc || sflag == 0)
3719 new_act = S_CATCH;
3720 break;
3721 case SIGQUIT:
3722 #if DEBUG
3723 if (debug)
3724 break;
3725 #endif
3726 /* man bash:
3727 * "In all cases, bash ignores SIGQUIT. Non-builtin
3728 * commands run by bash have signal handlers
3729 * set to the values inherited by the shell
3730 * from its parent". */
3731 new_act = S_IGN;
3732 break;
3733 case SIGTERM:
3734 if (iflag)
3735 new_act = S_IGN;
3736 break;
3737 #if JOBS
3738 case SIGTSTP:
3739 case SIGTTOU:
3740 if (mflag)
3741 new_act = S_IGN;
3742 break;
3743 #endif
3744 }
3745 }
3746 /* if !rootshell, we reset SIGQUIT to DFL,
3747 * whereas we have to restore it to what shell got on entry.
3748 * This is handled by the fact that if signal was IGNored on entry,
3749 * then cur_act is S_HARD_IGN and we never change its sigaction
3750 * (see code below).
3751 */
3752
3753 if (signo == SIGCHLD)
3754 new_act = S_CATCH;
3755
3756 t = &sigmode[signo - 1];
3757 cur_act = *t;
3758 if (cur_act == 0) {
3759 /* current setting is not yet known */
3760 if (sigaction(signo, NULL, &act)) {
3761 /* pretend it worked; maybe we should give a warning,
3762 * but other shells don't. We don't alter sigmode,
3763 * so we retry every time.
3764 * btw, in Linux it never fails. --vda */
3765 return;
3766 }
3767 if (act.sa_handler == SIG_IGN) {
3768 cur_act = S_HARD_IGN;
3769 if (mflag
3770 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3771 ) {
3772 cur_act = S_IGN; /* don't hard ignore these */
3773 }
3774 }
3775 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3776 /* installing SIG_DFL over SIG_DFL is a no-op */
3777 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3778 *t = S_DFL;
3779 return;
3780 }
3781 }
3782 if (cur_act == S_HARD_IGN || cur_act == new_act)
3783 return;
3784
3785 *t = new_act;
3786
3787 act.sa_handler = SIG_DFL;
3788 switch (new_act) {
3789 case S_CATCH:
3790 act.sa_handler = signal_handler;
3791 break;
3792 case S_IGN:
3793 act.sa_handler = SIG_IGN;
3794 break;
3795 }
3796 /* flags and mask matter only if !DFL and !IGN, but we do it
3797 * for all cases for more deterministic behavior:
3798 */
3799 act.sa_flags = 0; //TODO: why not SA_RESTART?
3800 sigfillset(&act.sa_mask);
3801
3802 sigaction_set(signo, &act);
3803 }
3804
3805 /* mode flags for set_curjob */
3806 #define CUR_DELETE 2
3807 #define CUR_RUNNING 1
3808 #define CUR_STOPPED 0
3809
3810 #if JOBS
3811 /* pgrp of shell on invocation */
3812 static int initialpgrp; //references:2
3813 static int ttyfd = -1; //5
3814 #endif
3815 /* array of jobs */
3816 static struct job *jobtab; //5
3817 /* size of array */
3818 static unsigned njobs; //4
3819 /* current job */
3820 static struct job *curjob; //lots
3821
3822 #if 0
3823 /* Bash has a feature: it restores termios after a successful wait for
3824 * a foreground job which had at least one stopped or sigkilled member.
3825 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3826 * properly restoring tty state. Should we do this too?
3827 * A reproducer: ^Z an interactive python:
3828 *
3829 * # python
3830 * Python 2.7.12 (...)
3831 * >>> ^Z
3832 * { python leaves tty in -icanon -echo state. We do survive that... }
3833 * [1]+ Stopped python
3834 * { ...however, next program (python #2) does not survive it well: }
3835 * # python
3836 * Python 2.7.12 (...)
3837 * >>> Traceback (most recent call last):
3838 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3839 * File "<stdin>", line 1, in <module>
3840 * NameError: name 'qwerty' is not defined
3841 *
3842 * The implementation below is modeled on bash code and seems to work.
3843 * However, I'm not sure we should do this. For one: what if I'd fg
3844 * the stopped python instead? It'll be confused by "restored" tty state.
3845 */
3846 static struct termios shell_tty_info;
3847 static void
3848 get_tty_state(void)
3849 {
3850 if (rootshell && ttyfd >= 0)
3851 tcgetattr(ttyfd, &shell_tty_info);
3852 }
3853 static void
3854 set_tty_state(void)
3855 {
3856 /* if (rootshell) - caller ensures this */
3857 if (ttyfd >= 0)
3858 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3859 }
3860 static int
3861 job_signal_status(struct job *jp)
3862 {
3863 int status;
3864 unsigned i;
3865 struct procstat *ps = jp->ps;
3866 for (i = 0; i < jp->nprocs; i++) {
3867 status = ps[i].ps_status;
3868 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3869 return status;
3870 }
3871 return 0;
3872 }
3873 static void
3874 restore_tty_if_stopped_or_signaled(struct job *jp)
3875 {
3876 //TODO: check what happens if we come from waitforjob() in expbackq()
3877 if (rootshell) {
3878 int s = job_signal_status(jp);
3879 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3880 set_tty_state();
3881 }
3882 }
3883 #else
3884 # define get_tty_state() ((void)0)
3885 # define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3886 #endif
3887
3888 static void
set_curjob(struct job * jp,unsigned mode)3889 set_curjob(struct job *jp, unsigned mode)
3890 {
3891 struct job *jp1;
3892 struct job **jpp, **curp;
3893
3894 /* first remove from list */
3895 jpp = curp = &curjob;
3896 while (1) {
3897 jp1 = *jpp;
3898 if (jp1 == jp)
3899 break;
3900 jpp = &jp1->prev_job;
3901 }
3902 *jpp = jp1->prev_job;
3903
3904 /* Then re-insert in correct position */
3905 jpp = curp;
3906 switch (mode) {
3907 default:
3908 #if DEBUG
3909 abort();
3910 #endif
3911 case CUR_DELETE:
3912 /* job being deleted */
3913 break;
3914 case CUR_RUNNING:
3915 /* newly created job or backgrounded job,
3916 * put after all stopped jobs.
3917 */
3918 while (1) {
3919 jp1 = *jpp;
3920 #if JOBS
3921 if (!jp1 || jp1->state != JOBSTOPPED)
3922 #endif
3923 break;
3924 jpp = &jp1->prev_job;
3925 }
3926 /* FALLTHROUGH */
3927 #if JOBS
3928 case CUR_STOPPED:
3929 #endif
3930 /* newly stopped job - becomes curjob */
3931 jp->prev_job = *jpp;
3932 *jpp = jp;
3933 break;
3934 }
3935 }
3936
3937 #if JOBS || DEBUG
3938 static int
jobno(const struct job * jp)3939 jobno(const struct job *jp)
3940 {
3941 return jp - jobtab + 1;
3942 }
3943 #endif
3944
3945 /*
3946 * Convert a job name to a job structure.
3947 */
3948 #if !JOBS
3949 #define getjob(name, getctl) getjob(name)
3950 #endif
3951 static struct job *
getjob(const char * name,int getctl)3952 getjob(const char *name, int getctl)
3953 {
3954 struct job *jp;
3955 struct job *found;
3956 const char *err_msg = "%s: no such job";
3957 unsigned num;
3958 int c;
3959 const char *p;
3960 char *(*match)(const char *, const char *);
3961
3962 jp = curjob;
3963 p = name;
3964 if (!p)
3965 goto currentjob;
3966
3967 if (*p != '%')
3968 goto err;
3969
3970 c = *++p;
3971 if (!c)
3972 goto currentjob;
3973
3974 if (!p[1]) {
3975 if (c == '+' || c == '%') {
3976 currentjob:
3977 err_msg = "No current job";
3978 goto check;
3979 }
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;
3988 }
3989 }
3990
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;
3998 }
3999 }
4000
4001 match = prefix;
4002 if (*p == '?') {
4003 match = strstr;
4004 p++;
4005 }
4006
4007 found = NULL;
4008 while (jp) {
4009 if (match(jp->ps[0].ps_cmd, p)) {
4010 if (found)
4011 goto err;
4012 found = jp;
4013 err_msg = "%s: ambiguous";
4014 }
4015 jp = jp->prev_job;
4016 }
4017 if (!found)
4018 goto err;
4019 jp = found;
4020
4021 gotit:
4022 #if JOBS
4023 err_msg = "job %s not created under job control";
4024 if (getctl && jp->jobctl == 0)
4025 goto err;
4026 #endif
4027 return jp;
4028 err:
4029 ash_msg_and_raise_error(err_msg, name);
4030 }
4031
4032 /*
4033 * Mark a job structure as unused.
4034 */
4035 static void
freejob(struct job * jp)4036 freejob(struct job *jp)
4037 {
4038 struct procstat *ps;
4039 int i;
4040
4041 INT_OFF;
4042 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
4043 if (ps->ps_cmd != nullstr)
4044 free(ps->ps_cmd);
4045 }
4046 if (jp->ps != &jp->ps0)
4047 free(jp->ps);
4048 jp->used = 0;
4049 set_curjob(jp, CUR_DELETE);
4050 INT_ON;
4051 }
4052
4053 #if JOBS
4054 static void
xtcsetpgrp(int fd,pid_t pgrp)4055 xtcsetpgrp(int fd, pid_t pgrp)
4056 {
4057 if (tcsetpgrp(fd, pgrp))
4058 ash_msg_and_raise_perror("can't set tty process group");
4059 }
4060
4061 /*
4062 * Turn job control on and off.
4063 *
4064 * Note: This code assumes that the third arg to ioctl is a character
4065 * pointer, which is true on Berkeley systems but not System V. Since
4066 * System V doesn't have job control yet, this isn't a problem now.
4067 *
4068 * Called with interrupts off.
4069 */
4070 static void
setjobctl(int on)4071 setjobctl(int on)
4072 {
4073 int fd;
4074 int pgrp;
4075
4076 if (on == doing_jobctl || rootshell == 0)
4077 return;
4078 if (on) {
4079 int ofd;
4080 ofd = fd = open(_PATH_TTY, O_RDWR);
4081 if (fd < 0) {
4082 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
4083 * That sometimes helps to acquire controlling tty.
4084 * Obviously, a workaround for bugs when someone
4085 * failed to provide a controlling tty to bash! :) */
4086 fd = 2;
4087 while (!isatty(fd))
4088 if (--fd < 0)
4089 goto out;
4090 }
4091 /* fd is a tty at this point */
4092 fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
4093 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
4094 close(ofd);
4095 if (fd < 0)
4096 goto out; /* F_DUPFD failed */
4097 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
4098 close_on_exec_on(fd);
4099 while (1) { /* while we are in the background */
4100 pgrp = tcgetpgrp(fd);
4101 if (pgrp < 0) {
4102 out:
4103 ash_msg("can't access tty; job control turned off");
4104 mflag = on = 0;
4105 goto close;
4106 }
4107 if (pgrp == getpgrp())
4108 break;
4109 killpg(0, SIGTTIN);
4110 }
4111 initialpgrp = pgrp;
4112
4113 setsignal(SIGTSTP);
4114 setsignal(SIGTTOU);
4115 setsignal(SIGTTIN);
4116 pgrp = rootpid;
4117 setpgid(0, pgrp);
4118 xtcsetpgrp(fd, pgrp);
4119 } else {
4120 /* turning job control off */
4121 fd = ttyfd;
4122 pgrp = initialpgrp;
4123 /* was xtcsetpgrp, but this can make exiting ash
4124 * loop forever if pty is already deleted */
4125 tcsetpgrp(fd, pgrp);
4126 setpgid(0, pgrp);
4127 setsignal(SIGTSTP);
4128 setsignal(SIGTTOU);
4129 setsignal(SIGTTIN);
4130 close:
4131 if (fd >= 0)
4132 close(fd);
4133 fd = -1;
4134 }
4135 ttyfd = fd;
4136 doing_jobctl = on;
4137 }
4138
4139 static int FAST_FUNC
killcmd(int argc,char ** argv)4140 killcmd(int argc, char **argv)
4141 {
4142 if (argv[1] && strcmp(argv[1], "-l") != 0) {
4143 int i = 1;
4144 do {
4145 if (argv[i][0] == '%') {
4146 /*
4147 * "kill %N" - job kill
4148 * Converting to pgrp / pid kill
4149 */
4150 struct job *jp;
4151 char *dst;
4152 int j, n;
4153
4154 jp = getjob(argv[i], 0);
4155 /*
4156 * In jobs started under job control, we signal
4157 * entire process group by kill -PGRP_ID.
4158 * This happens, f.e., in interactive shell.
4159 *
4160 * Otherwise, we signal each child via
4161 * kill PID1 PID2 PID3.
4162 * Testcases:
4163 * sh -c 'sleep 1|sleep 1 & kill %1'
4164 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4165 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4166 */
4167 n = jp->nprocs; /* can't be 0 (I hope) */
4168 if (jp->jobctl)
4169 n = 1;
4170 dst = alloca(n * sizeof(int)*4);
4171 argv[i] = dst;
4172 for (j = 0; j < n; j++) {
4173 struct procstat *ps = &jp->ps[j];
4174 /* Skip non-running and not-stopped members
4175 * (i.e. dead members) of the job
4176 */
4177 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4178 continue;
4179 /*
4180 * kill_main has matching code to expect
4181 * leading space. Needed to not confuse
4182 * negative pids with "kill -SIGNAL_NO" syntax
4183 */
4184 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4185 }
4186 *dst = '\0';
4187 }
4188 } while (argv[++i]);
4189 }
4190 return kill_main(argc, argv);
4191 }
4192
4193 static void
showpipe(struct job * jp)4194 showpipe(struct job *jp /*, FILE *out*/)
4195 {
4196 struct procstat *ps;
4197 struct procstat *psend;
4198
4199 psend = jp->ps + jp->nprocs;
4200 for (ps = jp->ps + 1; ps < psend; ps++)
4201 printf(" | %s", ps->ps_cmd);
4202 newline_and_flush(stdout);
4203 flush_stdout_stderr();
4204 }
4205
4206
4207 static int
restartjob(struct job * jp,int mode)4208 restartjob(struct job *jp, int mode)
4209 {
4210 struct procstat *ps;
4211 int i;
4212 int status;
4213 pid_t pgid;
4214
4215 INT_OFF;
4216 if (jp->state == JOBDONE)
4217 goto out;
4218 jp->state = JOBRUNNING;
4219 pgid = jp->ps[0].ps_pid;
4220 if (mode == FORK_FG) {
4221 get_tty_state();
4222 xtcsetpgrp(ttyfd, pgid);
4223 }
4224 killpg(pgid, SIGCONT);
4225 ps = jp->ps;
4226 i = jp->nprocs;
4227 do {
4228 if (WIFSTOPPED(ps->ps_status)) {
4229 ps->ps_status = -1;
4230 }
4231 ps++;
4232 } while (--i);
4233 out:
4234 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4235 INT_ON;
4236 return status;
4237 }
4238
4239 static int FAST_FUNC
fg_bgcmd(int argc UNUSED_PARAM,char ** argv)4240 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
4241 {
4242 struct job *jp;
4243 int mode;
4244 int retval;
4245
4246 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4247 nextopt(nullstr);
4248 argv = argptr;
4249 do {
4250 jp = getjob(*argv, 1);
4251 if (mode == FORK_BG) {
4252 set_curjob(jp, CUR_RUNNING);
4253 printf("[%d] ", jobno(jp));
4254 }
4255 out1str(jp->ps[0].ps_cmd);
4256 showpipe(jp /*, stdout*/);
4257 retval = restartjob(jp, mode);
4258 } while (*argv && *++argv);
4259 return retval;
4260 }
4261 #endif
4262
4263 static int
sprint_status48(char * os,int status,int sigonly)4264 sprint_status48(char *os, int status, int sigonly)
4265 {
4266 char *s = os;
4267 int st;
4268
4269 if (!WIFEXITED(status)) {
4270 #if JOBS
4271 if (WIFSTOPPED(status))
4272 st = WSTOPSIG(status);
4273 else
4274 #endif
4275 st = WTERMSIG(status);
4276 if (sigonly) {
4277 if (st == SIGINT || st == SIGPIPE)
4278 goto out;
4279 #if JOBS
4280 if (WIFSTOPPED(status))
4281 goto out;
4282 #endif
4283 }
4284 st &= 0x7f;
4285 s = stpncpy(s, strsignal(st), 32);
4286 if (WCOREDUMP(status)) {
4287 s = stpcpy(s, " (core dumped)");
4288 }
4289 } else if (!sigonly) {
4290 st = WEXITSTATUS(status);
4291 s += fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
4292 }
4293 out:
4294 return s - os;
4295 }
4296
4297 #define DOWAIT_NONBLOCK 0
4298 #define DOWAIT_BLOCK 1
4299 #define DOWAIT_BLOCK_OR_SIG 2
4300 #if BASH_WAIT_N
4301 # define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */
4302 #endif
4303
4304 static int
waitproc(int block,int * status)4305 waitproc(int block, int *status)
4306 {
4307 sigset_t oldmask;
4308 int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
4309 int err;
4310
4311 #if JOBS
4312 if (doing_jobctl)
4313 flags |= WUNTRACED;
4314 #endif
4315
4316 do {
4317 got_sigchld = 0;
4318 do
4319 err = waitpid(-1, status, flags);
4320 while (err < 0 && errno == EINTR);
4321
4322 if (err || (err = -!block))
4323 break;
4324
4325 sigfillset(&oldmask);
4326 sigprocmask2(SIG_SETMASK, &oldmask); /* mask is updated */
4327 while (!got_sigchld && !pending_sig)
4328 sigsuspend(&oldmask);
4329 sigprocmask(SIG_SETMASK, &oldmask, NULL);
4330 //simpler, but unsafe: a signal can set pending_sig after check, but before pause():
4331 //while (!got_sigchld && !pending_sig)
4332 // pause();
4333
4334 } while (got_sigchld);
4335
4336 return err;
4337 }
4338
4339 static int
waitone(int block,struct job * job)4340 waitone(int block, struct job *job)
4341 {
4342 int pid;
4343 int status;
4344 struct job *jp;
4345 struct job *thisjob = NULL;
4346 #if BASH_WAIT_N
4347 bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
4348 block = (block & ~DOWAIT_JOBSTATUS);
4349 #endif
4350
4351 TRACE(("dowait(0x%x) called\n", block));
4352
4353 /* It's wrong to call waitpid() outside of INT_OFF region:
4354 * signal can arrive just after syscall return and handler can
4355 * longjmp away, losing stop/exit notification processing.
4356 * Thus, for "jobs" builtin, and for waiting for a fg job,
4357 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4358 *
4359 * However, for "wait" builtin it is wrong to simply call waitpid()
4360 * in INT_OFF region: "wait" needs to wait for any running job
4361 * to change state, but should exit on any trap too.
4362 * In INT_OFF region, a signal just before syscall entry can set
4363 * pending_sig variables, but we can't check them, and we would
4364 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
4365 *
4366 * Because of this, we run inside INT_OFF, but use a special routine
4367 * which combines waitpid() and sigsuspend().
4368 * This is the reason why we need to have a handler for SIGCHLD:
4369 * SIG_DFL handler does not wake sigsuspend().
4370 */
4371 INT_OFF;
4372 pid = waitproc(block, &status);
4373 TRACE(("wait returns pid %d, status=%d\n", pid, status));
4374 if (pid <= 0)
4375 goto out;
4376
4377 for (jp = curjob; jp; jp = jp->prev_job) {
4378 int jobstate;
4379 struct procstat *ps;
4380 struct procstat *psend;
4381 if (jp->state == JOBDONE)
4382 continue;
4383 jobstate = JOBDONE;
4384 ps = jp->ps;
4385 psend = ps + jp->nprocs;
4386 do {
4387 if (ps->ps_pid == pid) {
4388 TRACE(("Job %d: changing status of proc %d "
4389 "from 0x%x to 0x%x\n",
4390 jobno(jp), pid, ps->ps_status, status));
4391 ps->ps_status = status;
4392 thisjob = jp;
4393 }
4394 if (ps->ps_status == -1)
4395 jobstate = JOBRUNNING;
4396 #if JOBS
4397 if (jobstate == JOBRUNNING)
4398 continue;
4399 if (WIFSTOPPED(ps->ps_status)) {
4400 jp->stopstatus = ps->ps_status;
4401 jobstate = JOBSTOPPED;
4402 }
4403 #endif
4404 } while (++ps < psend);
4405 if (!thisjob)
4406 continue;
4407
4408 /* Found the job where one of its processes changed its state.
4409 * Is there at least one live and running process in this job? */
4410 if (jobstate != JOBRUNNING) {
4411 /* No. All live processes in the job are stopped
4412 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4413 */
4414 thisjob->changed = 1;
4415 if (thisjob->state != jobstate) {
4416 TRACE(("Job %d: changing state from %d to %d\n",
4417 jobno(thisjob), thisjob->state, jobstate));
4418 thisjob->state = jobstate;
4419 #if JOBS
4420 if (jobstate == JOBSTOPPED)
4421 set_curjob(thisjob, CUR_STOPPED);
4422 #endif
4423 }
4424 }
4425 goto out;
4426 }
4427 /* The process wasn't found in job list */
4428 out:
4429 INT_ON;
4430
4431 #if BASH_WAIT_N
4432 if (want_jobexitstatus) {
4433 pid = -1;
4434 if (thisjob && thisjob->state == JOBDONE)
4435 pid = thisjob->ps[thisjob->nprocs - 1].ps_status;
4436 }
4437 #endif
4438 if (thisjob && thisjob == job) {
4439 char s[48 + 1];
4440 int len;
4441
4442 len = sprint_status48(s, status, 1);
4443 if (len) {
4444 s[len] = '\n';
4445 s[len + 1] = '\0';
4446 out2str(s);
4447 }
4448 }
4449 return pid;
4450 }
4451
4452 static int
dowait(int block,struct job * jp)4453 dowait(int block, struct job *jp)
4454 {
4455 smallint gotchld = *(volatile smallint *)&got_sigchld;
4456 int rpid;
4457 int pid;
4458
4459 if (jp && jp->state != JOBRUNNING)
4460 block = DOWAIT_NONBLOCK;
4461
4462 if (block == DOWAIT_NONBLOCK && !gotchld)
4463 return 1;
4464
4465 rpid = 1;
4466
4467 do {
4468 pid = waitone(block, jp);
4469 rpid &= !!pid;
4470
4471 if (!pid || (jp && jp->state != JOBRUNNING))
4472 block = DOWAIT_NONBLOCK;
4473 } while (pid >= 0);
4474
4475 return rpid;
4476 }
4477
4478 #if JOBS
4479 static void
showjob(struct job * jp,int mode)4480 showjob(struct job *jp, int mode)
4481 {
4482 struct procstat *ps;
4483 struct procstat *psend;
4484 int col;
4485 int indent_col;
4486 char s[16 + 16 + 48];
4487 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4488
4489 ps = jp->ps;
4490
4491 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4492 /* just output process (group) id of pipeline */
4493 fprintf(out, "%d\n", ps->ps_pid);
4494 return;
4495 }
4496
4497 col = fmtstr(s, 16, "[%d] ", jobno(jp));
4498 indent_col = col;
4499
4500 if (jp == curjob)
4501 s[col - 3] = '+';
4502 else if (curjob && jp == curjob->prev_job)
4503 s[col - 3] = '-';
4504
4505 if (mode & SHOW_PIDS)
4506 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4507
4508 psend = ps + jp->nprocs;
4509
4510 if (jp->state == JOBRUNNING) {
4511 strcpy(s + col, "Running");
4512 col += sizeof("Running") - 1;
4513 } else {
4514 int status = psend[-1].ps_status;
4515 if (jp->state == JOBSTOPPED)
4516 status = jp->stopstatus;
4517 col += sprint_status48(s + col, status, 0);
4518 }
4519 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
4520
4521 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4522 * or prints several "PID | <cmdN>" lines,
4523 * depending on SHOW_PIDS bit.
4524 * We do not print status of individual processes
4525 * between PID and <cmdN>. bash does it, but not very well:
4526 * first line shows overall job status, not process status,
4527 * making it impossible to know 1st process status.
4528 */
4529 goto start;
4530 do {
4531 /* for each process */
4532 s[0] = '\0';
4533 col = 33;
4534 if (mode & SHOW_PIDS)
4535 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4536 start:
4537 fprintf(out, "%s%*c%s%s",
4538 s,
4539 33 - col >= 0 ? 33 - col : 0, ' ',
4540 ps == jp->ps ? "" : "| ",
4541 ps->ps_cmd
4542 );
4543 } while (++ps != psend);
4544 newline_and_flush(out);
4545
4546 jp->changed = 0;
4547
4548 if (jp->state == JOBDONE) {
4549 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4550 freejob(jp);
4551 }
4552 }
4553
4554 /*
4555 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4556 * statuses have changed since the last call to showjobs.
4557 */
4558 static void
showjobs(int mode)4559 showjobs(int mode)
4560 {
4561 struct job *jp;
4562
4563 TRACE(("showjobs(0x%x) called\n", mode));
4564
4565 /* Handle all finished jobs */
4566 dowait(DOWAIT_NONBLOCK, NULL);
4567
4568 for (jp = curjob; jp; jp = jp->prev_job) {
4569 if (!(mode & SHOW_CHANGED) || jp->changed) {
4570 showjob(jp, mode);
4571 }
4572 }
4573 }
4574
4575 static int FAST_FUNC
jobscmd(int argc UNUSED_PARAM,char ** argv)4576 jobscmd(int argc UNUSED_PARAM, char **argv)
4577 {
4578 int mode, m;
4579
4580 mode = 0;
4581 while ((m = nextopt("lp")) != '\0') {
4582 if (m == 'l')
4583 mode |= SHOW_PIDS;
4584 else
4585 mode |= SHOW_ONLY_PGID;
4586 }
4587
4588 argv = argptr;
4589 if (*argv) {
4590 do
4591 showjob(getjob(*argv, 0), mode);
4592 while (*++argv);
4593 } else {
4594 showjobs(mode);
4595 }
4596
4597 return 0;
4598 }
4599 #endif /* JOBS */
4600
4601 /* Called only on finished or stopped jobs (no members are running) */
4602 static int
getstatus(struct job * job)4603 getstatus(struct job *job)
4604 {
4605 int status;
4606 int retval;
4607 struct procstat *ps;
4608
4609 /* Fetch last member's status */
4610 ps = job->ps + job->nprocs - 1;
4611 status = ps->ps_status;
4612 if (pipefail) {
4613 /* "set -o pipefail" mode: use last _nonzero_ status */
4614 while (status == 0 && --ps >= job->ps)
4615 status = ps->ps_status;
4616 }
4617
4618 retval = WEXITSTATUS(status);
4619 if (!WIFEXITED(status)) {
4620 #if JOBS
4621 retval = WSTOPSIG(status);
4622 if (!WIFSTOPPED(status))
4623 #endif
4624 {
4625 /* XXX: limits number of signals */
4626 retval = WTERMSIG(status);
4627 #if JOBS
4628 if (retval == SIGINT)
4629 job->sigint = 1;
4630 #endif
4631 }
4632 retval |= 128;
4633 }
4634 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4635 jobno(job), job->nprocs, status, retval));
4636 return retval;
4637 }
4638
4639 static int FAST_FUNC
waitcmd(int argc UNUSED_PARAM,char ** argv)4640 waitcmd(int argc UNUSED_PARAM, char **argv)
4641 {
4642 struct job *job;
4643 int retval;
4644 struct job *jp;
4645 #if BASH_WAIT_N
4646 int status;
4647 char one = nextopt("n");
4648 #else
4649 nextopt(nullstr);
4650 #endif
4651 retval = 0;
4652
4653 argv = argptr;
4654 if (!argv[0]) {
4655 /* wait for all jobs / one job if -n */
4656 for (;;) {
4657 jp = curjob;
4658 #if BASH_WAIT_N
4659 if (one && !jp)
4660 /* exitcode of "wait -n" with nothing to wait for is 127, not 0 */
4661 retval = 127;
4662 #endif
4663 while (1) {
4664 if (!jp) /* no running procs */
4665 goto ret;
4666 if (jp->state == JOBRUNNING)
4667 break;
4668 jp->waited = 1;
4669 jp = jp->prev_job;
4670 }
4671 /* man bash:
4672 * "When bash is waiting for an asynchronous command via
4673 * the wait builtin, the reception of a signal for which a trap
4674 * has been set will cause the wait builtin to return immediately
4675 * with an exit status greater than 128, immediately after which
4676 * the trap is executed."
4677 */
4678 #if BASH_WAIT_N
4679 status = dowait(DOWAIT_BLOCK_OR_SIG | DOWAIT_JOBSTATUS, NULL);
4680 #else
4681 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4682 #endif
4683 /* if child sends us a signal *and immediately exits*,
4684 * dowait() returns pid > 0. Check this case,
4685 * not "if (dowait() < 0)"!
4686 */
4687 if (pending_sig)
4688 goto sigout;
4689 #if BASH_WAIT_N
4690 if (one) {
4691 /* wait -n waits for one _job_, not one _process_.
4692 * date; sleep 3 & sleep 2 | sleep 1 & wait -n; date
4693 * should wait for 2 seconds. Not 1 or 3.
4694 */
4695 if (status != -1 && !WIFSTOPPED(status)) {
4696 retval = WEXITSTATUS(status);
4697 if (WIFSIGNALED(status))
4698 retval = 128 | WTERMSIG(status);
4699 goto ret;
4700 }
4701 }
4702 #endif
4703 }
4704 }
4705
4706 retval = 127;
4707 do {
4708 if (**argv != '%') {
4709 pid_t pid = number(*argv);
4710 job = curjob;
4711 while (1) {
4712 if (!job)
4713 goto repeat;
4714 if (job->ps[job->nprocs - 1].ps_pid == pid)
4715 break;
4716 job = job->prev_job;
4717 }
4718 } else {
4719 job = getjob(*argv, 0);
4720 }
4721 /* loop until process terminated or stopped */
4722 dowait(DOWAIT_BLOCK_OR_SIG, job);
4723 if (pending_sig)
4724 goto sigout;
4725 job->waited = 1;
4726 retval = getstatus(job);
4727 repeat: ;
4728 } while (*++argv);
4729
4730 ret:
4731 return retval;
4732 sigout:
4733 retval = 128 | pending_sig;
4734 return retval;
4735 }
4736
4737 static struct job *
growjobtab(void)4738 growjobtab(void)
4739 {
4740 size_t len;
4741 ptrdiff_t offset;
4742 struct job *jp, *jq;
4743
4744 len = njobs * sizeof(*jp);
4745 jq = jobtab;
4746 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4747
4748 offset = (char *)jp - (char *)jq;
4749 if (offset) {
4750 /* Relocate pointers */
4751 size_t l = len;
4752
4753 jq = (struct job *)((char *)jq + l);
4754 while (l) {
4755 l -= sizeof(*jp);
4756 jq--;
4757 #define joff(p) ((struct job *)((char *)(p) + l))
4758 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4759 if (joff(jp)->ps == &jq->ps0)
4760 jmove(joff(jp)->ps);
4761 if (joff(jp)->prev_job)
4762 jmove(joff(jp)->prev_job);
4763 }
4764 if (curjob)
4765 jmove(curjob);
4766 #undef joff
4767 #undef jmove
4768 }
4769
4770 njobs += 4;
4771 jobtab = jp;
4772 jp = (struct job *)((char *)jp + len);
4773 jq = jp + 3;
4774 do {
4775 jq->used = 0;
4776 } while (--jq >= jp);
4777 return jp;
4778 }
4779
4780 /*
4781 * Return a new job structure.
4782 * Called with interrupts off.
4783 */
4784 static struct job *
makejob(int nprocs)4785 makejob(/*union node *node,*/ int nprocs)
4786 {
4787 int i;
4788 struct job *jp;
4789
4790 for (i = njobs, jp = jobtab; ; jp++) {
4791 if (--i < 0) {
4792 jp = growjobtab();
4793 break;
4794 }
4795 if (jp->used == 0)
4796 break;
4797 if (jp->state != JOBDONE || !jp->waited)
4798 continue;
4799 #if JOBS
4800 if (doing_jobctl)
4801 continue;
4802 #endif
4803 freejob(jp);
4804 break;
4805 }
4806 memset(jp, 0, sizeof(*jp));
4807 #if JOBS
4808 /* jp->jobctl is a bitfield.
4809 * "jp->jobctl |= doing_jobctl" likely to give awful code */
4810 if (doing_jobctl)
4811 jp->jobctl = 1;
4812 #endif
4813 jp->prev_job = curjob;
4814 curjob = jp;
4815 jp->used = 1;
4816 jp->ps = &jp->ps0;
4817 if (nprocs > 1) {
4818 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4819 }
4820 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4821 jobno(jp)));
4822 return jp;
4823 }
4824
4825 #if JOBS
4826 /*
4827 * Return a string identifying a command (to be printed by the
4828 * jobs command).
4829 */
4830 static char *cmdnextc;
4831
4832 static void
cmdputs(const char * s)4833 cmdputs(const char *s)
4834 {
4835 static const char vstype[VSTYPE + 1][3] ALIGN1 = {
4836 "", "}", "-", "+", "?", "=",
4837 "%", "%%", "#", "##"
4838 IF_BASH_SUBSTR(, ":")
4839 IF_BASH_PATTERN_SUBST(, "/", "//")
4840 };
4841
4842 const char *p, *str;
4843 char cc[2];
4844 char *nextc;
4845 unsigned char c;
4846 unsigned char subtype = 0;
4847 int quoted = 0;
4848
4849 cc[1] = '\0';
4850 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4851 p = s;
4852 while ((c = *p++) != '\0') {
4853 str = NULL;
4854 switch (c) {
4855 case CTLESC:
4856 c = *p++;
4857 break;
4858 case CTLVAR:
4859 subtype = *p++;
4860 if ((subtype & VSTYPE) == VSLENGTH)
4861 str = "${#";
4862 else
4863 str = "${";
4864 goto dostr;
4865 case CTLENDVAR:
4866 str = "\"}";
4867 str += !(quoted & 1);
4868 quoted >>= 1;
4869 subtype = 0;
4870 goto dostr;
4871 #if BASH_PROCESS_SUBST
4872 case CTLBACKQ:
4873 c = '$';
4874 str = "(...)";
4875 break;
4876 case CTLTOPROC:
4877 c = '>';
4878 str = "(...)";
4879 break;
4880 case CTLFROMPROC:
4881 c = '<';
4882 str = "(...)";
4883 break;
4884 #else
4885 case CTLBACKQ:
4886 str = "$(...)";
4887 goto dostr;
4888 #endif
4889 #if ENABLE_FEATURE_SH_MATH
4890 case CTLARI:
4891 str = "$((";
4892 goto dostr;
4893 case CTLENDARI:
4894 str = "))";
4895 goto dostr;
4896 #endif
4897 case CTLQUOTEMARK:
4898 quoted ^= 1;
4899 c = '"';
4900 break;
4901 case '=':
4902 if (subtype == 0)
4903 break;
4904 if ((subtype & VSTYPE) != VSNORMAL)
4905 quoted <<= 1;
4906 str = vstype[subtype & VSTYPE];
4907 if (subtype & VSNUL)
4908 c = ':';
4909 else
4910 goto checkstr;
4911 break;
4912 case '\'':
4913 case '\\':
4914 case '"':
4915 case '$':
4916 /* These can only happen inside quotes */
4917 cc[0] = c;
4918 str = cc;
4919 //FIXME:
4920 // $ true $$ &
4921 // $ <cr>
4922 // [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
4923 c = '\\';
4924 break;
4925 default:
4926 break;
4927 }
4928 USTPUTC(c, nextc);
4929 checkstr:
4930 if (!str)
4931 continue;
4932 dostr:
4933 while ((c = *str++) != '\0') {
4934 USTPUTC(c, nextc);
4935 }
4936 } /* while *p++ not NUL */
4937
4938 if (quoted & 1) {
4939 USTPUTC('"', nextc);
4940 }
4941 *nextc = 0;
4942 cmdnextc = nextc;
4943 }
4944
4945 /* cmdtxt() and cmdlist() call each other */
4946 static void cmdtxt(union node *n);
4947
4948 static void
cmdlist(union node * np,int sep)4949 cmdlist(union node *np, int sep)
4950 {
4951 for (; np; np = np->narg.next) {
4952 if (!sep)
4953 cmdputs(" ");
4954 cmdtxt(np);
4955 if (sep && np->narg.next)
4956 cmdputs(" ");
4957 }
4958 }
4959
4960 static void
cmdtxt(union node * n)4961 cmdtxt(union node *n)
4962 {
4963 union node *np;
4964 struct nodelist *lp;
4965 const char *p;
4966
4967 if (!n)
4968 return;
4969 switch (n->type) {
4970 default:
4971 #if DEBUG
4972 abort();
4973 #endif
4974 case NPIPE:
4975 lp = n->npipe.cmdlist;
4976 for (;;) {
4977 cmdtxt(lp->n);
4978 lp = lp->next;
4979 if (!lp)
4980 break;
4981 cmdputs(" | ");
4982 }
4983 break;
4984 case NSEMI:
4985 p = "; ";
4986 goto binop;
4987 case NAND:
4988 p = " && ";
4989 goto binop;
4990 case NOR:
4991 p = " || ";
4992 binop:
4993 cmdtxt(n->nbinary.ch1);
4994 cmdputs(p);
4995 n = n->nbinary.ch2;
4996 goto donode;
4997 case NREDIR:
4998 case NBACKGND:
4999 n = n->nredir.n;
5000 goto donode;
5001 case NNOT:
5002 cmdputs("!");
5003 n = n->nnot.com;
5004 donode:
5005 cmdtxt(n);
5006 break;
5007 case NIF:
5008 cmdputs("if ");
5009 cmdtxt(n->nif.test);
5010 cmdputs("; then ");
5011 if (n->nif.elsepart) {
5012 cmdtxt(n->nif.ifpart);
5013 cmdputs("; else ");
5014 n = n->nif.elsepart;
5015 } else {
5016 n = n->nif.ifpart;
5017 }
5018 p = "; fi";
5019 goto dotail;
5020 case NSUBSHELL:
5021 cmdputs("(");
5022 n = n->nredir.n;
5023 p = ")";
5024 goto dotail;
5025 case NWHILE:
5026 p = "while ";
5027 goto until;
5028 case NUNTIL:
5029 p = "until ";
5030 until:
5031 cmdputs(p);
5032 cmdtxt(n->nbinary.ch1);
5033 n = n->nbinary.ch2;
5034 p = "; done";
5035 dodo:
5036 cmdputs("; do ");
5037 dotail:
5038 cmdtxt(n);
5039 goto dotail2;
5040 case NFOR:
5041 cmdputs("for ");
5042 cmdputs(n->nfor.var);
5043 cmdputs(" in ");
5044 cmdlist(n->nfor.args, 1);
5045 n = n->nfor.body;
5046 p = "; done";
5047 goto dodo;
5048 case NDEFUN:
5049 cmdputs(n->ndefun.text);
5050 p = "() { ... }";
5051 goto dotail2;
5052 case NCMD:
5053 cmdlist(n->ncmd.args, 1);
5054 cmdlist(n->ncmd.redirect, 0);
5055 break;
5056 case NARG:
5057 p = n->narg.text;
5058 dotail2:
5059 cmdputs(p);
5060 break;
5061 case NHERE:
5062 case NXHERE:
5063 p = "<<...";
5064 goto dotail2;
5065 case NCASE:
5066 cmdputs("case ");
5067 cmdputs(n->ncase.expr->narg.text);
5068 cmdputs(" in ");
5069 for (np = n->ncase.cases; np; np = np->nclist.next) {
5070 cmdtxt(np->nclist.pattern);
5071 cmdputs(") ");
5072 cmdtxt(np->nclist.body);
5073 cmdputs(";; ");
5074 }
5075 p = "esac";
5076 goto dotail2;
5077 case NTO:
5078 p = ">";
5079 goto redir;
5080 case NCLOBBER:
5081 p = ">|";
5082 goto redir;
5083 case NAPPEND:
5084 p = ">>";
5085 goto redir;
5086 #if BASH_REDIR_OUTPUT
5087 case NTO2:
5088 #endif
5089 case NTOFD:
5090 p = ">&";
5091 goto redir;
5092 case NFROM:
5093 p = "<";
5094 goto redir;
5095 case NFROMFD:
5096 p = "<&";
5097 goto redir;
5098 case NFROMTO:
5099 p = "<>";
5100 redir:
5101 cmdputs(utoa(n->nfile.fd));
5102 cmdputs(p);
5103 if (n->type == NTOFD || n->type == NFROMFD) {
5104 if (n->ndup.dupfd >= 0)
5105 cmdputs(utoa(n->ndup.dupfd));
5106 else
5107 cmdputs("-");
5108 break;
5109 }
5110 n = n->nfile.fname;
5111 goto donode;
5112 }
5113 }
5114
5115 static char *
commandtext(union node * n)5116 commandtext(union node *n)
5117 {
5118 char *name;
5119
5120 STARTSTACKSTR(cmdnextc);
5121 cmdtxt(n);
5122 name = stackblock();
5123 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
5124 return ckstrdup(name);
5125 }
5126 #endif /* JOBS */
5127
5128 /*
5129 * Fork off a subshell. If we are doing job control, give the subshell its
5130 * own process group. Jp is a job structure that the job is to be added to.
5131 * N is the command that will be evaluated by the child. Both jp and n may
5132 * be NULL. The mode parameter can be one of the following:
5133 * FORK_FG - Fork off a foreground process.
5134 * FORK_BG - Fork off a background process.
5135 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
5136 * process group even if job control is on.
5137 *
5138 * When job control is turned off, background processes have their standard
5139 * input redirected to /dev/null (except for the second and later processes
5140 * in a pipeline).
5141 *
5142 * Called with interrupts off.
5143 */
5144 /*
5145 * Clear traps on a fork.
5146 */
5147 static void
clear_traps(void)5148 clear_traps(void)
5149 {
5150 char **tp;
5151
5152 INT_OFF;
5153 for (tp = trap; tp <= &trap[NTRAP_LAST]; tp++) {
5154 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
5155 if (trap_ptr == trap)
5156 free(*tp);
5157 /* else: it "belongs" to trap_ptr vector, don't free */
5158 *tp = NULL;
5159 if ((tp - trap) != 0 && (tp - trap) < NSIG)
5160 setsignal(tp - trap);
5161 }
5162 }
5163 may_have_traps = 0;
5164 INT_ON;
5165 }
5166
5167 /* Lives far away from here, needed for forkchild */
5168 static void closescript(void);
5169
5170 /* Called after fork(), in child */
5171 /* jp and n are NULL when called by openhere() for heredoc support */
5172 static NOINLINE void
forkchild(struct job * jp,union node * n,int mode)5173 forkchild(struct job *jp, union node *n, int mode)
5174 {
5175 int oldlvl;
5176
5177 TRACE(("Child shell %d\n", getpid()));
5178 oldlvl = shlvl;
5179 shlvl++;
5180
5181 /* man bash: "Non-builtin commands run by bash have signal handlers
5182 * set to the values inherited by the shell from its parent".
5183 * Do we do it correctly? */
5184
5185 closescript();
5186
5187 if (mode == FORK_NOJOB /* is it `xxx` ? */
5188 && n && n->type == NCMD /* is it single cmd? */
5189 /* && n->ncmd.args->type == NARG - always true? */
5190 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
5191 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5192 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5193 ) {
5194 TRACE(("Trap hack\n"));
5195 /* Awful hack for `trap` or $(trap).
5196 *
5197 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5198 * contains an example where "trap" is executed in a subshell:
5199 *
5200 * save_traps=$(trap)
5201 * ...
5202 * eval "$save_traps"
5203 *
5204 * Standard does not say that "trap" in subshell shall print
5205 * parent shell's traps. It only says that its output
5206 * must have suitable form, but then, in the above example
5207 * (which is not supposed to be normative), it implies that.
5208 *
5209 * bash (and probably other shell) does implement it
5210 * (traps are reset to defaults, but "trap" still shows them),
5211 * but as a result, "trap" logic is hopelessly messed up:
5212 *
5213 * # trap
5214 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
5215 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
5216 * # true | trap <--- trap is in subshell - no output (ditto)
5217 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
5218 * trap -- 'echo Ho' SIGWINCH
5219 * # echo `(trap)` <--- in subshell in subshell - output
5220 * trap -- 'echo Ho' SIGWINCH
5221 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
5222 * trap -- 'echo Ho' SIGWINCH
5223 *
5224 * The rules when to forget and when to not forget traps
5225 * get really complex and nonsensical.
5226 *
5227 * Our solution: ONLY bare $(trap) or `trap` is special.
5228 */
5229 /* Save trap handler strings for trap builtin to print */
5230 trap_ptr = xmemdup(trap, sizeof(trap));
5231 /* Fall through into clearing traps */
5232 }
5233 clear_traps();
5234 #if JOBS
5235 /* do job control only in root shell */
5236 doing_jobctl = 0;
5237 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
5238 pid_t pgrp;
5239
5240 if (jp->nprocs == 0)
5241 pgrp = getpid();
5242 else
5243 pgrp = jp->ps[0].ps_pid;
5244 /* this can fail because we are doing it in the parent also */
5245 setpgid(0, pgrp);
5246 if (mode == FORK_FG)
5247 xtcsetpgrp(ttyfd, pgrp);
5248 setsignal(SIGTSTP);
5249 setsignal(SIGTTOU);
5250 } else
5251 #endif
5252 if (mode == FORK_BG) {
5253 /* man bash: "When job control is not in effect,
5254 * asynchronous commands ignore SIGINT and SIGQUIT" */
5255 ignoresig(SIGINT);
5256 ignoresig(SIGQUIT);
5257 if (jp->nprocs == 0) {
5258 close(0);
5259 if (open(bb_dev_null, O_RDONLY) != 0)
5260 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
5261 }
5262 }
5263 if (oldlvl == 0) {
5264 if (iflag) { /* why if iflag only? */
5265 setsignal(SIGINT);
5266 setsignal(SIGTERM);
5267 }
5268 /* man bash:
5269 * "In all cases, bash ignores SIGQUIT. Non-builtin
5270 * commands run by bash have signal handlers
5271 * set to the values inherited by the shell
5272 * from its parent".
5273 * Take care of the second rule: */
5274 setsignal(SIGQUIT);
5275 }
5276 #if JOBS
5277 if (n && n->type == NCMD
5278 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
5279 ) {
5280 TRACE(("Job hack\n"));
5281 /* "jobs": we do not want to clear job list for it,
5282 * instead we remove only _its_ own_ job from job list.
5283 * This makes "jobs .... | cat" more useful.
5284 */
5285 freejob(curjob);
5286 return;
5287 }
5288 #endif
5289 for (jp = curjob; jp; jp = jp->prev_job)
5290 freejob(jp);
5291 }
5292
5293 /* Called after fork(), in parent */
5294 #if !JOBS
5295 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5296 #endif
5297 static void
forkparent(struct job * jp,union node * n,int mode,pid_t pid)5298 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5299 {
5300 TRACE(("In parent shell: child = %d\n", pid));
5301 if (!jp) /* jp is NULL when called by openhere() for heredoc support */
5302 return;
5303 #if JOBS
5304 if (mode != FORK_NOJOB && jp->jobctl) {
5305 int pgrp;
5306
5307 if (jp->nprocs == 0)
5308 pgrp = pid;
5309 else
5310 pgrp = jp->ps[0].ps_pid;
5311 /* This can fail because we are doing it in the child also */
5312 setpgid(pid, pgrp);
5313 }
5314 #endif
5315 if (mode == FORK_BG) {
5316 backgndpid = pid; /* set $! */
5317 set_curjob(jp, CUR_RUNNING);
5318 }
5319 if (jp) {
5320 struct procstat *ps = &jp->ps[jp->nprocs++];
5321 ps->ps_pid = pid;
5322 ps->ps_status = -1;
5323 ps->ps_cmd = nullstr;
5324 #if JOBS
5325 if (doing_jobctl && n)
5326 ps->ps_cmd = commandtext(n);
5327 #endif
5328 }
5329 }
5330
5331 /* jp and n are NULL when called by openhere() for heredoc support */
5332 static int
forkshell(struct job * jp,union node * n,int mode)5333 forkshell(struct job *jp, union node *n, int mode)
5334 {
5335 int pid;
5336
5337 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5338 pid = fork();
5339 if (pid < 0) {
5340 TRACE(("Fork failed, errno=%d", errno));
5341 if (jp)
5342 freejob(jp);
5343 ash_msg_and_raise_perror("can't fork");
5344 }
5345 if (pid == 0) {
5346 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
5347 forkchild(jp, n, mode);
5348 } else {
5349 forkparent(jp, n, mode, pid);
5350 }
5351 return pid;
5352 }
5353
5354 /*
5355 * Wait for job to finish.
5356 *
5357 * Under job control we have the problem that while a child process
5358 * is running interrupts generated by the user are sent to the child
5359 * but not to the shell. This means that an infinite loop started by
5360 * an interactive user may be hard to kill. With job control turned off,
5361 * an interactive user may place an interactive program inside a loop.
5362 * If the interactive program catches interrupts, the user doesn't want
5363 * these interrupts to also abort the loop. The approach we take here
5364 * is to have the shell ignore interrupt signals while waiting for a
5365 * foreground process to terminate, and then send itself an interrupt
5366 * signal if the child process was terminated by an interrupt signal.
5367 * Unfortunately, some programs want to do a bit of cleanup and then
5368 * exit on interrupt; unless these processes terminate themselves by
5369 * sending a signal to themselves (instead of calling exit) they will
5370 * confuse this approach.
5371 *
5372 * Called with interrupts off.
5373 */
5374 static int
waitforjob(struct job * jp)5375 waitforjob(struct job *jp)
5376 {
5377 int st;
5378
5379 TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
5380
5381 /* In non-interactive shells, we _can_ get
5382 * a keyboard signal here and be EINTRed, but we just loop
5383 * inside dowait(), waiting for command to complete.
5384 *
5385 * man bash:
5386 * "If bash is waiting for a command to complete and receives
5387 * a signal for which a trap has been set, the trap
5388 * will not be executed until the command completes."
5389 *
5390 * Reality is that even if trap is not set, bash
5391 * will not act on the signal until command completes.
5392 * Try this. sleep5intoff.c:
5393 * #include <signal.h>
5394 * #include <unistd.h>
5395 * int main() {
5396 * sigset_t set;
5397 * sigemptyset(&set);
5398 * sigaddset(&set, SIGINT);
5399 * sigaddset(&set, SIGQUIT);
5400 * sigprocmask(SIG_BLOCK, &set, NULL);
5401 * sleep(5);
5402 * return 0;
5403 * }
5404 * $ bash -c './sleep5intoff; echo hi'
5405 * ^C^C^C^C <--- pressing ^C once a second
5406 * $ _
5407 * $ bash -c './sleep5intoff; echo hi'
5408 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5409 * $ _
5410 */
5411 dowait(jp ? DOWAIT_BLOCK : DOWAIT_NONBLOCK, jp);
5412 if (!jp)
5413 return exitstatus;
5414
5415 st = getstatus(jp);
5416 #if JOBS
5417 if (jp->jobctl) {
5418 xtcsetpgrp(ttyfd, rootpid);
5419 restore_tty_if_stopped_or_signaled(jp);
5420
5421 /*
5422 * This is truly gross.
5423 * If we're doing job control, then we did a TIOCSPGRP which
5424 * caused us (the shell) to no longer be in the controlling
5425 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5426 * intuit from the subprocess exit status whether a SIGINT
5427 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5428 */
5429 if (jp->sigint) /* TODO: do the same with all signals */
5430 raise(SIGINT); /* ... by raise(jp->sig) instead? */
5431 }
5432 if (jp->state == JOBDONE)
5433 #endif
5434 freejob(jp);
5435 return st;
5436 }
5437
5438 /*
5439 * return 1 if there are stopped jobs, otherwise 0
5440 */
5441 static int
stoppedjobs(void)5442 stoppedjobs(void)
5443 {
5444 struct job *jp;
5445 int retval;
5446
5447 retval = 0;
5448 if (!iflag || job_warning)
5449 goto out;
5450 jp = curjob;
5451 if (jp && jp->state == JOBSTOPPED) {
5452 out2str("You have stopped jobs.\n");
5453 job_warning = 2;
5454 retval++;
5455 }
5456 out:
5457 return retval;
5458 }
5459
5460
5461 /*
5462 * Code for dealing with input/output redirection.
5463 */
5464
5465 #undef EMPTY
5466 #undef CLOSED
5467 #define EMPTY -2 /* marks an unused slot in redirtab */
5468 #define CLOSED -1 /* marks a slot of previously-closed fd */
5469
5470 /*
5471 * Handle here documents. Normally we fork off a process to write the
5472 * data to a pipe. If the document is short, we can stuff the data in
5473 * the pipe without forking.
5474 */
5475 /* openhere needs this forward reference */
5476 static void expandhere(union node *arg);
5477 static int
openhere(union node * redir)5478 openhere(union node *redir)
5479 {
5480 char *p;
5481 int pip[2];
5482 size_t len = 0;
5483
5484 if (pipe(pip) < 0)
5485 ash_msg_and_raise_perror("can't create pipe");
5486
5487 p = redir->nhere.doc->narg.text;
5488 if (redir->type == NXHERE) {
5489 expandhere(redir->nhere.doc);
5490 p = stackblock();
5491 }
5492
5493 len = strlen(p);
5494 if (len <= PIPE_BUF) {
5495 xwrite(pip[1], p, len);
5496 goto out;
5497 }
5498
5499 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5500 /* child */
5501 close(pip[0]);
5502 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5503 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5504 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5505 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5506 signal(SIGPIPE, SIG_DFL);
5507 xwrite(pip[1], p, len);
5508 _exit(EXIT_SUCCESS);
5509 }
5510 out:
5511 close(pip[1]);
5512 return pip[0];
5513 }
5514
5515 static int
openredirect(union node * redir)5516 openredirect(union node *redir)
5517 {
5518 struct stat sb;
5519 char *fname;
5520 int f;
5521
5522 switch (redir->nfile.type) {
5523 /* Can't happen, our single caller does this itself */
5524 // case NTOFD:
5525 // case NFROMFD:
5526 // return -1;
5527 case NHERE:
5528 case NXHERE:
5529 return openhere(redir);
5530 }
5531
5532 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5533 * allocated space. Do it only when we know it is safe.
5534 */
5535 fname = redir->nfile.expfname;
5536
5537 switch (redir->nfile.type) {
5538 default:
5539 #if DEBUG
5540 abort();
5541 #endif
5542 case NFROM:
5543 f = open(fname, O_RDONLY);
5544 if (f < 0)
5545 goto eopen;
5546 break;
5547 case NFROMTO:
5548 f = open(fname, O_RDWR|O_CREAT, 0666);
5549 if (f < 0)
5550 goto ecreate;
5551 break;
5552 case NTO:
5553 #if BASH_REDIR_OUTPUT
5554 case NTO2:
5555 #endif
5556 /* Take care of noclobber mode. */
5557 if (Cflag) {
5558 if (stat(fname, &sb) < 0) {
5559 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5560 if (f < 0)
5561 goto ecreate;
5562 } else if (!S_ISREG(sb.st_mode)) {
5563 f = open(fname, O_WRONLY, 0666);
5564 if (f < 0)
5565 goto ecreate;
5566 if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
5567 close(f);
5568 errno = EEXIST;
5569 goto ecreate;
5570 }
5571 } else {
5572 errno = EEXIST;
5573 goto ecreate;
5574 }
5575 break;
5576 }
5577 /* FALLTHROUGH */
5578 case NCLOBBER:
5579 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5580 if (f < 0)
5581 goto ecreate;
5582 break;
5583 case NAPPEND:
5584 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5585 if (f < 0)
5586 goto ecreate;
5587 break;
5588 }
5589
5590 return f;
5591 ecreate:
5592 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5593 eopen:
5594 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5595 }
5596
5597 /*
5598 * Copy a file descriptor to be >= 10. Throws exception on error.
5599 */
5600 static int
savefd(int from)5601 savefd(int from)
5602 {
5603 int newfd;
5604 int err;
5605
5606 newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
5607 err = newfd < 0 ? errno : 0;
5608 if (err != EBADF) {
5609 if (err)
5610 ash_msg_and_raise_perror("%d", from);
5611 close(from);
5612 if (F_DUPFD_CLOEXEC == F_DUPFD)
5613 close_on_exec_on(newfd);
5614 }
5615
5616 return newfd;
5617 }
5618 static int
dup2_or_raise(int from,int to)5619 dup2_or_raise(int from, int to)
5620 {
5621 int newfd;
5622
5623 newfd = (from != to) ? dup2(from, to) : to;
5624 if (newfd < 0) {
5625 /* Happens when source fd is not open: try "echo >&99" */
5626 ash_msg_and_raise_perror("%d", from);
5627 }
5628 return newfd;
5629 }
5630 static int
dup_CLOEXEC(int fd,int avoid_fd)5631 dup_CLOEXEC(int fd, int avoid_fd)
5632 {
5633 int newfd;
5634 repeat:
5635 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5636 if (newfd >= 0) {
5637 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
5638 close_on_exec_on(newfd);
5639 } else { /* newfd < 0 */
5640 if (errno == EBUSY)
5641 goto repeat;
5642 if (errno == EINTR)
5643 goto repeat;
5644 }
5645 return newfd;
5646 }
5647 static int
xdup_CLOEXEC_and_close(int fd,int avoid_fd)5648 xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5649 {
5650 int newfd;
5651 repeat:
5652 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5653 if (newfd < 0) {
5654 if (errno == EBUSY)
5655 goto repeat;
5656 if (errno == EINTR)
5657 goto repeat;
5658 /* fd was not open? */
5659 if (errno == EBADF)
5660 return fd;
5661 ash_msg_and_raise_perror("%d", newfd);
5662 }
5663 if (F_DUPFD_CLOEXEC == F_DUPFD)
5664 close_on_exec_on(newfd);
5665 close(fd);
5666 return newfd;
5667 }
5668
5669 /* Struct def and variable are moved down to the first usage site */
5670 struct squirrel {
5671 int orig_fd;
5672 int moved_to;
5673 };
5674 struct redirtab {
5675 struct redirtab *next;
5676 int pair_count;
5677 struct squirrel two_fd[];
5678 };
5679 #define redirlist (G_var.redirlist)
5680
5681 static void
add_squirrel_closed(struct redirtab * sq,int fd)5682 add_squirrel_closed(struct redirtab *sq, int fd)
5683 {
5684 int i;
5685
5686 if (!sq)
5687 return;
5688
5689 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5690 /* If we collide with an already moved fd... */
5691 if (fd == sq->two_fd[i].orig_fd) {
5692 /* Examples:
5693 * "echo 3>FILE 3>&- 3>FILE"
5694 * "echo 3>&- 3>FILE"
5695 * No need for last redirect to insert
5696 * another "need to close 3" indicator.
5697 */
5698 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5699 return;
5700 }
5701 }
5702 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5703 sq->two_fd[i].orig_fd = fd;
5704 sq->two_fd[i].moved_to = CLOSED;
5705 }
5706
5707 static int
save_fd_on_redirect(int fd,int avoid_fd,struct redirtab * sq)5708 save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5709 {
5710 int i, new_fd;
5711
5712 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5713 avoid_fd = 9;
5714
5715 #if JOBS
5716 if (fd == ttyfd) {
5717 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5718 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5719 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5720 return 1; /* "we closed fd" */
5721 }
5722 #endif
5723 /* Are we called from redirect(0)? E.g. redirect
5724 * in a forked child. No need to save fds,
5725 * we aren't going to use them anymore, ok to trash.
5726 */
5727 if (!sq)
5728 return 0;
5729
5730 /* If this one of script's fds? */
5731 if (fd != 0) {
5732 struct parsefile *pf = g_parsefile;
5733 while (pf) {
5734 /* We skip fd == 0 case because of the following:
5735 * $ ash # running ash interactively
5736 * $ . ./script.sh
5737 * and in script.sh: "exec 9>&0".
5738 * Even though top-level pf_fd _is_ 0,
5739 * it's still ok to use it: "read" builtin uses it,
5740 * why should we cripple "exec" builtin?
5741 */
5742 if (fd == pf->pf_fd) {
5743 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5744 return 1; /* "we closed fd" */
5745 }
5746 pf = pf->prev;
5747 }
5748 }
5749
5750 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5751
5752 /* First: do we collide with some already moved fds? */
5753 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5754 /* If we collide with an already moved fd... */
5755 if (fd == sq->two_fd[i].moved_to) {
5756 new_fd = dup_CLOEXEC(fd, avoid_fd);
5757 sq->two_fd[i].moved_to = new_fd;
5758 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5759 if (new_fd < 0) /* what? */
5760 xfunc_die();
5761 return 0; /* "we did not close fd" */
5762 }
5763 if (fd == sq->two_fd[i].orig_fd) {
5764 /* Example: echo Hello >/dev/null 1>&2 */
5765 TRACE(("redirect_fd %d: already moved\n", fd));
5766 return 0; /* "we did not close fd" */
5767 }
5768 }
5769
5770 /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
5771 new_fd = dup_CLOEXEC(fd, avoid_fd);
5772 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5773 if (new_fd < 0) {
5774 if (errno != EBADF)
5775 xfunc_die();
5776 /* new_fd = CLOSED; - already is -1 */
5777 }
5778 sq->two_fd[i].moved_to = new_fd;
5779 sq->two_fd[i].orig_fd = fd;
5780
5781 /* if we move stderr, let "set -x" code know */
5782 if (fd == preverrout_fd)
5783 preverrout_fd = new_fd;
5784
5785 return 0; /* "we did not close fd" */
5786 }
5787
5788 static int
internally_opened_fd(int fd,struct redirtab * sq)5789 internally_opened_fd(int fd, struct redirtab *sq)
5790 {
5791 int i;
5792 #if JOBS
5793 if (fd == ttyfd)
5794 return 1;
5795 #endif
5796 /* If this one of script's fds? */
5797 if (fd != 0) {
5798 struct parsefile *pf = g_parsefile;
5799 while (pf) {
5800 if (fd == pf->pf_fd)
5801 return 1;
5802 pf = pf->prev;
5803 }
5804 }
5805
5806 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5807 if (fd == sq->two_fd[i].moved_to)
5808 return 1;
5809 }
5810 return 0;
5811 }
5812
5813 /*
5814 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5815 * old file descriptors are stashed away so that the redirection can be
5816 * undone by calling popredir.
5817 */
5818 /* flags passed to redirect */
5819 #define REDIR_PUSH 01 /* save previous values of file descriptors */
5820 static void
redirect(union node * redir,int flags)5821 redirect(union node *redir, int flags)
5822 {
5823 struct redirtab *sv;
5824
5825 if (!redir)
5826 return;
5827
5828 sv = NULL;
5829 INT_OFF;
5830 if (flags & REDIR_PUSH)
5831 sv = redirlist;
5832 do {
5833 int fd;
5834 int newfd;
5835 int close_fd;
5836 int closed;
5837
5838 fd = redir->nfile.fd;
5839 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5840 //bb_error_msg("doing %d > %d", fd, newfd);
5841 newfd = redir->ndup.dupfd;
5842 close_fd = -1;
5843 } else {
5844 newfd = openredirect(redir); /* always >= 0 */
5845 if (fd == newfd) {
5846 /* open() gave us precisely the fd we wanted.
5847 * This means that this fd was not busy
5848 * (not opened to anywhere).
5849 * Remember to close it on restore:
5850 */
5851 add_squirrel_closed(sv, fd);
5852 continue;
5853 }
5854 close_fd = newfd;
5855 }
5856
5857 if (fd == newfd)
5858 continue;
5859
5860 /* if "N>FILE": move newfd to fd */
5861 /* if "N>&M": dup newfd to fd */
5862 /* if "N>&-": close fd (newfd is -1) */
5863
5864 IF_BASH_REDIR_OUTPUT(redirect_more:)
5865
5866 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5867 if (newfd == -1) {
5868 /* "N>&-" means "close me" */
5869 if (!closed) {
5870 /* ^^^ optimization: saving may already
5871 * have closed it. If not... */
5872 close(fd);
5873 }
5874 } else {
5875 /* if newfd is a script fd or saved fd, simulate EBADF */
5876 if (internally_opened_fd(newfd, sv)) {
5877 errno = EBADF;
5878 ash_msg_and_raise_perror("%d", newfd);
5879 }
5880 dup2_or_raise(newfd, fd);
5881 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5882 close(close_fd);
5883 #if BASH_REDIR_OUTPUT
5884 if (redir->nfile.type == NTO2 && fd == 1) {
5885 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5886 fd = 2;
5887 newfd = 1;
5888 close_fd = -1;
5889 goto redirect_more;
5890 }
5891 #endif
5892 }
5893 } while ((redir = redir->nfile.next) != NULL);
5894 INT_ON;
5895
5896 //dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5897 #define REDIR_SAVEFD2 0
5898 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5899 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5900 // not only for calls with flags containing REDIR_SAVEFD2.
5901 // We do this unconditionally (see save_fd_on_redirect()).
5902 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5903 // preverrout_fd = copied_fd2;
5904 }
5905
5906 static int
redirectsafe(union node * redir,int flags)5907 redirectsafe(union node *redir, int flags)
5908 {
5909 int err;
5910 volatile int saveint;
5911 struct jmploc *volatile savehandler = exception_handler;
5912 struct jmploc jmploc;
5913
5914 SAVE_INT(saveint);
5915 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5916 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
5917 if (!err) {
5918 exception_handler = &jmploc;
5919 redirect(redir, flags);
5920 }
5921 exception_handler = savehandler;
5922 if (err && exception_type != EXERROR)
5923 longjmp(exception_handler->loc, 1);
5924 RESTORE_INT(saveint);
5925 return err;
5926 }
5927
5928 #if BASH_PROCESS_SUBST
5929 static void
pushfd(int fd)5930 pushfd(int fd)
5931 {
5932 struct redirtab *sv;
5933
5934 sv = ckzalloc(sizeof(*sv) + sizeof(sv->two_fd[0]));
5935 sv->pair_count = 1;
5936 sv->two_fd[0].orig_fd = fd;
5937 sv->two_fd[0].moved_to = CLOSED;
5938 sv->next = redirlist;
5939 redirlist = sv;
5940 }
5941 #endif
5942
5943 static struct redirtab*
pushredir(union node * redir)5944 pushredir(union node *redir)
5945 {
5946 struct redirtab *sv;
5947 int i;
5948
5949 if (!redir)
5950 return redirlist;
5951
5952 i = 0;
5953 do {
5954 i++;
5955 #if BASH_REDIR_OUTPUT
5956 if (redir->nfile.type == NTO2)
5957 i++;
5958 #endif
5959 redir = redir->nfile.next;
5960 } while (redir);
5961
5962 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5963 sv->pair_count = i;
5964 while (--i >= 0)
5965 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
5966 sv->next = redirlist;
5967 redirlist = sv;
5968 return sv->next;
5969 }
5970
5971 /*
5972 * Undo the effects of the last redirection.
5973 */
5974 static void
popredir(int drop)5975 popredir(int drop)
5976 {
5977 struct redirtab *rp;
5978 int i;
5979
5980 if (redirlist == NULL)
5981 return;
5982 INT_OFF;
5983 rp = redirlist;
5984 for (i = 0; i < rp->pair_count; i++) {
5985 int fd = rp->two_fd[i].orig_fd;
5986 int copy = rp->two_fd[i].moved_to;
5987 if (copy == CLOSED) {
5988 if (!drop)
5989 close(fd);
5990 continue;
5991 }
5992 if (copy != EMPTY) {
5993 if (!drop) {
5994 /*close(fd);*/
5995 dup2_or_raise(copy, fd);
5996 }
5997 close(copy);
5998 }
5999 }
6000 redirlist = rp->next;
6001 free(rp);
6002 INT_ON;
6003 }
6004
6005 static void
unwindredir(struct redirtab * stop)6006 unwindredir(struct redirtab *stop)
6007 {
6008 while (redirlist != stop)
6009 popredir(/*drop:*/ 0);
6010 }
6011
6012
6013 /* ============ Routines to expand arguments to commands
6014 *
6015 * We have to deal with backquotes, shell variables, and file metacharacters.
6016 */
6017
6018 #if ENABLE_FEATURE_SH_MATH
6019 static arith_t
ash_arith(const char * s)6020 ash_arith(const char *s)
6021 {
6022 arith_state_t math_state;
6023 arith_t result;
6024
6025 math_state.lookupvar = lookupvar;
6026 math_state.setvar = setvar0;
6027 //math_state.endofname = endofname;
6028
6029 INT_OFF;
6030 result = arith(&math_state, s);
6031 if (math_state.errmsg)
6032 ash_msg_and_raise_error(math_state.errmsg);
6033 INT_ON;
6034
6035 return result;
6036 }
6037 #endif
6038 #if BASH_SUBSTR
6039 # if ENABLE_FEATURE_SH_MATH
substr_atoi(const char * s)6040 static int substr_atoi(const char *s)
6041 {
6042 arith_t t = ash_arith(s);
6043 if (sizeof(t) > sizeof(int)) {
6044 /* clamp very large or very large negative nums for ${v:N:M}:
6045 * else "${v:0:0x100000001}" would work as "${v:0:1}"
6046 */
6047 if (t > INT_MAX)
6048 t = INT_MAX;
6049 if (t < INT_MIN)
6050 t = INT_MIN;
6051 }
6052 return t;
6053 }
6054 # else
6055 # define substr_atoi(s) number(s)
6056 # endif
6057 #endif
6058
6059 /*
6060 * expandarg flags
6061 */
6062 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
6063 #define EXP_TILDE 0x2 /* do normal tilde expansion */
6064 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
6065 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
6066 /* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
6067 * POSIX says for this case:
6068 * Pathname expansion shall not be performed on the word by a
6069 * non-interactive shell; an interactive shell may perform it, but shall
6070 * do so only when the expansion would result in one word.
6071 * Currently, our code complies to the above rule by never globbing
6072 * redirection filenames.
6073 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
6074 * (this means that on a typical Linux distro, bash almost always
6075 * performs globbing, and thus diverges from what we do).
6076 */
6077 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
6078 #define EXP_VARTILDE2 0x20 /* expand tildes after colons only */
6079 #define EXP_WORD 0x40 /* expand word in parameter expansion */
6080 #define EXP_QUOTED 0x100 /* expand word in double quotes */
6081 #define EXP_KEEPNUL 0x200 /* do not skip NUL characters */
6082 #define EXP_DISCARD 0x400 /* discard result of expansion */
6083
6084 /*
6085 * rmescape() flags
6086 */
6087 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
6088 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
6089 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
6090 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
6091
6092 /* Add CTLESC when necessary. */
6093 #define QUOTES_ESC (EXP_FULL | EXP_CASE)
6094
6095 /*
6096 * Structure specifying which parts of the string should be searched
6097 * for IFS characters.
6098 */
6099 struct ifsregion {
6100 struct ifsregion *next; /* next region in list */
6101 int begoff; /* offset of start of region */
6102 int endoff; /* offset of end of region */
6103 int nulonly; /* search for nul bytes only */
6104 };
6105
6106 struct arglist {
6107 struct strlist *list;
6108 struct strlist **lastp;
6109 };
6110
6111 /* output of current string */
6112 static char *expdest;
6113 /* list of back quote expressions */
6114 static struct nodelist *argbackq;
6115 /* first struct in list of ifs regions */
6116 static struct ifsregion ifsfirst;
6117 /* last struct in list */
6118 static struct ifsregion *ifslastp;
6119 /* holds expanded arg list */
6120 static struct arglist exparg;
6121
6122 /*
6123 * Break the argument string into pieces based upon IFS and add the
6124 * strings to the argument list. The regions of the string to be
6125 * searched for IFS characters have been stored by recordregion.
6126 */
6127 static void
ifsbreakup(char * string,struct arglist * arglist)6128 ifsbreakup(char *string, struct arglist *arglist)
6129 {
6130 struct ifsregion *ifsp;
6131 struct strlist *sp;
6132 char *start;
6133 char *p;
6134 char *q;
6135 const char *ifs, *realifs;
6136 int ifsspc;
6137 int nulonly;
6138
6139 start = string;
6140 if (ifslastp != NULL) {
6141 ifsspc = 0;
6142 nulonly = 0;
6143 realifs = ifsset() ? ifsval() : defifs;
6144 ifsp = &ifsfirst;
6145 do {
6146 int afternul;
6147
6148 p = string + ifsp->begoff;
6149 afternul = nulonly;
6150 nulonly = ifsp->nulonly;
6151 ifs = nulonly ? nullstr : realifs;
6152 ifsspc = 0;
6153 while (p < string + ifsp->endoff) {
6154 q = p;
6155 if ((unsigned char)*p == CTLESC)
6156 p++;
6157 if (!strchr(ifs, *p)) {
6158 p++;
6159 continue;
6160 }
6161 if (!(afternul || nulonly))
6162 ifsspc = (strchr(defifs, *p) != NULL);
6163 /* Ignore IFS whitespace at start */
6164 if (q == start && ifsspc) {
6165 p++;
6166 start = p;
6167 continue;
6168 }
6169 *q = '\0';
6170 sp = stzalloc(sizeof(*sp));
6171 sp->text = start;
6172 *arglist->lastp = sp;
6173 arglist->lastp = &sp->next;
6174 p++;
6175 if (!nulonly) {
6176 for (;;) {
6177 if (p >= string + ifsp->endoff) {
6178 break;
6179 }
6180 q = p;
6181 if ((unsigned char)*p == CTLESC)
6182 p++;
6183 if (strchr(ifs, *p) == NULL) {
6184 p = q;
6185 break;
6186 }
6187 if (strchr(defifs, *p) == NULL) {
6188 if (ifsspc) {
6189 p++;
6190 ifsspc = 0;
6191 } else {
6192 p = q;
6193 break;
6194 }
6195 } else
6196 p++;
6197 }
6198 }
6199 start = p;
6200 } /* while */
6201 ifsp = ifsp->next;
6202 } while (ifsp != NULL);
6203 if (nulonly)
6204 goto add;
6205 }
6206
6207 if (!*start)
6208 return;
6209
6210 add:
6211 sp = stzalloc(sizeof(*sp));
6212 sp->text = start;
6213 *arglist->lastp = sp;
6214 arglist->lastp = &sp->next;
6215 }
6216
6217 static void
ifsfree(void)6218 ifsfree(void)
6219 {
6220 struct ifsregion *p = ifsfirst.next;
6221
6222 if (!p)
6223 goto out;
6224
6225 INT_OFF;
6226 do {
6227 struct ifsregion *ifsp;
6228 ifsp = p->next;
6229 free(p);
6230 p = ifsp;
6231 } while (p);
6232 ifsfirst.next = NULL;
6233 INT_ON;
6234 out:
6235 ifslastp = NULL;
6236 }
6237
6238 static size_t
esclen(const char * start,const char * p)6239 esclen(const char *start, const char *p)
6240 {
6241 size_t esc = 0;
6242
6243 while (p > start && (unsigned char)*--p == CTLESC) {
6244 esc++;
6245 }
6246 return esc;
6247 }
6248
6249 /*
6250 * Remove any CTLESC characters from a string.
6251 */
6252 #if !BASH_PATTERN_SUBST
6253 #define rmescapes(str, flag, slash_position) \
6254 rmescapes(str, flag)
6255 #endif
6256 static char *
rmescapes(char * str,int flag,int * slash_position)6257 rmescapes(char *str, int flag, int *slash_position)
6258 {
6259 static const char qchars[] ALIGN1 = {
6260 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
6261
6262 char *p, *q, *r;
6263 unsigned protect_against_glob;
6264 unsigned globbing;
6265
6266 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
6267 if (!p)
6268 return str;
6269
6270 q = p;
6271 r = str;
6272 if (flag & RMESCAPE_ALLOC) {
6273 size_t len = p - str;
6274 size_t fulllen = len + strlen(p) + 1;
6275
6276 if (flag & RMESCAPE_GROW) {
6277 int strloc = str - (char *)stackblock();
6278 r = makestrspace(fulllen, expdest);
6279 /* p and str may be invalidated by makestrspace */
6280 str = (char *)stackblock() + strloc;
6281 p = str + len;
6282 } else if (flag & RMESCAPE_HEAP) {
6283 r = ckmalloc(fulllen);
6284 } else {
6285 r = stalloc(fulllen);
6286 }
6287 q = r;
6288 if (len > 0) {
6289 q = (char *)mempcpy(q, str, len);
6290 }
6291 }
6292
6293 globbing = flag & RMESCAPE_GLOB;
6294 protect_against_glob = globbing;
6295 while (*p) {
6296 if ((unsigned char)*p == CTLQUOTEMARK) {
6297 // Note: protect_against_glob only affect whether
6298 // CTLESC,<ch> gets converted to <ch> or to \<ch>
6299 p++;
6300 protect_against_glob = globbing;
6301 continue;
6302 }
6303 if (*p == '\\') {
6304 /* naked back slash */
6305 protect_against_glob = 0;
6306 goto copy;
6307 }
6308 if ((unsigned char)*p == CTLESC) {
6309 p++;
6310 #if DEBUG
6311 if (*p == '\0')
6312 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6313 #endif
6314 if (protect_against_glob) {
6315 /*
6316 * We used to trust glob() and fnmatch() to eat
6317 * superfluous escapes (\z where z has no
6318 * special meaning anyway). But this causes
6319 * bugs such as string of one greek letter rho
6320 * (unicode-encoded as two bytes "cf,81")
6321 * getting encoded as "cf,CTLESC,81"
6322 * and here, converted to "cf,\,81" -
6323 * which does not go well with some flavors
6324 * of fnmatch() in unicode locales
6325 * (for example, glibc <= 2.22).
6326 *
6327 * Lets add "\" only on the chars which need it.
6328 * Testcases for less obvious chars are shown.
6329 */
6330 if (*p == '*'
6331 || *p == '?'
6332 || *p == '['
6333 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6334 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6335 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6336 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
6337 /* Some libc support [^negate], that's why "^" also needs love */
6338 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
6339 ) {
6340 *q++ = '\\';
6341 }
6342 }
6343 }
6344 #if BASH_PATTERN_SUBST
6345 else if (slash_position && p == str + *slash_position) {
6346 /* stop handling globbing */
6347 globbing = 0;
6348 *slash_position = q - r;
6349 slash_position = NULL;
6350 }
6351 #endif
6352 protect_against_glob = globbing;
6353 copy:
6354 *q++ = *p++;
6355 }
6356 *q = '\0';
6357 if (flag & RMESCAPE_GROW) {
6358 expdest = r;
6359 STADJUST(q - r + 1, expdest);
6360 }
6361 return r;
6362 }
6363 #define pmatch(a, b) !fnmatch((a), (b), 0)
6364
6365 /*
6366 * Prepare a pattern for a expmeta (internal glob(3)) call.
6367 *
6368 * Returns an stalloced string.
6369 */
6370 static char *
preglob(const char * pattern,int flag)6371 preglob(const char *pattern, int flag)
6372 {
6373 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
6374 }
6375
6376 /*
6377 * Put a string on the stack.
6378 */
6379 static size_t
memtodest(const char * p,size_t len,int flags)6380 memtodest(const char *p, size_t len, int flags)
6381 {
6382 int syntax = flags & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6383 char *q;
6384 char *s;
6385
6386 if (!len)
6387 return 0;
6388
6389 q = makestrspace(len * 2, expdest);
6390 s = q;
6391
6392 do {
6393 unsigned char c = *p++;
6394 if (c) {
6395 if (flags & QUOTES_ESC) {
6396 int n = SIT(c, syntax);
6397 if (n == CCTL
6398 || ((flags & EXP_QUOTED) && n == CBACK)
6399 ) {
6400 USTPUTC(CTLESC, q);
6401 }
6402 }
6403 } else if (!(flags & EXP_KEEPNUL))
6404 continue;
6405 USTPUTC(c, q);
6406 } while (--len);
6407
6408 expdest = q;
6409 return q - s;
6410 }
6411
6412 static size_t
strtodest(const char * p,int flags)6413 strtodest(const char *p, int flags)
6414 {
6415 size_t len = strlen(p);
6416 memtodest(p, len, flags);
6417 return len;
6418 }
6419
6420 /*
6421 * Our own itoa().
6422 * cvtnum() is used even if math support is off (to prepare $? values and such).
6423 */
6424 static int
cvtnum(arith_t num,int flags)6425 cvtnum(arith_t num, int flags)
6426 {
6427 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
6428 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
6429 int len = (sizeof(arith_t) >= 4) ? sizeof(arith_t) * 3 : sizeof(arith_t) * 3 + 2;
6430 char buf[len];
6431
6432 len = fmtstr(buf, len, ARITH_FMT, num);
6433 return memtodest(buf, len, flags);
6434 }
6435
6436 /*
6437 * Record the fact that we have to scan this region of the
6438 * string for IFS characters.
6439 */
6440 static void
recordregion(int start,int end,int nulonly)6441 recordregion(int start, int end, int nulonly)
6442 {
6443 struct ifsregion *ifsp;
6444
6445 if (ifslastp == NULL) {
6446 ifsp = &ifsfirst;
6447 } else {
6448 INT_OFF;
6449 ifsp = ckzalloc(sizeof(*ifsp));
6450 /*ifsp->next = NULL; - ckzalloc did it */
6451 ifslastp->next = ifsp;
6452 INT_ON;
6453 }
6454 ifslastp = ifsp;
6455 ifslastp->begoff = start;
6456 ifslastp->endoff = end;
6457 ifslastp->nulonly = nulonly;
6458 }
6459
6460 static void
removerecordregions(int endoff)6461 removerecordregions(int endoff)
6462 {
6463 if (ifslastp == NULL)
6464 return;
6465
6466 if (ifsfirst.endoff > endoff) {
6467 while (ifsfirst.next) {
6468 struct ifsregion *ifsp;
6469 INT_OFF;
6470 ifsp = ifsfirst.next->next;
6471 free(ifsfirst.next);
6472 ifsfirst.next = ifsp;
6473 INT_ON;
6474 }
6475 if (ifsfirst.begoff > endoff) {
6476 ifslastp = NULL;
6477 } else {
6478 ifslastp = &ifsfirst;
6479 ifsfirst.endoff = endoff;
6480 }
6481 return;
6482 }
6483
6484 ifslastp = &ifsfirst;
6485 while (ifslastp->next && ifslastp->next->begoff < endoff)
6486 ifslastp = ifslastp->next;
6487 while (ifslastp->next) {
6488 struct ifsregion *ifsp;
6489 INT_OFF;
6490 ifsp = ifslastp->next->next;
6491 free(ifslastp->next);
6492 ifslastp->next = ifsp;
6493 INT_ON;
6494 }
6495 if (ifslastp->endoff > endoff)
6496 ifslastp->endoff = endoff;
6497 }
6498
6499 static char *
exptilde(char * startp,int flag)6500 exptilde(char *startp, int flag)
6501 {
6502 unsigned char c;
6503 char *name;
6504 struct passwd *pw;
6505 const char *home;
6506 char *p;
6507
6508 p = startp;
6509 name = p + 1;
6510
6511 while ((c = *++p) != '\0') {
6512 switch (c) {
6513 case CTLESC:
6514 return startp;
6515 case CTLQUOTEMARK:
6516 return startp;
6517 case ':':
6518 if (flag & EXP_VARTILDE)
6519 goto done;
6520 break;
6521 case '/':
6522 case CTLENDVAR:
6523 goto done;
6524 }
6525 }
6526 done:
6527 if (flag & EXP_DISCARD)
6528 goto out;
6529 *p = '\0';
6530 if (*name == '\0') {
6531 home = lookupvar("HOME");
6532 } else {
6533 pw = getpwnam(name);
6534 if (pw == NULL)
6535 goto lose;
6536 home = pw->pw_dir;
6537 }
6538 *p = c;
6539 if (!home)
6540 goto lose;
6541 strtodest(home, flag | EXP_QUOTED);
6542 out:
6543 return p;
6544 lose:
6545 return startp;
6546 }
6547
6548 /*
6549 * Execute a command inside back quotes. If it's a builtin command, we
6550 * want to save its output in a block obtained from malloc. Otherwise
6551 * we fork off a subprocess and get the output of the command via a pipe.
6552 * Should be called with interrupts off.
6553 */
6554 struct backcmd { /* result of evalbackcmd */
6555 int fd; /* file descriptor to read from */
6556 int nleft; /* number of chars in buffer */
6557 char *buf; /* buffer */
6558 struct job *jp; /* job structure for command */
6559 };
6560
6561 /* These forward decls are needed to use "eval" code for backticks handling: */
6562 /* flags in argument to evaltree */
6563 #define EV_EXIT 01 /* exit after evaluating tree */
6564 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
6565 static int evaltree(union node *, int);
6566
6567 /* An evaltree() which is known to never return.
6568 * Used to use an alias:
6569 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6570 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6571 */
6572 static ALWAYS_INLINE NORETURN void
evaltreenr(union node * n,int flags)6573 evaltreenr(union node *n, int flags)
6574 {
6575 evaltree(n, flags);
6576 bb_unreachable(abort());
6577 /* NOTREACHED */
6578 }
6579
6580 static void FAST_FUNC
6581 evalbackcmd(union node *n, struct backcmd *result
6582 IF_BASH_PROCESS_SUBST(, int ctl))
6583 {
6584 int pip[2];
6585 struct job *jp;
6586 #if BASH_PROCESS_SUBST
6587 /* determine end of pipe used by parent (ip) and child (ic) */
6588 const int ip = (ctl == CTLTOPROC);
6589 const int ic = !(ctl == CTLTOPROC);
6590 #else
6591 const int ctl = CTLBACKQ;
6592 const int ip = 0;
6593 const int ic = 1;
6594 #endif
6595
6596 result->fd = -1;
6597 result->buf = NULL;
6598 result->nleft = 0;
6599 result->jp = NULL;
6600 if (n == NULL) {
6601 goto out;
6602 }
6603
6604 if (pipe(pip) < 0)
6605 ash_msg_and_raise_perror("can't create pipe");
6606 /* process substitution uses NULL job/node, like openhere() */
6607 jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL;
6608 if (forkshell(jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB) == 0) {
6609 /* child */
6610 FORCE_INT_ON;
6611 close(pip[ip]);
6612 /* ic is index of child end of pipe *and* fd to connect it to */
6613 if (pip[ic] != ic) {
6614 /*close(ic);*/
6615 dup2_or_raise(pip[ic], ic);
6616 close(pip[ic]);
6617 }
6618 /* TODO: eflag clearing makes the following not abort:
6619 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6620 * which is what bash does (unless it is in POSIX mode).
6621 * dash deleted "eflag = 0" line in the commit
6622 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6623 * [EVAL] Don't clear eflag in evalbackcmd
6624 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6625 */
6626 eflag = 0;
6627 ifsfree();
6628 evaltreenr(n, EV_EXIT);
6629 /* NOTREACHED */
6630 }
6631 /* parent */
6632 #if BASH_PROCESS_SUBST
6633 if (ctl != CTLBACKQ) {
6634 int fd = fcntl(pip[ip], F_DUPFD, 64);
6635 if (fd > 0) {
6636 close(pip[ip]);
6637 pip[ip] = fd;
6638 }
6639 pushfd(pip[ip]);
6640 }
6641 #endif
6642 close(pip[ic]);
6643 result->fd = pip[ip];
6644 result->jp = jp;
6645
6646 out:
6647 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6648 result->fd, result->buf, result->nleft, result->jp));
6649 }
6650
6651 /*
6652 * Expand stuff in backwards quotes.
6653 */
6654 static void
6655 expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl))
6656 {
6657 #if !BASH_PROCESS_SUBST
6658 const int ctl = CTLBACKQ;
6659 #endif
6660 struct backcmd in;
6661 int i;
6662 char buf[128];
6663 char *p;
6664 char *dest;
6665 int startloc;
6666 struct stackmark smark;
6667
6668 if (flag & EXP_DISCARD)
6669 goto out;
6670
6671 INT_OFF;
6672 startloc = expdest - (char *)stackblock();
6673 pushstackmark(&smark, startloc);
6674 evalbackcmd(cmd, &in IF_BASH_PROCESS_SUBST(, ctl));
6675 popstackmark(&smark);
6676
6677 if (ctl != CTLBACKQ) {
6678 sprintf(buf, DEV_FD_PREFIX"%d", in.fd);
6679 strtodest(buf, BASESYNTAX);
6680 goto done;
6681 }
6682
6683 p = in.buf;
6684 i = in.nleft;
6685 if (i == 0)
6686 goto read;
6687 for (;;) {
6688 memtodest(p, i, flag);
6689 read:
6690 if (in.fd < 0)
6691 break;
6692 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6693 TRACE(("expbackq: read returns %d\n", i));
6694 if (i <= 0)
6695 break;
6696 p = buf;
6697 }
6698
6699 free(in.buf);
6700 if (in.fd >= 0) {
6701 close(in.fd);
6702 back_exitstatus = waitforjob(in.jp);
6703 }
6704 done:
6705 INT_ON;
6706
6707 /* Eat all trailing newlines */
6708 dest = expdest;
6709 for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';)
6710 STUNPUTC(dest);
6711 expdest = dest;
6712
6713 if (!(flag & EXP_QUOTED))
6714 recordregion(startloc, dest - (char *)stackblock(), 0);
6715 TRACE(("evalbackq: size:%d:'%.*s'\n",
6716 (int)((dest - (char *)stackblock()) - startloc),
6717 (int)((dest - (char *)stackblock()) - startloc),
6718 stackblock() + startloc));
6719
6720 out:
6721 argbackq = argbackq->next;
6722 }
6723
6724 /* expari needs it */
6725 static char *argstr(char *p, int flag);
6726
6727 #if ENABLE_FEATURE_SH_MATH
6728 /*
6729 * Expand arithmetic expression. Backup to start of expression,
6730 * evaluate, place result in (backed up) result, adjust string position.
6731 */
6732 static char *
expari(char * start,int flag)6733 expari(char *start, int flag)
6734 {
6735 struct stackmark sm;
6736 int begoff;
6737 int endoff;
6738 int len;
6739 arith_t result;
6740 char *p;
6741
6742 p = stackblock();
6743 begoff = expdest - p;
6744 p = argstr(start, flag & EXP_DISCARD);
6745
6746 if (flag & EXP_DISCARD)
6747 goto out;
6748
6749 start = stackblock();
6750 endoff = expdest - start;
6751 start += begoff;
6752 STADJUST(start - expdest, expdest);
6753
6754 removerecordregions(begoff);
6755
6756 if (flag & QUOTES_ESC)
6757 rmescapes(start, 0, NULL);
6758
6759 pushstackmark(&sm, endoff);
6760 result = ash_arith(start);
6761 popstackmark(&sm);
6762
6763 len = cvtnum(result, flag);
6764
6765 if (!(flag & EXP_QUOTED))
6766 recordregion(begoff, begoff + len, 0);
6767
6768 out:
6769 return p;
6770 }
6771 #endif
6772
6773 /* argstr needs it */
6774 static char *evalvar(char *p, int flags);
6775
6776 /*
6777 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6778 * characters to allow for further processing. Otherwise treat
6779 * $@ like $* since no splitting will be performed.
6780 */
6781 static char *
argstr(char * p,int flag)6782 argstr(char *p, int flag)
6783 {
6784 static const char spclchars[] ALIGN1 = {
6785 '=',
6786 ':',
6787 CTLQUOTEMARK,
6788 CTLENDVAR,
6789 CTLESC,
6790 CTLVAR,
6791 CTLBACKQ,
6792 #if BASH_PROCESS_SUBST
6793 CTLTOPROC,
6794 CTLFROMPROC,
6795 #endif
6796 #if ENABLE_FEATURE_SH_MATH
6797 CTLARI,
6798 CTLENDARI,
6799 #endif
6800 '\0'
6801 };
6802 const char *reject = spclchars;
6803 int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6804 int inquotes;
6805 size_t length;
6806 int startloc;
6807
6808 reject += !!(flag & EXP_VARTILDE2);
6809 reject += flag & EXP_VARTILDE ? 0 : 2;
6810 inquotes = 0;
6811 length = 0;
6812 if (flag & EXP_TILDE) {
6813 flag &= ~EXP_TILDE;
6814 tilde:
6815 if (*p == '~')
6816 p = exptilde(p, flag);
6817 }
6818 start:
6819 startloc = expdest - (char *)stackblock();
6820 for (;;) {
6821 int end;
6822 unsigned char c;
6823
6824 length += strcspn(p + length, reject);
6825 end = 0;
6826 c = p[length];
6827 if (!(c & 0x80)
6828 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6829 || c == CTLENDVAR
6830 ) {
6831 /*
6832 * c == '=' || c == ':' || c == '\0' ||
6833 * c == CTLENDARI || c == CTLENDVAR
6834 */
6835 length++;
6836 /* c == '\0' || c == CTLENDARI || c == CTLENDVAR */
6837 end = !!((c - 1) & 0x80);
6838 }
6839 if (length > 0 && !(flag & EXP_DISCARD)) {
6840 int newloc;
6841 char *q;
6842
6843 q = stnputs(p, length, expdest);
6844 q[-1] &= end - 1;
6845 expdest = q - (flag & EXP_WORD ? end : 0);
6846 newloc = q - (char *)stackblock() - end;
6847 if (breakall && !inquotes && newloc > startloc) {
6848 recordregion(startloc, newloc, 0);
6849 }
6850 startloc = newloc;
6851 }
6852 p += length + 1;
6853 length = 0;
6854
6855 if (end)
6856 break;
6857
6858 switch (c) {
6859 case '=':
6860 flag |= EXP_VARTILDE2;
6861 reject++;
6862 /* fall through */
6863 case ':':
6864 /*
6865 * sort of a hack - expand tildes in variable
6866 * assignments (after the first '=' and after ':'s).
6867 */
6868 if (*--p == '~') {
6869 goto tilde;
6870 }
6871 continue;
6872 case CTLQUOTEMARK:
6873 /* "$@" syntax adherence hack */
6874 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6875 p = evalvar(p + 1, flag | EXP_QUOTED) + 1;
6876 goto start;
6877 }
6878 inquotes ^= EXP_QUOTED;
6879 addquote:
6880 if (flag & QUOTES_ESC) {
6881 p--;
6882 length++;
6883 startloc++;
6884 }
6885 break;
6886 case CTLESC:
6887 startloc++;
6888 length++;
6889 goto addquote;
6890 case CTLVAR:
6891 TRACE(("argstr: evalvar('%s')\n", p));
6892 p = evalvar(p, flag | inquotes);
6893 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6894 goto start;
6895 #if BASH_PROCESS_SUBST
6896 case CTLTOPROC:
6897 case CTLFROMPROC:
6898 #endif
6899 case CTLBACKQ:
6900 expbackq(argbackq->n, flag | inquotes IF_BASH_PROCESS_SUBST(, c));
6901 goto start;
6902 #if ENABLE_FEATURE_SH_MATH
6903 case CTLARI:
6904 p = expari(p, flag | inquotes);
6905 goto start;
6906 #endif
6907 }
6908 }
6909 return p - 1;
6910 }
6911
6912 static char *
scanleft(char * startp,char * rmesc,char * rmescend UNUSED_PARAM,char * pattern,int quotes,int zero)6913 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6914 char *pattern, int quotes, int zero)
6915 {
6916 char *loc, *loc2;
6917 char c;
6918
6919 loc = startp;
6920 loc2 = rmesc;
6921 do {
6922 int match;
6923 const char *s = loc2;
6924
6925 c = *loc2;
6926 if (zero) {
6927 *loc2 = '\0';
6928 s = rmesc;
6929 }
6930 match = pmatch(pattern, s);
6931
6932 *loc2 = c;
6933 if (match)
6934 return loc;
6935 if (quotes && (unsigned char)*loc == CTLESC)
6936 loc++;
6937 loc++;
6938 loc2++;
6939 } while (c);
6940 return NULL;
6941 }
6942
6943 static char *
scanright(char * startp,char * rmesc,char * rmescend,char * pattern,int quotes,int match_at_start)6944 scanright(char *startp, char *rmesc, char *rmescend,
6945 char *pattern, int quotes, int match_at_start)
6946 {
6947 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6948 int try2optimize = match_at_start;
6949 #endif
6950 int esc = 0;
6951 char *loc;
6952 char *loc2;
6953
6954 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6955 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6956 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6957 * Logic:
6958 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6959 * and on each iteration they go back two/one char until they reach the beginning.
6960 * We try to match "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6961 * If one of these matches, return pointer past last matched char in startp.
6962 */
6963 /* TODO: document in what other circumstances we are called. */
6964
6965 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6966 int match;
6967 char c = *loc2;
6968 const char *s = loc2;
6969 if (match_at_start) {
6970 *loc2 = '\0';
6971 s = rmesc;
6972 }
6973 match = pmatch(pattern, s);
6974 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6975 *loc2 = c;
6976 if (match)
6977 return loc;
6978 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6979 if (try2optimize) {
6980 /* Maybe we can optimize this:
6981 * if pattern ends with unescaped *, we can avoid checking
6982 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6983 * it won't match truncated "raw_value_of_" strings too.
6984 */
6985 unsigned plen = strlen(pattern);
6986 /* Does it end with "*"? */
6987 if (plen != 0 && pattern[--plen] == '*') {
6988 /* "xxxx*" is not escaped */
6989 /* "xxx\*" is escaped */
6990 /* "xx\\*" is not escaped */
6991 /* "x\\\*" is escaped */
6992 int slashes = 0;
6993 while (plen != 0 && pattern[--plen] == '\\')
6994 slashes++;
6995 if (!(slashes & 1))
6996 break; /* ends with unescaped "*" */
6997 }
6998 try2optimize = 0;
6999 }
7000 #endif
7001 loc--;
7002 if (quotes) {
7003 if (--esc < 0) {
7004 esc = esclen(startp, loc);
7005 }
7006 if (esc % 2) {
7007 esc--;
7008 loc--;
7009 }
7010 }
7011 }
7012 return NULL;
7013 }
7014
7015 static void varunset(const char *, const char *, const char *, int) NORETURN;
7016 static void
varunset(const char * end,const char * var,const char * umsg,int varflags)7017 varunset(const char *end, const char *var, const char *umsg, int varflags)
7018 {
7019 const char *msg;
7020 const char *tail;
7021
7022 tail = nullstr;
7023 msg = "parameter not set";
7024 if (umsg) {
7025 if ((unsigned char)*end == CTLENDVAR) {
7026 if (varflags & VSNUL)
7027 tail = " or null";
7028 } else {
7029 msg = umsg;
7030 }
7031 }
7032 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
7033 }
7034
7035 static char *
subevalvar(char * start,char * str,int strloc,int startloc,int varflags,int flag)7036 subevalvar(char *start, char *str, int strloc,
7037 int startloc, int varflags, int flag)
7038 {
7039 int subtype = varflags & VSTYPE;
7040 int quotes = flag & QUOTES_ESC;
7041 char *startp;
7042 char *loc;
7043 char *rmesc, *rmescend;
7044 long amount;
7045 int resetloc;
7046 int argstr_flags;
7047 IF_BASH_PATTERN_SUBST(int workloc;)
7048 IF_BASH_PATTERN_SUBST(int slash_pos;)
7049 IF_BASH_PATTERN_SUBST(char *repl;)
7050 int zero;
7051 char *(*scan)(char*, char*, char*, char*, int, int);
7052 char *p;
7053
7054 //bb_error_msg("subevalvar(start:'%s',str:'%s',strloc:%d,startloc:%d,varflags:%x,quotes:%d)",
7055 // start, str, strloc, startloc, varflags, quotes);
7056
7057 #if BASH_PATTERN_SUBST
7058 /* For "${v/pattern/repl}", we must find the delimiter _before_
7059 * argstr() call expands possible variable references in pattern:
7060 * think about "v=a; a=a/; echo ${v/$a/r}" case.
7061 */
7062 repl = NULL;
7063 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7064 /* Find '/' and replace with NUL */
7065 repl = start;
7066 /* The pattern can't be empty.
7067 * IOW: if the first char after "${v//" is a slash,
7068 * it does not terminate the pattern - it's the first char of the pattern:
7069 * v=/dev/ram; echo ${v////-} prints -dev-ram (pattern is "/")
7070 * v=/dev/ram; echo ${v///r/-} prints /dev-am (pattern is "/r")
7071 */
7072 if (*repl == '/')
7073 repl++;
7074 for (;;) {
7075 if (*repl == '\0') {
7076 repl = NULL;
7077 break;
7078 }
7079 if (*repl == '/') {
7080 *repl = '\0';
7081 break;
7082 }
7083 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
7084 if ((unsigned char)*repl == CTLESC && repl[1])
7085 repl++;
7086 repl++;
7087 }
7088 }
7089 #endif
7090 argstr_flags = (flag & EXP_DISCARD) | EXP_TILDE;
7091 if (!str
7092 #if BASH_SUBSTR
7093 && subtype != VSSUBSTR
7094 #endif
7095 ) {
7096 /* EXP_CASE keeps CTLESC's */
7097 argstr_flags |= EXP_CASE;
7098 }
7099 p = argstr(start, argstr_flags);
7100
7101 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
7102 #if BASH_PATTERN_SUBST
7103 slash_pos = -1;
7104 if (repl) {
7105 slash_pos = expdest - ((char *)stackblock() + strloc);
7106 if (!(flag & EXP_DISCARD))
7107 STPUTC('/', expdest);
7108 //bb_error_msg("repl+1:'%s'", repl + 1);
7109 p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
7110 *repl = '/';
7111 }
7112 #endif
7113 if (flag & EXP_DISCARD)
7114 return p;
7115
7116 startp = (char *)stackblock() + startloc;
7117 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
7118
7119 switch (subtype) {
7120 case VSASSIGN:
7121 setvar0(str, startp);
7122
7123 loc = startp;
7124 goto out;
7125
7126 case VSQUESTION:
7127 varunset(start, str, startp, varflags);
7128 /* NOTREACHED */
7129
7130 #if BASH_SUBSTR
7131 case VSSUBSTR: {
7132 int pos, len, orig_len;
7133 char *colon;
7134 char *vstr;
7135
7136 loc = vstr = stackblock() + strloc;
7137
7138 /* Read POS in ${var:POS:LEN} */
7139 colon = strchr(loc, ':');
7140 if (colon) *colon = '\0';
7141 pos = substr_atoi(loc);
7142 if (colon) *colon = ':';
7143
7144 /* Read LEN in ${var:POS:LEN} */
7145 len = vstr - startp - 1;
7146 /* *loc != '\0', guaranteed by parser */
7147 if (quotes) {
7148 char *ptr;
7149 /* Adjust the length by the number of escapes */
7150 for (ptr = startp; ptr < (vstr - 1); ptr++) {
7151 if ((unsigned char)*ptr == CTLESC) {
7152 len--;
7153 ptr++;
7154 }
7155 }
7156 }
7157 orig_len = len;
7158 if (*loc++ == ':') {
7159 /* ${var::LEN} */
7160 len = substr_atoi(loc);
7161 } else {
7162 /* Skip POS in ${var:POS:LEN} */
7163 len = orig_len;
7164 while (*loc && *loc != ':')
7165 loc++;
7166 if (*loc++ == ':')
7167 len = substr_atoi(loc);
7168 }
7169 if (pos < 0) {
7170 /* ${VAR:$((-n)):l} starts n chars from the end */
7171 pos = orig_len + pos;
7172 }
7173 if ((unsigned)pos >= orig_len) {
7174 /* apart from obvious ${VAR:999999:l},
7175 * covers ${VAR:$((-9999999)):l} - result is ""
7176 * (bash compat)
7177 */
7178 pos = 0;
7179 len = 0;
7180 }
7181 if (len < 0) {
7182 /* ${VAR:N:-M} sets LEN to strlen()-M */
7183 len = (orig_len - pos) + len;
7184 }
7185 if ((unsigned)len > (orig_len - pos))
7186 len = orig_len - pos;
7187
7188 if (!quotes) {
7189 loc = mempcpy(startp, startp + pos, len);
7190 } else {
7191 for (vstr = startp; pos != 0; pos--) {
7192 if ((unsigned char)*vstr == CTLESC)
7193 vstr++;
7194 vstr++;
7195 }
7196 for (loc = startp; len != 0; len--) {
7197 if ((unsigned char)*vstr == CTLESC)
7198 *loc++ = *vstr++;
7199 *loc++ = *vstr++;
7200 }
7201 }
7202 *loc = '\0';
7203 goto out;
7204 }
7205 #endif /* BASH_SUBSTR */
7206 }
7207
7208 resetloc = expdest - (char *)stackblock();
7209
7210 #if BASH_PATTERN_SUBST
7211 repl = NULL;
7212
7213 /* We'll comeback here if we grow the stack while handling
7214 * a VSREPLACE or VSREPLACEALL, since our pointers into the
7215 * stack will need rebasing, and we'll need to remove our work
7216 * areas each time
7217 */
7218 restart:
7219 #endif
7220
7221 amount = expdest - ((char *)stackblock() + resetloc);
7222 STADJUST(-amount, expdest);
7223 startp = (char *)stackblock() + startloc;
7224
7225 rmesc = startp;
7226 rmescend = (char *)stackblock() + strloc;
7227 //bb_error_msg("str7:'%s'", rmescend);
7228 if (quotes) {
7229 //TODO: how to handle slash_pos here if string changes (shortens?)
7230 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
7231 if (rmesc != startp) {
7232 rmescend = expdest;
7233 startp = (char *)stackblock() + startloc;
7234 }
7235 }
7236 rmescend--;
7237 str = (char *)stackblock() + strloc;
7238 /*
7239 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7240 * The result is a_\_z_c (not a\_\_z_c)!
7241 *
7242 * The search pattern and replace string treat backslashes differently!
7243 * "&slash_pos" causes rmescapes() to work differently on the pattern
7244 * and string. It's only used on the first call.
7245 */
7246 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7247 rmescapes(str, RMESCAPE_GLOB,
7248 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7249 );
7250
7251 #if BASH_PATTERN_SUBST
7252 workloc = expdest - (char *)stackblock();
7253 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
7254 size_t no_meta_len, first_escaped;
7255 int len;
7256 char *idx, *end;
7257
7258 if (!repl) {
7259 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
7260 repl = nullstr;
7261 if (slash_pos >= 0) {
7262 repl = str + slash_pos;
7263 *repl++ = '\0';
7264 }
7265 }
7266 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
7267
7268 /* If there's no pattern to match, return the expansion unmolested */
7269 if (str[0] == '\0')
7270 goto out1;
7271
7272 first_escaped = (str[0] == '\\' && str[1]);
7273 /* "first_escaped" trick allows to treat e.g. "\*no_glob_chars"
7274 * as literal too (as it is semi-common, and easy to accomodate
7275 * by just using str + 1).
7276 */
7277 no_meta_len = strpbrk(str + first_escaped * 2, "*?[\\") ? 0 : strlen(str);
7278 len = 0;
7279 idx = startp;
7280 end = str - 1;
7281 while (idx <= end) {
7282 try_to_match:
7283 if (no_meta_len == 0) {
7284 /* pattern has meta chars, have to glob */
7285 loc = scanright(idx, rmesc, rmescend, str, quotes, /*match_at_start:*/ 1);
7286 } else {
7287 /* Testcase for very slow replace (performs about 22k replaces):
7288 * x=::::::::::::::::::::::
7289 * 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}
7290 * echo "${x//:/|}"
7291 * To test "first_escaped" logic, replace : with *.
7292 */
7293 if (strncmp(rmesc, str + first_escaped, no_meta_len - first_escaped) != 0)
7294 goto no_match;
7295 loc = idx;
7296 if (!quotes) {
7297 loc += no_meta_len - first_escaped;
7298 } else {
7299 size_t n = no_meta_len - first_escaped;
7300 do {
7301 if ((unsigned char)*loc == CTLESC)
7302 loc++;
7303 loc++;
7304 } while (--n != 0);
7305 }
7306 }
7307 //bb_error_msg("scanright('%s'):'%s'", str, loc);
7308 if (!loc) {
7309 char *restart_detect;
7310 no_match:
7311 /* No match, advance */
7312 restart_detect = stackblock();
7313 skip_matching:
7314 if (idx >= end)
7315 break;
7316 STPUTC(*idx, expdest);
7317 if (quotes && (unsigned char)*idx == CTLESC) {
7318 idx++;
7319 len++;
7320 STPUTC(*idx, expdest);
7321 }
7322 if (stackblock() != restart_detect)
7323 goto restart;
7324 idx++;
7325 len++;
7326 rmesc++;
7327 /* continue; - prone to quadratic behavior, smarter code: */
7328 if (str[0] == '*') {
7329 /* Pattern is "*foo". If "*foo" does not match "long_string",
7330 * it would never match "ong_string" etc, no point in trying.
7331 */
7332 goto skip_matching;
7333 }
7334 goto try_to_match;
7335 }
7336
7337 if (subtype == VSREPLACEALL) {
7338 while (idx < loc) {
7339 if (quotes && (unsigned char)*idx == CTLESC)
7340 idx++;
7341 idx++;
7342 rmesc++;
7343 }
7344 } else {
7345 idx = loc;
7346 }
7347
7348 //bb_error_msg("repl:'%s'", repl);
7349 for (loc = (char*)repl; *loc; loc++) {
7350 char *restart_detect = stackblock();
7351 if (quotes && *loc == '\\') {
7352 STPUTC(CTLESC, expdest);
7353 len++;
7354 }
7355 STPUTC(*loc, expdest);
7356 if (stackblock() != restart_detect)
7357 goto restart;
7358 len++;
7359 }
7360
7361 if (subtype == VSREPLACE) {
7362 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
7363 while (*idx) {
7364 char *restart_detect = stackblock();
7365 STPUTC(*idx, expdest);
7366 if (stackblock() != restart_detect)
7367 goto restart;
7368 len++;
7369 idx++;
7370 }
7371 break;
7372 }
7373 }
7374
7375 /* We've put the replaced text into a buffer at workloc, now
7376 * move it to the right place and adjust the stack.
7377 */
7378 STPUTC('\0', expdest);
7379 startp = (char *)stackblock() + startloc;
7380 memmove(startp, (char *)stackblock() + workloc, len + 1);
7381 //bb_error_msg("startp:'%s'", startp);
7382 loc = startp + len;
7383 goto out;
7384 }
7385 #endif /* BASH_PATTERN_SUBST */
7386
7387 subtype -= VSTRIMRIGHT;
7388 #if DEBUG
7389 if (subtype < 0 || subtype > 7)
7390 abort();
7391 #endif
7392 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
7393 zero = subtype >> 1;
7394 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7395 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7396
7397 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7398 if (loc) {
7399 if (zero) {
7400 memmove(startp, loc, str - loc);
7401 loc = startp + (str - loc) - 1;
7402 }
7403 *loc = '\0';
7404 } else
7405 loc = str - 1;
7406
7407 out:
7408 amount = loc - expdest;
7409 STADJUST(amount, expdest);
7410 #if BASH_PATTERN_SUBST
7411 out1:
7412 #endif
7413 /* Remove any recorded regions beyond start of variable */
7414 removerecordregions(startloc);
7415
7416 return p;
7417 }
7418
7419 /*
7420 * Add the value of a specialized variable to the stack string.
7421 * name parameter (examples):
7422 * ash -c 'echo $1' name:'1='
7423 * ash -c 'echo $qwe' name:'qwe='
7424 * ash -c 'echo $$' name:'$='
7425 * ash -c 'echo ${$}' name:'$='
7426 * ash -c 'echo ${$##q}' name:'$=q'
7427 * ash -c 'echo ${#$}' name:'$='
7428 * note: examples with bad shell syntax:
7429 * ash -c 'echo ${#$1}' name:'$=1'
7430 * ash -c 'echo ${#1#}' name:'1=#'
7431 */
7432 static NOINLINE ssize_t
varvalue(char * name,int varflags,int flags,int quoted)7433 varvalue(char *name, int varflags, int flags, int quoted)
7434 {
7435 const char *p;
7436 int num;
7437 int i;
7438 ssize_t len = 0;
7439 int sep;
7440 int subtype = varflags & VSTYPE;
7441 int discard = (subtype == VSPLUS || subtype == VSLENGTH) | (flags & EXP_DISCARD);
7442
7443 if (!subtype) {
7444 if (discard)
7445 return -1;
7446
7447 raise_error_syntax("bad substitution");
7448 }
7449
7450 flags |= EXP_KEEPNUL;
7451 flags &= discard ? ~QUOTES_ESC : ~0;
7452 sep = (flags & EXP_FULL) << CHAR_BIT;
7453
7454 switch (*name) {
7455 case '$':
7456 num = rootpid;
7457 goto numvar;
7458 case '?':
7459 num = exitstatus;
7460 goto numvar;
7461 case '#':
7462 num = shellparam.nparam;
7463 goto numvar;
7464 case '!':
7465 num = backgndpid;
7466 if (num == 0)
7467 return -1;
7468 numvar:
7469 len = cvtnum(num, flags);
7470 goto check_1char_name;
7471 case '-':
7472 expdest = makestrspace(NOPTS, expdest);
7473 for (i = NOPTS - 1; i >= 0; i--) {
7474 if (optlist[i] && optletters(i)) {
7475 USTPUTC(optletters(i), expdest);
7476 len++;
7477 }
7478 }
7479 check_1char_name:
7480 #if 0
7481 /* handles cases similar to ${#$1} */
7482 if (name[2] != '\0')
7483 raise_error_syntax("bad substitution");
7484 #endif
7485 break;
7486 case '@':
7487 if (quoted && sep)
7488 goto param;
7489 /* fall through */
7490 case '*': {
7491 char **ap;
7492 char sepc;
7493 char c;
7494
7495 /* We will set c to 0 or ~0 depending on whether
7496 * we're doing field splitting. We won't do field
7497 * splitting if either we're quoted or sep is zero.
7498 *
7499 * Instead of testing (quoted || !sep) the following
7500 * trick optimises away any branches by using the
7501 * fact that EXP_QUOTED (which is the only bit that
7502 * can be set in quoted) is the same as EXP_FULL <<
7503 * CHAR_BIT (which is the only bit that can be set
7504 * in sep).
7505 */
7506 #if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7507 #error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7508 #endif
7509 c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7510 sep &= ~quoted;
7511 sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
7512 param:
7513 sepc = sep;
7514 ap = shellparam.p;
7515 if (!ap)
7516 return -1;
7517 while ((p = *ap++) != NULL) {
7518 len += strtodest(p, flags);
7519
7520 if (*ap && sep) {
7521 len++;
7522 memtodest(&sepc, 1, flags);
7523 }
7524 }
7525 break;
7526 } /* case '*' */
7527 case '0':
7528 case '1':
7529 case '2':
7530 case '3':
7531 case '4':
7532 case '5':
7533 case '6':
7534 case '7':
7535 case '8':
7536 case '9':
7537 num = atoi(name); /* number(name) fails on ${N#str} etc */
7538 if (num < 0 || num > shellparam.nparam)
7539 return -1;
7540 p = num ? shellparam.p[num - 1] : arg0;
7541 goto value;
7542 default:
7543 /* NB: name has form "VAR=..." */
7544 p = lookupvar(name);
7545 value:
7546 if (!p)
7547 return -1;
7548
7549 len = strtodest(p, flags);
7550 #if ENABLE_UNICODE_SUPPORT
7551 if (subtype == VSLENGTH && len > 0) {
7552 reinit_unicode_for_ash();
7553 if (unicode_status == UNICODE_ON) {
7554 STADJUST(-len, expdest);
7555 discard = 0;
7556 len = unicode_strlen(p);
7557 }
7558 }
7559 #endif
7560 break;
7561 }
7562
7563 if (discard)
7564 STADJUST(-len, expdest);
7565
7566 return len;
7567 }
7568
7569 /*
7570 * Expand a variable, and return a pointer to the next character in the
7571 * input string.
7572 */
7573 static char *
evalvar(char * p,int flag)7574 evalvar(char *p, int flag)
7575 {
7576 char varflags;
7577 char subtype;
7578 char *var;
7579 int patloc;
7580 int startloc;
7581 ssize_t varlen;
7582 int discard;
7583 int quoted;
7584
7585 varflags = (unsigned char) *p++;
7586 subtype = varflags & VSTYPE;
7587
7588 quoted = flag & EXP_QUOTED;
7589 var = p;
7590 startloc = expdest - (char *)stackblock();
7591 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
7592
7593 again:
7594 varlen = varvalue(var, varflags, flag, quoted);
7595 if (varflags & VSNUL)
7596 varlen--;
7597
7598 discard = varlen < 0 ? EXP_DISCARD : 0;
7599
7600 switch (subtype) {
7601 case VSPLUS:
7602 discard ^= EXP_DISCARD;
7603 /* fall through */
7604 case 0:
7605 case VSMINUS:
7606 p = argstr(p, flag | EXP_TILDE | EXP_WORD | (discard ^ EXP_DISCARD));
7607 goto record;
7608
7609 case VSASSIGN:
7610 case VSQUESTION:
7611 p = subevalvar(p, var, 0, startloc, varflags,
7612 (flag & ~QUOTES_ESC) | (discard ^ EXP_DISCARD));
7613
7614 if ((flag | ~discard) & EXP_DISCARD)
7615 goto record;
7616
7617 varflags &= ~VSNUL;
7618 subtype = VSNORMAL;
7619 goto again;
7620 }
7621
7622 if ((discard & ~flag) && uflag)
7623 varunset(p, var, 0, 0);
7624
7625 if (subtype == VSLENGTH) {
7626 p++;
7627 if (flag & EXP_DISCARD)
7628 return p;
7629 cvtnum(varlen > 0 ? varlen : 0, flag);
7630 goto really_record;
7631 }
7632
7633 if (subtype == VSNORMAL)
7634 goto record;
7635
7636 #if DEBUG
7637 switch (subtype) {
7638 case VSTRIMLEFT:
7639 case VSTRIMLEFTMAX:
7640 case VSTRIMRIGHT:
7641 case VSTRIMRIGHTMAX:
7642 #if BASH_SUBSTR
7643 case VSSUBSTR:
7644 #endif
7645 #if BASH_PATTERN_SUBST
7646 case VSREPLACE:
7647 case VSREPLACEALL:
7648 #endif
7649 break;
7650 default:
7651 abort();
7652 }
7653 #endif
7654
7655 flag |= discard;
7656 if (!(flag & EXP_DISCARD)) {
7657 /*
7658 * Terminate the string and start recording the pattern
7659 * right after it
7660 */
7661 STPUTC('\0', expdest);
7662 }
7663
7664 patloc = expdest - (char *)stackblock();
7665 p = subevalvar(p, NULL, patloc, startloc, varflags, flag);
7666
7667 record:
7668 if ((flag | discard) & EXP_DISCARD)
7669 return p;
7670
7671 really_record:
7672 if (quoted) {
7673 quoted = *var == '@' && shellparam.nparam;
7674 if (!quoted)
7675 return p;
7676 }
7677 recordregion(startloc, expdest - (char *)stackblock(), quoted);
7678 return p;
7679 }
7680
7681 /*
7682 * Add a file name to the list.
7683 */
7684 static void
addfname(const char * name)7685 addfname(const char *name)
7686 {
7687 struct strlist *sp;
7688
7689 sp = stzalloc(sizeof(*sp));
7690 sp->text = sstrdup(name);
7691 *exparg.lastp = sp;
7692 exparg.lastp = &sp->next;
7693 }
7694
7695 /* Avoid glob() (and thus, stat() et al) for words like "echo" */
7696 static int
hasmeta(const char * p)7697 hasmeta(const char *p)
7698 {
7699 static const char chars[] ALIGN1 = {
7700 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7701 };
7702
7703 for (;;) {
7704 p = strpbrk(p, chars);
7705 if (!p)
7706 break;
7707 switch ((unsigned char)*p) {
7708 case CTLQUOTEMARK:
7709 for (;;) {
7710 p++;
7711 if ((unsigned char)*p == CTLQUOTEMARK)
7712 break;
7713 if ((unsigned char)*p == CTLESC)
7714 p++;
7715 if (*p == '\0') /* huh? */
7716 return 0;
7717 }
7718 break;
7719 case '\\':
7720 case CTLESC:
7721 p++;
7722 if (*p == '\0')
7723 return 0;
7724 break;
7725 case '[':
7726 if (!strchr(p + 1, ']')) {
7727 /* It's not a properly closed [] pattern,
7728 * but other metas may follow. Continue checking.
7729 * my[file* _is_ globbed by bash
7730 * and matches filenames like "my[file1".
7731 */
7732 break;
7733 }
7734 /* fallthrough */
7735 default:
7736 /* case '*': */
7737 /* case '?': */
7738 return 1;
7739 }
7740 p++;
7741 }
7742
7743 return 0;
7744 }
7745
7746 /* If we want to use glob() from libc... */
7747 #if !ENABLE_ASH_INTERNAL_GLOB
7748
7749 /* Add the result of glob() to the list */
7750 static void
addglob(const glob_t * pglob)7751 addglob(const glob_t *pglob)
7752 {
7753 char **p = pglob->gl_pathv;
7754
7755 do {
7756 addfname(*p);
7757 } while (*++p);
7758 }
7759 static void
expandmeta(struct strlist * str)7760 expandmeta(struct strlist *str /*, int flag*/)
7761 {
7762 /* TODO - EXP_REDIR */
7763
7764 while (str) {
7765 char *p;
7766 glob_t pglob;
7767 int i;
7768
7769 if (fflag)
7770 goto nometa;
7771
7772 if (!hasmeta(str->text))
7773 goto nometa;
7774
7775 INT_OFF;
7776 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7777 // GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7778 // GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7779 //
7780 // glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7781 // if you pass it "file\?", it returns "file\?", not "file?", if no match.
7782 // Which means you need to unescape the string, right? Not so fast:
7783 // if there _is_ a file named "file\?" (with backslash), it is returned
7784 // as "file\?" too (whichever pattern you used to find it, say, "file*").
7785 // You DON'T KNOW by looking at the result whether you need to unescape it.
7786 //
7787 // Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7788 // returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7789 // Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7790 // With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7791 // i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7792 // i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7793 i = glob(p, 0, NULL, &pglob);
7794 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7795 if (p != str->text)
7796 free(p);
7797 switch (i) {
7798 case 0:
7799 #if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7800 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7801 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7802 goto nometa2;
7803 #endif
7804 addglob(&pglob);
7805 globfree(&pglob);
7806 INT_ON;
7807 break;
7808 case GLOB_NOMATCH:
7809 //nometa2:
7810 globfree(&pglob);
7811 INT_ON;
7812 nometa:
7813 *exparg.lastp = str;
7814 rmescapes(str->text, 0, NULL);
7815 exparg.lastp = &str->next;
7816 break;
7817 default: /* GLOB_NOSPACE */
7818 globfree(&pglob);
7819 INT_ON;
7820 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7821 }
7822 str = str->next;
7823 }
7824 }
7825
7826 #else
7827 /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7828
7829 /*
7830 * Do metacharacter (i.e. *, ?, [...]) expansion.
7831 */
7832 typedef struct exp_t {
7833 char *dir;
7834 unsigned dir_max;
7835 } exp_t;
7836 static void
expmeta(exp_t * exp,char * name,unsigned name_len,unsigned expdir_len)7837 expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
7838 {
7839 #define expdir exp->dir
7840 #define expdir_max exp->dir_max
7841 char *enddir = expdir + expdir_len;
7842 char *p;
7843 const char *cp;
7844 char *start;
7845 char *endname;
7846 int metaflag;
7847 struct stat statb;
7848 DIR *dirp;
7849 struct dirent *dp;
7850 int atend;
7851 int matchdot;
7852 int esc;
7853
7854 metaflag = 0;
7855 start = name;
7856 for (p = name; esc = 0, *p; p += esc + 1) {
7857 if (*p == '*' || *p == '?')
7858 metaflag = 1;
7859 else if (*p == '[') {
7860 char *q = p + 1;
7861 if (*q == '!')
7862 q++;
7863 for (;;) {
7864 if (*q == '\\')
7865 q++;
7866 if (*q == '/' || *q == '\0')
7867 break;
7868 if (*++q == ']') {
7869 metaflag = 1;
7870 break;
7871 }
7872 }
7873 } else {
7874 if (*p == '\\' && p[1])
7875 esc++;
7876 if (p[esc] == '/') {
7877 if (metaflag)
7878 break;
7879 start = p + esc + 1;
7880 }
7881 }
7882 }
7883 if (metaflag == 0) { /* we've reached the end of the file name */
7884 if (!expdir_len)
7885 return;
7886 p = name;
7887 do {
7888 if (*p == '\\' && p[1])
7889 p++;
7890 *enddir++ = *p;
7891 } while (*p++);
7892 if (lstat(expdir, &statb) == 0)
7893 addfname(expdir);
7894 return;
7895 }
7896 endname = p;
7897 if (name < start) {
7898 p = name;
7899 do {
7900 if (*p == '\\' && p[1])
7901 p++;
7902 *enddir++ = *p++;
7903 } while (p < start);
7904 }
7905 *enddir = '\0';
7906 cp = expdir;
7907 expdir_len = enddir - cp;
7908 if (!expdir_len)
7909 cp = ".";
7910 dirp = opendir(cp);
7911 if (dirp == NULL)
7912 return;
7913 if (*endname == 0) {
7914 atend = 1;
7915 } else {
7916 atend = 0;
7917 *endname = '\0';
7918 endname += esc + 1;
7919 }
7920 name_len -= endname - name;
7921 matchdot = 0;
7922 p = start;
7923 if (*p == '\\')
7924 p++;
7925 if (*p == '.')
7926 matchdot++;
7927 while (!pending_int && (dp = readdir(dirp)) != NULL) {
7928 if (dp->d_name[0] == '.' && !matchdot)
7929 continue;
7930 if (pmatch(start, dp->d_name)) {
7931 if (atend) {
7932 strcpy(enddir, dp->d_name);
7933 addfname(expdir);
7934 } else {
7935 unsigned offset;
7936 unsigned len;
7937
7938 p = stpcpy(enddir, dp->d_name);
7939 *p = '/';
7940
7941 offset = p - expdir + 1;
7942 len = offset + name_len + NAME_MAX;
7943 if (len > expdir_max) {
7944 len += PATH_MAX;
7945 expdir = ckrealloc(expdir, len);
7946 expdir_max = len;
7947 }
7948
7949 expmeta(exp, endname, name_len, offset);
7950 enddir = expdir + expdir_len;
7951 }
7952 }
7953 }
7954 closedir(dirp);
7955 if (!atend)
7956 endname[-esc - 1] = esc ? '\\' : '/';
7957 #undef expdir
7958 #undef expdir_max
7959 }
7960
7961 static struct strlist *
msort(struct strlist * list,int len)7962 msort(struct strlist *list, int len)
7963 {
7964 struct strlist *p, *q = NULL;
7965 struct strlist **lpp;
7966 int half;
7967 int n;
7968
7969 if (len <= 1)
7970 return list;
7971 half = len >> 1;
7972 p = list;
7973 for (n = half; --n >= 0;) {
7974 q = p;
7975 p = p->next;
7976 }
7977 q->next = NULL; /* terminate first half of list */
7978 q = msort(list, half); /* sort first half of list */
7979 p = msort(p, len - half); /* sort second half */
7980 lpp = &list;
7981 for (;;) {
7982 #if ENABLE_LOCALE_SUPPORT
7983 if (strcoll(p->text, q->text) < 0)
7984 #else
7985 if (strcmp(p->text, q->text) < 0)
7986 #endif
7987 {
7988 *lpp = p;
7989 lpp = &p->next;
7990 p = *lpp;
7991 if (p == NULL) {
7992 *lpp = q;
7993 break;
7994 }
7995 } else {
7996 *lpp = q;
7997 lpp = &q->next;
7998 q = *lpp;
7999 if (q == NULL) {
8000 *lpp = p;
8001 break;
8002 }
8003 }
8004 }
8005 return list;
8006 }
8007
8008 /*
8009 * Sort the results of file name expansion. It calculates the number of
8010 * strings to sort and then calls msort (short for merge sort) to do the
8011 * work.
8012 */
8013 static struct strlist *
expsort(struct strlist * str)8014 expsort(struct strlist *str)
8015 {
8016 int len;
8017 struct strlist *sp;
8018
8019 len = 0;
8020 for (sp = str; sp; sp = sp->next)
8021 len++;
8022 return msort(str, len);
8023 }
8024
8025 static void
expandmeta(struct strlist * str)8026 expandmeta(struct strlist *str /*, int flag*/)
8027 {
8028 /* TODO - EXP_REDIR */
8029
8030 while (str) {
8031 exp_t exp;
8032 struct strlist **savelastp;
8033 struct strlist *sp;
8034 char *p;
8035 unsigned len;
8036
8037 if (fflag)
8038 goto nometa;
8039 if (!hasmeta(str->text))
8040 goto nometa;
8041 savelastp = exparg.lastp;
8042
8043 INT_OFF;
8044 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
8045 len = strlen(p);
8046 exp.dir_max = len + PATH_MAX;
8047 exp.dir = ckmalloc(exp.dir_max);
8048
8049 expmeta(&exp, p, len, 0);
8050 free(exp.dir);
8051 if (p != str->text)
8052 free(p);
8053 INT_ON;
8054 if (exparg.lastp == savelastp) {
8055 /*
8056 * no matches
8057 */
8058 nometa:
8059 *exparg.lastp = str;
8060 rmescapes(str->text, 0, NULL);
8061 exparg.lastp = &str->next;
8062 } else {
8063 *exparg.lastp = NULL;
8064 *savelastp = sp = expsort(*savelastp);
8065 while (sp->next != NULL)
8066 sp = sp->next;
8067 exparg.lastp = &sp->next;
8068 }
8069 str = str->next;
8070 }
8071 }
8072 #endif /* ENABLE_ASH_INTERNAL_GLOB */
8073
8074 /*
8075 * Perform variable substitution and command substitution on an argument,
8076 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
8077 * perform splitting and file name expansion. When arglist is NULL, perform
8078 * here document expansion.
8079 */
8080 static void
expandarg(union node * arg,struct arglist * arglist,int flag)8081 expandarg(union node *arg, struct arglist *arglist, int flag)
8082 {
8083 struct strlist *sp;
8084 char *p;
8085
8086 argbackq = arg->narg.backquote;
8087 STARTSTACKSTR(expdest);
8088 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
8089 argstr(arg->narg.text, flag);
8090 if (arglist == NULL) {
8091 /* here document expanded */
8092 goto out;
8093 }
8094 p = grabstackstr(expdest);
8095 TRACE(("expandarg: p:'%s'\n", p));
8096 exparg.lastp = &exparg.list;
8097 /*
8098 * TODO - EXP_REDIR
8099 */
8100 if (flag & EXP_FULL) {
8101 ifsbreakup(p, &exparg);
8102 *exparg.lastp = NULL;
8103 exparg.lastp = &exparg.list;
8104 expandmeta(exparg.list /*, flag*/);
8105 } else {
8106 sp = stzalloc(sizeof(*sp));
8107 sp->text = p;
8108 *exparg.lastp = sp;
8109 exparg.lastp = &sp->next;
8110 }
8111 *exparg.lastp = NULL;
8112 if (exparg.list) {
8113 *arglist->lastp = exparg.list;
8114 arglist->lastp = exparg.lastp;
8115 }
8116
8117 out:
8118 ifsfree();
8119 }
8120
8121 /*
8122 * Expand shell variables and backquotes inside a here document.
8123 */
8124 static void
expandhere(union node * arg)8125 expandhere(union node *arg)
8126 {
8127 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
8128 }
8129
8130 /*
8131 * Returns true if the pattern matches the string.
8132 */
8133 static int
patmatch(char * pattern,const char * string)8134 patmatch(char *pattern, const char *string)
8135 {
8136 char *p = preglob(pattern, 0);
8137 int r = pmatch(p, string);
8138 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
8139 return r;
8140 }
8141
8142 /*
8143 * See if a pattern matches in a case statement.
8144 */
8145 static int
casematch(union node * pattern,char * val)8146 casematch(union node *pattern, char *val)
8147 {
8148 struct stackmark smark;
8149 int result;
8150
8151 setstackmark(&smark);
8152 argbackq = pattern->narg.backquote;
8153 STARTSTACKSTR(expdest);
8154 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
8155 ifsfree();
8156 result = patmatch(stackblock(), val);
8157 popstackmark(&smark);
8158 return result;
8159 }
8160
8161
8162 /* ============ find_command */
8163
8164 struct builtincmd {
8165 const char *name;
8166 int (*builtin)(int, char **) FAST_FUNC;
8167 /* unsigned flags; */
8168 };
8169 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
8170 /* "regular" builtins always take precedence over commands,
8171 * regardless of PATH=....%builtin... position */
8172 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
8173 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
8174
8175 struct cmdentry {
8176 smallint cmdtype; /* CMDxxx */
8177 union param {
8178 int index;
8179 /* index >= 0 for commands without path (slashes) */
8180 /* (TODO: what exactly does the value mean? PATH position?) */
8181 /* index == -1 for commands with slashes */
8182 /* index == (-2 - applet_no) for NOFORK applets */
8183 const struct builtincmd *cmd;
8184 struct funcnode *func;
8185 } u;
8186 };
8187 /* values of cmdtype */
8188 #define CMDUNKNOWN -1 /* no entry in table for command */
8189 #define CMDNORMAL 0 /* command is an executable program */
8190 #define CMDFUNCTION 1 /* command is a shell function */
8191 #define CMDBUILTIN 2 /* command is a shell builtin */
8192
8193 /* action to find_command() */
8194 #define DO_ERR 0x01 /* prints errors */
8195 #define DO_ABS 0x02 /* checks absolute paths */
8196 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
8197 #define DO_ALTPATH 0x08 /* using alternate path */
8198 #define DO_REGBLTIN 0x10 /* regular built-ins and functions only */
8199
8200 static void find_command(char *, struct cmdentry *, int, const char *);
8201
8202
8203 /* ============ Hashing commands */
8204
8205 /*
8206 * When commands are first encountered, they are entered in a hash table.
8207 * This ensures that a full path search will not have to be done for them
8208 * on each invocation.
8209 *
8210 * We should investigate converting to a linear search, even though that
8211 * would make the command name "hash" a misnomer.
8212 */
8213
8214 struct tblentry {
8215 struct tblentry *next; /* next entry in hash chain */
8216 union param param; /* definition of builtin function */
8217 smallint cmdtype; /* CMDxxx */
8218 char rehash; /* if set, cd done since entry created */
8219 char cmdname[1]; /* name of command */
8220 };
8221
8222 static struct tblentry **cmdtable;
8223 #define INIT_G_cmdtable() do { \
8224 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
8225 } while (0)
8226
8227 static int builtinloc = -1; /* index in path of %builtin, or -1 */
8228
8229
8230 static void
8231 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
8232 {
8233 #if ENABLE_FEATURE_SH_STANDALONE
8234 if (applet_no >= 0) {
8235 if (APPLET_IS_NOEXEC(applet_no)) {
8236 clearenv();
8237 while (*envp)
8238 putenv(*envp++);
8239 popredir(/*drop:*/ 1);
8240 run_noexec_applet_and_exit(applet_no, cmd, argv);
8241 }
8242 /* re-exec ourselves with the new arguments */
8243 execve(bb_busybox_exec_path, argv, envp);
8244 /* If they called chroot or otherwise made the binary no longer
8245 * executable, fall through */
8246 }
8247 #endif
8248
8249 repeat:
8250 #ifdef SYSV
8251 do {
8252 execve(cmd, argv, envp);
8253 } while (errno == EINTR);
8254 #else
8255 execve(cmd, argv, envp);
8256 #endif
8257
8258 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
8259 /* Run "cmd" as a shell script:
8260 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8261 * "If the execve() function fails with ENOEXEC, the shell
8262 * shall execute a command equivalent to having a shell invoked
8263 * with the command name as its first operand,
8264 * with any remaining arguments passed to the new shell"
8265 *
8266 * That is, do not use $SHELL, user's shell, or /bin/sh;
8267 * just call ourselves.
8268 *
8269 * Note that bash reads ~80 chars of the file, and if it sees
8270 * a zero byte before it sees newline, it doesn't try to
8271 * interpret it, but fails with "cannot execute binary file"
8272 * message and exit code 126. For one, this prevents attempts
8273 * to interpret foreign ELF binaries as shell scripts.
8274 */
8275 argv[0] = (char*) cmd;
8276 cmd = bb_busybox_exec_path;
8277 /* NB: this is only possible because all callers of shellexec()
8278 * ensure that the argv[-1] slot exists!
8279 */
8280 argv--;
8281 argv[0] = (char*) "ash";
8282 goto repeat;
8283 }
8284 }
8285
8286 /*
8287 * Exec a program. Never returns. If you change this routine, you may
8288 * have to change the find_command routine as well.
8289 * argv[-1] must exist and be writable! See tryexec() for why.
8290 */
8291 static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
shellexec(char * prog,char ** argv,const char * path,int idx)8292 static void shellexec(char *prog, char **argv, const char *path, int idx)
8293 {
8294 char *cmdname;
8295 int e;
8296 char **envp;
8297 int exerrno;
8298 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
8299
8300 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
8301 if (strchr(prog, '/') != NULL
8302 #if ENABLE_FEATURE_SH_STANDALONE
8303 || (applet_no = find_applet_by_name(prog)) >= 0
8304 #endif
8305 ) {
8306 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
8307 if (applet_no >= 0) {
8308 /* We tried execing ourself, but it didn't work.
8309 * Maybe /proc/self/exe doesn't exist?
8310 * Try $PATH search.
8311 */
8312 goto try_PATH;
8313 }
8314 e = errno;
8315 } else {
8316 try_PATH:
8317 e = ENOENT;
8318 while (padvance(&path, argv[0]) >= 0) {
8319 cmdname = stackblock();
8320 if (--idx < 0 && pathopt == NULL) {
8321 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
8322 if (errno != ENOENT && errno != ENOTDIR)
8323 e = errno;
8324 }
8325 }
8326 }
8327
8328 /* Map to POSIX errors */
8329 switch (e) {
8330 default:
8331 exerrno = 126;
8332 break;
8333 case ELOOP:
8334 case ENAMETOOLONG:
8335 case ENOENT:
8336 case ENOTDIR:
8337 exerrno = 127;
8338 break;
8339 }
8340 exitstatus = exerrno;
8341 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
8342 prog, e, suppress_int));
8343 ash_msg_and_raise(EXEND, "%s: %s", prog, errmsg(e, "not found"));
8344 /* NOTREACHED */
8345 }
8346
8347 static void
printentry(struct tblentry * cmdp)8348 printentry(struct tblentry *cmdp)
8349 {
8350 int idx;
8351 const char *path;
8352 char *name;
8353
8354 idx = cmdp->param.index;
8355 path = pathval();
8356 do {
8357 padvance(&path, cmdp->cmdname);
8358 } while (--idx >= 0);
8359 name = stackblock();
8360 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8361 }
8362
8363 /*
8364 * Clear out command entries.
8365 */
8366 static void
clearcmdentry(void)8367 clearcmdentry(void)
8368 {
8369 struct tblentry **tblp;
8370 struct tblentry **pp;
8371 struct tblentry *cmdp;
8372
8373 INT_OFF;
8374 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8375 pp = tblp;
8376 while ((cmdp = *pp) != NULL) {
8377 if (cmdp->cmdtype == CMDNORMAL
8378 || (cmdp->cmdtype == CMDBUILTIN
8379 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8380 && builtinloc > 0
8381 )
8382 ) {
8383 *pp = cmdp->next;
8384 free(cmdp);
8385 } else {
8386 pp = &cmdp->next;
8387 }
8388 }
8389 }
8390 INT_ON;
8391 }
8392
8393 /*
8394 * Locate a command in the command hash table. If "add" is nonzero,
8395 * add the command to the table if it is not already present. The
8396 * variable "lastcmdentry" is set to point to the address of the link
8397 * pointing to the entry, so that delete_cmd_entry can delete the
8398 * entry.
8399 *
8400 * Interrupts must be off if called with add != 0.
8401 */
8402 static struct tblentry **lastcmdentry;
8403
8404 static struct tblentry *
cmdlookup(const char * name,int add)8405 cmdlookup(const char *name, int add)
8406 {
8407 unsigned int hashval;
8408 const char *p;
8409 struct tblentry *cmdp;
8410 struct tblentry **pp;
8411
8412 p = name;
8413 hashval = (unsigned char)*p << 4;
8414 while (*p)
8415 hashval += (unsigned char)*p++;
8416 hashval &= 0x7FFF;
8417 pp = &cmdtable[hashval % CMDTABLESIZE];
8418 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8419 if (strcmp(cmdp->cmdname, name) == 0)
8420 break;
8421 pp = &cmdp->next;
8422 }
8423 if (add && cmdp == NULL) {
8424 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8425 + strlen(name)
8426 /* + 1 - already done because
8427 * tblentry::cmdname is char[1] */);
8428 /*cmdp->next = NULL; - ckzalloc did it */
8429 cmdp->cmdtype = CMDUNKNOWN;
8430 strcpy(cmdp->cmdname, name);
8431 }
8432 lastcmdentry = pp;
8433 return cmdp;
8434 }
8435
8436 /*
8437 * Delete the command entry returned on the last lookup.
8438 */
8439 static void
delete_cmd_entry(void)8440 delete_cmd_entry(void)
8441 {
8442 struct tblentry *cmdp;
8443
8444 INT_OFF;
8445 cmdp = *lastcmdentry;
8446 *lastcmdentry = cmdp->next;
8447 if (cmdp->cmdtype == CMDFUNCTION)
8448 freefunc(cmdp->param.func);
8449 free(cmdp);
8450 INT_ON;
8451 }
8452
8453 /*
8454 * Add a new command entry, replacing any existing command entry for
8455 * the same name - except special builtins.
8456 */
8457 static void
addcmdentry(char * name,struct cmdentry * entry)8458 addcmdentry(char *name, struct cmdentry *entry)
8459 {
8460 struct tblentry *cmdp;
8461
8462 cmdp = cmdlookup(name, 1);
8463 if (cmdp->cmdtype == CMDFUNCTION) {
8464 freefunc(cmdp->param.func);
8465 }
8466 cmdp->cmdtype = entry->cmdtype;
8467 cmdp->param = entry->u;
8468 cmdp->rehash = 0;
8469 }
8470
8471 static int FAST_FUNC
hashcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)8472 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8473 {
8474 struct tblentry **pp;
8475 struct tblentry *cmdp;
8476 int c;
8477 struct cmdentry entry;
8478 char *name;
8479
8480 if (nextopt("r") != '\0') {
8481 clearcmdentry();
8482 return 0;
8483 }
8484
8485 if (*argptr == NULL) {
8486 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8487 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8488 if (cmdp->cmdtype == CMDNORMAL)
8489 printentry(cmdp);
8490 }
8491 }
8492 return 0;
8493 }
8494
8495 c = 0;
8496 while ((name = *argptr) != NULL) {
8497 cmdp = cmdlookup(name, 0);
8498 if (cmdp != NULL
8499 && (cmdp->cmdtype == CMDNORMAL
8500 || (cmdp->cmdtype == CMDBUILTIN
8501 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8502 && builtinloc > 0
8503 )
8504 )
8505 ) {
8506 delete_cmd_entry();
8507 }
8508 find_command(name, &entry, DO_ERR, pathval());
8509 if (entry.cmdtype == CMDUNKNOWN)
8510 c = 1;
8511 argptr++;
8512 }
8513 return c;
8514 }
8515
8516 /*
8517 * Called when a cd is done. Marks all commands so the next time they
8518 * are executed they will be rehashed.
8519 */
8520 static void
hashcd(void)8521 hashcd(void)
8522 {
8523 struct tblentry **pp;
8524 struct tblentry *cmdp;
8525
8526 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8527 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8528 if (cmdp->cmdtype == CMDNORMAL
8529 || (cmdp->cmdtype == CMDBUILTIN
8530 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8531 && builtinloc > 0)
8532 ) {
8533 cmdp->rehash = 1;
8534 }
8535 }
8536 }
8537 }
8538
8539 /*
8540 * Fix command hash table when PATH changed.
8541 * Called before PATH is changed. The argument is the new value of PATH;
8542 * pathval() still returns the old value at this point.
8543 * Called with interrupts off.
8544 */
8545 static void FAST_FUNC
changepath(const char * newval)8546 changepath(const char *newval)
8547 {
8548 const char *new;
8549 int idx;
8550 int bltin;
8551
8552 new = newval;
8553 idx = 0;
8554 bltin = -1;
8555 for (;;) {
8556 if (*new == '%' && prefix(new + 1, "builtin")) {
8557 bltin = idx;
8558 break;
8559 }
8560 new = strchr(new, ':');
8561 if (!new)
8562 break;
8563 idx++;
8564 new++;
8565 }
8566 builtinloc = bltin;
8567 clearcmdentry();
8568 }
8569 enum {
8570 TEOF,
8571 TNL,
8572 TREDIR,
8573 TWORD,
8574 TSEMI,
8575 TBACKGND,
8576 TAND,
8577 TOR,
8578 TPIPE,
8579 TLP,
8580 TRP,
8581 TENDCASE,
8582 TENDBQUOTE,
8583 TNOT,
8584 TCASE,
8585 TDO,
8586 TDONE,
8587 TELIF,
8588 TELSE,
8589 TESAC,
8590 TFI,
8591 TFOR,
8592 #if BASH_FUNCTION
8593 TFUNCTION,
8594 #endif
8595 TIF,
8596 TIN,
8597 TTHEN,
8598 TUNTIL,
8599 TWHILE,
8600 TBEGIN,
8601 TEND
8602 };
8603 typedef smallint token_id_t;
8604
8605 /* Nth bit indicates if token marks the end of a list */
8606 enum {
8607 tokendlist = 0
8608 /* 0 */ | (1u << TEOF)
8609 /* 1 */ | (0u << TNL)
8610 /* 2 */ | (0u << TREDIR)
8611 /* 3 */ | (0u << TWORD)
8612 /* 4 */ | (0u << TSEMI)
8613 /* 5 */ | (0u << TBACKGND)
8614 /* 6 */ | (0u << TAND)
8615 /* 7 */ | (0u << TOR)
8616 /* 8 */ | (0u << TPIPE)
8617 /* 9 */ | (0u << TLP)
8618 /* 10 */ | (1u << TRP)
8619 /* 11 */ | (1u << TENDCASE)
8620 /* 12 */ | (1u << TENDBQUOTE)
8621 /* 13 */ | (0u << TNOT)
8622 /* 14 */ | (0u << TCASE)
8623 /* 15 */ | (1u << TDO)
8624 /* 16 */ | (1u << TDONE)
8625 /* 17 */ | (1u << TELIF)
8626 /* 18 */ | (1u << TELSE)
8627 /* 19 */ | (1u << TESAC)
8628 /* 20 */ | (1u << TFI)
8629 /* 21 */ | (0u << TFOR)
8630 #if BASH_FUNCTION
8631 /* 22 */ | (0u << TFUNCTION)
8632 #endif
8633 /* 23 */ | (0u << TIF)
8634 /* 24 */ | (0u << TIN)
8635 /* 25 */ | (1u << TTHEN)
8636 /* 26 */ | (0u << TUNTIL)
8637 /* 27 */ | (0u << TWHILE)
8638 /* 28 */ | (0u << TBEGIN)
8639 /* 29 */ | (1u << TEND)
8640 , /* thus far 29 bits used */
8641 };
8642
8643 static const char *const tokname_array[] ALIGN_PTR = {
8644 "end of file",
8645 "newline",
8646 "redirection",
8647 "word",
8648 ";",
8649 "&",
8650 "&&",
8651 "||",
8652 "|",
8653 "(",
8654 ")",
8655 ";;",
8656 "`",
8657 #define KWDOFFSET 13
8658 /* the following are keywords */
8659 "!",
8660 "case",
8661 "do",
8662 "done",
8663 "elif",
8664 "else",
8665 "esac",
8666 "fi",
8667 "for",
8668 #if BASH_FUNCTION
8669 "function",
8670 #endif
8671 "if",
8672 "in",
8673 "then",
8674 "until",
8675 "while",
8676 "{",
8677 "}",
8678 };
8679
8680 /* Wrapper around strcmp for qsort/bsearch/... */
8681 static int
pstrcmp(const void * a,const void * b)8682 pstrcmp(const void *a, const void *b)
8683 {
8684 return strcmp((char*)a, *(char**)b);
8685 }
8686
8687 static const char *const *
findkwd(const char * s)8688 findkwd(const char *s)
8689 {
8690 return bsearch(s, tokname_array + KWDOFFSET,
8691 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8692 sizeof(tokname_array[0]), pstrcmp);
8693 }
8694
8695 /*
8696 * Locate and print what a word is...
8697 */
8698 static int
describe_command(char * command,const char * path,int describe_command_verbose)8699 describe_command(char *command, const char *path, int describe_command_verbose)
8700 {
8701 struct cmdentry entry;
8702 #if ENABLE_ASH_ALIAS
8703 const struct alias *ap;
8704 #endif
8705
8706 path = path ? path : pathval();
8707
8708 if (describe_command_verbose) {
8709 out1str(command);
8710 }
8711
8712 /* First look at the keywords */
8713 if (findkwd(command)) {
8714 out1str(describe_command_verbose ? " is a shell keyword" : command);
8715 goto out;
8716 }
8717
8718 #if ENABLE_ASH_ALIAS
8719 /* Then look at the aliases */
8720 ap = lookupalias(command, 0);
8721 if (ap != NULL) {
8722 if (!describe_command_verbose) {
8723 out1str("alias ");
8724 printalias(ap);
8725 return 0;
8726 }
8727 out1fmt(" is an alias for %s", ap->val);
8728 goto out;
8729 }
8730 #endif
8731 /* Brute force */
8732 find_command(command, &entry, DO_ABS, path);
8733
8734 switch (entry.cmdtype) {
8735 case CMDNORMAL: {
8736 int j = entry.u.index;
8737 char *p;
8738 if (j < 0) {
8739 p = command;
8740 } else {
8741 do {
8742 padvance(&path, command);
8743 } while (--j >= 0);
8744 p = stackblock();
8745 }
8746 if (describe_command_verbose) {
8747 out1fmt(" is %s", p);
8748 } else {
8749 out1str(p);
8750 }
8751 break;
8752 }
8753
8754 case CMDFUNCTION:
8755 if (describe_command_verbose) {
8756 /*out1str(" is a shell function");*/
8757 out1str(" is a function"); /* bash says this */
8758 } else {
8759 out1str(command);
8760 }
8761 break;
8762
8763 case CMDBUILTIN:
8764 if (describe_command_verbose) {
8765 out1fmt(" is a %sshell builtin",
8766 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8767 "special " : nullstr
8768 );
8769 } else {
8770 out1str(command);
8771 }
8772 break;
8773
8774 default:
8775 if (describe_command_verbose) {
8776 out1str(": not found\n");
8777 }
8778 return 127;
8779 }
8780 out:
8781 out1str("\n");
8782 return 0;
8783 }
8784
8785 static int FAST_FUNC
typecmd(int argc UNUSED_PARAM,char ** argv)8786 typecmd(int argc UNUSED_PARAM, char **argv)
8787 {
8788 int i = 1;
8789 int err = 0;
8790 int verbose = 1;
8791
8792 /* type -p ... ? (we don't bother checking for 'p') */
8793 if (argv[1] && argv[1][0] == '-') {
8794 i++;
8795 verbose = 0;
8796 }
8797 while (argv[i]) {
8798 err |= describe_command(argv[i++], NULL, verbose);
8799 }
8800 return err;
8801 }
8802
8803 static struct strlist *
fill_arglist(struct arglist * arglist,union node ** argpp)8804 fill_arglist(struct arglist *arglist, union node **argpp)
8805 {
8806 struct strlist **lastp = arglist->lastp;
8807 union node *argp;
8808
8809 while ((argp = *argpp) != NULL) {
8810 expandarg(argp, arglist, EXP_FULL | EXP_TILDE);
8811 *argpp = argp->narg.next;
8812 if (*lastp)
8813 break;
8814 }
8815
8816 return *lastp;
8817 }
8818
8819 #if ENABLE_ASH_CMDCMD
8820 /* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8821 static int
parse_command_args(struct arglist * arglist,union node ** argpp,const char ** path)8822 parse_command_args(struct arglist *arglist, union node **argpp, const char **path)
8823 {
8824 struct strlist *sp = arglist->list;
8825 char *cp, c;
8826
8827 for (;;) {
8828 sp = sp->next ? sp->next : fill_arglist(arglist, argpp);
8829 if (!sp)
8830 return 0;
8831 cp = sp->text;
8832 if (*cp++ != '-')
8833 break;
8834 c = *cp++;
8835 if (!c)
8836 break;
8837 if (c == '-' && !*cp) {
8838 if (!sp->next && !fill_arglist(arglist, argpp))
8839 return 0;
8840 sp = sp->next;
8841 break;
8842 }
8843 do {
8844 switch (c) {
8845 case 'p':
8846 *path = bb_default_path;
8847 break;
8848 default:
8849 /* run 'typecmd' for other options */
8850 return 0;
8851 }
8852 c = *cp++;
8853 } while (c);
8854 }
8855
8856 arglist->list = sp;
8857 return DO_NOFUNC;
8858 }
8859
8860 static int FAST_FUNC
commandcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)8861 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8862 {
8863 char *cmd;
8864 int c;
8865 enum {
8866 VERIFY_BRIEF = 1,
8867 VERIFY_VERBOSE = 2,
8868 } verify = 0;
8869 const char *path = NULL;
8870
8871 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8872 * never reaches this function.
8873 */
8874
8875 while ((c = nextopt("pvV")) != '\0')
8876 if (c == 'V')
8877 verify |= VERIFY_VERBOSE;
8878 else if (c == 'v')
8879 /*verify |= VERIFY_BRIEF*/;
8880 #if DEBUG
8881 else if (c != 'p')
8882 abort();
8883 #endif
8884 else
8885 path = bb_default_path;
8886
8887 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8888 cmd = *argptr;
8889 if (/*verify && */ cmd)
8890 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8891
8892 return 0;
8893 }
8894 #endif
8895
8896
8897 /*static int funcblocksize; // size of structures in function */
8898 /*static int funcstringsize; // size of strings in node */
8899 static void *funcblock; /* block to allocate function from */
8900 static char *funcstring_end; /* end of block to allocate strings from */
8901
8902 static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8903 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8904 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8905 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8906 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8907 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8908 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8909 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8910 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8911 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8912 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8913 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8914 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8915 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8916 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8917 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8918 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8919 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8920 #if BASH_REDIR_OUTPUT
8921 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
8922 #endif
8923 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8924 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8925 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8926 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8927 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8928 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8929 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8930 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8931 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8932 };
8933
8934 static int calcsize(int funcblocksize, union node *n);
8935
8936 static int
sizenodelist(int funcblocksize,struct nodelist * lp)8937 sizenodelist(int funcblocksize, struct nodelist *lp)
8938 {
8939 while (lp) {
8940 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8941 funcblocksize = calcsize(funcblocksize, lp->n);
8942 lp = lp->next;
8943 }
8944 return funcblocksize;
8945 }
8946
8947 static int
calcsize(int funcblocksize,union node * n)8948 calcsize(int funcblocksize, union node *n)
8949 {
8950 if (n == NULL)
8951 return funcblocksize;
8952 funcblocksize += nodesize[n->type];
8953 switch (n->type) {
8954 case NCMD:
8955 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8956 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8957 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8958 break;
8959 case NPIPE:
8960 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8961 break;
8962 case NREDIR:
8963 case NBACKGND:
8964 case NSUBSHELL:
8965 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8966 funcblocksize = calcsize(funcblocksize, n->nredir.n);
8967 break;
8968 case NAND:
8969 case NOR:
8970 case NSEMI:
8971 case NWHILE:
8972 case NUNTIL:
8973 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8974 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
8975 break;
8976 case NIF:
8977 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8978 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8979 funcblocksize = calcsize(funcblocksize, n->nif.test);
8980 break;
8981 case NFOR:
8982 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
8983 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8984 funcblocksize = calcsize(funcblocksize, n->nfor.args);
8985 break;
8986 case NCASE:
8987 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8988 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
8989 break;
8990 case NCLIST:
8991 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8992 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8993 funcblocksize = calcsize(funcblocksize, n->nclist.next);
8994 break;
8995 case NDEFUN:
8996 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8997 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8998 break;
8999 case NARG:
9000 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
9001 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
9002 funcblocksize = calcsize(funcblocksize, n->narg.next);
9003 break;
9004 case NTO:
9005 #if BASH_REDIR_OUTPUT
9006 case NTO2:
9007 #endif
9008 case NCLOBBER:
9009 case NFROM:
9010 case NFROMTO:
9011 case NAPPEND:
9012 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
9013 funcblocksize = calcsize(funcblocksize, n->nfile.next);
9014 break;
9015 case NTOFD:
9016 case NFROMFD:
9017 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
9018 funcblocksize = calcsize(funcblocksize, n->ndup.next);
9019 break;
9020 case NHERE:
9021 case NXHERE:
9022 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
9023 funcblocksize = calcsize(funcblocksize, n->nhere.next);
9024 break;
9025 case NNOT:
9026 funcblocksize = calcsize(funcblocksize, n->nnot.com);
9027 break;
9028 };
9029 return funcblocksize;
9030 }
9031
9032 static char *
nodeckstrdup(char * s)9033 nodeckstrdup(char *s)
9034 {
9035 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
9036 return strcpy(funcstring_end, s);
9037 }
9038
9039 static union node *copynode(union node *);
9040
9041 static struct nodelist *
copynodelist(struct nodelist * lp)9042 copynodelist(struct nodelist *lp)
9043 {
9044 struct nodelist *start;
9045 struct nodelist **lpp;
9046
9047 lpp = &start;
9048 while (lp) {
9049 *lpp = funcblock;
9050 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
9051 (*lpp)->n = copynode(lp->n);
9052 lp = lp->next;
9053 lpp = &(*lpp)->next;
9054 }
9055 *lpp = NULL;
9056 return start;
9057 }
9058
9059 static union node *
copynode(union node * n)9060 copynode(union node *n)
9061 {
9062 union node *new;
9063
9064 if (n == NULL)
9065 return NULL;
9066 new = funcblock;
9067 funcblock = (char *) funcblock + nodesize[n->type];
9068
9069 switch (n->type) {
9070 case NCMD:
9071 new->ncmd.redirect = copynode(n->ncmd.redirect);
9072 new->ncmd.args = copynode(n->ncmd.args);
9073 new->ncmd.assign = copynode(n->ncmd.assign);
9074 new->ncmd.linno = n->ncmd.linno;
9075 break;
9076 case NPIPE:
9077 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
9078 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
9079 break;
9080 case NREDIR:
9081 case NBACKGND:
9082 case NSUBSHELL:
9083 new->nredir.redirect = copynode(n->nredir.redirect);
9084 new->nredir.n = copynode(n->nredir.n);
9085 new->nredir.linno = n->nredir.linno;
9086 break;
9087 case NAND:
9088 case NOR:
9089 case NSEMI:
9090 case NWHILE:
9091 case NUNTIL:
9092 new->nbinary.ch2 = copynode(n->nbinary.ch2);
9093 new->nbinary.ch1 = copynode(n->nbinary.ch1);
9094 break;
9095 case NIF:
9096 new->nif.elsepart = copynode(n->nif.elsepart);
9097 new->nif.ifpart = copynode(n->nif.ifpart);
9098 new->nif.test = copynode(n->nif.test);
9099 break;
9100 case NFOR:
9101 new->nfor.var = nodeckstrdup(n->nfor.var);
9102 new->nfor.body = copynode(n->nfor.body);
9103 new->nfor.args = copynode(n->nfor.args);
9104 new->nfor.linno = n->nfor.linno;
9105 break;
9106 case NCASE:
9107 new->ncase.cases = copynode(n->ncase.cases);
9108 new->ncase.expr = copynode(n->ncase.expr);
9109 new->ncase.linno = n->ncase.linno;
9110 break;
9111 case NCLIST:
9112 new->nclist.body = copynode(n->nclist.body);
9113 new->nclist.pattern = copynode(n->nclist.pattern);
9114 new->nclist.next = copynode(n->nclist.next);
9115 break;
9116 case NDEFUN:
9117 new->ndefun.body = copynode(n->ndefun.body);
9118 new->ndefun.text = nodeckstrdup(n->ndefun.text);
9119 new->ndefun.linno = n->ndefun.linno;
9120 break;
9121 case NARG:
9122 new->narg.backquote = copynodelist(n->narg.backquote);
9123 new->narg.text = nodeckstrdup(n->narg.text);
9124 new->narg.next = copynode(n->narg.next);
9125 break;
9126 case NTO:
9127 #if BASH_REDIR_OUTPUT
9128 case NTO2:
9129 #endif
9130 case NCLOBBER:
9131 case NFROM:
9132 case NFROMTO:
9133 case NAPPEND:
9134 new->nfile.fname = copynode(n->nfile.fname);
9135 new->nfile.fd = n->nfile.fd;
9136 new->nfile.next = copynode(n->nfile.next);
9137 break;
9138 case NTOFD:
9139 case NFROMFD:
9140 new->ndup.vname = copynode(n->ndup.vname);
9141 new->ndup.dupfd = n->ndup.dupfd;
9142 new->ndup.fd = n->ndup.fd;
9143 new->ndup.next = copynode(n->ndup.next);
9144 break;
9145 case NHERE:
9146 case NXHERE:
9147 new->nhere.doc = copynode(n->nhere.doc);
9148 new->nhere.fd = n->nhere.fd;
9149 new->nhere.next = copynode(n->nhere.next);
9150 break;
9151 case NNOT:
9152 new->nnot.com = copynode(n->nnot.com);
9153 break;
9154 };
9155 new->type = n->type;
9156 return new;
9157 }
9158
9159 /*
9160 * Make a copy of a parse tree.
9161 */
9162 static struct funcnode *
copyfunc(union node * n)9163 copyfunc(union node *n)
9164 {
9165 struct funcnode *f;
9166 size_t blocksize;
9167
9168 /*funcstringsize = 0;*/
9169 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
9170 f = ckzalloc(blocksize /* + funcstringsize */);
9171 funcblock = (char *) f + offsetof(struct funcnode, n);
9172 funcstring_end = (char *) f + blocksize;
9173 copynode(n);
9174 /* f->count = 0; - ckzalloc did it */
9175 return f;
9176 }
9177
9178 /*
9179 * Define a shell function.
9180 */
9181 static void
defun(union node * func)9182 defun(union node *func)
9183 {
9184 struct cmdentry entry;
9185
9186 INT_OFF;
9187 entry.cmdtype = CMDFUNCTION;
9188 entry.u.func = copyfunc(func);
9189 addcmdentry(func->ndefun.text, &entry);
9190 INT_ON;
9191 }
9192
9193 /* Reasons for skipping commands (see comment on breakcmd routine) */
9194 #define SKIPBREAK (1 << 0)
9195 #define SKIPCONT (1 << 1)
9196 #define SKIPFUNC (1 << 2)
9197 #define SKIPFUNCDEF (1 << 3)
9198 static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
9199 static int skipcount; /* number of levels to skip */
9200 static int loopnest; /* current loop nesting level */
9201 static int funcline; /* starting line number of current function, or 0 if not in a function */
9202
9203 /* Forward decl way out to parsing code - dotrap needs it */
9204 static int evalstring(char *s, int flags);
9205
9206 /* Called to execute a trap.
9207 * Single callsite - at the end of evaltree().
9208 * If we return non-zero, evaltree raises EXEXIT exception.
9209 *
9210 * Perhaps we should avoid entering new trap handlers
9211 * while we are executing a trap handler. [is it a TODO?]
9212 */
9213 static void
dotrap(void)9214 dotrap(void)
9215 {
9216 uint8_t *g;
9217 int sig;
9218 int status, last_status;
9219
9220 if (!pending_sig)
9221 return;
9222
9223 status = savestatus;
9224 last_status = status;
9225 if (status < 0) {
9226 status = exitstatus;
9227 savestatus = status;
9228 }
9229 pending_sig = 0;
9230 barrier();
9231
9232 TRACE(("dotrap entered\n"));
9233 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
9234 char *p;
9235
9236 if (!*g)
9237 continue;
9238
9239 if (evalskip) {
9240 pending_sig = sig;
9241 break;
9242 }
9243
9244 p = trap[sig];
9245 /* non-trapped SIGINT is handled separately by raise_interrupt,
9246 * don't upset it by resetting gotsig[SIGINT-1] */
9247 if (sig == SIGINT && !p)
9248 continue;
9249
9250 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
9251 *g = 0;
9252 if (!p)
9253 continue;
9254 trap_depth++;
9255 evalstring(p, 0);
9256 trap_depth--;
9257 if (evalskip != SKIPFUNC)
9258 exitstatus = status;
9259 }
9260
9261 savestatus = last_status;
9262 TRACE(("dotrap returns\n"));
9263 }
9264
9265 /* forward declarations - evaluation is fairly recursive business... */
9266 static int evalloop(union node *, int);
9267 static int evalfor(union node *, int);
9268 static int evalcase(union node *, int);
9269 static int evalsubshell(union node *, int);
9270 static void expredir(union node *);
9271 static int evalpipe(union node *, int);
9272 static int evalcommand(union node *, int);
9273 static int evalbltin(const struct builtincmd *, int, char **, int);
9274 static void prehash(union node *);
9275
9276 /*
9277 * Evaluate a parse tree. The value is left in the global variable
9278 * exitstatus.
9279 */
9280 static int
evaltree(union node * n,int flags)9281 evaltree(union node *n, int flags)
9282 {
9283 int checkexit = 0;
9284 int (*evalfn)(union node *, int);
9285 struct stackmark smark;
9286 int status = 0;
9287
9288 setstackmark(&smark);
9289
9290 if (nflag)
9291 goto out;
9292
9293 if (n == NULL) {
9294 TRACE(("evaltree(NULL) called\n"));
9295 goto out;
9296 }
9297 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
9298
9299 dotrap();
9300
9301 switch (n->type) {
9302 default:
9303 #if DEBUG
9304 out1fmt("Node type = %d\n", n->type);
9305 fflush_all();
9306 break;
9307 #endif
9308 case NNOT:
9309 status = !evaltree(n->nnot.com, EV_TESTED);
9310 goto setstatus;
9311 case NREDIR:
9312 errlinno = lineno = n->nredir.linno;
9313 expredir(n->nredir.redirect);
9314 pushredir(n->nredir.redirect);
9315 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9316 if (!status) {
9317 status = evaltree(n->nredir.n, flags & EV_TESTED);
9318 }
9319 if (n->nredir.redirect)
9320 popredir(/*drop:*/ 0);
9321 goto setstatus;
9322 case NCMD:
9323 evalfn = evalcommand;
9324 checkexit:
9325 checkexit = ~flags & EV_TESTED;
9326 goto calleval;
9327 case NFOR:
9328 evalfn = evalfor;
9329 goto calleval;
9330 case NWHILE:
9331 case NUNTIL:
9332 evalfn = evalloop;
9333 goto calleval;
9334 case NSUBSHELL:
9335 case NBACKGND:
9336 evalfn = evalsubshell;
9337 goto checkexit;
9338 case NPIPE:
9339 evalfn = evalpipe;
9340 goto checkexit;
9341 case NCASE:
9342 evalfn = evalcase;
9343 goto calleval;
9344 case NAND:
9345 case NOR:
9346 case NSEMI: {
9347 #if NAND + 1 != NOR
9348 #error NAND + 1 != NOR
9349 #endif
9350 #if NOR + 1 != NSEMI
9351 #error NOR + 1 != NSEMI
9352 #endif
9353 unsigned is_or = n->type - NAND;
9354 status = evaltree(
9355 n->nbinary.ch1,
9356 (flags | ((is_or >> 1) - 1)) & EV_TESTED
9357 );
9358 if ((!status) == is_or || evalskip)
9359 break;
9360 n = n->nbinary.ch2;
9361 evaln:
9362 evalfn = evaltree;
9363 calleval:
9364 status = evalfn(n, flags);
9365 goto setstatus;
9366 }
9367 case NIF:
9368 status = evaltree(n->nif.test, EV_TESTED);
9369 if (evalskip)
9370 break;
9371 if (!status) {
9372 n = n->nif.ifpart;
9373 goto evaln;
9374 } else if (n->nif.elsepart) {
9375 n = n->nif.elsepart;
9376 goto evaln;
9377 }
9378 status = 0;
9379 goto setstatus;
9380 case NDEFUN:
9381 defun(n);
9382 /* Not necessary. To test it:
9383 * "false; f() { qwerty; }; echo $?" should print 0.
9384 */
9385 /* status = 0; */
9386 setstatus:
9387 exitstatus = status;
9388 break;
9389 }
9390 out:
9391 /* Order of checks below is important:
9392 * signal handlers trigger before exit caused by "set -e".
9393 */
9394 dotrap();
9395
9396 if (checkexit && status) {
9397 if (trap[NTRAP_ERR] && !in_trap_ERR) {
9398 int err;
9399 struct jmploc *volatile savehandler = exception_handler;
9400 struct jmploc jmploc;
9401
9402 in_trap_ERR = 1;
9403 trap_depth++;
9404 err = setjmp(jmploc.loc);
9405 if (!err) {
9406 exception_handler = &jmploc;
9407 savestatus = exitstatus;
9408 evalstring(trap[NTRAP_ERR], 0);
9409 }
9410 trap_depth--;
9411 in_trap_ERR = 0;
9412
9413 exception_handler = savehandler;
9414 if (err && exception_type != EXERROR)
9415 longjmp(exception_handler->loc, 1);
9416
9417 exitstatus = savestatus;
9418 }
9419 if (eflag)
9420 goto exexit;
9421 }
9422 if (flags & EV_EXIT) {
9423 exexit:
9424 raise_exception(EXEND);
9425 }
9426
9427 popstackmark(&smark);
9428 TRACE(("leaving evaltree (no interrupts)\n"));
9429 return exitstatus;
9430 }
9431
9432 static int
skiploop(void)9433 skiploop(void)
9434 {
9435 int skip = evalskip;
9436
9437 switch (skip) {
9438 case 0:
9439 break;
9440 case SKIPBREAK:
9441 case SKIPCONT:
9442 if (--skipcount <= 0) {
9443 evalskip = 0;
9444 break;
9445 }
9446 skip = SKIPBREAK;
9447 break;
9448 }
9449 return skip;
9450 }
9451
9452 static int
evalloop(union node * n,int flags)9453 evalloop(union node *n, int flags)
9454 {
9455 int skip;
9456 int status;
9457
9458 loopnest++;
9459 status = 0;
9460 flags &= EV_TESTED;
9461 do {
9462 int i;
9463
9464 i = evaltree(n->nbinary.ch1, EV_TESTED);
9465 skip = skiploop();
9466 if (skip == SKIPFUNC)
9467 status = i;
9468 if (skip)
9469 continue;
9470 if (n->type != NWHILE)
9471 i = !i;
9472 if (i != 0)
9473 break;
9474 status = evaltree(n->nbinary.ch2, flags);
9475 skip = skiploop();
9476 } while (!(skip & ~SKIPCONT));
9477 loopnest--;
9478
9479 return status;
9480 }
9481
9482 static int
evalfor(union node * n,int flags)9483 evalfor(union node *n, int flags)
9484 {
9485 struct arglist arglist;
9486 union node *argp;
9487 struct strlist *sp;
9488 int status = 0;
9489
9490 errlinno = lineno = n->ncase.linno;
9491
9492 arglist.list = NULL;
9493 arglist.lastp = &arglist.list;
9494 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
9495 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9496 }
9497 *arglist.lastp = NULL;
9498
9499 loopnest++;
9500 flags &= EV_TESTED;
9501 for (sp = arglist.list; sp; sp = sp->next) {
9502 setvar0(n->nfor.var, sp->text);
9503 status = evaltree(n->nfor.body, flags);
9504 if (skiploop() & ~SKIPCONT)
9505 break;
9506 }
9507 loopnest--;
9508
9509 return status;
9510 }
9511
9512 static int
evalcase(union node * n,int flags)9513 evalcase(union node *n, int flags)
9514 {
9515 union node *cp;
9516 union node *patp;
9517 struct arglist arglist;
9518 int status = 0;
9519
9520 errlinno = lineno = n->ncase.linno;
9521
9522 arglist.list = NULL;
9523 arglist.lastp = &arglist.list;
9524 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
9525 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9526 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
9527 if (casematch(patp, arglist.list->text)) {
9528 /* Ensure body is non-empty as otherwise
9529 * EV_EXIT may prevent us from setting the
9530 * exit status.
9531 */
9532 if (evalskip == 0 && cp->nclist.body) {
9533 status = evaltree(cp->nclist.body, flags);
9534 }
9535 goto out;
9536 }
9537 }
9538 }
9539 out:
9540 return status;
9541 }
9542
9543 /*
9544 * Kick off a subshell to evaluate a tree.
9545 */
9546 static int
evalsubshell(union node * n,int flags)9547 evalsubshell(union node *n, int flags)
9548 {
9549 struct job *jp;
9550 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9551 int status;
9552
9553 errlinno = lineno = n->nredir.linno;
9554
9555 expredir(n->nredir.redirect);
9556 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9557 goto nofork;
9558 INT_OFF;
9559 if (backgnd == FORK_FG)
9560 get_tty_state();
9561 jp = makejob(/*n,*/ 1);
9562 if (forkshell(jp, n, backgnd) == 0) {
9563 /* child */
9564 INT_ON;
9565 flags |= EV_EXIT;
9566 if (backgnd)
9567 flags &= ~EV_TESTED;
9568 nofork:
9569 redirect(n->nredir.redirect, 0);
9570 evaltreenr(n->nredir.n, flags);
9571 /* never returns */
9572 }
9573 /* parent */
9574 status = 0;
9575 if (backgnd == FORK_FG)
9576 status = waitforjob(jp);
9577 INT_ON;
9578 return status;
9579 }
9580
9581 /*
9582 * Compute the names of the files in a redirection list.
9583 */
9584 static void fixredir(union node *, const char *, int);
9585 static void
expredir(union node * n)9586 expredir(union node *n)
9587 {
9588 union node *redir;
9589
9590 for (redir = n; redir; redir = redir->nfile.next) {
9591 struct arglist fn;
9592
9593 fn.list = NULL;
9594 fn.lastp = &fn.list;
9595 switch (redir->type) {
9596 case NFROMTO:
9597 case NFROM:
9598 case NTO:
9599 #if BASH_REDIR_OUTPUT
9600 case NTO2:
9601 #endif
9602 case NCLOBBER:
9603 case NAPPEND:
9604 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
9605 TRACE(("expredir expanded to '%s'\n", fn.list->text));
9606 #if BASH_REDIR_OUTPUT
9607 store_expfname:
9608 #endif
9609 #if 0
9610 // By the design of stack allocator, the loop of this kind:
9611 // while true; do while true; do break; done </dev/null; done
9612 // will look like a memory leak: ash plans to free expfname's
9613 // of "/dev/null" as soon as it finishes running the loop
9614 // (in this case, never).
9615 // This "fix" is wrong:
9616 if (redir->nfile.expfname)
9617 stunalloc(redir->nfile.expfname);
9618 // It results in corrupted state of stacked allocations.
9619 #endif
9620 redir->nfile.expfname = fn.list->text;
9621 break;
9622 case NFROMFD:
9623 case NTOFD: /* >& */
9624 if (redir->ndup.vname) {
9625 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
9626 if (fn.list == NULL)
9627 ash_msg_and_raise_error("redir error");
9628 #if BASH_REDIR_OUTPUT
9629 if (!isdigit_str9(fn.list->text)) {
9630 /* >&file, not >&fd */
9631 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9632 ash_msg_and_raise_error("redir error");
9633 redir->type = NTO2;
9634 goto store_expfname;
9635 }
9636 #endif
9637 fixredir(redir, fn.list->text, 1);
9638 }
9639 break;
9640 }
9641 }
9642 }
9643
9644 /*
9645 * Evaluate a pipeline. All the processes in the pipeline are children
9646 * of the process creating the pipeline. (This differs from some versions
9647 * of the shell, which make the last process in a pipeline the parent
9648 * of all the rest.)
9649 */
9650 static int
evalpipe(union node * n,int flags)9651 evalpipe(union node *n, int flags)
9652 {
9653 struct job *jp;
9654 struct nodelist *lp;
9655 int pipelen;
9656 int prevfd;
9657 int pip[2];
9658 int status = 0;
9659
9660 TRACE(("evalpipe(0x%lx) called\n", (long)n));
9661 pipelen = 0;
9662 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
9663 pipelen++;
9664 flags |= EV_EXIT;
9665 INT_OFF;
9666 if (n->npipe.pipe_backgnd == 0)
9667 get_tty_state();
9668 jp = makejob(/*n,*/ pipelen);
9669 prevfd = -1;
9670 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
9671 prehash(lp->n);
9672 pip[1] = -1;
9673 if (lp->next) {
9674 if (pipe(pip) < 0) {
9675 close(prevfd);
9676 ash_msg_and_raise_perror("can't create pipe");
9677 }
9678 }
9679 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9680 /* child */
9681 INT_ON;
9682 if (pip[1] >= 0) {
9683 close(pip[0]);
9684 }
9685 if (prevfd > 0) {
9686 dup2(prevfd, 0);
9687 close(prevfd);
9688 }
9689 if (pip[1] > 1) {
9690 dup2(pip[1], 1);
9691 close(pip[1]);
9692 }
9693 evaltreenr(lp->n, flags);
9694 /* never returns */
9695 }
9696 /* parent */
9697 if (prevfd >= 0)
9698 close(prevfd);
9699 prevfd = pip[0];
9700 /* Don't want to trigger debugging */
9701 if (pip[1] != -1)
9702 close(pip[1]);
9703 }
9704 if (n->npipe.pipe_backgnd == 0) {
9705 status = waitforjob(jp);
9706 TRACE(("evalpipe: job done exit status %d\n", status));
9707 }
9708 INT_ON;
9709
9710 return status;
9711 }
9712
9713 /* setinteractive needs this forward reference */
9714 #if EDITING_HAS_get_exe_name
9715 static const char *get_builtin_name(int i) FAST_FUNC;
9716 #endif
9717
9718 /*
9719 * Controls whether the shell is interactive or not.
9720 */
9721 static void
setinteractive(int on)9722 setinteractive(int on)
9723 {
9724 static smallint is_interactive;
9725
9726 if (++on == is_interactive)
9727 return;
9728 is_interactive = on;
9729 setsignal(SIGINT);
9730 setsignal(SIGQUIT);
9731 setsignal(SIGTERM);
9732 if (is_interactive > 1) {
9733 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
9734 /* Looks like they want an interactive shell */
9735 static smallint did_banner;
9736
9737 if (!did_banner) {
9738 /* note: ash and hush share this string */
9739 out1fmt("\n\n%s %s\n"
9740 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9741 "\n",
9742 bb_banner,
9743 "built-in shell (ash)"
9744 );
9745 did_banner = 1;
9746 }
9747 #endif
9748 #if ENABLE_FEATURE_EDITING
9749 if (!line_input_state) {
9750 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
9751 # if EDITING_HAS_get_exe_name
9752 line_input_state->get_exe_name = get_builtin_name;
9753 # endif
9754 }
9755 #endif
9756 }
9757 }
9758
9759 static void
optschanged(void)9760 optschanged(void)
9761 {
9762 #if DEBUG
9763 opentrace();
9764 #endif
9765 setinteractive(iflag);
9766 setjobctl(mflag);
9767 #if ENABLE_FEATURE_EDITING_VI
9768 if (line_input_state) {
9769 if (viflag)
9770 line_input_state->flags |= VI_MODE;
9771 else
9772 line_input_state->flags &= ~VI_MODE;
9773 }
9774 #else
9775 viflag = 0; /* forcibly keep the option off */
9776 #endif
9777 }
9778
9779 struct localvar_list {
9780 struct localvar_list *next;
9781 struct localvar *lv;
9782 };
9783
9784 static struct localvar_list *localvar_stack;
9785
9786 /*
9787 * Called after a function returns.
9788 * Interrupts must be off.
9789 */
9790 static void
poplocalvars(int keep)9791 poplocalvars(int keep)
9792 {
9793 struct localvar_list *ll;
9794 struct localvar *lvp, *next;
9795 struct var *vp;
9796
9797 INT_OFF;
9798 ll = localvar_stack;
9799 localvar_stack = ll->next;
9800
9801 next = ll->lv;
9802 free(ll);
9803
9804 while ((lvp = next) != NULL) {
9805 next = lvp->next;
9806 vp = lvp->vp;
9807 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9808 if (keep) {
9809 int bits = VSTRFIXED;
9810
9811 if (lvp->flags != VUNSET) {
9812 if (vp->var_text == lvp->text)
9813 bits |= VTEXTFIXED;
9814 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9815 free((char*)lvp->text);
9816 }
9817
9818 vp->flags &= ~bits;
9819 vp->flags |= (lvp->flags & bits);
9820
9821 if ((vp->flags &
9822 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9823 unsetvar(vp->var_text);
9824 } else if (vp == NULL) { /* $- saved */
9825 memcpy(optlist, lvp->text, sizeof(optlist));
9826 free((char*)lvp->text);
9827 optschanged();
9828 } else if (lvp->flags == VUNSET) {
9829 vp->flags &= ~(VSTRFIXED|VREADONLY);
9830 unsetvar(vp->var_text);
9831 } else {
9832 if (vp->var_func)
9833 vp->var_func(var_end(lvp->text));
9834 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9835 free((char*)vp->var_text);
9836 vp->flags = lvp->flags;
9837 vp->var_text = lvp->text;
9838 }
9839 free(lvp);
9840 }
9841 INT_ON;
9842 }
9843
9844 /*
9845 * Create a new localvar environment.
9846 */
9847 static struct localvar_list *
pushlocalvars(int push)9848 pushlocalvars(int push)
9849 {
9850 struct localvar_list *ll;
9851 struct localvar_list *top;
9852
9853 top = localvar_stack;
9854 if (!push)
9855 goto out;
9856
9857 INT_OFF;
9858 ll = ckzalloc(sizeof(*ll));
9859 /*ll->lv = NULL; - zalloc did it */
9860 ll->next = top;
9861 localvar_stack = ll;
9862 INT_ON;
9863 out:
9864 return top;
9865 }
9866
9867 static void
unwindlocalvars(struct localvar_list * stop)9868 unwindlocalvars(struct localvar_list *stop)
9869 {
9870 while (localvar_stack != stop)
9871 poplocalvars(0);
9872 }
9873
9874 static int
evalfun(struct funcnode * func,int argc,char ** argv,int flags)9875 evalfun(struct funcnode *func, int argc, char **argv, int flags)
9876 {
9877 volatile struct shparam saveparam;
9878 struct jmploc *volatile savehandler;
9879 struct jmploc jmploc;
9880 int e;
9881 int savelineno;
9882 int savefuncline;
9883 char *savefuncname;
9884 char *savetrap = NULL;
9885
9886 if (!Eflag) {
9887 savetrap = trap[NTRAP_ERR];
9888 trap[NTRAP_ERR] = NULL;
9889 }
9890 savelineno = lineno;
9891 saveparam = shellparam;
9892 savefuncline = funcline;
9893 savefuncname = funcname;
9894 savehandler = exception_handler;
9895 e = setjmp(jmploc.loc);
9896 if (e) {
9897 goto funcdone;
9898 }
9899 INT_OFF;
9900 exception_handler = &jmploc;
9901 shellparam.malloced = 0;
9902 func->count++;
9903 funcname = func->n.ndefun.text;
9904 funcline = func->n.ndefun.linno;
9905 INT_ON;
9906 shellparam.nparam = argc - 1;
9907 shellparam.p = argv + 1;
9908 #if ENABLE_ASH_GETOPTS
9909 shellparam.optind = 1;
9910 shellparam.optoff = -1;
9911 #endif
9912 evaltree(func->n.ndefun.body, flags & EV_TESTED);
9913 funcdone:
9914 INT_OFF;
9915 funcname = savefuncname;
9916 if (savetrap) {
9917 if (!trap[NTRAP_ERR])
9918 trap[NTRAP_ERR] = savetrap;
9919 else
9920 free(savetrap);
9921 }
9922 funcline = savefuncline;
9923 lineno = savelineno;
9924 freefunc(func);
9925 freeparam(&shellparam);
9926 shellparam = saveparam;
9927 exception_handler = savehandler;
9928 INT_ON;
9929 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
9930 return e;
9931 }
9932
9933 /*
9934 * Make a variable a local variable. When a variable is made local, it's
9935 * value and flags are saved in a localvar structure. The saved values
9936 * will be restored when the shell function returns. We handle the name
9937 * "-" as a special case: it makes changes to "set +-options" local
9938 * (options will be restored on return from the function).
9939 */
9940 static void
mklocal(char * name,int flags)9941 mklocal(char *name, int flags)
9942 {
9943 struct localvar *lvp;
9944 struct var **vpp;
9945 struct var *vp;
9946 char *eq = strchr(name, '=');
9947
9948 INT_OFF;
9949 /* Cater for duplicate "local". Examples:
9950 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9951 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9952 */
9953 lvp = localvar_stack->lv;
9954 while (lvp) {
9955 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9956 if (eq)
9957 setvareq(name, 0);
9958 /* else:
9959 * it's a duplicate "local VAR" declaration, do nothing
9960 */
9961 goto ret;
9962 }
9963 lvp = lvp->next;
9964 }
9965
9966 lvp = ckzalloc(sizeof(*lvp));
9967 if (LONE_DASH(name)) {
9968 char *p;
9969 p = ckmalloc(sizeof(optlist));
9970 lvp->text = memcpy(p, optlist, sizeof(optlist));
9971 vp = NULL;
9972 } else {
9973 vpp = hashvar(name);
9974 vp = *findvar(vpp, name);
9975 if (vp == NULL) {
9976 /* variable did not exist yet */
9977 if (eq)
9978 vp = setvareq(name, VSTRFIXED | flags);
9979 else
9980 vp = setvar(name, NULL, VSTRFIXED | flags);
9981 lvp->flags = VUNSET;
9982 } else {
9983 lvp->text = vp->var_text;
9984 lvp->flags = vp->flags;
9985 /* make sure neither "struct var" nor string gets freed
9986 * during (un)setting:
9987 */
9988 vp->flags |= VSTRFIXED|VTEXTFIXED;
9989 if (eq)
9990 setvareq(name, flags);
9991 else
9992 /* "local VAR" unsets VAR: */
9993 setvar0(name, NULL);
9994 }
9995 }
9996 lvp->vp = vp;
9997 lvp->next = localvar_stack->lv;
9998 localvar_stack->lv = lvp;
9999 ret:
10000 INT_ON;
10001 }
10002
10003 /*
10004 * The "local" command.
10005 */
10006 static int FAST_FUNC
localcmd(int argc UNUSED_PARAM,char ** argv)10007 localcmd(int argc UNUSED_PARAM, char **argv)
10008 {
10009 char *name;
10010
10011 if (!localvar_stack)
10012 ash_msg_and_raise_error("not in a function");
10013
10014 argv = argptr;
10015 while ((name = *argv++) != NULL) {
10016 mklocal(name, 0);
10017 }
10018 return 0;
10019 }
10020
10021 static int FAST_FUNC
falsecmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)10022 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10023 {
10024 return 1;
10025 }
10026
10027 static int FAST_FUNC
truecmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)10028 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10029 {
10030 return 0;
10031 }
10032
10033 static int FAST_FUNC
execcmd(int argc UNUSED_PARAM,char ** argv)10034 execcmd(int argc UNUSED_PARAM, char **argv)
10035 {
10036 optionarg = NULL;
10037 while (nextopt("a:") != '\0')
10038 /* nextopt() sets optionarg to "-a ARGV0" */;
10039
10040 argv = argptr;
10041 if (argv[0]) {
10042 char *prog;
10043
10044 iflag = 0; /* exit on error */
10045 mflag = 0;
10046 optschanged();
10047 /* We should set up signals for "exec CMD"
10048 * the same way as for "CMD" without "exec".
10049 * But optschanged->setinteractive->setsignal
10050 * still thought we are a root shell. Therefore, for example,
10051 * SIGQUIT is still set to IGN. Fix it:
10052 */
10053 shlvl++;
10054 setsignal(SIGQUIT);
10055 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
10056 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
10057 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
10058
10059 prog = argv[0];
10060 if (optionarg)
10061 argv[0] = optionarg;
10062 shellexec(prog, argv, pathval(), 0);
10063 /* NOTREACHED */
10064 }
10065 return 0;
10066 }
10067
10068 /*
10069 * The return command.
10070 */
10071 static int FAST_FUNC
returncmd(int argc UNUSED_PARAM,char ** argv)10072 returncmd(int argc UNUSED_PARAM, char **argv)
10073 {
10074 int skip;
10075 int status;
10076
10077 /*
10078 * If called outside a function, do what ksh does;
10079 * skip the rest of the file.
10080 */
10081 if (argv[1]) {
10082 skip = SKIPFUNC;
10083 status = number(argv[1]);
10084 } else {
10085 skip = SKIPFUNCDEF;
10086 status = exitstatus;
10087 }
10088 evalskip = skip;
10089
10090 return status;
10091 }
10092
10093 /* Forward declarations for builtintab[] */
10094 static int breakcmd(int, char **) FAST_FUNC;
10095 static int dotcmd(int, char **) FAST_FUNC;
10096 static int evalcmd(int, char **, int) FAST_FUNC;
10097 static int exitcmd(int, char **) FAST_FUNC;
10098 static int exportcmd(int, char **) FAST_FUNC;
10099 #if ENABLE_ASH_GETOPTS
10100 static int getoptscmd(int, char **) FAST_FUNC;
10101 #endif
10102 #if ENABLE_ASH_HELP
10103 static int helpcmd(int, char **) FAST_FUNC;
10104 #endif
10105 #if MAX_HISTORY
10106 static int historycmd(int, char **) FAST_FUNC;
10107 #endif
10108 #if ENABLE_FEATURE_SH_MATH
10109 static int letcmd(int, char **) FAST_FUNC;
10110 #endif
10111 static int readcmd(int, char **) FAST_FUNC;
10112 static int setcmd(int, char **) FAST_FUNC;
10113 static int shiftcmd(int, char **) FAST_FUNC;
10114 static int timescmd(int, char **) FAST_FUNC;
10115 static int trapcmd(int, char **) FAST_FUNC;
10116 static int umaskcmd(int, char **) FAST_FUNC;
10117 static int unsetcmd(int, char **) FAST_FUNC;
10118 static int ulimitcmd(int, char **) FAST_FUNC;
10119
10120 #define BUILTIN_NOSPEC "0"
10121 #define BUILTIN_SPECIAL "1"
10122 #define BUILTIN_REGULAR "2"
10123 #define BUILTIN_SPEC_REG "3"
10124 #define BUILTIN_ASSIGN "4"
10125 #define BUILTIN_SPEC_ASSG "5"
10126 #define BUILTIN_REG_ASSG "6"
10127 #define BUILTIN_SPEC_REG_ASSG "7"
10128
10129 /* Stubs for calling non-FAST_FUNC's */
10130 #if ENABLE_ASH_ECHO
echocmd(int argc,char ** argv)10131 static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
10132 #endif
10133 #if ENABLE_ASH_PRINTF
printfcmd(int argc,char ** argv)10134 static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
10135 #endif
10136 #if ENABLE_ASH_TEST || BASH_TEST2
testcmd(int argc,char ** argv)10137 static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
10138 #endif
10139
10140 /* Keep these in proper order since it is searched via bsearch() */
10141 static const struct builtincmd builtintab[] = {
10142 { BUILTIN_SPEC_REG "." , dotcmd },
10143 { BUILTIN_SPEC_REG ":" , truecmd },
10144 #if ENABLE_ASH_TEST
10145 { BUILTIN_REGULAR "[" , testcmd },
10146 #endif
10147 #if BASH_TEST2
10148 { BUILTIN_REGULAR "[[" , testcmd },
10149 #endif
10150 #if ENABLE_ASH_ALIAS
10151 { BUILTIN_REG_ASSG "alias" , aliascmd },
10152 #endif
10153 #if JOBS
10154 { BUILTIN_REGULAR "bg" , fg_bgcmd },
10155 #endif
10156 { BUILTIN_SPEC_REG "break" , breakcmd },
10157 { BUILTIN_REGULAR "cd" , cdcmd },
10158 { BUILTIN_NOSPEC "chdir" , cdcmd },
10159 #if ENABLE_ASH_CMDCMD
10160 { BUILTIN_REGULAR "command" , commandcmd },
10161 #endif
10162 { BUILTIN_SPEC_REG "continue", breakcmd },
10163 #if ENABLE_ASH_ECHO
10164 { BUILTIN_REGULAR "echo" , echocmd },
10165 #endif
10166 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
10167 { BUILTIN_SPEC_REG "exec" , execcmd },
10168 { BUILTIN_SPEC_REG "exit" , exitcmd },
10169 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
10170 { BUILTIN_REGULAR "false" , falsecmd },
10171 #if JOBS
10172 { BUILTIN_REGULAR "fg" , fg_bgcmd },
10173 #endif
10174 #if ENABLE_ASH_GETOPTS
10175 { BUILTIN_REGULAR "getopts" , getoptscmd },
10176 #endif
10177 { BUILTIN_REGULAR "hash" , hashcmd },
10178 #if ENABLE_ASH_HELP
10179 { BUILTIN_NOSPEC "help" , helpcmd },
10180 #endif
10181 #if MAX_HISTORY
10182 { BUILTIN_NOSPEC "history" , historycmd },
10183 #endif
10184 #if JOBS
10185 { BUILTIN_REGULAR "jobs" , jobscmd },
10186 { BUILTIN_REGULAR "kill" , killcmd },
10187 #endif
10188 #if ENABLE_FEATURE_SH_MATH
10189 { BUILTIN_NOSPEC "let" , letcmd },
10190 #endif
10191 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
10192 #if ENABLE_ASH_PRINTF
10193 { BUILTIN_REGULAR "printf" , printfcmd },
10194 #endif
10195 { BUILTIN_REGULAR "pwd" , pwdcmd },
10196 { BUILTIN_REGULAR "read" , readcmd },
10197 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
10198 { BUILTIN_SPEC_REG "return" , returncmd },
10199 { BUILTIN_SPEC_REG "set" , setcmd },
10200 { BUILTIN_SPEC_REG "shift" , shiftcmd },
10201 #if BASH_SOURCE
10202 { BUILTIN_SPEC_REG "source" , dotcmd },
10203 #endif
10204 #if ENABLE_ASH_TEST
10205 { BUILTIN_REGULAR "test" , testcmd },
10206 #endif
10207 { BUILTIN_SPEC_REG "times" , timescmd },
10208 { BUILTIN_SPEC_REG "trap" , trapcmd },
10209 { BUILTIN_REGULAR "true" , truecmd },
10210 { BUILTIN_REGULAR "type" , typecmd },
10211 { BUILTIN_REGULAR "ulimit" , ulimitcmd },
10212 { BUILTIN_REGULAR "umask" , umaskcmd },
10213 #if ENABLE_ASH_ALIAS
10214 { BUILTIN_REGULAR "unalias" , unaliascmd },
10215 #endif
10216 { BUILTIN_SPEC_REG "unset" , unsetcmd },
10217 { BUILTIN_REGULAR "wait" , waitcmd },
10218 };
10219
10220 /* Should match the above table! */
10221 #define COMMANDCMD (builtintab + \
10222 /* . : */ 2 + \
10223 /* [ */ 1 * ENABLE_ASH_TEST + \
10224 /* [[ */ 1 * BASH_TEST2 + \
10225 /* alias */ 1 * ENABLE_ASH_ALIAS + \
10226 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
10227 /* break cd cddir */ 3)
10228 #define EVALCMD (COMMANDCMD + \
10229 /* command */ 1 * ENABLE_ASH_CMDCMD + \
10230 /* continue */ 1 + \
10231 /* echo */ 1 * ENABLE_ASH_ECHO + \
10232 0)
10233 #define EXECCMD (EVALCMD + \
10234 /* eval */ 1)
10235
10236 /*
10237 * Search the table of builtin commands.
10238 */
10239 static int
pstrcmp1(const void * a,const void * b)10240 pstrcmp1(const void *a, const void *b)
10241 {
10242 return strcmp((char*)a, *(char**)b + 1);
10243 }
10244 static struct builtincmd *
find_builtin(const char * name)10245 find_builtin(const char *name)
10246 {
10247 struct builtincmd *bp;
10248
10249 bp = bsearch(
10250 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
10251 pstrcmp1
10252 );
10253 return bp;
10254 }
10255
10256 #if EDITING_HAS_get_exe_name
10257 static const char * FAST_FUNC
get_builtin_name(int i)10258 get_builtin_name(int i)
10259 {
10260 return /*i >= 0 &&*/ i < ARRAY_SIZE(builtintab) ? builtintab[i].name + 1 : NULL;
10261 }
10262 #endif
10263
10264 /*
10265 * Execute a simple command.
10266 */
10267 static void unwindfiles(struct parsefile *stop);
10268 static int
isassignment(const char * p)10269 isassignment(const char *p)
10270 {
10271 const char *q = endofname(p);
10272 if (p == q)
10273 return 0;
10274 return *q == '=';
10275 }
10276 static int FAST_FUNC
bltincmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)10277 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10278 {
10279 /* Preserve exitstatus of a previous possible redirection
10280 * as POSIX mandates */
10281 return back_exitstatus;
10282 }
10283 static int
evalcommand(union node * cmd,int flags)10284 evalcommand(union node *cmd, int flags)
10285 {
10286 static const struct builtincmd null_bltin = {
10287 BUILTIN_REGULAR "", bltincmd
10288 };
10289 struct localvar_list *localvar_stop;
10290 struct parsefile *file_stop;
10291 struct redirtab *redir_stop;
10292 union node *argp;
10293 struct arglist arglist;
10294 struct arglist varlist;
10295 char **argv;
10296 int argc;
10297 struct strlist *osp;
10298 const struct strlist *sp;
10299 struct cmdentry cmdentry;
10300 struct job *jp;
10301 char *lastarg;
10302 const char *path;
10303 int spclbltin;
10304 int cmd_flag;
10305 int status;
10306 char **nargv;
10307 smallint cmd_is_exec;
10308 int vflags;
10309 int vlocal;
10310
10311 errlinno = lineno = cmd->ncmd.linno;
10312
10313 /* First expand the arguments. */
10314 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
10315 #if BASH_PROCESS_SUBST
10316 redir_stop = redirlist;
10317 #endif
10318 file_stop = g_parsefile;
10319 back_exitstatus = 0;
10320
10321 cmdentry.cmdtype = CMDBUILTIN;
10322 cmdentry.u.cmd = &null_bltin;
10323 varlist.lastp = &varlist.list;
10324 *varlist.lastp = NULL;
10325 arglist.lastp = &arglist.list;
10326 *arglist.lastp = NULL;
10327
10328 cmd_flag = 0;
10329 cmd_is_exec = 0;
10330 spclbltin = -1;
10331 vflags = 0;
10332 vlocal = 0;
10333 path = NULL;
10334
10335 argc = 0;
10336 argp = cmd->ncmd.args;
10337 osp = fill_arglist(&arglist, &argp);
10338 if (osp) {
10339 int pseudovarflag = 0;
10340
10341 for (;;) {
10342 find_command(arglist.list->text, &cmdentry,
10343 cmd_flag | DO_REGBLTIN, pathval());
10344
10345 vlocal++;
10346
10347 /* implement bltin and command here */
10348 if (cmdentry.cmdtype != CMDBUILTIN)
10349 break;
10350
10351 pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
10352 if (spclbltin < 0) {
10353 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10354 vlocal = !spclbltin;
10355 }
10356 cmd_is_exec = cmdentry.u.cmd == EXECCMD;
10357 #if ENABLE_ASH_CMDCMD
10358 if (cmdentry.u.cmd != COMMANDCMD)
10359 break;
10360
10361 cmd_flag = parse_command_args(&arglist, &argp, &path);
10362 if (!cmd_flag)
10363 #endif
10364 break;
10365 }
10366
10367 for (; argp; argp = argp->narg.next)
10368 expandarg(argp, &arglist,
10369 pseudovarflag &&
10370 isassignment(argp->narg.text) ?
10371 EXP_VARTILDE : EXP_FULL | EXP_TILDE);
10372
10373 for (sp = arglist.list; sp; sp = sp->next)
10374 argc++;
10375
10376 if (cmd_is_exec && argc > 1)
10377 vflags = VEXPORT;
10378 }
10379
10380 localvar_stop = pushlocalvars(vlocal);
10381
10382 /* Reserve one extra spot at the front for shellexec. */
10383 nargv = stalloc(sizeof(char *) * (argc + 2));
10384 argv = ++nargv;
10385 for (sp = arglist.list; sp; sp = sp->next) {
10386 TRACE(("evalcommand arg: %s\n", sp->text));
10387 *nargv++ = sp->text;
10388 }
10389 *nargv = NULL;
10390
10391 lastarg = NULL;
10392 if (iflag && funcline == 0 && argc > 0)
10393 lastarg = nargv[-1];
10394
10395 expredir(cmd->ncmd.redirect);
10396 #if !BASH_PROCESS_SUBST
10397 redir_stop = pushredir(cmd->ncmd.redirect);
10398 #else
10399 pushredir(cmd->ncmd.redirect);
10400 #endif
10401 preverrout_fd = 2;
10402 if (BASH_XTRACEFD && xflag) {
10403 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10404 * we do not emulate this. We only use its value.
10405 */
10406 const char *xtracefd = lookupvar("BASH_XTRACEFD");
10407 if (xtracefd && is_number(xtracefd))
10408 preverrout_fd = atoi(xtracefd);
10409
10410 }
10411 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
10412
10413 if (status) {
10414 bail:
10415 exitstatus = status;
10416
10417 /* We have a redirection error. */
10418 if (spclbltin > 0)
10419 raise_exception(EXERROR);
10420
10421 goto out;
10422 }
10423
10424 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10425 struct strlist **spp;
10426
10427 spp = varlist.lastp;
10428 expandarg(argp, &varlist, EXP_VARTILDE);
10429
10430 if (vlocal)
10431 mklocal((*spp)->text, VEXPORT);
10432 else
10433 setvareq((*spp)->text, vflags);
10434 }
10435
10436 /* Print the command if xflag is set. */
10437 if (xflag && !inps4) {
10438 const char *pfx = "";
10439
10440 inps4 = 1;
10441 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
10442 inps4 = 0;
10443
10444 sp = varlist.list;
10445 while (sp) {
10446 char *varval = sp->text;
10447 char *eq = strchrnul(varval, '=');
10448 if (*eq)
10449 eq++;
10450 fdprintf(preverrout_fd, "%s%.*s%s",
10451 pfx,
10452 (int)(eq - varval), varval,
10453 maybe_single_quote(eq)
10454 );
10455 sp = sp->next;
10456 pfx = " ";
10457 }
10458
10459 sp = arglist.list;
10460 while (sp) {
10461 fdprintf(preverrout_fd, "%s%s",
10462 pfx,
10463 /* always quote if matches reserved word: */
10464 findkwd(sp->text)
10465 ? single_quote(sp->text)
10466 : maybe_single_quote(sp->text)
10467 );
10468 sp = sp->next;
10469 pfx = " ";
10470 }
10471 safe_write(preverrout_fd, "\n", 1);
10472 }
10473
10474 /* Now locate the command. */
10475 if (cmdentry.cmdtype != CMDBUILTIN
10476 || !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
10477 ) {
10478 path = path ? path : pathval();
10479 find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path);
10480 }
10481
10482 jp = NULL;
10483
10484 /* Execute the command. */
10485 switch (cmdentry.cmdtype) {
10486 case CMDUNKNOWN:
10487 status = 127;
10488 flush_stdout_stderr();
10489 goto bail;
10490
10491 default: {
10492
10493 #if ENABLE_FEATURE_SH_STANDALONE \
10494 && ENABLE_FEATURE_SH_NOFORK \
10495 && NUM_APPLETS > 1
10496 /* (1) BUG: if variables are set, we need to fork, or save/restore them
10497 * around run_nofork_applet() call.
10498 * (2) Should this check also be done in forkshell()?
10499 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10500 */
10501 /* find_command() encodes applet_no as (-2 - applet_no) */
10502 int applet_no = (- cmdentry.u.index - 2);
10503 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
10504 char **sv_environ;
10505
10506 INT_OFF;
10507 sv_environ = environ;
10508 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
10509 /*
10510 * Run <applet>_main().
10511 * Signals (^C) can't interrupt here.
10512 * Otherwise we can mangle stdio or malloc internal state.
10513 * This makes applets which can run for a long time
10514 * and/or wait for user input ineligible for NOFORK:
10515 * for example, "yes" or "rm" (rm -i waits for input).
10516 */
10517 exitstatus = run_nofork_applet(applet_no, argv);
10518 environ = sv_environ;
10519 /*
10520 * Try enabling NOFORK for "yes" applet.
10521 * ^C _will_ stop it (write returns EINTR),
10522 * but this causes stdout FILE to be stuck
10523 * and needing clearerr(). What if other applets
10524 * also can get EINTRs? Do we need to switch
10525 * our signals to SA_RESTART?
10526 */
10527 /*clearerr(stdout);*/
10528 INT_ON;
10529 break;
10530 }
10531 #endif
10532 /* Can we avoid forking? For example, very last command
10533 * in a script or a subshell does not need forking,
10534 * we can just exec it.
10535 */
10536 if (!(flags & EV_EXIT) || may_have_traps) {
10537 /* No, forking off a child is necessary */
10538 INT_OFF;
10539 get_tty_state();
10540 jp = makejob(/*cmd,*/ 1);
10541 if (forkshell(jp, cmd, FORK_FG) != 0) {
10542 /* parent */
10543 break;
10544 }
10545 /* child */
10546 FORCE_INT_ON;
10547 /* fall through to exec'ing external program */
10548 }
10549 shellexec(argv[0], argv, path, cmdentry.u.index);
10550 /* NOTREACHED */
10551 } /* default */
10552 case CMDBUILTIN:
10553 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
10554 && !(exception_type == EXERROR && spclbltin <= 0)
10555 ) {
10556 raise:
10557 longjmp(exception_handler->loc, 1);
10558 }
10559 break;
10560
10561 case CMDFUNCTION:
10562 if (evalfun(cmdentry.u.func, argc, argv, flags))
10563 goto raise;
10564 break;
10565 } /* switch */
10566
10567 status = waitforjob(jp);
10568 if (jp)
10569 TRACE(("forked child exited with %d\n", status));
10570 FORCE_INT_ON;
10571
10572 out:
10573 if (cmd->ncmd.redirect)
10574 popredir(/*drop:*/ cmd_is_exec);
10575 unwindredir(redir_stop);
10576 unwindfiles(file_stop);
10577 unwindlocalvars(localvar_stop);
10578 if (lastarg) {
10579 /* dsl: I think this is intended to be used to support
10580 * '_' in 'vi' command mode during line editing...
10581 * However I implemented that within libedit itself.
10582 */
10583 setvar0("_", lastarg);
10584 }
10585
10586 return status;
10587 }
10588
10589 static int
evalbltin(const struct builtincmd * cmd,int argc,char ** argv,int flags)10590 evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
10591 {
10592 char *volatile savecmdname;
10593 struct jmploc *volatile savehandler;
10594 struct jmploc jmploc;
10595 int status;
10596 int i;
10597
10598 savecmdname = commandname;
10599 savehandler = exception_handler;
10600 i = setjmp(jmploc.loc);
10601 if (i)
10602 goto cmddone;
10603 exception_handler = &jmploc;
10604 commandname = argv[0];
10605 argptr = argv + 1;
10606 optptr = NULL; /* initialize nextopt */
10607 if (cmd == EVALCMD)
10608 status = evalcmd(argc, argv, flags);
10609 else
10610 status = (*cmd->builtin)(argc, argv);
10611 flush_stdout_stderr();
10612 status |= ferror(stdout);
10613 exitstatus = status;
10614 cmddone:
10615 clearerr(stdout);
10616 commandname = savecmdname;
10617 exception_handler = savehandler;
10618
10619 return i;
10620 }
10621
10622 static int
goodname(const char * p)10623 goodname(const char *p)
10624 {
10625 return endofname(p)[0] == '\0';
10626 }
10627
10628
10629 /*
10630 * Search for a command. This is called before we fork so that the
10631 * location of the command will be available in the parent as well as
10632 * the child. The check for "goodname" is an overly conservative
10633 * check that the name will not be subject to expansion.
10634 */
10635 static void
prehash(union node * n)10636 prehash(union node *n)
10637 {
10638 struct cmdentry entry;
10639
10640 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10641 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
10642 }
10643
10644
10645 /* ============ Builtin commands
10646 *
10647 * Builtin commands whose functions are closely tied to evaluation
10648 * are implemented here.
10649 */
10650
10651 /*
10652 * Handle break and continue commands. Break, continue, and return are
10653 * all handled by setting the evalskip flag. The evaluation routines
10654 * above all check this flag, and if it is set they start skipping
10655 * commands rather than executing them. The variable skipcount is
10656 * the number of loops to break/continue, or the number of function
10657 * levels to return. (The latter is always 1.) It should probably
10658 * be an error to break out of more loops than exist, but it isn't
10659 * in the standard shell so we don't make it one here.
10660 */
10661 static int FAST_FUNC
breakcmd(int argc UNUSED_PARAM,char ** argv)10662 breakcmd(int argc UNUSED_PARAM, char **argv)
10663 {
10664 int n = argv[1] ? number(argv[1]) : 1;
10665
10666 if (n <= 0)
10667 ash_msg_and_raise_error(msg_illnum, argv[1]);
10668 if (n > loopnest)
10669 n = loopnest;
10670 if (n > 0) {
10671 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
10672 skipcount = n;
10673 }
10674 return 0;
10675 }
10676
10677
10678 /*
10679 * This implements the input routines used by the parser.
10680 */
10681
10682 enum {
10683 INPUT_PUSH_FILE = 1,
10684 INPUT_NOFILE_OK = 2,
10685 };
10686
10687 static smallint checkkwd;
10688 /* values of checkkwd variable */
10689 #define CHKALIAS 0x1
10690 #define CHKKWD 0x2
10691 #define CHKNL 0x4
10692 #define CHKEOFMARK 0x8
10693
10694 /*
10695 * Push a string back onto the input at this current parsefile level.
10696 * We handle aliases this way.
10697 */
10698 #if !ENABLE_ASH_ALIAS
10699 #define pushstring(s, ap) pushstring(s)
10700 #endif
10701 static void
pushstring(char * s,struct alias * ap)10702 pushstring(char *s, struct alias *ap)
10703 {
10704 struct strpush *sp;
10705 int len;
10706
10707 len = strlen(s);
10708 INT_OFF;
10709 if (g_parsefile->strpush || g_parsefile->spfree) {
10710 sp = ckzalloc(sizeof(*sp));
10711 sp->prev = g_parsefile->strpush;
10712 } else {
10713 sp = &(g_parsefile->basestrpush);
10714 }
10715 g_parsefile->strpush = sp;
10716 sp->prev_string = g_parsefile->next_to_pgetc;
10717 sp->prev_left_in_line = g_parsefile->left_in_line;
10718 sp->unget = g_parsefile->unget;
10719 sp->spfree = g_parsefile->spfree;
10720 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
10721 #if ENABLE_ASH_ALIAS
10722 sp->ap = ap;
10723 if (ap) {
10724 ap->flag |= ALIASINUSE;
10725 sp->string = s;
10726 }
10727 #endif
10728 g_parsefile->next_to_pgetc = s;
10729 g_parsefile->left_in_line = len;
10730 g_parsefile->unget = 0;
10731 g_parsefile->spfree = NULL;
10732 INT_ON;
10733 }
10734
popstring(void)10735 static void popstring(void)
10736 {
10737 struct strpush *sp = g_parsefile->strpush;
10738
10739 INT_OFF;
10740 #if ENABLE_ASH_ALIAS
10741 if (sp->ap) {
10742 if (g_parsefile->next_to_pgetc[-1] == ' '
10743 || g_parsefile->next_to_pgetc[-1] == '\t'
10744 ) {
10745 checkkwd |= CHKALIAS;
10746 }
10747 if (sp->string != sp->ap->val) {
10748 free(sp->string);
10749 }
10750 }
10751 #endif
10752 g_parsefile->next_to_pgetc = sp->prev_string;
10753 g_parsefile->left_in_line = sp->prev_left_in_line;
10754 g_parsefile->unget = sp->unget;
10755 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
10756 g_parsefile->strpush = sp->prev;
10757 g_parsefile->spfree = sp;
10758 INT_ON;
10759 }
10760
10761 static int
preadfd(void)10762 preadfd(void)
10763 {
10764 int nr;
10765 char *buf = g_parsefile->buf;
10766
10767 g_parsefile->next_to_pgetc = buf;
10768 #if ENABLE_FEATURE_EDITING
10769 /* retry: */
10770 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10771 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10772 else {
10773 # if ENABLE_ASH_IDLE_TIMEOUT
10774 int timeout = -1;
10775 const char *tmout_var = lookupvar("TMOUT");
10776 if (tmout_var) {
10777 timeout = atoi(tmout_var) * 1000;
10778 if (timeout <= 0)
10779 timeout = -1;
10780 }
10781 line_input_state->timeout = timeout;
10782 # endif
10783 # if ENABLE_FEATURE_TAB_COMPLETION
10784 line_input_state->path_lookup = pathval();
10785 # endif
10786 reinit_unicode_for_ash();
10787 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
10788 if (nr == 0) {
10789 /* ^C pressed, "convert" to SIGINT */
10790 write(STDOUT_FILENO, "^C", 2);
10791 raise(SIGINT);
10792 if (trap[SIGINT]) {
10793 buf[0] = '\n';
10794 buf[1] = '\0';
10795 return 1;
10796 }
10797 exitstatus = 128 + SIGINT;
10798 return -1;
10799 }
10800 if (nr < 0) {
10801 if (errno == 0) {
10802 /* Ctrl+D pressed */
10803 nr = 0;
10804 }
10805 # if ENABLE_ASH_IDLE_TIMEOUT
10806 else if (errno == EAGAIN && timeout > 0) {
10807 puts("\007timed out waiting for input: auto-logout");
10808 exitshell();
10809 }
10810 # endif
10811 }
10812 }
10813 #else
10814 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10815 #endif
10816
10817 #if 0 /* disabled: nonblock_immune_read() handles this problem */
10818 if (nr < 0) {
10819 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10820 int flags = fcntl(0, F_GETFL);
10821 if (flags >= 0 && (flags & O_NONBLOCK)) {
10822 flags &= ~O_NONBLOCK;
10823 if (fcntl(0, F_SETFL, flags) >= 0) {
10824 out2str("sh: turning off NDELAY mode\n");
10825 goto retry;
10826 }
10827 }
10828 }
10829 }
10830 #endif
10831 return nr;
10832 }
10833
10834 /*
10835 * Refill the input buffer and return the next input character:
10836 *
10837 * 1) If a string was pushed back on the input, pop it;
10838 * 2) If we are reading from a string we can't refill the buffer, return EOF.
10839 * 3) If there is more stuff in this buffer, use it else call read to fill it.
10840 * 4) Process input up to the next newline, deleting nul characters.
10841 */
10842 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10843 #define pgetc_debug(...) ((void)0)
10844 static int __pgetc(void);
10845 static int
preadbuffer(void)10846 preadbuffer(void)
10847 {
10848 char *q;
10849 int more;
10850
10851 if (unlikely(g_parsefile->strpush)) {
10852 popstring();
10853 return __pgetc();
10854 }
10855
10856 if (g_parsefile->buf == NULL) {
10857 pgetc_debug("preadbuffer PEOF1");
10858 return PEOF;
10859 }
10860
10861 more = g_parsefile->left_in_buffer;
10862 if (more <= 0) {
10863 flush_stdout_stderr();
10864 again:
10865 more = preadfd();
10866 if (more <= 0) {
10867 g_parsefile->left_in_buffer = g_parsefile->left_in_line = 0;
10868 pgetc_debug("preadbuffer PEOF2");
10869 return PEOF;
10870 }
10871 }
10872
10873 /* Find out where's the end of line.
10874 * Set g_parsefile->left_in_line
10875 * and g_parsefile->left_in_buffer acordingly.
10876 * NUL chars are deleted.
10877 */
10878 q = g_parsefile->next_to_pgetc;
10879 for (;;) {
10880 char c;
10881
10882 more--;
10883
10884 c = *q;
10885 if (c == '\0') {
10886 memmove(q, q + 1, more);
10887 } else {
10888 q++;
10889 if (c == '\n') {
10890 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10891 break;
10892 }
10893 }
10894
10895 if (more <= 0) {
10896 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10897 if (g_parsefile->left_in_line < 0)
10898 goto again;
10899 break;
10900 }
10901 }
10902 g_parsefile->left_in_buffer = more;
10903
10904 if (vflag) {
10905 char save = *q;
10906 *q = '\0';
10907 out2str(g_parsefile->next_to_pgetc);
10908 *q = save;
10909 }
10910
10911 pgetc_debug("preadbuffer at %d:%p'%s'",
10912 g_parsefile->left_in_line,
10913 g_parsefile->next_to_pgetc,
10914 g_parsefile->next_to_pgetc);
10915 return (unsigned char)*g_parsefile->next_to_pgetc++;
10916 }
10917
10918 static void
nlprompt(void)10919 nlprompt(void)
10920 {
10921 if (trap_depth == 0)
10922 g_parsefile->linno++;
10923 setprompt_if(doprompt, 2);
10924 }
10925 static void
nlnoprompt(void)10926 nlnoprompt(void)
10927 {
10928 if (trap_depth == 0)
10929 g_parsefile->linno++;
10930 needprompt = doprompt;
10931 }
10932
freestrings(struct strpush * sp)10933 static void freestrings(struct strpush *sp)
10934 {
10935 INT_OFF;
10936 do {
10937 struct strpush *psp;
10938 #if ENABLE_ASH_ALIAS
10939 if (sp->ap) {
10940 sp->ap->flag &= ~ALIASINUSE;
10941 if (sp->ap->flag & ALIASDEAD) {
10942 unalias(sp->ap->name);
10943 }
10944 }
10945 #endif
10946 psp = sp;
10947 sp = sp->spfree;
10948
10949 if (psp != &(g_parsefile->basestrpush))
10950 free(psp);
10951 } while (sp);
10952
10953 g_parsefile->spfree = NULL;
10954 INT_ON;
10955 }
10956
__pgetc(void)10957 static int __pgetc(void)
10958 {
10959 int c;
10960
10961 pgetc_debug("pgetc at %d:%p'%s'",
10962 g_parsefile->left_in_line,
10963 g_parsefile->next_to_pgetc,
10964 g_parsefile->next_to_pgetc);
10965 if (g_parsefile->unget)
10966 return g_parsefile->lastc[--g_parsefile->unget];
10967
10968 if (--g_parsefile->left_in_line >= 0)
10969 c = (unsigned char)*g_parsefile->next_to_pgetc++;
10970 else
10971 c = preadbuffer();
10972
10973 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10974 g_parsefile->lastc[0] = c;
10975
10976 return c;
10977 }
10978
10979 /*
10980 * Read a character from the script, returning PEOF on end of file.
10981 * Nul characters in the input are silently discarded.
10982 */
pgetc(void)10983 static int pgetc(void)
10984 {
10985 struct strpush *sp = g_parsefile->spfree;
10986
10987 if (unlikely(sp))
10988 freestrings(sp);
10989
10990 return __pgetc();
10991 }
10992
10993 /*
10994 * Undo a call to pgetc. Only two characters may be pushed back.
10995 * PEOF may be pushed back.
10996 */
10997 static void
pungetc(void)10998 pungetc(void)
10999 {
11000 g_parsefile->unget++;
11001 }
11002
11003 /* This one eats backslash+newline */
11004 static int
pgetc_eatbnl(void)11005 pgetc_eatbnl(void)
11006 {
11007 int c;
11008
11009 while ((c = pgetc()) == '\\') {
11010 if (pgetc() != '\n') {
11011 pungetc();
11012 break;
11013 }
11014
11015 nlprompt();
11016 }
11017
11018 return c;
11019 }
11020
11021 struct synstack {
11022 smalluint syntax;
11023 uint8_t innerdq :1;
11024 uint8_t varpushed :1;
11025 uint8_t dblquote :1;
11026 int varnest; /* levels of variables expansion */
11027 int dqvarnest; /* levels of variables expansion within double quotes */
11028 int parenlevel; /* levels of parens in arithmetic */
11029 struct synstack *prev;
11030 struct synstack *next;
11031 };
11032
11033 static int
pgetc_top(struct synstack * stack)11034 pgetc_top(struct synstack *stack)
11035 {
11036 return stack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl();
11037 }
11038
11039 static void
synstack_push(struct synstack ** stack,struct synstack * next,int syntax)11040 synstack_push(struct synstack **stack, struct synstack *next, int syntax)
11041 {
11042 memset(next, 0, sizeof(*next));
11043 next->syntax = syntax;
11044 next->next = *stack;
11045 (*stack)->prev = next;
11046 *stack = next;
11047 }
11048
11049 static ALWAYS_INLINE void
synstack_pop(struct synstack ** stack)11050 synstack_pop(struct synstack **stack)
11051 {
11052 *stack = (*stack)->next;
11053 }
11054
11055 /*
11056 * To handle the "." command, a stack of input files is used. Pushfile
11057 * adds a new entry to the stack and popfile restores the previous level.
11058 */
11059 static void
pushfile(void)11060 pushfile(void)
11061 {
11062 struct parsefile *pf;
11063
11064 pf = ckzalloc(sizeof(*pf));
11065 pf->prev = g_parsefile;
11066 pf->pf_fd = -1;
11067 /*pf->strpush = NULL; - ckzalloc did it */
11068 /*pf->spfree = NULL;*/
11069 /*pf->basestrpush.prev = NULL;*/
11070 /*pf->unget = 0;*/
11071 g_parsefile = pf;
11072 }
11073
11074 static void
popfile(void)11075 popfile(void)
11076 {
11077 struct parsefile *pf = g_parsefile;
11078
11079 if (pf == &basepf)
11080 return;
11081
11082 INT_OFF;
11083 if (pf->pf_fd >= 0)
11084 close(pf->pf_fd);
11085 free(pf->buf);
11086 if (g_parsefile->spfree)
11087 freestrings(g_parsefile->spfree);
11088 while (pf->strpush) {
11089 popstring();
11090 freestrings(g_parsefile->spfree);
11091 }
11092 g_parsefile = pf->prev;
11093 free(pf);
11094 INT_ON;
11095 }
11096
11097 static void
unwindfiles(struct parsefile * stop)11098 unwindfiles(struct parsefile *stop)
11099 {
11100 while (g_parsefile != stop)
11101 popfile();
11102 }
11103
11104 /*
11105 * Return to top level.
11106 */
11107 static void
popallfiles(void)11108 popallfiles(void)
11109 {
11110 unwindfiles(&basepf);
11111 }
11112
11113 /*
11114 * Close the file(s) that the shell is reading commands from. Called
11115 * after a fork is done.
11116 */
11117 static void
closescript(void)11118 closescript(void)
11119 {
11120 popallfiles();
11121 if (g_parsefile->pf_fd > 0) {
11122 close(g_parsefile->pf_fd);
11123 g_parsefile->pf_fd = 0;
11124 }
11125 }
11126
11127 /*
11128 * Like setinputfile, but takes an open file descriptor. Call this with
11129 * interrupts off.
11130 */
11131 static void
setinputfd(int fd,int push)11132 setinputfd(int fd, int push)
11133 {
11134 if (push) {
11135 pushfile();
11136 g_parsefile->buf = NULL;
11137 }
11138 g_parsefile->pf_fd = fd;
11139 if (g_parsefile->buf == NULL)
11140 g_parsefile->buf = ckmalloc(IBUFSIZ);
11141 g_parsefile->left_in_buffer = 0;
11142 g_parsefile->left_in_line = 0;
11143 g_parsefile->linno = 1;
11144 }
11145
11146 /*
11147 * Set the input to take input from a file. If push is set, push the
11148 * old input onto the stack first.
11149 */
11150 static int
setinputfile(const char * fname,int flags)11151 setinputfile(const char *fname, int flags)
11152 {
11153 int fd;
11154
11155 INT_OFF;
11156 fd = open(fname, O_RDONLY | O_CLOEXEC);
11157 if (fd < 0) {
11158 if (flags & INPUT_NOFILE_OK)
11159 goto out;
11160 exitstatus = 127;
11161 ash_msg_and_raise_perror("can't open '%s'", fname);
11162 }
11163 if (fd < 10)
11164 fd = savefd(fd);
11165 else if (O_CLOEXEC == 0) /* old libc */
11166 close_on_exec_on(fd);
11167
11168 setinputfd(fd, flags & INPUT_PUSH_FILE);
11169 out:
11170 INT_ON;
11171 return fd;
11172 }
11173
11174 /*
11175 * Like setinputfile, but takes input from a string.
11176 */
11177 static void
setinputstring(char * string)11178 setinputstring(char *string)
11179 {
11180 INT_OFF;
11181 pushfile();
11182 g_parsefile->next_to_pgetc = string;
11183 g_parsefile->left_in_line = strlen(string);
11184 g_parsefile->buf = NULL;
11185 g_parsefile->linno = lineno;
11186 INT_ON;
11187 }
11188
11189
11190 /*
11191 * Routines to check for mail.
11192 */
11193
11194 #if ENABLE_ASH_MAIL
11195
11196 /* Hash of mtimes of mailboxes */
11197 static unsigned mailtime_hash;
11198 /* Set if MAIL or MAILPATH is changed. */
11199 static smallint mail_var_path_changed;
11200
11201 /*
11202 * Print appropriate message(s) if mail has arrived.
11203 * If mail_var_path_changed is set,
11204 * then the value of MAIL has mail_var_path_changed,
11205 * so we just update the values.
11206 */
11207 static void
chkmail(void)11208 chkmail(void)
11209 {
11210 const char *mpath;
11211 char *p;
11212 char *q;
11213 unsigned new_hash;
11214 struct stackmark smark;
11215 struct stat statb;
11216
11217 setstackmark(&smark);
11218 mpath = mpathset() ? mpathval() : mailval();
11219 new_hash = 0;
11220 for (;;) {
11221 int len;
11222
11223 len = padvance_magic(&mpath, nullstr, 2);
11224 if (!len)
11225 break;
11226 p = stackblock();
11227 break;
11228 if (*p == '\0')
11229 continue;
11230 for (q = p; *q; q++)
11231 continue;
11232 #if DEBUG
11233 if (q[-1] != '/')
11234 abort();
11235 #endif
11236 q[-1] = '\0'; /* delete trailing '/' */
11237 if (stat(p, &statb) < 0) {
11238 continue;
11239 }
11240 /* Very simplistic "hash": just a sum of all mtimes */
11241 new_hash += (unsigned)statb.st_mtime;
11242 }
11243 if (!mail_var_path_changed && mailtime_hash != new_hash) {
11244 if (mailtime_hash != 0)
11245 out2str("you have mail\n");
11246 mailtime_hash = new_hash;
11247 }
11248 mail_var_path_changed = 0;
11249 popstackmark(&smark);
11250 }
11251
11252 static void FAST_FUNC
changemail(const char * val UNUSED_PARAM)11253 changemail(const char *val UNUSED_PARAM)
11254 {
11255 mail_var_path_changed = 1;
11256 }
11257
11258 #endif /* ASH_MAIL */
11259
11260
11261 /* ============ ??? */
11262
11263 /*
11264 * Set the shell parameters.
11265 */
11266 static void
setparam(char ** argv)11267 setparam(char **argv)
11268 {
11269 char **newparam;
11270 char **ap;
11271 int nparam;
11272
11273 for (nparam = 0; argv[nparam]; nparam++)
11274 continue;
11275 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
11276 while (*argv) {
11277 *ap++ = ckstrdup(*argv++);
11278 }
11279 *ap = NULL;
11280 freeparam(&shellparam);
11281 shellparam.malloced = 1;
11282 shellparam.nparam = nparam;
11283 shellparam.p = newparam;
11284 #if ENABLE_ASH_GETOPTS
11285 shellparam.optind = 1;
11286 shellparam.optoff = -1;
11287 #endif
11288 }
11289
11290 /*
11291 * Process shell options. The global variable argptr contains a pointer
11292 * to the argument list; we advance it past the options.
11293 *
11294 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
11295 * For a non-interactive shell, an error condition encountered
11296 * by a special built-in ... shall cause the shell to write a diagnostic message
11297 * to standard error and exit as shown in the following table:
11298 * Error Special Built-In
11299 * ...
11300 * Utility syntax error (option or operand error) Shall exit
11301 * ...
11302 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
11303 * we see that bash does not do that (set "finishes" with error code 1 instead,
11304 * and shell continues), and people rely on this behavior!
11305 * Testcase:
11306 * set -o barfoo 2>/dev/null
11307 * echo $?
11308 *
11309 * Oh well. Let's mimic that.
11310 */
11311 static int
plus_minus_o(char * name,int val)11312 plus_minus_o(char *name, int val)
11313 {
11314 int i;
11315
11316 if (name) {
11317 for (i = 0; i < NOPTS; i++) {
11318 if (strcmp(name, optnames(i)) == 0) {
11319 optlist[i] = val;
11320 return 0;
11321 }
11322 }
11323 ash_msg("illegal option %co %s", val ? '-' : '+', name);
11324 return 1;
11325 }
11326 for (i = 0; i < NOPTS; i++) {
11327 if (optnames(i)[0] == '\0')
11328 continue;
11329 if (val) {
11330 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11331 } else {
11332 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11333 }
11334 }
11335 return 0;
11336 }
11337 static void
setoption(int flag,int val)11338 setoption(int flag, int val)
11339 {
11340 int i;
11341
11342 for (i = 0; i < NOPTS; i++) {
11343 if (optletters(i) == flag && optnames(i)[0] != '\0') {
11344 optlist[i] = val;
11345 return;
11346 }
11347 }
11348 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
11349 /* NOTREACHED */
11350 }
11351 /* If login_sh is not NULL, we are called to parse command line opts,
11352 * not "set -opts"
11353 */
11354 static int
options(int * login_sh)11355 options(int *login_sh)
11356 {
11357 char *p;
11358 int val;
11359 int c;
11360
11361 if (login_sh)
11362 minusc = NULL;
11363 while ((p = *argptr) != NULL) {
11364 c = *p++;
11365 if (c != '-' && c != '+')
11366 break;
11367 argptr++;
11368 val = 0; /* val = 0 if c == '+' */
11369 if (c == '-') {
11370 val = 1;
11371 if (p[0] == '\0' || LONE_DASH(p)) {
11372 if (!login_sh) {
11373 /* "-" means turn off -x and -v */
11374 if (p[0] == '\0')
11375 xflag = vflag = 0;
11376 /* "--" means reset params */
11377 else if (*argptr == NULL)
11378 setparam(argptr);
11379 }
11380 break; /* "-" or "--" terminates options */
11381 }
11382 }
11383 /* first char was + or - */
11384 while ((c = *p++) != '\0') {
11385 if (login_sh) {
11386 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
11387 if (c == 'c') {
11388 minusc = p; /* command is after shell args */
11389 cflag = 1;
11390 continue;
11391 }
11392 if (c == 's') { /* -s, +s */
11393 sflag = 1;
11394 continue;
11395 }
11396 if (c == 'i') { /* -i, +i */
11397 iflag = 1;
11398 continue;
11399 }
11400 if (c == 'l') {
11401 *login_sh = 1; /* -l or +l == --login */
11402 continue;
11403 }
11404 /* bash does not accept +-login, we also won't */
11405 if (val && (c == '-')) { /* long options */
11406 if (strcmp(p, "login") == 0) {
11407 *login_sh = 1;
11408 }
11409 break;
11410 }
11411 }
11412 if (c == 'o') {
11413 if (plus_minus_o(*argptr, val)) {
11414 /* it already printed err message */
11415 return 1; /* error */
11416 }
11417 if (*argptr)
11418 argptr++;
11419 } else {
11420 setoption(c, val);
11421 }
11422 }
11423 }
11424 return 0;
11425 }
11426
11427 /*
11428 * The shift builtin command.
11429 */
11430 static int FAST_FUNC
shiftcmd(int argc UNUSED_PARAM,char ** argv)11431 shiftcmd(int argc UNUSED_PARAM, char **argv)
11432 {
11433 int n;
11434 char **ap1, **ap2;
11435
11436 n = 1;
11437 if (argv[1])
11438 n = number(argv[1]);
11439 if (n > shellparam.nparam)
11440 return 1;
11441 INT_OFF;
11442 shellparam.nparam -= n;
11443 for (ap1 = shellparam.p; --n >= 0; ap1++) {
11444 if (shellparam.malloced)
11445 free(*ap1);
11446 }
11447 ap2 = shellparam.p;
11448 while ((*ap2++ = *ap1++) != NULL)
11449 continue;
11450 #if ENABLE_ASH_GETOPTS
11451 shellparam.optind = 1;
11452 shellparam.optoff = -1;
11453 #endif
11454 INT_ON;
11455 return 0;
11456 }
11457
11458 /*
11459 * POSIX requires that 'set' (but not export or readonly) output the
11460 * variables in lexicographic order - by the locale's collating order (sigh).
11461 * Maybe we could keep them in an ordered balanced binary tree
11462 * instead of hashed lists.
11463 * For now just roll 'em through qsort for printing...
11464 */
11465 static int
showvars(const char * sep_prefix,int on,int off)11466 showvars(const char *sep_prefix, int on, int off)
11467 {
11468 const char *sep;
11469 char **ep, **epend;
11470
11471 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
11472 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11473
11474 sep = *sep_prefix ? " " : sep_prefix;
11475
11476 for (; ep < epend; ep++) {
11477 const char *p;
11478 const char *q;
11479
11480 p = endofname(*ep);
11481 /* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11482 * makes "export -p" to have output not suitable for "eval":
11483 * import os
11484 * os.environ["test-test"]="test"
11485 * if os.fork() == 0:
11486 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11487 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11488 */
11489 q = nullstr;
11490 if (*p == '=')
11491 q = single_quote(++p);
11492 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11493 }
11494 return 0;
11495 }
11496
11497 /*
11498 * The set command builtin.
11499 */
11500 static int FAST_FUNC
setcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)11501 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11502 {
11503 int retval;
11504
11505 if (!argv[1])
11506 return showvars(nullstr, 0, VUNSET);
11507
11508 INT_OFF;
11509 retval = options(/*login_sh:*/ NULL);
11510 if (retval == 0) { /* if no parse error... */
11511 optschanged();
11512 if (*argptr != NULL) {
11513 setparam(argptr);
11514 }
11515 }
11516 INT_ON;
11517 return retval;
11518 }
11519
11520 #if ENABLE_ASH_RANDOM_SUPPORT
11521 static void FAST_FUNC
change_random(const char * value)11522 change_random(const char *value)
11523 {
11524 uint32_t t;
11525
11526 if (value == NULL) {
11527 /* "get", generate */
11528 t = next_random(&random_gen);
11529 /* set without recursion */
11530 setvar(vrandom.var_text, utoa(t), VNOFUNC);
11531 vrandom.flags &= ~VNOFUNC;
11532 } else {
11533 /* set/reset */
11534 t = strtoul(value, NULL, 10);
11535 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
11536 }
11537 }
11538 #endif
11539
11540 #if BASH_EPOCH_VARS
11541 static void FAST_FUNC
change_epoch(struct var * vepoch,const char * fmt)11542 change_epoch(struct var *vepoch, const char *fmt)
11543 {
11544 struct timeval tv;
11545 char buffer[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
11546
11547 xgettimeofday(&tv);
11548 sprintf(buffer, fmt, (unsigned long long)tv.tv_sec, (unsigned)tv.tv_usec);
11549 setvar(vepoch->var_text, buffer, VNOFUNC);
11550 vepoch->flags &= ~VNOFUNC;
11551 }
11552
11553 static void FAST_FUNC
change_seconds(const char * value UNUSED_PARAM)11554 change_seconds(const char *value UNUSED_PARAM)
11555 {
11556 change_epoch(&vepochs, "%llu");
11557 }
11558
11559 static void FAST_FUNC
change_realtime(const char * value UNUSED_PARAM)11560 change_realtime(const char *value UNUSED_PARAM)
11561 {
11562 change_epoch(&vepochr, "%llu.%06u");
11563 }
11564 #endif
11565
11566 #if ENABLE_ASH_GETOPTS
11567 static int
getopts(char * optstr,char * optvar,char ** optfirst)11568 getopts(char *optstr, char *optvar, char **optfirst)
11569 {
11570 char *p, *q;
11571 char c = '?';
11572 int done = 0;
11573 char sbuf[2];
11574 char **optnext;
11575 int ind = shellparam.optind;
11576 int off = shellparam.optoff;
11577
11578 sbuf[1] = '\0';
11579
11580 shellparam.optind = -1;
11581 optnext = optfirst + ind - 1;
11582
11583 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
11584 p = NULL;
11585 else
11586 p = optnext[-1] + off;
11587 if (p == NULL || *p == '\0') {
11588 /* Current word is done, advance */
11589 p = *optnext;
11590 if (p == NULL || *p != '-' || *++p == '\0') {
11591 atend:
11592 unsetvar("OPTARG");
11593 p = NULL;
11594 done = 1;
11595 goto out;
11596 }
11597 optnext++;
11598 if (LONE_DASH(p)) /* check for "--" */
11599 goto atend;
11600 }
11601
11602 c = *p++;
11603 for (q = optstr; *q != c;) {
11604 if (*q == '\0') {
11605 /* OPTERR is a bashism */
11606 const char *cp = lookupvar("OPTERR");
11607 if ((cp && LONE_CHAR(cp, '0'))
11608 || (optstr[0] == ':')
11609 ) {
11610 sbuf[0] = c;
11611 /*sbuf[1] = '\0'; - already is */
11612 setvar0("OPTARG", sbuf);
11613 } else {
11614 fprintf(stderr, "Illegal option -%c\n", c);
11615 unsetvar("OPTARG");
11616 }
11617 c = '?';
11618 goto out;
11619 }
11620 if (*++q == ':')
11621 q++;
11622 }
11623
11624 if (*++q == ':') {
11625 if (*p == '\0' && (p = *optnext) == NULL) {
11626 /* OPTERR is a bashism */
11627 const char *cp = lookupvar("OPTERR");
11628 if ((cp && LONE_CHAR(cp, '0'))
11629 || (optstr[0] == ':')
11630 ) {
11631 sbuf[0] = c;
11632 /*sbuf[1] = '\0'; - already is */
11633 setvar0("OPTARG", sbuf);
11634 c = ':';
11635 } else {
11636 fprintf(stderr, "No arg for -%c option\n", c);
11637 unsetvar("OPTARG");
11638 c = '?';
11639 }
11640 goto out;
11641 }
11642
11643 if (p == *optnext)
11644 optnext++;
11645 setvar0("OPTARG", p);
11646 p = NULL;
11647 } else
11648 setvar0("OPTARG", nullstr);
11649 out:
11650 ind = optnext - optfirst + 1;
11651 setvar("OPTIND", itoa(ind), VNOFUNC);
11652 sbuf[0] = c;
11653 /*sbuf[1] = '\0'; - already is */
11654 setvar0(optvar, sbuf);
11655
11656 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11657 shellparam.optind = ind;
11658
11659 return done;
11660 }
11661
11662 /*
11663 * The getopts builtin. Shellparam.optnext points to the next argument
11664 * to be processed. Shellparam.optptr points to the next character to
11665 * be processed in the current argument. If shellparam.optnext is NULL,
11666 * then it's the first time getopts has been called.
11667 */
11668 static int FAST_FUNC
getoptscmd(int argc,char ** argv)11669 getoptscmd(int argc, char **argv)
11670 {
11671 char **optbase;
11672
11673 if (argc < 3)
11674 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
11675 if (argc == 3) {
11676 optbase = shellparam.p;
11677 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
11678 shellparam.optind = 1;
11679 shellparam.optoff = -1;
11680 }
11681 } else {
11682 optbase = &argv[3];
11683 if ((unsigned)shellparam.optind > argc - 2) {
11684 shellparam.optind = 1;
11685 shellparam.optoff = -1;
11686 }
11687 }
11688
11689 return getopts(argv[1], argv[2], optbase);
11690 }
11691 #endif /* ASH_GETOPTS */
11692
11693
11694 /* ============ Shell parser */
11695
11696 struct heredoc {
11697 struct heredoc *next; /* next here document in list */
11698 union node *here; /* redirection node */
11699 char *eofmark; /* string indicating end of input */
11700 smallint striptabs; /* if set, strip leading tabs */
11701 };
11702
11703 static smallint tokpushback; /* last token pushed back */
11704 static smallint quoteflag; /* set if (part of) last token was quoted */
11705 static token_id_t lasttoken; /* last token read (integer id Txxx) */
11706 static struct heredoc *heredoclist; /* list of here documents to read */
11707 static char *wordtext; /* text of last word returned by readtoken */
11708 static struct nodelist *backquotelist;
11709 static union node *redirnode;
11710 static struct heredoc *heredoc;
11711
11712 static const char *
tokname(char * buf,int tok)11713 tokname(char *buf, int tok)
11714 {
11715 if (tok < TSEMI)
11716 return tokname_array[tok];
11717 sprintf(buf, "\"%s\"", tokname_array[tok]);
11718 return buf;
11719 }
11720
11721 /* raise_error_unexpected_syntax:
11722 * Called when an unexpected token is read during the parse. The argument
11723 * is the token that is expected, or -1 if more than one type of token can
11724 * occur at this point.
11725 */
11726 static void raise_error_unexpected_syntax(int) NORETURN;
11727 static void
raise_error_unexpected_syntax(int token)11728 raise_error_unexpected_syntax(int token)
11729 {
11730 char msg[64];
11731 char buf[16];
11732 int l;
11733
11734 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
11735 if (token >= 0)
11736 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
11737 raise_error_syntax(msg);
11738 /* NOTREACHED */
11739 }
11740
11741 /* parsing is heavily cross-recursive, need these forward decls */
11742 static union node *andor(void);
11743 static union node *pipeline(void);
11744 static union node *parse_command(void);
11745 static void parseheredoc(void);
11746 static int readtoken(void);
11747
11748 static union node *
list(int nlflag)11749 list(int nlflag)
11750 {
11751 int chknl = nlflag & 1 ? 0 : CHKNL;
11752 union node *n1, *n2, *n3;
11753 int tok;
11754
11755 n1 = NULL;
11756 for (;;) {
11757 checkkwd = chknl | CHKKWD | CHKALIAS;
11758 tok = readtoken();
11759 switch (tok) {
11760 case TNL:
11761 parseheredoc();
11762 return n1;
11763
11764 case TEOF:
11765 if (!n1 && !chknl)
11766 n1 = NODE_EOF;
11767 out_eof:
11768 parseheredoc();
11769 tokpushback++;
11770 lasttoken = TEOF;
11771 return n1;
11772 }
11773
11774 tokpushback++;
11775 if (nlflag == 2 && ((1 << tok) & tokendlist))
11776 return n1;
11777 nlflag |= 2;
11778
11779 n2 = andor();
11780 tok = readtoken();
11781 if (tok == TBACKGND) {
11782 if (n2->type == NPIPE) {
11783 n2->npipe.pipe_backgnd = 1;
11784 } else {
11785 if (n2->type != NREDIR) {
11786 n3 = stzalloc(sizeof(struct nredir));
11787 n3->nredir.n = n2;
11788 /*n3->nredir.redirect = NULL; - stzalloc did it */
11789 n2 = n3;
11790 }
11791 n2->type = NBACKGND;
11792 }
11793 }
11794 if (n1 == NULL) {
11795 n1 = n2;
11796 } else {
11797 n3 = stzalloc(sizeof(struct nbinary));
11798 n3->type = NSEMI;
11799 n3->nbinary.ch1 = n1;
11800 n3->nbinary.ch2 = n2;
11801 n1 = n3;
11802 }
11803 switch (tok) {
11804 case TEOF:
11805 goto out_eof;
11806 case TNL:
11807 tokpushback = 1;
11808 /* fall through */
11809 case TBACKGND:
11810 case TSEMI:
11811 break;
11812 default:
11813 if (!chknl)
11814 raise_error_unexpected_syntax(-1);
11815 tokpushback = 1;
11816 return n1;
11817 }
11818 }
11819 }
11820
11821 static union node *
andor(void)11822 andor(void)
11823 {
11824 union node *n1, *n2, *n3;
11825 int t;
11826
11827 n1 = pipeline();
11828 for (;;) {
11829 t = readtoken();
11830 if (t == TAND) {
11831 t = NAND;
11832 } else if (t == TOR) {
11833 t = NOR;
11834 } else {
11835 tokpushback = 1;
11836 return n1;
11837 }
11838 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11839 n2 = pipeline();
11840 n3 = stzalloc(sizeof(struct nbinary));
11841 n3->type = t;
11842 n3->nbinary.ch1 = n1;
11843 n3->nbinary.ch2 = n2;
11844 n1 = n3;
11845 }
11846 }
11847
11848 static union node *
pipeline(void)11849 pipeline(void)
11850 {
11851 union node *n1, *n2, *pipenode;
11852 struct nodelist *lp, *prev;
11853 int negate;
11854
11855 negate = 0;
11856 TRACE(("pipeline: entered\n"));
11857 if (readtoken() == TNOT) {
11858 negate = !negate;
11859 checkkwd = CHKKWD | CHKALIAS;
11860 } else
11861 tokpushback = 1;
11862 n1 = parse_command();
11863 if (readtoken() == TPIPE) {
11864 pipenode = stzalloc(sizeof(struct npipe));
11865 pipenode->type = NPIPE;
11866 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
11867 lp = stzalloc(sizeof(struct nodelist));
11868 pipenode->npipe.cmdlist = lp;
11869 lp->n = n1;
11870 do {
11871 prev = lp;
11872 lp = stzalloc(sizeof(struct nodelist));
11873 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11874 lp->n = parse_command();
11875 prev->next = lp;
11876 } while (readtoken() == TPIPE);
11877 lp->next = NULL;
11878 n1 = pipenode;
11879 }
11880 tokpushback = 1;
11881 if (negate) {
11882 n2 = stzalloc(sizeof(struct nnot));
11883 n2->type = NNOT;
11884 n2->nnot.com = n1;
11885 return n2;
11886 }
11887 return n1;
11888 }
11889
11890 static union node *
makename(void)11891 makename(void)
11892 {
11893 union node *n;
11894
11895 n = stzalloc(sizeof(struct narg));
11896 n->type = NARG;
11897 /*n->narg.next = NULL; - stzalloc did it */
11898 n->narg.text = wordtext;
11899 n->narg.backquote = backquotelist;
11900 return n;
11901 }
11902
11903 static void
fixredir(union node * n,const char * text,int err)11904 fixredir(union node *n, const char *text, int err)
11905 {
11906 int fd;
11907
11908 TRACE(("Fix redir %s %d\n", text, err));
11909 if (!err)
11910 n->ndup.vname = NULL;
11911
11912 fd = bb_strtou(text, NULL, 10);
11913 if (!errno && fd >= 0)
11914 n->ndup.dupfd = fd;
11915 else if (LONE_DASH(text))
11916 n->ndup.dupfd = -1;
11917 else {
11918 if (err)
11919 raise_error_syntax("bad fd number");
11920 n->ndup.vname = makename();
11921 }
11922 }
11923
11924 static void
parsefname(void)11925 parsefname(void)
11926 {
11927 union node *n = redirnode;
11928
11929 if (n->type == NHERE)
11930 checkkwd = CHKEOFMARK;
11931 if (readtoken() != TWORD)
11932 raise_error_unexpected_syntax(-1);
11933 if (n->type == NHERE) {
11934 struct heredoc *here = heredoc;
11935 struct heredoc *p;
11936
11937 if (quoteflag == 0)
11938 n->type = NXHERE;
11939 TRACE(("Here document %d\n", n->type));
11940 rmescapes(wordtext, 0, NULL);
11941 here->eofmark = wordtext;
11942 here->next = NULL;
11943 if (heredoclist == NULL)
11944 heredoclist = here;
11945 else {
11946 for (p = heredoclist; p->next; p = p->next)
11947 continue;
11948 p->next = here;
11949 }
11950 } else if (n->type == NTOFD || n->type == NFROMFD) {
11951 fixredir(n, wordtext, 0);
11952 } else {
11953 n->nfile.fname = makename();
11954 }
11955 }
11956
11957 static union node *
simplecmd(void)11958 simplecmd(void)
11959 {
11960 union node *args, **app;
11961 union node *n = NULL;
11962 union node *vars, **vpp;
11963 union node **rpp, *redir;
11964 int savecheckkwd;
11965 int savelinno;
11966 #if BASH_TEST2
11967 smallint double_brackets_flag = 0;
11968 #endif
11969 IF_BASH_FUNCTION(smallint function_flag = 0;)
11970
11971 args = NULL;
11972 app = &args;
11973 vars = NULL;
11974 vpp = &vars;
11975 redir = NULL;
11976 rpp = &redir;
11977
11978 savecheckkwd = CHKALIAS;
11979 savelinno = g_parsefile->linno;
11980 for (;;) {
11981 int t;
11982 checkkwd = savecheckkwd;
11983 t = readtoken();
11984 switch (t) {
11985 #if BASH_FUNCTION
11986 case TFUNCTION:
11987 if (readtoken() != TWORD)
11988 raise_error_unexpected_syntax(TWORD);
11989 tokpushback = 1;
11990 function_flag = 1;
11991 break;
11992 #endif
11993 #if BASH_TEST2
11994 case TAND: /* "&&" */
11995 case TOR: /* "||" */
11996 if (!double_brackets_flag) {
11997 tokpushback = 1;
11998 goto out;
11999 }
12000 /* pass "&&" or "||" to [[ ]] as literal args */
12001 wordtext = (char *) (t == TAND ? "&&" : "||");
12002 #endif
12003 case TWORD:
12004 n = stzalloc(sizeof(struct narg));
12005 n->type = NARG;
12006 /*n->narg.next = NULL; - stzalloc did it */
12007 n->narg.text = wordtext;
12008 #if BASH_TEST2
12009 if (strcmp("[[", wordtext) == 0)
12010 double_brackets_flag = 1;
12011 else if (strcmp("]]", wordtext) == 0)
12012 double_brackets_flag = 0;
12013 #endif
12014 n->narg.backquote = backquotelist;
12015 if (savecheckkwd && isassignment(wordtext)) {
12016 *vpp = n;
12017 vpp = &n->narg.next;
12018 } else {
12019 *app = n;
12020 app = &n->narg.next;
12021 savecheckkwd = 0;
12022 }
12023 #if BASH_FUNCTION
12024 if (function_flag) {
12025 checkkwd = CHKNL | CHKKWD;
12026 t = readtoken();
12027 tokpushback = 1;
12028 switch (t) {
12029 case TBEGIN:
12030 case TIF:
12031 case TCASE:
12032 case TUNTIL:
12033 case TWHILE:
12034 case TFOR:
12035 goto do_func;
12036 case TLP:
12037 function_flag = 0;
12038 break;
12039 # if BASH_TEST2
12040 case TWORD:
12041 if (strcmp("[[", wordtext) == 0)
12042 goto do_func;
12043 /* fall through */
12044 # endif
12045 default:
12046 raise_error_unexpected_syntax(-1);
12047 }
12048 }
12049 #endif
12050 break;
12051 case TREDIR:
12052 *rpp = n = redirnode;
12053 rpp = &n->nfile.next;
12054 parsefname(); /* read name of redirection file */
12055 break;
12056 case TLP:
12057 IF_BASH_FUNCTION(do_func:)
12058 if (args && app == &args->narg.next
12059 && !vars && !redir
12060 ) {
12061 struct builtincmd *bcmd;
12062 const char *name;
12063
12064 /* We have a function */
12065 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
12066 raise_error_unexpected_syntax(TRP);
12067 name = n->narg.text;
12068 if (!goodname(name)
12069 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
12070 ) {
12071 raise_error_syntax("bad function name");
12072 }
12073 n->type = NDEFUN;
12074 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12075 n->ndefun.text = n->narg.text;
12076 n->ndefun.linno = g_parsefile->linno;
12077 n->ndefun.body = parse_command();
12078 return n;
12079 }
12080 IF_BASH_FUNCTION(function_flag = 0;)
12081 /* fall through */
12082 default:
12083 tokpushback = 1;
12084 goto out;
12085 }
12086 }
12087 out:
12088 *app = NULL;
12089 *vpp = NULL;
12090 *rpp = NULL;
12091 n = stzalloc(sizeof(struct ncmd));
12092 if (NCMD != 0)
12093 n->type = NCMD;
12094 n->ncmd.linno = savelinno;
12095 n->ncmd.args = args;
12096 n->ncmd.assign = vars;
12097 n->ncmd.redirect = redir;
12098 return n;
12099 }
12100
12101 static union node *
parse_command(void)12102 parse_command(void)
12103 {
12104 union node *n1, *n2;
12105 union node *ap, **app;
12106 union node *cp, **cpp;
12107 union node *redir, **rpp;
12108 union node **rpp2;
12109 int t;
12110 int savelinno;
12111
12112 redir = NULL;
12113 rpp2 = &redir;
12114
12115 savelinno = g_parsefile->linno;
12116
12117 switch (readtoken()) {
12118 default:
12119 raise_error_unexpected_syntax(-1);
12120 /* NOTREACHED */
12121 case TIF:
12122 n1 = stzalloc(sizeof(struct nif));
12123 n1->type = NIF;
12124 n1->nif.test = list(0);
12125 if (readtoken() != TTHEN)
12126 raise_error_unexpected_syntax(TTHEN);
12127 n1->nif.ifpart = list(0);
12128 n2 = n1;
12129 while (readtoken() == TELIF) {
12130 n2->nif.elsepart = stzalloc(sizeof(struct nif));
12131 n2 = n2->nif.elsepart;
12132 n2->type = NIF;
12133 n2->nif.test = list(0);
12134 if (readtoken() != TTHEN)
12135 raise_error_unexpected_syntax(TTHEN);
12136 n2->nif.ifpart = list(0);
12137 }
12138 if (lasttoken == TELSE)
12139 n2->nif.elsepart = list(0);
12140 else {
12141 n2->nif.elsepart = NULL;
12142 tokpushback = 1;
12143 }
12144 t = TFI;
12145 break;
12146 case TWHILE:
12147 case TUNTIL: {
12148 int got;
12149 n1 = stzalloc(sizeof(struct nbinary));
12150 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
12151 n1->nbinary.ch1 = list(0);
12152 got = readtoken();
12153 if (got != TDO) {
12154 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
12155 got == TWORD ? wordtext : ""));
12156 raise_error_unexpected_syntax(TDO);
12157 }
12158 n1->nbinary.ch2 = list(0);
12159 t = TDONE;
12160 break;
12161 }
12162 case TFOR:
12163 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
12164 raise_error_syntax("bad for loop variable");
12165 n1 = stzalloc(sizeof(struct nfor));
12166 n1->type = NFOR;
12167 n1->nfor.linno = savelinno;
12168 n1->nfor.var = wordtext;
12169 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12170 if (readtoken() == TIN) {
12171 app = ≈
12172 while (readtoken() == TWORD) {
12173 n2 = stzalloc(sizeof(struct narg));
12174 n2->type = NARG;
12175 /*n2->narg.next = NULL; - stzalloc did it */
12176 n2->narg.text = wordtext;
12177 n2->narg.backquote = backquotelist;
12178 *app = n2;
12179 app = &n2->narg.next;
12180 }
12181 *app = NULL;
12182 n1->nfor.args = ap;
12183 if (lasttoken != TNL && lasttoken != TSEMI)
12184 raise_error_unexpected_syntax(-1);
12185 } else {
12186 n2 = stzalloc(sizeof(struct narg));
12187 n2->type = NARG;
12188 /*n2->narg.next = NULL; - stzalloc did it */
12189 n2->narg.text = (char *)dolatstr;
12190 /*n2->narg.backquote = NULL;*/
12191 n1->nfor.args = n2;
12192 /*
12193 * Newline or semicolon here is optional (but note
12194 * that the original Bourne shell only allowed NL).
12195 */
12196 if (lasttoken != TSEMI)
12197 tokpushback = 1;
12198 }
12199 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12200 if (readtoken() != TDO)
12201 raise_error_unexpected_syntax(TDO);
12202 n1->nfor.body = list(0);
12203 t = TDONE;
12204 break;
12205 case TCASE:
12206 n1 = stzalloc(sizeof(struct ncase));
12207 n1->type = NCASE;
12208 n1->ncase.linno = savelinno;
12209 if (readtoken() != TWORD)
12210 raise_error_unexpected_syntax(TWORD);
12211 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
12212 n2->type = NARG;
12213 /*n2->narg.next = NULL; - stzalloc did it */
12214 n2->narg.text = wordtext;
12215 n2->narg.backquote = backquotelist;
12216 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12217 if (readtoken() != TIN)
12218 raise_error_unexpected_syntax(TIN);
12219 cpp = &n1->ncase.cases;
12220 next_case:
12221 checkkwd = CHKNL | CHKKWD;
12222 t = readtoken();
12223 while (t != TESAC) {
12224 if (lasttoken == TLP)
12225 readtoken();
12226 *cpp = cp = stzalloc(sizeof(struct nclist));
12227 cp->type = NCLIST;
12228 app = &cp->nclist.pattern;
12229 for (;;) {
12230 *app = ap = stzalloc(sizeof(struct narg));
12231 ap->type = NARG;
12232 /*ap->narg.next = NULL; - stzalloc did it */
12233 ap->narg.text = wordtext;
12234 ap->narg.backquote = backquotelist;
12235 if (readtoken() != TPIPE)
12236 break;
12237 app = &ap->narg.next;
12238 readtoken();
12239 }
12240 //ap->narg.next = NULL;
12241 if (lasttoken != TRP)
12242 raise_error_unexpected_syntax(TRP);
12243 cp->nclist.body = list(2);
12244
12245 cpp = &cp->nclist.next;
12246
12247 checkkwd = CHKNL | CHKKWD;
12248 t = readtoken();
12249 if (t != TESAC) {
12250 if (t != TENDCASE)
12251 raise_error_unexpected_syntax(TENDCASE);
12252 goto next_case;
12253 }
12254 }
12255 *cpp = NULL;
12256 goto redir;
12257 case TLP:
12258 n1 = stzalloc(sizeof(struct nredir));
12259 n1->type = NSUBSHELL;
12260 n1->nredir.linno = savelinno;
12261 n1->nredir.n = list(0);
12262 /*n1->nredir.redirect = NULL; - stzalloc did it */
12263 t = TRP;
12264 break;
12265 case TBEGIN:
12266 n1 = list(0);
12267 t = TEND;
12268 break;
12269 IF_BASH_FUNCTION(case TFUNCTION:)
12270 case TWORD:
12271 case TREDIR:
12272 tokpushback = 1;
12273 return simplecmd();
12274 }
12275
12276 if (readtoken() != t)
12277 raise_error_unexpected_syntax(t);
12278
12279 redir:
12280 /* Now check for redirection which may follow command */
12281 checkkwd = CHKKWD | CHKALIAS;
12282 rpp = rpp2;
12283 while (readtoken() == TREDIR) {
12284 *rpp = n2 = redirnode;
12285 rpp = &n2->nfile.next;
12286 parsefname();
12287 }
12288 tokpushback = 1;
12289 *rpp = NULL;
12290 if (redir) {
12291 if (n1->type != NSUBSHELL) {
12292 n2 = stzalloc(sizeof(struct nredir));
12293 n2->type = NREDIR;
12294 n2->nredir.linno = savelinno;
12295 n2->nredir.n = n1;
12296 n1 = n2;
12297 }
12298 n1->nredir.redirect = redir;
12299 }
12300 return n1;
12301 }
12302
12303 #if BASH_DOLLAR_SQUOTE
12304 static int
decode_dollar_squote(void)12305 decode_dollar_squote(void)
12306 {
12307 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
12308 int c, cnt;
12309 char *p;
12310 char buf[4];
12311
12312 c = pgetc();
12313 p = strchr(C_escapes, c);
12314 if (p) {
12315 buf[0] = c;
12316 p = buf;
12317 cnt = 3;
12318 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
12319 do {
12320 c = pgetc();
12321 *++p = c;
12322 } while ((unsigned char)(c - '0') <= 7 && --cnt);
12323 pungetc();
12324 } else if (c == 'x') { /* \xHH */
12325 do {
12326 c = pgetc();
12327 *++p = c;
12328 } while (isxdigit(c) && --cnt);
12329 pungetc();
12330 if (cnt == 3) { /* \x but next char is "bad" */
12331 c = 'x';
12332 goto unrecognized;
12333 }
12334 } else { /* simple seq like \\ or \t */
12335 p++;
12336 }
12337 *p = '\0';
12338 p = buf;
12339 c = bb_process_escape_sequence((void*)&p);
12340 } else { /* unrecognized "\z": print both chars unless ' or " */
12341 if (c != '\'' && c != '"') {
12342 unrecognized:
12343 c |= 0x100; /* "please encode \, then me" */
12344 }
12345 }
12346 return c;
12347 }
12348 #endif
12349
12350 /* Used by expandstr to get here-doc like behaviour. */
12351 #define FAKEEOFMARK ((char*)(uintptr_t)1)
12352
12353 static ALWAYS_INLINE int
realeofmark(const char * eofmark)12354 realeofmark(const char *eofmark)
12355 {
12356 return eofmark && eofmark != FAKEEOFMARK;
12357 }
12358
12359 /*
12360 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
12361 * is not NULL, read a here document. In the latter case, eofmark is the
12362 * word which marks the end of the document and striptabs is true if
12363 * leading tabs should be stripped from the document. The argument c
12364 * is the first character of the input token or document.
12365 *
12366 * Because C does not have internal subroutines, I have simulated them
12367 * using goto's to implement the subroutine linkage. The following macros
12368 * will run code that appears at the end of readtoken1.
12369 */
12370 #define CHECKEND() {goto checkend; checkend_return:;}
12371 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
12372 #define PARSESUB() {goto parsesub; parsesub_return:;}
12373 #define PARSEBACKQOLD() {style = OLD; goto parsebackq; parsebackq_oldreturn:;}
12374 #define PARSEBACKQNEW() {style = NEW; goto parsebackq; parsebackq_newreturn:;}
12375 #define PARSEPROCSUB() {style = PSUB; goto parsebackq; parsebackq_psreturn:;}
12376 #define PARSEARITH() {goto parsearith; parsearith_return:;}
12377 static int
readtoken1(int c,int syntax,char * eofmark,int striptabs)12378 readtoken1(int c, int syntax, char *eofmark, int striptabs)
12379 {
12380 /* NB: syntax parameter fits into smallint */
12381 /* c parameter is an unsigned char or PEOF */
12382 char *out;
12383 size_t len;
12384 struct nodelist *bqlist;
12385 smallint quotef;
12386 smallint style;
12387 enum { OLD, NEW, PSUB };
12388 #define oldstyle (style == OLD)
12389 smallint pssyntax; /* we are expanding a prompt string */
12390 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
12391 /* syntax stack */
12392 struct synstack synbase = { };
12393 struct synstack *synstack = &synbase;
12394
12395 #if ENABLE_ASH_EXPAND_PRMT
12396 pssyntax = (syntax == PSSYNTAX);
12397 if (pssyntax)
12398 syntax = DQSYNTAX;
12399 #else
12400 pssyntax = 0; /* constant */
12401 #endif
12402 synstack->syntax = syntax;
12403
12404 if (syntax == DQSYNTAX)
12405 synstack->dblquote = 1;
12406 quotef = 0;
12407 bqlist = NULL;
12408
12409 STARTSTACKSTR(out);
12410 loop:
12411 /* For each line, until end of word */
12412 CHECKEND(); /* set c to PEOF if at end of here document */
12413 for (;;) { /* until end of line or end of word */
12414 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
12415 switch (SIT(c, synstack->syntax)) {
12416 case CNL: /* '\n' */
12417 if (synstack->syntax == BASESYNTAX
12418 && !synstack->varnest
12419 ) {
12420 goto endword; /* exit outer loop */
12421 }
12422 USTPUTC(c, out);
12423 nlprompt();
12424 c = pgetc_top(synstack);
12425 goto loop; /* continue outer loop */
12426 case CWORD:
12427 USTPUTC(c, out);
12428 break;
12429 case CCTL:
12430 #if BASH_DOLLAR_SQUOTE
12431 if (c == '\\' && bash_dollar_squote) {
12432 c = decode_dollar_squote();
12433 if (c == '\0') {
12434 /* skip $'\000', $'\x00' (like bash) */
12435 break;
12436 }
12437 if (c & 0x100) {
12438 /* Unknown escape. Encode as '\z' */
12439 c = (unsigned char)c;
12440 if (eofmark == NULL || synstack->dblquote)
12441 USTPUTC(CTLESC, out);
12442 USTPUTC('\\', out);
12443 }
12444 }
12445 #endif
12446 if (!eofmark || synstack->dblquote || synstack->varnest)
12447 USTPUTC(CTLESC, out);
12448 USTPUTC(c, out);
12449 break;
12450 case CBACK: /* backslash */
12451 c = pgetc();
12452 if (c == PEOF) {
12453 USTPUTC(CTLESC, out);
12454 USTPUTC('\\', out);
12455 pungetc();
12456 } else {
12457 if (pssyntax && c == '$') {
12458 USTPUTC(CTLESC, out);
12459 USTPUTC('\\', out);
12460 }
12461 /* Backslash is retained if we are in "str"
12462 * and next char isn't dquote-special.
12463 */
12464 if (synstack->dblquote
12465 && c != '\\'
12466 && c != '`'
12467 && c != '$'
12468 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12469 && (c != '}' || !synstack->varnest)
12470 ) {
12471 USTPUTC(CTLESC, out); /* protect '\' from glob */
12472 USTPUTC('\\', out);
12473 }
12474 USTPUTC(CTLESC, out);
12475 USTPUTC(c, out);
12476 quotef = 1;
12477 }
12478 break;
12479 case CSQUOTE:
12480 synstack->syntax = SQSYNTAX;
12481 quotemark:
12482 if (eofmark == NULL) {
12483 USTPUTC(CTLQUOTEMARK, out);
12484 }
12485 break;
12486 case CDQUOTE:
12487 synstack->syntax = DQSYNTAX;
12488 synstack->dblquote = 1;
12489 toggledq:
12490 if (synstack->varnest)
12491 synstack->innerdq ^= 1;
12492 goto quotemark;
12493 case CENDQUOTE:
12494 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
12495 if (eofmark != NULL && synstack->varnest == 0) {
12496 USTPUTC(c, out);
12497 break;
12498 }
12499
12500 if (synstack->dqvarnest == 0) {
12501 synstack->syntax = BASESYNTAX;
12502 synstack->dblquote = 0;
12503 }
12504
12505 quotef = 1;
12506
12507 if (c == '"')
12508 goto toggledq;
12509
12510 goto quotemark;
12511 case CVAR: /* '$' */
12512 PARSESUB(); /* parse substitution */
12513 break;
12514 case CENDVAR: /* '}' */
12515 if (!synstack->innerdq && synstack->varnest > 0) {
12516 if (!--synstack->varnest && synstack->varpushed)
12517 synstack_pop(&synstack);
12518 else if (synstack->dqvarnest > 0)
12519 synstack->dqvarnest--;
12520 c = CTLENDVAR;
12521 }
12522 USTPUTC(c, out);
12523 break;
12524 #if ENABLE_FEATURE_SH_MATH
12525 case CLP: /* '(' in arithmetic */
12526 synstack->parenlevel++;
12527 USTPUTC(c, out);
12528 break;
12529 case CRP: /* ')' in arithmetic */
12530 if (synstack->parenlevel > 0) {
12531 synstack->parenlevel--;
12532 } else {
12533 if (pgetc_eatbnl() == ')') {
12534 c = CTLENDARI;
12535 synstack_pop(&synstack);
12536 } else {
12537 /*
12538 * unbalanced parens
12539 * (don't 2nd guess - no error)
12540 */
12541 pungetc();
12542 }
12543 }
12544 USTPUTC(c, out);
12545 break;
12546 #endif
12547 case CBQUOTE: /* '`' */
12548 if (checkkwd & CHKEOFMARK) {
12549 quotef = 1;
12550 USTPUTC('`', out);
12551 break;
12552 }
12553
12554 PARSEBACKQOLD();
12555 break;
12556 case CENDFILE:
12557 goto endword; /* exit outer loop */
12558 default:
12559 if (synstack->varnest == 0) {
12560 #if BASH_REDIR_OUTPUT
12561 if (c == '&') {
12562 //Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
12563 if (pgetc() == '>')
12564 c = 0x100 + '>'; /* flag &> */
12565 pungetc();
12566 }
12567 #endif
12568 #if BASH_PROCESS_SUBST
12569 if (c == '<' || c == '>') {
12570 if (pgetc() == '(') {
12571 PARSEPROCSUB();
12572 break;
12573 }
12574 pungetc();
12575 }
12576 #endif
12577 goto endword; /* exit outer loop */
12578 }
12579 USTPUTC(c, out);
12580 }
12581 c = pgetc_top(synstack);
12582 } /* for (;;) */
12583 endword:
12584
12585 #if ENABLE_FEATURE_SH_MATH
12586 if (synstack->syntax == ARISYNTAX)
12587 raise_error_syntax("missing '))'");
12588 #endif
12589 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
12590 raise_error_syntax("unterminated quoted string");
12591 if (synstack->varnest != 0) {
12592 /* { */
12593 raise_error_syntax("missing '}'");
12594 }
12595 USTPUTC('\0', out);
12596 len = out - (char *)stackblock();
12597 out = stackblock();
12598 if (eofmark == NULL) {
12599 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
12600 && quotef == 0
12601 ) {
12602 if (isdigit_str9(out)) {
12603 PARSEREDIR(); /* passed as params: out, c */
12604 lasttoken = TREDIR;
12605 return lasttoken;
12606 }
12607 /* else: non-number X seen, interpret it
12608 * as "NNNX>file" = "NNNX >file" */
12609 }
12610 pungetc();
12611 }
12612 quoteflag = quotef;
12613 backquotelist = bqlist;
12614 grabstackblock(len);
12615 wordtext = out;
12616 lasttoken = TWORD;
12617 return lasttoken;
12618 /* end of readtoken routine */
12619
12620 /*
12621 * Check to see whether we are at the end of the here document. When this
12622 * is called, c is set to the first character of the next input line. If
12623 * we are at the end of the here document, this routine sets the c to PEOF.
12624 */
12625 checkend: {
12626 if (realeofmark(eofmark)) {
12627 int markloc;
12628 char *p;
12629
12630 if (striptabs) {
12631 while (c == '\t')
12632 c = pgetc();
12633 }
12634
12635 markloc = out - (char *)stackblock();
12636 for (p = eofmark; STPUTC(c, out), *p; p++) {
12637 if (c != *p)
12638 goto more_heredoc;
12639 /* FIXME: fails for backslash-newlined terminator:
12640 * cat <<EOF
12641 * ...
12642 * EO\
12643 * F
12644 * (see heredoc_bkslash_newline2.tests)
12645 */
12646 c = pgetc();
12647 }
12648
12649 if (c == '\n' || c == PEOF) {
12650 c = PEOF;
12651 if (trap_depth == 0)
12652 g_parsefile->linno++;
12653 needprompt = doprompt;
12654 } else {
12655 int len_here;
12656
12657 more_heredoc:
12658 p = (char *)stackblock() + markloc + 1;
12659 len_here = out - p;
12660
12661 if (len_here) {
12662 len_here -= (c >= PEOF);
12663 c = p[-1];
12664
12665 if (len_here) {
12666 char *str;
12667
12668 str = alloca(len_here + 1);
12669 *(char *)mempcpy(str, p, len_here) = '\0';
12670
12671 pushstring(str, NULL);
12672 }
12673 }
12674 }
12675
12676 STADJUST((char *)stackblock() + markloc - out, out);
12677 }
12678 goto checkend_return;
12679 }
12680
12681 /*
12682 * Parse a redirection operator. The variable "out" points to a string
12683 * specifying the fd to be redirected. The variable "c" contains the
12684 * first character of the redirection operator.
12685 */
12686 parseredir: {
12687 /* out is already checked to be a valid number or "" */
12688 int fd = (*out == '\0' ? -1 : atoi(out));
12689 union node *np;
12690
12691 np = stzalloc(sizeof(struct nfile));
12692 if (c == '>') {
12693 np->nfile.fd = 1;
12694 c = pgetc_eatbnl();
12695 if (c == '>')
12696 np->type = NAPPEND;
12697 else if (c == '|')
12698 np->type = NCLOBBER;
12699 else if (c == '&')
12700 np->type = NTOFD;
12701 /* it also can be NTO2 (>&file), but we can't figure it out yet */
12702 else {
12703 np->type = NTO;
12704 pungetc();
12705 }
12706 }
12707 #if BASH_REDIR_OUTPUT
12708 else if (c == 0x100 + '>') { /* this flags &> redirection */
12709 np->nfile.fd = 1;
12710 pgetc(); /* this is '>', no need to check */
12711 np->type = NTO2;
12712 }
12713 #endif
12714 else { /* c == '<' */
12715 /*np->nfile.fd = 0; - stzalloc did it */
12716 c = pgetc_eatbnl();
12717 switch (c) {
12718 case '<':
12719 if (sizeof(struct nfile) != sizeof(struct nhere)) {
12720 np = stzalloc(sizeof(struct nhere));
12721 /*np->nfile.fd = 0; - stzalloc did it */
12722 }
12723 np->type = NHERE;
12724 heredoc = stzalloc(sizeof(struct heredoc));
12725 heredoc->here = np;
12726 c = pgetc_eatbnl();
12727 if (c == '-') {
12728 heredoc->striptabs = 1;
12729 } else {
12730 /*heredoc->striptabs = 0; - stzalloc did it */
12731 pungetc();
12732 }
12733 break;
12734
12735 case '&':
12736 np->type = NFROMFD;
12737 break;
12738
12739 case '>':
12740 np->type = NFROMTO;
12741 break;
12742
12743 default:
12744 np->type = NFROM;
12745 pungetc();
12746 break;
12747 }
12748 }
12749 if (fd >= 0)
12750 np->nfile.fd = fd;
12751 redirnode = np;
12752 goto parseredir_return;
12753 }
12754
12755 /*
12756 * Parse a substitution. At this point, we have read the dollar sign
12757 * and nothing else.
12758 */
12759
12760 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12761 * (assuming ascii char codes, as the original implementation did) */
12762 #define is_special(c) \
12763 (((unsigned)(c) - 33 < 32) \
12764 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
12765 parsesub: {
12766 unsigned char subtype;
12767 int typeloc;
12768
12769 c = pgetc_eatbnl();
12770 if ((checkkwd & CHKEOFMARK)
12771 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
12772 ) {
12773 #if BASH_DOLLAR_SQUOTE
12774 if (synstack->syntax != DQSYNTAX && c == '\'')
12775 bash_dollar_squote = 1;
12776 else
12777 #endif
12778 USTPUTC('$', out);
12779 pungetc();
12780 } else if (c == '(') {
12781 /* $(command) or $((arith)) */
12782 if (pgetc_eatbnl() == '(') {
12783 #if ENABLE_FEATURE_SH_MATH
12784 PARSEARITH();
12785 #else
12786 raise_error_syntax("support for $((arith)) is disabled");
12787 #endif
12788 } else {
12789 pungetc();
12790 PARSEBACKQNEW();
12791 }
12792 } else {
12793 /* $VAR, $<specialchar>, ${...}, or PEOF */
12794 smalluint newsyn = synstack->syntax;
12795
12796 USTPUTC(CTLVAR, out);
12797 typeloc = out - (char *)stackblock();
12798 STADJUST(1, out);
12799 subtype = VSNORMAL;
12800 if (c == '{') {
12801 c = pgetc_eatbnl();
12802 subtype = 0;
12803 }
12804 varname:
12805 if (is_name(c)) {
12806 /* $[{[#]]NAME[}] */
12807 do {
12808 STPUTC(c, out);
12809 c = pgetc_eatbnl();
12810 } while (is_in_name(c));
12811 } else if (isdigit(c)) {
12812 /* $[{[#]]NUM[}] */
12813 do {
12814 STPUTC(c, out);
12815 c = pgetc_eatbnl();
12816 } while ((subtype == 0 || subtype == VSLENGTH) && isdigit(c));
12817 } else if (c != '}') {
12818 /* $[{[#]]<specialchar>[}] */
12819 int cc = c;
12820
12821 c = pgetc_eatbnl();
12822 if (!subtype && cc == '#') {
12823 subtype = VSLENGTH;
12824 if (c == '_' || isalnum(c))
12825 goto varname;
12826 cc = c;
12827 c = pgetc_eatbnl();
12828 if (cc == '}' || c != '}') {
12829 pungetc();
12830 subtype = 0;
12831 c = cc;
12832 cc = '#';
12833 }
12834 }
12835
12836 if (!is_special(cc)) {
12837 if (subtype == VSLENGTH)
12838 subtype = 0;
12839 goto badsub;
12840 }
12841
12842 USTPUTC(cc, out);
12843 } else
12844 goto badsub;
12845
12846 if (subtype == 0) {
12847 static const char types[] ALIGN1 = "}-+?=";
12848 /* ${VAR...} but not $VAR or ${#VAR} */
12849 /* c == first char after VAR */
12850 int cc = c;
12851
12852 switch (c) {
12853 case ':':
12854 c = pgetc_eatbnl();
12855 #if BASH_SUBSTR
12856 /* This check is only needed to not misinterpret
12857 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12858 * constructs.
12859 */
12860 if (!strchr(types, c)) {
12861 subtype = VSSUBSTR;
12862 pungetc();
12863 break; /* "goto badsub" is bigger (!) */
12864 }
12865 #endif
12866 subtype = VSNUL;
12867 /*FALLTHROUGH*/
12868 default: {
12869 const char *p = strchr(types, c);
12870 if (p == NULL)
12871 break;
12872 subtype |= p - types + VSNORMAL;
12873 break;
12874 }
12875 case '%':
12876 case '#':
12877 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
12878 c = pgetc_eatbnl();
12879 if (c == cc)
12880 subtype++;
12881 else
12882 pungetc();
12883
12884 newsyn = BASESYNTAX;
12885 break;
12886 #if BASH_PATTERN_SUBST
12887 case '/':
12888 /* ${v/[/]pattern/repl} */
12889 //TODO: encode pattern and repl separately.
12890 // Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12891 // are broken (should print "ONE")
12892 subtype = VSREPLACE;
12893 newsyn = BASESYNTAX;
12894 c = pgetc_eatbnl();
12895 if (c != '/')
12896 goto badsub;
12897 subtype++; /* VSREPLACEALL */
12898 break;
12899 #endif
12900 }
12901 } else {
12902 if (subtype == VSLENGTH && c != '}')
12903 subtype = 0;
12904 badsub:
12905 pungetc();
12906 }
12907
12908 if (newsyn == ARISYNTAX)
12909 newsyn = DQSYNTAX;
12910
12911 if ((newsyn != synstack->syntax || synstack->innerdq)
12912 && subtype != VSNORMAL
12913 ) {
12914 synstack_push(&synstack,
12915 synstack->prev ?: alloca(sizeof(*synstack)),
12916 newsyn);
12917
12918 synstack->varpushed = 1;
12919 synstack->dblquote = newsyn != BASESYNTAX;
12920 }
12921
12922 ((unsigned char *)stackblock())[typeloc] = subtype;
12923 if (subtype != VSNORMAL) {
12924 synstack->varnest++;
12925 if (synstack->dblquote)
12926 synstack->dqvarnest++;
12927 }
12928 STPUTC('=', out);
12929 }
12930 goto parsesub_return;
12931 }
12932
12933 /*
12934 * Called to parse command substitutions. Newstyle is set if the command
12935 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12936 * list of commands (passed by reference), and savelen is the number of
12937 * characters on the top of the stack which must be preserved.
12938 */
12939 parsebackq: {
12940 struct nodelist **nlpp;
12941 union node *n;
12942 char *str;
12943 size_t savelen;
12944 struct heredoc *saveheredoclist;
12945 smallint saveprompt = 0;
12946
12947 str = NULL;
12948 savelen = out - (char *)stackblock();
12949 if (savelen > 0) {
12950 /*
12951 * FIXME: this can allocate very large block on stack and SEGV.
12952 * Example:
12953 * echo "..<100kbytes>..`true` $(true) `true` ..."
12954 * allocates 100kb for every command subst. With about
12955 * a hundred command substitutions stack overflows.
12956 * With larger prepended string, SEGV happens sooner.
12957 */
12958 str = alloca(savelen);
12959 memcpy(str, stackblock(), savelen);
12960 }
12961
12962 if (oldstyle) {
12963 /* We must read until the closing backquote, giving special
12964 * treatment to some slashes, and then push the string and
12965 * reread it as input, interpreting it normally.
12966 */
12967 char *pout;
12968 size_t psavelen;
12969 char *pstr;
12970
12971 STARTSTACKSTR(pout);
12972 for (;;) {
12973 int pc;
12974
12975 setprompt_if(needprompt, 2);
12976 pc = pgetc_eatbnl();
12977 switch (pc) {
12978 case '`':
12979 goto done;
12980
12981 case '\\':
12982 pc = pgetc(); /* not pgetc_eatbnl! */
12983 if (pc != '\\' && pc != '`' && pc != '$'
12984 && (!synstack->dblquote || pc != '"')
12985 ) {
12986 STPUTC('\\', pout);
12987 }
12988 break;
12989
12990 case PEOF:
12991 raise_error_syntax("EOF in backquote substitution");
12992
12993 case '\n':
12994 nlnoprompt();
12995 break;
12996
12997 default:
12998 break;
12999 }
13000 STPUTC(pc, pout);
13001 }
13002 done:
13003 STPUTC('\0', pout);
13004 psavelen = pout - (char *)stackblock();
13005 if (psavelen > 0) {
13006 pstr = grabstackstr(pout);
13007 setinputstring(pstr);
13008 }
13009 }
13010 nlpp = &bqlist;
13011 while (*nlpp)
13012 nlpp = &(*nlpp)->next;
13013 *nlpp = stzalloc(sizeof(**nlpp));
13014 /* (*nlpp)->next = NULL; - stzalloc did it */
13015
13016 saveheredoclist = heredoclist;
13017 heredoclist = NULL;
13018
13019 if (oldstyle) {
13020 saveprompt = doprompt;
13021 doprompt = 0;
13022 }
13023
13024 n = list(2);
13025
13026 if (oldstyle)
13027 doprompt = saveprompt;
13028 else {
13029 if (readtoken() != TRP)
13030 raise_error_unexpected_syntax(TRP);
13031 setinputstring(nullstr);
13032 }
13033
13034 parseheredoc();
13035 heredoclist = saveheredoclist;
13036
13037 (*nlpp)->n = n;
13038 /* Start reading from old file again. */
13039 popfile();
13040 /* Ignore any pushed back tokens left from the backquote parsing. */
13041 if (oldstyle)
13042 tokpushback = 0;
13043 out = growstackto(savelen + 1);
13044 if (str) {
13045 memcpy(out, str, savelen);
13046 STADJUST(savelen, out);
13047 }
13048 #if BASH_PROCESS_SUBST
13049 if (style == PSUB)
13050 USTPUTC(c == '<' ? CTLFROMPROC : CTLTOPROC, out);
13051 else
13052 #endif
13053 USTPUTC(CTLBACKQ, out);
13054 if (oldstyle)
13055 goto parsebackq_oldreturn;
13056 #if BASH_PROCESS_SUBST
13057 else if (style == PSUB)
13058 goto parsebackq_psreturn;
13059 #endif
13060 goto parsebackq_newreturn;
13061 }
13062
13063 #if ENABLE_FEATURE_SH_MATH
13064 /*
13065 * Parse an arithmetic expansion (indicate start of one and set state)
13066 */
13067 parsearith: {
13068
13069 synstack_push(&synstack,
13070 synstack->prev ?: alloca(sizeof(*synstack)),
13071 ARISYNTAX);
13072 synstack->dblquote = 1;
13073 USTPUTC(CTLARI, out);
13074 goto parsearith_return;
13075 }
13076 #endif
13077 } /* end of readtoken */
13078
13079 /*
13080 * Read the next input token.
13081 * If the token is a word, we set backquotelist to the list of cmds in
13082 * backquotes. We set quoteflag to true if any part of the word was
13083 * quoted.
13084 * If the token is TREDIR, then we set redirnode to a structure containing
13085 * the redirection.
13086 *
13087 * [Change comment: here documents and internal procedures]
13088 * [Readtoken shouldn't have any arguments. Perhaps we should make the
13089 * word parsing code into a separate routine. In this case, readtoken
13090 * doesn't need to have any internal procedures, but parseword does.
13091 * We could also make parseoperator in essence the main routine, and
13092 * have parseword (readtoken1?) handle both words and redirection.]
13093 */
13094 #define NEW_xxreadtoken
13095 #ifdef NEW_xxreadtoken
13096 /* singles must be first! */
13097 static const char xxreadtoken_chars[7] ALIGN1 = {
13098 '\n', '(', ')', /* singles */
13099 '&', '|', ';', /* doubles */
13100 0
13101 };
13102
13103 #define xxreadtoken_singles 3
13104 #define xxreadtoken_doubles 3
13105
13106 static const char xxreadtoken_tokens[] ALIGN1 = {
13107 TNL, TLP, TRP, /* only single occurrence allowed */
13108 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
13109 TEOF, /* corresponds to trailing nul */
13110 TAND, TOR, TENDCASE /* if double occurrence */
13111 };
13112
13113 static int
xxreadtoken(void)13114 xxreadtoken(void)
13115 {
13116 int c;
13117
13118 if (tokpushback) {
13119 tokpushback = 0;
13120 return lasttoken;
13121 }
13122 setprompt_if(needprompt, 2);
13123 for (;;) { /* until token or start of word found */
13124 c = pgetc_eatbnl();
13125 if (c == ' ' || c == '\t')
13126 continue;
13127
13128 if (c == '#') {
13129 while ((c = pgetc()) != '\n' && c != PEOF)
13130 continue;
13131 pungetc();
13132 } else if (c == '\\') {
13133 break; /* return readtoken1(...) */
13134 } else {
13135 const char *p;
13136
13137 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
13138 if (c != PEOF) {
13139 if (c == '\n') {
13140 nlnoprompt();
13141 }
13142
13143 p = strchr(xxreadtoken_chars, c);
13144 if (p == NULL)
13145 break; /* return readtoken1(...) */
13146
13147 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
13148 int cc = pgetc_eatbnl();
13149 if (cc == c) { /* double occurrence? */
13150 p += xxreadtoken_doubles + 1;
13151 } else {
13152 pungetc();
13153 #if BASH_REDIR_OUTPUT
13154 if (c == '&' && cc == '>') /* &> */
13155 break; /* return readtoken1(...) */
13156 #endif
13157 }
13158 }
13159 }
13160 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
13161 return lasttoken;
13162 }
13163 } /* for (;;) */
13164
13165 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
13166 }
13167 #else /* old xxreadtoken */
13168 #define RETURN(token) return lasttoken = token
13169 static int
xxreadtoken(void)13170 xxreadtoken(void)
13171 {
13172 int c;
13173
13174 if (tokpushback) {
13175 tokpushback = 0;
13176 return lasttoken;
13177 }
13178 setprompt_if(needprompt, 2);
13179 for (;;) { /* until token or start of word found */
13180 c = pgetc_eatbnl();
13181 switch (c) {
13182 case ' ': case '\t':
13183 continue;
13184 case '#':
13185 while ((c = pgetc()) != '\n' && c != PEOF)
13186 continue;
13187 pungetc();
13188 continue;
13189 case '\n':
13190 nlnoprompt();
13191 RETURN(TNL);
13192 case PEOF:
13193 RETURN(TEOF);
13194 case '&':
13195 if (pgetc_eatbnl() == '&')
13196 RETURN(TAND);
13197 pungetc();
13198 RETURN(TBACKGND);
13199 case '|':
13200 if (pgetc_eatbnl() == '|')
13201 RETURN(TOR);
13202 pungetc();
13203 RETURN(TPIPE);
13204 case ';':
13205 if (pgetc_eatbnl() == ';')
13206 RETURN(TENDCASE);
13207 pungetc();
13208 RETURN(TSEMI);
13209 case '(':
13210 RETURN(TLP);
13211 case ')':
13212 RETURN(TRP);
13213 }
13214 break;
13215 }
13216 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
13217 #undef RETURN
13218 }
13219 #endif /* old xxreadtoken */
13220
13221 static int
readtoken(void)13222 readtoken(void)
13223 {
13224 int t;
13225 int kwd = checkkwd;
13226 #if DEBUG
13227 smallint alreadyseen = tokpushback;
13228 #endif
13229
13230 #if ENABLE_ASH_ALIAS
13231 top:
13232 #endif
13233
13234 t = xxreadtoken();
13235
13236 /*
13237 * eat newlines
13238 */
13239 if (kwd & CHKNL) {
13240 while (t == TNL) {
13241 parseheredoc();
13242 checkkwd = 0;
13243 t = xxreadtoken();
13244 }
13245 }
13246
13247 kwd |= checkkwd;
13248 checkkwd = 0;
13249
13250 if (t != TWORD || quoteflag) {
13251 goto out;
13252 }
13253
13254 /*
13255 * check for keywords
13256 */
13257 if (kwd & CHKKWD) {
13258 const char *const *pp;
13259
13260 pp = findkwd(wordtext);
13261 if (pp) {
13262 lasttoken = t = pp - tokname_array;
13263 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
13264 goto out;
13265 }
13266 }
13267
13268 if (kwd & CHKALIAS) {
13269 #if ENABLE_ASH_ALIAS
13270 struct alias *ap;
13271 ap = lookupalias(wordtext, 1);
13272 if (ap != NULL) {
13273 if (*ap->val) {
13274 pushstring(ap->val, ap);
13275 }
13276 goto top;
13277 }
13278 #endif
13279 }
13280 out:
13281 #if DEBUG
13282 if (!alreadyseen)
13283 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13284 else
13285 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
13286 #endif
13287 return t;
13288 }
13289
13290 /*
13291 * Read and parse a command. Returns NODE_EOF on end of file.
13292 * (NULL is a valid parse tree indicating a blank line.)
13293 */
13294 static union node *
parsecmd(int interact)13295 parsecmd(int interact)
13296 {
13297 tokpushback = 0;
13298 checkkwd = 0;
13299 heredoclist = 0;
13300 doprompt = interact;
13301 setprompt_if(doprompt, doprompt);
13302 needprompt = 0;
13303 return list(1);
13304 }
13305
13306 /*
13307 * Input any here documents.
13308 */
13309 static void
parseheredoc(void)13310 parseheredoc(void)
13311 {
13312 struct heredoc *here;
13313 union node *n;
13314
13315 here = heredoclist;
13316 heredoclist = NULL;
13317
13318 while (here) {
13319 tokpushback = 0;
13320 setprompt_if(needprompt, 2);
13321 if (here->here->type == NHERE)
13322 readtoken1(pgetc(), SQSYNTAX, here->eofmark, here->striptabs);
13323 else
13324 readtoken1(pgetc_eatbnl(), DQSYNTAX, here->eofmark, here->striptabs);
13325 n = stzalloc(sizeof(struct narg));
13326 n->narg.type = NARG;
13327 /*n->narg.next = NULL; - stzalloc did it */
13328 n->narg.text = wordtext;
13329 n->narg.backquote = backquotelist;
13330 here->here->nhere.doc = n;
13331 here = here->next;
13332 }
13333 }
13334
13335
13336 static const char *
expandstr(const char * ps,int syntax_type)13337 expandstr(const char *ps, int syntax_type)
13338 {
13339 struct parsefile *file_stop;
13340 struct jmploc *volatile savehandler;
13341 struct heredoc *saveheredoclist;
13342 const char *result;
13343 int saveprompt;
13344 struct jmploc jmploc;
13345 union node n;
13346 int err;
13347
13348 file_stop = g_parsefile;
13349
13350 /* XXX Fix (char *) cast. */
13351 setinputstring((char *)ps);
13352
13353 saveheredoclist = heredoclist;
13354 heredoclist = NULL;
13355 saveprompt = doprompt;
13356 doprompt = 0;
13357 result = ps;
13358 savehandler = exception_handler;
13359 err = setjmp(jmploc.loc);
13360 if (err)
13361 goto out;
13362
13363 /* readtoken1() might die horribly.
13364 * Try a prompt with syntactically wrong command:
13365 * PS1='$(date "+%H:%M:%S) > '
13366 */
13367 exception_handler = &jmploc;
13368 readtoken1(pgetc_eatbnl(), syntax_type, FAKEEOFMARK, 0);
13369
13370 n.narg.type = NARG;
13371 n.narg.next = NULL;
13372 n.narg.text = wordtext;
13373 n.narg.backquote = backquotelist;
13374
13375 /* expandarg() might fail too:
13376 * PS1='$((123+))'
13377 */
13378 expandarg(&n, NULL, EXP_QUOTED);
13379 result = stackblock();
13380
13381 out:
13382 exception_handler = savehandler;
13383 if (err && exception_type != EXERROR)
13384 longjmp(exception_handler->loc, 1);
13385
13386 doprompt = saveprompt;
13387 /* Try: PS1='`xxx(`' */
13388 unwindfiles(file_stop);
13389 heredoclist = saveheredoclist;
13390
13391 return result;
13392 }
13393
13394 static inline int
parser_eof(void)13395 parser_eof(void)
13396 {
13397 return tokpushback && lasttoken == TEOF;
13398 }
13399
13400 /*
13401 * Execute a command or commands contained in a string.
13402 */
13403 static int
evalstring(char * s,int flags)13404 evalstring(char *s, int flags)
13405 {
13406 struct jmploc *volatile savehandler;
13407 struct jmploc jmploc;
13408 int ex;
13409
13410 union node *n;
13411 struct stackmark smark;
13412 int status;
13413
13414 s = sstrdup(s);
13415 setinputstring(s);
13416 setstackmark(&smark);
13417
13418 status = 0;
13419 /* On exception inside execution loop, we must popfile().
13420 * Try interactively:
13421 * readonly a=a
13422 * command eval "a=b" # throws "is read only" error
13423 * "command BLTIN" is not supposed to abort (even in non-interactive use).
13424 * But if we skip popfile(), we hit EOF in eval's string, and exit.
13425 */
13426 savehandler = exception_handler;
13427 ex = setjmp(jmploc.loc);
13428 if (ex)
13429 goto out;
13430 exception_handler = &jmploc;
13431
13432 while ((n = parsecmd(0)) != NODE_EOF) {
13433 int i;
13434
13435 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
13436 if (n)
13437 status = i;
13438 popstackmark(&smark);
13439 if (evalskip)
13440 break;
13441 }
13442 out:
13443 popstackmark(&smark);
13444 popfile();
13445 stunalloc(s);
13446
13447 exception_handler = savehandler;
13448 if (ex)
13449 longjmp(exception_handler->loc, ex);
13450
13451 return status;
13452 }
13453
13454 /*
13455 * The eval command.
13456 */
13457 static int FAST_FUNC
evalcmd(int argc UNUSED_PARAM,char ** argv,int flags)13458 evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
13459 {
13460 char *p;
13461 char *concat;
13462
13463 if (argv[1]) {
13464 p = argv[1];
13465 argv += 2;
13466 if (argv[0]) {
13467 STARTSTACKSTR(concat);
13468 for (;;) {
13469 concat = stack_putstr(p, concat);
13470 p = *argv++;
13471 if (p == NULL)
13472 break;
13473 STPUTC(' ', concat);
13474 }
13475 STPUTC('\0', concat);
13476 p = grabstackstr(concat);
13477 }
13478 return evalstring(p, flags & EV_TESTED);
13479 }
13480 return 0;
13481 }
13482
13483 /*
13484 * Read and execute commands.
13485 * "Top" is nonzero for the top level command loop;
13486 * it turns on prompting if the shell is interactive.
13487 */
13488 static int
cmdloop(int top)13489 cmdloop(int top)
13490 {
13491 union node *n;
13492 struct stackmark smark;
13493 int inter;
13494 int status = 0;
13495 int numeof = 0;
13496
13497 TRACE(("cmdloop(%d) called\n", top));
13498 for (;;) {
13499 int skip;
13500
13501 setstackmark(&smark);
13502 #if JOBS
13503 if (doing_jobctl)
13504 showjobs(SHOW_CHANGED|SHOW_STDERR);
13505 #endif
13506 inter = 0;
13507 if (iflag && top) {
13508 inter++;
13509 chkmail();
13510 }
13511 n = parsecmd(inter);
13512 #if DEBUG
13513 if (DEBUG > 2 && debug && (n != NODE_EOF))
13514 showtree(n);
13515 #endif
13516 if (n == NODE_EOF) {
13517 if (!top || numeof >= 50)
13518 break;
13519 if (!stoppedjobs()) {
13520 if (!iflag)
13521 break;
13522 if (!Iflag) {
13523 newline_and_flush(stderr);
13524 break;
13525 }
13526 /* "set -o ignoreeof" active, do not exit command loop on ^D */
13527 out2str("\nUse \"exit\" to leave shell.\n");
13528 }
13529 numeof++;
13530 } else {
13531 int i;
13532
13533 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13534 job_warning >>= 1;
13535 numeof = 0;
13536 i = evaltree(n, 0);
13537 if (n)
13538 status = i;
13539 }
13540 popstackmark(&smark);
13541 skip = evalskip;
13542
13543 if (skip) {
13544 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
13545 break;
13546 }
13547 }
13548 return status;
13549 }
13550
13551 /*
13552 * Take commands from a file. To be compatible we should do a path
13553 * search for the file, which is necessary to find sub-commands.
13554 */
13555 static char *
find_dot_file(char * basename)13556 find_dot_file(char *basename)
13557 {
13558 char *fullname;
13559 const char *path = pathval();
13560 struct stat statb;
13561 int len;
13562
13563 /* don't try this for absolute or relative paths */
13564 if (strchr(basename, '/'))
13565 return basename;
13566
13567 while ((len = padvance(&path, basename)) >= 0) {
13568 fullname = stackblock();
13569 if ((!pathopt || *pathopt == 'f')
13570 && !stat(fullname, &statb) && S_ISREG(statb.st_mode)
13571 ) {
13572 /* This will be freed by the caller. */
13573 return stalloc(len);
13574 }
13575 }
13576 /* not found in PATH */
13577
13578 #if ENABLE_ASH_BASH_SOURCE_CURDIR
13579 return basename;
13580 #else
13581 ash_msg_and_raise_error("%s: not found", basename);
13582 /* NOTREACHED */
13583 #endif
13584 }
13585
13586 static int FAST_FUNC
dotcmd(int argc_ UNUSED_PARAM,char ** argv_ UNUSED_PARAM)13587 dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
13588 {
13589 /* "false; . empty_file; echo $?" should print 0, not 1: */
13590 int status = 0;
13591 char *fullname;
13592 char **argv;
13593 char *args_need_save;
13594 volatile struct shparam saveparam;
13595
13596 //???
13597 // struct strlist *sp;
13598 // for (sp = cmdenviron; sp; sp = sp->next)
13599 // setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
13600
13601 nextopt(nullstr); /* handle possible "--" */
13602 argv = argptr;
13603
13604 if (!argv[0]) {
13605 /* bash says: "bash: .: filename argument required" */
13606 return 2; /* bash compat */
13607 }
13608
13609 /* This aborts if file isn't found, which is POSIXly correct.
13610 * bash returns exitcode 1 instead.
13611 */
13612 fullname = find_dot_file(argv[0]);
13613 argv++;
13614 args_need_save = argv[0];
13615 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
13616 int argc;
13617 saveparam = shellparam;
13618 shellparam.malloced = 0;
13619 argc = 1;
13620 while (argv[argc])
13621 argc++;
13622 shellparam.nparam = argc;
13623 shellparam.p = argv;
13624 };
13625
13626 /* This aborts if file can't be opened, which is POSIXly correct.
13627 * bash returns exitcode 1 instead.
13628 */
13629 setinputfile(fullname, INPUT_PUSH_FILE);
13630 commandname = fullname;
13631 status = cmdloop(0);
13632 popfile();
13633
13634 if (args_need_save) {
13635 freeparam(&shellparam);
13636 shellparam = saveparam;
13637 };
13638
13639 return status;
13640 }
13641
13642 static int FAST_FUNC
exitcmd(int argc UNUSED_PARAM,char ** argv)13643 exitcmd(int argc UNUSED_PARAM, char **argv)
13644 {
13645 if (stoppedjobs())
13646 return 0;
13647
13648 if (argv[1])
13649 savestatus = number(argv[1]);
13650
13651 //TODO: this script
13652 // trap 'echo trap:$FUNCNAME' EXIT
13653 // f() { exit; }
13654 // f
13655 //prints "trap:f" in bash. We can call exitshell() here to achieve this.
13656 //For now, keeping dash code:
13657 raise_exception(EXEXIT);
13658 /* NOTREACHED */
13659 }
13660
13661 /*
13662 * Read a file containing shell functions.
13663 */
13664 static void
readcmdfile(char * name)13665 readcmdfile(char *name)
13666 {
13667 setinputfile(name, INPUT_PUSH_FILE);
13668 cmdloop(0);
13669 popfile();
13670 }
13671
13672
13673 /* ============ find_command inplementation */
13674
13675 /*
13676 * Resolve a command name. If you change this routine, you may have to
13677 * change the shellexec routine as well.
13678 */
13679 static void
find_command(char * name,struct cmdentry * entry,int act,const char * path)13680 find_command(char *name, struct cmdentry *entry, int act, const char *path)
13681 {
13682 struct tblentry *cmdp;
13683 int idx;
13684 int prev;
13685 char *fullname;
13686 struct stat statb;
13687 int e;
13688 int updatetbl;
13689 struct builtincmd *bcmd;
13690 int len;
13691
13692 /* If name contains a slash, don't use PATH or hash table */
13693 if (strchr(name, '/') != NULL) {
13694 entry->u.index = -1;
13695 if (act & DO_ABS) {
13696 while (stat(name, &statb) < 0) {
13697 #ifdef SYSV
13698 if (errno == EINTR)
13699 continue;
13700 #endif
13701 entry->cmdtype = CMDUNKNOWN;
13702 return;
13703 }
13704 }
13705 entry->cmdtype = CMDNORMAL;
13706 return;
13707 }
13708
13709 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
13710
13711 updatetbl = (path == pathval());
13712 if (!updatetbl)
13713 act |= DO_ALTPATH;
13714
13715 /* If name is in the table, check answer will be ok */
13716 cmdp = cmdlookup(name, 0);
13717 if (cmdp != NULL) {
13718 int bit;
13719
13720 switch (cmdp->cmdtype) {
13721 default:
13722 #if DEBUG
13723 abort();
13724 #endif
13725 case CMDNORMAL:
13726 bit = DO_ALTPATH | DO_REGBLTIN;
13727 break;
13728 case CMDFUNCTION:
13729 bit = DO_NOFUNC;
13730 break;
13731 case CMDBUILTIN:
13732 bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
13733 break;
13734 }
13735 if (act & bit) {
13736 if (act & bit & DO_REGBLTIN)
13737 goto fail;
13738
13739 updatetbl = 0;
13740 cmdp = NULL;
13741 } else if (cmdp->rehash == 0)
13742 /* if not invalidated by cd, we're done */
13743 goto success;
13744 }
13745
13746 /* If %builtin not in path, check for builtin next */
13747 bcmd = find_builtin(name);
13748 if (bcmd) {
13749 if (IS_BUILTIN_REGULAR(bcmd))
13750 goto builtin_success;
13751 if (act & DO_ALTPATH)
13752 goto builtin_success;
13753 if (builtinloc <= 0)
13754 goto builtin_success;
13755 }
13756
13757 if (act & DO_REGBLTIN)
13758 goto fail;
13759
13760 #if ENABLE_FEATURE_SH_STANDALONE
13761 {
13762 int applet_no = find_applet_by_name(name);
13763 if (applet_no >= 0) {
13764 entry->cmdtype = CMDNORMAL;
13765 entry->u.index = -2 - applet_no;
13766 return;
13767 }
13768 }
13769 #endif
13770
13771 /* We have to search path. */
13772 prev = -1; /* where to start */
13773 if (cmdp && cmdp->rehash) { /* doing a rehash */
13774 if (cmdp->cmdtype == CMDBUILTIN)
13775 prev = builtinloc;
13776 else
13777 prev = cmdp->param.index;
13778 }
13779
13780 e = ENOENT;
13781 idx = -1;
13782 loop:
13783 while ((len = padvance(&path, name)) >= 0) {
13784 const char *lpathopt = pathopt;
13785
13786 fullname = stackblock();
13787 idx++;
13788 if (lpathopt) {
13789 if (*lpathopt == 'b') {
13790 if (bcmd)
13791 goto builtin_success;
13792 continue;
13793 } else if (!(act & DO_NOFUNC)) {
13794 /* handled below */
13795 } else {
13796 /* ignore unimplemented options */
13797 continue;
13798 }
13799 }
13800 /* if rehash, don't redo absolute path names */
13801 if (fullname[0] == '/' && idx <= prev) {
13802 if (idx < prev)
13803 continue;
13804 TRACE(("searchexec \"%s\": no change\n", name));
13805 goto success;
13806 }
13807 while (stat(fullname, &statb) < 0) {
13808 #ifdef SYSV
13809 if (errno == EINTR)
13810 continue;
13811 #endif
13812 if (errno != ENOENT && errno != ENOTDIR)
13813 e = errno;
13814 goto loop;
13815 }
13816 e = EACCES; /* if we fail, this will be the error */
13817 if (!S_ISREG(statb.st_mode))
13818 continue;
13819 if (lpathopt) { /* this is a %func directory */
13820 stalloc(len);
13821 /* NB: stalloc will return space pointed by fullname
13822 * (because we don't have any intervening allocations
13823 * between stunalloc above and this stalloc) */
13824 readcmdfile(fullname);
13825 cmdp = cmdlookup(name, 0);
13826 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13827 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13828 stunalloc(fullname);
13829 goto success;
13830 }
13831 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13832 if (!updatetbl) {
13833 entry->cmdtype = CMDNORMAL;
13834 entry->u.index = idx;
13835 return;
13836 }
13837 INT_OFF;
13838 cmdp = cmdlookup(name, 1);
13839 cmdp->cmdtype = CMDNORMAL;
13840 cmdp->param.index = idx;
13841 INT_ON;
13842 goto success;
13843 }
13844
13845 /* We failed. If there was an entry for this command, delete it */
13846 if (cmdp && updatetbl)
13847 delete_cmd_entry();
13848 if (act & DO_ERR) {
13849 #if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13850 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13851 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13852 char *argv[3];
13853 argv[0] = (char*) "command_not_found_handle";
13854 argv[1] = name;
13855 argv[2] = NULL;
13856 evalfun(hookp->param.func, 2, argv, 0);
13857 entry->cmdtype = CMDUNKNOWN;
13858 return;
13859 }
13860 #endif
13861 ash_msg("%s: %s", name, errmsg(e, "not found"));
13862 }
13863 fail:
13864 entry->cmdtype = CMDUNKNOWN;
13865 return;
13866
13867 builtin_success:
13868 if (!updatetbl) {
13869 entry->cmdtype = CMDBUILTIN;
13870 entry->u.cmd = bcmd;
13871 return;
13872 }
13873 INT_OFF;
13874 cmdp = cmdlookup(name, 1);
13875 cmdp->cmdtype = CMDBUILTIN;
13876 cmdp->param.cmd = bcmd;
13877 INT_ON;
13878 success:
13879 cmdp->rehash = 0;
13880 entry->cmdtype = cmdp->cmdtype;
13881 entry->u = cmdp->param;
13882 }
13883
13884
13885 /*
13886 * The trap builtin.
13887 */
13888 static int FAST_FUNC
trapcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)13889 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13890 {
13891 char *action;
13892 char **ap;
13893 int signo, exitcode;
13894
13895 nextopt(nullstr);
13896 ap = argptr;
13897 if (!*ap) {
13898 for (signo = 0; signo <= NTRAP_LAST; signo++) {
13899 char *tr = trap_ptr[signo];
13900 if (tr) {
13901 /* note: bash adds "SIG", but only if invoked
13902 * as "bash". If called as "sh", or if set -o posix,
13903 * then it prints short signal names.
13904 * We are printing short names: */
13905 out1fmt("trap -- %s %s\n",
13906 single_quote(tr),
13907 (signo == NTRAP_ERR) ? "ERR" : get_signame(signo));
13908 /* trap_ptr != trap only if we are in special-cased `trap` code.
13909 * In this case, we will exit very soon, no need to free(). */
13910 /* if (trap_ptr != trap && tp[0]) */
13911 /* free(tr); */
13912 }
13913 }
13914 /*
13915 if (trap_ptr != trap) {
13916 free(trap_ptr);
13917 trap_ptr = trap;
13918 }
13919 */
13920 return 0;
13921 }
13922
13923 /* Why the second check?
13924 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13925 * In this case, NUM is signal no, not an action.
13926 */
13927 action = NULL;
13928 if (ap[1] && !is_number(ap[0]))
13929 action = *ap++;
13930
13931 exitcode = 0;
13932 while (*ap) {
13933 signo = strcmp(*ap, "ERR") == 0 ? NTRAP_ERR : get_signum(*ap);
13934 if (signo < 0) {
13935 /* Mimic bash message exactly */
13936 ash_msg("%s: invalid signal specification", *ap);
13937 exitcode = 1;
13938 goto next;
13939 }
13940 INT_OFF;
13941 if (action) {
13942 if (LONE_DASH(action))
13943 action = NULL;
13944 else {
13945 if (action[0]) /* not NULL and not "" and not "-" */
13946 may_have_traps = 1;
13947 action = ckstrdup(action);
13948 }
13949 }
13950 free(trap[signo]);
13951 trap[signo] = action;
13952 if (signo != 0 && signo < NSIG)
13953 setsignal(signo);
13954 INT_ON;
13955 next:
13956 ap++;
13957 }
13958 return exitcode;
13959 }
13960
13961
13962 /* ============ Builtins */
13963
13964 #if ENABLE_ASH_HELP
13965 static int FAST_FUNC
helpcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)13966 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13967 {
13968 unsigned col;
13969 unsigned i;
13970
13971 out1fmt(
13972 "Built-in commands:\n"
13973 "------------------\n");
13974 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
13975 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
13976 builtintab[i].name + 1);
13977 if (col > 60) {
13978 out1fmt("\n");
13979 col = 0;
13980 }
13981 }
13982 # if ENABLE_FEATURE_SH_STANDALONE
13983 {
13984 const char *a = applet_names;
13985 while (*a) {
13986 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13987 if (col > 60) {
13988 out1fmt("\n");
13989 col = 0;
13990 }
13991 while (*a++ != '\0')
13992 continue;
13993 }
13994 }
13995 # endif
13996 newline_and_flush(stdout);
13997 return EXIT_SUCCESS;
13998 }
13999 #endif
14000
14001 #if MAX_HISTORY
14002 static int FAST_FUNC
historycmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)14003 historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14004 {
14005 show_history(line_input_state);
14006 return EXIT_SUCCESS;
14007 }
14008 #endif
14009
14010 /*
14011 * The export and readonly commands.
14012 */
14013 static int FAST_FUNC
exportcmd(int argc UNUSED_PARAM,char ** argv)14014 exportcmd(int argc UNUSED_PARAM, char **argv)
14015 {
14016 struct var *vp;
14017 char *name;
14018 const char *p;
14019 char **aptr;
14020 char opt;
14021 int flag;
14022 int flag_off;
14023
14024 /* "readonly" in bash accepts, but ignores -n.
14025 * We do the same: it saves a conditional in nextopt's param.
14026 */
14027 flag_off = 0;
14028 while ((opt = nextopt("np")) != '\0') {
14029 if (opt == 'n')
14030 flag_off = VEXPORT;
14031 }
14032 flag = VEXPORT;
14033 if (argv[0][0] == 'r') {
14034 flag = VREADONLY;
14035 flag_off = 0; /* readonly ignores -n */
14036 }
14037 flag_off = ~flag_off;
14038
14039 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
14040 {
14041 aptr = argptr;
14042 name = *aptr;
14043 if (name) {
14044 do {
14045 p = strchr(name, '=');
14046 if (p != NULL) {
14047 p++;
14048 } else {
14049 vp = *findvar(hashvar(name), name);
14050 if (vp) {
14051 vp->flags = ((vp->flags | flag) & flag_off);
14052 continue;
14053 }
14054 }
14055 setvar(name, p, (flag & flag_off));
14056 } while ((name = *++aptr) != NULL);
14057 return 0;
14058 }
14059 }
14060
14061 /* No arguments. Show the list of exported or readonly vars.
14062 * -n is ignored.
14063 */
14064 showvars(argv[0], flag, 0);
14065 return 0;
14066 }
14067
14068 /*
14069 * Delete a function if it exists.
14070 */
14071 static void
unsetfunc(const char * name)14072 unsetfunc(const char *name)
14073 {
14074 struct tblentry *cmdp;
14075
14076 cmdp = cmdlookup(name, 0);
14077 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
14078 delete_cmd_entry();
14079 }
14080
14081 /*
14082 * The unset builtin command. We unset the function before we unset the
14083 * variable to allow a function to be unset when there is a readonly variable
14084 * with the same name.
14085 */
14086 static int FAST_FUNC
unsetcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)14087 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14088 {
14089 char **ap;
14090 int i;
14091 int flag = 0;
14092
14093 while ((i = nextopt("vf")) != 0) {
14094 flag = i;
14095 }
14096
14097 for (ap = argptr; *ap; ap++) {
14098 if (flag != 'f') {
14099 unsetvar(*ap);
14100 continue;
14101 }
14102 if (flag != 'v')
14103 unsetfunc(*ap);
14104 }
14105 return 0;
14106 }
14107
14108 static const unsigned char timescmd_str[] ALIGN1 = {
14109 ' ', offsetof(struct tms, tms_utime),
14110 '\n', offsetof(struct tms, tms_stime),
14111 ' ', offsetof(struct tms, tms_cutime),
14112 '\n', offsetof(struct tms, tms_cstime),
14113 0
14114 };
14115 static int FAST_FUNC
timescmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)14116 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14117 {
14118 unsigned clk_tck;
14119 const unsigned char *p;
14120 struct tms buf;
14121
14122 clk_tck = bb_clk_tck();
14123
14124 times(&buf);
14125 p = timescmd_str;
14126 do {
14127 unsigned sec, frac;
14128 unsigned long t;
14129 t = *(clock_t *)(((char *) &buf) + p[1]);
14130 sec = t / clk_tck;
14131 frac = t % clk_tck;
14132 out1fmt("%um%u.%03us%c",
14133 sec / 60, sec % 60,
14134 (frac * 1000) / clk_tck,
14135 p[0]);
14136 p += 2;
14137 } while (*p);
14138
14139 return 0;
14140 }
14141
14142 #if ENABLE_FEATURE_SH_MATH
14143 /*
14144 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
14145 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
14146 *
14147 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
14148 */
14149 static int FAST_FUNC
letcmd(int argc UNUSED_PARAM,char ** argv)14150 letcmd(int argc UNUSED_PARAM, char **argv)
14151 {
14152 arith_t i;
14153
14154 argv++;
14155 if (!*argv)
14156 ash_msg_and_raise_error("expression expected");
14157 do {
14158 i = ash_arith(*argv);
14159 } while (*++argv);
14160
14161 return !i;
14162 }
14163 #endif
14164
14165 /*
14166 * The read builtin. Options:
14167 * -r Do not interpret '\' specially
14168 * -s Turn off echo (tty only)
14169 * -n NCHARS Read NCHARS max
14170 * -p PROMPT Display PROMPT on stderr (if input is from tty)
14171 * -t SECONDS Timeout after SECONDS (tty or pipe only)
14172 * -u FD Read from given FD instead of fd 0
14173 * -d DELIM End on DELIM char, not newline
14174 * This uses unbuffered input, which may be avoidable in some cases.
14175 * TODO: bash also has:
14176 * -a ARRAY Read into array[0],[1],etc
14177 * -e Use line editing (tty only)
14178 */
14179 static int FAST_FUNC
readcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)14180 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14181 {
14182 struct builtin_read_params params;
14183 const char *r;
14184 int i;
14185
14186 memset(¶ms, 0, sizeof(params));
14187
14188 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
14189 switch (i) {
14190 case 'p':
14191 params.opt_p = optionarg;
14192 break;
14193 case 'n':
14194 params.opt_n = optionarg;
14195 break;
14196 case 's':
14197 params.read_flags |= BUILTIN_READ_SILENT;
14198 break;
14199 case 't':
14200 params.opt_t = optionarg;
14201 break;
14202 case 'r':
14203 params.read_flags |= BUILTIN_READ_RAW;
14204 break;
14205 case 'u':
14206 params.opt_u = optionarg;
14207 break;
14208 #if BASH_READ_D
14209 case 'd':
14210 params.opt_d = optionarg;
14211 break;
14212 #endif
14213 default:
14214 break;
14215 }
14216 }
14217
14218 if (!ENABLE_ASH_BASH_COMPAT && !argptr) {
14219 bb_simple_error_msg("read: need variable name");
14220 return 1;
14221 }
14222 params.argv = argptr;
14223 params.setvar = setvar0;
14224 params.ifs = bltinlookup("IFS"); /* can be NULL */
14225
14226 /* "read -s" needs to save/restore termios, can't allow ^C
14227 * to jump out of it.
14228 */
14229 again:
14230 INT_OFF;
14231 r = shell_builtin_read(¶ms);
14232 INT_ON;
14233
14234 if ((uintptr_t)r == 1 && errno == EINTR) {
14235 /* To get SIGCHLD: sleep 1 & read x; echo $x
14236 * Correct behavior is to not exit "read"
14237 */
14238 if (pending_sig == 0)
14239 goto again;
14240 }
14241
14242 if ((uintptr_t)r > 1)
14243 ash_msg_and_raise_error(r);
14244
14245 return (uintptr_t)r;
14246 }
14247
14248 static int FAST_FUNC
umaskcmd(int argc UNUSED_PARAM,char ** argv UNUSED_PARAM)14249 umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
14250 {
14251 static const char permuser[3] ALIGN1 = "ogu";
14252
14253 mode_t mask;
14254 int symbolic_mode = 0;
14255
14256 while (nextopt("S") != '\0') {
14257 symbolic_mode = 1;
14258 }
14259
14260 INT_OFF;
14261 mask = umask(0);
14262 umask(mask);
14263 INT_ON;
14264
14265 if (*argptr == NULL) {
14266 if (symbolic_mode) {
14267 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
14268 char *p = buf;
14269 int i;
14270
14271 i = 2;
14272 for (;;) {
14273 *p++ = ',';
14274 *p++ = permuser[i];
14275 *p++ = '=';
14276 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
14277 if (!(mask & 0400)) *p++ = 'r';
14278 if (!(mask & 0200)) *p++ = 'w';
14279 if (!(mask & 0100)) *p++ = 'x';
14280 mask <<= 3;
14281 if (--i < 0)
14282 break;
14283 }
14284 *p = '\0';
14285 puts(buf + 1);
14286 } else {
14287 out1fmt("%04o\n", mask);
14288 }
14289 } else {
14290 char *modestr = *argptr;
14291 /* numeric umasks are taken as-is */
14292 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
14293 if (!isdigit(modestr[0]))
14294 mask ^= 0777;
14295 mask = bb_parse_mode(modestr, mask);
14296 if ((unsigned)mask > 0777) {
14297 ash_msg_and_raise_error("illegal mode: %s", modestr);
14298 }
14299 if (!isdigit(modestr[0]))
14300 mask ^= 0777;
14301 umask(mask);
14302 }
14303 return 0;
14304 }
14305
14306 static int FAST_FUNC
ulimitcmd(int argc UNUSED_PARAM,char ** argv)14307 ulimitcmd(int argc UNUSED_PARAM, char **argv)
14308 {
14309 return shell_builtin_ulimit(argv);
14310 }
14311
14312 /* ============ main() and helpers */
14313
14314 /*
14315 * This routine is called when an error or an interrupt occurs in an
14316 * interactive shell and control is returned to the main command loop
14317 * but prior to exitshell.
14318 */
14319 static void
exitreset(void)14320 exitreset(void)
14321 {
14322 /* from eval.c: */
14323 if (savestatus >= 0) {
14324 if (exception_type == EXEXIT || evalskip == SKIPFUNCDEF)
14325 exitstatus = savestatus;
14326 savestatus = -1;
14327 }
14328 evalskip = 0;
14329 loopnest = 0;
14330 inps4 = 0;
14331
14332 /* from expand.c: */
14333 ifsfree();
14334
14335 /* from redir.c: */
14336 unwindredir(NULL);
14337 }
14338
14339 /*
14340 * This routine is called when an error or an interrupt occurs in an
14341 * interactive shell and control is returned to the main command loop.
14342 * (In dash, this function is auto-generated by build machinery).
14343 */
14344 static void
reset(void)14345 reset(void)
14346 {
14347 /* from input.c: */
14348 g_parsefile->left_in_buffer = 0;
14349 g_parsefile->left_in_line = 0; /* clear input buffer */
14350 g_parsefile->unget = 0;
14351 popallfiles();
14352
14353 /* from var.c: */
14354 unwindlocalvars(NULL);
14355 }
14356
14357 /*
14358 * Called to exit the shell.
14359 */
14360 static void
exitshell(void)14361 exitshell(void)
14362 {
14363 struct jmploc loc;
14364 char *p;
14365
14366 #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
14367 save_history(line_input_state); /* may be NULL */
14368 #endif
14369 savestatus = exitstatus;
14370 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
14371 if (setjmp(loc.loc))
14372 goto out;
14373 exception_handler = &loc;
14374 p = trap[0];
14375 if (p) {
14376 trap[0] = NULL;
14377 evalskip = 0;
14378 trap_depth++;
14379 evalstring(p, 0);
14380 trap_depth--;
14381 evalskip = SKIPFUNCDEF;
14382 /*free(p); - we'll exit soon */
14383 }
14384 out:
14385 exitreset();
14386 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14387 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
14388 */
14389 setjobctl(0);
14390 flush_stdout_stderr();
14391 _exit(exitstatus);
14392 /* NOTREACHED */
14393 }
14394
14395 /* Don't inline: conserve stack of caller from having our locals too */
14396 static NOINLINE void
init(void)14397 init(void)
14398 {
14399 /* we will never free this */
14400 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
14401 basepf.linno = 1;
14402
14403 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
14404 setsignal(SIGCHLD);
14405
14406 {
14407 char **envp;
14408 const char *p;
14409
14410 initvar();
14411 for (envp = environ; envp && *envp; envp++) {
14412 /* Used to have
14413 * p = endofname(*envp);
14414 * if (p != *envp && *p == '=') {
14415 * here to weed out badly-named variables, but this breaks
14416 * scenarios where people do want them passed to children:
14417 * import os
14418 * os.environ["test-test"]="test"
14419 * if os.fork() == 0:
14420 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
14421 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
14422 */
14423 if (strchr(*envp, '=')) {
14424 setvareq(*envp, VEXPORT|VTEXTFIXED);
14425 }
14426 }
14427
14428 setvareq((char*)defifsvar, VTEXTFIXED);
14429 setvareq((char*)defoptindvar, VTEXTFIXED);
14430
14431 setvar0("PPID", utoa(getppid()));
14432 #if BASH_SHLVL_VAR
14433 p = lookupvar("SHLVL");
14434 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
14435 #endif
14436 #if BASH_HOSTNAME_VAR
14437 if (!lookupvar("HOSTNAME")) {
14438 struct utsname uts;
14439 uname(&uts);
14440 setvar0("HOSTNAME", uts.nodename);
14441 }
14442 #endif
14443 p = lookupvar("PWD");
14444 if (p) {
14445 struct stat st1, st2;
14446 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
14447 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14448 ) {
14449 p = NULL;
14450 }
14451 }
14452 setpwd(p, 0);
14453 }
14454 }
14455
14456
14457 //usage:#define ash_trivial_usage
14458 //usage: "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]"
14459 //////// comes from ^^^^^^^^^^optletters
14460 //usage:#define ash_full_usage "\n\n"
14461 //usage: "Unix shell interpreter"
14462
14463 /*
14464 * Process the shell command line arguments.
14465 */
14466 static int
procargs(char ** argv)14467 procargs(char **argv)
14468 {
14469 int i;
14470 const char *xminusc;
14471 char **xargv;
14472 int login_sh;
14473
14474 xargv = argv;
14475 login_sh = xargv[0] && xargv[0][0] == '-';
14476 #if NUM_SCRIPTS > 0
14477 if (minusc)
14478 goto setarg0;
14479 #endif
14480 arg0 = xargv[0];
14481 /* if (xargv[0]) - mmm, this is always true! */
14482 xargv++;
14483 argptr = xargv;
14484 for (i = 0; i < NOPTS; i++)
14485 optlist[i] = 2;
14486 if (options(&login_sh)) {
14487 /* it already printed err message */
14488 raise_exception(EXERROR);
14489 }
14490 xargv = argptr;
14491 xminusc = minusc;
14492 if (*xargv == NULL) {
14493 if (xminusc)
14494 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14495 sflag = 1;
14496 }
14497 if (iflag == 2 /* no explicit -i given */
14498 && sflag == 1 /* -s given (or implied) */
14499 && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */
14500 && isatty(0) && isatty(1) /* we are on tty */
14501 ) {
14502 iflag = 1;
14503 }
14504 if (mflag == 2)
14505 mflag = iflag;
14506 /* Unset options which weren't explicitly set or unset */
14507 for (i = 0; i < NOPTS; i++)
14508 optlist[i] &= 1; /* same effect as "if (optlist[i] == 2) optlist[i] = 0;" */
14509 #if DEBUG == 2
14510 debug = 1;
14511 #endif
14512 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
14513 if (xminusc) {
14514 minusc = *xargv++;
14515 if (*xargv)
14516 goto setarg0;
14517 } else if (!sflag) {
14518 setinputfile(*xargv, 0);
14519 setarg0:
14520 arg0 = *xargv++;
14521 commandname = arg0;
14522 }
14523
14524 shellparam.p = xargv;
14525 #if ENABLE_ASH_GETOPTS
14526 shellparam.optind = 1;
14527 shellparam.optoff = -1;
14528 #endif
14529 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
14530 while (*xargv) {
14531 shellparam.nparam++;
14532 xargv++;
14533 }
14534
14535 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
14536 * Try:
14537 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
14538 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
14539 * NB: must do it before setting up signals (in optschanged())
14540 * and reading .profile etc (after we return from here):
14541 */
14542 if (iflag)
14543 signal(SIGHUP, SIG_DFL);
14544
14545 optschanged();
14546
14547 return login_sh;
14548 }
14549
14550 /*
14551 * Read /etc/profile, ~/.profile, $ENV.
14552 */
14553 static void
read_profile(const char * name)14554 read_profile(const char *name)
14555 {
14556 name = expandstr(name, DQSYNTAX);
14557 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14558 return;
14559 cmdloop(0);
14560 popfile();
14561 }
14562
14563 #if PROFILE
14564 static short profile_buf[16384];
14565 extern int etext();
14566 #endif
14567
14568 /*
14569 * Main routine. We initialize things, parse the arguments, execute
14570 * profiles if we're a login shell, and then call cmdloop to execute
14571 * commands. The setjmp call sets up the location to jump to when an
14572 * exception occurs. When an exception occurs the variable "state"
14573 * is used to figure out how far we had gotten.
14574 */
14575 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14576 #if NUM_SCRIPTS > 0
ash_main(int argc,char ** argv)14577 int ash_main(int argc, char **argv)
14578 #else
14579 int ash_main(int argc UNUSED_PARAM, char **argv)
14580 #endif
14581 /* note: 'argc' is used only if embedded scripts are enabled */
14582 {
14583 volatile smallint state;
14584 struct jmploc jmploc;
14585 struct stackmark smark;
14586 int login_sh;
14587
14588 /* Initialize global data */
14589 INIT_G_misc();
14590 INIT_G_memstack();
14591 INIT_G_var();
14592 #if ENABLE_ASH_ALIAS
14593 INIT_G_alias();
14594 #endif
14595 INIT_G_cmdtable();
14596
14597 #if PROFILE
14598 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14599 #endif
14600
14601 state = 0;
14602 if (setjmp(jmploc.loc)) {
14603 smallint e;
14604 smallint s;
14605
14606 exitreset();
14607
14608 e = exception_type;
14609 s = state;
14610 if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
14611 exitshell();
14612 }
14613
14614 reset();
14615
14616 if (e == EXINT) {
14617 newline_and_flush(stderr);
14618 }
14619
14620 popstackmark(&smark);
14621 FORCE_INT_ON; /* enable interrupts */
14622 if (s == 1)
14623 goto state1;
14624 if (s == 2)
14625 goto state2;
14626 if (s == 3)
14627 goto state3;
14628 goto state4;
14629 }
14630 exception_handler = &jmploc;
14631 rootpid = getpid();
14632
14633 init();
14634 setstackmark(&smark);
14635
14636 #if NUM_SCRIPTS > 0
14637 if (argc < 0)
14638 /* Non-NULL minusc tells procargs that an embedded script is being run */
14639 minusc = get_script_content(-argc - 1);
14640 #endif
14641 login_sh = procargs(argv);
14642 #if DEBUG
14643 TRACE(("Shell args: "));
14644 trace_puts_args(argv);
14645 #endif
14646
14647 if (login_sh) {
14648 const char *hp;
14649
14650 state = 1;
14651 read_profile("/etc/profile");
14652 state1:
14653 state = 2;
14654 hp = lookupvar("HOME");
14655 if (hp)
14656 read_profile("$HOME/.profile");
14657 }
14658 state2:
14659 state = 3;
14660 if (iflag
14661 #ifndef linux
14662 && getuid() == geteuid() && getgid() == getegid()
14663 #endif
14664 ) {
14665 const char *shinit = lookupvar("ENV");
14666 if (shinit != NULL && *shinit != '\0')
14667 read_profile(shinit);
14668 }
14669 popstackmark(&smark);
14670 state3:
14671 state = 4;
14672 if (minusc) {
14673 /* evalstring pushes parsefile stack.
14674 * Ensure we don't falsely claim that 0 (stdin)
14675 * is one of stacked source fds.
14676 * Testcase: ash -c 'exec 1>&0' must not complain. */
14677
14678 // if (!sflag) g_parsefile->pf_fd = -1;
14679 // ^^ not necessary since now we special-case fd 0
14680 // in save_fd_on_redirect()
14681
14682 lineno = 0; // bash compat
14683 // dash: evalstring(minusc, sflag ? 0 : EV_EXIT);
14684 // The above makes
14685 // ash -sc 'echo $-'
14686 // continue reading input from stdin after running 'echo'.
14687 // bash does not do this: it prints "hBcs" and exits.
14688 evalstring(minusc, EV_EXIT);
14689 }
14690
14691 if (sflag || minusc == NULL) {
14692 #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
14693 if (line_input_state) {
14694 const char *hp = lookupvar("HISTFILE");
14695 if (!hp) {
14696 hp = lookupvar("HOME");
14697 if (hp) {
14698 INT_OFF;
14699 hp = concat_path_file(hp, ".ash_history");
14700 setvar0("HISTFILE", hp);
14701 free((char*)hp);
14702 INT_ON;
14703 hp = lookupvar("HISTFILE");
14704 }
14705 }
14706 if (hp)
14707 line_input_state->hist_file = xstrdup(hp);
14708 # if ENABLE_FEATURE_SH_HISTFILESIZE
14709 hp = lookupvar("HISTFILESIZE");
14710 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14711 # endif
14712 }
14713 #endif
14714 state4: /* XXX ??? - why isn't this before the "if" statement */
14715 cmdloop(1);
14716 }
14717 #if PROFILE
14718 monitor(0);
14719 #endif
14720 #ifdef GPROF
14721 {
14722 extern void _mcleanup(void);
14723 _mcleanup();
14724 }
14725 #endif
14726 TRACE(("End of main reached\n"));
14727 exitshell();
14728 /* NOTREACHED */
14729 }
14730
14731
14732 /*-
14733 * Copyright (c) 1989, 1991, 1993, 1994
14734 * The Regents of the University of California. All rights reserved.
14735 *
14736 * This code is derived from software contributed to Berkeley by
14737 * Kenneth Almquist.
14738 *
14739 * Redistribution and use in source and binary forms, with or without
14740 * modification, are permitted provided that the following conditions
14741 * are met:
14742 * 1. Redistributions of source code must retain the above copyright
14743 * notice, this list of conditions and the following disclaimer.
14744 * 2. Redistributions in binary form must reproduce the above copyright
14745 * notice, this list of conditions and the following disclaimer in the
14746 * documentation and/or other materials provided with the distribution.
14747 * 3. Neither the name of the University nor the names of its contributors
14748 * may be used to endorse or promote products derived from this software
14749 * without specific prior written permission.
14750 *
14751 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
14752 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14753 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14754 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14755 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14756 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14757 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14758 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14759 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14760 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14761 * SUCH DAMAGE.
14762 */
14763