blob: 58da0a2a0cc5ae9f05a5bbde9c57808f9192b855 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
Denys Vlasenko73067272010-01-12 22:11:24 +01005 * 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 *
Eric Andersendf82f612001-06-28 07:46:40 +000010 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000011 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +000012 *
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
Eric Andersen81fe1232003-07-29 06:38:40 +000014 * was re-ported from NetBSD and debianized.
15 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020016 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Eric Andersencb57d552001-06-28 07:25:16 +000017 */
Denys Vlasenko67e15292020-06-24 13:39:13 +020018//config:config SHELL_ASH
19//config: bool #hidden option
20//config: depends on !NOMMU
21//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +020022//config:config ASH
Denys Vlasenkob097a842018-12-28 03:20:17 +010023//config: bool "ash (78 kb)"
Denys Vlasenko771f1992010-07-16 14:31:34 +020024//config: default y
25//config: depends on !NOMMU
Denys Vlasenko67e15292020-06-24 13:39:13 +020026//config: select SHELL_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +020027//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020028//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.
Denys Vlasenko771f1992010-07-16 14:31:34 +020032//config:
Kang-Che Sung6cd02942017-01-06 17:02:03 +010033//config:# ash options
34//config:# note: Don't remove !NOMMU part in the next line; it would break
35//config:# menuconfig's indenting.
Denys Vlasenko67e15292020-06-24 13:39:13 +020036//config:if !NOMMU && (SHELL_ASH || ASH || SH_IS_ASH || BASH_IS_ASH)
Kang-Che Sung6cd02942017-01-06 17:02:03 +010037//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +020038//config:config ASH_OPTIMIZE_FOR_SIZE
39//config: bool "Optimize for size instead of speed"
40//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +020041//config: depends on SHELL_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020042//config:
43//config:config ASH_INTERNAL_GLOB
44//config: bool "Use internal glob() implementation"
Denys Vlasenko326edc32016-12-22 14:36:49 +010045//config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now
Denys Vlasenko67e15292020-06-24 13:39:13 +020046//config: depends on SHELL_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020047//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020048//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.
Denys Vlasenkof5604222017-01-10 14:58:54 +010053//config:
54//config:config ASH_BASH_COMPAT
55//config: bool "bash-compatible extensions"
56//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +020057//config: depends on SHELL_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +010058//config:
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010059//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
Denys Vlasenko54c21112018-01-27 20:46:45 +010062//config: depends on ASH_BASH_COMPAT
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010063//config: help
64//config: This is not compliant with standards. Avoid if possible.
65//config:
William Pitcockd8fd88a2018-01-24 18:33:18 +010066//config:config ASH_BASH_NOT_FOUND_HOOK
67//config: bool "command_not_found_handle hook support"
68//config: default y
Denys Vlasenko54c21112018-01-27 20:46:45 +010069//config: depends on ASH_BASH_COMPAT
William Pitcockd8fd88a2018-01-24 18:33:18 +010070//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:
Denys Vlasenkof5604222017-01-10 14:58:54 +010075//config:config ASH_JOB_CONTROL
76//config: bool "Job control"
77//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +020078//config: depends on SHELL_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +010079//config:
80//config:config ASH_ALIAS
81//config: bool "Alias support"
82//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +020083//config: depends on SHELL_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020084//config:
85//config:config ASH_RANDOM_SUPPORT
86//config: bool "Pseudorandom generator and $RANDOM variable"
87//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +020088//config: depends on SHELL_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020089//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020090//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.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020095//config:
96//config:config ASH_EXPAND_PRMT
97//config: bool "Expand prompt string"
98//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +020099//config: depends on SHELL_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +0200100//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200101//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.
Denys Vlasenko514b51d2016-10-01 14:33:08 +0200104//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +0100105//config:config ASH_IDLE_TIMEOUT
Denys Vlasenkof5604222017-01-10 14:58:54 +0100106//config: bool "Idle timeout variable $TMOUT"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200107//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200108//config: depends on SHELL_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200109//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200110//config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200111//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +0100112//config:config ASH_MAIL
113//config: bool "Check for new mail in interactive shell"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200114//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200115//config: depends on SHELL_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200116//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200117//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.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200121//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100122//config:config ASH_ECHO
Denys Vlasenkof5604222017-01-10 14:58:54 +0100123//config: bool "echo builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200124//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200125//config: depends on SHELL_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200126//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100127//config:config ASH_PRINTF
Denys Vlasenkof5604222017-01-10 14:58:54 +0100128//config: bool "printf builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200129//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200130//config: depends on SHELL_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200131//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100132//config:config ASH_TEST
Denys Vlasenkof5604222017-01-10 14:58:54 +0100133//config: bool "test builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200134//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200135//config: depends on SHELL_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200136//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200137//config:config ASH_HELP
138//config: bool "help builtin"
139//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200140//config: depends on SHELL_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100141//config:
142//config:config ASH_GETOPTS
143//config: bool "getopts builtin"
144//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200145//config: depends on SHELL_ASH
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200146//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200147//config:config ASH_CMDCMD
Denys Vlasenkof5604222017-01-10 14:58:54 +0100148//config: bool "command builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200149//config: default y
Denys Vlasenko67e15292020-06-24 13:39:13 +0200150//config: depends on SHELL_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200151//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200152//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.
Kang-Che Sung6cd02942017-01-06 17:02:03 +0100155//config:
156//config:endif # ash options
Denys Vlasenko771f1992010-07-16 14:31:34 +0200157
Denys Vlasenko20704f02011-03-23 17:59:27 +0100158//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko205d48e2017-01-29 14:57:33 +0100159// 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))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100161//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100162
Denys Vlasenko67e15292020-06-24 13:39:13 +0200163//kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100164//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
165
Denys Vlasenko67047462016-12-22 15:21:58 +0100166/*
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100167 * 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.
Denys Vlasenko67047462016-12-22 15:21:58 +0100171 */
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
Denys Vlasenko67047462016-12-22 15:21:58 +0100183#include <fnmatch.h>
184#include <sys/times.h>
185#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko67047462016-12-22 15:21:58 +0100186#include "busybox.h" /* for applet_names */
Ron Yorston71df2d32018-11-27 14:34:25 +0000187#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +0100188# include "embedded_scripts.h"
189#else
190# define NUM_SCRIPTS 0
191#endif
Denys Vlasenko67047462016-12-22 15:21:58 +0100192
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100193/* 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
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200208/* BASH_TEST2: [[ EXPR ]]
209 * Status of [[ support:
210 * We replace && and || with -a and -o
211 * TODO:
212 * singleword+noglob expansion:
213 * v='a b'; [[ $v = 'a b' ]]; echo 0:$?
Denys Vlasenko89e9d552018-04-11 01:15:33 +0200214 * [[ /bin/n* ]]; echo 0:$?
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200215 * -a/-o are not AND/OR ops! (they are just strings)
216 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
217 * = is glob match operator, not equality operator: STR = GLOB
218 * (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
219 * == same as =
220 * add =~ regex match operator: STR =~ REGEX
221 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100222#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
Ron Yorston1d371862019-04-15 10:52:05 +0100226#define BASH_EPOCH_VARS ENABLE_ASH_BASH_COMPAT
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100227#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +0200228#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
Johannes Schindelin3bef5d82017-08-08 16:46:39 +0200229#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
230#define IF_BASH_READ_D IF_ASH_BASH_COMPAT
Ron Yorstone48559e2019-03-31 09:27:09 +0100231#define BASH_WAIT_N ENABLE_ASH_BASH_COMPAT
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100232
Denys Vlasenko67047462016-12-22 15:21:58 +0100233#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
234/* Bionic at least up to version 24 has no glob() */
235# undef ENABLE_ASH_INTERNAL_GLOB
236# define ENABLE_ASH_INTERNAL_GLOB 1
237#endif
238
239#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
240# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
241# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
242# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
243# error glob() should unbackslash them and match. uClibc does not unbackslash,
244# error fails to match dirname, subsequently not expanding <pattern> in it.
245// Testcase:
246// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
247// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
248#endif
249
250#if !ENABLE_ASH_INTERNAL_GLOB
251# include <glob.h>
252#endif
253
254#include "unicode.h"
255#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100256#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100257# include "math.h"
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200258#else
259typedef long arith_t;
260# define ARITH_FMT "%ld"
Denys Vlasenko67047462016-12-22 15:21:58 +0100261#endif
262#if ENABLE_ASH_RANDOM_SUPPORT
263# include "random.h"
264#else
265# define CLEAR_RANDOM_T(rnd) ((void)0)
266#endif
267
268#include "NUM_APPLETS.h"
269#if NUM_APPLETS == 1
270/* STANDALONE does not make sense, and won't compile */
271# undef CONFIG_FEATURE_SH_STANDALONE
272# undef ENABLE_FEATURE_SH_STANDALONE
273# undef IF_FEATURE_SH_STANDALONE
274# undef IF_NOT_FEATURE_SH_STANDALONE
275# define ENABLE_FEATURE_SH_STANDALONE 0
276# define IF_FEATURE_SH_STANDALONE(...)
277# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
278#endif
279
Denys Vlasenko9acd63c2018-03-28 18:35:07 +0200280#ifndef F_DUPFD_CLOEXEC
281# define F_DUPFD_CLOEXEC F_DUPFD
282#endif
Denys Vlasenko60fb98e2018-03-30 22:15:14 +0200283#ifndef O_CLOEXEC
284# define O_CLOEXEC 0
285#endif
Denys Vlasenko67047462016-12-22 15:21:58 +0100286#ifndef PIPE_BUF
287# define PIPE_BUF 4096 /* amount of buffering in a pipe */
288#endif
289
290#if !BB_MMU
291# error "Do not even bother, ash will not run on NOMMU machine"
292#endif
293
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100294/* We use a trick to have more optimized code (fewer pointer reloads):
295 * ash.c: extern struct globals *const ash_ptr_to_globals;
296 * ash_ptr_hack.c: struct globals *ash_ptr_to_globals;
297 * This way, compiler in ash.c knows the pointer can not change.
298 *
299 * However, this may break on weird arches or toolchains. In this case,
300 * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable
301 * this optimization.
302 */
303#ifndef BB_GLOBAL_CONST
304# define BB_GLOBAL_CONST const
305#endif
306
Denis Vlasenkob012b102007-02-19 22:43:01 +0000307
Denis Vlasenko01631112007-12-16 17:20:38 +0000308/* ============ Hash table sizes. Configurable. */
309
310#define VTABSIZE 39
311#define ATABSIZE 39
312#define CMDTABLESIZE 31 /* should be prime */
313
314
Denis Vlasenkob012b102007-02-19 22:43:01 +0000315/* ============ Shell options */
316
317static const char *const optletters_optnames[] = {
318 "e" "errexit",
319 "f" "noglob",
320 "I" "ignoreeof",
Denys Vlasenkof3634582019-06-03 12:21:04 +0200321/* The below allowed this invocation:
Denys Vlasenko897475a2019-06-01 16:35:09 +0200322 * ash -c 'set -i; echo $-; sleep 5; echo $-'
323 * to be ^C-ed and get to interactive ash prompt.
Denys Vlasenkof3634582019-06-03 12:21:04 +0200324 * bash does not support such "set -i".
325 * In our code, this is denoted by empty long name:
Denys Vlasenko897475a2019-06-01 16:35:09 +0200326 */
Denys Vlasenkof3634582019-06-03 12:21:04 +0200327 "i" "",
Denis Vlasenkob012b102007-02-19 22:43:01 +0000328 "m" "monitor",
329 "n" "noexec",
Denys Vlasenkof3634582019-06-03 12:21:04 +0200330/* Ditto: bash has no "set -s" */
331 "s" "",
332 "c" "",
Denis Vlasenkob012b102007-02-19 22:43:01 +0000333 "x" "xtrace",
334 "v" "verbose",
335 "C" "noclobber",
336 "a" "allexport",
337 "b" "notify",
338 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100339 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100340#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100341 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100342#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000343#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000344 ,"\0" "nolog"
345 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000346#endif
347};
Denys Vlasenko897475a2019-06-01 16:35:09 +0200348//bash 4.4.23 also has these opts (with these defaults):
349//braceexpand on
350//emacs on
351//errtrace off
352//functrace off
353//hashall on
354//histexpand off
355//history on
356//interactive-comments on
357//keyword off
358//onecmd off
359//physical off
360//posix off
361//privileged off
Denis Vlasenkob012b102007-02-19 22:43:01 +0000362
Denys Vlasenko285ad152009-12-04 23:02:27 +0100363#define optletters(n) optletters_optnames[n][0]
364#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000365
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000366enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000367
Eric Andersenc470f442003-07-28 09:56:35 +0000368
Denis Vlasenkob012b102007-02-19 22:43:01 +0000369/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000370
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200371#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000372
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000373/*
Eric Andersenc470f442003-07-28 09:56:35 +0000374 * We enclose jmp_buf in a structure so that we can declare pointers to
375 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000376 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000377 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000378 * exception handlers, the user should save the value of handler on entry
379 * to an inner scope, set handler to point to a jmploc structure for the
380 * inner scope, and restore handler on exit from the scope.
381 */
Eric Andersenc470f442003-07-28 09:56:35 +0000382struct jmploc {
383 jmp_buf loc;
384};
Denis Vlasenko01631112007-12-16 17:20:38 +0000385
386struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200387 uint8_t exitstatus; /* exit status of last command */
388 uint8_t back_exitstatus;/* exit status of backquoted command */
389 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
Denys Vlasenko4ccddc82020-02-14 17:27:18 +0100390 int savestatus; /* exit status of last command outside traps */
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200391 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000392 /* shell level: 0 for the main shell, 1 for its children, and so on */
393 int shlvl;
394#define rootshell (!shlvl)
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100395 int errlinno;
396
Denis Vlasenko01631112007-12-16 17:20:38 +0000397 char *minusc; /* argument to -c option */
398
399 char *curdir; // = nullstr; /* current working directory */
400 char *physdir; // = nullstr; /* physical working directory */
401
402 char *arg0; /* value of $0 */
403
404 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000405
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200406 volatile int suppress_int; /* counter */
407 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200408 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200409 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denys Vlasenkof977e002020-02-20 16:54:29 +0100410 smallint exception_type; /* kind of exception: */
Eric Andersenc470f442003-07-28 09:56:35 +0000411#define EXINT 0 /* SIGINT received */
412#define EXERROR 1 /* a generic error */
Denys Vlasenkof977e002020-02-20 16:54:29 +0100413#define EXEND 3 /* exit the shell */
414#define EXEXIT 4 /* exit the shell via exitcmd */
Eric Andersen2870d962001-07-02 17:27:21 +0000415
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000416 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000417
418 char optlist[NOPTS];
419#define eflag optlist[0]
420#define fflag optlist[1]
421#define Iflag optlist[2]
422#define iflag optlist[3]
423#define mflag optlist[4]
424#define nflag optlist[5]
425#define sflag optlist[6]
Denys Vlasenkof3634582019-06-03 12:21:04 +0200426#define cflag optlist[7]
427#define xflag optlist[8]
428#define vflag optlist[9]
429#define Cflag optlist[10]
430#define aflag optlist[11]
431#define bflag optlist[12]
432#define uflag optlist[13]
433#define viflag optlist[14]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100434#if BASH_PIPEFAIL
Denys Vlasenkof3634582019-06-03 12:21:04 +0200435# define pipefail optlist[15]
Michael Abbott359da5e2009-12-04 23:03:29 +0100436#else
437# define pipefail 0
438#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000439#if DEBUG
Denys Vlasenkof3634582019-06-03 12:21:04 +0200440# define nolog optlist[15 + BASH_PIPEFAIL]
441# define debug optlist[16 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000442#endif
443
444 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000445 /*
446 * Sigmode records the current value of the signal handlers for the various
447 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000448 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000449 */
450 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000451#define S_DFL 1 /* default signal handling (SIG_DFL) */
452#define S_CATCH 2 /* signal is caught */
453#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenko0f14f412017-08-06 20:06:19 +0200454#define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000455
Denis Vlasenko01631112007-12-16 17:20:38 +0000456 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000457 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200458 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000459 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200460 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000461
462 /* Rarely referenced stuff */
463#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200464 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000465#endif
466 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000467};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100468extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000469#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200470#define exitstatus (G_misc.exitstatus )
471#define back_exitstatus (G_misc.back_exitstatus )
472#define job_warning (G_misc.job_warning)
Denys Vlasenko4ccddc82020-02-14 17:27:18 +0100473#define savestatus (G_misc.savestatus )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000474#define rootpid (G_misc.rootpid )
475#define shlvl (G_misc.shlvl )
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100476#define errlinno (G_misc.errlinno )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000477#define minusc (G_misc.minusc )
478#define curdir (G_misc.curdir )
479#define physdir (G_misc.physdir )
480#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000481#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000482#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200483#define suppress_int (G_misc.suppress_int )
484#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200485#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200486#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000487#define nullstr (G_misc.nullstr )
488#define optlist (G_misc.optlist )
489#define sigmode (G_misc.sigmode )
490#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200491#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000492#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200493#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200494#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000495#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000496#define INIT_G_misc() do { \
Denys Vlasenkoaf7169b2019-10-25 12:12:22 +0200497 (*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000498 barrier(); \
Denys Vlasenko4ccddc82020-02-14 17:27:18 +0100499 savestatus = -1; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000500 curdir = nullstr; \
501 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200502 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000503} while (0)
504
505
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000506/* ============ DEBUG */
507#if DEBUG
508static void trace_printf(const char *fmt, ...);
509static void trace_vprintf(const char *fmt, va_list va);
510# define TRACE(param) trace_printf param
511# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000512# define close(fd) do { \
513 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000514 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200515 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000516 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000517} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000518#else
519# define TRACE(param)
520# define TRACEV(param)
521#endif
522
523
Denis Vlasenko559691a2008-10-05 18:39:31 +0000524/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100525#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
526#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
527
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200528static int
529isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000530{
531 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
532 while (--maxlen && isdigit(*str))
533 str++;
534 return (*str == '\0');
535}
Denis Vlasenko01631112007-12-16 17:20:38 +0000536
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200537static const char *
538var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200539{
540 while (*var)
541 if (*var++ == '=')
542 break;
543 return var;
544}
545
Denis Vlasenko559691a2008-10-05 18:39:31 +0000546
547/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100548
549static void exitshell(void) NORETURN;
550
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000551/*
Eric Andersen2870d962001-07-02 17:27:21 +0000552 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000553 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000554 * much more efficient and portable. (But hacking the kernel is so much
555 * more fun than worrying about efficiency and portability. :-))
556 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100557#if DEBUG_INTONOFF
558# define INT_OFF do { \
559 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200560 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200561 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000562} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100563#else
564# define INT_OFF do { \
565 suppress_int++; \
566 barrier(); \
567} while (0)
568#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000569
570/*
571 * Called to raise an exception. Since C doesn't include exceptions, we
572 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000573 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000574 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000575static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000576static void
577raise_exception(int e)
578{
579#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000580 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000581 abort();
582#endif
583 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000584 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000585 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000586}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000587#if DEBUG
588#define raise_exception(e) do { \
589 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
590 raise_exception(e); \
591} while (0)
592#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000593
594/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200595 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000596 * that SIGINT is to be trapped or ignored using the trap builtin, then
597 * this routine is not called.) Suppressint is nonzero when interrupts
598 * are held using the INT_OFF macro. (The test for iflag is just
599 * defensive programming.)
600 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000601static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000602static void
603raise_interrupt(void)
604{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200605 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000606 /* Signal is not automatically unmasked after it is raised,
607 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000608 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200609 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000610
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200611 if (!(rootshell && iflag)) {
612 /* Kill ourself with SIGINT */
613 signal(SIGINT, SIG_DFL);
614 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000615 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200616 /* bash: ^C even on empty command line sets $? */
617 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200618 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000619 /* NOTREACHED */
620}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000621#if DEBUG
622#define raise_interrupt() do { \
623 TRACE(("raising interrupt on line %d\n", __LINE__)); \
624 raise_interrupt(); \
625} while (0)
626#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000627
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000628static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000629int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000630{
Denys Vlasenkode892052016-10-02 01:49:13 +0200631 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200632 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000633 raise_interrupt();
634 }
635}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100636#if DEBUG_INTONOFF
637# define INT_ON do { \
638 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
639 int_on(); \
640} while (0)
641#else
642# define INT_ON int_on()
643#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000644static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000645force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000646{
Denys Vlasenkode892052016-10-02 01:49:13 +0200647 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200648 suppress_int = 0;
649 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000650 raise_interrupt();
651}
652#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000653
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200654#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000655
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000656#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200657 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200658 suppress_int = (v); \
659 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000660 raise_interrupt(); \
661} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000662
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000663
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000664/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000665
Eric Andersenc470f442003-07-28 09:56:35 +0000666static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000667outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000668{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000669 INT_OFF;
670 fputs(p, file);
671 INT_ON;
672}
673
674static void
675flush_stdout_stderr(void)
676{
677 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100678 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000679 INT_ON;
680}
681
Denys Vlasenko9c541002015-10-07 15:44:36 +0200682/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000683static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200684newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000685{
686 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200687 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000688 fflush(dest);
689 INT_ON;
690}
691
692static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
693static int
694out1fmt(const char *fmt, ...)
695{
696 va_list ap;
697 int r;
698
699 INT_OFF;
700 va_start(ap, fmt);
701 r = vprintf(fmt, ap);
702 va_end(ap);
703 INT_ON;
704 return r;
705}
706
707static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
708static int
709fmtstr(char *outbuf, size_t length, const char *fmt, ...)
710{
711 va_list ap;
712 int ret;
713
Denis Vlasenkob012b102007-02-19 22:43:01 +0000714 INT_OFF;
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200715 va_start(ap, fmt);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000716 ret = vsnprintf(outbuf, length, fmt, ap);
717 va_end(ap);
718 INT_ON;
Denys Vlasenko3f7fb2c2020-02-16 18:06:20 +0100719 return ret > (int)length ? length : ret;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000720}
721
722static void
723out1str(const char *p)
724{
725 outstr(p, stdout);
726}
727
728static void
729out2str(const char *p)
730{
731 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100732 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000733}
734
735
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000736/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000737
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000738/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100739#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200740#define CTLESC ((unsigned char)'\201') /* escape next character */
741#define CTLVAR ((unsigned char)'\202') /* variable defn */
742#define CTLENDVAR ((unsigned char)'\203')
743#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200744#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
745#define CTLENDARI ((unsigned char)'\207')
746#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100747#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000748
749/* variable substitution byte (follows CTLVAR) */
750#define VSTYPE 0x0f /* type of variable substitution */
751#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000752
753/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000754#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
755#define VSMINUS 0x2 /* ${var-text} */
756#define VSPLUS 0x3 /* ${var+text} */
757#define VSQUESTION 0x4 /* ${var?message} */
758#define VSASSIGN 0x5 /* ${var=text} */
759#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
760#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
761#define VSTRIMLEFT 0x8 /* ${var#pattern} */
762#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
763#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100764#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000765#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100766#endif
767#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000768#define VSREPLACE 0xd /* ${var/pattern/replacement} */
769#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
770#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000771
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000772static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200773 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000774};
Ron Yorston549deab2015-05-18 09:57:51 +0200775#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000776
Denis Vlasenko559691a2008-10-05 18:39:31 +0000777#define NCMD 0
778#define NPIPE 1
779#define NREDIR 2
780#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000781#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000782#define NAND 5
783#define NOR 6
784#define NSEMI 7
785#define NIF 8
786#define NWHILE 9
787#define NUNTIL 10
788#define NFOR 11
789#define NCASE 12
790#define NCLIST 13
791#define NDEFUN 14
792#define NARG 15
793#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100794#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000795#define NTO2 17
796#endif
797#define NCLOBBER 18
798#define NFROM 19
799#define NFROMTO 20
800#define NAPPEND 21
801#define NTOFD 22
802#define NFROMFD 23
803#define NHERE 24
804#define NXHERE 25
805#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000806#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000807
808union node;
809
810struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000811 smallint type; /* Nxxxx */
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100812 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000813 union node *assign;
814 union node *args;
815 union node *redirect;
816};
817
818struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000819 smallint type;
820 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000821 struct nodelist *cmdlist;
822};
823
824struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000825 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100826 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000827 union node *n;
828 union node *redirect;
829};
830
831struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000832 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000833 union node *ch1;
834 union node *ch2;
835};
836
837struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000838 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000839 union node *test;
840 union node *ifpart;
841 union node *elsepart;
842};
843
844struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000845 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100846 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000847 union node *args;
848 union node *body;
849 char *var;
850};
851
852struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000853 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100854 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000855 union node *expr;
856 union node *cases;
857};
858
859struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000860 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000861 union node *next;
862 union node *pattern;
863 union node *body;
864};
865
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100866struct ndefun {
867 smallint type;
868 int linno;
869 char *text;
870 union node *body;
871};
872
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000873struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000874 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000875 union node *next;
876 char *text;
877 struct nodelist *backquote;
878};
879
Denis Vlasenko559691a2008-10-05 18:39:31 +0000880/* nfile and ndup layout must match!
881 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
882 * that it is actually NTO2 (>&file), and change its type.
883 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000884struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000885 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000886 union node *next;
887 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000888 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000889 union node *fname;
890 char *expfname;
891};
892
893struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000894 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000895 union node *next;
896 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000897 int dupfd;
898 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000899 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000900};
901
902struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000903 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000904 union node *next;
905 int fd;
906 union node *doc;
907};
908
909struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000910 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000911 union node *com;
912};
913
914union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000915 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000916 struct ncmd ncmd;
917 struct npipe npipe;
918 struct nredir nredir;
919 struct nbinary nbinary;
920 struct nif nif;
921 struct nfor nfor;
922 struct ncase ncase;
923 struct nclist nclist;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100924 struct ndefun ndefun;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000925 struct narg narg;
926 struct nfile nfile;
927 struct ndup ndup;
928 struct nhere nhere;
929 struct nnot nnot;
930};
931
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200932/*
933 * NODE_EOF is returned by parsecmd when it encounters an end of file.
934 * It must be distinct from NULL.
935 */
936#define NODE_EOF ((union node *) -1L)
937
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000938struct nodelist {
939 struct nodelist *next;
940 union node *n;
941};
942
943struct funcnode {
944 int count;
945 union node n;
946};
947
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000948/*
949 * Free a parse tree.
950 */
951static void
952freefunc(struct funcnode *f)
953{
954 if (f && --f->count < 0)
955 free(f);
956}
957
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000958
959/* ============ Debugging output */
960
961#if DEBUG
962
963static FILE *tracefile;
964
965static void
966trace_printf(const char *fmt, ...)
967{
968 va_list va;
969
970 if (debug != 1)
971 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000972 if (DEBUG_TIME)
973 fprintf(tracefile, "%u ", (int) time(NULL));
974 if (DEBUG_PID)
975 fprintf(tracefile, "[%u] ", (int) getpid());
976 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200977 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000978 va_start(va, fmt);
979 vfprintf(tracefile, fmt, va);
980 va_end(va);
981}
982
983static void
984trace_vprintf(const char *fmt, va_list va)
985{
986 if (debug != 1)
987 return;
988 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100989 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000990}
991
992static void
993trace_puts(const char *s)
994{
995 if (debug != 1)
996 return;
997 fputs(s, tracefile);
998}
999
1000static void
1001trace_puts_quoted(char *s)
1002{
1003 char *p;
1004 char c;
1005
1006 if (debug != 1)
1007 return;
1008 putc('"', tracefile);
1009 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001010 switch ((unsigned char)*p) {
1011 case '\n': c = 'n'; goto backslash;
1012 case '\t': c = 't'; goto backslash;
1013 case '\r': c = 'r'; goto backslash;
1014 case '\"': c = '\"'; goto backslash;
1015 case '\\': c = '\\'; goto backslash;
1016 case CTLESC: c = 'e'; goto backslash;
1017 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001018 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001019 backslash:
1020 putc('\\', tracefile);
1021 putc(c, tracefile);
1022 break;
1023 default:
1024 if (*p >= ' ' && *p <= '~')
1025 putc(*p, tracefile);
1026 else {
1027 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +01001028 putc((*p >> 6) & 03, tracefile);
1029 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001030 putc(*p & 07, tracefile);
1031 }
1032 break;
1033 }
1034 }
1035 putc('"', tracefile);
1036}
1037
1038static void
1039trace_puts_args(char **ap)
1040{
1041 if (debug != 1)
1042 return;
1043 if (!*ap)
1044 return;
1045 while (1) {
1046 trace_puts_quoted(*ap);
1047 if (!*++ap) {
1048 putc('\n', tracefile);
1049 break;
1050 }
1051 putc(' ', tracefile);
1052 }
1053}
1054
1055static void
1056opentrace(void)
1057{
1058 char s[100];
1059#ifdef O_APPEND
1060 int flags;
1061#endif
1062
1063 if (debug != 1) {
1064 if (tracefile)
1065 fflush(tracefile);
1066 /* leave open because libedit might be using it */
1067 return;
1068 }
1069 strcpy(s, "./trace");
1070 if (tracefile) {
1071 if (!freopen(s, "a", tracefile)) {
1072 fprintf(stderr, "Can't re-open %s\n", s);
1073 debug = 0;
1074 return;
1075 }
1076 } else {
1077 tracefile = fopen(s, "a");
1078 if (tracefile == NULL) {
1079 fprintf(stderr, "Can't open %s\n", s);
1080 debug = 0;
1081 return;
1082 }
1083 }
1084#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +00001085 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001086 if (flags >= 0)
1087 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1088#endif
1089 setlinebuf(tracefile);
1090 fputs("\nTracing started.\n", tracefile);
1091}
1092
1093static void
1094indent(int amount, char *pfx, FILE *fp)
1095{
1096 int i;
1097
1098 for (i = 0; i < amount; i++) {
1099 if (pfx && i == amount - 1)
1100 fputs(pfx, fp);
1101 putc('\t', fp);
1102 }
1103}
1104
1105/* little circular references here... */
1106static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1107
1108static void
1109sharg(union node *arg, FILE *fp)
1110{
1111 char *p;
1112 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001113 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001114
1115 if (arg->type != NARG) {
1116 out1fmt("<node type %d>\n", arg->type);
1117 abort();
1118 }
1119 bqlist = arg->narg.backquote;
1120 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001121 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001122 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001123 p++;
1124 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001125 break;
1126 case CTLVAR:
1127 putc('$', fp);
1128 putc('{', fp);
1129 subtype = *++p;
1130 if (subtype == VSLENGTH)
1131 putc('#', fp);
1132
Dan Fandrich77d48722010-09-07 23:38:28 -07001133 while (*p != '=') {
1134 putc(*p, fp);
1135 p++;
1136 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001137
1138 if (subtype & VSNUL)
1139 putc(':', fp);
1140
1141 switch (subtype & VSTYPE) {
1142 case VSNORMAL:
1143 putc('}', fp);
1144 break;
1145 case VSMINUS:
1146 putc('-', fp);
1147 break;
1148 case VSPLUS:
1149 putc('+', fp);
1150 break;
1151 case VSQUESTION:
1152 putc('?', fp);
1153 break;
1154 case VSASSIGN:
1155 putc('=', fp);
1156 break;
1157 case VSTRIMLEFT:
1158 putc('#', fp);
1159 break;
1160 case VSTRIMLEFTMAX:
1161 putc('#', fp);
1162 putc('#', fp);
1163 break;
1164 case VSTRIMRIGHT:
1165 putc('%', fp);
1166 break;
1167 case VSTRIMRIGHTMAX:
1168 putc('%', fp);
1169 putc('%', fp);
1170 break;
1171 case VSLENGTH:
1172 break;
1173 default:
1174 out1fmt("<subtype %d>", subtype);
1175 }
1176 break;
1177 case CTLENDVAR:
1178 putc('}', fp);
1179 break;
1180 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001181 putc('$', fp);
1182 putc('(', fp);
1183 shtree(bqlist->n, -1, NULL, fp);
1184 putc(')', fp);
1185 break;
1186 default:
1187 putc(*p, fp);
1188 break;
1189 }
1190 }
1191}
1192
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001193static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001194shcmd(union node *cmd, FILE *fp)
1195{
1196 union node *np;
1197 int first;
1198 const char *s;
1199 int dftfd;
1200
1201 first = 1;
1202 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001203 if (!first)
1204 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001205 sharg(np, fp);
1206 first = 0;
1207 }
1208 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001209 if (!first)
1210 putc(' ', fp);
1211 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001212 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001213 case NTO: s = ">>"+1; dftfd = 1; break;
1214 case NCLOBBER: s = ">|"; dftfd = 1; break;
1215 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001216#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001217 case NTO2:
1218#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001219 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001220 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001221 case NFROMFD: s = "<&"; break;
1222 case NFROMTO: s = "<>"; break;
1223 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001224 }
1225 if (np->nfile.fd != dftfd)
1226 fprintf(fp, "%d", np->nfile.fd);
1227 fputs(s, fp);
1228 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1229 fprintf(fp, "%d", np->ndup.dupfd);
1230 } else {
1231 sharg(np->nfile.fname, fp);
1232 }
1233 first = 0;
1234 }
1235}
1236
1237static void
1238shtree(union node *n, int ind, char *pfx, FILE *fp)
1239{
1240 struct nodelist *lp;
1241 const char *s;
1242
1243 if (n == NULL)
1244 return;
1245
1246 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001247
1248 if (n == NODE_EOF) {
1249 fputs("<EOF>", fp);
1250 return;
1251 }
1252
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001253 switch (n->type) {
1254 case NSEMI:
1255 s = "; ";
1256 goto binop;
1257 case NAND:
1258 s = " && ";
1259 goto binop;
1260 case NOR:
1261 s = " || ";
1262 binop:
1263 shtree(n->nbinary.ch1, ind, NULL, fp);
1264 /* if (ind < 0) */
1265 fputs(s, fp);
1266 shtree(n->nbinary.ch2, ind, NULL, fp);
1267 break;
1268 case NCMD:
1269 shcmd(n, fp);
1270 if (ind >= 0)
1271 putc('\n', fp);
1272 break;
1273 case NPIPE:
1274 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001275 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001276 if (lp->next)
1277 fputs(" | ", fp);
1278 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001279 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001280 fputs(" &", fp);
1281 if (ind >= 0)
1282 putc('\n', fp);
1283 break;
1284 default:
1285 fprintf(fp, "<node type %d>", n->type);
1286 if (ind >= 0)
1287 putc('\n', fp);
1288 break;
1289 }
1290}
1291
1292static void
1293showtree(union node *n)
1294{
1295 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001296 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001297}
1298
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001299#endif /* DEBUG */
1300
1301
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001302/* ============ Parser data */
1303
1304/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001305 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1306 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001307struct strlist {
1308 struct strlist *next;
1309 char *text;
1310};
1311
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001312struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001313
Denis Vlasenkob012b102007-02-19 22:43:01 +00001314struct strpush {
1315 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001316 char *prev_string;
1317 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001318#if ENABLE_ASH_ALIAS
1319 struct alias *ap; /* if push was associated with an alias */
1320#endif
1321 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001322
1323 /* Remember last two characters for pungetc. */
1324 int lastc[2];
1325
1326 /* Number of outstanding calls to pungetc. */
1327 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001328};
1329
Denys Vlasenko0485b672017-08-14 19:46:56 +02001330/*
1331 * The parsefile structure pointed to by the global variable parsefile
1332 * contains information about the current file being read.
1333 */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001334struct parsefile {
1335 struct parsefile *prev; /* preceding file on stack */
1336 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001337 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001338 int left_in_line; /* number of chars left in this line */
1339 int left_in_buffer; /* number of chars left in this buffer past the line */
1340 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001341 char *buf; /* input buffer */
1342 struct strpush *strpush; /* for pushing strings at this level */
1343 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001344
1345 /* Remember last two characters for pungetc. */
1346 int lastc[2];
1347
1348 /* Number of outstanding calls to pungetc. */
1349 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001350};
1351
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001352static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001353static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001354static char *commandname; /* currently executing command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001355
1356
1357/* ============ Message printing */
1358
1359static void
1360ash_vmsg(const char *msg, va_list ap)
1361{
1362 fprintf(stderr, "%s: ", arg0);
1363 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001364 if (strcmp(arg0, commandname))
1365 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001366 if (!iflag || g_parsefile->pf_fd > 0)
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001367 fprintf(stderr, "line %d: ", errlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001368 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001369 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001370 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001371}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001372
1373/*
1374 * Exverror is called to raise the error exception. If the second argument
1375 * is not NULL then error prints an error message using printf style
1376 * formatting. It then raises the error exception.
1377 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001378static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001379static void
1380ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001381{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001382#if DEBUG
1383 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001384 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001385 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001386 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001387 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001388 if (msg)
1389#endif
1390 ash_vmsg(msg, ap);
1391
1392 flush_stdout_stderr();
1393 raise_exception(cond);
1394 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001395}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001396
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001397static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001398static void
1399ash_msg_and_raise_error(const char *msg, ...)
1400{
1401 va_list ap;
1402
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001403 exitstatus = 2;
1404
Denis Vlasenkob012b102007-02-19 22:43:01 +00001405 va_start(ap, msg);
1406 ash_vmsg_and_raise(EXERROR, msg, ap);
1407 /* NOTREACHED */
1408 va_end(ap);
1409}
1410
Ron Yorstonbe366e52017-07-27 13:53:39 +01001411/*
Ron Yorstonbe366e52017-07-27 13:53:39 +01001412 * 'fmt' must be a string literal.
1413 */
Denys Vlasenko6f97b302017-09-29 18:17:25 +02001414#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO)
Ron Yorstonbe366e52017-07-27 13:53:39 +01001415
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001416static void raise_error_syntax(const char *) NORETURN;
1417static void
1418raise_error_syntax(const char *msg)
1419{
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001420 errlinno = g_parsefile->linno;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001421 ash_msg_and_raise_error("syntax error: %s", msg);
1422 /* NOTREACHED */
1423}
1424
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001425static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001426static void
1427ash_msg_and_raise(int cond, const char *msg, ...)
1428{
1429 va_list ap;
1430
1431 va_start(ap, msg);
1432 ash_vmsg_and_raise(cond, msg, ap);
1433 /* NOTREACHED */
1434 va_end(ap);
1435}
1436
1437/*
1438 * error/warning routines for external builtins
1439 */
1440static void
1441ash_msg(const char *fmt, ...)
1442{
1443 va_list ap;
1444
1445 va_start(ap, fmt);
1446 ash_vmsg(fmt, ap);
1447 va_end(ap);
1448}
1449
1450/*
1451 * Return a string describing an error. The returned string may be a
1452 * pointer to a static buffer that will be overwritten on the next call.
1453 * Action describes the operation that got the error.
1454 */
1455static const char *
1456errmsg(int e, const char *em)
1457{
1458 if (e == ENOENT || e == ENOTDIR) {
1459 return em;
1460 }
1461 return strerror(e);
1462}
1463
1464
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001465/* ============ Memory allocation */
1466
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001467#if 0
1468/* I consider these wrappers nearly useless:
1469 * ok, they return you to nearest exception handler, but
1470 * how much memory do you leak in the process, making
1471 * memory starvation worse?
1472 */
1473static void *
1474ckrealloc(void * p, size_t nbytes)
1475{
1476 p = realloc(p, nbytes);
1477 if (!p)
1478 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1479 return p;
1480}
1481
1482static void *
1483ckmalloc(size_t nbytes)
1484{
1485 return ckrealloc(NULL, nbytes);
1486}
1487
1488static void *
1489ckzalloc(size_t nbytes)
1490{
1491 return memset(ckmalloc(nbytes), 0, nbytes);
1492}
1493
1494static char *
1495ckstrdup(const char *s)
1496{
1497 char *p = strdup(s);
1498 if (!p)
1499 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1500 return p;
1501}
1502#else
1503/* Using bbox equivalents. They exit if out of memory */
1504# define ckrealloc xrealloc
1505# define ckmalloc xmalloc
1506# define ckzalloc xzalloc
1507# define ckstrdup xstrdup
1508#endif
1509
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001510/*
1511 * It appears that grabstackstr() will barf with such alignments
1512 * because stalloc() will return a string allocated in a new stackblock.
1513 */
1514#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1515enum {
1516 /* Most machines require the value returned from malloc to be aligned
1517 * in some way. The following macro will get this right
1518 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001519 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001520 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001521 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001522};
1523
1524struct stack_block {
1525 struct stack_block *prev;
1526 char space[MINSIZE];
1527};
1528
1529struct stackmark {
1530 struct stack_block *stackp;
1531 char *stacknxt;
1532 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001533};
1534
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001535
Denis Vlasenko01631112007-12-16 17:20:38 +00001536struct globals_memstack {
1537 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001538 char *g_stacknxt; // = stackbase.space;
1539 char *sstrend; // = stackbase.space + MINSIZE;
1540 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001541 struct stack_block stackbase;
1542};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01001543extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001544#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001545#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001546#define g_stacknxt (G_memstack.g_stacknxt )
1547#define sstrend (G_memstack.sstrend )
1548#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001549#define stackbase (G_memstack.stackbase )
1550#define INIT_G_memstack() do { \
Denys Vlasenkoaf7169b2019-10-25 12:12:22 +02001551 (*(struct globals_memstack**)not_const_pp(&ash_ptr_to_globals_memstack)) = xzalloc(sizeof(G_memstack)); \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001552 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001553 g_stackp = &stackbase; \
1554 g_stacknxt = stackbase.space; \
1555 g_stacknleft = MINSIZE; \
1556 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001557} while (0)
1558
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001559
Denis Vlasenko01631112007-12-16 17:20:38 +00001560#define stackblock() ((void *)g_stacknxt)
1561#define stackblocksize() g_stacknleft
1562
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001563/*
1564 * Parse trees for commands are allocated in lifo order, so we use a stack
1565 * to make this more efficient, and also to avoid all sorts of exception
1566 * handling code to handle interrupts in the middle of a parse.
1567 *
1568 * The size 504 was chosen because the Ultrix malloc handles that size
1569 * well.
1570 */
1571static void *
1572stalloc(size_t nbytes)
1573{
1574 char *p;
1575 size_t aligned;
1576
1577 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001578 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001579 size_t len;
1580 size_t blocksize;
1581 struct stack_block *sp;
1582
1583 blocksize = aligned;
1584 if (blocksize < MINSIZE)
1585 blocksize = MINSIZE;
1586 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1587 if (len < blocksize)
1588 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1589 INT_OFF;
1590 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001591 sp->prev = g_stackp;
1592 g_stacknxt = sp->space;
1593 g_stacknleft = blocksize;
1594 sstrend = g_stacknxt + blocksize;
1595 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001596 INT_ON;
1597 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001598 p = g_stacknxt;
1599 g_stacknxt += aligned;
1600 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001601 return p;
1602}
1603
Denis Vlasenko597906c2008-02-20 16:38:54 +00001604static void *
1605stzalloc(size_t nbytes)
1606{
1607 return memset(stalloc(nbytes), 0, nbytes);
1608}
1609
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001610static void
1611stunalloc(void *p)
1612{
1613#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001614 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001615 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001616 abort();
1617 }
1618#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001619 g_stacknleft += g_stacknxt - (char *)p;
1620 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001621}
1622
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001623/*
1624 * Like strdup but works with the ash stack.
1625 */
1626static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001627sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001628{
1629 size_t len = strlen(p) + 1;
1630 return memcpy(stalloc(len), p, len);
1631}
1632
Denys Vlasenko03c36e02018-01-10 15:18:35 +01001633static ALWAYS_INLINE void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001634grabstackblock(size_t len)
1635{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001636 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001637}
1638
1639static void
1640pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001641{
Denis Vlasenko01631112007-12-16 17:20:38 +00001642 mark->stackp = g_stackp;
1643 mark->stacknxt = g_stacknxt;
1644 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001645 grabstackblock(len);
1646}
1647
1648static void
1649setstackmark(struct stackmark *mark)
1650{
1651 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001652}
1653
1654static void
1655popstackmark(struct stackmark *mark)
1656{
1657 struct stack_block *sp;
1658
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001659 if (!mark->stackp)
1660 return;
1661
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001662 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001663 while (g_stackp != mark->stackp) {
1664 sp = g_stackp;
1665 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001666 free(sp);
1667 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001668 g_stacknxt = mark->stacknxt;
1669 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001670 sstrend = mark->stacknxt + mark->stacknleft;
1671 INT_ON;
1672}
1673
1674/*
1675 * When the parser reads in a string, it wants to stick the string on the
1676 * stack and only adjust the stack pointer when it knows how big the
1677 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1678 * of space on top of the stack and stackblocklen returns the length of
1679 * this block. Growstackblock will grow this space by at least one byte,
1680 * possibly moving it (like realloc). Grabstackblock actually allocates the
1681 * part of the block that has been used.
1682 */
1683static void
Denys Vlasenkoda2e46d2020-02-21 15:25:37 +01001684growstackblock(size_t min)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001685{
1686 size_t newlen;
1687
Denis Vlasenko01631112007-12-16 17:20:38 +00001688 newlen = g_stacknleft * 2;
1689 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001690 ash_msg_and_raise_error(bb_msg_memory_exhausted);
Denys Vlasenkoda2e46d2020-02-21 15:25:37 +01001691 min = SHELL_ALIGN(min | 128);
1692 if (newlen < min)
1693 newlen += min;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001694
Denis Vlasenko01631112007-12-16 17:20:38 +00001695 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001696 struct stack_block *sp;
1697 struct stack_block *prevstackp;
1698 size_t grosslen;
1699
1700 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001701 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001702 prevstackp = sp->prev;
1703 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1704 sp = ckrealloc(sp, grosslen);
1705 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001706 g_stackp = sp;
1707 g_stacknxt = sp->space;
1708 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001709 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001710 INT_ON;
1711 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001712 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001713 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001714 char *p = stalloc(newlen);
1715
1716 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001717 g_stacknxt = memcpy(p, oldspace, oldlen);
1718 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001719 }
1720}
1721
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001722/*
1723 * The following routines are somewhat easier to use than the above.
1724 * The user declares a variable of type STACKSTR, which may be declared
1725 * to be a register. The macro STARTSTACKSTR initializes things. Then
1726 * the user uses the macro STPUTC to add characters to the string. In
1727 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1728 * grown as necessary. When the user is done, she can just leave the
1729 * string there and refer to it using stackblock(). Or she can allocate
1730 * the space for it using grabstackstr(). If it is necessary to allow
1731 * someone else to use the stack temporarily and then continue to grow
1732 * the string, the user should use grabstack to allocate the space, and
1733 * then call ungrabstr(p) to return to the previous mode of operation.
1734 *
1735 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1736 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1737 * is space for at least one character.
1738 */
1739static void *
1740growstackstr(void)
1741{
1742 size_t len = stackblocksize();
Denys Vlasenkoda2e46d2020-02-21 15:25:37 +01001743 growstackblock(0);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001744 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001745}
1746
Denys Vlasenkoc55847f2020-02-17 15:59:08 +01001747static char *
1748growstackto(size_t len)
1749{
Denys Vlasenkoda2e46d2020-02-21 15:25:37 +01001750 if (stackblocksize() < len)
1751 growstackblock(len);
Denys Vlasenkoc55847f2020-02-17 15:59:08 +01001752 return stackblock();
1753}
1754
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001755/*
1756 * Called from CHECKSTRSPACE.
1757 */
1758static char *
1759makestrspace(size_t newlen, char *p)
1760{
Denis Vlasenko01631112007-12-16 17:20:38 +00001761 size_t len = p - g_stacknxt;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001762
Denys Vlasenkoc55847f2020-02-17 15:59:08 +01001763 return growstackto(len + newlen) + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001764}
1765
1766static char *
Denys Vlasenko538ee412020-02-22 19:11:41 +01001767stnputs(const char *s, size_t n, char *p)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001768{
1769 p = makestrspace(n, p);
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001770 p = (char *)mempcpy(p, s, n);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001771 return p;
1772}
1773
1774static char *
1775stack_putstr(const char *s, char *p)
1776{
Denys Vlasenko538ee412020-02-22 19:11:41 +01001777 return stnputs(s, strlen(s), p);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001778}
1779
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001780static char *
1781_STPUTC(int c, char *p)
1782{
1783 if (p == sstrend)
1784 p = growstackstr();
1785 *p++ = c;
1786 return p;
1787}
1788
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001789#define STARTSTACKSTR(p) ((p) = stackblock())
1790#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001791#define CHECKSTRSPACE(n, p) do { \
1792 char *q = (p); \
1793 size_t l = (n); \
1794 size_t m = sstrend - q; \
1795 if (l > m) \
1796 (p) = makestrspace(l, q); \
1797} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001798#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001799#define STACKSTRNUL(p) do { \
1800 if ((p) == sstrend) \
1801 (p) = growstackstr(); \
1802 *(p) = '\0'; \
1803} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001804#define STUNPUTC(p) (--(p))
1805#define STTOPC(p) ((p)[-1])
1806#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001807
1808#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001809#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001810#define stackstrend() ((void *)sstrend)
1811
1812
1813/* ============ String helpers */
1814
1815/*
1816 * prefix -- see if pfx is a prefix of string.
1817 */
1818static char *
1819prefix(const char *string, const char *pfx)
1820{
1821 while (*pfx) {
1822 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001823 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001824 }
1825 return (char *) string;
1826}
1827
1828/*
1829 * Check for a valid number. This should be elsewhere.
1830 */
1831static int
1832is_number(const char *p)
1833{
1834 do {
1835 if (!isdigit(*p))
1836 return 0;
1837 } while (*++p != '\0');
1838 return 1;
1839}
1840
1841/*
1842 * Convert a string of digits to an integer, printing an error message on
1843 * failure.
1844 */
1845static int
1846number(const char *s)
1847{
1848 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001849 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001850 return atoi(s);
1851}
1852
1853/*
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001854 * Produce a single quoted string suitable as input to the shell.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001855 * The return string is allocated on the stack.
1856 */
1857static char *
1858single_quote(const char *s)
1859{
1860 char *p;
1861
1862 STARTSTACKSTR(p);
1863
1864 do {
1865 char *q;
1866 size_t len;
1867
1868 len = strchrnul(s, '\'') - s;
1869
1870 q = p = makestrspace(len + 3, p);
1871
1872 *q++ = '\'';
Denys Vlasenko94af83e2017-07-23 21:55:40 +02001873 q = (char *)mempcpy(q, s, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001874 *q++ = '\'';
1875 s += len;
1876
1877 STADJUST(q - p, p);
1878
Denys Vlasenkocd716832009-11-28 22:14:02 +01001879 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001880 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001881 len = 0;
1882 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001883
1884 q = p = makestrspace(len + 3, p);
1885
1886 *q++ = '"';
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001887 q = (char *)mempcpy(q, s - len, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001888 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001889
1890 STADJUST(q - p, p);
1891 } while (*s);
1892
Denys Vlasenkocd716832009-11-28 22:14:02 +01001893 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001894
1895 return stackblock();
1896}
1897
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001898/*
1899 * Produce a possibly single quoted string suitable as input to the shell.
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001900 * If quoting was done, the return string is allocated on the stack,
1901 * otherwise a pointer to the original string is returned.
1902 */
1903static const char *
1904maybe_single_quote(const char *s)
1905{
1906 const char *p = s;
1907
1908 while (*p) {
1909 /* Assuming ACSII */
1910 /* quote ctrl_chars space !"#$%&'()* */
1911 if (*p < '+')
1912 goto need_quoting;
1913 /* quote ;<=>? */
1914 if (*p >= ';' && *p <= '?')
1915 goto need_quoting;
1916 /* quote `[\ */
1917 if (*p == '`')
1918 goto need_quoting;
1919 if (*p == '[')
1920 goto need_quoting;
1921 if (*p == '\\')
1922 goto need_quoting;
1923 /* quote {|}~ DEL and high bytes */
1924 if (*p > 'z')
1925 goto need_quoting;
1926 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1927 /* TODO: maybe avoid quoting % */
1928 p++;
1929 }
1930 return s;
1931
1932 need_quoting:
1933 return single_quote(s);
1934}
1935
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001936
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001937/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001938
1939static char **argptr; /* argument list for builtin commands */
1940static char *optionarg; /* set by nextopt (like getopt) */
1941static char *optptr; /* used by nextopt */
1942
1943/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001944 * XXX - should get rid of. Have all builtins use getopt(3).
1945 * The library getopt must have the BSD extension static variable
1946 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001947 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001948 * Standard option processing (a la getopt) for builtin routines.
1949 * The only argument that is passed to nextopt is the option string;
1950 * the other arguments are unnecessary. It returns the character,
1951 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001952 */
1953static int
1954nextopt(const char *optstring)
1955{
1956 char *p;
1957 const char *q;
1958 char c;
1959
1960 p = optptr;
1961 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001962 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001963 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001964 if (p == NULL)
1965 return '\0';
1966 if (*p != '-')
1967 return '\0';
1968 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001969 return '\0';
1970 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001971 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001972 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001973 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001974 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001975 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001976 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001977 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001978 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001979 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001980 if (*++q == ':')
1981 q++;
1982 }
1983 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001984 if (*p == '\0') {
1985 p = *argptr++;
1986 if (p == NULL)
1987 ash_msg_and_raise_error("no arg for -%c option", c);
1988 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001989 optionarg = p;
1990 p = NULL;
1991 }
1992 optptr = p;
1993 return c;
1994}
1995
1996
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001997/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001998
Denis Vlasenko01631112007-12-16 17:20:38 +00001999struct shparam {
2000 int nparam; /* # of positional parameters (without $0) */
2001#if ENABLE_ASH_GETOPTS
2002 int optind; /* next parameter to be processed by getopts */
2003 int optoff; /* used by getopts */
2004#endif
2005 unsigned char malloced; /* if parameter list dynamically allocated */
2006 char **p; /* parameter list */
2007};
2008
2009/*
2010 * Free the list of positional parameters.
2011 */
2012static void
2013freeparam(volatile struct shparam *param)
2014{
Denis Vlasenko01631112007-12-16 17:20:38 +00002015 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00002016 char **ap, **ap1;
2017 ap = ap1 = param->p;
2018 while (*ap)
2019 free(*ap++);
2020 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00002021 }
2022}
2023
2024#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002025static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00002026#endif
2027
2028struct var {
2029 struct var *next; /* next entry in hash list */
2030 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002031 const char *var_text; /* name=value */
2032 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00002033 /* the variable gets set/unset */
2034};
2035
2036struct localvar {
2037 struct localvar *next; /* next local variable in list */
2038 struct var *vp; /* the variable that was made local */
2039 int flags; /* saved flags */
2040 const char *text; /* saved text */
2041};
2042
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002043/* flags */
2044#define VEXPORT 0x01 /* variable is exported */
2045#define VREADONLY 0x02 /* variable cannot be modified */
2046#define VSTRFIXED 0x04 /* variable struct is statically allocated */
2047#define VTEXTFIXED 0x08 /* text is statically allocated */
2048#define VSTACK 0x10 /* text is allocated on the stack */
2049#define VUNSET 0x20 /* the variable is not set */
2050#define VNOFUNC 0x40 /* don't call the callback function */
2051#define VNOSET 0x80 /* do not set variable - just readonly test */
2052#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002053#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002054# define VDYNAMIC 0x200 /* dynamic variable */
2055#else
2056# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002057#endif
2058
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002059
Denis Vlasenko01631112007-12-16 17:20:38 +00002060/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002061#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002062static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002063change_lc_all(const char *value)
2064{
2065 if (value && *value != '\0')
2066 setlocale(LC_ALL, value);
2067}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002068static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002069change_lc_ctype(const char *value)
2070{
2071 if (value && *value != '\0')
2072 setlocale(LC_CTYPE, value);
2073}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002074#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002075#if ENABLE_ASH_MAIL
2076static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01002077static void changemail(const char *var_value) FAST_FUNC;
2078#else
2079# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002080#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002081static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002082#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002083static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002084#endif
Ron Yorston1d371862019-04-15 10:52:05 +01002085#if BASH_EPOCH_VARS
2086static void change_seconds(const char *) FAST_FUNC;
2087static void change_realtime(const char *) FAST_FUNC;
2088#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002089
Denis Vlasenko01631112007-12-16 17:20:38 +00002090static const struct {
2091 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002092 const char *var_text;
2093 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00002094} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02002095 /*
2096 * Note: VEXPORT would not work correctly here for NOFORK applets:
2097 * some environment strings may be constant.
2098 */
Denis Vlasenko01631112007-12-16 17:20:38 +00002099 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002100#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002101 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2102 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002103#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00002104 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2105 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2106 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2107 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002108#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002109 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002110#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002111 { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002112#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002113 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002114#endif
Ron Yorston1d371862019-04-15 10:52:05 +01002115#if BASH_EPOCH_VARS
2116 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHSECONDS", change_seconds },
2117 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "EPOCHREALTIME", change_realtime },
2118#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002119#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002120 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2121 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002122#endif
2123#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002124 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002125#endif
2126};
2127
Denis Vlasenko0b769642008-07-24 07:54:57 +00002128struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002129
2130struct globals_var {
2131 struct shparam shellparam; /* $@ current positional parameters */
2132 struct redirtab *redirlist;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02002133 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
Denis Vlasenko01631112007-12-16 17:20:38 +00002134 struct var *vartab[VTABSIZE];
2135 struct var varinit[ARRAY_SIZE(varinit_data)];
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002136 int lineno;
2137 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
Denis Vlasenko01631112007-12-16 17:20:38 +00002138};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01002139extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002140#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002141#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002142//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002143#define preverrout_fd (G_var.preverrout_fd)
2144#define vartab (G_var.vartab )
2145#define varinit (G_var.varinit )
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002146#define lineno (G_var.lineno )
2147#define linenovar (G_var.linenovar )
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002148#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002149#if ENABLE_ASH_MAIL
Ron Yorston1d371862019-04-15 10:52:05 +01002150# define vmail varinit[1]
2151# define vmpath varinit[2]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002152#endif
Ron Yorston1d371862019-04-15 10:52:05 +01002153#define VAR_OFFSET1 (ENABLE_ASH_MAIL*2)
2154#define vpath varinit[VAR_OFFSET1 + 1]
2155#define vps1 varinit[VAR_OFFSET1 + 2]
2156#define vps2 varinit[VAR_OFFSET1 + 3]
2157#define vps4 varinit[VAR_OFFSET1 + 4]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002158#if ENABLE_ASH_GETOPTS
Ron Yorston1d371862019-04-15 10:52:05 +01002159# define voptind varinit[VAR_OFFSET1 + 5]
2160#endif
2161#define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
2162#define vlineno varinit[VAR_OFFSET2 + 5]
2163#if ENABLE_ASH_RANDOM_SUPPORT
2164# define vrandom varinit[VAR_OFFSET2 + 6]
2165#endif
2166#define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
2167#if BASH_EPOCH_VARS
2168# define vepochs varinit[VAR_OFFSET3 + 6]
2169# define vepochr varinit[VAR_OFFSET3 + 7]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002170#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002171#define INIT_G_var() do { \
2172 unsigned i; \
Denys Vlasenkoaf7169b2019-10-25 12:12:22 +02002173 (*(struct globals_var**)not_const_pp(&ash_ptr_to_globals_var)) = xzalloc(sizeof(G_var)); \
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002174 barrier(); \
2175 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2176 varinit[i].flags = varinit_data[i].flags; \
2177 varinit[i].var_text = varinit_data[i].var_text; \
2178 varinit[i].var_func = varinit_data[i].var_func; \
2179 } \
2180 strcpy(linenovar, "LINENO="); \
2181 vlineno.var_text = linenovar; \
2182} while (0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002183
2184/*
2185 * The following macros access the values of the above variables.
2186 * They have to skip over the name. They return the null string
2187 * for unset variables.
2188 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002189#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002190#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002191#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002192# define mailval() (vmail.var_text + 5)
2193# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002194# define mpathset() ((vmpath.flags & VUNSET) == 0)
2195#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002196#define pathval() (vpath.var_text + 5)
2197#define ps1val() (vps1.var_text + 4)
2198#define ps2val() (vps2.var_text + 4)
2199#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002200#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002201# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002202#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002203
Denis Vlasenko01631112007-12-16 17:20:38 +00002204#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002205static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002206getoptsreset(const char *value)
2207{
Denys Vlasenko46289452017-08-11 00:59:36 +02002208 shellparam.optind = 1;
2209 if (is_number(value))
2210 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002211 shellparam.optoff = -1;
2212}
2213#endif
2214
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002215/*
2216 * Compares two strings up to the first = or '\0'. The first
2217 * string must be terminated by '='; the second may be terminated by
2218 * either '=' or '\0'.
2219 */
2220static int
2221varcmp(const char *p, const char *q)
2222{
2223 int c, d;
2224
2225 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002226 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002227 goto out;
2228 p++;
2229 q++;
2230 }
2231 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002232 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002233 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002234 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002235 out:
2236 return c - d;
2237}
2238
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002239/*
2240 * Find the appropriate entry in the hash table from the name.
2241 */
2242static struct var **
2243hashvar(const char *p)
2244{
2245 unsigned hashval;
2246
2247 hashval = ((unsigned char) *p) << 4;
2248 while (*p && *p != '=')
2249 hashval += (unsigned char) *p++;
2250 return &vartab[hashval % VTABSIZE];
2251}
2252
2253static int
2254vpcmp(const void *a, const void *b)
2255{
2256 return varcmp(*(const char **)a, *(const char **)b);
2257}
2258
2259/*
2260 * This routine initializes the builtin variables.
2261 */
2262static void
2263initvar(void)
2264{
2265 struct var *vp;
2266 struct var *end;
2267 struct var **vpp;
2268
2269 /*
2270 * PS1 depends on uid
2271 */
2272#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002273 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002274#else
2275 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002276 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002277#endif
2278 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002279 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002280 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002281 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002282 vp->next = *vpp;
2283 *vpp = vp;
2284 } while (++vp < end);
2285}
2286
2287static struct var **
2288findvar(struct var **vpp, const char *name)
2289{
2290 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002291 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002292 break;
2293 }
2294 }
2295 return vpp;
2296}
2297
2298/*
2299 * Find the value of a variable. Returns NULL if not set.
2300 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002301static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002302lookupvar(const char *name)
2303{
2304 struct var *v;
2305
2306 v = *findvar(hashvar(name), name);
2307 if (v) {
Ron Yorston1d371862019-04-15 10:52:05 +01002308#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002309 /*
2310 * Dynamic variables are implemented roughly the same way they are
2311 * in bash. Namely, they're "special" so long as they aren't unset.
2312 * As soon as they're unset, they're no longer dynamic, and dynamic
2313 * lookup will no longer happen at that point. -- PFM.
2314 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002315 if (v->flags & VDYNAMIC)
2316 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002317#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002318 if (!(v->flags & VUNSET)) {
2319 if (v == &vlineno && v->var_text == linenovar) {
2320 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2321 }
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002322 return var_end(v->var_text);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002323 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002324 }
2325 return NULL;
2326}
2327
Denys Vlasenko0b883582016-12-23 16:49:07 +01002328#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002329static void
2330reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002331{
2332 /* Unicode support should be activated even if LANG is set
2333 * _during_ shell execution, not only if it was set when
2334 * shell was started. Therefore, re-check LANG every time:
2335 */
2336 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2337 || ENABLE_UNICODE_USING_LOCALE
2338 ) {
2339 const char *s = lookupvar("LC_ALL");
2340 if (!s) s = lookupvar("LC_CTYPE");
2341 if (!s) s = lookupvar("LANG");
2342 reinit_unicode(s);
2343 }
2344}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002345#else
2346# define reinit_unicode_for_ash() ((void)0)
2347#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002348
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002349/*
2350 * Search the environment of a builtin command.
2351 */
Denys Vlasenko488e6092017-07-26 23:08:36 +02002352static ALWAYS_INLINE const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002353bltinlookup(const char *name)
2354{
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002355 return lookupvar(name);
2356}
2357
2358/*
2359 * Same as setvar except that the variable and value are passed in
2360 * the first argument as name=value. Since the first argument will
2361 * be actually stored in the table, it should not be a string that
2362 * will go away.
2363 * Called with interrupts off.
2364 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002365static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002366setvareq(char *s, int flags)
2367{
2368 struct var *vp, **vpp;
2369
2370 vpp = hashvar(s);
2371 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002372 vpp = findvar(vpp, s);
2373 vp = *vpp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002374 if (vp) {
2375 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2376 const char *n;
2377
2378 if (flags & VNOSAVE)
2379 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002380 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002381 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002382 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2383 }
2384
2385 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002386 goto out;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002387
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002388 if (vp->var_func && !(flags & VNOFUNC))
2389 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002390
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002391 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2392 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002393
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002394 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2395 *vpp = vp->next;
2396 free(vp);
2397 out_free:
2398 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2399 free(s);
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002400 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002401 }
2402
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002403 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
Ron Yorston1d371862019-04-15 10:52:05 +01002404#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
Ron Yorstond96c69d2019-04-15 10:49:35 +01002405 if (flags & VUNSET)
2406 flags &= ~VDYNAMIC;
2407#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002408 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002409 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002410 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002411 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002412 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2413 goto out_free;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002414 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002415 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002416 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002417 *vpp = vp;
2418 }
2419 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2420 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002421 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002422 vp->flags = flags;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002423
2424 out:
2425 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002426}
2427
2428/*
2429 * Set the value of a variable. The flags argument is ored with the
2430 * flags of the variable. If val is NULL, the variable is unset.
2431 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002432static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002433setvar(const char *name, const char *val, int flags)
2434{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002435 const char *q;
2436 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002437 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002438 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002439 size_t vallen;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002440 struct var *vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002441
2442 q = endofname(name);
2443 p = strchrnul(q, '=');
2444 namelen = p - name;
2445 if (!namelen || p != q)
2446 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2447 vallen = 0;
2448 if (val == NULL) {
2449 flags |= VUNSET;
2450 } else {
2451 vallen = strlen(val);
2452 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002453
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002454 INT_OFF;
Ron Yorstone6a63bf2018-11-12 21:10:54 +00002455 nameeq = ckzalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002456 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002457 if (val) {
2458 *p++ = '=';
Ron Yorstone6a63bf2018-11-12 21:10:54 +00002459 memcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002460 }
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002461 vp = setvareq(nameeq, flags | VNOSAVE);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002462 INT_ON;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002463
2464 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002465}
2466
Denys Vlasenko03dad222010-01-12 23:29:57 +01002467static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002468setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002469{
2470 setvar(name, val, 0);
2471}
2472
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002473/*
2474 * Unset the specified variable.
2475 */
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002476static void
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002477unsetvar(const char *s)
2478{
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02002479 setvar(s, NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002480}
2481
2482/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002483 * Generate a list of variables satisfying the given conditions.
2484 */
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002485#if !ENABLE_FEATURE_SH_NOFORK
2486# define listvars(on, off, lp, end) listvars(on, off, end)
2487#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002488static char **
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002489listvars(int on, int off, struct strlist *lp, char ***end)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002490{
2491 struct var **vpp;
2492 struct var *vp;
2493 char **ep;
2494 int mask;
2495
2496 STARTSTACKSTR(ep);
2497 vpp = vartab;
2498 mask = on | off;
2499 do {
2500 for (vp = *vpp; vp; vp = vp->next) {
2501 if ((vp->flags & mask) == on) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002502#if ENABLE_FEATURE_SH_NOFORK
2503 /* If variable with the same name is both
2504 * exported and temporarily set for a command:
2505 * export ZVAR=5
2506 * ZVAR=6 printenv
2507 * then "ZVAR=6" will be both in vartab and
2508 * lp lists. Do not pass it twice to printenv.
2509 */
2510 struct strlist *lp1 = lp;
2511 while (lp1) {
2512 if (strcmp(lp1->text, vp->var_text) == 0)
2513 goto skip;
2514 lp1 = lp1->next;
2515 }
2516#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002517 if (ep == stackstrend())
2518 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002519 *ep++ = (char*)vp->var_text;
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002520#if ENABLE_FEATURE_SH_NOFORK
2521 skip: ;
2522#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002523 }
2524 }
2525 } while (++vpp < vartab + VTABSIZE);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002526
2527#if ENABLE_FEATURE_SH_NOFORK
2528 while (lp) {
2529 if (ep == stackstrend())
2530 ep = growstackstr();
2531 *ep++ = lp->text;
2532 lp = lp->next;
2533 }
2534#endif
2535
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002536 if (ep == stackstrend())
2537 ep = growstackstr();
2538 if (end)
2539 *end = ep;
2540 *ep++ = NULL;
2541 return grabstackstr(ep);
2542}
2543
2544
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01002545/* ============ Path search helper */
2546static const char *
2547legal_pathopt(const char *opt, const char *term, int magic)
2548{
2549 switch (magic) {
2550 case 0:
2551 opt = NULL;
2552 break;
2553
2554 case 1:
2555 opt = prefix(opt, "builtin") ?: prefix(opt, "func");
2556 break;
2557
2558 default:
2559 opt += strcspn(opt, term);
2560 break;
2561 }
2562
2563 if (opt && *opt == '%')
2564 opt++;
2565
2566 return opt;
2567}
2568
2569/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002570 * The variable path (passed by reference) should be set to the start
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01002571 * of the path before the first call; padvance will update
2572 * this value as it proceeds. Successive calls to padvance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002573 * the possible path expansions in sequence. If an option (indicated by
2574 * a percent sign) appears in the path entry then the global variable
2575 * pathopt will be set to point to it; otherwise pathopt will be set to
2576 * NULL.
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01002577 *
2578 * If magic is 0 then pathopt recognition will be disabled. If magic is
2579 * 1 we shall recognise %builtin/%func. Otherwise we shall accept any
2580 * pathopt.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002581 */
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01002582static const char *pathopt; /* set by padvance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002583
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01002584static int
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01002585padvance_magic(const char **path, const char *name, int magic)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002586{
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01002587 const char *term = "%:";
2588 const char *lpathopt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002589 const char *p;
2590 char *q;
2591 const char *start;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01002592 size_t qlen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002593 size_t len;
2594
2595 if (*path == NULL)
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01002596 return -1;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01002597
2598 lpathopt = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002599 start = *path;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01002600
2601 if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) {
2602 lpathopt = start + 1;
2603 start = p;
2604 term = ":";
2605 }
2606
2607 len = strcspn(start, term);
2608 p = start + len;
2609
2610 if (*p == '%') {
2611 size_t extra = strchrnul(p, ':') - p;
2612
2613 if (legal_pathopt(p + 1, term, magic))
2614 lpathopt = p + 1;
2615 else
2616 len += extra;
2617
2618 p += extra;
2619 }
2620
2621 pathopt = lpathopt;
2622 *path = *p == ':' ? p + 1 : NULL;
2623
2624 /* "2" is for '/' and '\0' */
2625 qlen = len + strlen(name) + 2;
2626 q = growstackto(qlen);
2627
2628 if (len) {
2629 q = mempcpy(q, start, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002630 *q++ = '/';
2631 }
2632 strcpy(q, name);
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01002633
2634 return qlen;
2635}
2636
2637static int
2638padvance(const char **path, const char *name)
2639{
2640 return padvance_magic(path, name, 1);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002641}
2642
2643
2644/* ============ Prompt */
2645
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002646static smallint doprompt; /* if set, prompt the user */
2647static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002648
2649#if ENABLE_FEATURE_EDITING
2650static line_input_t *line_input_state;
2651static const char *cmdedit_prompt;
2652static void
2653putprompt(const char *s)
2654{
2655 if (ENABLE_ASH_EXPAND_PRMT) {
2656 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002657 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002658 return;
2659 }
2660 cmdedit_prompt = s;
2661}
2662#else
2663static void
2664putprompt(const char *s)
2665{
2666 out2str(s);
2667}
2668#endif
2669
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002670/* expandstr() needs parsing machinery, so it is far away ahead... */
Denys Vlasenko46999802017-07-29 21:12:29 +02002671static const char *expandstr(const char *ps, int syntax_type);
2672/* Values for syntax param */
2673#define BASESYNTAX 0 /* not in quotes */
2674#define DQSYNTAX 1 /* in double quotes */
2675#define SQSYNTAX 2 /* in single quotes */
2676#define ARISYNTAX 3 /* in arithmetic */
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +02002677#if ENABLE_ASH_EXPAND_PRMT
2678# define PSSYNTAX 4 /* prompt. never passed to SIT() */
2679#endif
Denys Vlasenko46999802017-07-29 21:12:29 +02002680/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002681
Denys Vlasenko46999802017-07-29 21:12:29 +02002682/*
2683 * called by editline -- any expansions to the prompt should be added here.
2684 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002685static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002686setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002687{
2688 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002689 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2690
2691 if (!do_set)
2692 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002693
2694 needprompt = 0;
2695
2696 switch (whichprompt) {
2697 case 1:
2698 prompt = ps1val();
2699 break;
2700 case 2:
2701 prompt = ps2val();
2702 break;
2703 default: /* 0 */
2704 prompt = nullstr;
2705 }
2706#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002707 pushstackmark(&smark, stackblocksize());
Denys Vlasenko46999802017-07-29 21:12:29 +02002708 putprompt(expandstr(prompt, PSSYNTAX));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002709 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002710#else
2711 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002712#endif
2713}
2714
2715
2716/* ============ The cd and pwd commands */
2717
2718#define CD_PHYSICAL 1
2719#define CD_PRINT 2
2720
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002721static int
2722cdopt(void)
2723{
2724 int flags = 0;
2725 int i, j;
2726
2727 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002728 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002729 if (i != j) {
2730 flags ^= CD_PHYSICAL;
2731 j = i;
2732 }
2733 }
2734
2735 return flags;
2736}
2737
2738/*
2739 * Update curdir (the name of the current directory) in response to a
2740 * cd command.
2741 */
2742static const char *
2743updatepwd(const char *dir)
2744{
2745 char *new;
2746 char *p;
2747 char *cdcomppath;
2748 const char *lim;
2749
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002750 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002751 STARTSTACKSTR(new);
2752 if (*dir != '/') {
2753 if (curdir == nullstr)
2754 return 0;
2755 new = stack_putstr(curdir, new);
2756 }
2757 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002758 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002759 if (*dir != '/') {
2760 if (new[-1] != '/')
2761 USTPUTC('/', new);
2762 if (new > lim && *lim == '/')
2763 lim++;
2764 } else {
2765 USTPUTC('/', new);
2766 cdcomppath++;
2767 if (dir[1] == '/' && dir[2] != '/') {
2768 USTPUTC('/', new);
2769 cdcomppath++;
2770 lim++;
2771 }
2772 }
Denys Vlasenko24966162020-10-06 02:36:47 +02002773 p = strtok_r(cdcomppath, "/", &cdcomppath);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002774 while (p) {
2775 switch (*p) {
2776 case '.':
2777 if (p[1] == '.' && p[2] == '\0') {
2778 while (new > lim) {
2779 STUNPUTC(new);
2780 if (new[-1] == '/')
2781 break;
2782 }
2783 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002784 }
2785 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002786 break;
2787 /* fall through */
2788 default:
2789 new = stack_putstr(p, new);
2790 USTPUTC('/', new);
2791 }
Denys Vlasenko24966162020-10-06 02:36:47 +02002792 p = strtok_r(NULL, "/", &cdcomppath);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002793 }
2794 if (new > lim)
2795 STUNPUTC(new);
2796 *new = 0;
2797 return stackblock();
2798}
2799
2800/*
2801 * Find out what the current directory is. If we already know the current
2802 * directory, this routine returns immediately.
2803 */
2804static char *
2805getpwd(void)
2806{
Denis Vlasenko01631112007-12-16 17:20:38 +00002807 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002808 return dir ? dir : nullstr;
2809}
2810
2811static void
2812setpwd(const char *val, int setold)
2813{
2814 char *oldcur, *dir;
2815
2816 oldcur = dir = curdir;
2817
2818 if (setold) {
2819 setvar("OLDPWD", oldcur, VEXPORT);
2820 }
2821 INT_OFF;
2822 if (physdir != nullstr) {
2823 if (physdir != oldcur)
2824 free(physdir);
2825 physdir = nullstr;
2826 }
2827 if (oldcur == val || !val) {
2828 char *s = getpwd();
2829 physdir = s;
2830 if (!val)
2831 dir = s;
2832 } else
2833 dir = ckstrdup(val);
2834 if (oldcur != dir && oldcur != nullstr) {
2835 free(oldcur);
2836 }
2837 curdir = dir;
2838 INT_ON;
2839 setvar("PWD", dir, VEXPORT);
2840}
2841
2842static void hashcd(void);
2843
2844/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002845 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002846 * know that the current directory has changed.
2847 */
2848static int
2849docd(const char *dest, int flags)
2850{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002851 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002852 int err;
2853
2854 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2855
2856 INT_OFF;
2857 if (!(flags & CD_PHYSICAL)) {
2858 dir = updatepwd(dest);
2859 if (dir)
2860 dest = dir;
2861 }
2862 err = chdir(dest);
2863 if (err)
2864 goto out;
2865 setpwd(dir, 1);
2866 hashcd();
2867 out:
2868 INT_ON;
2869 return err;
2870}
2871
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002872static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002873cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002874{
2875 const char *dest;
2876 const char *path;
2877 const char *p;
2878 char c;
2879 struct stat statb;
2880 int flags;
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01002881 int len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002882
2883 flags = cdopt();
2884 dest = *argptr;
2885 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002886 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002887 else if (LONE_DASH(dest)) {
2888 dest = bltinlookup("OLDPWD");
2889 flags |= CD_PRINT;
2890 }
2891 if (!dest)
2892 dest = nullstr;
2893 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002894 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002895 if (*dest == '.') {
2896 c = dest[1];
2897 dotdot:
2898 switch (c) {
2899 case '\0':
2900 case '/':
2901 goto step6;
2902 case '.':
2903 c = dest[2];
2904 if (c != '.')
2905 goto dotdot;
2906 }
2907 }
2908 if (!*dest)
2909 dest = ".";
2910 path = bltinlookup("CDPATH");
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01002911 while (p = path, (len = padvance(&path, dest)) >= 0) {
2912 c = *p;
2913 p = stalloc(len);
2914
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002915 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2916 if (c && c != ':')
2917 flags |= CD_PRINT;
2918 docd:
2919 if (!docd(p, flags))
2920 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002921 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002922 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002923 }
2924
2925 step6:
2926 p = dest;
2927 goto docd;
2928
2929 err:
Johannes Schindelin687aac02017-08-22 22:03:22 +02002930 ash_msg_and_raise_perror("can't cd to %s", dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002931 /* NOTREACHED */
2932 out:
2933 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002934 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002935 return 0;
2936}
2937
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002938static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002939pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002940{
2941 int flags;
2942 const char *dir = curdir;
2943
2944 flags = cdopt();
2945 if (flags) {
2946 if (physdir == nullstr)
2947 setpwd(dir, 0);
2948 dir = physdir;
2949 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002950 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002951 return 0;
2952}
2953
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002954
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002955/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002956
Denis Vlasenko834dee72008-10-07 09:18:30 +00002957
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002958#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002959
Eric Andersenc470f442003-07-28 09:56:35 +00002960/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002961#define CWORD 0 /* character is nothing special */
2962#define CNL 1 /* newline character */
2963#define CBACK 2 /* a backslash character */
2964#define CSQUOTE 3 /* single quote */
2965#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002966#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002967#define CBQUOTE 6 /* backwards single quote */
2968#define CVAR 7 /* a dollar sign */
2969#define CENDVAR 8 /* a '}' character */
2970#define CLP 9 /* a left paren in arithmetic */
2971#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002972#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002973#define CCTL 12 /* like CWORD, except it must be escaped */
2974#define CSPCL 13 /* these terminate a word */
2975#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002976
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002977#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002978#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002979# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002980#endif
2981
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002982#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002983
Denys Vlasenko0b883582016-12-23 16:49:07 +01002984#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002985# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002986#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002987# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002988#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002989static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002990#if ENABLE_ASH_ALIAS
2991 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2992#endif
2993 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2994 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2995 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2996 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2997 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2998 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2999 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
3000 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
3001 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
3002 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
3003 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003004#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003005 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
3006 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
3007 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
3008#endif
3009#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00003010};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003011/* Constants below must match table above */
3012enum {
3013#if ENABLE_ASH_ALIAS
3014 CSPCL_CIGN_CIGN_CIGN , /* 0 */
3015#endif
3016 CSPCL_CWORD_CWORD_CWORD , /* 1 */
3017 CNL_CNL_CNL_CNL , /* 2 */
3018 CWORD_CCTL_CCTL_CWORD , /* 3 */
3019 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
3020 CVAR_CVAR_CWORD_CVAR , /* 5 */
3021 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
3022 CSPCL_CWORD_CWORD_CLP , /* 7 */
3023 CSPCL_CWORD_CWORD_CRP , /* 8 */
3024 CBACK_CBACK_CCTL_CBACK , /* 9 */
3025 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
3026 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
3027 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
3028 CWORD_CWORD_CWORD_CWORD , /* 13 */
3029 CCTL_CCTL_CCTL_CCTL , /* 14 */
3030};
Eric Andersen2870d962001-07-02 17:27:21 +00003031
Denys Vlasenkocd716832009-11-28 22:14:02 +01003032/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
3033 * caller must ensure proper cast on it if c is *char_ptr!
3034 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003035#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003036
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003037static int
3038SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003039{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02003040 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
3041 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
3042 /*
3043 * This causes '/' to be prepended with CTLESC in dquoted string,
3044 * making "./file"* treated incorrectly because we feed
3045 * ".\/file*" string to glob(), confusing it (see expandmeta func).
3046 * The "homegrown" glob implementation is okay with that,
3047 * but glibc one isn't. With '/' always treated as CWORD,
3048 * both work fine.
3049 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01003050# if ENABLE_ASH_ALIAS
3051 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00003052 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02003053 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00003054 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
3055 11, 3 /* "}~" */
3056 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01003057# else
3058 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00003059 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02003060 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00003061 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
3062 10, 2 /* "}~" */
3063 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01003064# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003065 const char *s;
3066 int indx;
3067
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003068 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003069 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01003070# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003071 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003072 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003073 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01003074# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003075 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003076 /* Cast is purely for paranoia here,
3077 * just in case someone passed signed char to us */
3078 if ((unsigned char)c >= CTL_FIRST
3079 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003080 ) {
3081 return CCTL;
3082 }
3083 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003084 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003085 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003086 indx = syntax_index_table[s - spec_symbls];
3087 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003088 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003089}
3090
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003091#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003092
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02003093static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003094 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01003095 /* 0 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 1 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 2 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 3 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 4 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 5 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 6 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 7 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 8 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3105 /* 10 "\n" */ CNL_CNL_CNL_CNL,
3106 /* 11 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 12 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 13 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 14 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 15 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 16 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 17 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 18 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 19 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 20 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 21 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 22 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 23 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 24 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 25 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 26 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 27 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 28 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 29 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 30 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 31 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
3128 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
3129 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3130 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
3131 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
3132 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
3133 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
3134 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3135 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
3136 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
3137 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
3138 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
3139 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
3140 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
3141 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02003142/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3143 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003144 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
3145 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
3146 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
3147 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
3148 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
3149 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
3150 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
3151 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
3152 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
3153 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
3154 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
3155 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
3156 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
3157 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
3158 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
3159 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
3160 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
3161 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
3162 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
3163 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
3164 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
3165 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
3166 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
3167 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
3168 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
3169 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
3170 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
3171 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
3172 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
3173 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
3174 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
3175 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
3176 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3177 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3178 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3179 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3180 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3181 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3182 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3183 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3184 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3185 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3186 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3187 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3188 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3189 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3190 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3191 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3192 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3193 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3194 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3195 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3196 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3197 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3198 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3199 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3200 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3201 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3202 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3203 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3204 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3205 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3206 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3207 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3208 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3209 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3210 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3211 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3212 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3213 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3214 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3215 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3216 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3217 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3218 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3219 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3220 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3221 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3222 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3223 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3224 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3225 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3226 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3227 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3228 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3229 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3230 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3231 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3232 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3233 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3234 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3235 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3236 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3237 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3238 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3239 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3240 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3241 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3242 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3243 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3244 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3245 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3246 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3247 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3248 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3249 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3250 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3251 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3252 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3253 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3254 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3255 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3256 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3257 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3258 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3259 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3260 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3261 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3262 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3263 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3264 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3265 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3266 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3267 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3268 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3269 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3270 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3271 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3272 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3273 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3274 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3275 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3276 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3277 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3278 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3279 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3280 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3281 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3282 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3283 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3284 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3285 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3286 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3287 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3288 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3289 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3290 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3291 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3292 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3293 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3294 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3295 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3296 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3297 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3298 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3299 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3300 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3301 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3302 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3303 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3304 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3305 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3306 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3307 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3308 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3309 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3310 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3311 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3312 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3313 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3314 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3315 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3316 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3317 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3318 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3319 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3320 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3321 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3322 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3323 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3324 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3325 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3326 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3327 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3328 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3329 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3330 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3331 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3332 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3333 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3334 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3335 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3336 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3337 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3338 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3339 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3340 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3341 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3342 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3343 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3344 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3345 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3346 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3347 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3348 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3349 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3350 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3351 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003352 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003353# if ENABLE_ASH_ALIAS
3354 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3355# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003356};
3357
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003358#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003359# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003360#else /* debug version, caught one signed char bug */
3361# define SIT(c, syntax) \
3362 ({ \
3363 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3364 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003365 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003366 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3367 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3368 })
3369#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003370
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003371#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003372
Eric Andersen2870d962001-07-02 17:27:21 +00003373
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003374/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003375
Denis Vlasenko131ae172007-02-18 13:00:19 +00003376#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003377
3378#define ALIASINUSE 1
3379#define ALIASDEAD 2
3380
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003381struct alias {
3382 struct alias *next;
3383 char *name;
3384 char *val;
3385 int flag;
3386};
3387
Denis Vlasenko01631112007-12-16 17:20:38 +00003388
3389static struct alias **atab; // [ATABSIZE];
3390#define INIT_G_alias() do { \
3391 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3392} while (0)
3393
Eric Andersen2870d962001-07-02 17:27:21 +00003394
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003395static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003396__lookupalias(const char *name)
3397{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003398 unsigned int hashval;
3399 struct alias **app;
3400 const char *p;
3401 unsigned int ch;
3402
3403 p = name;
3404
3405 ch = (unsigned char)*p;
3406 hashval = ch << 4;
3407 while (ch) {
3408 hashval += ch;
3409 ch = (unsigned char)*++p;
3410 }
3411 app = &atab[hashval % ATABSIZE];
3412
3413 for (; *app; app = &(*app)->next) {
3414 if (strcmp(name, (*app)->name) == 0) {
3415 break;
3416 }
3417 }
3418
3419 return app;
3420}
3421
3422static struct alias *
3423lookupalias(const char *name, int check)
3424{
3425 struct alias *ap = *__lookupalias(name);
3426
3427 if (check && ap && (ap->flag & ALIASINUSE))
3428 return NULL;
3429 return ap;
3430}
3431
3432static struct alias *
3433freealias(struct alias *ap)
3434{
3435 struct alias *next;
3436
3437 if (ap->flag & ALIASINUSE) {
3438 ap->flag |= ALIASDEAD;
3439 return ap;
3440 }
3441
3442 next = ap->next;
3443 free(ap->name);
3444 free(ap->val);
3445 free(ap);
3446 return next;
3447}
Eric Andersencb57d552001-06-28 07:25:16 +00003448
Eric Andersenc470f442003-07-28 09:56:35 +00003449static void
3450setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003451{
3452 struct alias *ap, **app;
3453
3454 app = __lookupalias(name);
3455 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003456 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003457 if (ap) {
3458 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003459 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003460 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003461 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003462 ap->flag &= ~ALIASDEAD;
3463 } else {
3464 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003465 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003466 ap->name = ckstrdup(name);
3467 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003468 /*ap->flag = 0; - ckzalloc did it */
3469 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003470 *app = ap;
3471 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003472 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003473}
3474
Eric Andersenc470f442003-07-28 09:56:35 +00003475static int
3476unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003477{
Eric Andersencb57d552001-06-28 07:25:16 +00003478 struct alias **app;
3479
3480 app = __lookupalias(name);
3481
3482 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003483 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003484 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003485 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003486 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003487 }
3488
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003489 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003490}
3491
Eric Andersenc470f442003-07-28 09:56:35 +00003492static void
3493rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003494{
Eric Andersencb57d552001-06-28 07:25:16 +00003495 struct alias *ap, **app;
3496 int i;
3497
Denis Vlasenkob012b102007-02-19 22:43:01 +00003498 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003499 for (i = 0; i < ATABSIZE; i++) {
3500 app = &atab[i];
3501 for (ap = *app; ap; ap = *app) {
3502 *app = freealias(*app);
3503 if (ap == *app) {
3504 app = &ap->next;
3505 }
3506 }
3507 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003508 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003509}
3510
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003511static void
3512printalias(const struct alias *ap)
3513{
3514 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3515}
3516
Eric Andersencb57d552001-06-28 07:25:16 +00003517/*
3518 * TODO - sort output
3519 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003520static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003521aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003522{
3523 char *n, *v;
3524 int ret = 0;
3525 struct alias *ap;
3526
Denis Vlasenko68404f12008-03-17 09:00:54 +00003527 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003528 int i;
3529
Denis Vlasenko68404f12008-03-17 09:00:54 +00003530 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003531 for (ap = atab[i]; ap; ap = ap->next) {
3532 printalias(ap);
3533 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003534 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003535 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003536 }
3537 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003538 v = strchr(n+1, '=');
3539 if (v == NULL) { /* n+1: funny ksh stuff */
3540 ap = *__lookupalias(n);
3541 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003542 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003543 ret = 1;
3544 } else
3545 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003546 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003547 *v++ = '\0';
3548 setalias(n, v);
3549 }
3550 }
3551
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003552 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003553}
3554
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003555static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003556unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003557{
3558 int i;
3559
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003560 while (nextopt("a") != '\0') {
3561 rmaliases();
3562 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003563 }
3564 for (i = 0; *argptr; argptr++) {
3565 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003566 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003567 i = 1;
3568 }
3569 }
3570
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003571 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003572}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003573
Denis Vlasenko131ae172007-02-18 13:00:19 +00003574#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003575
Eric Andersenc470f442003-07-28 09:56:35 +00003576
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003577/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003578#define FORK_FG 0
3579#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003580#define FORK_NOJOB 2
3581
3582/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003583#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3584#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3585#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003586#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003587
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003588/*
3589 * A job structure contains information about a job. A job is either a
3590 * single process or a set of processes contained in a pipeline. In the
3591 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3592 * array of pids.
3593 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003594struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003595 pid_t ps_pid; /* process id */
3596 int ps_status; /* last process status from wait() */
3597 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003598};
3599
3600struct job {
3601 struct procstat ps0; /* status of process */
Denys Vlasenko966f0872019-03-27 15:51:42 +01003602 struct procstat *ps; /* status of processes when more than one */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003603#if JOBS
3604 int stopstatus; /* status of a stopped job */
3605#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003606 unsigned nprocs; /* number of processes */
3607
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003608#define JOBRUNNING 0 /* at least one proc running */
3609#define JOBSTOPPED 1 /* all procs are stopped */
3610#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003611 unsigned
3612 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003613#if JOBS
3614 sigint: 1, /* job was killed by SIGINT */
3615 jobctl: 1, /* job running under job control */
3616#endif
3617 waited: 1, /* true if this entry has been waited for */
3618 used: 1, /* true if this entry is in used */
3619 changed: 1; /* true if status has changed */
3620 struct job *prev_job; /* previous job */
3621};
3622
Denis Vlasenko68404f12008-03-17 09:00:54 +00003623static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003624static int forkshell(struct job *, union node *, int);
3625static int waitforjob(struct job *);
3626
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003627#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003628enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003629#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003630#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003631static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003632static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003633#endif
3634
3635/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003636 * Ignore a signal.
3637 */
3638static void
3639ignoresig(int signo)
3640{
3641 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3642 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3643 /* No, need to do it */
3644 signal(signo, SIG_IGN);
3645 }
3646 sigmode[signo - 1] = S_HARD_IGN;
3647}
3648
3649/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003650 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003651 */
3652static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003653signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003654{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003655 if (signo == SIGCHLD) {
3656 got_sigchld = 1;
3657 if (!trap[SIGCHLD])
3658 return;
3659 }
3660
Denis Vlasenko4b875702009-03-19 13:30:04 +00003661 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003662 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003663
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003664 if (signo == SIGINT && !trap[SIGINT]) {
3665 if (!suppress_int) {
3666 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003667 raise_interrupt(); /* does not return */
3668 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003669 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003670 }
3671}
3672
3673/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003674 * Set the signal handler for the specified signal. The routine figures
3675 * out what it should be set to.
3676 */
3677static void
3678setsignal(int signo)
3679{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003680 char *t;
3681 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003682 struct sigaction act;
3683
3684 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003685 new_act = S_DFL;
3686 if (t != NULL) { /* trap for this sig is set */
3687 new_act = S_CATCH;
3688 if (t[0] == '\0') /* trap is "": ignore this sig */
3689 new_act = S_IGN;
3690 }
3691
3692 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003693 switch (signo) {
3694 case SIGINT:
3695 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003696 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003697 break;
3698 case SIGQUIT:
3699#if DEBUG
3700 if (debug)
3701 break;
3702#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003703 /* man bash:
3704 * "In all cases, bash ignores SIGQUIT. Non-builtin
3705 * commands run by bash have signal handlers
3706 * set to the values inherited by the shell
3707 * from its parent". */
3708 new_act = S_IGN;
3709 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003710 case SIGTERM:
3711 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003712 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003713 break;
3714#if JOBS
3715 case SIGTSTP:
3716 case SIGTTOU:
3717 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003718 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003719 break;
3720#endif
3721 }
3722 }
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003723 /* if !rootshell, we reset SIGQUIT to DFL,
3724 * whereas we have to restore it to what shell got on entry.
3725 * This is handled by the fact that if signal was IGNored on entry,
3726 * then cur_act is S_HARD_IGN and we never change its sigaction
3727 * (see code below).
3728 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003729
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003730 if (signo == SIGCHLD)
3731 new_act = S_CATCH;
3732
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003733 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003734 cur_act = *t;
3735 if (cur_act == 0) {
3736 /* current setting is not yet known */
3737 if (sigaction(signo, NULL, &act)) {
3738 /* pretend it worked; maybe we should give a warning,
3739 * but other shells don't. We don't alter sigmode,
3740 * so we retry every time.
3741 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003742 return;
3743 }
3744 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003745 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003746 if (mflag
3747 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3748 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003749 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003750 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003751 }
Denys Vlasenko0f14f412017-08-06 20:06:19 +02003752 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3753 /* installing SIG_DFL over SIG_DFL is a no-op */
3754 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3755 *t = S_DFL;
3756 return;
3757 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003758 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003759 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003760 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003761
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003762 *t = new_act;
3763
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003764 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003765 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003766 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003767 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003768 break;
3769 case S_IGN:
3770 act.sa_handler = SIG_IGN;
3771 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003772 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003773 /* flags and mask matter only if !DFL and !IGN, but we do it
3774 * for all cases for more deterministic behavior:
3775 */
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003776 act.sa_flags = 0; //TODO: why not SA_RESTART?
Ian Wienand89b3cba2011-04-16 20:05:14 +02003777 sigfillset(&act.sa_mask);
3778
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003779 sigaction_set(signo, &act);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003780}
3781
3782/* mode flags for set_curjob */
3783#define CUR_DELETE 2
3784#define CUR_RUNNING 1
3785#define CUR_STOPPED 0
3786
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003787#if JOBS
3788/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003789static int initialpgrp; //references:2
3790static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003791#endif
3792/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003793static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003794/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003795static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003796/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003797static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003798
Denys Vlasenko098b7132017-01-11 19:59:03 +01003799#if 0
3800/* Bash has a feature: it restores termios after a successful wait for
3801 * a foreground job which had at least one stopped or sigkilled member.
3802 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3803 * properly restoring tty state. Should we do this too?
3804 * A reproducer: ^Z an interactive python:
3805 *
3806 * # python
3807 * Python 2.7.12 (...)
3808 * >>> ^Z
3809 * { python leaves tty in -icanon -echo state. We do survive that... }
3810 * [1]+ Stopped python
3811 * { ...however, next program (python #2) does not survive it well: }
3812 * # python
3813 * Python 2.7.12 (...)
3814 * >>> Traceback (most recent call last):
3815 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3816 * File "<stdin>", line 1, in <module>
3817 * NameError: name 'qwerty' is not defined
3818 *
3819 * The implementation below is modeled on bash code and seems to work.
3820 * However, I'm not sure we should do this. For one: what if I'd fg
3821 * the stopped python instead? It'll be confused by "restored" tty state.
3822 */
3823static struct termios shell_tty_info;
3824static void
3825get_tty_state(void)
3826{
3827 if (rootshell && ttyfd >= 0)
3828 tcgetattr(ttyfd, &shell_tty_info);
3829}
3830static void
3831set_tty_state(void)
3832{
3833 /* if (rootshell) - caller ensures this */
3834 if (ttyfd >= 0)
3835 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3836}
3837static int
3838job_signal_status(struct job *jp)
3839{
3840 int status;
3841 unsigned i;
3842 struct procstat *ps = jp->ps;
3843 for (i = 0; i < jp->nprocs; i++) {
3844 status = ps[i].ps_status;
3845 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3846 return status;
3847 }
3848 return 0;
3849}
3850static void
3851restore_tty_if_stopped_or_signaled(struct job *jp)
3852{
3853//TODO: check what happens if we come from waitforjob() in expbackq()
3854 if (rootshell) {
3855 int s = job_signal_status(jp);
3856 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3857 set_tty_state();
3858 }
3859}
3860#else
3861# define get_tty_state() ((void)0)
3862# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3863#endif
3864
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003865static void
3866set_curjob(struct job *jp, unsigned mode)
3867{
3868 struct job *jp1;
3869 struct job **jpp, **curp;
3870
3871 /* first remove from list */
3872 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003873 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003874 jp1 = *jpp;
3875 if (jp1 == jp)
3876 break;
3877 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003878 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003879 *jpp = jp1->prev_job;
3880
3881 /* Then re-insert in correct position */
3882 jpp = curp;
3883 switch (mode) {
3884 default:
3885#if DEBUG
3886 abort();
3887#endif
3888 case CUR_DELETE:
3889 /* job being deleted */
3890 break;
3891 case CUR_RUNNING:
3892 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003893 * put after all stopped jobs.
3894 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003895 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003896 jp1 = *jpp;
3897#if JOBS
3898 if (!jp1 || jp1->state != JOBSTOPPED)
3899#endif
3900 break;
3901 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003902 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003903 /* FALLTHROUGH */
3904#if JOBS
3905 case CUR_STOPPED:
3906#endif
3907 /* newly stopped job - becomes curjob */
3908 jp->prev_job = *jpp;
3909 *jpp = jp;
3910 break;
3911 }
3912}
3913
3914#if JOBS || DEBUG
3915static int
3916jobno(const struct job *jp)
3917{
3918 return jp - jobtab + 1;
3919}
3920#endif
3921
3922/*
3923 * Convert a job name to a job structure.
3924 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003925#if !JOBS
3926#define getjob(name, getctl) getjob(name)
3927#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003928static struct job *
3929getjob(const char *name, int getctl)
3930{
3931 struct job *jp;
3932 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003933 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003934 unsigned num;
3935 int c;
3936 const char *p;
3937 char *(*match)(const char *, const char *);
3938
3939 jp = curjob;
3940 p = name;
3941 if (!p)
3942 goto currentjob;
3943
3944 if (*p != '%')
3945 goto err;
3946
3947 c = *++p;
3948 if (!c)
3949 goto currentjob;
3950
3951 if (!p[1]) {
3952 if (c == '+' || c == '%') {
3953 currentjob:
3954 err_msg = "No current job";
3955 goto check;
3956 }
3957 if (c == '-') {
3958 if (jp)
3959 jp = jp->prev_job;
3960 err_msg = "No previous job";
3961 check:
3962 if (!jp)
3963 goto err;
3964 goto gotit;
3965 }
3966 }
3967
3968 if (is_number(p)) {
3969 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003970 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003971 jp = jobtab + num - 1;
3972 if (jp->used)
3973 goto gotit;
3974 goto err;
3975 }
3976 }
3977
3978 match = prefix;
3979 if (*p == '?') {
3980 match = strstr;
3981 p++;
3982 }
3983
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003984 found = NULL;
3985 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003986 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003987 if (found)
3988 goto err;
3989 found = jp;
3990 err_msg = "%s: ambiguous";
3991 }
3992 jp = jp->prev_job;
3993 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003994 if (!found)
3995 goto err;
3996 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003997
3998 gotit:
3999#if JOBS
4000 err_msg = "job %s not created under job control";
4001 if (getctl && jp->jobctl == 0)
4002 goto err;
4003#endif
4004 return jp;
4005 err:
4006 ash_msg_and_raise_error(err_msg, name);
4007}
4008
4009/*
4010 * Mark a job structure as unused.
4011 */
4012static void
4013freejob(struct job *jp)
4014{
4015 struct procstat *ps;
4016 int i;
4017
4018 INT_OFF;
4019 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004020 if (ps->ps_cmd != nullstr)
4021 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004022 }
4023 if (jp->ps != &jp->ps0)
4024 free(jp->ps);
4025 jp->used = 0;
4026 set_curjob(jp, CUR_DELETE);
4027 INT_ON;
4028}
4029
4030#if JOBS
4031static void
4032xtcsetpgrp(int fd, pid_t pgrp)
4033{
4034 if (tcsetpgrp(fd, pgrp))
Ron Yorstonbe366e52017-07-27 13:53:39 +01004035 ash_msg_and_raise_perror("can't set tty process group");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004036}
4037
4038/*
4039 * Turn job control on and off.
4040 *
4041 * Note: This code assumes that the third arg to ioctl is a character
4042 * pointer, which is true on Berkeley systems but not System V. Since
4043 * System V doesn't have job control yet, this isn't a problem now.
4044 *
4045 * Called with interrupts off.
4046 */
4047static void
4048setjobctl(int on)
4049{
4050 int fd;
4051 int pgrp;
4052
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004053 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004054 return;
4055 if (on) {
4056 int ofd;
4057 ofd = fd = open(_PATH_TTY, O_RDWR);
4058 if (fd < 0) {
4059 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
4060 * That sometimes helps to acquire controlling tty.
4061 * Obviously, a workaround for bugs when someone
4062 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00004063 fd = 2;
4064 while (!isatty(fd))
4065 if (--fd < 0)
4066 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004067 }
Denys Vlasenko64774602016-10-26 15:24:30 +02004068 /* fd is a tty at this point */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02004069 fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02004070 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00004071 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004072 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02004073 goto out; /* F_DUPFD failed */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02004074 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
4075 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01004076 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077 pgrp = tcgetpgrp(fd);
4078 if (pgrp < 0) {
4079 out:
4080 ash_msg("can't access tty; job control turned off");
4081 mflag = on = 0;
4082 goto close;
4083 }
4084 if (pgrp == getpgrp())
4085 break;
4086 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01004087 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004088 initialpgrp = pgrp;
4089
4090 setsignal(SIGTSTP);
4091 setsignal(SIGTTOU);
4092 setsignal(SIGTTIN);
4093 pgrp = rootpid;
4094 setpgid(0, pgrp);
4095 xtcsetpgrp(fd, pgrp);
4096 } else {
4097 /* turning job control off */
4098 fd = ttyfd;
4099 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004100 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004101 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004102 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004103 setpgid(0, pgrp);
4104 setsignal(SIGTSTP);
4105 setsignal(SIGTTOU);
4106 setsignal(SIGTTIN);
4107 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00004108 if (fd >= 0)
4109 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110 fd = -1;
4111 }
4112 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004113 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004114}
4115
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004116static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004117killcmd(int argc, char **argv)
4118{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004119 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004120 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004121 do {
4122 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004123 /*
4124 * "kill %N" - job kill
4125 * Converting to pgrp / pid kill
4126 */
4127 struct job *jp;
4128 char *dst;
4129 int j, n;
4130
4131 jp = getjob(argv[i], 0);
4132 /*
4133 * In jobs started under job control, we signal
4134 * entire process group by kill -PGRP_ID.
4135 * This happens, f.e., in interactive shell.
4136 *
4137 * Otherwise, we signal each child via
4138 * kill PID1 PID2 PID3.
4139 * Testcases:
4140 * sh -c 'sleep 1|sleep 1 & kill %1'
4141 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4142 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4143 */
4144 n = jp->nprocs; /* can't be 0 (I hope) */
4145 if (jp->jobctl)
4146 n = 1;
4147 dst = alloca(n * sizeof(int)*4);
4148 argv[i] = dst;
4149 for (j = 0; j < n; j++) {
4150 struct procstat *ps = &jp->ps[j];
4151 /* Skip non-running and not-stopped members
4152 * (i.e. dead members) of the job
4153 */
4154 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4155 continue;
4156 /*
4157 * kill_main has matching code to expect
4158 * leading space. Needed to not confuse
4159 * negative pids with "kill -SIGNAL_NO" syntax
4160 */
4161 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4162 }
4163 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004164 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004165 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004166 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004167 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004168}
4169
4170static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01004171showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004172{
Denys Vlasenko285ad152009-12-04 23:02:27 +01004173 struct procstat *ps;
4174 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004175
Denys Vlasenko285ad152009-12-04 23:02:27 +01004176 psend = jp->ps + jp->nprocs;
4177 for (ps = jp->ps + 1; ps < psend; ps++)
4178 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004179 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180 flush_stdout_stderr();
4181}
4182
4183
4184static int
4185restartjob(struct job *jp, int mode)
4186{
4187 struct procstat *ps;
4188 int i;
4189 int status;
4190 pid_t pgid;
4191
4192 INT_OFF;
4193 if (jp->state == JOBDONE)
4194 goto out;
4195 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004196 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004197 if (mode == FORK_FG) {
4198 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004199 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004200 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004201 killpg(pgid, SIGCONT);
4202 ps = jp->ps;
4203 i = jp->nprocs;
4204 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004205 if (WIFSTOPPED(ps->ps_status)) {
4206 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004207 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004208 ps++;
4209 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004210 out:
4211 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4212 INT_ON;
4213 return status;
4214}
4215
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004216static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004217fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004218{
4219 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004220 int mode;
4221 int retval;
4222
4223 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4224 nextopt(nullstr);
4225 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004226 do {
4227 jp = getjob(*argv, 1);
4228 if (mode == FORK_BG) {
4229 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004230 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004231 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004232 out1str(jp->ps[0].ps_cmd);
4233 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004234 retval = restartjob(jp, mode);
4235 } while (*argv && *++argv);
4236 return retval;
4237}
4238#endif
4239
4240static int
Denys Vlasenko2bad3a32020-02-16 18:23:43 +01004241sprint_status48(char *os, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004242{
Denys Vlasenko2bad3a32020-02-16 18:23:43 +01004243 char *s = os;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004244 int st;
4245
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004246 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004247#if JOBS
4248 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004249 st = WSTOPSIG(status);
4250 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004251#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004252 st = WTERMSIG(status);
4253 if (sigonly) {
4254 if (st == SIGINT || st == SIGPIPE)
4255 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004256#if JOBS
4257 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004258 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004259#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004260 }
4261 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004262//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denys Vlasenko2bad3a32020-02-16 18:23:43 +01004263 //s = stpncpy(s, strsignal(st), 32); //not all libc have stpncpy()
4264 s += fmtstr(s, 32, strsignal(st));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004265 if (WCOREDUMP(status)) {
Denys Vlasenko2bad3a32020-02-16 18:23:43 +01004266 s = stpcpy(s, " (core dumped)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004267 }
4268 } else if (!sigonly) {
4269 st = WEXITSTATUS(status);
Denys Vlasenko2bad3a32020-02-16 18:23:43 +01004270 s += fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004271 }
4272 out:
Denys Vlasenko2bad3a32020-02-16 18:23:43 +01004273 return s - os;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004274}
4275
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004276#define DOWAIT_NONBLOCK 0
4277#define DOWAIT_BLOCK 1
4278#define DOWAIT_BLOCK_OR_SIG 2
Ron Yorstone48559e2019-03-31 09:27:09 +01004279#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004280# define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */
4281#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004282
4283static int
Denys Vlasenko91e11eb2020-09-29 20:35:55 +02004284waitproc(int block, int *status)
4285{
4286 sigset_t oldmask;
4287 int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
4288 int err;
4289
4290#if JOBS
4291 if (doing_jobctl)
4292 flags |= WUNTRACED;
4293#endif
4294
4295 do {
4296 got_sigchld = 0;
4297 do
4298 err = waitpid(-1, status, flags);
4299 while (err < 0 && errno == EINTR);
4300
4301 if (err || (err = -!block))
4302 break;
4303
4304 sigfillset(&oldmask);
4305 sigprocmask2(SIG_SETMASK, &oldmask); /* mask is updated */
4306 while (!got_sigchld && !pending_sig)
4307 sigsuspend(&oldmask);
4308 sigprocmask(SIG_SETMASK, &oldmask, NULL);
4309 //simpler, but unsafe: a signal can set pending_sig after check, but before pause():
4310 //while (!got_sigchld && !pending_sig)
4311 // pause();
4312
4313 } while (got_sigchld);
4314
4315 return err;
4316}
4317
4318static int
Denys Vlasenko47eb9792020-02-18 15:37:43 +01004319waitone(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004320{
4321 int pid;
4322 int status;
4323 struct job *jp;
Denys Vlasenko91e11eb2020-09-29 20:35:55 +02004324 struct job *thisjob = NULL;
Ron Yorstone48559e2019-03-31 09:27:09 +01004325#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004326 bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
4327 block = (block & ~DOWAIT_JOBSTATUS);
4328#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004329
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004330 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004331
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004332 /* It's wrong to call waitpid() outside of INT_OFF region:
4333 * signal can arrive just after syscall return and handler can
4334 * longjmp away, losing stop/exit notification processing.
4335 * Thus, for "jobs" builtin, and for waiting for a fg job,
4336 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4337 *
4338 * However, for "wait" builtin it is wrong to simply call waitpid()
4339 * in INT_OFF region: "wait" needs to wait for any running job
4340 * to change state, but should exit on any trap too.
4341 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004342 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004343 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004344 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004345 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004346 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004347 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004348 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004349 */
4350 INT_OFF;
Denys Vlasenko91e11eb2020-09-29 20:35:55 +02004351 pid = waitproc(block, &status);
4352 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004353 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004354 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004355
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004356 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004357 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004358 struct procstat *ps;
4359 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004360 if (jp->state == JOBDONE)
4361 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004362 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004363 ps = jp->ps;
4364 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004365 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004366 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004367 TRACE(("Job %d: changing status of proc %d "
4368 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004369 jobno(jp), pid, ps->ps_status, status));
4370 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004371 thisjob = jp;
4372 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004373 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004374 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004375#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004376 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004377 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004378 if (WIFSTOPPED(ps->ps_status)) {
4379 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004380 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004381 }
4382#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004383 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004384 if (!thisjob)
4385 continue;
4386
4387 /* Found the job where one of its processes changed its state.
4388 * Is there at least one live and running process in this job? */
4389 if (jobstate != JOBRUNNING) {
4390 /* No. All live processes in the job are stopped
4391 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4392 */
4393 thisjob->changed = 1;
4394 if (thisjob->state != jobstate) {
4395 TRACE(("Job %d: changing state from %d to %d\n",
4396 jobno(thisjob), thisjob->state, jobstate));
4397 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004398#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004399 if (jobstate == JOBSTOPPED)
4400 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004401#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004402 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004403 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004404 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004405 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004406 /* The process wasn't found in job list */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004407 out:
4408 INT_ON;
4409
Ron Yorstone48559e2019-03-31 09:27:09 +01004410#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004411 if (want_jobexitstatus) {
4412 pid = -1;
4413 if (thisjob && thisjob->state == JOBDONE)
4414 pid = thisjob->ps[thisjob->nprocs - 1].ps_status;
4415 }
4416#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004417 if (thisjob && thisjob == job) {
4418 char s[48 + 1];
4419 int len;
4420
Denys Vlasenko9c541002015-10-07 15:44:36 +02004421 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004422 if (len) {
4423 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004424 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004425 out2str(s);
4426 }
4427 }
4428 return pid;
4429}
4430
Denys Vlasenko47eb9792020-02-18 15:37:43 +01004431static int
4432dowait(int block, struct job *jp)
4433{
Denys Vlasenko8d5f4652020-09-29 16:44:46 +02004434 smallint gotchld = *(volatile smallint *)&got_sigchld;
4435 int rpid;
4436 int pid;
Denys Vlasenko47eb9792020-02-18 15:37:43 +01004437
Denys Vlasenko8d5f4652020-09-29 16:44:46 +02004438 if (jp && jp->state != JOBRUNNING)
4439 block = DOWAIT_NONBLOCK;
4440
4441 if (block == DOWAIT_NONBLOCK && !gotchld)
4442 return 1;
4443
4444 rpid = 1;
4445
4446 do {
Denys Vlasenko47eb9792020-02-18 15:37:43 +01004447 pid = waitone(block, jp);
Denys Vlasenko8d5f4652020-09-29 16:44:46 +02004448 rpid &= !!pid;
Denys Vlasenko47eb9792020-02-18 15:37:43 +01004449
Denys Vlasenko8d5f4652020-09-29 16:44:46 +02004450 if (!pid || (jp && jp->state != JOBRUNNING))
4451 block = DOWAIT_NONBLOCK;
4452 } while (pid >= 0);
4453
4454 return rpid;
Denys Vlasenko47eb9792020-02-18 15:37:43 +01004455}
4456
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004457#if JOBS
4458static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004459showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004460{
4461 struct procstat *ps;
4462 struct procstat *psend;
4463 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004464 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004465 char s[16 + 16 + 48];
4466 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004467
4468 ps = jp->ps;
4469
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004470 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004471 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004472 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004473 return;
4474 }
4475
4476 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004477 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004478
4479 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004480 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004481 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004482 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004483
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004484 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004485 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004486
4487 psend = ps + jp->nprocs;
4488
4489 if (jp->state == JOBRUNNING) {
4490 strcpy(s + col, "Running");
4491 col += sizeof("Running") - 1;
4492 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004493 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004494 if (jp->state == JOBSTOPPED)
4495 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004496 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004497 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004498 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004499
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004500 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4501 * or prints several "PID | <cmdN>" lines,
4502 * depending on SHOW_PIDS bit.
4503 * We do not print status of individual processes
4504 * between PID and <cmdN>. bash does it, but not very well:
4505 * first line shows overall job status, not process status,
4506 * making it impossible to know 1st process status.
4507 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004508 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004509 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004510 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004511 s[0] = '\0';
4512 col = 33;
4513 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004514 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004515 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004516 fprintf(out, "%s%*c%s%s",
4517 s,
4518 33 - col >= 0 ? 33 - col : 0, ' ',
4519 ps == jp->ps ? "" : "| ",
4520 ps->ps_cmd
4521 );
4522 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004523 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004524
4525 jp->changed = 0;
4526
4527 if (jp->state == JOBDONE) {
4528 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4529 freejob(jp);
4530 }
4531}
4532
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004533/*
4534 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4535 * statuses have changed since the last call to showjobs.
4536 */
4537static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004538showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004539{
4540 struct job *jp;
4541
Denys Vlasenko883cea42009-07-11 15:31:59 +02004542 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004543
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004544 /* Handle all finished jobs */
Denys Vlasenko47eb9792020-02-18 15:37:43 +01004545 dowait(DOWAIT_NONBLOCK, NULL);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004546
4547 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004548 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004549 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004550 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004551 }
4552}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004553
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004554static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004555jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004556{
4557 int mode, m;
4558
4559 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004560 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004561 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004562 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004563 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004564 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004565 }
4566
4567 argv = argptr;
4568 if (*argv) {
4569 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004570 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004571 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004572 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004573 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004574 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004575
4576 return 0;
4577}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004578#endif /* JOBS */
4579
Michael Abbott359da5e2009-12-04 23:03:29 +01004580/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004581static int
4582getstatus(struct job *job)
4583{
4584 int status;
4585 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004586 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004587
Michael Abbott359da5e2009-12-04 23:03:29 +01004588 /* Fetch last member's status */
4589 ps = job->ps + job->nprocs - 1;
4590 status = ps->ps_status;
4591 if (pipefail) {
4592 /* "set -o pipefail" mode: use last _nonzero_ status */
4593 while (status == 0 && --ps >= job->ps)
4594 status = ps->ps_status;
4595 }
4596
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004597 retval = WEXITSTATUS(status);
4598 if (!WIFEXITED(status)) {
4599#if JOBS
4600 retval = WSTOPSIG(status);
4601 if (!WIFSTOPPED(status))
4602#endif
4603 {
4604 /* XXX: limits number of signals */
4605 retval = WTERMSIG(status);
4606#if JOBS
4607 if (retval == SIGINT)
4608 job->sigint = 1;
4609#endif
4610 }
4611 retval += 128;
4612 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004613 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004614 jobno(job), job->nprocs, status, retval));
4615 return retval;
4616}
4617
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004618static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004619waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004620{
4621 struct job *job;
4622 int retval;
4623 struct job *jp;
Ron Yorstone48559e2019-03-31 09:27:09 +01004624#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004625 int status;
4626 char one = nextopt("n");
4627#else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004628 nextopt(nullstr);
Denys Vlasenko966f0872019-03-27 15:51:42 +01004629#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004630 retval = 0;
4631
4632 argv = argptr;
Denys Vlasenko966f0872019-03-27 15:51:42 +01004633 if (!argv[0]) {
4634 /* wait for all jobs / one job if -n */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004635 for (;;) {
4636 jp = curjob;
Ron Yorstone48559e2019-03-31 09:27:09 +01004637#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004638 if (one && !jp)
4639 /* exitcode of "wait -n" with nothing to wait for is 127, not 0 */
4640 retval = 127;
4641#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004642 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004643 if (!jp) /* no running procs */
4644 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004645 if (jp->state == JOBRUNNING)
4646 break;
4647 jp->waited = 1;
4648 jp = jp->prev_job;
4649 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004650 /* man bash:
4651 * "When bash is waiting for an asynchronous command via
4652 * the wait builtin, the reception of a signal for which a trap
4653 * has been set will cause the wait builtin to return immediately
4654 * with an exit status greater than 128, immediately after which
4655 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004656 */
Ron Yorstone48559e2019-03-31 09:27:09 +01004657#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004658 status = dowait(DOWAIT_BLOCK_OR_SIG | DOWAIT_JOBSTATUS, NULL);
4659#else
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004660 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenko966f0872019-03-27 15:51:42 +01004661#endif
Denys Vlasenko47eb9792020-02-18 15:37:43 +01004662 /* if child sends us a signal *and immediately exits*,
4663 * dowait() returns pid > 0. Check this case,
4664 * not "if (dowait() < 0)"!
4665 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004666 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004667 goto sigout;
Ron Yorstone48559e2019-03-31 09:27:09 +01004668#if BASH_WAIT_N
Denys Vlasenko966f0872019-03-27 15:51:42 +01004669 if (one) {
4670 /* wait -n waits for one _job_, not one _process_.
4671 * date; sleep 3 & sleep 2 | sleep 1 & wait -n; date
4672 * should wait for 2 seconds. Not 1 or 3.
4673 */
4674 if (status != -1 && !WIFSTOPPED(status)) {
4675 retval = WEXITSTATUS(status);
4676 if (WIFSIGNALED(status))
4677 retval = WTERMSIG(status) + 128;
4678 goto ret;
4679 }
4680 }
4681#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004682 }
4683 }
4684
4685 retval = 127;
4686 do {
4687 if (**argv != '%') {
4688 pid_t pid = number(*argv);
4689 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004690 while (1) {
4691 if (!job)
4692 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004693 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004694 break;
4695 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004696 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004697 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004698 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004699 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004700 /* loop until process terminated or stopped */
Denys Vlasenko91e11eb2020-09-29 20:35:55 +02004701 dowait(DOWAIT_BLOCK_OR_SIG, job);
Denys Vlasenko47eb9792020-02-18 15:37:43 +01004702 if (pending_sig)
4703 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004704 job->waited = 1;
4705 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004706 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004707 } while (*++argv);
4708
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004709 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004710 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004711 sigout:
4712 retval = 128 + pending_sig;
4713 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004714}
4715
4716static struct job *
4717growjobtab(void)
4718{
4719 size_t len;
4720 ptrdiff_t offset;
4721 struct job *jp, *jq;
4722
4723 len = njobs * sizeof(*jp);
4724 jq = jobtab;
4725 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4726
4727 offset = (char *)jp - (char *)jq;
4728 if (offset) {
4729 /* Relocate pointers */
4730 size_t l = len;
4731
4732 jq = (struct job *)((char *)jq + l);
4733 while (l) {
4734 l -= sizeof(*jp);
4735 jq--;
4736#define joff(p) ((struct job *)((char *)(p) + l))
4737#define jmove(p) (p) = (void *)((char *)(p) + offset)
4738 if (joff(jp)->ps == &jq->ps0)
4739 jmove(joff(jp)->ps);
4740 if (joff(jp)->prev_job)
4741 jmove(joff(jp)->prev_job);
4742 }
4743 if (curjob)
4744 jmove(curjob);
4745#undef joff
4746#undef jmove
4747 }
4748
4749 njobs += 4;
4750 jobtab = jp;
4751 jp = (struct job *)((char *)jp + len);
4752 jq = jp + 3;
4753 do {
4754 jq->used = 0;
4755 } while (--jq >= jp);
4756 return jp;
4757}
4758
4759/*
4760 * Return a new job structure.
4761 * Called with interrupts off.
4762 */
4763static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004764makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004765{
4766 int i;
4767 struct job *jp;
4768
4769 for (i = njobs, jp = jobtab; ; jp++) {
4770 if (--i < 0) {
4771 jp = growjobtab();
4772 break;
4773 }
4774 if (jp->used == 0)
4775 break;
4776 if (jp->state != JOBDONE || !jp->waited)
4777 continue;
4778#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004779 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004780 continue;
4781#endif
4782 freejob(jp);
4783 break;
4784 }
4785 memset(jp, 0, sizeof(*jp));
4786#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004787 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004788 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004789 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004790 jp->jobctl = 1;
4791#endif
4792 jp->prev_job = curjob;
4793 curjob = jp;
4794 jp->used = 1;
4795 jp->ps = &jp->ps0;
4796 if (nprocs > 1) {
4797 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4798 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004799 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004800 jobno(jp)));
4801 return jp;
4802}
4803
4804#if JOBS
4805/*
4806 * Return a string identifying a command (to be printed by the
4807 * jobs command).
4808 */
4809static char *cmdnextc;
4810
4811static void
4812cmdputs(const char *s)
4813{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004814 static const char vstype[VSTYPE + 1][3] = {
4815 "", "}", "-", "+", "?", "=",
4816 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004817 IF_BASH_SUBSTR(, ":")
4818 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004819 };
4820
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004821 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004822 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004823 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004824 unsigned char c;
4825 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004826 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004827
Denys Vlasenko46a14772009-12-10 21:27:13 +01004828 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004829 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4830 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004831 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004832 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004833 switch (c) {
4834 case CTLESC:
4835 c = *p++;
4836 break;
4837 case CTLVAR:
4838 subtype = *p++;
4839 if ((subtype & VSTYPE) == VSLENGTH)
4840 str = "${#";
4841 else
4842 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004843 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004844 case CTLENDVAR:
Denys Vlasenko3f4847b2020-02-16 19:06:42 +01004845 str = "\"}";
4846 str += !(quoted & 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004847 quoted >>= 1;
4848 subtype = 0;
4849 goto dostr;
4850 case CTLBACKQ:
4851 str = "$(...)";
4852 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004853#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004854 case CTLARI:
4855 str = "$((";
4856 goto dostr;
4857 case CTLENDARI:
4858 str = "))";
4859 goto dostr;
4860#endif
4861 case CTLQUOTEMARK:
4862 quoted ^= 1;
4863 c = '"';
4864 break;
4865 case '=':
4866 if (subtype == 0)
4867 break;
4868 if ((subtype & VSTYPE) != VSNORMAL)
4869 quoted <<= 1;
4870 str = vstype[subtype & VSTYPE];
4871 if (subtype & VSNUL)
4872 c = ':';
4873 else
4874 goto checkstr;
4875 break;
4876 case '\'':
4877 case '\\':
4878 case '"':
4879 case '$':
4880 /* These can only happen inside quotes */
4881 cc[0] = c;
4882 str = cc;
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004883//FIXME:
4884// $ true $$ &
4885// $ <cr>
4886// [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004887 c = '\\';
4888 break;
4889 default:
4890 break;
4891 }
4892 USTPUTC(c, nextc);
4893 checkstr:
4894 if (!str)
4895 continue;
4896 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004897 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004898 USTPUTC(c, nextc);
4899 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004900 } /* while *p++ not NUL */
4901
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004902 if (quoted & 1) {
4903 USTPUTC('"', nextc);
4904 }
4905 *nextc = 0;
4906 cmdnextc = nextc;
4907}
4908
4909/* cmdtxt() and cmdlist() call each other */
4910static void cmdtxt(union node *n);
4911
4912static void
4913cmdlist(union node *np, int sep)
4914{
4915 for (; np; np = np->narg.next) {
4916 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004917 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004918 cmdtxt(np);
4919 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004920 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004921 }
4922}
4923
4924static void
4925cmdtxt(union node *n)
4926{
4927 union node *np;
4928 struct nodelist *lp;
4929 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004930
4931 if (!n)
4932 return;
4933 switch (n->type) {
4934 default:
4935#if DEBUG
4936 abort();
4937#endif
4938 case NPIPE:
4939 lp = n->npipe.cmdlist;
4940 for (;;) {
4941 cmdtxt(lp->n);
4942 lp = lp->next;
4943 if (!lp)
4944 break;
4945 cmdputs(" | ");
4946 }
4947 break;
4948 case NSEMI:
4949 p = "; ";
4950 goto binop;
4951 case NAND:
4952 p = " && ";
4953 goto binop;
4954 case NOR:
4955 p = " || ";
4956 binop:
4957 cmdtxt(n->nbinary.ch1);
4958 cmdputs(p);
4959 n = n->nbinary.ch2;
4960 goto donode;
4961 case NREDIR:
4962 case NBACKGND:
4963 n = n->nredir.n;
4964 goto donode;
4965 case NNOT:
4966 cmdputs("!");
4967 n = n->nnot.com;
4968 donode:
4969 cmdtxt(n);
4970 break;
4971 case NIF:
4972 cmdputs("if ");
4973 cmdtxt(n->nif.test);
4974 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004975 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004976 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004977 cmdputs("; else ");
4978 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004979 } else {
4980 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004981 }
4982 p = "; fi";
4983 goto dotail;
4984 case NSUBSHELL:
4985 cmdputs("(");
4986 n = n->nredir.n;
4987 p = ")";
4988 goto dotail;
4989 case NWHILE:
4990 p = "while ";
4991 goto until;
4992 case NUNTIL:
4993 p = "until ";
4994 until:
4995 cmdputs(p);
4996 cmdtxt(n->nbinary.ch1);
4997 n = n->nbinary.ch2;
4998 p = "; done";
4999 dodo:
5000 cmdputs("; do ");
5001 dotail:
5002 cmdtxt(n);
5003 goto dotail2;
5004 case NFOR:
5005 cmdputs("for ");
5006 cmdputs(n->nfor.var);
5007 cmdputs(" in ");
5008 cmdlist(n->nfor.args, 1);
5009 n = n->nfor.body;
5010 p = "; done";
5011 goto dodo;
5012 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01005013 cmdputs(n->ndefun.text);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005014 p = "() { ... }";
5015 goto dotail2;
5016 case NCMD:
5017 cmdlist(n->ncmd.args, 1);
5018 cmdlist(n->ncmd.redirect, 0);
5019 break;
5020 case NARG:
5021 p = n->narg.text;
5022 dotail2:
5023 cmdputs(p);
5024 break;
5025 case NHERE:
5026 case NXHERE:
5027 p = "<<...";
5028 goto dotail2;
5029 case NCASE:
5030 cmdputs("case ");
5031 cmdputs(n->ncase.expr->narg.text);
5032 cmdputs(" in ");
5033 for (np = n->ncase.cases; np; np = np->nclist.next) {
5034 cmdtxt(np->nclist.pattern);
5035 cmdputs(") ");
5036 cmdtxt(np->nclist.body);
5037 cmdputs(";; ");
5038 }
5039 p = "esac";
5040 goto dotail2;
5041 case NTO:
5042 p = ">";
5043 goto redir;
5044 case NCLOBBER:
5045 p = ">|";
5046 goto redir;
5047 case NAPPEND:
5048 p = ">>";
5049 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005050#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005051 case NTO2:
5052#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005053 case NTOFD:
5054 p = ">&";
5055 goto redir;
5056 case NFROM:
5057 p = "<";
5058 goto redir;
5059 case NFROMFD:
5060 p = "<&";
5061 goto redir;
5062 case NFROMTO:
5063 p = "<>";
5064 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005065 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005066 cmdputs(p);
5067 if (n->type == NTOFD || n->type == NFROMFD) {
Denys Vlasenkod0fff912017-07-31 14:32:18 +02005068 if (n->ndup.dupfd >= 0)
5069 cmdputs(utoa(n->ndup.dupfd));
5070 else
5071 cmdputs("-");
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005072 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005073 }
5074 n = n->nfile.fname;
5075 goto donode;
5076 }
5077}
5078
5079static char *
5080commandtext(union node *n)
5081{
5082 char *name;
5083
5084 STARTSTACKSTR(cmdnextc);
5085 cmdtxt(n);
5086 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02005087 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005088 return ckstrdup(name);
5089}
5090#endif /* JOBS */
5091
5092/*
5093 * Fork off a subshell. If we are doing job control, give the subshell its
5094 * own process group. Jp is a job structure that the job is to be added to.
5095 * N is the command that will be evaluated by the child. Both jp and n may
5096 * be NULL. The mode parameter can be one of the following:
5097 * FORK_FG - Fork off a foreground process.
5098 * FORK_BG - Fork off a background process.
5099 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
5100 * process group even if job control is on.
5101 *
5102 * When job control is turned off, background processes have their standard
5103 * input redirected to /dev/null (except for the second and later processes
5104 * in a pipeline).
5105 *
5106 * Called with interrupts off.
5107 */
5108/*
5109 * Clear traps on a fork.
5110 */
5111static void
5112clear_traps(void)
5113{
5114 char **tp;
5115
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02005116 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005117 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005118 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02005119 if (trap_ptr == trap)
5120 free(*tp);
5121 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005122 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02005123 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005124 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005125 }
5126 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02005127 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02005128 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005129}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005130
5131/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005132static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00005133
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005134/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02005135/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02005136static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005137forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005138{
5139 int oldlvl;
5140
5141 TRACE(("Child shell %d\n", getpid()));
5142 oldlvl = shlvl;
5143 shlvl++;
5144
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005145 /* man bash: "Non-builtin commands run by bash have signal handlers
5146 * set to the values inherited by the shell from its parent".
5147 * Do we do it correctly? */
5148
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005149 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02005150
5151 if (mode == FORK_NOJOB /* is it `xxx` ? */
5152 && n && n->type == NCMD /* is it single cmd? */
5153 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01005154 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005155 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5156 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5157 ) {
5158 TRACE(("Trap hack\n"));
5159 /* Awful hack for `trap` or $(trap).
5160 *
5161 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5162 * contains an example where "trap" is executed in a subshell:
5163 *
5164 * save_traps=$(trap)
5165 * ...
5166 * eval "$save_traps"
5167 *
5168 * Standard does not say that "trap" in subshell shall print
5169 * parent shell's traps. It only says that its output
5170 * must have suitable form, but then, in the above example
5171 * (which is not supposed to be normative), it implies that.
5172 *
5173 * bash (and probably other shell) does implement it
5174 * (traps are reset to defaults, but "trap" still shows them),
5175 * but as a result, "trap" logic is hopelessly messed up:
5176 *
5177 * # trap
5178 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
5179 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
5180 * # true | trap <--- trap is in subshell - no output (ditto)
5181 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
5182 * trap -- 'echo Ho' SIGWINCH
5183 * # echo `(trap)` <--- in subshell in subshell - output
5184 * trap -- 'echo Ho' SIGWINCH
5185 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
5186 * trap -- 'echo Ho' SIGWINCH
5187 *
5188 * The rules when to forget and when to not forget traps
5189 * get really complex and nonsensical.
5190 *
5191 * Our solution: ONLY bare $(trap) or `trap` is special.
5192 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005193 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02005194 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005195 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02005196 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02005197 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005198#if JOBS
5199 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005200 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005201 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005202 pid_t pgrp;
5203
5204 if (jp->nprocs == 0)
5205 pgrp = getpid();
5206 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005207 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005208 /* this can fail because we are doing it in the parent also */
5209 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005210 if (mode == FORK_FG)
5211 xtcsetpgrp(ttyfd, pgrp);
5212 setsignal(SIGTSTP);
5213 setsignal(SIGTTOU);
5214 } else
5215#endif
5216 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005217 /* man bash: "When job control is not in effect,
5218 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005219 ignoresig(SIGINT);
5220 ignoresig(SIGQUIT);
5221 if (jp->nprocs == 0) {
5222 close(0);
5223 if (open(bb_dev_null, O_RDONLY) != 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005224 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005225 }
5226 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005227 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005228 if (iflag) { /* why if iflag only? */
5229 setsignal(SIGINT);
5230 setsignal(SIGTERM);
5231 }
5232 /* man bash:
5233 * "In all cases, bash ignores SIGQUIT. Non-builtin
5234 * commands run by bash have signal handlers
5235 * set to the values inherited by the shell
5236 * from its parent".
5237 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005238 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005239 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005240#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02005241 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01005242 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005243 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005244 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005245 /* "jobs": we do not want to clear job list for it,
5246 * instead we remove only _its_ own_ job from job list.
5247 * This makes "jobs .... | cat" more useful.
5248 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005249 freejob(curjob);
5250 return;
5251 }
5252#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005253 for (jp = curjob; jp; jp = jp->prev_job)
5254 freejob(jp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005255}
5256
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005257/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005258#if !JOBS
5259#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5260#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005261static void
5262forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5263{
5264 TRACE(("In parent shell: child = %d\n", pid));
Denys Vlasenko47eb9792020-02-18 15:37:43 +01005265 if (!jp) /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005266 return;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005267#if JOBS
5268 if (mode != FORK_NOJOB && jp->jobctl) {
5269 int pgrp;
5270
5271 if (jp->nprocs == 0)
5272 pgrp = pid;
5273 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005274 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005275 /* This can fail because we are doing it in the child also */
5276 setpgid(pid, pgrp);
5277 }
5278#endif
5279 if (mode == FORK_BG) {
5280 backgndpid = pid; /* set $! */
5281 set_curjob(jp, CUR_RUNNING);
5282 }
5283 if (jp) {
5284 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005285 ps->ps_pid = pid;
5286 ps->ps_status = -1;
5287 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005288#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005289 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005290 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005291#endif
5292 }
5293}
5294
Denys Vlasenko70392332016-10-27 02:31:55 +02005295/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005296static int
5297forkshell(struct job *jp, union node *n, int mode)
5298{
5299 int pid;
5300
5301 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5302 pid = fork();
5303 if (pid < 0) {
5304 TRACE(("Fork failed, errno=%d", errno));
5305 if (jp)
5306 freejob(jp);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005307 ash_msg_and_raise_perror("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005308 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005309 if (pid == 0) {
5310 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005311 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005312 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005313 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005314 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005315 return pid;
5316}
5317
5318/*
5319 * Wait for job to finish.
5320 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005321 * Under job control we have the problem that while a child process
5322 * is running interrupts generated by the user are sent to the child
5323 * but not to the shell. This means that an infinite loop started by
5324 * an interactive user may be hard to kill. With job control turned off,
5325 * an interactive user may place an interactive program inside a loop.
5326 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005327 * these interrupts to also abort the loop. The approach we take here
5328 * is to have the shell ignore interrupt signals while waiting for a
5329 * foreground process to terminate, and then send itself an interrupt
5330 * signal if the child process was terminated by an interrupt signal.
5331 * Unfortunately, some programs want to do a bit of cleanup and then
5332 * exit on interrupt; unless these processes terminate themselves by
5333 * sending a signal to themselves (instead of calling exit) they will
5334 * confuse this approach.
5335 *
5336 * Called with interrupts off.
5337 */
5338static int
5339waitforjob(struct job *jp)
5340{
5341 int st;
5342
Denys Vlasenkod81af722020-02-18 14:28:30 +01005343 TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005344
Denys Vlasenko47eb9792020-02-18 15:37:43 +01005345 /* In non-interactive shells, we _can_ get
5346 * a keyboard signal here and be EINTRed, but we just loop
5347 * inside dowait(), waiting for command to complete.
5348 *
5349 * man bash:
5350 * "If bash is waiting for a command to complete and receives
5351 * a signal for which a trap has been set, the trap
5352 * will not be executed until the command completes."
5353 *
5354 * Reality is that even if trap is not set, bash
5355 * will not act on the signal until command completes.
5356 * Try this. sleep5intoff.c:
5357 * #include <signal.h>
5358 * #include <unistd.h>
5359 * int main() {
5360 * sigset_t set;
5361 * sigemptyset(&set);
5362 * sigaddset(&set, SIGINT);
5363 * sigaddset(&set, SIGQUIT);
5364 * sigprocmask(SIG_BLOCK, &set, NULL);
5365 * sleep(5);
5366 * return 0;
5367 * }
5368 * $ bash -c './sleep5intoff; echo hi'
5369 * ^C^C^C^C <--- pressing ^C once a second
5370 * $ _
5371 * $ bash -c './sleep5intoff; echo hi'
5372 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5373 * $ _
5374 */
5375 dowait(jp ? DOWAIT_BLOCK : DOWAIT_NONBLOCK, jp);
5376 if (!jp)
Denys Vlasenko97edfc42020-02-18 14:37:56 +01005377 return exitstatus;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005378
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005379 st = getstatus(jp);
5380#if JOBS
5381 if (jp->jobctl) {
5382 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005383 restore_tty_if_stopped_or_signaled(jp);
5384
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005385 /*
5386 * This is truly gross.
5387 * If we're doing job control, then we did a TIOCSPGRP which
5388 * caused us (the shell) to no longer be in the controlling
5389 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5390 * intuit from the subprocess exit status whether a SIGINT
5391 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5392 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005393 if (jp->sigint) /* TODO: do the same with all signals */
5394 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005395 }
5396 if (jp->state == JOBDONE)
5397#endif
5398 freejob(jp);
5399 return st;
5400}
5401
5402/*
5403 * return 1 if there are stopped jobs, otherwise 0
5404 */
5405static int
5406stoppedjobs(void)
5407{
5408 struct job *jp;
5409 int retval;
5410
5411 retval = 0;
5412 if (job_warning)
5413 goto out;
5414 jp = curjob;
5415 if (jp && jp->state == JOBSTOPPED) {
5416 out2str("You have stopped jobs.\n");
5417 job_warning = 2;
5418 retval++;
5419 }
5420 out:
5421 return retval;
5422}
5423
5424
Denys Vlasenko70392332016-10-27 02:31:55 +02005425/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005426 * Code for dealing with input/output redirection.
5427 */
5428
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005429#undef EMPTY
5430#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005431#define EMPTY -2 /* marks an unused slot in redirtab */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005432#define CLOSED -1 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005433
5434/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005435 * Handle here documents. Normally we fork off a process to write the
5436 * data to a pipe. If the document is short, we can stuff the data in
5437 * the pipe without forking.
5438 */
5439/* openhere needs this forward reference */
Denys Vlasenkoc2058ec2020-02-22 20:25:03 +01005440static void expandhere(union node *arg);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005441static int
5442openhere(union node *redir)
5443{
Denys Vlasenkoc2058ec2020-02-22 20:25:03 +01005444 char *p;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005445 int pip[2];
5446 size_t len = 0;
5447
5448 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005449 ash_msg_and_raise_perror("can't create pipe");
Denys Vlasenkoc2058ec2020-02-22 20:25:03 +01005450
5451 p = redir->nhere.doc->narg.text;
5452 if (redir->type == NXHERE) {
5453 expandhere(redir->nhere.doc);
5454 p = stackblock();
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005455 }
Denys Vlasenkoc2058ec2020-02-22 20:25:03 +01005456
5457 len = strlen(p);
5458 if (len <= PIPE_BUF) {
5459 xwrite(pip[1], p, len);
5460 goto out;
5461 }
5462
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005463 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005464 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005465 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005466 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5467 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5468 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5469 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005470 signal(SIGPIPE, SIG_DFL);
Denys Vlasenkoc2058ec2020-02-22 20:25:03 +01005471 xwrite(pip[1], p, len);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005472 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005473 }
5474 out:
5475 close(pip[1]);
5476 return pip[0];
5477}
5478
5479static int
5480openredirect(union node *redir)
5481{
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005482 struct stat sb;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005483 char *fname;
5484 int f;
5485
5486 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005487/* Can't happen, our single caller does this itself */
5488// case NTOFD:
5489// case NFROMFD:
5490// return -1;
5491 case NHERE:
5492 case NXHERE:
5493 return openhere(redir);
5494 }
5495
5496 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5497 * allocated space. Do it only when we know it is safe.
5498 */
5499 fname = redir->nfile.expfname;
5500
5501 switch (redir->nfile.type) {
5502 default:
5503#if DEBUG
5504 abort();
5505#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005506 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005507 f = open(fname, O_RDONLY);
5508 if (f < 0)
5509 goto eopen;
5510 break;
5511 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005512 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005513 if (f < 0)
5514 goto ecreate;
5515 break;
5516 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005517#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005518 case NTO2:
5519#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005520 /* Take care of noclobber mode. */
5521 if (Cflag) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005522 if (stat(fname, &sb) < 0) {
5523 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5524 if (f < 0)
5525 goto ecreate;
5526 } else if (!S_ISREG(sb.st_mode)) {
5527 f = open(fname, O_WRONLY, 0666);
5528 if (f < 0)
5529 goto ecreate;
Denys Vlasenko355ec352018-04-02 13:34:57 +02005530 if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005531 close(f);
5532 errno = EEXIST;
5533 goto ecreate;
5534 }
5535 } else {
5536 errno = EEXIST;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005537 goto ecreate;
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005538 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005539 break;
5540 }
5541 /* FALLTHROUGH */
5542 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005543 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5544 if (f < 0)
5545 goto ecreate;
5546 break;
5547 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005548 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5549 if (f < 0)
5550 goto ecreate;
5551 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005552 }
5553
5554 return f;
5555 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005556 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005557 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005558 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005559}
5560
5561/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005562 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005563 */
5564static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005565savefd(int from)
5566{
5567 int newfd;
5568 int err;
5569
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005570 newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02005571 err = newfd < 0 ? errno : 0;
5572 if (err != EBADF) {
5573 if (err)
Ron Yorstonbe366e52017-07-27 13:53:39 +01005574 ash_msg_and_raise_perror("%d", from);
Denys Vlasenko64774602016-10-26 15:24:30 +02005575 close(from);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005576 if (F_DUPFD_CLOEXEC == F_DUPFD)
5577 close_on_exec_on(newfd);
Denys Vlasenko64774602016-10-26 15:24:30 +02005578 }
5579
5580 return newfd;
5581}
5582static int
5583dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005584{
5585 int newfd;
5586
Denys Vlasenko64774602016-10-26 15:24:30 +02005587 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005588 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005589 /* Happens when source fd is not open: try "echo >&99" */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005590 ash_msg_and_raise_perror("%d", from);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005591 }
5592 return newfd;
5593}
Denys Vlasenko035486c2017-07-31 04:09:19 +02005594static int
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005595dup_CLOEXEC(int fd, int avoid_fd)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005596{
5597 int newfd;
5598 repeat:
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005599 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5600 if (newfd >= 0) {
5601 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005602 close_on_exec_on(newfd);
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005603 } else { /* newfd < 0 */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005604 if (errno == EBUSY)
5605 goto repeat;
5606 if (errno == EINTR)
5607 goto repeat;
5608 }
5609 return newfd;
5610}
5611static int
5612xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5613{
5614 int newfd;
5615 repeat:
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005616 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005617 if (newfd < 0) {
5618 if (errno == EBUSY)
5619 goto repeat;
5620 if (errno == EINTR)
5621 goto repeat;
5622 /* fd was not open? */
5623 if (errno == EBADF)
5624 return fd;
5625 ash_msg_and_raise_perror("%d", newfd);
5626 }
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005627 if (F_DUPFD_CLOEXEC == F_DUPFD)
5628 close_on_exec_on(newfd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005629 close(fd);
5630 return newfd;
5631}
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005632
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005633/* Struct def and variable are moved down to the first usage site */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005634struct squirrel {
5635 int orig_fd;
5636 int moved_to;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005637};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005638struct redirtab {
5639 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005640 int pair_count;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005641 struct squirrel two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005642};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005643#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005644
Denys Vlasenko035486c2017-07-31 04:09:19 +02005645static void
5646add_squirrel_closed(struct redirtab *sq, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005647{
5648 int i;
5649
Denys Vlasenko035486c2017-07-31 04:09:19 +02005650 if (!sq)
5651 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005652
Denys Vlasenko035486c2017-07-31 04:09:19 +02005653 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5654 /* If we collide with an already moved fd... */
5655 if (fd == sq->two_fd[i].orig_fd) {
5656 /* Examples:
5657 * "echo 3>FILE 3>&- 3>FILE"
5658 * "echo 3>&- 3>FILE"
5659 * No need for last redirect to insert
5660 * another "need to close 3" indicator.
5661 */
5662 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5663 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005664 }
5665 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005666 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5667 sq->two_fd[i].orig_fd = fd;
5668 sq->two_fd[i].moved_to = CLOSED;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005669}
5670
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005671static int
Denys Vlasenko035486c2017-07-31 04:09:19 +02005672save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005673{
Denys Vlasenko035486c2017-07-31 04:09:19 +02005674 int i, new_fd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005675
Denys Vlasenko035486c2017-07-31 04:09:19 +02005676 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5677 avoid_fd = 9;
5678
5679#if JOBS
5680 if (fd == ttyfd) {
5681 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5682 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5683 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5684 return 1; /* "we closed fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005685 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005686#endif
5687 /* Are we called from redirect(0)? E.g. redirect
5688 * in a forked child. No need to save fds,
5689 * we aren't going to use them anymore, ok to trash.
5690 */
5691 if (!sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005692 return 0;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005693
5694 /* If this one of script's fds? */
5695 if (fd != 0) {
5696 struct parsefile *pf = g_parsefile;
5697 while (pf) {
5698 /* We skip fd == 0 case because of the following:
5699 * $ ash # running ash interactively
5700 * $ . ./script.sh
5701 * and in script.sh: "exec 9>&0".
5702 * Even though top-level pf_fd _is_ 0,
5703 * it's still ok to use it: "read" builtin uses it,
5704 * why should we cripple "exec" builtin?
5705 */
5706 if (fd == pf->pf_fd) {
5707 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5708 return 1; /* "we closed fd" */
5709 }
5710 pf = pf->prev;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005711 }
5712 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005713
5714 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5715
5716 /* First: do we collide with some already moved fds? */
5717 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5718 /* If we collide with an already moved fd... */
5719 if (fd == sq->two_fd[i].moved_to) {
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005720 new_fd = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005721 sq->two_fd[i].moved_to = new_fd;
5722 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5723 if (new_fd < 0) /* what? */
5724 xfunc_die();
5725 return 0; /* "we did not close fd" */
5726 }
5727 if (fd == sq->two_fd[i].orig_fd) {
5728 /* Example: echo Hello >/dev/null 1>&2 */
5729 TRACE(("redirect_fd %d: already moved\n", fd));
5730 return 0; /* "we did not close fd" */
5731 }
5732 }
5733
5734 /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005735 new_fd = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005736 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5737 if (new_fd < 0) {
5738 if (errno != EBADF)
5739 xfunc_die();
5740 /* new_fd = CLOSED; - already is -1 */
5741 }
5742 sq->two_fd[i].moved_to = new_fd;
5743 sq->two_fd[i].orig_fd = fd;
5744
5745 /* if we move stderr, let "set -x" code know */
5746 if (fd == preverrout_fd)
5747 preverrout_fd = new_fd;
5748
5749 return 0; /* "we did not close fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005750}
5751
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005752static int
5753internally_opened_fd(int fd, struct redirtab *sq)
5754{
5755 int i;
5756#if JOBS
5757 if (fd == ttyfd)
5758 return 1;
5759#endif
5760 /* If this one of script's fds? */
5761 if (fd != 0) {
5762 struct parsefile *pf = g_parsefile;
5763 while (pf) {
5764 if (fd == pf->pf_fd)
5765 return 1;
5766 pf = pf->prev;
5767 }
5768 }
5769
5770 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5771 if (fd == sq->two_fd[i].moved_to)
5772 return 1;
5773 }
5774 return 0;
5775}
5776
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005777/*
5778 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5779 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005780 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005781 */
5782/* flags passed to redirect */
5783#define REDIR_PUSH 01 /* save previous values of file descriptors */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005784static void
5785redirect(union node *redir, int flags)
5786{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005787 struct redirtab *sv;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005788
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005789 if (!redir)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005790 return;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005791
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005792 sv = NULL;
5793 INT_OFF;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005794 if (flags & REDIR_PUSH)
5795 sv = redirlist;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005796 do {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005797 int fd;
5798 int newfd;
5799 int close_fd;
5800 int closed;
5801
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005802 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005803 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005804 //bb_error_msg("doing %d > %d", fd, newfd);
5805 newfd = redir->ndup.dupfd;
5806 close_fd = -1;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005807 } else {
5808 newfd = openredirect(redir); /* always >= 0 */
5809 if (fd == newfd) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005810 /* open() gave us precisely the fd we wanted.
5811 * This means that this fd was not busy
5812 * (not opened to anywhere).
5813 * Remember to close it on restore:
5814 */
5815 add_squirrel_closed(sv, fd);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005816 continue;
5817 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005818 close_fd = newfd;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005819 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005820
5821 if (fd == newfd)
5822 continue;
5823
5824 /* if "N>FILE": move newfd to fd */
5825 /* if "N>&M": dup newfd to fd */
5826 /* if "N>&-": close fd (newfd is -1) */
5827
5828 IF_BASH_REDIR_OUTPUT(redirect_more:)
5829
5830 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5831 if (newfd == -1) {
5832 /* "N>&-" means "close me" */
5833 if (!closed) {
5834 /* ^^^ optimization: saving may already
5835 * have closed it. If not... */
5836 close(fd);
Denis Vlasenko22f74142008-07-24 22:34:43 +00005837 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005838 } else {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005839 /* if newfd is a script fd or saved fd, simulate EBADF */
5840 if (internally_opened_fd(newfd, sv)) {
5841 errno = EBADF;
5842 ash_msg_and_raise_perror("%d", newfd);
5843 }
Denys Vlasenko64774602016-10-26 15:24:30 +02005844 dup2_or_raise(newfd, fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005845 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5846 close(close_fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005847#if BASH_REDIR_OUTPUT
Denys Vlasenko035486c2017-07-31 04:09:19 +02005848 if (redir->nfile.type == NTO2 && fd == 1) {
5849 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5850 fd = 2;
5851 newfd = 1;
5852 close_fd = -1;
5853 goto redirect_more;
5854 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005855#endif
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005856 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005857 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005858 INT_ON;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005859
5860//dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5861#define REDIR_SAVEFD2 0
5862 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5863 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5864 // not only for calls with flags containing REDIR_SAVEFD2.
Denys Vlasenko035486c2017-07-31 04:09:19 +02005865 // We do this unconditionally (see save_fd_on_redirect()).
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005866 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5867 // preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005868}
5869
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005870static int
5871redirectsafe(union node *redir, int flags)
5872{
5873 int err;
5874 volatile int saveint;
5875 struct jmploc *volatile savehandler = exception_handler;
5876 struct jmploc jmploc;
5877
5878 SAVE_INT(saveint);
5879 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005880 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005881 if (!err) {
5882 exception_handler = &jmploc;
5883 redirect(redir, flags);
5884 }
5885 exception_handler = savehandler;
5886 if (err && exception_type != EXERROR)
5887 longjmp(exception_handler->loc, 1);
5888 RESTORE_INT(saveint);
5889 return err;
5890}
5891
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005892static struct redirtab*
5893pushredir(union node *redir)
5894{
5895 struct redirtab *sv;
5896 int i;
5897
5898 if (!redir)
5899 return redirlist;
5900
5901 i = 0;
5902 do {
5903 i++;
5904#if BASH_REDIR_OUTPUT
5905 if (redir->nfile.type == NTO2)
5906 i++;
5907#endif
5908 redir = redir->nfile.next;
5909 } while (redir);
5910
5911 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5912 sv->pair_count = i;
5913 while (--i >= 0)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005914 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005915 sv->next = redirlist;
5916 redirlist = sv;
5917 return sv->next;
5918}
5919
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005920/*
5921 * Undo the effects of the last redirection.
5922 */
5923static void
Denys Vlasenko035486c2017-07-31 04:09:19 +02005924popredir(int drop)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005925{
5926 struct redirtab *rp;
5927 int i;
5928
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005929 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005930 return;
5931 INT_OFF;
5932 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005933 for (i = 0; i < rp->pair_count; i++) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005934 int fd = rp->two_fd[i].orig_fd;
5935 int copy = rp->two_fd[i].moved_to;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005936 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005937 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005938 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005939 continue;
5940 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005941 if (copy != EMPTY) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005942 if (!drop) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005943 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005944 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005945 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005946 close(copy);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005947 }
5948 }
5949 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005950 free(rp);
5951 INT_ON;
5952}
5953
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005954static void
5955unwindredir(struct redirtab *stop)
5956{
5957 while (redirlist != stop)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005958 popredir(/*drop:*/ 0);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005959}
5960
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005961
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005962/* ============ Routines to expand arguments to commands
5963 *
5964 * We have to deal with backquotes, shell variables, and file metacharacters.
5965 */
5966
Denys Vlasenko0b883582016-12-23 16:49:07 +01005967#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005968static arith_t
5969ash_arith(const char *s)
5970{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005971 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005972 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005973
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005974 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005975 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005976 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005977
5978 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005979 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005980 if (math_state.errmsg)
5981 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005982 INT_ON;
5983
5984 return result;
5985}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005986#endif
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01005987#if BASH_SUBSTR
5988# if ENABLE_FEATURE_SH_MATH
5989static int substr_atoi(const char *s)
5990{
5991 arith_t t = ash_arith(s);
5992 if (sizeof(t) > sizeof(int)) {
5993 /* clamp very large or very large negative nums for ${v:N:M}:
5994 * else "${v:0:0x100000001}" would work as "${v:0:1}"
5995 */
5996 if (t > INT_MAX)
5997 t = INT_MAX;
5998 if (t < INT_MIN)
5999 t = INT_MIN;
6000 }
6001 return t;
6002}
6003# else
6004# define substr_atoi(s) number(s)
6005# endif
6006#endif
Denis Vlasenko448d30e2008-06-27 00:24:11 +00006007
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006008/*
6009 * expandarg flags
6010 */
6011#define EXP_FULL 0x1 /* perform word splitting & file globbing */
6012#define EXP_TILDE 0x2 /* do normal tilde expansion */
6013#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
6014#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02006015/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
6016 * POSIX says for this case:
6017 * Pathname expansion shall not be performed on the word by a
6018 * non-interactive shell; an interactive shell may perform it, but shall
6019 * do so only when the expansion would result in one word.
6020 * Currently, our code complies to the above rule by never globbing
6021 * redirection filenames.
6022 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
6023 * (this means that on a typical Linux distro, bash almost always
6024 * performs globbing, and thus diverges from what we do).
6025 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006026#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Denys Vlasenko216913c2018-04-02 12:35:04 +02006027#define EXP_VARTILDE2 0x20 /* expand tildes after colons only */
6028#define EXP_WORD 0x40 /* expand word in parameter expansion */
Denys Vlasenko440da972018-08-05 14:29:58 +02006029#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006030#define EXP_KEEPNUL 0x200 /* do not skip NUL characters */
Denys Vlasenko82331882020-02-24 10:02:50 +01006031#define EXP_DISCARD 0x400 /* discard result of expansion */
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006032
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006033/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006034 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006035 */
6036#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
6037#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006038#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
6039#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
6040
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006041/* Add CTLESC when necessary. */
Denys Vlasenko216913c2018-04-02 12:35:04 +02006042#define QUOTES_ESC (EXP_FULL | EXP_CASE)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006043
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006044/*
6045 * Structure specifying which parts of the string should be searched
6046 * for IFS characters.
6047 */
6048struct ifsregion {
6049 struct ifsregion *next; /* next region in list */
6050 int begoff; /* offset of start of region */
6051 int endoff; /* offset of end of region */
6052 int nulonly; /* search for nul bytes only */
6053};
6054
6055struct arglist {
6056 struct strlist *list;
6057 struct strlist **lastp;
6058};
6059
6060/* output of current string */
6061static char *expdest;
6062/* list of back quote expressions */
6063static struct nodelist *argbackq;
6064/* first struct in list of ifs regions */
6065static struct ifsregion ifsfirst;
6066/* last struct in list */
6067static struct ifsregion *ifslastp;
6068/* holds expanded arg list */
6069static struct arglist exparg;
6070
6071/*
Denys Vlasenko455e4222016-10-27 14:45:13 +02006072 * Break the argument string into pieces based upon IFS and add the
6073 * strings to the argument list. The regions of the string to be
6074 * searched for IFS characters have been stored by recordregion.
6075 */
6076static void
6077ifsbreakup(char *string, struct arglist *arglist)
6078{
6079 struct ifsregion *ifsp;
6080 struct strlist *sp;
6081 char *start;
6082 char *p;
6083 char *q;
6084 const char *ifs, *realifs;
6085 int ifsspc;
6086 int nulonly;
6087
6088 start = string;
6089 if (ifslastp != NULL) {
6090 ifsspc = 0;
6091 nulonly = 0;
6092 realifs = ifsset() ? ifsval() : defifs;
6093 ifsp = &ifsfirst;
6094 do {
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006095 int afternul;
6096
Denys Vlasenko455e4222016-10-27 14:45:13 +02006097 p = string + ifsp->begoff;
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006098 afternul = nulonly;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006099 nulonly = ifsp->nulonly;
6100 ifs = nulonly ? nullstr : realifs;
6101 ifsspc = 0;
6102 while (p < string + ifsp->endoff) {
6103 q = p;
6104 if ((unsigned char)*p == CTLESC)
6105 p++;
6106 if (!strchr(ifs, *p)) {
6107 p++;
6108 continue;
6109 }
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006110 if (!(afternul || nulonly))
Denys Vlasenko455e4222016-10-27 14:45:13 +02006111 ifsspc = (strchr(defifs, *p) != NULL);
6112 /* Ignore IFS whitespace at start */
6113 if (q == start && ifsspc) {
6114 p++;
6115 start = p;
6116 continue;
6117 }
6118 *q = '\0';
6119 sp = stzalloc(sizeof(*sp));
6120 sp->text = start;
6121 *arglist->lastp = sp;
6122 arglist->lastp = &sp->next;
6123 p++;
6124 if (!nulonly) {
6125 for (;;) {
6126 if (p >= string + ifsp->endoff) {
6127 break;
6128 }
6129 q = p;
6130 if ((unsigned char)*p == CTLESC)
6131 p++;
6132 if (strchr(ifs, *p) == NULL) {
6133 p = q;
6134 break;
6135 }
6136 if (strchr(defifs, *p) == NULL) {
6137 if (ifsspc) {
6138 p++;
6139 ifsspc = 0;
6140 } else {
6141 p = q;
6142 break;
6143 }
6144 } else
6145 p++;
6146 }
6147 }
6148 start = p;
6149 } /* while */
6150 ifsp = ifsp->next;
6151 } while (ifsp != NULL);
6152 if (nulonly)
6153 goto add;
6154 }
6155
6156 if (!*start)
6157 return;
6158
6159 add:
6160 sp = stzalloc(sizeof(*sp));
6161 sp->text = start;
6162 *arglist->lastp = sp;
6163 arglist->lastp = &sp->next;
6164}
6165
6166static void
6167ifsfree(void)
6168{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006169 struct ifsregion *p = ifsfirst.next;
6170
6171 if (!p)
6172 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006173
6174 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006175 do {
6176 struct ifsregion *ifsp;
6177 ifsp = p->next;
6178 free(p);
6179 p = ifsp;
6180 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02006181 ifsfirst.next = NULL;
6182 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006183 out:
6184 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006185}
6186
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006187static size_t
6188esclen(const char *start, const char *p)
6189{
6190 size_t esc = 0;
6191
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006192 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006193 esc++;
6194 }
6195 return esc;
6196}
6197
6198/*
6199 * Remove any CTLESC characters from a string.
6200 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006201#if !BASH_PATTERN_SUBST
6202#define rmescapes(str, flag, slash_position) \
6203 rmescapes(str, flag)
6204#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006205static char *
Denys Vlasenko740058b2018-01-09 17:01:00 +01006206rmescapes(char *str, int flag, int *slash_position)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006207{
Ron Yorston417622c2015-05-18 09:59:14 +02006208 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006209 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00006210
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006211 char *p, *q, *r;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006212 unsigned protect_against_glob;
6213 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006214
Denys Vlasenko740058b2018-01-09 17:01:00 +01006215 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006216 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006217 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006218
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006219 q = p;
6220 r = str;
6221 if (flag & RMESCAPE_ALLOC) {
6222 size_t len = p - str;
6223 size_t fulllen = len + strlen(p) + 1;
6224
6225 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02006226 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006227 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02006228 /* p and str may be invalidated by makestrspace */
6229 str = (char *)stackblock() + strloc;
6230 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006231 } else if (flag & RMESCAPE_HEAP) {
6232 r = ckmalloc(fulllen);
6233 } else {
6234 r = stalloc(fulllen);
6235 }
6236 q = r;
6237 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02006238 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006239 }
6240 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006241
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006242 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006243 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006244 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006245 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenko216913c2018-04-02 12:35:04 +02006246// Note: protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006247// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006248 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006249 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006250 continue;
6251 }
Denys Vlasenko216913c2018-04-02 12:35:04 +02006252 if (*p == '\\') {
6253 /* naked back slash */
6254 protect_against_glob = 0;
6255 goto copy;
6256 }
Ron Yorston549deab2015-05-18 09:57:51 +02006257 if ((unsigned char)*p == CTLESC) {
6258 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02006259#if DEBUG
6260 if (*p == '\0')
6261 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6262#endif
Ron Yorston549deab2015-05-18 09:57:51 +02006263 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006264 /*
6265 * We used to trust glob() and fnmatch() to eat
6266 * superfluous escapes (\z where z has no
6267 * special meaning anyway). But this causes
6268 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02006269 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006270 * getting encoded as "cf,CTLESC,81"
6271 * and here, converted to "cf,\,81" -
6272 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02006273 * of fnmatch() in unicode locales
6274 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006275 *
6276 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02006277 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006278 */
6279 if (*p == '*'
6280 || *p == '?'
6281 || *p == '['
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006282 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6283 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6284 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6285 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenko4142f012017-07-05 22:19:28 +02006286 /* Some libc support [^negate], that's why "^" also needs love */
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006287 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006288 ) {
6289 *q++ = '\\';
6290 }
Ron Yorston549deab2015-05-18 09:57:51 +02006291 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006292 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006293#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006294 else if (slash_position && p == str + *slash_position) {
6295 /* stop handling globbing */
6296 globbing = 0;
6297 *slash_position = q - r;
6298 slash_position = NULL;
Ron Yorston417622c2015-05-18 09:59:14 +02006299 }
6300#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006301 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006302 copy:
6303 *q++ = *p++;
6304 }
6305 *q = '\0';
6306 if (flag & RMESCAPE_GROW) {
6307 expdest = r;
6308 STADJUST(q - r + 1, expdest);
6309 }
6310 return r;
6311}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006312#define pmatch(a, b) !fnmatch((a), (b), 0)
6313
6314/*
6315 * Prepare a pattern for a expmeta (internal glob(3)) call.
6316 *
6317 * Returns an stalloced string.
6318 */
6319static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006320preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006321{
Denys Vlasenko740058b2018-01-09 17:01:00 +01006322 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006323}
6324
6325/*
6326 * Put a string on the stack.
6327 */
Denys Vlasenko45dd87a2020-02-21 16:30:44 +01006328static size_t
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006329memtodest(const char *p, size_t len, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006330{
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006331 int syntax = flags & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006332 char *q;
Denys Vlasenko45dd87a2020-02-21 16:30:44 +01006333 char *s;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006334
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006335 if (!len)
Denys Vlasenko45dd87a2020-02-21 16:30:44 +01006336 return 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006337
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006338 q = makestrspace(len * 2, expdest);
Denys Vlasenko45dd87a2020-02-21 16:30:44 +01006339 s = q;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006340
6341 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006342 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006343 if (c) {
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006344 if (flags & QUOTES_ESC) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006345 int n = SIT(c, syntax);
6346 if (n == CCTL
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006347 || ((flags & EXP_QUOTED) && n == CBACK)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006348 ) {
6349 USTPUTC(CTLESC, q);
6350 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006351 }
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006352 } else if (!(flags & EXP_KEEPNUL))
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006353 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006354 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006355 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006356
6357 expdest = q;
Denys Vlasenko45dd87a2020-02-21 16:30:44 +01006358 return q - s;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006359}
6360
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006361static size_t
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006362strtodest(const char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006363{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006364 size_t len = strlen(p);
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006365 memtodest(p, len, flags);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006366 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006367}
6368
6369/*
Denys Vlasenko45dd87a2020-02-21 16:30:44 +01006370 * Our own itoa().
6371 * cvtnum() is used even if math support is off (to prepare $? values and such).
6372 */
6373static int
6374cvtnum(arith_t num, int flags)
6375{
6376 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
6377 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
6378 int len = (sizeof(arith_t) >= 4) ? sizeof(arith_t) * 3 : sizeof(arith_t) * 3 + 2;
6379 char buf[len];
6380
6381 len = fmtstr(buf, len, ARITH_FMT, num);
6382 return memtodest(buf, len, flags);
6383}
6384
6385/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006386 * Record the fact that we have to scan this region of the
6387 * string for IFS characters.
6388 */
6389static void
6390recordregion(int start, int end, int nulonly)
6391{
6392 struct ifsregion *ifsp;
6393
6394 if (ifslastp == NULL) {
6395 ifsp = &ifsfirst;
6396 } else {
6397 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006398 ifsp = ckzalloc(sizeof(*ifsp));
6399 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006400 ifslastp->next = ifsp;
6401 INT_ON;
6402 }
6403 ifslastp = ifsp;
6404 ifslastp->begoff = start;
6405 ifslastp->endoff = end;
6406 ifslastp->nulonly = nulonly;
6407}
6408
6409static void
6410removerecordregions(int endoff)
6411{
6412 if (ifslastp == NULL)
6413 return;
6414
6415 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006416 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006417 struct ifsregion *ifsp;
6418 INT_OFF;
6419 ifsp = ifsfirst.next->next;
6420 free(ifsfirst.next);
6421 ifsfirst.next = ifsp;
6422 INT_ON;
6423 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006424 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006425 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006426 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006427 ifslastp = &ifsfirst;
6428 ifsfirst.endoff = endoff;
6429 }
6430 return;
6431 }
6432
6433 ifslastp = &ifsfirst;
6434 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006435 ifslastp = ifslastp->next;
6436 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006437 struct ifsregion *ifsp;
6438 INT_OFF;
6439 ifsp = ifslastp->next->next;
6440 free(ifslastp->next);
6441 ifslastp->next = ifsp;
6442 INT_ON;
6443 }
6444 if (ifslastp->endoff > endoff)
6445 ifslastp->endoff = endoff;
6446}
6447
6448static char *
Denys Vlasenko82331882020-02-24 10:02:50 +01006449exptilde(char *startp, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006450{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006451 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006452 char *name;
6453 struct passwd *pw;
6454 const char *home;
Denys Vlasenko82331882020-02-24 10:02:50 +01006455 char *p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006456
Denys Vlasenko82331882020-02-24 10:02:50 +01006457 p = startp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006458 name = p + 1;
6459
6460 while ((c = *++p) != '\0') {
6461 switch (c) {
6462 case CTLESC:
6463 return startp;
6464 case CTLQUOTEMARK:
6465 return startp;
6466 case ':':
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006467 if (flag & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006468 goto done;
6469 break;
6470 case '/':
6471 case CTLENDVAR:
6472 goto done;
6473 }
6474 }
6475 done:
Denys Vlasenko82331882020-02-24 10:02:50 +01006476 if (flag & EXP_DISCARD)
6477 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006478 *p = '\0';
6479 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006480 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006481 } else {
6482 pw = getpwnam(name);
6483 if (pw == NULL)
6484 goto lose;
6485 home = pw->pw_dir;
6486 }
Denys Vlasenko82331882020-02-24 10:02:50 +01006487 *p = c;
Denys Vlasenkoe880b1f2020-02-16 18:31:05 +01006488 if (!home)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006489 goto lose;
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006490 strtodest(home, flag | EXP_QUOTED);
Denys Vlasenko82331882020-02-24 10:02:50 +01006491 out:
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006492 return p;
6493 lose:
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006494 return startp;
6495}
6496
6497/*
6498 * Execute a command inside back quotes. If it's a builtin command, we
6499 * want to save its output in a block obtained from malloc. Otherwise
6500 * we fork off a subprocess and get the output of the command via a pipe.
6501 * Should be called with interrupts off.
6502 */
6503struct backcmd { /* result of evalbackcmd */
6504 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006505 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006506 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006507 struct job *jp; /* job structure for command */
6508};
6509
6510/* These forward decls are needed to use "eval" code for backticks handling: */
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +02006511/* flags in argument to evaltree */
6512#define EV_EXIT 01 /* exit after evaluating tree */
6513#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006514static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006515
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006516/* An evaltree() which is known to never return.
6517 * Used to use an alias:
6518 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6519 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6520 */
6521static ALWAYS_INLINE NORETURN void
6522evaltreenr(union node *n, int flags)
6523{
6524 evaltree(n, flags);
6525 bb_unreachable(abort());
6526 /* NOTREACHED */
6527}
6528
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006529static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006530evalbackcmd(union node *n, struct backcmd *result)
6531{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006532 int pip[2];
6533 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006534
6535 result->fd = -1;
6536 result->buf = NULL;
6537 result->nleft = 0;
6538 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006539 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006540 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006541 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006542
Denys Vlasenko579ad102016-10-25 21:10:20 +02006543 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02006544 ash_msg_and_raise_perror("can't create pipe");
Denys Vlasenko579ad102016-10-25 21:10:20 +02006545 jp = makejob(/*n,*/ 1);
6546 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006547 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006548 FORCE_INT_ON;
6549 close(pip[0]);
6550 if (pip[1] != 1) {
6551 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006552 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006553 close(pip[1]);
6554 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006555/* TODO: eflag clearing makes the following not abort:
6556 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6557 * which is what bash does (unless it is in POSIX mode).
6558 * dash deleted "eflag = 0" line in the commit
6559 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6560 * [EVAL] Don't clear eflag in evalbackcmd
6561 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6562 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006563 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006564 ifsfree();
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006565 evaltreenr(n, EV_EXIT);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006566 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006567 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006568 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006569 close(pip[1]);
6570 result->fd = pip[0];
6571 result->jp = jp;
6572
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006573 out:
6574 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6575 result->fd, result->buf, result->nleft, result->jp));
6576}
6577
6578/*
6579 * Expand stuff in backwards quotes.
6580 */
6581static void
Ron Yorston549deab2015-05-18 09:57:51 +02006582expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006583{
6584 struct backcmd in;
6585 int i;
6586 char buf[128];
6587 char *p;
6588 char *dest;
6589 int startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006590 struct stackmark smark;
6591
Denys Vlasenko82331882020-02-24 10:02:50 +01006592 if (flag & EXP_DISCARD)
6593 goto out;
6594
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006595 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006596 startloc = expdest - (char *)stackblock();
6597 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006598 evalbackcmd(cmd, &in);
6599 popstackmark(&smark);
6600
6601 p = in.buf;
6602 i = in.nleft;
6603 if (i == 0)
6604 goto read;
6605 for (;;) {
Denys Vlasenkoecc85832020-02-20 10:06:20 +01006606 memtodest(p, i, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006607 read:
6608 if (in.fd < 0)
6609 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006610 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006611 TRACE(("expbackq: read returns %d\n", i));
6612 if (i <= 0)
6613 break;
6614 p = buf;
6615 }
6616
Denis Vlasenko60818682007-09-28 22:07:23 +00006617 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006618 if (in.fd >= 0) {
6619 close(in.fd);
6620 back_exitstatus = waitforjob(in.jp);
6621 }
6622 INT_ON;
6623
6624 /* Eat all trailing newlines */
6625 dest = expdest;
Denys Vlasenko9ee58922020-02-17 10:24:32 +01006626 for (; dest > ((char *)stackblock() + startloc) && dest[-1] == '\n';)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006627 STUNPUTC(dest);
6628 expdest = dest;
6629
Ron Yorston549deab2015-05-18 09:57:51 +02006630 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006631 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006632 TRACE(("evalbackq: size:%d:'%.*s'\n",
6633 (int)((dest - (char *)stackblock()) - startloc),
6634 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006635 stackblock() + startloc));
Denys Vlasenko82331882020-02-24 10:02:50 +01006636
6637 out:
6638 argbackq = argbackq->next;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006639}
6640
Denys Vlasenko82331882020-02-24 10:02:50 +01006641/* expari needs it */
6642static char *argstr(char *p, int flag);
6643
Denys Vlasenko0b883582016-12-23 16:49:07 +01006644#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006645/*
6646 * Expand arithmetic expression. Backup to start of expression,
6647 * evaluate, place result in (backed up) result, adjust string position.
6648 */
Denys Vlasenko82331882020-02-24 10:02:50 +01006649static char *
6650expari(char *start, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006651{
Denys Vlasenko82331882020-02-24 10:02:50 +01006652 struct stackmark sm;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006653 int begoff;
Denys Vlasenko82331882020-02-24 10:02:50 +01006654 int endoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006655 int len;
Denys Vlasenko82331882020-02-24 10:02:50 +01006656 arith_t result;
6657 char *p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006658
Denys Vlasenko82331882020-02-24 10:02:50 +01006659 p = stackblock();
6660 begoff = expdest - p;
6661 p = argstr(start, flag & EXP_DISCARD);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006662
Denys Vlasenko82331882020-02-24 10:02:50 +01006663 if (flag & EXP_DISCARD)
6664 goto out;
6665
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006666 start = stackblock();
Denys Vlasenko82331882020-02-24 10:02:50 +01006667 endoff = expdest - start;
6668 start += begoff;
6669 STADJUST(start - expdest, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006670
6671 removerecordregions(begoff);
6672
Ron Yorston549deab2015-05-18 09:57:51 +02006673 if (flag & QUOTES_ESC)
Denys Vlasenko82331882020-02-24 10:02:50 +01006674 rmescapes(start, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006675
Denys Vlasenko82331882020-02-24 10:02:50 +01006676 pushstackmark(&sm, endoff);
6677 result = ash_arith(start);
6678 popstackmark(&sm);
6679
6680 len = cvtnum(result, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006681
Ron Yorston549deab2015-05-18 09:57:51 +02006682 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006683 recordregion(begoff, begoff + len, 0);
Denys Vlasenko82331882020-02-24 10:02:50 +01006684
6685 out:
6686 return p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006687}
6688#endif
6689
6690/* argstr needs it */
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006691static char *evalvar(char *p, int flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006692
6693/*
6694 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6695 * characters to allow for further processing. Otherwise treat
6696 * $@ like $* since no splitting will be performed.
6697 */
Denys Vlasenko82331882020-02-24 10:02:50 +01006698static char *
Denys Vlasenko7f198482020-02-24 09:57:08 +01006699argstr(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006700{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006701 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006702 '=',
6703 ':',
6704 CTLQUOTEMARK,
6705 CTLENDVAR,
6706 CTLESC,
6707 CTLVAR,
6708 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006709#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko82331882020-02-24 10:02:50 +01006710 CTLARI,
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006711 CTLENDARI,
6712#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006713 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006714 };
6715 const char *reject = spclchars;
Denys Vlasenko7f198482020-02-24 09:57:08 +01006716 int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006717 int inquotes;
6718 size_t length;
6719 int startloc;
6720
Denys Vlasenko82331882020-02-24 10:02:50 +01006721 reject += !!(flag & EXP_VARTILDE2);
6722 reject += flag & EXP_VARTILDE ? 0 : 2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006723 inquotes = 0;
6724 length = 0;
Denys Vlasenko7f198482020-02-24 09:57:08 +01006725 if (flag & EXP_TILDE) {
Denys Vlasenko7f198482020-02-24 09:57:08 +01006726 flag &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006727 tilde:
Denys Vlasenko82331882020-02-24 10:02:50 +01006728 if (*p == '~')
6729 p = exptilde(p, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006730 }
6731 start:
6732 startloc = expdest - (char *)stackblock();
6733 for (;;) {
Denys Vlasenko82331882020-02-24 10:02:50 +01006734 int end;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006735 unsigned char c;
6736
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006737 length += strcspn(p + length, reject);
Denys Vlasenko82331882020-02-24 10:02:50 +01006738 end = 0;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006739 c = p[length];
Denys Vlasenko82331882020-02-24 10:02:50 +01006740 if (!(c & 0x80)
6741 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6742 || c == CTLENDVAR
6743 ) {
6744 /*
6745 * c == '=' || c == ':' || c == '\0' ||
6746 * c == CTLENDARI || c == CTLENDVAR
6747 */
6748 length++;
6749 /* c == '\0' || c == CTLENDARI || c == CTLENDVAR */
6750 end = !!((c - 1) & 0x80);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006751 }
Denys Vlasenko82331882020-02-24 10:02:50 +01006752 if (length > 0 && !(flag & EXP_DISCARD)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006753 int newloc;
Denys Vlasenko82331882020-02-24 10:02:50 +01006754 char *q;
6755
6756 q = stnputs(p, length, expdest);
6757 q[-1] &= end - 1;
6758 expdest = q - (flag & EXP_WORD ? end : 0);
6759 newloc = q - (char *)stackblock() - end;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006760 if (breakall && !inquotes && newloc > startloc) {
6761 recordregion(startloc, newloc, 0);
6762 }
6763 startloc = newloc;
6764 }
6765 p += length + 1;
6766 length = 0;
6767
Denys Vlasenko82331882020-02-24 10:02:50 +01006768 if (end)
6769 break;
6770
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006771 switch (c) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006772 case '=':
Denys Vlasenko7f198482020-02-24 09:57:08 +01006773 flag |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006774 reject++;
6775 /* fall through */
6776 case ':':
6777 /*
6778 * sort of a hack - expand tildes in variable
6779 * assignments (after the first '=' and after ':'s).
6780 */
6781 if (*--p == '~') {
6782 goto tilde;
6783 }
6784 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006785 case CTLQUOTEMARK:
6786 /* "$@" syntax adherence hack */
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006787 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
Denys Vlasenko7f198482020-02-24 09:57:08 +01006788 p = evalvar(p + 1, flag | EXP_QUOTED) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006789 goto start;
6790 }
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006791 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006792 addquote:
Denys Vlasenko7f198482020-02-24 09:57:08 +01006793 if (flag & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006794 p--;
6795 length++;
6796 startloc++;
6797 }
6798 break;
6799 case CTLESC:
6800 startloc++;
6801 length++;
6802 goto addquote;
6803 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006804 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenko7f198482020-02-24 09:57:08 +01006805 p = evalvar(p, flag | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006806 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006807 goto start;
6808 case CTLBACKQ:
Denys Vlasenko7f198482020-02-24 09:57:08 +01006809 expbackq(argbackq->n, flag | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006810 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006811#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko82331882020-02-24 10:02:50 +01006812 case CTLARI:
6813 p = expari(p, flag | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006814 goto start;
6815#endif
6816 }
6817 }
Denys Vlasenko82331882020-02-24 10:02:50 +01006818 return p - 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006819}
6820
6821static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006822scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6823 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006824{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006825 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006826 char c;
6827
6828 loc = startp;
6829 loc2 = rmesc;
6830 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006831 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006832 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006833
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006834 c = *loc2;
6835 if (zero) {
6836 *loc2 = '\0';
6837 s = rmesc;
6838 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006839 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006840
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006841 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006842 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006843 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006844 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006845 loc++;
6846 loc++;
6847 loc2++;
6848 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006849 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006850}
6851
6852static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006853scanright(char *startp, char *rmesc, char *rmescend,
6854 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006855{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006856#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6857 int try2optimize = match_at_start;
6858#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006859 int esc = 0;
6860 char *loc;
6861 char *loc2;
6862
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006863 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6864 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6865 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6866 * Logic:
6867 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6868 * and on each iteration they go back two/one char until they reach the beginning.
6869 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6870 */
6871 /* TODO: document in what other circumstances we are called. */
6872
6873 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006874 int match;
6875 char c = *loc2;
6876 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006877 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006878 *loc2 = '\0';
6879 s = rmesc;
6880 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006881 match = pmatch(pattern, s);
6882 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006883 *loc2 = c;
6884 if (match)
6885 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006886#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6887 if (try2optimize) {
6888 /* Maybe we can optimize this:
6889 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006890 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6891 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006892 */
6893 unsigned plen = strlen(pattern);
6894 /* Does it end with "*"? */
6895 if (plen != 0 && pattern[--plen] == '*') {
6896 /* "xxxx*" is not escaped */
6897 /* "xxx\*" is escaped */
6898 /* "xx\\*" is not escaped */
6899 /* "x\\\*" is escaped */
6900 int slashes = 0;
6901 while (plen != 0 && pattern[--plen] == '\\')
6902 slashes++;
6903 if (!(slashes & 1))
6904 break; /* ends with unescaped "*" */
6905 }
6906 try2optimize = 0;
6907 }
6908#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006909 loc--;
6910 if (quotes) {
6911 if (--esc < 0) {
6912 esc = esclen(startp, loc);
6913 }
6914 if (esc % 2) {
6915 esc--;
6916 loc--;
6917 }
6918 }
6919 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006920 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006921}
6922
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006923static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006924static void
6925varunset(const char *end, const char *var, const char *umsg, int varflags)
6926{
6927 const char *msg;
6928 const char *tail;
6929
6930 tail = nullstr;
6931 msg = "parameter not set";
6932 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006933 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006934 if (varflags & VSNUL)
6935 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006936 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006937 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006938 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006939 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006940 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006941}
6942
Denys Vlasenko82331882020-02-24 10:02:50 +01006943static char *
6944subevalvar(char *start, char *str, int strloc,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006945 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006946{
Denys Vlasenko82331882020-02-24 10:02:50 +01006947 int subtype = varflags & VSTYPE;
Ron Yorston549deab2015-05-18 09:57:51 +02006948 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006949 char *startp;
6950 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006951 char *rmesc, *rmescend;
Denys Vlasenko82331882020-02-24 10:02:50 +01006952 long amount;
6953 int resetloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006954 int argstr_flags;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006955 IF_BASH_PATTERN_SUBST(int workloc;)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006956 IF_BASH_PATTERN_SUBST(int slash_pos;)
6957 IF_BASH_PATTERN_SUBST(char *repl;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006958 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006959 char *(*scan)(char*, char*, char*, char*, int, int);
Denys Vlasenko82331882020-02-24 10:02:50 +01006960 char *p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006961
Denys Vlasenko82331882020-02-24 10:02:50 +01006962 //bb_error_msg("subevalvar(start:'%s',str:'%s',strloc:%d,startloc:%d,varflags:%x,quotes:%d)",
6963 // start, str, strloc, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006964
Denys Vlasenko740058b2018-01-09 17:01:00 +01006965#if BASH_PATTERN_SUBST
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006966 /* For "${v/pattern/repl}", we must find the delimiter _before_
6967 * argstr() call expands possible variable references in pattern:
6968 * think about "v=a; a=a/; echo ${v/$a/r}" case.
6969 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006970 repl = NULL;
6971 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6972 /* Find '/' and replace with NUL */
Denys Vlasenko82331882020-02-24 10:02:50 +01006973 repl = start;
Denys Vlasenkoc2aa2182018-08-04 22:25:28 +02006974 /* The pattern can't be empty.
6975 * IOW: if the first char after "${v//" is a slash,
6976 * it does not terminate the pattern - it's the first char of the pattern:
6977 * v=/dev/ram; echo ${v////-} prints -dev-ram (pattern is "/")
6978 * v=/dev/ram; echo ${v///r/-} prints /dev-am (pattern is "/r")
6979 */
6980 if (*repl == '/')
6981 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006982 for (;;) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01006983 if (*repl == '\0') {
6984 repl = NULL;
6985 break;
6986 }
6987 if (*repl == '/') {
6988 *repl = '\0';
6989 break;
6990 }
Denys Vlasenkoc2aa2182018-08-04 22:25:28 +02006991 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006992 if ((unsigned char)*repl == CTLESC && repl[1])
Denys Vlasenko740058b2018-01-09 17:01:00 +01006993 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006994 repl++;
6995 }
6996 }
6997#endif
Denys Vlasenko82331882020-02-24 10:02:50 +01006998 argstr_flags = (flag & EXP_DISCARD) | EXP_TILDE;
6999 if (!str
Denys Vlasenko216913c2018-04-02 12:35:04 +02007000#if BASH_SUBSTR
7001 && subtype != VSSUBSTR
7002#endif
7003 ) {
7004 /* EXP_CASE keeps CTLESC's */
Denys Vlasenko82331882020-02-24 10:02:50 +01007005 argstr_flags |= EXP_CASE;
Denys Vlasenko216913c2018-04-02 12:35:04 +02007006 }
Denys Vlasenko82331882020-02-24 10:02:50 +01007007 p = argstr(start, argstr_flags);
7008
Denys Vlasenko216913c2018-04-02 12:35:04 +02007009 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
Denys Vlasenko740058b2018-01-09 17:01:00 +01007010#if BASH_PATTERN_SUBST
7011 slash_pos = -1;
7012 if (repl) {
7013 slash_pos = expdest - ((char *)stackblock() + strloc);
7014 STPUTC('/', expdest);
Denys Vlasenko216913c2018-04-02 12:35:04 +02007015 //bb_error_msg("repl+1:'%s'", repl + 1);
Denys Vlasenko82331882020-02-24 10:02:50 +01007016 p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
Denys Vlasenko740058b2018-01-09 17:01:00 +01007017 *repl = '/';
7018 }
7019#endif
Denys Vlasenko82331882020-02-24 10:02:50 +01007020 if (flag & EXP_DISCARD)
7021 return p;
7022
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007023 startp = (char *)stackblock() + startloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007024 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007025
7026 switch (subtype) {
7027 case VSASSIGN:
Denys Vlasenko7f198482020-02-24 09:57:08 +01007028 setvar0(str, startp);
Denys Vlasenko82331882020-02-24 10:02:50 +01007029
7030 loc = startp;
7031 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007032
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007033 case VSQUESTION:
Denys Vlasenko82331882020-02-24 10:02:50 +01007034 varunset(start, str, startp, varflags);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007035 /* NOTREACHED */
7036
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007037#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02007038 case VSSUBSTR: {
7039 int pos, len, orig_len;
7040 char *colon;
Denys Vlasenko7f198482020-02-24 09:57:08 +01007041 char *vstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007042
Denys Vlasenko7f198482020-02-24 09:57:08 +01007043 loc = vstr = stackblock() + strloc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02007044
Denys Vlasenko826360f2017-07-17 17:49:11 +02007045 /* Read POS in ${var:POS:LEN} */
7046 colon = strchr(loc, ':');
7047 if (colon) *colon = '\0';
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01007048 pos = substr_atoi(loc);
Denys Vlasenko826360f2017-07-17 17:49:11 +02007049 if (colon) *colon = ':';
7050
7051 /* Read LEN in ${var:POS:LEN} */
Denys Vlasenko7f198482020-02-24 09:57:08 +01007052 len = vstr - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007053 /* *loc != '\0', guaranteed by parser */
7054 if (quotes) {
7055 char *ptr;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007056 /* Adjust the length by the number of escapes */
Denys Vlasenko7f198482020-02-24 09:57:08 +01007057 for (ptr = startp; ptr < (vstr - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007058 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007059 len--;
7060 ptr++;
7061 }
7062 }
7063 }
7064 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007065 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007066 /* ${var::LEN} */
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01007067 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007068 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007069 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007070 len = orig_len;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01007071 while (*loc && *loc != ':')
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007072 loc++;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01007073 if (*loc++ == ':')
7074 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007075 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01007076 if (pos < 0) {
7077 /* ${VAR:$((-n)):l} starts n chars from the end */
7078 pos = orig_len + pos;
7079 }
7080 if ((unsigned)pos >= orig_len) {
7081 /* apart from obvious ${VAR:999999:l},
7082 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02007083 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01007084 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007085 pos = 0;
7086 len = 0;
7087 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02007088 if (len < 0) {
7089 /* ${VAR:N:-M} sets LEN to strlen()-M */
7090 len = (orig_len - pos) + len;
7091 }
7092 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007093 len = orig_len - pos;
7094
Denys Vlasenko7f198482020-02-24 09:57:08 +01007095 for (vstr = startp; pos; vstr++, pos--) {
7096 if (quotes && (unsigned char)*vstr == CTLESC)
7097 vstr++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007098 }
7099 for (loc = startp; len; len--) {
Denys Vlasenko7f198482020-02-24 09:57:08 +01007100 if (quotes && (unsigned char)*vstr == CTLESC)
7101 *loc++ = *vstr++;
7102 *loc++ = *vstr++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007103 }
7104 *loc = '\0';
Denys Vlasenko82331882020-02-24 10:02:50 +01007105 goto out;
Denys Vlasenko826360f2017-07-17 17:49:11 +02007106 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007107#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007108 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007109
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007110 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007111
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007112#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01007113 repl = NULL;
7114
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007115 /* We'll comeback here if we grow the stack while handling
7116 * a VSREPLACE or VSREPLACEALL, since our pointers into the
7117 * stack will need rebasing, and we'll need to remove our work
7118 * areas each time
7119 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007120 restart:
7121#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007122
7123 amount = expdest - ((char *)stackblock() + resetloc);
7124 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007125 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007126
7127 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007128 rmescend = (char *)stackblock() + strloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007129 //bb_error_msg("str7:'%s'", rmescend);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007130 if (quotes) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007131//TODO: how to handle slash_pos here if string changes (shortens?)
7132 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007133 if (rmesc != startp) {
7134 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007135 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007136 }
7137 }
7138 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007139 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02007140 /*
7141 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7142 * The result is a_\_z_c (not a\_\_z_c)!
7143 *
7144 * The search pattern and replace string treat backslashes differently!
Denys Vlasenko740058b2018-01-09 17:01:00 +01007145 * "&slash_pos" causes rmescapes() to work differently on the pattern
Ron Yorston417622c2015-05-18 09:59:14 +02007146 * and string. It's only used on the first call.
7147 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01007148 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7149 rmescapes(str, RMESCAPE_GLOB,
7150 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7151 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007152
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007153#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02007154 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007155 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02007156 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007157 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007158
Denis Vlasenkod6855d12008-09-27 14:03:25 +00007159 if (!repl) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007160 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01007161 repl = nullstr;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007162 if (slash_pos >= 0) {
7163 repl = str + slash_pos;
Ron Yorston417622c2015-05-18 09:59:14 +02007164 *repl++ = '\0';
Denys Vlasenko740058b2018-01-09 17:01:00 +01007165 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007166 }
Ron Yorston417622c2015-05-18 09:59:14 +02007167 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007168
7169 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007170 if (str[0] == '\0')
Denys Vlasenko82331882020-02-24 10:02:50 +01007171 goto out1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007172
7173 len = 0;
7174 idx = startp;
7175 end = str - 1;
7176 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007177 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007178 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007179 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007180 if (!loc) {
7181 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007182 char *restart_detect = stackblock();
7183 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007184 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01007185 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007186 idx++;
7187 len++;
7188 STPUTC(*idx, expdest);
7189 }
7190 if (stackblock() != restart_detect)
7191 goto restart;
7192 idx++;
7193 len++;
7194 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007195 /* continue; - prone to quadratic behavior, smarter code: */
7196 if (idx >= end)
7197 break;
7198 if (str[0] == '*') {
7199 /* Pattern is "*foo". If "*foo" does not match "long_string",
7200 * it would never match "ong_string" etc, no point in trying.
7201 */
7202 goto skip_matching;
7203 }
7204 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007205 }
7206
7207 if (subtype == VSREPLACEALL) {
7208 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007209 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007210 idx++;
7211 idx++;
7212 rmesc++;
7213 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007214 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007215 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007216 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007217
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007218 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007219 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007220 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007221 if (quotes && *loc == '\\') {
7222 STPUTC(CTLESC, expdest);
7223 len++;
7224 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007225 STPUTC(*loc, expdest);
7226 if (stackblock() != restart_detect)
7227 goto restart;
7228 len++;
7229 }
7230
7231 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02007232 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007233 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007234 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007235 STPUTC(*idx, expdest);
7236 if (stackblock() != restart_detect)
7237 goto restart;
7238 len++;
7239 idx++;
7240 }
7241 break;
7242 }
7243 }
7244
7245 /* We've put the replaced text into a buffer at workloc, now
7246 * move it to the right place and adjust the stack.
7247 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007248 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007249 startp = (char *)stackblock() + startloc;
7250 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007251 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenko82331882020-02-24 10:02:50 +01007252 loc = startp + len;
7253 goto out;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007254 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007255#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007256
7257 subtype -= VSTRIMRIGHT;
7258#if DEBUG
7259 if (subtype < 0 || subtype > 7)
7260 abort();
7261#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007262 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007263 zero = subtype >> 1;
7264 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7265 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7266
7267 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7268 if (loc) {
7269 if (zero) {
7270 memmove(startp, loc, str - loc);
7271 loc = startp + (str - loc) - 1;
7272 }
7273 *loc = '\0';
Denys Vlasenko82331882020-02-24 10:02:50 +01007274 } else
7275 loc = str - 1;
7276
7277 out:
7278 amount = loc - expdest;
7279 STADJUST(amount, expdest);
7280 out1:
7281 /* Remove any recorded regions beyond start of variable */
7282 removerecordregions(startloc);
7283
7284 return p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007285}
7286
7287/*
7288 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007289 * name parameter (examples):
7290 * ash -c 'echo $1' name:'1='
7291 * ash -c 'echo $qwe' name:'qwe='
7292 * ash -c 'echo $$' name:'$='
7293 * ash -c 'echo ${$}' name:'$='
7294 * ash -c 'echo ${$##q}' name:'$=q'
7295 * ash -c 'echo ${#$}' name:'$='
7296 * note: examples with bad shell syntax:
7297 * ash -c 'echo ${#$1}' name:'$=1'
7298 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007299 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02007300static NOINLINE ssize_t
Denys Vlasenko440da972018-08-05 14:29:58 +02007301varvalue(char *name, int varflags, int flags, int quoted)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007302{
Mike Frysinger98c52642009-04-02 10:02:37 +00007303 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007304 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007305 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007306 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007307 int sep;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007308 int subtype = varflags & VSTYPE;
Denys Vlasenko82331882020-02-24 10:02:50 +01007309 int discard = (subtype == VSPLUS || subtype == VSLENGTH) | (flags & EXP_DISCARD);
7310
7311 if (!subtype) {
7312 if (discard)
7313 return -1;
7314
7315 raise_error_syntax("bad substitution");
7316 }
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007317
Denys Vlasenkoecc85832020-02-20 10:06:20 +01007318 flags |= EXP_KEEPNUL;
7319 flags &= discard ? ~QUOTES_ESC : ~0;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007320 sep = (flags & EXP_FULL) << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007321
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007322 switch (*name) {
7323 case '$':
7324 num = rootpid;
7325 goto numvar;
7326 case '?':
7327 num = exitstatus;
7328 goto numvar;
7329 case '#':
7330 num = shellparam.nparam;
7331 goto numvar;
7332 case '!':
7333 num = backgndpid;
7334 if (num == 0)
7335 return -1;
7336 numvar:
Denys Vlasenko45dd87a2020-02-21 16:30:44 +01007337 len = cvtnum(num, flags);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007338 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007339 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007340 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007341 for (i = NOPTS - 1; i >= 0; i--) {
Martijn Dekkerad4e9612018-03-31 18:15:59 +02007342 if (optlist[i] && optletters(i)) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007343 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007344 len++;
7345 }
7346 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007347 check_1char_name:
7348#if 0
7349 /* handles cases similar to ${#$1} */
7350 if (name[2] != '\0')
7351 raise_error_syntax("bad substitution");
7352#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007353 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007354 case '@':
7355 if (quoted && sep)
7356 goto param;
7357 /* fall through */
7358 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007359 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007360 char sepc;
Denys Vlasenko440da972018-08-05 14:29:58 +02007361 char c;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007362
Denys Vlasenko440da972018-08-05 14:29:58 +02007363 /* We will set c to 0 or ~0 depending on whether
7364 * we're doing field splitting. We won't do field
7365 * splitting if either we're quoted or sep is zero.
7366 *
7367 * Instead of testing (quoted || !sep) the following
7368 * trick optimises away any branches by using the
7369 * fact that EXP_QUOTED (which is the only bit that
7370 * can be set in quoted) is the same as EXP_FULL <<
7371 * CHAR_BIT (which is the only bit that can be set
7372 * in sep).
7373 */
7374#if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7375#error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7376#endif
7377 c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7378 sep &= ~quoted;
7379 sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007380 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007381 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007382 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007383 if (!ap)
7384 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007385 while ((p = *ap++) != NULL) {
Denys Vlasenkoecc85832020-02-20 10:06:20 +01007386 len += strtodest(p, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007387
7388 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007389 len++;
Denys Vlasenkoecc85832020-02-20 10:06:20 +01007390 memtodest(&sepc, 1, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007391 }
7392 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007393 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007394 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007395 case '0':
7396 case '1':
7397 case '2':
7398 case '3':
7399 case '4':
7400 case '5':
7401 case '6':
7402 case '7':
7403 case '8':
7404 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007405 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007406 if (num < 0 || num > shellparam.nparam)
7407 return -1;
7408 p = num ? shellparam.p[num - 1] : arg0;
7409 goto value;
7410 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007411 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007412 p = lookupvar(name);
7413 value:
7414 if (!p)
7415 return -1;
7416
Denys Vlasenkoecc85832020-02-20 10:06:20 +01007417 len = strtodest(p, flags);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007418#if ENABLE_UNICODE_SUPPORT
7419 if (subtype == VSLENGTH && len > 0) {
7420 reinit_unicode_for_ash();
7421 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007422 STADJUST(-len, expdest);
7423 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007424 len = unicode_strlen(p);
7425 }
7426 }
7427#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007428 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007429 }
7430
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007431 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007432 STADJUST(-len, expdest);
Denys Vlasenko82331882020-02-24 10:02:50 +01007433
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007434 return len;
7435}
7436
7437/*
7438 * Expand a variable, and return a pointer to the next character in the
7439 * input string.
7440 */
7441static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007442evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007443{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007444 char varflags;
7445 char subtype;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007446 char *var;
7447 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007448 int startloc;
7449 ssize_t varlen;
Denys Vlasenko15558952020-02-22 19:38:40 +01007450 int discard;
Denys Vlasenko82331882020-02-24 10:02:50 +01007451 int quoted;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007452
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007453 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007454 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007455
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007456 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007457 var = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007458 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007459 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007460
7461 again:
Denys Vlasenko440da972018-08-05 14:29:58 +02007462 varlen = varvalue(var, varflags, flag, quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007463 if (varflags & VSNUL)
7464 varlen--;
7465
Denys Vlasenko15558952020-02-22 19:38:40 +01007466 discard = varlen < 0 ? EXP_DISCARD : 0;
7467
Denys Vlasenko82331882020-02-24 10:02:50 +01007468 switch (subtype) {
7469 case VSPLUS:
Denys Vlasenko15558952020-02-22 19:38:40 +01007470 discard ^= EXP_DISCARD;
Denys Vlasenko82331882020-02-24 10:02:50 +01007471 /* fall through */
7472 case 0:
7473 case VSMINUS:
Denys Vlasenko15558952020-02-22 19:38:40 +01007474 p = argstr(p, flag | EXP_TILDE | EXP_WORD | (discard ^ EXP_DISCARD));
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007475 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007476
Denys Vlasenko82331882020-02-24 10:02:50 +01007477 case VSASSIGN:
7478 case VSQUESTION:
Denys Vlasenko15558952020-02-22 19:38:40 +01007479 p = subevalvar(p, var, 0, startloc, varflags,
7480 (flag & ~QUOTES_ESC) | (discard ^ EXP_DISCARD));
7481
7482 if ((flag | ~discard) & EXP_DISCARD)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007483 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007484
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007485 varflags &= ~VSNUL;
Denys Vlasenko15558952020-02-22 19:38:40 +01007486 subtype = VSNORMAL;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007487 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007488 }
7489
Denys Vlasenko15558952020-02-22 19:38:40 +01007490 if ((discard & ~flag) && uflag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007491 varunset(p, var, 0, 0);
7492
7493 if (subtype == VSLENGTH) {
Denys Vlasenko82331882020-02-24 10:02:50 +01007494 p++;
7495 if (flag & EXP_DISCARD)
7496 return p;
Denys Vlasenko45dd87a2020-02-21 16:30:44 +01007497 cvtnum(varlen > 0 ? varlen : 0, flag);
Denys Vlasenko15558952020-02-22 19:38:40 +01007498 goto really_record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007499 }
7500
Denys Vlasenko82331882020-02-24 10:02:50 +01007501 if (subtype == VSNORMAL)
7502 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007503
7504#if DEBUG
7505 switch (subtype) {
7506 case VSTRIMLEFT:
7507 case VSTRIMLEFTMAX:
7508 case VSTRIMRIGHT:
7509 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007510#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007511 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007512#endif
7513#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007514 case VSREPLACE:
7515 case VSREPLACEALL:
7516#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007517 break;
7518 default:
7519 abort();
7520 }
7521#endif
7522
Denys Vlasenko15558952020-02-22 19:38:40 +01007523 flag |= discard;
Denys Vlasenko82331882020-02-24 10:02:50 +01007524 if (!(flag & EXP_DISCARD)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007525 /*
7526 * Terminate the string and start recording the pattern
7527 * right after it
7528 */
7529 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007530 }
7531
Denys Vlasenko82331882020-02-24 10:02:50 +01007532 patloc = expdest - (char *)stackblock();
7533 p = subevalvar(p, NULL, patloc, startloc, varflags, flag);
Denys Vlasenko4ace3852020-02-16 18:42:50 +01007534
Denys Vlasenko82331882020-02-24 10:02:50 +01007535 record:
Denys Vlasenko15558952020-02-22 19:38:40 +01007536 if ((flag | discard) & EXP_DISCARD)
Denys Vlasenko82331882020-02-24 10:02:50 +01007537 return p;
7538
Denys Vlasenko15558952020-02-22 19:38:40 +01007539 really_record:
Denys Vlasenko82331882020-02-24 10:02:50 +01007540 if (quoted) {
7541 quoted = *var == '@' && shellparam.nparam;
7542 if (!quoted)
7543 return p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007544 }
Denys Vlasenko82331882020-02-24 10:02:50 +01007545 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007546 return p;
7547}
7548
7549/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007550 * Add a file name to the list.
7551 */
7552static void
7553addfname(const char *name)
7554{
7555 struct strlist *sp;
7556
Denis Vlasenko597906c2008-02-20 16:38:54 +00007557 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007558 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007559 *exparg.lastp = sp;
7560 exparg.lastp = &sp->next;
7561}
7562
Felix Fietkaub5b21122017-01-31 21:58:55 +01007563/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7564static int
7565hasmeta(const char *p)
7566{
7567 static const char chars[] ALIGN1 = {
7568 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7569 };
7570
7571 for (;;) {
7572 p = strpbrk(p, chars);
7573 if (!p)
7574 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007575 switch ((unsigned char)*p) {
Felix Fietkaub5b21122017-01-31 21:58:55 +01007576 case CTLQUOTEMARK:
7577 for (;;) {
7578 p++;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007579 if ((unsigned char)*p == CTLQUOTEMARK)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007580 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007581 if ((unsigned char)*p == CTLESC)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007582 p++;
7583 if (*p == '\0') /* huh? */
7584 return 0;
7585 }
7586 break;
7587 case '\\':
7588 case CTLESC:
7589 p++;
7590 if (*p == '\0')
7591 return 0;
7592 break;
7593 case '[':
7594 if (!strchr(p + 1, ']')) {
7595 /* It's not a properly closed [] pattern,
7596 * but other metas may follow. Continue checking.
7597 * my[file* _is_ globbed by bash
7598 * and matches filenames like "my[file1".
7599 */
7600 break;
7601 }
7602 /* fallthrough */
7603 default:
7604 /* case '*': */
7605 /* case '?': */
7606 return 1;
7607 }
7608 p++;
7609 }
7610
7611 return 0;
7612}
7613
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007614/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007615#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007616
7617/* Add the result of glob() to the list */
7618static void
7619addglob(const glob_t *pglob)
7620{
7621 char **p = pglob->gl_pathv;
7622
7623 do {
7624 addfname(*p);
7625 } while (*++p);
7626}
7627static void
7628expandmeta(struct strlist *str /*, int flag*/)
7629{
7630 /* TODO - EXP_REDIR */
7631
7632 while (str) {
7633 char *p;
7634 glob_t pglob;
7635 int i;
7636
7637 if (fflag)
7638 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007639
Felix Fietkaub5b21122017-01-31 21:58:55 +01007640 if (!hasmeta(str->text))
7641 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007642
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007643 INT_OFF;
7644 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007645// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7646// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7647//
7648// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7649// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7650// Which means you need to unescape the string, right? Not so fast:
7651// if there _is_ a file named "file\?" (with backslash), it is returned
7652// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007653// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007654//
7655// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7656// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7657// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7658// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7659// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7660// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7661 i = glob(p, 0, NULL, &pglob);
7662 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007663 if (p != str->text)
7664 free(p);
7665 switch (i) {
7666 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007667#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007668 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7669 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7670 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007671#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007672 addglob(&pglob);
7673 globfree(&pglob);
7674 INT_ON;
7675 break;
7676 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007677 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007678 globfree(&pglob);
7679 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007680 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007681 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007682 rmescapes(str->text, 0, NULL);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007683 exparg.lastp = &str->next;
7684 break;
7685 default: /* GLOB_NOSPACE */
7686 globfree(&pglob);
7687 INT_ON;
7688 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7689 }
7690 str = str->next;
7691 }
7692}
7693
7694#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007695/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007696
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007697/*
7698 * Do metacharacter (i.e. *, ?, [...]) expansion.
7699 */
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007700typedef struct exp_t {
7701 char *dir;
7702 unsigned dir_max;
7703} exp_t;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007704static void
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007705expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007706{
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007707#define expdir exp->dir
7708#define expdir_max exp->dir_max
7709 char *enddir = expdir + expdir_len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007710 char *p;
7711 const char *cp;
7712 char *start;
7713 char *endname;
7714 int metaflag;
7715 struct stat statb;
7716 DIR *dirp;
7717 struct dirent *dp;
7718 int atend;
7719 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007720 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007721
7722 metaflag = 0;
7723 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007724 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007725 if (*p == '*' || *p == '?')
7726 metaflag = 1;
7727 else if (*p == '[') {
7728 char *q = p + 1;
7729 if (*q == '!')
7730 q++;
7731 for (;;) {
7732 if (*q == '\\')
7733 q++;
7734 if (*q == '/' || *q == '\0')
7735 break;
7736 if (*++q == ']') {
7737 metaflag = 1;
7738 break;
7739 }
7740 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007741 } else {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007742 if (*p == '\\' && p[1])
Ron Yorstonca25af92015-09-04 10:32:41 +01007743 esc++;
7744 if (p[esc] == '/') {
7745 if (metaflag)
7746 break;
7747 start = p + esc + 1;
7748 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007749 }
7750 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007751 if (metaflag == 0) { /* we've reached the end of the file name */
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007752 if (!expdir_len)
7753 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007754 p = name;
7755 do {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007756 if (*p == '\\' && p[1])
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007757 p++;
7758 *enddir++ = *p;
7759 } while (*p++);
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007760 if (lstat(expdir, &statb) == 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007761 addfname(expdir);
7762 return;
7763 }
7764 endname = p;
7765 if (name < start) {
7766 p = name;
7767 do {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007768 if (*p == '\\' && p[1])
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007769 p++;
7770 *enddir++ = *p++;
7771 } while (p < start);
7772 }
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007773 *enddir = '\0';
7774 cp = expdir;
7775 expdir_len = enddir - cp;
7776 if (!expdir_len)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007777 cp = ".";
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007778 dirp = opendir(cp);
7779 if (dirp == NULL)
7780 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007781 if (*endname == 0) {
7782 atend = 1;
7783 } else {
7784 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007785 *endname = '\0';
7786 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007787 }
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007788 name_len -= endname - name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007789 matchdot = 0;
7790 p = start;
7791 if (*p == '\\')
7792 p++;
7793 if (*p == '.')
7794 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007795 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007796 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007797 continue;
7798 if (pmatch(start, dp->d_name)) {
7799 if (atend) {
7800 strcpy(enddir, dp->d_name);
7801 addfname(expdir);
7802 } else {
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007803 unsigned offset;
7804 unsigned len;
7805
7806 p = stpcpy(enddir, dp->d_name);
7807 *p = '/';
7808
7809 offset = p - expdir + 1;
7810 len = offset + name_len + NAME_MAX;
7811 if (len > expdir_max) {
7812 len += PATH_MAX;
7813 expdir = ckrealloc(expdir, len);
7814 expdir_max = len;
7815 }
7816
7817 expmeta(exp, endname, name_len, offset);
7818 enddir = expdir + expdir_len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007819 }
7820 }
7821 }
7822 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007823 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007824 endname[-esc - 1] = esc ? '\\' : '/';
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007825#undef expdir
7826#undef expdir_max
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007827}
7828
7829static struct strlist *
7830msort(struct strlist *list, int len)
7831{
7832 struct strlist *p, *q = NULL;
7833 struct strlist **lpp;
7834 int half;
7835 int n;
7836
7837 if (len <= 1)
7838 return list;
7839 half = len >> 1;
7840 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007841 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007842 q = p;
7843 p = p->next;
7844 }
7845 q->next = NULL; /* terminate first half of list */
7846 q = msort(list, half); /* sort first half of list */
7847 p = msort(p, len - half); /* sort second half */
7848 lpp = &list;
7849 for (;;) {
7850#if ENABLE_LOCALE_SUPPORT
7851 if (strcoll(p->text, q->text) < 0)
7852#else
7853 if (strcmp(p->text, q->text) < 0)
7854#endif
7855 {
7856 *lpp = p;
7857 lpp = &p->next;
7858 p = *lpp;
7859 if (p == NULL) {
7860 *lpp = q;
7861 break;
7862 }
7863 } else {
7864 *lpp = q;
7865 lpp = &q->next;
7866 q = *lpp;
7867 if (q == NULL) {
7868 *lpp = p;
7869 break;
7870 }
7871 }
7872 }
7873 return list;
7874}
7875
7876/*
7877 * Sort the results of file name expansion. It calculates the number of
7878 * strings to sort and then calls msort (short for merge sort) to do the
7879 * work.
7880 */
7881static struct strlist *
7882expsort(struct strlist *str)
7883{
7884 int len;
7885 struct strlist *sp;
7886
7887 len = 0;
7888 for (sp = str; sp; sp = sp->next)
7889 len++;
7890 return msort(str, len);
7891}
7892
7893static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007894expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007895{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007896 /* TODO - EXP_REDIR */
7897
7898 while (str) {
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007899 exp_t exp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007900 struct strlist **savelastp;
7901 struct strlist *sp;
7902 char *p;
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007903 unsigned len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007904
7905 if (fflag)
7906 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007907 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007908 goto nometa;
7909 savelastp = exparg.lastp;
7910
7911 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007912 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007913 len = strlen(p);
7914 exp.dir_max = len + PATH_MAX;
7915 exp.dir = ckmalloc(exp.dir_max);
7916
7917 expmeta(&exp, p, len, 0);
7918 free(exp.dir);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007919 if (p != str->text)
7920 free(p);
7921 INT_ON;
7922 if (exparg.lastp == savelastp) {
7923 /*
7924 * no matches
7925 */
7926 nometa:
7927 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007928 rmescapes(str->text, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007929 exparg.lastp = &str->next;
7930 } else {
7931 *exparg.lastp = NULL;
7932 *savelastp = sp = expsort(*savelastp);
7933 while (sp->next != NULL)
7934 sp = sp->next;
7935 exparg.lastp = &sp->next;
7936 }
7937 str = str->next;
7938 }
7939}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007940#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007941
7942/*
7943 * Perform variable substitution and command substitution on an argument,
7944 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7945 * perform splitting and file name expansion. When arglist is NULL, perform
7946 * here document expansion.
7947 */
7948static void
7949expandarg(union node *arg, struct arglist *arglist, int flag)
7950{
7951 struct strlist *sp;
7952 char *p;
7953
7954 argbackq = arg->narg.backquote;
7955 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007956 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007957 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007958 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007959 /* here document expanded */
7960 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007961 }
Denys Vlasenko82331882020-02-24 10:02:50 +01007962 p = grabstackstr(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007963 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007964 exparg.lastp = &exparg.list;
7965 /*
7966 * TODO - EXP_REDIR
7967 */
7968 if (flag & EXP_FULL) {
7969 ifsbreakup(p, &exparg);
7970 *exparg.lastp = NULL;
7971 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007972 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007973 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007974 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007975 sp->text = p;
7976 *exparg.lastp = sp;
7977 exparg.lastp = &sp->next;
7978 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007979 *exparg.lastp = NULL;
7980 if (exparg.list) {
7981 *arglist->lastp = exparg.list;
7982 arglist->lastp = exparg.lastp;
7983 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007984
7985 out:
7986 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007987}
7988
7989/*
7990 * Expand shell variables and backquotes inside a here document.
7991 */
7992static void
Denys Vlasenkoc2058ec2020-02-22 20:25:03 +01007993expandhere(union node *arg)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007994{
Ron Yorston549deab2015-05-18 09:57:51 +02007995 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007996}
7997
7998/*
7999 * Returns true if the pattern matches the string.
8000 */
8001static int
8002patmatch(char *pattern, const char *string)
8003{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02008004 char *p = preglob(pattern, 0);
Denys Vlasenko4476c702017-08-15 15:27:41 +02008005 int r = pmatch(p, string);
8006 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
8007 return r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008008}
8009
8010/*
8011 * See if a pattern matches in a case statement.
8012 */
8013static int
8014casematch(union node *pattern, char *val)
8015{
8016 struct stackmark smark;
8017 int result;
8018
8019 setstackmark(&smark);
8020 argbackq = pattern->narg.backquote;
8021 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02008022 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02008023 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008024 result = patmatch(stackblock(), val);
8025 popstackmark(&smark);
8026 return result;
8027}
8028
8029
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008030/* ============ find_command */
8031
8032struct builtincmd {
8033 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008034 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008035 /* unsigned flags; */
8036};
8037#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00008038/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008039 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008040#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008041#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008042
8043struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008044 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008045 union param {
8046 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008047 /* index >= 0 for commands without path (slashes) */
8048 /* (TODO: what exactly does the value mean? PATH position?) */
8049 /* index == -1 for commands with slashes */
8050 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008051 const struct builtincmd *cmd;
8052 struct funcnode *func;
8053 } u;
8054};
8055/* values of cmdtype */
8056#define CMDUNKNOWN -1 /* no entry in table for command */
8057#define CMDNORMAL 0 /* command is an executable program */
8058#define CMDFUNCTION 1 /* command is a shell function */
8059#define CMDBUILTIN 2 /* command is a shell builtin */
8060
8061/* action to find_command() */
8062#define DO_ERR 0x01 /* prints errors */
8063#define DO_ABS 0x02 /* checks absolute paths */
8064#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
8065#define DO_ALTPATH 0x08 /* using alternate path */
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008066#define DO_REGBLTIN 0x10 /* regular built-ins and functions only */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008067
8068static void find_command(char *, struct cmdentry *, int, const char *);
8069
8070
8071/* ============ Hashing commands */
8072
8073/*
8074 * When commands are first encountered, they are entered in a hash table.
8075 * This ensures that a full path search will not have to be done for them
8076 * on each invocation.
8077 *
8078 * We should investigate converting to a linear search, even though that
8079 * would make the command name "hash" a misnomer.
8080 */
8081
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008082struct tblentry {
8083 struct tblentry *next; /* next entry in hash chain */
8084 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008085 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008086 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008087 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008088};
8089
Denis Vlasenko01631112007-12-16 17:20:38 +00008090static struct tblentry **cmdtable;
8091#define INIT_G_cmdtable() do { \
8092 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
8093} while (0)
8094
8095static int builtinloc = -1; /* index in path of %builtin, or -1 */
8096
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008097
8098static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008099tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008100{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008101#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00008102 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00008103 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02008104 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00008105 while (*envp)
8106 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02008107 popredir(/*drop:*/ 1);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02008108 run_noexec_applet_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00008109 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00008110 /* re-exec ourselves with the new arguments */
8111 execve(bb_busybox_exec_path, argv, envp);
8112 /* If they called chroot or otherwise made the binary no longer
8113 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008114 }
8115#endif
8116
8117 repeat:
8118#ifdef SYSV
8119 do {
8120 execve(cmd, argv, envp);
8121 } while (errno == EINTR);
8122#else
8123 execve(cmd, argv, envp);
8124#endif
Ron Yorstonca82b532018-11-01 11:45:03 +01008125
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008126 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01008127 /* Run "cmd" as a shell script:
8128 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8129 * "If the execve() function fails with ENOEXEC, the shell
8130 * shall execute a command equivalent to having a shell invoked
8131 * with the command name as its first operand,
8132 * with any remaining arguments passed to the new shell"
8133 *
8134 * That is, do not use $SHELL, user's shell, or /bin/sh;
8135 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01008136 *
8137 * Note that bash reads ~80 chars of the file, and if it sees
8138 * a zero byte before it sees newline, it doesn't try to
8139 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01008140 * message and exit code 126. For one, this prevents attempts
8141 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01008142 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008143 argv[0] = (char*) cmd;
8144 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008145 /* NB: this is only possible because all callers of shellexec()
8146 * ensure that the argv[-1] slot exists!
8147 */
8148 argv--;
8149 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008150 goto repeat;
8151 }
8152}
8153
8154/*
8155 * Exec a program. Never returns. If you change this routine, you may
8156 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008157 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008158 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008159static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8160static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008161{
8162 char *cmdname;
8163 int e;
8164 char **envp;
8165 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008166 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008167
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01008168 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008169 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008170#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008171 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008172#endif
8173 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008174 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008175 if (applet_no >= 0) {
8176 /* We tried execing ourself, but it didn't work.
8177 * Maybe /proc/self/exe doesn't exist?
8178 * Try $PATH search.
8179 */
8180 goto try_PATH;
8181 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008182 e = errno;
8183 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008184 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008185 e = ENOENT;
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01008186 while (padvance(&path, argv[0]) >= 0) {
8187 cmdname = stackblock();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008188 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00008189 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008190 if (errno != ENOENT && errno != ENOTDIR)
8191 e = errno;
8192 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008193 }
8194 }
8195
8196 /* Map to POSIX errors */
8197 switch (e) {
Denys Vlasenko2596f412018-08-05 18:04:09 +02008198 default:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008199 exerrno = 126;
8200 break;
Denys Vlasenko2596f412018-08-05 18:04:09 +02008201 case ELOOP:
8202 case ENAMETOOLONG:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008203 case ENOENT:
Denys Vlasenko2596f412018-08-05 18:04:09 +02008204 case ENOTDIR:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008205 exerrno = 127;
8206 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008207 }
8208 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008209 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008210 prog, e, suppress_int));
Denys Vlasenkof977e002020-02-20 16:54:29 +01008211 ash_msg_and_raise(EXEND, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008212 /* NOTREACHED */
8213}
8214
8215static void
8216printentry(struct tblentry *cmdp)
8217{
8218 int idx;
8219 const char *path;
8220 char *name;
8221
8222 idx = cmdp->param.index;
8223 path = pathval();
8224 do {
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01008225 padvance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008226 } while (--idx >= 0);
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01008227 name = stackblock();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008228 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8229}
8230
8231/*
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008232 * Clear out command entries.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008233 */
8234static void
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008235clearcmdentry(void)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008236{
8237 struct tblentry **tblp;
8238 struct tblentry **pp;
8239 struct tblentry *cmdp;
8240
8241 INT_OFF;
8242 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8243 pp = tblp;
8244 while ((cmdp = *pp) != NULL) {
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008245 if (cmdp->cmdtype == CMDNORMAL
Denys Vlasenko22c75922020-02-17 16:20:05 +01008246 || (cmdp->cmdtype == CMDBUILTIN
8247 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8248 && builtinloc > 0
8249 )
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008250 ) {
8251 *pp = cmdp->next;
8252 free(cmdp);
8253 } else {
8254 pp = &cmdp->next;
8255 }
8256 }
8257 }
8258 INT_ON;
8259}
8260
8261/*
8262 * Locate a command in the command hash table. If "add" is nonzero,
8263 * add the command to the table if it is not already present. The
8264 * variable "lastcmdentry" is set to point to the address of the link
8265 * pointing to the entry, so that delete_cmd_entry can delete the
8266 * entry.
8267 *
8268 * Interrupts must be off if called with add != 0.
8269 */
8270static struct tblentry **lastcmdentry;
8271
8272static struct tblentry *
8273cmdlookup(const char *name, int add)
8274{
8275 unsigned int hashval;
8276 const char *p;
8277 struct tblentry *cmdp;
8278 struct tblentry **pp;
8279
8280 p = name;
8281 hashval = (unsigned char)*p << 4;
8282 while (*p)
8283 hashval += (unsigned char)*p++;
8284 hashval &= 0x7FFF;
8285 pp = &cmdtable[hashval % CMDTABLESIZE];
8286 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8287 if (strcmp(cmdp->cmdname, name) == 0)
8288 break;
8289 pp = &cmdp->next;
8290 }
8291 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008292 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8293 + strlen(name)
8294 /* + 1 - already done because
8295 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00008296 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008297 cmdp->cmdtype = CMDUNKNOWN;
8298 strcpy(cmdp->cmdname, name);
8299 }
8300 lastcmdentry = pp;
8301 return cmdp;
8302}
8303
8304/*
8305 * Delete the command entry returned on the last lookup.
8306 */
8307static void
8308delete_cmd_entry(void)
8309{
8310 struct tblentry *cmdp;
8311
8312 INT_OFF;
8313 cmdp = *lastcmdentry;
8314 *lastcmdentry = cmdp->next;
8315 if (cmdp->cmdtype == CMDFUNCTION)
8316 freefunc(cmdp->param.func);
8317 free(cmdp);
8318 INT_ON;
8319}
8320
8321/*
8322 * Add a new command entry, replacing any existing command entry for
8323 * the same name - except special builtins.
8324 */
8325static void
8326addcmdentry(char *name, struct cmdentry *entry)
8327{
8328 struct tblentry *cmdp;
8329
8330 cmdp = cmdlookup(name, 1);
8331 if (cmdp->cmdtype == CMDFUNCTION) {
8332 freefunc(cmdp->param.func);
8333 }
8334 cmdp->cmdtype = entry->cmdtype;
8335 cmdp->param = entry->u;
8336 cmdp->rehash = 0;
8337}
8338
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008339static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008340hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008341{
8342 struct tblentry **pp;
8343 struct tblentry *cmdp;
8344 int c;
8345 struct cmdentry entry;
8346 char *name;
8347
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008348 if (nextopt("r") != '\0') {
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008349 clearcmdentry();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008350 return 0;
8351 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008352
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008353 if (*argptr == NULL) {
8354 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8355 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8356 if (cmdp->cmdtype == CMDNORMAL)
8357 printentry(cmdp);
8358 }
8359 }
8360 return 0;
8361 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008362
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008363 c = 0;
8364 while ((name = *argptr) != NULL) {
8365 cmdp = cmdlookup(name, 0);
8366 if (cmdp != NULL
8367 && (cmdp->cmdtype == CMDNORMAL
Denys Vlasenko22c75922020-02-17 16:20:05 +01008368 || (cmdp->cmdtype == CMDBUILTIN
8369 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8370 && builtinloc > 0
8371 )
8372 )
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008373 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008374 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008375 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008376 find_command(name, &entry, DO_ERR, pathval());
8377 if (entry.cmdtype == CMDUNKNOWN)
8378 c = 1;
8379 argptr++;
8380 }
8381 return c;
8382}
8383
8384/*
8385 * Called when a cd is done. Marks all commands so the next time they
8386 * are executed they will be rehashed.
8387 */
8388static void
8389hashcd(void)
8390{
8391 struct tblentry **pp;
8392 struct tblentry *cmdp;
8393
8394 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8395 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008396 if (cmdp->cmdtype == CMDNORMAL
8397 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008398 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008399 && builtinloc > 0)
8400 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008401 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008402 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008403 }
8404 }
8405}
8406
8407/*
8408 * Fix command hash table when PATH changed.
8409 * Called before PATH is changed. The argument is the new value of PATH;
8410 * pathval() still returns the old value at this point.
8411 * Called with interrupts off.
8412 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008413static void FAST_FUNC
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008414changepath(const char *newval)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008415{
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008416 const char *new;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008417 int idx;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008418 int bltin;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008419
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008420 new = newval;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008421 idx = 0;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008422 bltin = -1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008423 for (;;) {
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008424 if (*new == '%' && prefix(new + 1, "builtin")) {
8425 bltin = idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008426 break;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008427 }
8428 new = strchr(new, ':');
8429 if (!new)
8430 break;
8431 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008432 new++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008433 }
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008434 builtinloc = bltin;
8435 clearcmdentry();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008436}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008437enum {
8438 TEOF,
8439 TNL,
8440 TREDIR,
8441 TWORD,
8442 TSEMI,
8443 TBACKGND,
8444 TAND,
8445 TOR,
8446 TPIPE,
8447 TLP,
8448 TRP,
8449 TENDCASE,
8450 TENDBQUOTE,
8451 TNOT,
8452 TCASE,
8453 TDO,
8454 TDONE,
8455 TELIF,
8456 TELSE,
8457 TESAC,
8458 TFI,
8459 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008460#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008461 TFUNCTION,
8462#endif
8463 TIF,
8464 TIN,
8465 TTHEN,
8466 TUNTIL,
8467 TWHILE,
8468 TBEGIN,
8469 TEND
8470};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008471typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008472
Denys Vlasenko888527c2016-10-02 16:54:17 +02008473/* Nth bit indicates if token marks the end of a list */
8474enum {
8475 tokendlist = 0
8476 /* 0 */ | (1u << TEOF)
8477 /* 1 */ | (0u << TNL)
8478 /* 2 */ | (0u << TREDIR)
8479 /* 3 */ | (0u << TWORD)
8480 /* 4 */ | (0u << TSEMI)
8481 /* 5 */ | (0u << TBACKGND)
8482 /* 6 */ | (0u << TAND)
8483 /* 7 */ | (0u << TOR)
8484 /* 8 */ | (0u << TPIPE)
8485 /* 9 */ | (0u << TLP)
8486 /* 10 */ | (1u << TRP)
8487 /* 11 */ | (1u << TENDCASE)
8488 /* 12 */ | (1u << TENDBQUOTE)
8489 /* 13 */ | (0u << TNOT)
8490 /* 14 */ | (0u << TCASE)
8491 /* 15 */ | (1u << TDO)
8492 /* 16 */ | (1u << TDONE)
8493 /* 17 */ | (1u << TELIF)
8494 /* 18 */ | (1u << TELSE)
8495 /* 19 */ | (1u << TESAC)
8496 /* 20 */ | (1u << TFI)
8497 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008498#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008499 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008500#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008501 /* 23 */ | (0u << TIF)
8502 /* 24 */ | (0u << TIN)
8503 /* 25 */ | (1u << TTHEN)
8504 /* 26 */ | (0u << TUNTIL)
8505 /* 27 */ | (0u << TWHILE)
8506 /* 28 */ | (0u << TBEGIN)
8507 /* 29 */ | (1u << TEND)
8508 , /* thus far 29 bits used */
8509};
8510
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008511static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008512 "end of file",
8513 "newline",
8514 "redirection",
8515 "word",
8516 ";",
8517 "&",
8518 "&&",
8519 "||",
8520 "|",
8521 "(",
8522 ")",
8523 ";;",
8524 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008525#define KWDOFFSET 13
8526 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008527 "!",
8528 "case",
8529 "do",
8530 "done",
8531 "elif",
8532 "else",
8533 "esac",
8534 "fi",
8535 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008536#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008537 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008538#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008539 "if",
8540 "in",
8541 "then",
8542 "until",
8543 "while",
8544 "{",
8545 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008546};
8547
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008548/* Wrapper around strcmp for qsort/bsearch/... */
8549static int
8550pstrcmp(const void *a, const void *b)
8551{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008552 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008553}
8554
8555static const char *const *
8556findkwd(const char *s)
8557{
8558 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008559 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8560 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008561}
8562
8563/*
8564 * Locate and print what a word is...
8565 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008566static int
Ron Yorston3f221112015-08-03 13:47:33 +01008567describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008568{
8569 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008570#if ENABLE_ASH_ALIAS
8571 const struct alias *ap;
8572#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008573
8574 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008575
8576 if (describe_command_verbose) {
8577 out1str(command);
8578 }
8579
8580 /* First look at the keywords */
8581 if (findkwd(command)) {
8582 out1str(describe_command_verbose ? " is a shell keyword" : command);
8583 goto out;
8584 }
8585
8586#if ENABLE_ASH_ALIAS
8587 /* Then look at the aliases */
8588 ap = lookupalias(command, 0);
8589 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008590 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008591 out1str("alias ");
8592 printalias(ap);
8593 return 0;
8594 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008595 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008596 goto out;
8597 }
8598#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008599 /* Brute force */
8600 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008601
8602 switch (entry.cmdtype) {
8603 case CMDNORMAL: {
8604 int j = entry.u.index;
8605 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008606 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008607 p = command;
8608 } else {
8609 do {
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01008610 padvance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008611 } while (--j >= 0);
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01008612 p = stackblock();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008613 }
8614 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008615 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008616 } else {
8617 out1str(p);
8618 }
8619 break;
8620 }
8621
8622 case CMDFUNCTION:
8623 if (describe_command_verbose) {
Denys Vlasenko63c42af2018-07-24 17:08:04 +02008624 /*out1str(" is a shell function");*/
8625 out1str(" is a function"); /* bash says this */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008626 } else {
8627 out1str(command);
8628 }
8629 break;
8630
8631 case CMDBUILTIN:
8632 if (describe_command_verbose) {
8633 out1fmt(" is a %sshell builtin",
8634 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8635 "special " : nullstr
8636 );
8637 } else {
8638 out1str(command);
8639 }
8640 break;
8641
8642 default:
8643 if (describe_command_verbose) {
8644 out1str(": not found\n");
8645 }
8646 return 127;
8647 }
8648 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008649 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008650 return 0;
8651}
8652
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008653static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008654typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008655{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008656 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008657 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008658 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008659
Denis Vlasenko46846e22007-05-20 13:08:31 +00008660 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008661 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008662 i++;
8663 verbose = 0;
8664 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008665 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008666 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008667 }
8668 return err;
8669}
8670
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008671static struct strlist *
8672fill_arglist(struct arglist *arglist, union node **argpp)
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008673{
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008674 struct strlist **lastp = arglist->lastp;
8675 union node *argp;
8676
8677 while ((argp = *argpp) != NULL) {
8678 expandarg(argp, arglist, EXP_FULL | EXP_TILDE);
8679 *argpp = argp->narg.next;
8680 if (*lastp)
8681 break;
8682 }
8683
8684 return *lastp;
8685}
8686
Ron Yorstonda7a6db2020-02-27 09:50:18 +00008687#if ENABLE_ASH_CMDCMD
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008688/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8689static int
8690parse_command_args(struct arglist *arglist, union node **argpp, const char **path)
8691{
8692 struct strlist *sp = arglist->list;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008693 char *cp, c;
8694
8695 for (;;) {
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008696 sp = sp->next ? sp->next : fill_arglist(arglist, argpp);
8697 if (!sp)
8698 return 0;
8699 cp = sp->text;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008700 if (*cp++ != '-')
8701 break;
8702 c = *cp++;
8703 if (!c)
8704 break;
8705 if (c == '-' && !*cp) {
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008706 if (!sp->next && !fill_arglist(arglist, argpp))
8707 return 0;
8708 sp = sp->next;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008709 break;
8710 }
8711 do {
8712 switch (c) {
8713 case 'p':
8714 *path = bb_default_path;
8715 break;
8716 default:
8717 /* run 'typecmd' for other options */
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008718 return 0;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008719 }
8720 c = *cp++;
8721 } while (c);
8722 }
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008723
8724 arglist->list = sp;
8725 return DO_NOFUNC;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008726}
8727
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008728static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008729commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008730{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008731 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008732 int c;
8733 enum {
8734 VERIFY_BRIEF = 1,
8735 VERIFY_VERBOSE = 2,
8736 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008737 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008738
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008739 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8740 * never reaches this function.
8741 */
8742
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008743 while ((c = nextopt("pvV")) != '\0')
8744 if (c == 'V')
8745 verify |= VERIFY_VERBOSE;
8746 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008747 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008748#if DEBUG
8749 else if (c != 'p')
8750 abort();
8751#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008752 else
8753 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008754
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008755 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008756 cmd = *argptr;
8757 if (/*verify && */ cmd)
8758 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008759
8760 return 0;
8761}
8762#endif
8763
8764
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008765/*static int funcblocksize; // size of structures in function */
8766/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008767static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008768static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008769
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008770static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008771 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8772 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8773 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8774 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8775 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8776 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8777 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8778 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8779 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8780 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8781 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8782 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8783 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8784 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8785 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8786 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8787 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008788#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008789 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008790#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008791 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8792 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8793 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8794 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8795 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8796 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8797 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8798 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8799 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008800};
8801
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008802static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008803
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008804static int
8805sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008806{
8807 while (lp) {
8808 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008809 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008810 lp = lp->next;
8811 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008812 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008813}
8814
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008815static int
8816calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008817{
8818 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008819 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008820 funcblocksize += nodesize[n->type];
8821 switch (n->type) {
8822 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008823 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8824 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8825 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008826 break;
8827 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008828 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008829 break;
8830 case NREDIR:
8831 case NBACKGND:
8832 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008833 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8834 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008835 break;
8836 case NAND:
8837 case NOR:
8838 case NSEMI:
8839 case NWHILE:
8840 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008841 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8842 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008843 break;
8844 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008845 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8846 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8847 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008848 break;
8849 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008850 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008851 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8852 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008853 break;
8854 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008855 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8856 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008857 break;
8858 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008859 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8860 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8861 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008862 break;
8863 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008864 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8865 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8866 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008867 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008868 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008869 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008870 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008871 break;
8872 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008873#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008874 case NTO2:
8875#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008876 case NCLOBBER:
8877 case NFROM:
8878 case NFROMTO:
8879 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008880 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8881 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008882 break;
8883 case NTOFD:
8884 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008885 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8886 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008887 break;
8888 case NHERE:
8889 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008890 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8891 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008892 break;
8893 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008894 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008895 break;
8896 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008897 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008898}
8899
8900static char *
8901nodeckstrdup(char *s)
8902{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008903 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008904 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008905}
8906
8907static union node *copynode(union node *);
8908
8909static struct nodelist *
8910copynodelist(struct nodelist *lp)
8911{
8912 struct nodelist *start;
8913 struct nodelist **lpp;
8914
8915 lpp = &start;
8916 while (lp) {
8917 *lpp = funcblock;
8918 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8919 (*lpp)->n = copynode(lp->n);
8920 lp = lp->next;
8921 lpp = &(*lpp)->next;
8922 }
8923 *lpp = NULL;
8924 return start;
8925}
8926
8927static union node *
8928copynode(union node *n)
8929{
8930 union node *new;
8931
8932 if (n == NULL)
8933 return NULL;
8934 new = funcblock;
8935 funcblock = (char *) funcblock + nodesize[n->type];
8936
8937 switch (n->type) {
8938 case NCMD:
8939 new->ncmd.redirect = copynode(n->ncmd.redirect);
8940 new->ncmd.args = copynode(n->ncmd.args);
8941 new->ncmd.assign = copynode(n->ncmd.assign);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008942 new->ncmd.linno = n->ncmd.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008943 break;
8944 case NPIPE:
8945 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008946 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008947 break;
8948 case NREDIR:
8949 case NBACKGND:
8950 case NSUBSHELL:
8951 new->nredir.redirect = copynode(n->nredir.redirect);
8952 new->nredir.n = copynode(n->nredir.n);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008953 new->nredir.linno = n->nredir.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008954 break;
8955 case NAND:
8956 case NOR:
8957 case NSEMI:
8958 case NWHILE:
8959 case NUNTIL:
8960 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8961 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8962 break;
8963 case NIF:
8964 new->nif.elsepart = copynode(n->nif.elsepart);
8965 new->nif.ifpart = copynode(n->nif.ifpart);
8966 new->nif.test = copynode(n->nif.test);
8967 break;
8968 case NFOR:
8969 new->nfor.var = nodeckstrdup(n->nfor.var);
8970 new->nfor.body = copynode(n->nfor.body);
8971 new->nfor.args = copynode(n->nfor.args);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008972 new->nfor.linno = n->nfor.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008973 break;
8974 case NCASE:
8975 new->ncase.cases = copynode(n->ncase.cases);
8976 new->ncase.expr = copynode(n->ncase.expr);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008977 new->ncase.linno = n->ncase.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008978 break;
8979 case NCLIST:
8980 new->nclist.body = copynode(n->nclist.body);
8981 new->nclist.pattern = copynode(n->nclist.pattern);
8982 new->nclist.next = copynode(n->nclist.next);
8983 break;
8984 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008985 new->ndefun.body = copynode(n->ndefun.body);
8986 new->ndefun.text = nodeckstrdup(n->ndefun.text);
8987 new->ndefun.linno = n->ndefun.linno;
8988 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008989 case NARG:
8990 new->narg.backquote = copynodelist(n->narg.backquote);
8991 new->narg.text = nodeckstrdup(n->narg.text);
8992 new->narg.next = copynode(n->narg.next);
8993 break;
8994 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008995#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008996 case NTO2:
8997#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008998 case NCLOBBER:
8999 case NFROM:
9000 case NFROMTO:
9001 case NAPPEND:
9002 new->nfile.fname = copynode(n->nfile.fname);
9003 new->nfile.fd = n->nfile.fd;
9004 new->nfile.next = copynode(n->nfile.next);
9005 break;
9006 case NTOFD:
9007 case NFROMFD:
9008 new->ndup.vname = copynode(n->ndup.vname);
9009 new->ndup.dupfd = n->ndup.dupfd;
9010 new->ndup.fd = n->ndup.fd;
9011 new->ndup.next = copynode(n->ndup.next);
9012 break;
9013 case NHERE:
9014 case NXHERE:
9015 new->nhere.doc = copynode(n->nhere.doc);
9016 new->nhere.fd = n->nhere.fd;
9017 new->nhere.next = copynode(n->nhere.next);
9018 break;
9019 case NNOT:
9020 new->nnot.com = copynode(n->nnot.com);
9021 break;
9022 };
9023 new->type = n->type;
9024 return new;
9025}
9026
9027/*
9028 * Make a copy of a parse tree.
9029 */
9030static struct funcnode *
9031copyfunc(union node *n)
9032{
9033 struct funcnode *f;
9034 size_t blocksize;
9035
Denys Vlasenko4c438b52016-10-07 04:05:15 +02009036 /*funcstringsize = 0;*/
9037 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
9038 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009039 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02009040 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009041 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02009042 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009043 return f;
9044}
9045
9046/*
9047 * Define a shell function.
9048 */
9049static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009050defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009051{
9052 struct cmdentry entry;
9053
9054 INT_OFF;
9055 entry.cmdtype = CMDFUNCTION;
9056 entry.u.func = copyfunc(func);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009057 addcmdentry(func->ndefun.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009058 INT_ON;
9059}
9060
Denis Vlasenko4b875702009-03-19 13:30:04 +00009061/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009062#define SKIPBREAK (1 << 0)
9063#define SKIPCONT (1 << 1)
9064#define SKIPFUNC (1 << 2)
Denys Vlasenkocd24a502020-02-20 16:47:01 +01009065#define SKIPFUNCDEF (1 << 3)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009066static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009067static int skipcount; /* number of levels to skip */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00009068static int loopnest; /* current loop nesting level */
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009069static int funcline; /* starting line number of current function, or 0 if not in a function */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009070
Denis Vlasenko4b875702009-03-19 13:30:04 +00009071/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009072static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009073
Denis Vlasenko4b875702009-03-19 13:30:04 +00009074/* Called to execute a trap.
9075 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02009076 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00009077 *
9078 * Perhaps we should avoid entering new trap handlers
9079 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009080 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009081static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009082dotrap(void)
9083{
Denis Vlasenko4b875702009-03-19 13:30:04 +00009084 uint8_t *g;
9085 int sig;
Denys Vlasenko4ccddc82020-02-14 17:27:18 +01009086 int status, last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009087
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009088 if (!pending_sig)
9089 return;
9090
Denys Vlasenko4ccddc82020-02-14 17:27:18 +01009091 status = savestatus;
9092 last_status = status;
9093 if (status < 0) {
9094 status = exitstatus;
9095 savestatus = status;
9096 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009097 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02009098 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009099
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009100 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00009101 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009102 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009103
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009104 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009105 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009106
9107 if (evalskip) {
9108 pending_sig = sig;
9109 break;
9110 }
9111
9112 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00009113 /* non-trapped SIGINT is handled separately by raise_interrupt,
9114 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009115 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009116 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009117
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009118 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00009119 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009120 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009121 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009122 evalstring(p, 0);
Denys Vlasenkocd24a502020-02-20 16:47:01 +01009123 if (evalskip != SKIPFUNC)
9124 exitstatus = status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009125 }
Denys Vlasenko4ccddc82020-02-14 17:27:18 +01009126
9127 savestatus = last_status;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009128 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009129}
9130
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00009131/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009132static int evalloop(union node *, int);
9133static int evalfor(union node *, int);
9134static int evalcase(union node *, int);
9135static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009136static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009137static int evalpipe(union node *, int);
9138static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009139static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009140static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009141
Eric Andersen62483552001-07-10 06:09:16 +00009142/*
Eric Andersenc470f442003-07-28 09:56:35 +00009143 * Evaluate a parse tree. The value is left in the global variable
9144 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00009145 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009146static int
Eric Andersenc470f442003-07-28 09:56:35 +00009147evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00009148{
Eric Andersenc470f442003-07-28 09:56:35 +00009149 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009150 int (*evalfn)(union node *, int);
Ron Yorstonf55161a2019-02-25 08:29:38 +00009151 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009152 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009153
Ron Yorstonf55161a2019-02-25 08:29:38 +00009154 setstackmark(&smark);
9155
Eric Andersenc470f442003-07-28 09:56:35 +00009156 if (n == NULL) {
9157 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009158 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00009159 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009160 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009161
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009162 dotrap();
9163
Eric Andersenc470f442003-07-28 09:56:35 +00009164 switch (n->type) {
9165 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009166#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00009167 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009168 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00009169 break;
9170#endif
9171 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009172 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009173 goto setstatus;
9174 case NREDIR:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009175 errlinno = lineno = n->nredir.linno;
9176 if (funcline)
9177 lineno -= funcline - 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009178 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009179 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00009180 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9181 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009182 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009183 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009184 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02009185 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00009186 goto setstatus;
9187 case NCMD:
9188 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009189 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00009190 if (eflag && !(flags & EV_TESTED))
9191 checkexit = ~0;
9192 goto calleval;
9193 case NFOR:
9194 evalfn = evalfor;
9195 goto calleval;
9196 case NWHILE:
9197 case NUNTIL:
9198 evalfn = evalloop;
9199 goto calleval;
9200 case NSUBSHELL:
9201 case NBACKGND:
9202 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02009203 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00009204 case NPIPE:
9205 evalfn = evalpipe;
9206 goto checkexit;
9207 case NCASE:
9208 evalfn = evalcase;
9209 goto calleval;
9210 case NAND:
9211 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009212 case NSEMI: {
9213
Eric Andersenc470f442003-07-28 09:56:35 +00009214#if NAND + 1 != NOR
9215#error NAND + 1 != NOR
9216#endif
9217#if NOR + 1 != NSEMI
9218#error NOR + 1 != NSEMI
9219#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00009220 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009221 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00009222 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009223 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00009224 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02009225 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00009226 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009227 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009228 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009229 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009230 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009231 status = evalfn(n, flags);
9232 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009233 }
Eric Andersenc470f442003-07-28 09:56:35 +00009234 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009235 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009236 if (evalskip)
9237 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009238 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00009239 n = n->nif.ifpart;
9240 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009241 }
9242 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00009243 n = n->nif.elsepart;
9244 goto evaln;
9245 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009246 status = 0;
9247 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009248 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009249 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009250 /* Not necessary. To test it:
9251 * "false; f() { qwerty; }; echo $?" should print 0.
9252 */
9253 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009254 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00009255 exitstatus = status;
9256 break;
9257 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009258 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02009259 /* Order of checks below is important:
9260 * signal handlers trigger before exit caused by "set -e".
9261 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009262 dotrap();
9263
9264 if (checkexit & status)
Denys Vlasenkof977e002020-02-20 16:54:29 +01009265 raise_exception(EXEND);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009266 if (flags & EV_EXIT)
Denys Vlasenkof977e002020-02-20 16:54:29 +01009267 raise_exception(EXEND);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009268
Ron Yorstonf55161a2019-02-25 08:29:38 +00009269 popstackmark(&smark);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009270 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009271 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00009272}
9273
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02009274static int
9275skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009276{
9277 int skip = evalskip;
9278
9279 switch (skip) {
9280 case 0:
9281 break;
9282 case SKIPBREAK:
9283 case SKIPCONT:
9284 if (--skipcount <= 0) {
9285 evalskip = 0;
9286 break;
9287 }
9288 skip = SKIPBREAK;
9289 break;
9290 }
9291 return skip;
9292}
9293
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009294static int
Eric Andersenc470f442003-07-28 09:56:35 +00009295evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009296{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009297 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00009298 int status;
9299
9300 loopnest++;
9301 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009302 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009303 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009304 int i;
9305
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009306 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009307 skip = skiploop();
9308 if (skip == SKIPFUNC)
9309 status = i;
9310 if (skip)
9311 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00009312 if (n->type != NWHILE)
9313 i = !i;
9314 if (i != 0)
9315 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009316 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009317 skip = skiploop();
9318 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009319 loopnest--;
9320
9321 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009322}
9323
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009324static int
Eric Andersenc470f442003-07-28 09:56:35 +00009325evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009326{
9327 struct arglist arglist;
9328 union node *argp;
9329 struct strlist *sp;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009330 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009331
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009332 errlinno = lineno = n->ncase.linno;
9333 if (funcline)
9334 lineno -= funcline - 1;
9335
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009336 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009337 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009338 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02009339 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00009340 }
9341 *arglist.lastp = NULL;
9342
Eric Andersencb57d552001-06-28 07:25:16 +00009343 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009344 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009345 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009346 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009347 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009348 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00009349 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009350 }
9351 loopnest--;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009352
9353 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009354}
9355
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009356static int
Eric Andersenc470f442003-07-28 09:56:35 +00009357evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009358{
9359 union node *cp;
9360 union node *patp;
9361 struct arglist arglist;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009362 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009363
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009364 errlinno = lineno = n->ncase.linno;
9365 if (funcline)
9366 lineno -= funcline - 1;
9367
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009368 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009369 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009370 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009371 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9372 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009373 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009374 /* Ensure body is non-empty as otherwise
9375 * EV_EXIT may prevent us from setting the
9376 * exit status.
9377 */
9378 if (evalskip == 0 && cp->nclist.body) {
9379 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009380 }
9381 goto out;
9382 }
9383 }
9384 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009385 out:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009386 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009387}
9388
Eric Andersenc470f442003-07-28 09:56:35 +00009389/*
9390 * Kick off a subshell to evaluate a tree.
9391 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009392static int
Eric Andersenc470f442003-07-28 09:56:35 +00009393evalsubshell(union node *n, int flags)
9394{
9395 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009396 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009397 int status;
9398
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009399 errlinno = lineno = n->nredir.linno;
9400 if (funcline)
9401 lineno -= funcline - 1;
9402
Eric Andersenc470f442003-07-28 09:56:35 +00009403 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009404 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009405 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009406 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009407 if (backgnd == FORK_FG)
9408 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009409 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009410 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009411 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009412 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009413 flags |= EV_EXIT;
9414 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009415 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009416 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009417 redirect(n->nredir.redirect, 0);
9418 evaltreenr(n->nredir.n, flags);
9419 /* never returns */
9420 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009421 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009422 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009423 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009424 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009425 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009426 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009427}
9428
Eric Andersenc470f442003-07-28 09:56:35 +00009429/*
9430 * Compute the names of the files in a redirection list.
9431 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009432static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009433static void
9434expredir(union node *n)
9435{
9436 union node *redir;
9437
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009438 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009439 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009440
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009441 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009442 fn.lastp = &fn.list;
9443 switch (redir->type) {
9444 case NFROMTO:
9445 case NFROM:
9446 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009447#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009448 case NTO2:
9449#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009450 case NCLOBBER:
9451 case NAPPEND:
9452 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009453 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009454#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009455 store_expfname:
9456#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009457#if 0
9458// By the design of stack allocator, the loop of this kind:
9459// while true; do while true; do break; done </dev/null; done
9460// will look like a memory leak: ash plans to free expfname's
9461// of "/dev/null" as soon as it finishes running the loop
9462// (in this case, never).
9463// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009464 if (redir->nfile.expfname)
9465 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009466// It results in corrupted state of stacked allocations.
9467#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009468 redir->nfile.expfname = fn.list->text;
9469 break;
9470 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009471 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009472 if (redir->ndup.vname) {
Denys Vlasenkoe368d852020-02-16 19:02:22 +01009473 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009474 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009475 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009476#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009477 if (!isdigit_str9(fn.list->text)) {
9478 /* >&file, not >&fd */
9479 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9480 ash_msg_and_raise_error("redir error");
9481 redir->type = NTO2;
9482 goto store_expfname;
9483 }
9484#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009485 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009486 }
9487 break;
9488 }
9489 }
9490}
9491
Eric Andersencb57d552001-06-28 07:25:16 +00009492/*
Eric Andersencb57d552001-06-28 07:25:16 +00009493 * Evaluate a pipeline. All the processes in the pipeline are children
9494 * of the process creating the pipeline. (This differs from some versions
9495 * of the shell, which make the last process in a pipeline the parent
9496 * of all the rest.)
9497 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009498static int
Eric Andersenc470f442003-07-28 09:56:35 +00009499evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009500{
9501 struct job *jp;
9502 struct nodelist *lp;
9503 int pipelen;
9504 int prevfd;
9505 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009506 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009507
Eric Andersenc470f442003-07-28 09:56:35 +00009508 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009509 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009510 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009511 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009512 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009513 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009514 if (n->npipe.pipe_backgnd == 0)
9515 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009516 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009517 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009518 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009519 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009520 pip[1] = -1;
9521 if (lp->next) {
9522 if (pipe(pip) < 0) {
9523 close(prevfd);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02009524 ash_msg_and_raise_perror("can't create pipe");
Eric Andersencb57d552001-06-28 07:25:16 +00009525 }
9526 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009527 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009528 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009529 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009530 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009531 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009532 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009533 if (prevfd > 0) {
9534 dup2(prevfd, 0);
9535 close(prevfd);
9536 }
9537 if (pip[1] > 1) {
9538 dup2(pip[1], 1);
9539 close(pip[1]);
9540 }
Eric Andersenc470f442003-07-28 09:56:35 +00009541 evaltreenr(lp->n, flags);
9542 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009543 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009544 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009545 if (prevfd >= 0)
9546 close(prevfd);
9547 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009548 /* Don't want to trigger debugging */
9549 if (pip[1] != -1)
9550 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009551 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009552 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009553 status = waitforjob(jp);
9554 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009555 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009556 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009557
9558 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009559}
9560
Ron Yorston9e2a5662020-01-21 16:01:58 +00009561/* setinteractive needs this forward reference */
9562#if EDITING_HAS_get_exe_name
9563static const char *get_builtin_name(int i) FAST_FUNC;
9564#endif
9565
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009566/*
9567 * Controls whether the shell is interactive or not.
9568 */
9569static void
9570setinteractive(int on)
9571{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009572 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009573
9574 if (++on == is_interactive)
9575 return;
9576 is_interactive = on;
9577 setsignal(SIGINT);
9578 setsignal(SIGQUIT);
9579 setsignal(SIGTERM);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009580 if (is_interactive > 1) {
Denys Vlasenko897475a2019-06-01 16:35:09 +02009581#if !ENABLE_FEATURE_SH_EXTRA_QUIET
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009582 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009583 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009584
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009585 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009586 /* note: ash and hush share this string */
9587 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009588 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9589 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009590 bb_banner,
9591 "built-in shell (ash)"
9592 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009593 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009594 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009595#endif
Denys Vlasenko897475a2019-06-01 16:35:09 +02009596#if ENABLE_FEATURE_EDITING
Ron Yorston9e2a5662020-01-21 16:01:58 +00009597 if (!line_input_state) {
Denys Vlasenko897475a2019-06-01 16:35:09 +02009598 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
Ron Yorston9e2a5662020-01-21 16:01:58 +00009599# if EDITING_HAS_get_exe_name
9600 line_input_state->get_exe_name = get_builtin_name;
9601# endif
9602 }
Denys Vlasenko897475a2019-06-01 16:35:09 +02009603#endif
9604 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009605}
9606
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009607static void
9608optschanged(void)
9609{
9610#if DEBUG
9611 opentrace();
9612#endif
9613 setinteractive(iflag);
9614 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009615#if ENABLE_FEATURE_EDITING_VI
Denys Vlasenko897475a2019-06-01 16:35:09 +02009616 if (line_input_state) {
9617 if (viflag)
9618 line_input_state->flags |= VI_MODE;
9619 else
9620 line_input_state->flags &= ~VI_MODE;
9621 }
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009622#else
9623 viflag = 0; /* forcibly keep the option off */
9624#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009625}
9626
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009627struct localvar_list {
9628 struct localvar_list *next;
9629 struct localvar *lv;
9630};
9631
9632static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009633
9634/*
9635 * Called after a function returns.
9636 * Interrupts must be off.
9637 */
9638static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009639poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009640{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009641 struct localvar_list *ll;
9642 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009643 struct var *vp;
9644
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009645 INT_OFF;
9646 ll = localvar_stack;
9647 localvar_stack = ll->next;
9648
9649 next = ll->lv;
9650 free(ll);
9651
9652 while ((lvp = next) != NULL) {
9653 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009654 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009655 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009656 if (keep) {
9657 int bits = VSTRFIXED;
9658
9659 if (lvp->flags != VUNSET) {
9660 if (vp->var_text == lvp->text)
9661 bits |= VTEXTFIXED;
9662 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9663 free((char*)lvp->text);
9664 }
9665
9666 vp->flags &= ~bits;
9667 vp->flags |= (lvp->flags & bits);
9668
9669 if ((vp->flags &
9670 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9671 unsetvar(vp->var_text);
9672 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009673 memcpy(optlist, lvp->text, sizeof(optlist));
9674 free((char*)lvp->text);
9675 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009676 } else if (lvp->flags == VUNSET) {
9677 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009678 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009679 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009680 if (vp->var_func)
9681 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009682 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009683 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009684 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009685 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009686 }
9687 free(lvp);
9688 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009689 INT_ON;
9690}
9691
9692/*
9693 * Create a new localvar environment.
9694 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009695static struct localvar_list *
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +01009696pushlocalvars(int push)
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009697{
9698 struct localvar_list *ll;
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +01009699 struct localvar_list *top;
9700
9701 top = localvar_stack;
9702 if (!push)
9703 goto out;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009704
9705 INT_OFF;
9706 ll = ckzalloc(sizeof(*ll));
9707 /*ll->lv = NULL; - zalloc did it */
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +01009708 ll->next = top;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009709 localvar_stack = ll;
9710 INT_ON;
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +01009711 out:
9712 return top;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009713}
9714
9715static void
9716unwindlocalvars(struct localvar_list *stop)
9717{
9718 while (localvar_stack != stop)
9719 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009720}
9721
9722static int
9723evalfun(struct funcnode *func, int argc, char **argv, int flags)
9724{
9725 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009726 struct jmploc *volatile savehandler;
9727 struct jmploc jmploc;
9728 int e;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009729 int savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009730
9731 saveparam = shellparam;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009732 savefuncline = funcline;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009733 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009734 e = setjmp(jmploc.loc);
9735 if (e) {
9736 goto funcdone;
9737 }
9738 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009739 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009740 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009741 func->count++;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009742 funcline = func->n.ndefun.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009743 INT_ON;
9744 shellparam.nparam = argc - 1;
9745 shellparam.p = argv + 1;
9746#if ENABLE_ASH_GETOPTS
9747 shellparam.optind = 1;
9748 shellparam.optoff = -1;
9749#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009750 evaltree(func->n.ndefun.body, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009751 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009752 INT_OFF;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009753 funcline = savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009754 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009755 freeparam(&shellparam);
9756 shellparam = saveparam;
9757 exception_handler = savehandler;
9758 INT_ON;
Denys Vlasenkocd24a502020-02-20 16:47:01 +01009759 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009760 return e;
9761}
9762
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009763/*
9764 * Make a variable a local variable. When a variable is made local, it's
9765 * value and flags are saved in a localvar structure. The saved values
9766 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009767 * "-" as a special case: it makes changes to "set +-options" local
9768 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009769 */
9770static void
Denys Vlasenko3e729102020-02-19 17:33:44 +01009771mklocal(char *name, int flags)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009772{
9773 struct localvar *lvp;
9774 struct var **vpp;
9775 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009776 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009777
9778 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009779 /* Cater for duplicate "local". Examples:
9780 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9781 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9782 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009783 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009784 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009785 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009786 if (eq)
9787 setvareq(name, 0);
9788 /* else:
9789 * it's a duplicate "local VAR" declaration, do nothing
9790 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009791 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009792 }
9793 lvp = lvp->next;
9794 }
9795
9796 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009797 if (LONE_DASH(name)) {
9798 char *p;
9799 p = ckmalloc(sizeof(optlist));
9800 lvp->text = memcpy(p, optlist, sizeof(optlist));
9801 vp = NULL;
9802 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009803 vpp = hashvar(name);
9804 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009805 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009806 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009807 if (eq)
Denys Vlasenko3e729102020-02-19 17:33:44 +01009808 vp = setvareq(name, VSTRFIXED | flags);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009809 else
Denys Vlasenko3e729102020-02-19 17:33:44 +01009810 vp = setvar(name, NULL, VSTRFIXED | flags);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009811 lvp->flags = VUNSET;
9812 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009813 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009814 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009815 /* make sure neither "struct var" nor string gets freed
9816 * during (un)setting:
9817 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009818 vp->flags |= VSTRFIXED|VTEXTFIXED;
9819 if (eq)
Denys Vlasenko3e729102020-02-19 17:33:44 +01009820 setvareq(name, flags);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009821 else
9822 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009823 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009824 }
9825 }
9826 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009827 lvp->next = localvar_stack->lv;
9828 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009829 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009830 INT_ON;
9831}
9832
9833/*
9834 * The "local" command.
9835 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009836static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009837localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009838{
9839 char *name;
9840
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009841 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009842 ash_msg_and_raise_error("not in a function");
9843
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009844 argv = argptr;
9845 while ((name = *argv++) != NULL) {
Denys Vlasenko3e729102020-02-19 17:33:44 +01009846 mklocal(name, 0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009847 }
9848 return 0;
9849}
9850
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009851static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009852falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009853{
9854 return 1;
9855}
9856
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009857static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009858truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009859{
9860 return 0;
9861}
9862
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009863static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009864execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009865{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009866 optionarg = NULL;
9867 while (nextopt("a:") != '\0')
9868 /* nextopt() sets optionarg to "-a ARGV0" */;
9869
9870 argv = argptr;
9871 if (argv[0]) {
9872 char *prog;
9873
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009874 iflag = 0; /* exit on error */
9875 mflag = 0;
9876 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009877 /* We should set up signals for "exec CMD"
9878 * the same way as for "CMD" without "exec".
9879 * But optschanged->setinteractive->setsignal
9880 * still thought we are a root shell. Therefore, for example,
9881 * SIGQUIT is still set to IGN. Fix it:
9882 */
9883 shlvl++;
9884 setsignal(SIGQUIT);
9885 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9886 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9887 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9888
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009889 prog = argv[0];
9890 if (optionarg)
9891 argv[0] = optionarg;
9892 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009893 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009894 }
9895 return 0;
9896}
9897
9898/*
9899 * The return command.
9900 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009901static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009902returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009903{
Denys Vlasenkocd24a502020-02-20 16:47:01 +01009904 int skip;
9905 int status;
9906
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009907 /*
9908 * If called outside a function, do what ksh does;
9909 * skip the rest of the file.
9910 */
Denys Vlasenkocd24a502020-02-20 16:47:01 +01009911 if (argv[1]) {
9912 skip = SKIPFUNC;
9913 status = number(argv[1]);
9914 } else {
9915 skip = SKIPFUNCDEF;
9916 status = exitstatus;
9917 }
9918 evalskip = skip;
9919
9920 return status;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009921}
9922
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009923/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009924static int breakcmd(int, char **) FAST_FUNC;
9925static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009926static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009927static int exitcmd(int, char **) FAST_FUNC;
9928static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009929#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009930static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009931#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009932#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009933static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009934#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009935#if MAX_HISTORY
9936static int historycmd(int, char **) FAST_FUNC;
9937#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009938#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009939static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009940#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009941static int readcmd(int, char **) FAST_FUNC;
9942static int setcmd(int, char **) FAST_FUNC;
9943static int shiftcmd(int, char **) FAST_FUNC;
9944static int timescmd(int, char **) FAST_FUNC;
9945static int trapcmd(int, char **) FAST_FUNC;
9946static int umaskcmd(int, char **) FAST_FUNC;
9947static int unsetcmd(int, char **) FAST_FUNC;
9948static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009949
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009950#define BUILTIN_NOSPEC "0"
9951#define BUILTIN_SPECIAL "1"
9952#define BUILTIN_REGULAR "2"
9953#define BUILTIN_SPEC_REG "3"
9954#define BUILTIN_ASSIGN "4"
9955#define BUILTIN_SPEC_ASSG "5"
9956#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009957#define BUILTIN_SPEC_REG_ASSG "7"
9958
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009959/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009960#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009961static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009962#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009963#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009964static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009965#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009966#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009967static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009968#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009969
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009970/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009971static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009972 { BUILTIN_SPEC_REG "." , dotcmd },
9973 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009974#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009975 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009976#endif
9977#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009978 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009979#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009980#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009981 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009982#endif
9983#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009984 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009985#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009986 { BUILTIN_SPEC_REG "break" , breakcmd },
9987 { BUILTIN_REGULAR "cd" , cdcmd },
9988 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009989#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009990 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009991#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009992 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009993#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009994 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009995#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009996 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009997 { BUILTIN_SPEC_REG "exec" , execcmd },
9998 { BUILTIN_SPEC_REG "exit" , exitcmd },
9999 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
10000 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010001#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010002 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010003#endif
10004#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010005 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010006#endif
Denys Vlasenkoa7b97e32020-02-16 18:29:52 +010010007 { BUILTIN_REGULAR "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +020010008#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010009 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010010#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +020010011#if MAX_HISTORY
10012 { BUILTIN_NOSPEC "history" , historycmd },
10013#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010014#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010015 { BUILTIN_REGULAR "jobs" , jobscmd },
10016 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010017#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +010010018#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010019 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010020#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +020010021 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +010010022#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010023 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +000010024#endif
Denys Vlasenkoa7b97e32020-02-16 18:29:52 +010010025 { BUILTIN_REGULAR "pwd" , pwdcmd },
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010026 { BUILTIN_REGULAR "read" , readcmd },
10027 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
10028 { BUILTIN_SPEC_REG "return" , returncmd },
10029 { BUILTIN_SPEC_REG "set" , setcmd },
10030 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010010031#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010032 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +020010033#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +010010034#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010035 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010036#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010037 { BUILTIN_SPEC_REG "times" , timescmd },
10038 { BUILTIN_SPEC_REG "trap" , trapcmd },
10039 { BUILTIN_REGULAR "true" , truecmd },
Denys Vlasenkoa7b97e32020-02-16 18:29:52 +010010040 { BUILTIN_REGULAR "type" , typecmd },
10041 { BUILTIN_REGULAR "ulimit" , ulimitcmd },
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010042 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010043#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010044 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010045#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010046 { BUILTIN_SPEC_REG "unset" , unsetcmd },
10047 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010048};
10049
Denis Vlasenko80591b02008-03-25 07:49:43 +000010050/* Should match the above table! */
10051#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +020010052 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +010010053 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010010054 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +020010055 /* alias */ 1 * ENABLE_ASH_ALIAS + \
10056 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
10057 /* break cd cddir */ 3)
10058#define EVALCMD (COMMANDCMD + \
10059 /* command */ 1 * ENABLE_ASH_CMDCMD + \
10060 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +010010061 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +020010062 0)
10063#define EXECCMD (EVALCMD + \
10064 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010065
10066/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000010067 * Search the table of builtin commands.
10068 */
Denys Vlasenko888527c2016-10-02 16:54:17 +020010069static int
10070pstrcmp1(const void *a, const void *b)
10071{
10072 return strcmp((char*)a, *(char**)b + 1);
10073}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000010074static struct builtincmd *
10075find_builtin(const char *name)
10076{
10077 struct builtincmd *bp;
10078
10079 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +000010080 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +020010081 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000010082 );
10083 return bp;
10084}
10085
Ron Yorston9e2a5662020-01-21 16:01:58 +000010086#if EDITING_HAS_get_exe_name
10087static const char * FAST_FUNC
10088get_builtin_name(int i)
10089{
10090 return /*i >= 0 &&*/ i < ARRAY_SIZE(builtintab) ? builtintab[i].name + 1 : NULL;
10091}
10092#endif
10093
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000010094/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010095 * Execute a simple command.
10096 */
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010097static void unwindfiles(struct parsefile *stop);
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010098static int
10099isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +000010100{
10101 const char *q = endofname(p);
10102 if (p == q)
10103 return 0;
10104 return *q == '=';
10105}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010106static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010107bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010108{
10109 /* Preserve exitstatus of a previous possible redirection
10110 * as POSIX mandates */
10111 return back_exitstatus;
10112}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010113static int
Eric Andersenc470f442003-07-28 09:56:35 +000010114evalcommand(union node *cmd, int flags)
10115{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010116 static const struct builtincmd null_bltin = {
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010117 BUILTIN_REGULAR "", bltincmd
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010118 };
Denys Vlasenko484fc202017-07-26 19:55:31 +020010119 struct localvar_list *localvar_stop;
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010120 struct parsefile *file_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010121 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +000010122 union node *argp;
10123 struct arglist arglist;
10124 struct arglist varlist;
10125 char **argv;
10126 int argc;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010127 struct strlist *osp;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010128 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +000010129 struct cmdentry cmdentry;
10130 struct job *jp;
10131 char *lastarg;
10132 const char *path;
10133 int spclbltin;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010134 int cmd_flag;
Eric Andersenc470f442003-07-28 09:56:35 +000010135 int status;
10136 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +000010137 smallint cmd_is_exec;
Denys Vlasenko3e729102020-02-19 17:33:44 +010010138 int vflags;
10139 int vlocal;
Eric Andersenc470f442003-07-28 09:56:35 +000010140
Denys Vlasenko675d24a2018-01-27 22:02:05 +010010141 errlinno = lineno = cmd->ncmd.linno;
10142 if (funcline)
10143 lineno -= funcline - 1;
10144
Eric Andersenc470f442003-07-28 09:56:35 +000010145 /* First expand the arguments. */
10146 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010147 file_stop = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010148 back_exitstatus = 0;
10149
10150 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010151 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +000010152 varlist.lastp = &varlist.list;
10153 *varlist.lastp = NULL;
10154 arglist.lastp = &arglist.list;
10155 *arglist.lastp = NULL;
10156
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010157 cmd_flag = 0;
10158 cmd_is_exec = 0;
10159 spclbltin = -1;
Denys Vlasenko3e729102020-02-19 17:33:44 +010010160 vflags = 0;
10161 vlocal = 0;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010162 path = NULL;
10163
Eric Andersenc470f442003-07-28 09:56:35 +000010164 argc = 0;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010165 argp = cmd->ncmd.args;
10166 osp = fill_arglist(&arglist, &argp);
10167 if (osp) {
10168 int pseudovarflag = 0;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010169
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010170 for (;;) {
10171 find_command(arglist.list->text, &cmdentry,
10172 cmd_flag | DO_REGBLTIN, pathval());
Paul Foxc3850c82005-07-20 18:23:39 +000010173
Denys Vlasenko3e729102020-02-19 17:33:44 +010010174 vlocal++;
10175
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010176 /* implement bltin and command here */
10177 if (cmdentry.cmdtype != CMDBUILTIN)
10178 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010179
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010180 pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
10181 if (spclbltin < 0) {
10182 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
Denys Vlasenko3e729102020-02-19 17:33:44 +010010183 vlocal = !spclbltin;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010184 }
10185 cmd_is_exec = cmdentry.u.cmd == EXECCMD;
Ron Yorstonda7a6db2020-02-27 09:50:18 +000010186#if ENABLE_ASH_CMDCMD
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010187 if (cmdentry.u.cmd != COMMANDCMD)
10188 break;
Paul Foxc3850c82005-07-20 18:23:39 +000010189
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010190 cmd_flag = parse_command_args(&arglist, &argp, &path);
10191 if (!cmd_flag)
Ron Yorstonda7a6db2020-02-27 09:50:18 +000010192#endif
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010193 break;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010194 }
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010195
10196 for (; argp; argp = argp->narg.next)
10197 expandarg(argp, &arglist,
10198 pseudovarflag &&
10199 isassignment(argp->narg.text) ?
10200 EXP_VARTILDE : EXP_FULL | EXP_TILDE);
10201
10202 for (sp = arglist.list; sp; sp = sp->next)
10203 argc++;
Denys Vlasenko3e729102020-02-19 17:33:44 +010010204
10205 if (cmd_is_exec && argc > 1)
10206 vflags = VEXPORT;
Eric Andersenc470f442003-07-28 09:56:35 +000010207 }
10208
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +010010209 localvar_stop = pushlocalvars(vlocal);
10210
Denys Vlasenko65a8b852016-10-26 22:29:11 +020010211 /* Reserve one extra spot at the front for shellexec. */
10212 nargv = stalloc(sizeof(char *) * (argc + 2));
10213 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010214 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +000010215 TRACE(("evalcommand arg: %s\n", sp->text));
10216 *nargv++ = sp->text;
10217 }
10218 *nargv = NULL;
10219
10220 lastarg = NULL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010010221 if (iflag && funcline == 0 && argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010222 lastarg = nargv[-1];
10223
10224 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010225 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010226 preverrout_fd = 2;
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +020010227 if (BASH_XTRACEFD && xflag) {
10228 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10229 * we do not emulate this. We only use its value.
10230 */
10231 const char *xtracefd = lookupvar("BASH_XTRACEFD");
10232 if (xtracefd && is_number(xtracefd))
10233 preverrout_fd = atoi(xtracefd);
10234
10235 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010236 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +000010237
Denys Vlasenko54bef2a2020-02-19 15:30:20 +010010238 if (status) {
10239 bail:
10240 exitstatus = status;
10241
10242 /* We have a redirection error. */
10243 if (spclbltin > 0)
10244 raise_exception(EXERROR);
10245
10246 goto out;
10247 }
10248
Eric Andersenc470f442003-07-28 09:56:35 +000010249 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10250 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +000010251
10252 spp = varlist.lastp;
10253 expandarg(argp, &varlist, EXP_VARTILDE);
10254
Denys Vlasenko3e729102020-02-19 17:33:44 +010010255 if (vlocal)
10256 mklocal((*spp)->text, VEXPORT);
10257 else
10258 setvareq((*spp)->text, vflags);
Eric Andersenc470f442003-07-28 09:56:35 +000010259 }
10260
10261 /* Print the command if xflag is set. */
10262 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010263 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +000010264
Denys Vlasenko46999802017-07-29 21:12:29 +020010265 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010266
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010267 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010268 while (sp) {
10269 char *varval = sp->text;
10270 char *eq = strchrnul(varval, '=');
10271 if (*eq)
10272 eq++;
10273 fdprintf(preverrout_fd, "%s%.*s%s",
10274 pfx,
10275 (int)(eq - varval), varval,
10276 maybe_single_quote(eq)
10277 );
10278 sp = sp->next;
10279 pfx = " ";
10280 }
10281
10282 sp = arglist.list;
10283 while (sp) {
10284 fdprintf(preverrout_fd, "%s%s",
10285 pfx,
10286 /* always quote if matches reserved word: */
10287 findkwd(sp->text)
10288 ? single_quote(sp->text)
10289 : maybe_single_quote(sp->text)
10290 );
10291 sp = sp->next;
10292 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010293 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010294 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010295 }
10296
Eric Andersenc470f442003-07-28 09:56:35 +000010297 /* Now locate the command. */
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010298 if (cmdentry.cmdtype != CMDBUILTIN
10299 || !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
10300 ) {
Denys Vlasenko3e729102020-02-19 17:33:44 +010010301 path = path ? path : pathval();
10302 find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path);
Eric Andersenc470f442003-07-28 09:56:35 +000010303 }
10304
Denys Vlasenkod81af722020-02-18 14:28:30 +010010305 jp = NULL;
10306
Eric Andersenc470f442003-07-28 09:56:35 +000010307 /* Execute the command. */
10308 switch (cmdentry.cmdtype) {
Denys Vlasenko54bef2a2020-02-19 15:30:20 +010010309 case CMDUNKNOWN:
10310 status = 127;
10311 flush_stdout_stderr();
10312 goto bail;
10313
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010314 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010315
Denys Vlasenko1750d3a2018-01-15 00:41:04 +010010316#if ENABLE_FEATURE_SH_STANDALONE \
10317 && ENABLE_FEATURE_SH_NOFORK \
10318 && NUM_APPLETS > 1
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010319/* (1) BUG: if variables are set, we need to fork, or save/restore them
10320 * around run_nofork_applet() call.
10321 * (2) Should this check also be done in forkshell()?
10322 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10323 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000010324 /* find_command() encodes applet_no as (-2 - applet_no) */
10325 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010326 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010327 char **sv_environ;
10328
10329 INT_OFF;
10330 sv_environ = environ;
10331 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
Denys Vlasenkod329e342017-08-04 14:50:03 +020010332 /*
10333 * Run <applet>_main().
10334 * Signals (^C) can't interrupt here.
10335 * Otherwise we can mangle stdio or malloc internal state.
10336 * This makes applets which can run for a long time
10337 * and/or wait for user input ineligible for NOFORK:
10338 * for example, "yes" or "rm" (rm -i waits for input).
10339 */
Ron Yorstond5bfe262020-02-20 08:23:03 +000010340 exitstatus = run_nofork_applet(applet_no, argv);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010341 environ = sv_environ;
Denys Vlasenkod329e342017-08-04 14:50:03 +020010342 /*
10343 * Try enabling NOFORK for "yes" applet.
10344 * ^C _will_ stop it (write returns EINTR),
10345 * but this causes stdout FILE to be stuck
10346 * and needing clearerr(). What if other applets
10347 * also can get EINTRs? Do we need to switch
10348 * our signals to SA_RESTART?
10349 */
10350 /*clearerr(stdout);*/
10351 INT_ON;
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010352 break;
10353 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010354#endif
Denys Vlasenkocfd392b2017-08-03 19:56:29 +020010355 /* Can we avoid forking? For example, very last command
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010356 * in a script or a subshell does not need forking,
10357 * we can just exec it.
10358 */
Denys Vlasenko238bf182010-05-18 15:49:07 +020010359 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010360 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010361 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +010010362 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +000010363 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010364 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +020010365 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +000010366 break;
10367 }
Denys Vlasenko238bf182010-05-18 15:49:07 +020010368 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010369 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +020010370 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +000010371 }
Denys Vlasenkoe139ae32017-04-12 21:02:33 +020010372 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +000010373 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010374 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +000010375 case CMDBUILTIN:
Denys Vlasenko97edfc42020-02-18 14:37:56 +010010376 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
10377 && !(exception_type == EXERROR && spclbltin <= 0)
10378 ) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010379 raise:
10380 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010381 }
Denys Vlasenkod81af722020-02-18 14:28:30 +010010382 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010383
10384 case CMDFUNCTION:
Eric Andersenc470f442003-07-28 09:56:35 +000010385 if (evalfun(cmdentry.u.func, argc, argv, flags))
10386 goto raise;
10387 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010388 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +000010389
Denys Vlasenkod81af722020-02-18 14:28:30 +010010390 status = waitforjob(jp);
Ron Yorston6cda0b02020-02-21 16:16:56 +000010391 if (jp)
10392 TRACE(("forked child exited with %d\n", status));
Denys Vlasenko97edfc42020-02-18 14:37:56 +010010393 FORCE_INT_ON;
Denys Vlasenkod81af722020-02-18 14:28:30 +010010394
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010395 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +020010396 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +020010397 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010398 unwindredir(redir_stop);
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010399 unwindfiles(file_stop);
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +010010400 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010401 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +000010402 /* dsl: I think this is intended to be used to support
10403 * '_' in 'vi' command mode during line editing...
10404 * However I implemented that within libedit itself.
10405 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020010406 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010407 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010408
10409 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000010410}
10411
10412static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010413evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010414{
Eric Andersenc470f442003-07-28 09:56:35 +000010415 char *volatile savecmdname;
10416 struct jmploc *volatile savehandler;
10417 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010418 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010419 int i;
10420
10421 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010422 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010423 i = setjmp(jmploc.loc);
10424 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010425 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010426 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010427 commandname = argv[0];
10428 argptr = argv + 1;
10429 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010430 if (cmd == EVALCMD)
10431 status = evalcmd(argc, argv, flags);
10432 else
10433 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010434 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010435 status |= ferror(stdout);
10436 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010437 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010438 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010439 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010440 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010441
10442 return i;
10443}
10444
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010445static int
10446goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010447{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010448 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010449}
10450
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010451
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010452/*
10453 * Search for a command. This is called before we fork so that the
10454 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010455 * the child. The check for "goodname" is an overly conservative
10456 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010457 */
Eric Andersenc470f442003-07-28 09:56:35 +000010458static void
10459prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010460{
10461 struct cmdentry entry;
10462
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010463 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10464 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010465}
10466
Eric Andersencb57d552001-06-28 07:25:16 +000010467
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010468/* ============ Builtin commands
10469 *
10470 * Builtin commands whose functions are closely tied to evaluation
10471 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010472 */
10473
10474/*
Eric Andersencb57d552001-06-28 07:25:16 +000010475 * Handle break and continue commands. Break, continue, and return are
10476 * all handled by setting the evalskip flag. The evaluation routines
10477 * above all check this flag, and if it is set they start skipping
10478 * commands rather than executing them. The variable skipcount is
10479 * the number of loops to break/continue, or the number of function
10480 * levels to return. (The latter is always 1.) It should probably
10481 * be an error to break out of more loops than exist, but it isn't
10482 * in the standard shell so we don't make it one here.
10483 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010484static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010485breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010486{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010487 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010488
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010489 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010490 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010491 if (n > loopnest)
10492 n = loopnest;
10493 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010494 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010495 skipcount = n;
10496 }
10497 return 0;
10498}
10499
Eric Andersenc470f442003-07-28 09:56:35 +000010500
Denys Vlasenko70392332016-10-27 02:31:55 +020010501/*
Eric Andersen90898442003-08-06 11:20:52 +000010502 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010503 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010504
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010505enum {
10506 INPUT_PUSH_FILE = 1,
10507 INPUT_NOFILE_OK = 2,
10508};
Eric Andersencb57d552001-06-28 07:25:16 +000010509
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010510static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010511/* values of checkkwd variable */
10512#define CHKALIAS 0x1
10513#define CHKKWD 0x2
10514#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010515#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010516
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010517/*
10518 * Push a string back onto the input at this current parsefile level.
10519 * We handle aliases this way.
10520 */
10521#if !ENABLE_ASH_ALIAS
10522#define pushstring(s, ap) pushstring(s)
10523#endif
10524static void
10525pushstring(char *s, struct alias *ap)
10526{
10527 struct strpush *sp;
10528 int len;
10529
10530 len = strlen(s);
10531 INT_OFF;
10532 if (g_parsefile->strpush) {
10533 sp = ckzalloc(sizeof(*sp));
10534 sp->prev = g_parsefile->strpush;
10535 } else {
10536 sp = &(g_parsefile->basestrpush);
10537 }
10538 g_parsefile->strpush = sp;
10539 sp->prev_string = g_parsefile->next_to_pgetc;
10540 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010541 sp->unget = g_parsefile->unget;
10542 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010543#if ENABLE_ASH_ALIAS
10544 sp->ap = ap;
10545 if (ap) {
10546 ap->flag |= ALIASINUSE;
10547 sp->string = s;
10548 }
10549#endif
10550 g_parsefile->next_to_pgetc = s;
10551 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010552 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010553 INT_ON;
10554}
10555
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010556static void
10557popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010558{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010559 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010560
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010561 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010562#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010563 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010564 if (g_parsefile->next_to_pgetc[-1] == ' '
10565 || g_parsefile->next_to_pgetc[-1] == '\t'
10566 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010567 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010568 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010569 if (sp->string != sp->ap->val) {
10570 free(sp->string);
10571 }
10572 sp->ap->flag &= ~ALIASINUSE;
10573 if (sp->ap->flag & ALIASDEAD) {
10574 unalias(sp->ap->name);
10575 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010576 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010577#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010578 g_parsefile->next_to_pgetc = sp->prev_string;
10579 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010580 g_parsefile->unget = sp->unget;
10581 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010582 g_parsefile->strpush = sp->prev;
10583 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010584 free(sp);
10585 INT_ON;
10586}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010587
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010588static int
10589preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010590{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010591 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010592 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010593
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010594 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010595#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010596 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010597 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010598 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010599 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010600# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010601 int timeout = -1;
Denys Vlasenko897475a2019-06-01 16:35:09 +020010602 const char *tmout_var = lookupvar("TMOUT");
10603 if (tmout_var) {
10604 timeout = atoi(tmout_var) * 1000;
10605 if (timeout <= 0)
10606 timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010607 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010608 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010609# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010610# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010611 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010612# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010613 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010614 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010615 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010616 /* ^C pressed, "convert" to SIGINT */
10617 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010618 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010619 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010620 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010621 raise(SIGINT);
10622 return 1;
10623 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010624 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010625 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010626 goto retry;
10627 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010628 if (nr < 0) {
10629 if (errno == 0) {
10630 /* Ctrl+D pressed */
10631 nr = 0;
10632 }
10633# if ENABLE_ASH_IDLE_TIMEOUT
10634 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010635 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010636 exitshell();
10637 }
10638# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010639 }
Eric Andersencb57d552001-06-28 07:25:16 +000010640 }
10641#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010642 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010643#endif
10644
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010645#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010646 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010647 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010648 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010649 if (flags >= 0 && (flags & O_NONBLOCK)) {
10650 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010651 if (fcntl(0, F_SETFL, flags) >= 0) {
10652 out2str("sh: turning off NDELAY mode\n");
10653 goto retry;
10654 }
10655 }
10656 }
10657 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010658#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010659 return nr;
10660}
10661
10662/*
10663 * Refill the input buffer and return the next input character:
10664 *
10665 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010666 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10667 * or we are reading from a string so we can't refill the buffer,
10668 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010669 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010670 * 4) Process input up to the next newline, deleting nul characters.
10671 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010672//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10673#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010674static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010675static int
Eric Andersenc470f442003-07-28 09:56:35 +000010676preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010677{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010678 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010679 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010680
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010681 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010682#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010683 if (g_parsefile->left_in_line == -1
10684 && g_parsefile->strpush->ap
10685 && g_parsefile->next_to_pgetc[-1] != ' '
10686 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010687 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010688 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010689 return PEOA;
10690 }
Eric Andersen2870d962001-07-02 17:27:21 +000010691#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010692 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010693 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010694 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010695 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010696 * "pgetc" needs refilling.
10697 */
10698
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010699 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010700 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010701 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010702 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010703 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010704 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010705 /* even in failure keep left_in_line and next_to_pgetc
10706 * in lock step, for correct multi-layer pungetc.
10707 * left_in_line was decremented before preadbuffer(),
10708 * must inc next_to_pgetc: */
10709 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010710 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010711 }
Eric Andersencb57d552001-06-28 07:25:16 +000010712
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010713 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010714 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010715 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010716 again:
10717 more = preadfd();
10718 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010719 /* don't try reading again */
10720 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010721 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010722 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010723 return PEOF;
10724 }
10725 }
10726
Denis Vlasenko727752d2008-11-28 03:41:47 +000010727 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010728 * Set g_parsefile->left_in_line
10729 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010730 * NUL chars are deleted.
10731 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010732 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010733 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010734 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010735
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010736 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010737
Denis Vlasenko727752d2008-11-28 03:41:47 +000010738 c = *q;
10739 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010740 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010741 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010742 q++;
10743 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010744 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010745 break;
10746 }
Eric Andersencb57d552001-06-28 07:25:16 +000010747 }
10748
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010749 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010750 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10751 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010752 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010753 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010754 }
10755 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010756 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010757
Eric Andersencb57d552001-06-28 07:25:16 +000010758 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010759 char save = *q;
10760 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010761 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010762 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010763 }
10764
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010765 pgetc_debug("preadbuffer at %d:%p'%s'",
10766 g_parsefile->left_in_line,
10767 g_parsefile->next_to_pgetc,
10768 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010769 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010770}
10771
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010772static void
10773nlprompt(void)
10774{
10775 g_parsefile->linno++;
10776 setprompt_if(doprompt, 2);
10777}
10778static void
10779nlnoprompt(void)
10780{
10781 g_parsefile->linno++;
10782 needprompt = doprompt;
10783}
10784
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010785static int
10786pgetc(void)
10787{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010788 int c;
10789
10790 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010791 g_parsefile->left_in_line,
10792 g_parsefile->next_to_pgetc,
10793 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010794 if (g_parsefile->unget)
10795 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010796
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010797 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010798 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010799 else
10800 c = preadbuffer();
10801
10802 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10803 g_parsefile->lastc[0] = c;
10804
10805 return c;
10806}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010807
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010808#if ENABLE_ASH_ALIAS
10809static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010810pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010811{
10812 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010813 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010814 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010815 g_parsefile->left_in_line,
10816 g_parsefile->next_to_pgetc,
10817 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010818 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010819 } while (c == PEOA);
10820 return c;
10821}
10822#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010823# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010824#endif
10825
10826/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010827 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010828 * PEOF may be pushed back.
10829 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010830static void
Eric Andersenc470f442003-07-28 09:56:35 +000010831pungetc(void)
10832{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010833 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010834}
10835
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010836/* This one eats backslash+newline */
10837static int
10838pgetc_eatbnl(void)
10839{
10840 int c;
10841
10842 while ((c = pgetc()) == '\\') {
10843 if (pgetc() != '\n') {
10844 pungetc();
10845 break;
10846 }
10847
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010848 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010849 }
10850
10851 return c;
10852}
10853
Denys Vlasenko216913c2018-04-02 12:35:04 +020010854struct synstack {
10855 smalluint syntax;
10856 uint8_t innerdq :1;
10857 uint8_t varpushed :1;
10858 uint8_t dblquote :1;
10859 int varnest; /* levels of variables expansion */
10860 int dqvarnest; /* levels of variables expansion within double quotes */
10861 int parenlevel; /* levels of parens in arithmetic */
10862 struct synstack *prev;
10863 struct synstack *next;
10864};
10865
Denys Vlasenkof7eea8c2020-02-14 16:16:34 +010010866static int
10867pgetc_top(struct synstack *stack)
10868{
10869 return stack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl();
10870}
10871
Denys Vlasenko216913c2018-04-02 12:35:04 +020010872static void
10873synstack_push(struct synstack **stack, struct synstack *next, int syntax)
10874{
10875 memset(next, 0, sizeof(*next));
10876 next->syntax = syntax;
10877 next->next = *stack;
10878 (*stack)->prev = next;
10879 *stack = next;
10880}
10881
10882static ALWAYS_INLINE void
10883synstack_pop(struct synstack **stack)
10884{
10885 *stack = (*stack)->next;
10886}
10887
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010888/*
10889 * To handle the "." command, a stack of input files is used. Pushfile
10890 * adds a new entry to the stack and popfile restores the previous level.
10891 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010892static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010893pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010894{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010895 struct parsefile *pf;
10896
Denis Vlasenko597906c2008-02-20 16:38:54 +000010897 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010898 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010899 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010900 /*pf->strpush = NULL; - ckzalloc did it */
10901 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010902 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010903 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010904}
10905
10906static void
10907popfile(void)
10908{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010909 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010910
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010911 if (pf == &basepf)
10912 return;
10913
Denis Vlasenkob012b102007-02-19 22:43:01 +000010914 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010915 if (pf->pf_fd >= 0)
10916 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010917 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010918 while (pf->strpush)
10919 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010920 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010921 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010922 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010923}
10924
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010925static void
10926unwindfiles(struct parsefile *stop)
10927{
10928 while (g_parsefile != stop)
10929 popfile();
10930}
10931
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010932/*
10933 * Return to top level.
10934 */
10935static void
10936popallfiles(void)
10937{
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010938 unwindfiles(&basepf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010939}
10940
10941/*
10942 * Close the file(s) that the shell is reading commands from. Called
10943 * after a fork is done.
10944 */
10945static void
10946closescript(void)
10947{
10948 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010949 if (g_parsefile->pf_fd > 0) {
10950 close(g_parsefile->pf_fd);
10951 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010952 }
10953}
10954
10955/*
10956 * Like setinputfile, but takes an open file descriptor. Call this with
10957 * interrupts off.
10958 */
10959static void
10960setinputfd(int fd, int push)
10961{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010962 if (push) {
10963 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010964 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010965 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010966 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010967 if (g_parsefile->buf == NULL)
10968 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010969 g_parsefile->left_in_buffer = 0;
10970 g_parsefile->left_in_line = 0;
10971 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010972}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010973
Eric Andersenc470f442003-07-28 09:56:35 +000010974/*
10975 * Set the input to take input from a file. If push is set, push the
10976 * old input onto the stack first.
10977 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010978static int
10979setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010980{
10981 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010982
Denis Vlasenkob012b102007-02-19 22:43:01 +000010983 INT_OFF;
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010984 fd = open(fname, O_RDONLY | O_CLOEXEC);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010985 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010986 if (flags & INPUT_NOFILE_OK)
10987 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010988 exitstatus = 127;
Johannes Schindelin20a63b22017-08-22 22:03:17 +020010989 ash_msg_and_raise_perror("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010990 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010991 if (fd < 10)
10992 fd = savefd(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010993 else if (O_CLOEXEC == 0) /* old libc */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010994 close_on_exec_on(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010995
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010996 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010997 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010998 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010999 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011000}
11001
Eric Andersencb57d552001-06-28 07:25:16 +000011002/*
11003 * Like setinputfile, but takes input from a string.
11004 */
Eric Andersenc470f442003-07-28 09:56:35 +000011005static void
11006setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000011007{
Denis Vlasenkob012b102007-02-19 22:43:01 +000011008 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000011009 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011010 g_parsefile->next_to_pgetc = string;
11011 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011012 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011013 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011014 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000011015}
11016
11017
Denys Vlasenko70392332016-10-27 02:31:55 +020011018/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011019 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000011020 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011021
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011022#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000011023
Denys Vlasenko23841622015-10-09 15:52:03 +020011024/* Hash of mtimes of mailboxes */
11025static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000011026/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011027static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000011028
Eric Andersencb57d552001-06-28 07:25:16 +000011029/*
Eric Andersenc470f442003-07-28 09:56:35 +000011030 * Print appropriate message(s) if mail has arrived.
11031 * If mail_var_path_changed is set,
11032 * then the value of MAIL has mail_var_path_changed,
11033 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000011034 */
Eric Andersenc470f442003-07-28 09:56:35 +000011035static void
11036chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011037{
Eric Andersencb57d552001-06-28 07:25:16 +000011038 const char *mpath;
11039 char *p;
11040 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020011041 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000011042 struct stackmark smark;
11043 struct stat statb;
11044
Eric Andersencb57d552001-06-28 07:25:16 +000011045 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000011046 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020011047 new_hash = 0;
11048 for (;;) {
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010011049 int len;
11050
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010011051 len = padvance_magic(&mpath, nullstr, 2);
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010011052 if (!len)
11053 break;
11054 p = stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011055 break;
11056 if (*p == '\0')
11057 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011058 for (q = p; *q; q++)
11059 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011060#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011061 if (q[-1] != '/')
11062 abort();
11063#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011064 q[-1] = '\0'; /* delete trailing '/' */
11065 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000011066 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000011067 }
Denys Vlasenko23841622015-10-09 15:52:03 +020011068 /* Very simplistic "hash": just a sum of all mtimes */
11069 new_hash += (unsigned)statb.st_mtime;
11070 }
11071 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020011072 if (mailtime_hash != 0)
11073 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020011074 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000011075 }
Eric Andersenc470f442003-07-28 09:56:35 +000011076 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011077 popstackmark(&smark);
11078}
Eric Andersencb57d552001-06-28 07:25:16 +000011079
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011080static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011081changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000011082{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011083 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011084}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011085
Denis Vlasenko131ae172007-02-18 13:00:19 +000011086#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000011087
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011088
11089/* ============ ??? */
11090
Eric Andersencb57d552001-06-28 07:25:16 +000011091/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011092 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000011093 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011094static void
11095setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011096{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011097 char **newparam;
11098 char **ap;
11099 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000011100
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011101 for (nparam = 0; argv[nparam]; nparam++)
11102 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011103 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
11104 while (*argv) {
11105 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000011106 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011107 *ap = NULL;
11108 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000011109 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011110 shellparam.nparam = nparam;
11111 shellparam.p = newparam;
11112#if ENABLE_ASH_GETOPTS
11113 shellparam.optind = 1;
11114 shellparam.optoff = -1;
11115#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011116}
11117
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011118/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011119 * Process shell options. The global variable argptr contains a pointer
11120 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000011121 *
11122 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
11123 * For a non-interactive shell, an error condition encountered
11124 * by a special built-in ... shall cause the shell to write a diagnostic message
11125 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000011126 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000011127 * ...
11128 * Utility syntax error (option or operand error) Shall exit
11129 * ...
11130 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
11131 * we see that bash does not do that (set "finishes" with error code 1 instead,
11132 * and shell continues), and people rely on this behavior!
11133 * Testcase:
11134 * set -o barfoo 2>/dev/null
11135 * echo $?
11136 *
11137 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011138 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011139static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011140plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000011141{
11142 int i;
11143
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011144 if (name) {
11145 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011146 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000011147 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011148 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000011149 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011150 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011151 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011152 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000011153 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000011154 for (i = 0; i < NOPTS; i++) {
Denys Vlasenko2f9c1242019-08-02 16:43:36 +020011155 if (optnames(i)[0] == '\0')
11156 continue;
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011157 if (val) {
11158 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11159 } else {
11160 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11161 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000011162 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011163 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000011164}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011165static void
11166setoption(int flag, int val)
11167{
11168 int i;
11169
11170 for (i = 0; i < NOPTS; i++) {
Denys Vlasenkof3634582019-06-03 12:21:04 +020011171 if (optletters(i) == flag && optnames(i)[0] != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011172 optlist[i] = val;
11173 return;
11174 }
11175 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011176 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011177 /* NOTREACHED */
11178}
Denys Vlasenko897475a2019-06-01 16:35:09 +020011179/* If login_sh is not NULL, we are called to parse command line opts,
11180 * not "set -opts"
11181 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011182static int
Denys Vlasenko897475a2019-06-01 16:35:09 +020011183options(int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000011184{
11185 char *p;
11186 int val;
11187 int c;
11188
Denys Vlasenko897475a2019-06-01 16:35:09 +020011189 if (login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000011190 minusc = NULL;
11191 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011192 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011193 if (c != '-' && c != '+')
11194 break;
11195 argptr++;
11196 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011197 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000011198 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011199 if (p[0] == '\0' || LONE_DASH(p)) {
Denys Vlasenko897475a2019-06-01 16:35:09 +020011200 if (!login_sh) {
Eric Andersen2870d962001-07-02 17:27:21 +000011201 /* "-" means turn off -x and -v */
11202 if (p[0] == '\0')
11203 xflag = vflag = 0;
11204 /* "--" means reset params */
11205 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011206 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000011207 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011208 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000011209 }
Eric Andersencb57d552001-06-28 07:25:16 +000011210 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011211 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000011212 while ((c = *p++) != '\0') {
Denys Vlasenko897475a2019-06-01 16:35:09 +020011213 if (login_sh) {
11214 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
11215 if (c == 'c') {
11216 minusc = p; /* command is after shell args */
Denys Vlasenkof3634582019-06-03 12:21:04 +020011217 cflag = 1;
11218 continue;
11219 }
11220 if (c == 's') { /* -s, +s */
11221 sflag = 1;
11222 continue;
11223 }
11224 if (c == 'i') { /* -i, +i */
11225 iflag = 1;
Denys Vlasenko897475a2019-06-01 16:35:09 +020011226 continue;
11227 }
11228 if (c == 'l') {
11229 *login_sh = 1; /* -l or +l == --login */
11230 continue;
11231 }
11232 /* bash does not accept +-login, we also won't */
11233 if (val && (c == '-')) { /* long options */
11234 if (strcmp(p, "login") == 0) {
11235 *login_sh = 1;
11236 }
11237 break;
11238 }
11239 }
11240 if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011241 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011242 /* it already printed err message */
11243 return 1; /* error */
11244 }
Eric Andersencb57d552001-06-28 07:25:16 +000011245 if (*argptr)
11246 argptr++;
11247 } else {
11248 setoption(c, val);
11249 }
11250 }
11251 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011252 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011253}
11254
Eric Andersencb57d552001-06-28 07:25:16 +000011255/*
Eric Andersencb57d552001-06-28 07:25:16 +000011256 * The shift builtin command.
11257 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011258static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011259shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011260{
11261 int n;
11262 char **ap1, **ap2;
11263
11264 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000011265 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011266 n = number(argv[1]);
11267 if (n > shellparam.nparam)
Ingo van Lil9c8e94b2018-01-05 15:04:23 +010011268 return 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011269 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000011270 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011271 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000011272 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000011273 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000011274 }
11275 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011276 while ((*ap2++ = *ap1++) != NULL)
11277 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000011278#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011279 shellparam.optind = 1;
11280 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000011281#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000011282 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000011283 return 0;
11284}
11285
Eric Andersencb57d552001-06-28 07:25:16 +000011286/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011287 * POSIX requires that 'set' (but not export or readonly) output the
11288 * variables in lexicographic order - by the locale's collating order (sigh).
11289 * Maybe we could keep them in an ordered balanced binary tree
11290 * instead of hashed lists.
11291 * For now just roll 'em through qsort for printing...
11292 */
11293static int
11294showvars(const char *sep_prefix, int on, int off)
11295{
11296 const char *sep;
11297 char **ep, **epend;
11298
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010011299 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011300 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11301
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011302 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011303
11304 for (; ep < epend; ep++) {
11305 const char *p;
11306 const char *q;
11307
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011308 p = endofname(*ep);
11309/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11310 * makes "export -p" to have output not suitable for "eval":
11311 * import os
11312 * os.environ["test-test"]="test"
11313 * if os.fork() == 0:
11314 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11315 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11316 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011317 q = nullstr;
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011318 if (*p == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011319 q = single_quote(++p);
11320 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11321 }
11322 return 0;
11323}
11324
11325/*
Eric Andersencb57d552001-06-28 07:25:16 +000011326 * The set command builtin.
11327 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011328static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011329setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000011330{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011331 int retval;
11332
Denis Vlasenko68404f12008-03-17 09:00:54 +000011333 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000011334 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011335
Denis Vlasenkob012b102007-02-19 22:43:01 +000011336 INT_OFF;
Denys Vlasenko897475a2019-06-01 16:35:09 +020011337 retval = options(/*login_sh:*/ NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011338 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011339 optschanged();
11340 if (*argptr != NULL) {
11341 setparam(argptr);
11342 }
Eric Andersencb57d552001-06-28 07:25:16 +000011343 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011344 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011345 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000011346}
11347
Denis Vlasenko131ae172007-02-18 13:00:19 +000011348#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011349static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011350change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000011351{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011352 uint32_t t;
11353
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011354 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000011355 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011356 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000011357 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020011358 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000011359 vrandom.flags &= ~VNOFUNC;
11360 } else {
11361 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011362 t = strtoul(value, NULL, 10);
11363 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000011364 }
Eric Andersenef02f822004-03-11 13:34:24 +000011365}
Eric Andersen16767e22004-03-16 05:14:10 +000011366#endif
11367
Ron Yorston1d371862019-04-15 10:52:05 +010011368#if BASH_EPOCH_VARS
11369static void FAST_FUNC
11370change_epoch(struct var *vepoch, const char *fmt)
11371{
11372 struct timeval tv;
11373 char buffer[sizeof("%lu.nnnnnn") + sizeof(long)*3];
11374
11375 gettimeofday(&tv, NULL);
11376 sprintf(buffer, fmt, (unsigned long)tv.tv_sec, (unsigned)tv.tv_usec);
11377 setvar(vepoch->var_text, buffer, VNOFUNC);
11378 vepoch->flags &= ~VNOFUNC;
11379}
11380
11381static void FAST_FUNC
11382change_seconds(const char *value UNUSED_PARAM)
11383{
11384 change_epoch(&vepochs, "%lu");
11385}
11386
11387static void FAST_FUNC
11388change_realtime(const char *value UNUSED_PARAM)
11389{
11390 change_epoch(&vepochr, "%lu.%06u");
11391}
11392#endif
11393
Denis Vlasenko131ae172007-02-18 13:00:19 +000011394#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011395static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011396getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000011397{
11398 char *p, *q;
11399 char c = '?';
11400 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020011401 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000011402 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011403 int ind = shellparam.optind;
11404 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000011405
Denys Vlasenko9c541002015-10-07 15:44:36 +020011406 sbuf[1] = '\0';
11407
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011408 shellparam.optind = -1;
11409 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000011410
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011411 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000011412 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011413 else
11414 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000011415 if (p == NULL || *p == '\0') {
11416 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000011417 p = *optnext;
11418 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011419 atend:
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011420 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011421 p = NULL;
11422 done = 1;
11423 goto out;
11424 }
11425 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011426 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000011427 goto atend;
11428 }
11429
11430 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000011431 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000011432 if (*q == '\0') {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011433 /* OPTERR is a bashism */
11434 const char *cp = lookupvar("OPTERR");
11435 if ((cp && LONE_CHAR(cp, '0'))
11436 || (optstr[0] == ':')
11437 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011438 sbuf[0] = c;
11439 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011440 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011441 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011442 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011443 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011444 }
11445 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000011446 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011447 }
11448 if (*++q == ':')
11449 q++;
11450 }
11451
11452 if (*++q == ':') {
11453 if (*p == '\0' && (p = *optnext) == NULL) {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011454 /* OPTERR is a bashism */
11455 const char *cp = lookupvar("OPTERR");
11456 if ((cp && LONE_CHAR(cp, '0'))
11457 || (optstr[0] == ':')
11458 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011459 sbuf[0] = c;
11460 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011461 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000011462 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011463 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011464 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011465 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011466 c = '?';
11467 }
Eric Andersenc470f442003-07-28 09:56:35 +000011468 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011469 }
11470
11471 if (p == *optnext)
11472 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011473 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000011474 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011475 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011476 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011477 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011478 ind = optnext - optfirst + 1;
11479 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020011480 sbuf[0] = c;
11481 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011482 setvar0(optvar, sbuf);
11483
11484 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11485 shellparam.optind = ind;
11486
Eric Andersencb57d552001-06-28 07:25:16 +000011487 return done;
11488}
Eric Andersenc470f442003-07-28 09:56:35 +000011489
11490/*
11491 * The getopts builtin. Shellparam.optnext points to the next argument
11492 * to be processed. Shellparam.optptr points to the next character to
11493 * be processed in the current argument. If shellparam.optnext is NULL,
11494 * then it's the first time getopts has been called.
11495 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011496static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000011497getoptscmd(int argc, char **argv)
11498{
11499 char **optbase;
11500
11501 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000011502 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011503 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000011504 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011505 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000011506 shellparam.optind = 1;
11507 shellparam.optoff = -1;
11508 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011509 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011510 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011511 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000011512 shellparam.optind = 1;
11513 shellparam.optoff = -1;
11514 }
11515 }
11516
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011517 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011518}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011519#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011520
Eric Andersencb57d552001-06-28 07:25:16 +000011521
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011522/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011523
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011524struct heredoc {
11525 struct heredoc *next; /* next here document in list */
11526 union node *here; /* redirection node */
11527 char *eofmark; /* string indicating end of input */
11528 smallint striptabs; /* if set, strip leading tabs */
11529};
11530
11531static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011532static smallint quoteflag; /* set if (part of) last token was quoted */
11533static token_id_t lasttoken; /* last token read (integer id Txxx) */
11534static struct heredoc *heredoclist; /* list of here documents to read */
11535static char *wordtext; /* text of last word returned by readtoken */
11536static struct nodelist *backquotelist;
11537static union node *redirnode;
11538static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011539
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011540static const char *
11541tokname(char *buf, int tok)
11542{
11543 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011544 return tokname_array[tok];
11545 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011546 return buf;
11547}
11548
11549/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011550 * Called when an unexpected token is read during the parse. The argument
11551 * is the token that is expected, or -1 if more than one type of token can
11552 * occur at this point.
11553 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011554static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011555static void
11556raise_error_unexpected_syntax(int token)
11557{
11558 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011559 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011560 int l;
11561
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011562 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011563 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011564 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011565 raise_error_syntax(msg);
11566 /* NOTREACHED */
11567}
Eric Andersencb57d552001-06-28 07:25:16 +000011568
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011569/* parsing is heavily cross-recursive, need these forward decls */
11570static union node *andor(void);
11571static union node *pipeline(void);
11572static union node *parse_command(void);
11573static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011574static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011575static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011576
Eric Andersenc470f442003-07-28 09:56:35 +000011577static union node *
11578list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011579{
11580 union node *n1, *n2, *n3;
11581 int tok;
11582
Eric Andersencb57d552001-06-28 07:25:16 +000011583 n1 = NULL;
11584 for (;;) {
Denys Vlasenkoc08993f2020-02-22 17:26:23 +010011585 switch (readtoken()) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011586 case TNL:
11587 if (!(nlflag & 1))
11588 break;
11589 parseheredoc();
11590 return n1;
11591
11592 case TEOF:
11593 if (!n1 && (nlflag & 1))
11594 n1 = NODE_EOF;
11595 parseheredoc();
Denys Vlasenkoc08993f2020-02-22 17:26:23 +010011596 tokpushback++;
11597 lasttoken = TEOF;
Ron Yorstonc0e00762015-10-29 11:30:55 +000011598 return n1;
11599 }
11600
Denys Vlasenkoc08993f2020-02-22 17:26:23 +010011601 tokpushback++;
Ron Yorstonc0e00762015-10-29 11:30:55 +000011602 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011603 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011604 return n1;
11605 nlflag |= 2;
11606
Eric Andersencb57d552001-06-28 07:25:16 +000011607 n2 = andor();
11608 tok = readtoken();
11609 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011610 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011611 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011612 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011613 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011614 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011615 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011616 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011617 n2 = n3;
11618 }
11619 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011620 }
11621 }
11622 if (n1 == NULL) {
11623 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011624 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011625 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011626 n3->type = NSEMI;
11627 n3->nbinary.ch1 = n1;
11628 n3->nbinary.ch2 = n2;
11629 n1 = n3;
11630 }
11631 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011632 case TNL:
11633 case TEOF:
11634 tokpushback = 1;
11635 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011636 case TBACKGND:
11637 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011638 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011639 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011640 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011641 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011642 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011643 return n1;
11644 }
11645 }
11646}
11647
Eric Andersenc470f442003-07-28 09:56:35 +000011648static union node *
11649andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011650{
Eric Andersencb57d552001-06-28 07:25:16 +000011651 union node *n1, *n2, *n3;
11652 int t;
11653
Eric Andersencb57d552001-06-28 07:25:16 +000011654 n1 = pipeline();
11655 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011656 t = readtoken();
11657 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011658 t = NAND;
11659 } else if (t == TOR) {
11660 t = NOR;
11661 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011662 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011663 return n1;
11664 }
Eric Andersenc470f442003-07-28 09:56:35 +000011665 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011666 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011667 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011668 n3->type = t;
11669 n3->nbinary.ch1 = n1;
11670 n3->nbinary.ch2 = n2;
11671 n1 = n3;
11672 }
11673}
11674
Eric Andersenc470f442003-07-28 09:56:35 +000011675static union node *
11676pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011677{
Eric Andersencb57d552001-06-28 07:25:16 +000011678 union node *n1, *n2, *pipenode;
11679 struct nodelist *lp, *prev;
11680 int negate;
11681
11682 negate = 0;
11683 TRACE(("pipeline: entered\n"));
11684 if (readtoken() == TNOT) {
11685 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011686 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011687 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011688 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011689 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011690 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011691 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011692 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011693 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011694 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011695 pipenode->npipe.cmdlist = lp;
11696 lp->n = n1;
11697 do {
11698 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011699 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011700 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011701 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011702 prev->next = lp;
11703 } while (readtoken() == TPIPE);
11704 lp->next = NULL;
11705 n1 = pipenode;
11706 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011707 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011708 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011709 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011710 n2->type = NNOT;
11711 n2->nnot.com = n1;
11712 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011713 }
11714 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011715}
11716
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011717static union node *
11718makename(void)
11719{
11720 union node *n;
11721
Denis Vlasenko597906c2008-02-20 16:38:54 +000011722 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011723 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011724 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011725 n->narg.text = wordtext;
11726 n->narg.backquote = backquotelist;
11727 return n;
11728}
11729
11730static void
11731fixredir(union node *n, const char *text, int err)
11732{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011733 int fd;
11734
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011735 TRACE(("Fix redir %s %d\n", text, err));
11736 if (!err)
11737 n->ndup.vname = NULL;
11738
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011739 fd = bb_strtou(text, NULL, 10);
11740 if (!errno && fd >= 0)
11741 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011742 else if (LONE_DASH(text))
11743 n->ndup.dupfd = -1;
11744 else {
11745 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011746 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011747 n->ndup.vname = makename();
11748 }
11749}
11750
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011751static void
11752parsefname(void)
11753{
11754 union node *n = redirnode;
11755
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011756 if (n->type == NHERE)
11757 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011758 if (readtoken() != TWORD)
11759 raise_error_unexpected_syntax(-1);
11760 if (n->type == NHERE) {
11761 struct heredoc *here = heredoc;
11762 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011763
11764 if (quoteflag == 0)
11765 n->type = NXHERE;
11766 TRACE(("Here document %d\n", n->type));
Denys Vlasenko740058b2018-01-09 17:01:00 +010011767 rmescapes(wordtext, 0, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011768 here->eofmark = wordtext;
11769 here->next = NULL;
11770 if (heredoclist == NULL)
11771 heredoclist = here;
11772 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011773 for (p = heredoclist; p->next; p = p->next)
11774 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011775 p->next = here;
11776 }
11777 } else if (n->type == NTOFD || n->type == NFROMFD) {
11778 fixredir(n, wordtext, 0);
11779 } else {
11780 n->nfile.fname = makename();
11781 }
11782}
Eric Andersencb57d552001-06-28 07:25:16 +000011783
Eric Andersenc470f442003-07-28 09:56:35 +000011784static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011785simplecmd(void)
11786{
11787 union node *args, **app;
11788 union node *n = NULL;
11789 union node *vars, **vpp;
11790 union node **rpp, *redir;
11791 int savecheckkwd;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011792 int savelinno;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011793#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011794 smallint double_brackets_flag = 0;
11795#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011796 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011797
11798 args = NULL;
11799 app = &args;
11800 vars = NULL;
11801 vpp = &vars;
11802 redir = NULL;
11803 rpp = &redir;
11804
11805 savecheckkwd = CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011806 savelinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011807 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011808 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011809 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011810 t = readtoken();
11811 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011812#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011813 case TFUNCTION:
11814 if (peektoken() != TWORD)
11815 raise_error_unexpected_syntax(TWORD);
11816 function_flag = 1;
11817 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011818#endif
11819#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011820 case TAND: /* "&&" */
11821 case TOR: /* "||" */
11822 if (!double_brackets_flag) {
11823 tokpushback = 1;
11824 goto out;
11825 }
11826 wordtext = (char *) (t == TAND ? "-a" : "-o");
11827#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011828 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011829 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011830 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011831 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011832 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011833#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011834 if (strcmp("[[", wordtext) == 0)
11835 double_brackets_flag = 1;
11836 else if (strcmp("]]", wordtext) == 0)
11837 double_brackets_flag = 0;
11838#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011839 n->narg.backquote = backquotelist;
11840 if (savecheckkwd && isassignment(wordtext)) {
11841 *vpp = n;
11842 vpp = &n->narg.next;
11843 } else {
11844 *app = n;
11845 app = &n->narg.next;
11846 savecheckkwd = 0;
11847 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011848#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011849 if (function_flag) {
11850 checkkwd = CHKNL | CHKKWD;
11851 switch (peektoken()) {
11852 case TBEGIN:
11853 case TIF:
11854 case TCASE:
11855 case TUNTIL:
11856 case TWHILE:
11857 case TFOR:
11858 goto do_func;
11859 case TLP:
11860 function_flag = 0;
11861 break;
Denys Vlasenkoe93031e2018-04-10 01:23:19 +020011862# if BASH_TEST2
Ron Yorston95ebcf72015-11-03 09:42:23 +000011863 case TWORD:
11864 if (strcmp("[[", wordtext) == 0)
11865 goto do_func;
11866 /* fall through */
Denys Vlasenkoe93031e2018-04-10 01:23:19 +020011867# endif
Ron Yorston95ebcf72015-11-03 09:42:23 +000011868 default:
11869 raise_error_unexpected_syntax(-1);
11870 }
11871 }
11872#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011873 break;
11874 case TREDIR:
11875 *rpp = n = redirnode;
11876 rpp = &n->nfile.next;
11877 parsefname(); /* read name of redirection file */
11878 break;
11879 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011880 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011881 if (args && app == &args->narg.next
11882 && !vars && !redir
11883 ) {
11884 struct builtincmd *bcmd;
11885 const char *name;
11886
11887 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011888 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011889 raise_error_unexpected_syntax(TRP);
11890 name = n->narg.text;
11891 if (!goodname(name)
11892 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11893 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011894 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011895 }
11896 n->type = NDEFUN;
11897 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011898 n->ndefun.text = n->narg.text;
11899 n->ndefun.linno = g_parsefile->linno;
11900 n->ndefun.body = parse_command();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011901 return n;
11902 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011903 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011904 /* fall through */
11905 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011906 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011907 goto out;
11908 }
11909 }
11910 out:
11911 *app = NULL;
11912 *vpp = NULL;
11913 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011914 n = stzalloc(sizeof(struct ncmd));
Denys Vlasenko57b7efb2018-04-10 01:20:26 +020011915 if (NCMD != 0)
11916 n->type = NCMD;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011917 n->ncmd.linno = savelinno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011918 n->ncmd.args = args;
11919 n->ncmd.assign = vars;
11920 n->ncmd.redirect = redir;
11921 return n;
11922}
11923
11924static union node *
11925parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011926{
Eric Andersencb57d552001-06-28 07:25:16 +000011927 union node *n1, *n2;
11928 union node *ap, **app;
11929 union node *cp, **cpp;
11930 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011931 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011932 int t;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011933 int savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011934
11935 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011936 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011937
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011938 savelinno = g_parsefile->linno;
11939
Eric Andersencb57d552001-06-28 07:25:16 +000011940 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011941 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011942 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011943 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011944 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011945 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011946 n1->type = NIF;
11947 n1->nif.test = list(0);
11948 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011949 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011950 n1->nif.ifpart = list(0);
11951 n2 = n1;
11952 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011953 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011954 n2 = n2->nif.elsepart;
11955 n2->type = NIF;
11956 n2->nif.test = list(0);
11957 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011958 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011959 n2->nif.ifpart = list(0);
11960 }
11961 if (lasttoken == TELSE)
11962 n2->nif.elsepart = list(0);
11963 else {
11964 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011965 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011966 }
Eric Andersenc470f442003-07-28 09:56:35 +000011967 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011968 break;
11969 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011970 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011971 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011972 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011973 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011974 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011975 got = readtoken();
11976 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011977 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011978 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011979 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011980 }
11981 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011982 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011983 break;
11984 }
11985 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011986 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011987 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011988 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011989 n1->type = NFOR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011990 n1->nfor.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011991 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011992 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011993 if (readtoken() == TIN) {
11994 app = &ap;
11995 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011996 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011997 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011998 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011999 n2->narg.text = wordtext;
12000 n2->narg.backquote = backquotelist;
12001 *app = n2;
12002 app = &n2->narg.next;
12003 }
12004 *app = NULL;
12005 n1->nfor.args = ap;
12006 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012007 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000012008 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012009 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000012010 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012011 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012012 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012013 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000012014 n1->nfor.args = n2;
12015 /*
12016 * Newline or semicolon here is optional (but note
12017 * that the original Bourne shell only allowed NL).
12018 */
Ron Yorstonab80e012015-08-03 13:46:00 +010012019 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012020 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012021 }
Eric Andersenc470f442003-07-28 09:56:35 +000012022 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000012023 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012024 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000012025 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000012026 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000012027 break;
12028 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012029 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000012030 n1->type = NCASE;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010012031 n1->ncase.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000012032 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012033 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012034 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000012035 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012036 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000012037 n2->narg.text = wordtext;
12038 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010012039 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12040 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012041 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000012042 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012043 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000012044 checkkwd = CHKNL | CHKKWD;
12045 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012046 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000012047 if (lasttoken == TLP)
12048 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012049 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000012050 cp->type = NCLIST;
12051 app = &cp->nclist.pattern;
12052 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012053 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000012054 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012055 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000012056 ap->narg.text = wordtext;
12057 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000012058 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000012059 break;
12060 app = &ap->narg.next;
12061 readtoken();
12062 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000012063 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000012064 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012065 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012066 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000012067
Eric Andersenc470f442003-07-28 09:56:35 +000012068 cpp = &cp->nclist.next;
12069
12070 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012071 t = readtoken();
12072 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000012073 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012074 raise_error_unexpected_syntax(TENDCASE);
12075 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000012076 }
Eric Andersenc470f442003-07-28 09:56:35 +000012077 }
Eric Andersencb57d552001-06-28 07:25:16 +000012078 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000012079 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000012080 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000012081 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000012082 n1->type = NSUBSHELL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010012083 n1->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000012084 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012085 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012086 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000012087 break;
12088 case TBEGIN:
12089 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000012090 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000012091 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012092 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000012093 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000012094 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012095 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000012096 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000012097 }
12098
Eric Andersenc470f442003-07-28 09:56:35 +000012099 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012100 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000012101
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012102 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000012103 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000012104 checkkwd = CHKKWD | CHKALIAS;
12105 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000012106 while (readtoken() == TREDIR) {
12107 *rpp = n2 = redirnode;
12108 rpp = &n2->nfile.next;
12109 parsefname();
12110 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012111 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012112 *rpp = NULL;
12113 if (redir) {
12114 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012115 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000012116 n2->type = NREDIR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010012117 n2->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000012118 n2->nredir.n = n1;
12119 n1 = n2;
12120 }
12121 n1->nredir.redirect = redir;
12122 }
Eric Andersencb57d552001-06-28 07:25:16 +000012123 return n1;
12124}
12125
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012126#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020012127static int
12128decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012129{
12130 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
12131 int c, cnt;
12132 char *p;
12133 char buf[4];
12134
12135 c = pgetc();
12136 p = strchr(C_escapes, c);
12137 if (p) {
12138 buf[0] = c;
12139 p = buf;
12140 cnt = 3;
12141 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
12142 do {
12143 c = pgetc();
12144 *++p = c;
12145 } while ((unsigned char)(c - '0') <= 7 && --cnt);
12146 pungetc();
12147 } else if (c == 'x') { /* \xHH */
12148 do {
12149 c = pgetc();
12150 *++p = c;
12151 } while (isxdigit(c) && --cnt);
12152 pungetc();
12153 if (cnt == 3) { /* \x but next char is "bad" */
12154 c = 'x';
12155 goto unrecognized;
12156 }
12157 } else { /* simple seq like \\ or \t */
12158 p++;
12159 }
12160 *p = '\0';
12161 p = buf;
12162 c = bb_process_escape_sequence((void*)&p);
12163 } else { /* unrecognized "\z": print both chars unless ' or " */
12164 if (c != '\'' && c != '"') {
12165 unrecognized:
12166 c |= 0x100; /* "please encode \, then me" */
12167 }
12168 }
12169 return c;
12170}
12171#endif
12172
Denys Vlasenko46999802017-07-29 21:12:29 +020012173/* Used by expandstr to get here-doc like behaviour. */
12174#define FAKEEOFMARK ((char*)(uintptr_t)1)
12175
12176static ALWAYS_INLINE int
12177realeofmark(const char *eofmark)
12178{
12179 return eofmark && eofmark != FAKEEOFMARK;
12180}
12181
Eric Andersencb57d552001-06-28 07:25:16 +000012182/*
12183 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
12184 * is not NULL, read a here document. In the latter case, eofmark is the
12185 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010012186 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000012187 * is the first character of the input token or document.
12188 *
12189 * Because C does not have internal subroutines, I have simulated them
12190 * using goto's to implement the subroutine linkage. The following macros
12191 * will run code that appears at the end of readtoken1.
12192 */
Eric Andersen2870d962001-07-02 17:27:21 +000012193#define CHECKEND() {goto checkend; checkend_return:;}
12194#define PARSEREDIR() {goto parseredir; parseredir_return:;}
12195#define PARSESUB() {goto parsesub; parsesub_return:;}
12196#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
12197#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
12198#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000012199static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010012200readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000012201{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012202 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010012203 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000012204 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020012205 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012206 struct nodelist *bqlist;
12207 smallint quotef;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012208 smallint oldstyle;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012209 smallint pssyntax; /* we are expanding a prompt string */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012210 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012211 /* syntax stack */
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020012212 struct synstack synbase = { };
Denys Vlasenko216913c2018-04-02 12:35:04 +020012213 struct synstack *synstack = &synbase;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012214
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012215#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000012216 pssyntax = (syntax == PSSYNTAX);
12217 if (pssyntax)
12218 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012219#else
12220 pssyntax = 0; /* constant */
12221#endif
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020012222 synstack->syntax = syntax;
12223
Denys Vlasenko216913c2018-04-02 12:35:04 +020012224 if (syntax == DQSYNTAX)
12225 synstack->dblquote = 1;
12226 quotef = 0;
12227 bqlist = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000012228
12229 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012230 loop:
12231 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012232 CHECKEND(); /* set c to PEOF if at end of here document */
12233 for (;;) { /* until end of line or end of word */
12234 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012235 switch (SIT(c, synstack->syntax)) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012236 case CNL: /* '\n' */
Denys Vlasenko680c3012018-04-11 12:39:18 +020012237 if (synstack->syntax == BASESYNTAX
12238 && !synstack->varnest
12239 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012240 goto endword; /* exit outer loop */
Denys Vlasenko680c3012018-04-11 12:39:18 +020012241 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012242 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012243 nlprompt();
Denys Vlasenkof7eea8c2020-02-14 16:16:34 +010012244 c = pgetc_top(synstack);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012245 goto loop; /* continue outer loop */
12246 case CWORD:
12247 USTPUTC(c, out);
12248 break;
12249 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012250#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020012251 if (c == '\\' && bash_dollar_squote) {
12252 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020012253 if (c == '\0') {
12254 /* skip $'\000', $'\x00' (like bash) */
12255 break;
12256 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012257 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020012258 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012259 c = (unsigned char)c;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012260 if (eofmark == NULL || synstack->dblquote)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012261 USTPUTC(CTLESC, out);
12262 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012263 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012264 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012265#endif
Denys Vlasenkoc4c20122018-04-02 13:29:20 +020012266 if (!eofmark || synstack->dblquote || synstack->varnest)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012267 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012268 USTPUTC(c, out);
12269 break;
12270 case CBACK: /* backslash */
12271 c = pgetc_without_PEOA();
12272 if (c == PEOF) {
12273 USTPUTC(CTLESC, out);
12274 USTPUTC('\\', out);
12275 pungetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012276 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012277 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000012278 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012279 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012280 }
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012281 /* Backslash is retained if we are in "str"
12282 * and next char isn't dquote-special.
12283 */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012284 if (synstack->dblquote
Denys Vlasenko958581a2010-09-12 15:04:27 +020012285 && c != '\\'
12286 && c != '`'
12287 && c != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012288 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12289 && (c != '}' || !synstack->varnest)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012290 ) {
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012291 USTPUTC(CTLESC, out); /* protect '\' from glob */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012292 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012293 }
Ron Yorston549deab2015-05-18 09:57:51 +020012294 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020012295 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012296 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012297 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012298 break;
12299 case CSQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012300 synstack->syntax = SQSYNTAX;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012301 quotemark:
12302 if (eofmark == NULL) {
12303 USTPUTC(CTLQUOTEMARK, out);
12304 }
12305 break;
12306 case CDQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012307 synstack->syntax = DQSYNTAX;
12308 synstack->dblquote = 1;
12309 toggledq:
12310 if (synstack->varnest)
12311 synstack->innerdq ^= 1;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012312 goto quotemark;
12313 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012314 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012315 if (eofmark != NULL && synstack->varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012316 USTPUTC(c, out);
Denys Vlasenko216913c2018-04-02 12:35:04 +020012317 break;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012318 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012319
12320 if (synstack->dqvarnest == 0) {
12321 synstack->syntax = BASESYNTAX;
12322 synstack->dblquote = 0;
12323 }
12324
12325 quotef = 1;
12326
12327 if (c == '"')
12328 goto toggledq;
12329
12330 goto quotemark;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012331 case CVAR: /* '$' */
12332 PARSESUB(); /* parse substitution */
12333 break;
12334 case CENDVAR: /* '}' */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012335 if (!synstack->innerdq && synstack->varnest > 0) {
12336 if (!--synstack->varnest && synstack->varpushed)
12337 synstack_pop(&synstack);
12338 else if (synstack->dqvarnest > 0)
12339 synstack->dqvarnest--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012340 c = CTLENDVAR;
12341 }
12342 USTPUTC(c, out);
12343 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010012344#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020012345 case CLP: /* '(' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012346 synstack->parenlevel++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012347 USTPUTC(c, out);
12348 break;
12349 case CRP: /* ')' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012350 if (synstack->parenlevel > 0) {
12351 synstack->parenlevel--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012352 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012353 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020012354 c = CTLENDARI;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012355 synstack_pop(&synstack);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012356 } else {
12357 /*
12358 * unbalanced parens
12359 * (don't 2nd guess - no error)
12360 */
12361 pungetc();
12362 }
12363 }
12364 USTPUTC(c, out);
12365 break;
12366#endif
12367 case CBQUOTE: /* '`' */
Denys Vlasenko41fddb42018-04-01 16:38:32 +020012368 if (checkkwd & CHKEOFMARK) {
12369 quotef = 1;
12370 USTPUTC('`', out);
12371 break;
12372 }
12373
Denys Vlasenko958581a2010-09-12 15:04:27 +020012374 PARSEBACKQOLD();
12375 break;
12376 case CENDFILE:
12377 goto endword; /* exit outer loop */
12378 case CIGN:
12379 break;
12380 default:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012381 if (synstack->varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012382#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020012383 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012384//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020012385 if (pgetc() == '>')
12386 c = 0x100 + '>'; /* flag &> */
12387 pungetc();
12388 }
12389#endif
12390 goto endword; /* exit outer loop */
12391 }
12392 IF_ASH_ALIAS(if (c != PEOA))
12393 USTPUTC(c, out);
12394 }
Denys Vlasenkof7eea8c2020-02-14 16:16:34 +010012395 c = pgetc_top(synstack);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012396 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012397 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020012398
Denys Vlasenko0b883582016-12-23 16:49:07 +010012399#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko216913c2018-04-02 12:35:04 +020012400 if (synstack->syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012401 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000012402#endif
Denys Vlasenko216913c2018-04-02 12:35:04 +020012403 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012404 raise_error_syntax("unterminated quoted string");
Denys Vlasenko216913c2018-04-02 12:35:04 +020012405 if (synstack->varnest != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012406 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000012407 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000012408 }
12409 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012410 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000012411 out = stackblock();
12412 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012413 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000012414 && quotef == 0
12415 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000012416 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012417 PARSEREDIR(); /* passed as params: out, c */
12418 lasttoken = TREDIR;
12419 return lasttoken;
12420 }
12421 /* else: non-number X seen, interpret it
12422 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000012423 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012424 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012425 }
12426 quoteflag = quotef;
12427 backquotelist = bqlist;
12428 grabstackblock(len);
12429 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012430 lasttoken = TWORD;
12431 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012432/* end of readtoken routine */
12433
Eric Andersencb57d552001-06-28 07:25:16 +000012434/*
12435 * Check to see whether we are at the end of the here document. When this
12436 * is called, c is set to the first character of the next input line. If
12437 * we are at the end of the here document, this routine sets the c to PEOF.
12438 */
Eric Andersenc470f442003-07-28 09:56:35 +000012439checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020012440 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012441 int markloc;
12442 char *p;
12443
Denis Vlasenko131ae172007-02-18 13:00:19 +000012444#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012445 if (c == PEOA)
12446 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000012447#endif
12448 if (striptabs) {
12449 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012450 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000012451 }
Eric Andersenc470f442003-07-28 09:56:35 +000012452 }
Eric Andersencb57d552001-06-28 07:25:16 +000012453
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012454 markloc = out - (char *)stackblock();
12455 for (p = eofmark; STPUTC(c, out), *p; p++) {
12456 if (c != *p)
12457 goto more_heredoc;
Denys Vlasenko35e349d2019-09-05 14:31:49 +020012458 /* FIXME: fails for backslash-newlined terminator:
12459 * cat <<EOF
12460 * ...
12461 * EO\
12462 * F
12463 * (see heredoc_bkslash_newline2.tests)
12464 */
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012465 c = pgetc_without_PEOA();
12466 }
12467
12468 if (c == '\n' || c == PEOF) {
12469 c = PEOF;
12470 g_parsefile->linno++;
12471 needprompt = doprompt;
12472 } else {
12473 int len_here;
12474
12475 more_heredoc:
12476 p = (char *)stackblock() + markloc + 1;
12477 len_here = out - p;
12478
12479 if (len_here) {
12480 len_here -= (c >= PEOF);
12481 c = p[-1];
12482
12483 if (len_here) {
12484 char *str;
12485
12486 str = alloca(len_here + 1);
12487 *(char *)mempcpy(str, p, len_here) = '\0';
12488
12489 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012490 }
12491 }
12492 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012493
12494 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012495 }
Eric Andersenc470f442003-07-28 09:56:35 +000012496 goto checkend_return;
12497}
Eric Andersencb57d552001-06-28 07:25:16 +000012498
Eric Andersencb57d552001-06-28 07:25:16 +000012499/*
12500 * Parse a redirection operator. The variable "out" points to a string
12501 * specifying the fd to be redirected. The variable "c" contains the
12502 * first character of the redirection operator.
12503 */
Eric Andersenc470f442003-07-28 09:56:35 +000012504parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012505 /* out is already checked to be a valid number or "" */
12506 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000012507 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000012508
Denis Vlasenko597906c2008-02-20 16:38:54 +000012509 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000012510 if (c == '>') {
12511 np->nfile.fd = 1;
Denys Vlasenko220be532018-03-31 19:21:31 +020012512 c = pgetc_eatbnl();
Eric Andersenc470f442003-07-28 09:56:35 +000012513 if (c == '>')
12514 np->type = NAPPEND;
12515 else if (c == '|')
12516 np->type = NCLOBBER;
12517 else if (c == '&')
12518 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012519 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000012520 else {
12521 np->type = NTO;
12522 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012523 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000012524 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012525#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012526 else if (c == 0x100 + '>') { /* this flags &> redirection */
12527 np->nfile.fd = 1;
12528 pgetc(); /* this is '>', no need to check */
12529 np->type = NTO2;
12530 }
12531#endif
12532 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000012533 /*np->nfile.fd = 0; - stzalloc did it */
Denys Vlasenko220be532018-03-31 19:21:31 +020012534 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012535 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000012536 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012537 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012538 np = stzalloc(sizeof(struct nhere));
12539 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012540 }
12541 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012542 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000012543 heredoc->here = np;
Denys Vlasenko220be532018-03-31 19:21:31 +020012544 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012545 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000012546 heredoc->striptabs = 1;
12547 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012548 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012549 pungetc();
12550 }
12551 break;
12552
12553 case '&':
12554 np->type = NFROMFD;
12555 break;
12556
12557 case '>':
12558 np->type = NFROMTO;
12559 break;
12560
12561 default:
12562 np->type = NFROM;
12563 pungetc();
12564 break;
12565 }
Eric Andersencb57d552001-06-28 07:25:16 +000012566 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012567 if (fd >= 0)
12568 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012569 redirnode = np;
12570 goto parseredir_return;
12571}
Eric Andersencb57d552001-06-28 07:25:16 +000012572
Eric Andersencb57d552001-06-28 07:25:16 +000012573/*
12574 * Parse a substitution. At this point, we have read the dollar sign
12575 * and nothing else.
12576 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012577
12578/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12579 * (assuming ascii char codes, as the original implementation did) */
12580#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012581 (((unsigned)(c) - 33 < 32) \
12582 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012583parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012584 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012585 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012586
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012587 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012588 if ((checkkwd & CHKEOFMARK)
12589 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012590 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012591 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012592#if BASH_DOLLAR_SQUOTE
Denys Vlasenko216913c2018-04-02 12:35:04 +020012593 if (synstack->syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012594 bash_dollar_squote = 1;
12595 else
12596#endif
12597 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012598 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012599 } else if (c == '(') {
12600 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012601 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012602#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012603 PARSEARITH();
12604#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012605 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012606#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012607 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012608 pungetc();
12609 PARSEBACKQNEW();
12610 }
12611 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012612 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012613 smalluint newsyn = synstack->syntax;
12614
Eric Andersenc470f442003-07-28 09:56:35 +000012615 USTPUTC(CTLVAR, out);
12616 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012617 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012618 subtype = VSNORMAL;
12619 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012620 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012621 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012622 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012623 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012624 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012625 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012626 do {
12627 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012628 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012629 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012630 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012631 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012632 do {
12633 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012634 c = pgetc_eatbnl();
Denys Vlasenkoc2ce8882020-02-17 10:15:35 +010012635 } while (!subtype && isdigit(c));
Denys Vlasenko58eb8052018-08-05 15:58:13 +020012636 } else if (c != '}') {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012637 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012638 int cc = c;
12639
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012640 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012641 if (!subtype && cc == '#') {
12642 subtype = VSLENGTH;
12643 if (c == '_' || isalnum(c))
12644 goto varname;
12645 cc = c;
12646 c = pgetc_eatbnl();
12647 if (cc == '}' || c != '}') {
12648 pungetc();
12649 subtype = 0;
12650 c = cc;
12651 cc = '#';
12652 }
12653 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012654
12655 if (!is_special(cc)) {
12656 if (subtype == VSLENGTH)
12657 subtype = 0;
12658 goto badsub;
12659 }
12660
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012661 USTPUTC(cc, out);
Denys Vlasenko58eb8052018-08-05 15:58:13 +020012662 } else
12663 goto badsub;
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012664
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012665 if (c != '}' && subtype == VSLENGTH) {
12666 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012667 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012668 }
Eric Andersencb57d552001-06-28 07:25:16 +000012669
Eric Andersenc470f442003-07-28 09:56:35 +000012670 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012671 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012672 /* ${VAR...} but not $VAR or ${#VAR} */
12673 /* c == first char after VAR */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012674 int cc = c;
12675
Eric Andersenc470f442003-07-28 09:56:35 +000012676 switch (c) {
12677 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012678 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012679#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012680 /* This check is only needed to not misinterpret
12681 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12682 * constructs.
12683 */
12684 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012685 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012686 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012687 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012688 }
12689#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012690 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012691 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012692 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012693 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012694 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012695 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012696 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012697 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012698 }
Eric Andersenc470f442003-07-28 09:56:35 +000012699 case '%':
Denys Vlasenko216913c2018-04-02 12:35:04 +020012700 case '#':
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012701 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012702 c = pgetc_eatbnl();
Denys Vlasenko216913c2018-04-02 12:35:04 +020012703 if (c == cc)
12704 subtype++;
12705 else
12706 pungetc();
12707
12708 newsyn = BASESYNTAX;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012709 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012710#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012711 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012712 /* ${v/[/]pattern/repl} */
12713//TODO: encode pattern and repl separately.
Denys Vlasenko216913c2018-04-02 12:35:04 +020012714// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12715// are broken (should print "ONE")
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012716 subtype = VSREPLACE;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012717 newsyn = BASESYNTAX;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012718 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012719 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012720 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012721 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012722 break;
12723#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012724 }
Eric Andersenc470f442003-07-28 09:56:35 +000012725 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012726 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012727 pungetc();
12728 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012729
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012730 if (newsyn == ARISYNTAX)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012731 newsyn = DQSYNTAX;
12732
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012733 if ((newsyn != synstack->syntax || synstack->innerdq)
12734 && subtype != VSNORMAL
12735 ) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012736 synstack_push(&synstack,
12737 synstack->prev ?: alloca(sizeof(*synstack)),
12738 newsyn);
12739
12740 synstack->varpushed = 1;
12741 synstack->dblquote = newsyn != BASESYNTAX;
12742 }
12743
Denys Vlasenko3df14102016-10-26 16:41:13 +020012744 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012745 if (subtype != VSNORMAL) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012746 synstack->varnest++;
12747 if (synstack->dblquote)
12748 synstack->dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012749 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012750 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012751 }
Eric Andersenc470f442003-07-28 09:56:35 +000012752 goto parsesub_return;
12753}
Eric Andersencb57d552001-06-28 07:25:16 +000012754
Eric Andersencb57d552001-06-28 07:25:16 +000012755/*
12756 * Called to parse command substitutions. Newstyle is set if the command
12757 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12758 * list of commands (passed by reference), and savelen is the number of
12759 * characters on the top of the stack which must be preserved.
12760 */
Eric Andersenc470f442003-07-28 09:56:35 +000012761parsebackq: {
12762 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012763 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012764 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012765 size_t savelen;
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012766 struct heredoc *saveheredoclist;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012767 smallint saveprompt = 0;
12768
Eric Andersenc470f442003-07-28 09:56:35 +000012769 str = NULL;
12770 savelen = out - (char *)stackblock();
12771 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012772 /*
12773 * FIXME: this can allocate very large block on stack and SEGV.
12774 * Example:
12775 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012776 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012777 * a hundred command substitutions stack overflows.
12778 * With larger prepended string, SEGV happens sooner.
12779 */
Ron Yorston072fc602015-07-01 16:46:18 +010012780 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012781 memcpy(str, stackblock(), savelen);
12782 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012783
Eric Andersenc470f442003-07-28 09:56:35 +000012784 if (oldstyle) {
12785 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012786 * treatment to some slashes, and then push the string and
12787 * reread it as input, interpreting it normally.
12788 */
Eric Andersenc470f442003-07-28 09:56:35 +000012789 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012790 size_t psavelen;
12791 char *pstr;
12792
Eric Andersenc470f442003-07-28 09:56:35 +000012793 STARTSTACKSTR(pout);
12794 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012795 int pc;
12796
12797 setprompt_if(needprompt, 2);
Denys Vlasenko220be532018-03-31 19:21:31 +020012798 pc = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012799 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012800 case '`':
12801 goto done;
12802
12803 case '\\':
Denys Vlasenko777a6352020-09-29 16:25:32 +020012804 pc = pgetc(); /* not pgetc_eatbnl! */
Eric Andersenc470f442003-07-28 09:56:35 +000012805 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012806 && (!synstack->dblquote || pc != '"')
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012807 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012808 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012809 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012810 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012811 break;
12812 }
12813 /* fall through */
12814
12815 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012816 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012817 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012818
12819 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012820 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012821 break;
12822
12823 default:
12824 break;
12825 }
12826 STPUTC(pc, pout);
12827 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012828 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012829 STPUTC('\0', pout);
12830 psavelen = pout - (char *)stackblock();
12831 if (psavelen > 0) {
12832 pstr = grabstackstr(pout);
12833 setinputstring(pstr);
12834 }
12835 }
12836 nlpp = &bqlist;
12837 while (*nlpp)
12838 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012839 *nlpp = stzalloc(sizeof(**nlpp));
12840 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012841
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012842 saveheredoclist = heredoclist;
12843 heredoclist = NULL;
12844
Eric Andersenc470f442003-07-28 09:56:35 +000012845 if (oldstyle) {
12846 saveprompt = doprompt;
12847 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012848 }
12849
Eric Andersenc470f442003-07-28 09:56:35 +000012850 n = list(2);
12851
12852 if (oldstyle)
12853 doprompt = saveprompt;
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012854 else {
12855 if (readtoken() != TRP)
12856 raise_error_unexpected_syntax(TRP);
12857 setinputstring(nullstr);
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012858 }
12859
Denys Vlasenko9a1a6592020-02-22 16:39:27 +010012860 parseheredoc();
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012861 heredoclist = saveheredoclist;
Eric Andersenc470f442003-07-28 09:56:35 +000012862
12863 (*nlpp)->n = n;
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012864 /* Start reading from old file again. */
12865 popfile();
12866 /* Ignore any pushed back tokens left from the backquote parsing. */
12867 if (oldstyle)
Eric Andersenc470f442003-07-28 09:56:35 +000012868 tokpushback = 0;
Denys Vlasenkoc55847f2020-02-17 15:59:08 +010012869 out = growstackto(savelen + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012870 if (str) {
12871 memcpy(out, str, savelen);
12872 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012873 }
Ron Yorston549deab2015-05-18 09:57:51 +020012874 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012875 if (oldstyle)
12876 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012877 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012878}
12879
Denys Vlasenko0b883582016-12-23 16:49:07 +010012880#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012881/*
12882 * Parse an arithmetic expansion (indicate start of one and set state)
12883 */
Eric Andersenc470f442003-07-28 09:56:35 +000012884parsearith: {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012885
12886 synstack_push(&synstack,
12887 synstack->prev ?: alloca(sizeof(*synstack)),
12888 ARISYNTAX);
12889 synstack->dblquote = 1;
Ron Yorstonad88bde2015-05-18 09:56:16 +020012890 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012891 goto parsearith_return;
12892}
12893#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012894} /* end of readtoken */
12895
Eric Andersencb57d552001-06-28 07:25:16 +000012896/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012897 * Read the next input token.
12898 * If the token is a word, we set backquotelist to the list of cmds in
12899 * backquotes. We set quoteflag to true if any part of the word was
12900 * quoted.
12901 * If the token is TREDIR, then we set redirnode to a structure containing
12902 * the redirection.
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012903 *
12904 * [Change comment: here documents and internal procedures]
12905 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12906 * word parsing code into a separate routine. In this case, readtoken
12907 * doesn't need to have any internal procedures, but parseword does.
12908 * We could also make parseoperator in essence the main routine, and
12909 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012910 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012911#define NEW_xxreadtoken
12912#ifdef NEW_xxreadtoken
12913/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012914static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012915 '\n', '(', ')', /* singles */
12916 '&', '|', ';', /* doubles */
12917 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012918};
Eric Andersencb57d552001-06-28 07:25:16 +000012919
Denis Vlasenko834dee72008-10-07 09:18:30 +000012920#define xxreadtoken_singles 3
12921#define xxreadtoken_doubles 3
12922
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012923static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012924 TNL, TLP, TRP, /* only single occurrence allowed */
12925 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12926 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012927 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012928};
12929
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012930static int
12931xxreadtoken(void)
12932{
12933 int c;
12934
12935 if (tokpushback) {
12936 tokpushback = 0;
12937 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012938 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012939 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012940 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012941 c = pgetc_eatbnl();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012942 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012943 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012944
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012945 if (c == '#') {
12946 while ((c = pgetc()) != '\n' && c != PEOF)
12947 continue;
12948 pungetc();
12949 } else if (c == '\\') {
Denys Vlasenko220be532018-03-31 19:21:31 +020012950 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012951 } else {
12952 const char *p;
12953
12954 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12955 if (c != PEOF) {
12956 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012957 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012958 }
12959
12960 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012961 if (p == NULL)
12962 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012963
Denis Vlasenko834dee72008-10-07 09:18:30 +000012964 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
Denys Vlasenko1e5111b2018-04-01 03:04:55 +020012965 int cc = pgetc_eatbnl();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012966 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012967 p += xxreadtoken_doubles + 1;
12968 } else {
12969 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012970#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012971 if (c == '&' && cc == '>') /* &> */
12972 break; /* return readtoken1(...) */
12973#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012974 }
12975 }
12976 }
12977 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12978 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012979 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012980 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012981
12982 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012983}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012984#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012985#define RETURN(token) return lasttoken = token
12986static int
12987xxreadtoken(void)
12988{
12989 int c;
12990
12991 if (tokpushback) {
12992 tokpushback = 0;
12993 return lasttoken;
12994 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012995 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012996 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012997 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012998 switch (c) {
12999 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010013000 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013001 continue;
13002 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000013003 while ((c = pgetc()) != '\n' && c != PEOF)
13004 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013005 pungetc();
13006 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013007 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020013008 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013009 RETURN(TNL);
13010 case PEOF:
13011 RETURN(TEOF);
13012 case '&':
Denys Vlasenko220be532018-03-31 19:21:31 +020013013 if (pgetc_eatbnl() == '&')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013014 RETURN(TAND);
13015 pungetc();
13016 RETURN(TBACKGND);
13017 case '|':
Denys Vlasenko220be532018-03-31 19:21:31 +020013018 if (pgetc_eatbnl() == '|')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013019 RETURN(TOR);
13020 pungetc();
13021 RETURN(TPIPE);
13022 case ';':
Denys Vlasenko220be532018-03-31 19:21:31 +020013023 if (pgetc_eatbnl() == ';')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013024 RETURN(TENDCASE);
13025 pungetc();
13026 RETURN(TSEMI);
13027 case '(':
13028 RETURN(TLP);
13029 case ')':
13030 RETURN(TRP);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013031 }
Denys Vlasenko220be532018-03-31 19:21:31 +020013032 break;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013033 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013034 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
13035#undef RETURN
13036}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000013037#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013038
13039static int
13040readtoken(void)
13041{
13042 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000013043 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013044#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000013045 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013046#endif
13047
13048#if ENABLE_ASH_ALIAS
13049 top:
13050#endif
13051
13052 t = xxreadtoken();
13053
13054 /*
13055 * eat newlines
13056 */
Ron Yorston713f07d2015-10-29 16:44:56 +000013057 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013058 while (t == TNL) {
13059 parseheredoc();
13060 t = xxreadtoken();
13061 }
13062 }
13063
13064 if (t != TWORD || quoteflag) {
13065 goto out;
13066 }
13067
13068 /*
13069 * check for keywords
13070 */
Ron Yorston713f07d2015-10-29 16:44:56 +000013071 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013072 const char *const *pp;
13073
13074 pp = findkwd(wordtext);
13075 if (pp) {
13076 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020013077 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013078 goto out;
13079 }
13080 }
13081
13082 if (checkkwd & CHKALIAS) {
13083#if ENABLE_ASH_ALIAS
13084 struct alias *ap;
13085 ap = lookupalias(wordtext, 1);
13086 if (ap != NULL) {
13087 if (*ap->val) {
13088 pushstring(ap->val, ap);
13089 }
13090 goto top;
13091 }
13092#endif
13093 }
13094 out:
13095 checkkwd = 0;
13096#if DEBUG
13097 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020013098 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013099 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020013100 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013101#endif
13102 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000013103}
13104
Ron Yorstonc0e00762015-10-29 11:30:55 +000013105static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000013106peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013107{
13108 int t;
13109
13110 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000013111 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000013112 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013113}
Eric Andersencb57d552001-06-28 07:25:16 +000013114
13115/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013116 * Read and parse a command. Returns NODE_EOF on end of file.
13117 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000013118 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013119static union node *
13120parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000013121{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013122 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000013123 checkkwd = 0;
13124 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013125 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020013126 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013127 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013128 return list(1);
13129}
13130
13131/*
13132 * Input any here documents.
13133 */
13134static void
13135parseheredoc(void)
13136{
13137 struct heredoc *here;
13138 union node *n;
13139
13140 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000013141 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013142
13143 while (here) {
Christoph Schulz03ad7ae2018-11-20 17:45:52 +010013144 tokpushback = 0;
Denys Vlasenko958581a2010-09-12 15:04:27 +020013145 setprompt_if(needprompt, 2);
Denys Vlasenkoacf79f92020-02-14 16:12:06 +010013146 if (here->here->type == NHERE)
13147 readtoken1(pgetc(), SQSYNTAX, here->eofmark, here->striptabs);
13148 else
13149 readtoken1(pgetc_eatbnl(), DQSYNTAX, here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000013150 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013151 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000013152 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013153 n->narg.text = wordtext;
13154 n->narg.backquote = backquotelist;
13155 here->here->nhere.doc = n;
13156 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000013157 }
Eric Andersencb57d552001-06-28 07:25:16 +000013158}
13159
13160
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013161static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020013162expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013163{
13164 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020013165 int saveprompt;
Ron Yorston48645b82019-04-18 09:48:13 +010013166 struct parsefile *file_stop = g_parsefile;
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013167 volatile int saveint;
13168 struct jmploc *volatile savehandler = exception_handler;
13169 struct jmploc jmploc;
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013170 const char *volatile result;
13171 int err;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013172
Denys Vlasenko46999802017-07-29 21:12:29 +020013173 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013174 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020013175
13176 saveprompt = doprompt;
13177 doprompt = 0;
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013178 result = ps;
13179
13180 SAVE_INT(saveint);
13181 err = setjmp(jmploc.loc);
13182 if (err)
13183 goto out;
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020013184
13185 /* readtoken1() might die horribly.
Denys Vlasenko3c183a82017-10-12 19:35:42 +020013186 * Try a prompt with syntactically wrong command:
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020013187 * PS1='$(date "+%H:%M:%S) > '
13188 */
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013189 exception_handler = &jmploc;
13190 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013191
13192 n.narg.type = NARG;
13193 n.narg.next = NULL;
13194 n.narg.text = wordtext;
13195 n.narg.backquote = backquotelist;
13196
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013197 /* expandarg() might fail too:
13198 * PS1='$((123+))'
13199 */
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013200 expandarg(&n, NULL, EXP_QUOTED);
13201 result = stackblock();
13202
13203out:
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013204 exception_handler = savehandler;
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013205 if (err && exception_type != EXERROR)
13206 longjmp(exception_handler->loc, 1);
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013207 RESTORE_INT(saveint);
13208
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013209 doprompt = saveprompt;
13210 /* Try: PS1='`xxx(`' */
13211 unwindfiles(file_stop);
13212
13213 return result;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013214}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013215
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013216static inline int
13217parser_eof(void)
13218{
13219 return tokpushback && lasttoken == TEOF;
13220}
13221
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013222/*
13223 * Execute a command or commands contained in a string.
13224 */
13225static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013226evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000013227{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010013228 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013229 struct jmploc jmploc;
13230 int ex;
13231
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013232 union node *n;
13233 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013234 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013235
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013236 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013237 setinputstring(s);
13238 setstackmark(&smark);
13239
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013240 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013241 /* On exception inside execution loop, we must popfile().
13242 * Try interactively:
13243 * readonly a=a
13244 * command eval "a=b" # throws "is read only" error
13245 * "command BLTIN" is not supposed to abort (even in non-interactive use).
13246 * But if we skip popfile(), we hit EOF in eval's string, and exit.
13247 */
13248 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013249 ex = setjmp(jmploc.loc);
13250 if (ex)
13251 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010013252 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013253
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013254 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013255 int i;
13256
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013257 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013258 if (n)
13259 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013260 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013261 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013262 break;
13263 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013264 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013265 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013266 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013267 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013268
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013269 exception_handler = savehandler;
13270 if (ex)
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013271 longjmp(exception_handler->loc, ex);
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013272
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013273 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000013274}
13275
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013276/*
13277 * The eval command.
13278 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013279static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013280evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013281{
13282 char *p;
13283 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013284
Denis Vlasenko68404f12008-03-17 09:00:54 +000013285 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013286 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013287 argv += 2;
13288 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013289 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013290 for (;;) {
13291 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013292 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013293 if (p == NULL)
13294 break;
13295 STPUTC(' ', concat);
13296 }
13297 STPUTC('\0', concat);
13298 p = grabstackstr(concat);
13299 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013300 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013301 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013302 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013303}
13304
13305/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010013306 * Read and execute commands.
13307 * "Top" is nonzero for the top level command loop;
13308 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013309 */
13310static int
13311cmdloop(int top)
13312{
13313 union node *n;
13314 struct stackmark smark;
13315 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013316 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013317 int numeof = 0;
13318
13319 TRACE(("cmdloop(%d) called\n", top));
13320 for (;;) {
13321 int skip;
13322
13323 setstackmark(&smark);
13324#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000013325 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020013326 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013327#endif
13328 inter = 0;
13329 if (iflag && top) {
13330 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013331 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013332 }
13333 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020013334#if DEBUG
13335 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020013336 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000013337#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013338 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013339 if (!top || numeof >= 50)
13340 break;
13341 if (!stoppedjobs()) {
Denys Vlasenko226b8a12020-02-16 18:57:53 +010013342 if (!Iflag) {
13343 if (iflag) {
13344 newline_and_flush(stderr);
13345 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013346 break;
Denys Vlasenko226b8a12020-02-16 18:57:53 +010013347 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013348 out2str("\nUse \"exit\" to leave shell.\n");
13349 }
13350 numeof++;
13351 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013352 int i;
13353
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000013354 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13355 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013356 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013357 i = evaltree(n, 0);
13358 if (n)
13359 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013360 }
13361 popstackmark(&smark);
13362 skip = evalskip;
13363
13364 if (skip) {
Denys Vlasenkocd24a502020-02-20 16:47:01 +010013365 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
Denys Vlasenko0840c912016-10-01 15:27:44 +020013366 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013367 }
13368 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013369 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013370}
13371
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013372/*
13373 * Take commands from a file. To be compatible we should do a path
13374 * search for the file, which is necessary to find sub-commands.
13375 */
13376static char *
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013377find_dot_file(char *basename)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013378{
13379 char *fullname;
13380 const char *path = pathval();
13381 struct stat statb;
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013382 int len;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013383
13384 /* don't try this for absolute or relative paths */
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013385 if (strchr(basename, '/'))
13386 return basename;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013387
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013388 while ((len = padvance(&path, basename)) >= 0) {
13389 fullname = stackblock();
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010013390 if ((!pathopt || *pathopt == 'f')
13391 && !stat(fullname, &statb) && S_ISREG(statb.st_mode)
13392 ) {
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013393 /* This will be freed by the caller. */
13394 return stalloc(len);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013395 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013396 }
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013397 /* not found in PATH */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013398
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013399#if ENABLE_ASH_BASH_SOURCE_CURDIR
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013400 return basename;
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013401#else
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013402 ash_msg_and_raise_error("%s: not found", basename);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013403 /* NOTREACHED */
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013404#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013405}
13406
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013407static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013408dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013409{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013410 /* "false; . empty_file; echo $?" should print 0, not 1: */
13411 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013412 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013413 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013414 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013415 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013416
Denys Vlasenko981a0562017-07-26 19:53:11 +020013417//???
13418// struct strlist *sp;
13419// for (sp = cmdenviron; sp; sp = sp->next)
13420// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013421
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013422 nextopt(nullstr); /* handle possible "--" */
13423 argv = argptr;
13424
13425 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013426 /* bash says: "bash: .: filename argument required" */
13427 return 2; /* bash compat */
13428 }
13429
Denys Vlasenko091f8312013-03-17 14:25:22 +010013430 /* This aborts if file isn't found, which is POSIXly correct.
13431 * bash returns exitcode 1 instead.
13432 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013433 fullname = find_dot_file(argv[0]);
13434 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013435 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013436 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013437 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013438 saveparam = shellparam;
13439 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013440 argc = 1;
13441 while (argv[argc])
13442 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013443 shellparam.nparam = argc;
13444 shellparam.p = argv;
13445 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013446
Denys Vlasenko091f8312013-03-17 14:25:22 +010013447 /* This aborts if file can't be opened, which is POSIXly correct.
13448 * bash returns exitcode 1 instead.
13449 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013450 setinputfile(fullname, INPUT_PUSH_FILE);
13451 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013452 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013453 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013454
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013455 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013456 freeparam(&shellparam);
13457 shellparam = saveparam;
13458 };
13459
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013460 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013461}
13462
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013463static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013464exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013465{
13466 if (stoppedjobs())
13467 return 0;
Denys Vlasenko4ccddc82020-02-14 17:27:18 +010013468
Denys Vlasenko970470e2020-02-14 17:32:22 +010013469 if (argv[1])
13470 savestatus = number(argv[1]);
Denys Vlasenko4ccddc82020-02-14 17:27:18 +010013471
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013472 raise_exception(EXEXIT);
13473 /* NOTREACHED */
13474}
13475
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013476/*
13477 * Read a file containing shell functions.
13478 */
13479static void
13480readcmdfile(char *name)
13481{
13482 setinputfile(name, INPUT_PUSH_FILE);
13483 cmdloop(0);
13484 popfile();
13485}
13486
13487
Denis Vlasenkocc571512007-02-23 21:10:35 +000013488/* ============ find_command inplementation */
13489
13490/*
13491 * Resolve a command name. If you change this routine, you may have to
13492 * change the shellexec routine as well.
13493 */
13494static void
13495find_command(char *name, struct cmdentry *entry, int act, const char *path)
13496{
13497 struct tblentry *cmdp;
13498 int idx;
13499 int prev;
13500 char *fullname;
13501 struct stat statb;
13502 int e;
13503 int updatetbl;
13504 struct builtincmd *bcmd;
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013505 int len;
Denis Vlasenkocc571512007-02-23 21:10:35 +000013506
13507 /* If name contains a slash, don't use PATH or hash table */
13508 if (strchr(name, '/') != NULL) {
13509 entry->u.index = -1;
13510 if (act & DO_ABS) {
13511 while (stat(name, &statb) < 0) {
13512#ifdef SYSV
13513 if (errno == EINTR)
13514 continue;
13515#endif
13516 entry->cmdtype = CMDUNKNOWN;
13517 return;
13518 }
13519 }
13520 entry->cmdtype = CMDNORMAL;
13521 return;
13522 }
13523
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013524/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013525
13526 updatetbl = (path == pathval());
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013527 if (!updatetbl)
Denis Vlasenkocc571512007-02-23 21:10:35 +000013528 act |= DO_ALTPATH;
Denis Vlasenkocc571512007-02-23 21:10:35 +000013529
13530 /* If name is in the table, check answer will be ok */
13531 cmdp = cmdlookup(name, 0);
13532 if (cmdp != NULL) {
13533 int bit;
13534
13535 switch (cmdp->cmdtype) {
13536 default:
13537#if DEBUG
13538 abort();
13539#endif
13540 case CMDNORMAL:
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013541 bit = DO_ALTPATH | DO_REGBLTIN;
Denis Vlasenkocc571512007-02-23 21:10:35 +000013542 break;
13543 case CMDFUNCTION:
13544 bit = DO_NOFUNC;
13545 break;
13546 case CMDBUILTIN:
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013547 bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
Denis Vlasenkocc571512007-02-23 21:10:35 +000013548 break;
13549 }
13550 if (act & bit) {
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013551 if (act & bit & DO_REGBLTIN)
13552 goto fail;
13553
Denis Vlasenkocc571512007-02-23 21:10:35 +000013554 updatetbl = 0;
13555 cmdp = NULL;
13556 } else if (cmdp->rehash == 0)
13557 /* if not invalidated by cd, we're done */
13558 goto success;
13559 }
13560
13561 /* If %builtin not in path, check for builtin next */
13562 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013563 if (bcmd) {
13564 if (IS_BUILTIN_REGULAR(bcmd))
13565 goto builtin_success;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013566 if (act & DO_ALTPATH)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013567 goto builtin_success;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013568 if (builtinloc <= 0)
13569 goto builtin_success;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013570 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013571
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013572 if (act & DO_REGBLTIN)
13573 goto fail;
13574
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013575#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000013576 {
13577 int applet_no = find_applet_by_name(name);
13578 if (applet_no >= 0) {
13579 entry->cmdtype = CMDNORMAL;
13580 entry->u.index = -2 - applet_no;
13581 return;
13582 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013583 }
13584#endif
13585
Denis Vlasenkocc571512007-02-23 21:10:35 +000013586 /* We have to search path. */
13587 prev = -1; /* where to start */
13588 if (cmdp && cmdp->rehash) { /* doing a rehash */
13589 if (cmdp->cmdtype == CMDBUILTIN)
13590 prev = builtinloc;
13591 else
13592 prev = cmdp->param.index;
13593 }
13594
13595 e = ENOENT;
13596 idx = -1;
13597 loop:
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013598 while ((len = padvance(&path, name)) >= 0) {
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010013599 const char *lpathopt = pathopt;
13600
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013601 fullname = stackblock();
Denis Vlasenkocc571512007-02-23 21:10:35 +000013602 idx++;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010013603 if (lpathopt) {
13604 if (*lpathopt == 'b') {
Denis Vlasenkocc571512007-02-23 21:10:35 +000013605 if (bcmd)
13606 goto builtin_success;
13607 continue;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010013608 } else if (!(act & DO_NOFUNC)) {
13609 /* handled below */
13610 } else {
13611 /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013612 continue;
13613 }
13614 }
13615 /* if rehash, don't redo absolute path names */
13616 if (fullname[0] == '/' && idx <= prev) {
13617 if (idx < prev)
13618 continue;
13619 TRACE(("searchexec \"%s\": no change\n", name));
13620 goto success;
13621 }
13622 while (stat(fullname, &statb) < 0) {
13623#ifdef SYSV
13624 if (errno == EINTR)
13625 continue;
13626#endif
13627 if (errno != ENOENT && errno != ENOTDIR)
13628 e = errno;
13629 goto loop;
13630 }
13631 e = EACCES; /* if we fail, this will be the error */
13632 if (!S_ISREG(statb.st_mode))
13633 continue;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010013634 if (lpathopt) { /* this is a %func directory */
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013635 stalloc(len);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013636 /* NB: stalloc will return space pointed by fullname
13637 * (because we don't have any intervening allocations
13638 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013639 readcmdfile(fullname);
13640 cmdp = cmdlookup(name, 0);
13641 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13642 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13643 stunalloc(fullname);
13644 goto success;
13645 }
13646 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13647 if (!updatetbl) {
13648 entry->cmdtype = CMDNORMAL;
13649 entry->u.index = idx;
13650 return;
13651 }
13652 INT_OFF;
13653 cmdp = cmdlookup(name, 1);
13654 cmdp->cmdtype = CMDNORMAL;
13655 cmdp->param.index = idx;
13656 INT_ON;
13657 goto success;
13658 }
13659
13660 /* We failed. If there was an entry for this command, delete it */
13661 if (cmdp && updatetbl)
13662 delete_cmd_entry();
William Pitcockd8fd88a2018-01-24 18:33:18 +010013663 if (act & DO_ERR) {
13664#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13665 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13666 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13667 char *argv[3];
13668 argv[0] = (char*) "command_not_found_handle";
13669 argv[1] = name;
13670 argv[2] = NULL;
13671 evalfun(hookp->param.func, 2, argv, 0);
13672 entry->cmdtype = CMDUNKNOWN;
13673 return;
13674 }
13675#endif
Denis Vlasenkocc571512007-02-23 21:10:35 +000013676 ash_msg("%s: %s", name, errmsg(e, "not found"));
William Pitcockd8fd88a2018-01-24 18:33:18 +010013677 }
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013678 fail:
Denis Vlasenkocc571512007-02-23 21:10:35 +000013679 entry->cmdtype = CMDUNKNOWN;
13680 return;
13681
13682 builtin_success:
13683 if (!updatetbl) {
13684 entry->cmdtype = CMDBUILTIN;
13685 entry->u.cmd = bcmd;
13686 return;
13687 }
13688 INT_OFF;
13689 cmdp = cmdlookup(name, 1);
13690 cmdp->cmdtype = CMDBUILTIN;
13691 cmdp->param.cmd = bcmd;
13692 INT_ON;
13693 success:
13694 cmdp->rehash = 0;
13695 entry->cmdtype = cmdp->cmdtype;
13696 entry->u = cmdp->param;
13697}
13698
13699
Eric Andersencb57d552001-06-28 07:25:16 +000013700/*
Eric Andersencb57d552001-06-28 07:25:16 +000013701 * The trap builtin.
13702 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013703static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013704trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013705{
13706 char *action;
13707 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013708 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013709
Eric Andersenc470f442003-07-28 09:56:35 +000013710 nextopt(nullstr);
13711 ap = argptr;
13712 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013713 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013714 char *tr = trap_ptr[signo];
13715 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013716 /* note: bash adds "SIG", but only if invoked
13717 * as "bash". If called as "sh", or if set -o posix,
13718 * then it prints short signal names.
13719 * We are printing short names: */
13720 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013721 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013722 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013723 /* trap_ptr != trap only if we are in special-cased `trap` code.
13724 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013725 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013726 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013727 }
13728 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013729 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013730 if (trap_ptr != trap) {
13731 free(trap_ptr);
13732 trap_ptr = trap;
13733 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013734 */
Eric Andersencb57d552001-06-28 07:25:16 +000013735 return 0;
13736 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013737
Denys Vlasenko86981e32017-07-25 20:06:17 +020013738 /* Why the second check?
13739 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13740 * In this case, NUM is signal no, not an action.
13741 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013742 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013743 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013744 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013745
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013746 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013747 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013748 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013749 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013750 /* Mimic bash message exactly */
13751 ash_msg("%s: invalid signal specification", *ap);
13752 exitcode = 1;
13753 goto next;
13754 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013755 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013756 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013757 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013758 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013759 else {
13760 if (action[0]) /* not NULL and not "" and not "-" */
13761 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013762 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013763 }
Eric Andersencb57d552001-06-28 07:25:16 +000013764 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013765 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013766 trap[signo] = action;
13767 if (signo != 0)
13768 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013769 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013770 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013771 ap++;
13772 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013773 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013774}
13775
Eric Andersenc470f442003-07-28 09:56:35 +000013776
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013777/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013778
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013779#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013780static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013781helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013782{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013783 unsigned col;
13784 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013785
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013786 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013787 "Built-in commands:\n"
13788 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013789 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013790 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013791 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013792 if (col > 60) {
13793 out1fmt("\n");
13794 col = 0;
13795 }
13796 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013797# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013798 {
13799 const char *a = applet_names;
13800 while (*a) {
13801 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13802 if (col > 60) {
13803 out1fmt("\n");
13804 col = 0;
13805 }
Ron Yorston2b919582016-04-08 11:57:20 +010013806 while (*a++ != '\0')
13807 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013808 }
13809 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013810# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013811 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013812 return EXIT_SUCCESS;
13813}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013814#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013815
Flemming Madsend96ffda2013-04-07 18:47:24 +020013816#if MAX_HISTORY
13817static int FAST_FUNC
13818historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13819{
Ron Yorston9f3b4102019-12-16 09:31:10 +000013820 show_history(line_input_state);
Flemming Madsend96ffda2013-04-07 18:47:24 +020013821 return EXIT_SUCCESS;
13822}
13823#endif
13824
Eric Andersencb57d552001-06-28 07:25:16 +000013825/*
Eric Andersencb57d552001-06-28 07:25:16 +000013826 * The export and readonly commands.
13827 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013828static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013829exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013830{
13831 struct var *vp;
13832 char *name;
13833 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013834 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013835 char opt;
13836 int flag;
13837 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013838
Denys Vlasenkod5275882012-10-01 13:41:17 +020013839 /* "readonly" in bash accepts, but ignores -n.
13840 * We do the same: it saves a conditional in nextopt's param.
13841 */
13842 flag_off = 0;
13843 while ((opt = nextopt("np")) != '\0') {
13844 if (opt == 'n')
13845 flag_off = VEXPORT;
13846 }
13847 flag = VEXPORT;
13848 if (argv[0][0] == 'r') {
13849 flag = VREADONLY;
13850 flag_off = 0; /* readonly ignores -n */
13851 }
13852 flag_off = ~flag_off;
13853
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013854 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013855 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013856 aptr = argptr;
13857 name = *aptr;
13858 if (name) {
13859 do {
13860 p = strchr(name, '=');
13861 if (p != NULL) {
13862 p++;
13863 } else {
13864 vp = *findvar(hashvar(name), name);
13865 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013866 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013867 continue;
13868 }
Eric Andersencb57d552001-06-28 07:25:16 +000013869 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013870 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013871 } while ((name = *++aptr) != NULL);
13872 return 0;
13873 }
Eric Andersencb57d552001-06-28 07:25:16 +000013874 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013875
13876 /* No arguments. Show the list of exported or readonly vars.
13877 * -n is ignored.
13878 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013879 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013880 return 0;
13881}
13882
Eric Andersencb57d552001-06-28 07:25:16 +000013883/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013884 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013885 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013886static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013887unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013888{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013889 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013890
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013891 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013892 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013893 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013894}
13895
Eric Andersencb57d552001-06-28 07:25:16 +000013896/*
Eric Andersencb57d552001-06-28 07:25:16 +000013897 * The unset builtin command. We unset the function before we unset the
13898 * variable to allow a function to be unset when there is a readonly variable
13899 * with the same name.
13900 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013901static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013902unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013903{
13904 char **ap;
13905 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013906 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013907
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013908 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013909 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013910 }
Eric Andersencb57d552001-06-28 07:25:16 +000013911
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013912 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013913 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013914 unsetvar(*ap);
13915 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013916 }
13917 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013918 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013919 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013920 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013921}
13922
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013923static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013924 ' ', offsetof(struct tms, tms_utime),
13925 '\n', offsetof(struct tms, tms_stime),
13926 ' ', offsetof(struct tms, tms_cutime),
13927 '\n', offsetof(struct tms, tms_cstime),
13928 0
13929};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013930static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013931timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013932{
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013933 unsigned clk_tck;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013934 const unsigned char *p;
13935 struct tms buf;
13936
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013937 clk_tck = bb_clk_tck();
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013938
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013939 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013940 p = timescmd_str;
13941 do {
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013942 unsigned sec, frac;
13943 unsigned long t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013944 t = *(clock_t *)(((char *) &buf) + p[1]);
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013945 sec = t / clk_tck;
13946 frac = t % clk_tck;
13947 out1fmt("%um%u.%03us%c",
13948 sec / 60, sec % 60,
13949 (frac * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013950 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013951 p += 2;
13952 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013953
Eric Andersencb57d552001-06-28 07:25:16 +000013954 return 0;
13955}
13956
Denys Vlasenko0b883582016-12-23 16:49:07 +010013957#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013958/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013959 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013960 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013961 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013962 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013963 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013964static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013965letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013966{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013967 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013968
Denis Vlasenko68404f12008-03-17 09:00:54 +000013969 argv++;
13970 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013971 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013972 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013973 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013974 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013975
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013976 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013977}
Eric Andersenc470f442003-07-28 09:56:35 +000013978#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013979
Eric Andersenc470f442003-07-28 09:56:35 +000013980/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013981 * The read builtin. Options:
13982 * -r Do not interpret '\' specially
13983 * -s Turn off echo (tty only)
13984 * -n NCHARS Read NCHARS max
13985 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13986 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13987 * -u FD Read from given FD instead of fd 0
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013988 * -d DELIM End on DELIM char, not newline
Eric Andersenc470f442003-07-28 09:56:35 +000013989 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013990 * TODO: bash also has:
13991 * -a ARRAY Read into array[0],[1],etc
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013992 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013993 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013994static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013995readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013996{
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013997 struct builtin_read_params params;
Denys Vlasenko73067272010-01-12 22:11:24 +010013998 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013999 int i;
14000
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014001 memset(&params, 0, sizeof(params));
14002
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020014003 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000014004 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000014005 case 'p':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014006 params.opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000014007 break;
Paul Fox02eb9342005-09-07 16:56:02 +000014008 case 'n':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014009 params.opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000014010 break;
14011 case 's':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014012 params.read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000014013 break;
Paul Fox02eb9342005-09-07 16:56:02 +000014014 case 't':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014015 params.opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000014016 break;
Paul Fox02eb9342005-09-07 16:56:02 +000014017 case 'r':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014018 params.read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000014019 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000014020 case 'u':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014021 params.opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000014022 break;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020014023#if BASH_READ_D
14024 case 'd':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014025 params.opt_d = optionarg;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020014026 break;
14027#endif
Paul Fox02eb9342005-09-07 16:56:02 +000014028 default:
14029 break;
14030 }
Eric Andersenc470f442003-07-28 09:56:35 +000014031 }
Paul Fox02eb9342005-09-07 16:56:02 +000014032
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014033 params.argv = argptr;
14034 params.setvar = setvar0;
14035 params.ifs = bltinlookup("IFS"); /* can be NULL */
14036
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020014037 /* "read -s" needs to save/restore termios, can't allow ^C
14038 * to jump out of it.
14039 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020014040 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020014041 INT_OFF;
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014042 r = shell_builtin_read(&params);
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020014043 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000014044
Denys Vlasenkof5470412017-05-22 19:34:45 +020014045 if ((uintptr_t)r == 1 && errno == EINTR) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014046 /* To get SIGCHLD: sleep 1 & read x; echo $x
14047 * Correct behavior is to not exit "read"
14048 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020014049 if (pending_sig == 0)
14050 goto again;
14051 }
14052
Denys Vlasenko73067272010-01-12 22:11:24 +010014053 if ((uintptr_t)r > 1)
14054 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000014055
Denys Vlasenko73067272010-01-12 22:11:24 +010014056 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000014057}
14058
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020014059static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020014060umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000014061{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014062 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000014063
Eric Andersenc470f442003-07-28 09:56:35 +000014064 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000014065 int symbolic_mode = 0;
14066
14067 while (nextopt("S") != '\0') {
14068 symbolic_mode = 1;
14069 }
14070
Denis Vlasenkob012b102007-02-19 22:43:01 +000014071 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000014072 mask = umask(0);
14073 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000014074 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000014075
Denys Vlasenko6283f982015-10-07 16:56:20 +020014076 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000014077 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020014078 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000014079 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014080 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000014081
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014082 i = 2;
14083 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020014084 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000014085 *p++ = permuser[i];
14086 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014087 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020014088 if (!(mask & 0400)) *p++ = 'r';
14089 if (!(mask & 0200)) *p++ = 'w';
14090 if (!(mask & 0100)) *p++ = 'x';
14091 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014092 if (--i < 0)
14093 break;
Eric Andersenc470f442003-07-28 09:56:35 +000014094 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014095 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020014096 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000014097 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020014098 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000014099 }
14100 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020014101 char *modestr = *argptr;
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020014102 /* numeric umasks are taken as-is */
14103 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
Denys Vlasenko6283f982015-10-07 16:56:20 +020014104 if (!isdigit(modestr[0]))
14105 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020014106 mask = bb_parse_mode(modestr, mask);
14107 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020014108 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000014109 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020014110 if (!isdigit(modestr[0]))
14111 mask ^= 0777;
14112 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000014113 }
14114 return 0;
14115}
14116
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020014117static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010014118ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000014119{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010014120 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000014121}
14122
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014123/* ============ main() and helpers */
14124
14125/*
Denys Vlasenkof977e002020-02-20 16:54:29 +010014126 * This routine is called when an error or an interrupt occurs in an
14127 * interactive shell and control is returned to the main command loop
14128 * but prior to exitshell.
14129 */
14130static void
14131exitreset(void)
14132{
14133 /* from eval.c: */
14134 if (savestatus >= 0) {
14135 if (exception_type == EXEXIT || evalskip == SKIPFUNCDEF)
14136 exitstatus = savestatus;
14137 savestatus = -1;
14138 }
14139 evalskip = 0;
14140 loopnest = 0;
14141
14142 /* from expand.c: */
14143 ifsfree();
14144
14145 /* from redir.c: */
14146 unwindredir(NULL);
14147}
14148
14149/*
14150 * This routine is called when an error or an interrupt occurs in an
14151 * interactive shell and control is returned to the main command loop.
14152 * (In dash, this function is auto-generated by build machinery).
14153 */
14154static void
14155reset(void)
14156{
14157 /* from input.c: */
14158 g_parsefile->left_in_buffer = 0;
14159 g_parsefile->left_in_line = 0; /* clear input buffer */
14160 popallfiles();
14161
14162 /* from var.c: */
14163 unwindlocalvars(NULL);
14164}
14165
14166/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014167 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014168 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014169static void
14170exitshell(void)
14171{
14172 struct jmploc loc;
14173 char *p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014174
Denys Vlasenkobede2152011-09-04 16:12:33 +020014175#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
Denys Vlasenko897475a2019-06-01 16:35:09 +020014176 if (line_input_state)
14177 save_history(line_input_state);
Denys Vlasenkobede2152011-09-04 16:12:33 +020014178#endif
Denys Vlasenko4ccddc82020-02-14 17:27:18 +010014179 savestatus = exitstatus;
14180 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
14181 if (setjmp(loc.loc))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014182 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014183 exception_handler = &loc;
14184 p = trap[0];
14185 if (p) {
14186 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020014187 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014188 evalstring(p, 0);
Denys Vlasenkof977e002020-02-20 16:54:29 +010014189 evalskip = SKIPFUNCDEF;
Denys Vlasenkof37e1152016-10-07 03:17:28 +020014190 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014191 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014192 out:
Denys Vlasenkof977e002020-02-20 16:54:29 +010014193 exitreset();
Denys Vlasenkof37e1152016-10-07 03:17:28 +020014194 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14195 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
14196 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014197 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020014198 flush_stdout_stderr();
Denys Vlasenkof977e002020-02-20 16:54:29 +010014199 _exit(exitstatus);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014200 /* NOTREACHED */
14201}
14202
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014203/* Don't inline: conserve stack of caller from having our locals too */
14204static NOINLINE void
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000014205init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014206{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020014207 /* we will never free this */
14208 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denys Vlasenko0485b672017-08-14 19:46:56 +020014209 basepf.linno = 1;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014210
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014211 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
Denys Vlasenko458c1f22016-10-27 23:51:19 +020014212 setsignal(SIGCHLD);
14213
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014214 {
14215 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014216 const char *p;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014217
14218 initvar();
14219 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010014220/* Used to have
14221 * p = endofname(*envp);
14222 * if (p != *envp && *p == '=') {
14223 * here to weed out badly-named variables, but this breaks
14224 * scenarios where people do want them passed to children:
14225 * import os
14226 * os.environ["test-test"]="test"
14227 * if os.fork() == 0:
14228 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
14229 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
14230 */
14231 if (strchr(*envp, '=')) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014232 setvareq(*envp, VEXPORT|VTEXTFIXED);
14233 }
14234 }
14235
Denys Vlasenko67dae152018-08-05 13:59:35 +020014236 setvareq((char*)defifsvar, VTEXTFIXED);
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020014237 setvareq((char*)defoptindvar, VTEXTFIXED);
14238
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014239 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010014240#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010014241 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010014242 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010014243#endif
14244#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020014245 if (!lookupvar("HOSTNAME")) {
14246 struct utsname uts;
14247 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014248 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020014249 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010014250#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014251 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014252 if (p) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014253 struct stat st1, st2;
Denys Vlasenkoef159702016-09-01 11:16:22 +020014254 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014255 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14256 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020014257 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014258 }
14259 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014260 setpwd(p, 0);
14261 }
14262}
14263
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014264
14265//usage:#define ash_trivial_usage
Denys Vlasenkof2ed39b2018-04-05 16:46:49 +020014266//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014267//usage:#define ash_full_usage "\n\n"
14268//usage: "Unix shell interpreter"
14269
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014270/*
14271 * Process the shell command line arguments.
14272 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014273static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000014274procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014275{
14276 int i;
14277 const char *xminusc;
14278 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014279 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014280
14281 xargv = argv;
Ron Yorston8767c122018-11-05 13:13:08 +000014282 login_sh = xargv[0] && xargv[0][0] == '-';
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014283#if NUM_SCRIPTS > 0
14284 if (minusc)
14285 goto setarg0;
14286#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014287 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000014288 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014289 xargv++;
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014290 argptr = xargv;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014291 for (i = 0; i < NOPTS; i++)
14292 optlist[i] = 2;
Denys Vlasenko897475a2019-06-01 16:35:09 +020014293 if (options(&login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000014294 /* it already printed err message */
14295 raise_exception(EXERROR);
14296 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014297 xargv = argptr;
14298 xminusc = minusc;
14299 if (*xargv == NULL) {
14300 if (xminusc)
14301 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14302 sflag = 1;
14303 }
Denys Vlasenkof3634582019-06-03 12:21:04 +020014304 if (iflag == 2 /* no explicit -i given */
14305 && sflag == 1 /* -s given (or implied) */
14306 && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */
14307 && isatty(0) && isatty(1) /* we are on tty */
14308 ) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014309 iflag = 1;
Denys Vlasenkof3634582019-06-03 12:21:04 +020014310 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014311 if (mflag == 2)
14312 mflag = iflag;
14313 for (i = 0; i < NOPTS; i++)
14314 if (optlist[i] == 2)
14315 optlist[i] = 0;
14316#if DEBUG == 2
14317 debug = 1;
14318#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014319 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014320 if (xminusc) {
14321 minusc = *xargv++;
14322 if (*xargv)
14323 goto setarg0;
14324 } else if (!sflag) {
14325 setinputfile(*xargv, 0);
14326 setarg0:
14327 arg0 = *xargv++;
14328 commandname = arg0;
14329 }
14330
14331 shellparam.p = xargv;
14332#if ENABLE_ASH_GETOPTS
14333 shellparam.optind = 1;
14334 shellparam.optoff = -1;
14335#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014336 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014337 while (*xargv) {
14338 shellparam.nparam++;
14339 xargv++;
14340 }
14341 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014342
14343 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014344}
14345
14346/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014347 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014348 */
14349static void
14350read_profile(const char *name)
14351{
Denys Vlasenko46999802017-07-29 21:12:29 +020014352 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014353 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14354 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020014355 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014356 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014357}
14358
14359#if PROFILE
14360static short profile_buf[16384];
14361extern int etext();
14362#endif
14363
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014364/*
14365 * Main routine. We initialize things, parse the arguments, execute
14366 * profiles if we're a login shell, and then call cmdloop to execute
14367 * commands. The setjmp call sets up the location to jump to when an
14368 * exception occurs. When an exception occurs the variable "state"
14369 * is used to figure out how far we had gotten.
14370 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000014371int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Ron Yorston8767c122018-11-05 13:13:08 +000014372#if NUM_SCRIPTS > 0
14373int ash_main(int argc, char **argv)
14374#else
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000014375int ash_main(int argc UNUSED_PARAM, char **argv)
Ron Yorston8767c122018-11-05 13:13:08 +000014376#endif
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014377/* note: 'argc' is used only if embedded scripts are enabled */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014378{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014379 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014380 struct jmploc jmploc;
14381 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014382 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014383
Denis Vlasenko01631112007-12-16 17:20:38 +000014384 /* Initialize global data */
14385 INIT_G_misc();
14386 INIT_G_memstack();
14387 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014388#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000014389 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014390#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014391 INIT_G_cmdtable();
14392
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014393#if PROFILE
14394 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14395#endif
14396
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014397 state = 0;
14398 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014399 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014400 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014401
Denys Vlasenkoafc91fa2020-02-17 11:22:59 +010014402 exitreset();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014403
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014404 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014405 s = state;
Denys Vlasenkof977e002020-02-20 16:54:29 +010014406 if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014407 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020014408 }
Denys Vlasenkoafc91fa2020-02-17 11:22:59 +010014409
14410 reset();
14411
Denys Vlasenkob563f622010-09-25 17:15:13 +020014412 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020014413 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020014414 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014415
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014416 popstackmark(&smark);
14417 FORCE_INT_ON; /* enable interrupts */
14418 if (s == 1)
14419 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014420 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014421 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014422 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014423 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014424 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014425 }
14426 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014427 rootpid = getpid();
14428
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014429 init();
14430 setstackmark(&smark);
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014431
14432#if NUM_SCRIPTS > 0
14433 if (argc < 0)
14434 /* Non-NULL minusc tells procargs that an embedded script is being run */
14435 minusc = get_script_content(-argc - 1);
14436#endif
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014437 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010014438#if DEBUG
14439 TRACE(("Shell args: "));
14440 trace_puts_args(argv);
14441#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000014442
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014443 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014444 const char *hp;
14445
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014446 state = 1;
14447 read_profile("/etc/profile");
14448 state1:
14449 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014450 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014451 if (hp)
14452 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014453 }
14454 state2:
14455 state = 3;
14456 if (
14457#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014458 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014459#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014460 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014461 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014462 const char *shinit = lookupvar("ENV");
14463 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014464 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014465 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014466 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014467 state3:
14468 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014469 if (minusc) {
14470 /* evalstring pushes parsefile stack.
14471 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000014472 * is one of stacked source fds.
14473 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenkof3634582019-06-03 12:21:04 +020014474
Denys Vlasenko79b3d422010-06-03 04:29:08 +020014475 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020014476 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020014477 // in save_fd_on_redirect()
Denys Vlasenkof3634582019-06-03 12:21:04 +020014478
14479 // dash: evalstring(minusc, sflag ? 0 : EV_EXIT);
14480 // The above makes
14481 // ash -sc 'echo $-'
14482 // continue reading input from stdin after running 'echo'.
14483 // bash does not do this: it prints "hBcs" and exits.
14484 evalstring(minusc, EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014485 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014486
14487 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020014488#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000014489 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014490 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014491 if (!hp) {
14492 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014493 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014494 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014495 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014496 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014497 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014498 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014499 hp = lookupvar("HISTFILE");
14500 }
14501 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014502 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014503 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020014504# if ENABLE_FEATURE_SH_HISTFILESIZE
14505 hp = lookupvar("HISTFILESIZE");
14506 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14507# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014508 }
14509#endif
14510 state4: /* XXX ??? - why isn't this before the "if" statement */
Denys Vlasenko23bc5622020-02-18 16:46:01 +010014511
14512 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
14513 * Try:
14514 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
14515 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
14516 */
14517 signal(SIGHUP, SIG_DFL);
14518
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014519 cmdloop(1);
14520 }
14521#if PROFILE
14522 monitor(0);
14523#endif
14524#ifdef GPROF
14525 {
14526 extern void _mcleanup(void);
14527 _mcleanup();
14528 }
14529#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020014530 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014531 exitshell();
14532 /* NOTREACHED */
14533}
14534
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014535
Eric Andersendf82f612001-06-28 07:46:40 +000014536/*-
14537 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000014538 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000014539 *
14540 * This code is derived from software contributed to Berkeley by
14541 * Kenneth Almquist.
14542 *
14543 * Redistribution and use in source and binary forms, with or without
14544 * modification, are permitted provided that the following conditions
14545 * are met:
14546 * 1. Redistributions of source code must retain the above copyright
14547 * notice, this list of conditions and the following disclaimer.
14548 * 2. Redistributions in binary form must reproduce the above copyright
14549 * notice, this list of conditions and the following disclaimer in the
14550 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000014551 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000014552 * may be used to endorse or promote products derived from this software
14553 * without specific prior written permission.
14554 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020014555 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000014556 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14557 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14558 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14559 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14560 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14561 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14562 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14563 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14564 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14565 * SUCH DAMAGE.
14566 */