blob: e24b74c035f2a30aee7f79aa3b2103df72299a57 [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:
Denys Vlasenkod2241f52020-10-31 03:34:07 +0100210 * && and || work as they should
211 * = is glob match operator, not equality operator: STR = GLOB
Denys Vlasenkod2241f52020-10-31 03:34:07 +0100212 * == same as =
Denys Vlasenkoa7c06532020-10-31 04:32:34 +0100213 * =~ is regex match operator: STR =~ REGEX
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200214 * TODO:
215 * singleword+noglob expansion:
216 * v='a b'; [[ $v = 'a b' ]]; echo 0:$?
Denys Vlasenko89e9d552018-04-11 01:15:33 +0200217 * [[ /bin/n* ]]; echo 0:$?
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200218 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
Denys Vlasenkoa7c06532020-10-31 04:32:34 +0100219 * ( ) < > should not have special meaning (IOW: should not require quoting)
220 * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*"
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200221 */
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
Denys Vlasenko2124c0e2020-12-19 14:33:02 +0100547/* ============ Parser data */
548
549/*
550 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
551 */
552struct strlist {
553 struct strlist *next;
554 char *text;
555};
556
557struct alias;
558
559struct strpush {
560 struct strpush *prev; /* preceding string on stack */
561 char *prev_string;
562 int prev_left_in_line;
563#if ENABLE_ASH_ALIAS
564 struct alias *ap; /* if push was associated with an alias */
565#endif
566 char *string; /* remember the string since it may change */
567
568 /* Remember last two characters for pungetc. */
569 int lastc[2];
570
571 /* Number of outstanding calls to pungetc. */
572 int unget;
573};
574
575/*
576 * The parsefile structure pointed to by the global variable parsefile
577 * contains information about the current file being read.
578 */
579struct parsefile {
580 struct parsefile *prev; /* preceding file on stack */
581 int linno; /* current line */
582 int pf_fd; /* file descriptor (or -1 if string) */
583 int left_in_line; /* number of chars left in this line */
584 int left_in_buffer; /* number of chars left in this buffer past the line */
585 char *next_to_pgetc; /* next char in buffer */
586 char *buf; /* input buffer */
587 struct strpush *strpush; /* for pushing strings at this level */
588 struct strpush basestrpush; /* so pushing one is fast */
589
590 /* Remember last two characters for pungetc. */
591 int lastc[2];
592
593 /* Number of outstanding calls to pungetc. */
594 int unget;
595};
596
597static struct parsefile basepf; /* top level input file */
598static struct parsefile *g_parsefile = &basepf; /* current input file */
599static char *commandname; /* currently executing command */
600
601
Denis Vlasenko559691a2008-10-05 18:39:31 +0000602/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100603
604static void exitshell(void) NORETURN;
605
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000606/*
Eric Andersen2870d962001-07-02 17:27:21 +0000607 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000608 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000609 * much more efficient and portable. (But hacking the kernel is so much
610 * more fun than worrying about efficiency and portability. :-))
611 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100612#if DEBUG_INTONOFF
613# define INT_OFF do { \
614 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200615 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200616 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000617} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100618#else
619# define INT_OFF do { \
620 suppress_int++; \
621 barrier(); \
622} while (0)
623#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000624
625/*
626 * Called to raise an exception. Since C doesn't include exceptions, we
627 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000628 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000629 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000630static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000631static void
632raise_exception(int e)
633{
634#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000635 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000636 abort();
637#endif
638 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000639 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000640 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000641}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000642#if DEBUG
643#define raise_exception(e) do { \
644 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
645 raise_exception(e); \
646} while (0)
647#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000648
649/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200650 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000651 * that SIGINT is to be trapped or ignored using the trap builtin, then
652 * this routine is not called.) Suppressint is nonzero when interrupts
653 * are held using the INT_OFF macro. (The test for iflag is just
654 * defensive programming.)
655 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000656static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000657static void
658raise_interrupt(void)
659{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200660 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000661 /* Signal is not automatically unmasked after it is raised,
662 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000663 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200664 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000665
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200666 if (!(rootshell && iflag)) {
667 /* Kill ourself with SIGINT */
668 signal(SIGINT, SIG_DFL);
669 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000670 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200671 /* bash: ^C even on empty command line sets $? */
672 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200673 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000674 /* NOTREACHED */
675}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000676#if DEBUG
677#define raise_interrupt() do { \
678 TRACE(("raising interrupt on line %d\n", __LINE__)); \
679 raise_interrupt(); \
680} while (0)
681#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000682
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000683static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000684int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000685{
Denys Vlasenkode892052016-10-02 01:49:13 +0200686 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200687 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000688 raise_interrupt();
689 }
690}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100691#if DEBUG_INTONOFF
692# define INT_ON do { \
693 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
694 int_on(); \
695} while (0)
696#else
697# define INT_ON int_on()
698#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000699static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000700force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000701{
Denys Vlasenkode892052016-10-02 01:49:13 +0200702 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200703 suppress_int = 0;
704 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000705 raise_interrupt();
706}
707#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000708
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200709#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000710
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000711#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200712 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200713 suppress_int = (v); \
714 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000715 raise_interrupt(); \
716} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000717
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000718
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000719/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000720
Eric Andersenc470f442003-07-28 09:56:35 +0000721static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000722outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000723{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000724 INT_OFF;
725 fputs(p, file);
726 INT_ON;
727}
728
729static void
730flush_stdout_stderr(void)
731{
732 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100733 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000734 INT_ON;
735}
736
Denys Vlasenko9c541002015-10-07 15:44:36 +0200737/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000738static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200739newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000740{
741 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200742 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000743 fflush(dest);
744 INT_ON;
745}
746
747static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
748static int
749out1fmt(const char *fmt, ...)
750{
751 va_list ap;
752 int r;
753
754 INT_OFF;
755 va_start(ap, fmt);
756 r = vprintf(fmt, ap);
757 va_end(ap);
758 INT_ON;
759 return r;
760}
761
762static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
763static int
764fmtstr(char *outbuf, size_t length, const char *fmt, ...)
765{
766 va_list ap;
767 int ret;
768
Denis Vlasenkob012b102007-02-19 22:43:01 +0000769 INT_OFF;
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200770 va_start(ap, fmt);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000771 ret = vsnprintf(outbuf, length, fmt, ap);
772 va_end(ap);
773 INT_ON;
Denys Vlasenko3f7fb2c2020-02-16 18:06:20 +0100774 return ret > (int)length ? length : ret;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000775}
776
777static void
778out1str(const char *p)
779{
780 outstr(p, stdout);
781}
782
783static void
784out2str(const char *p)
785{
786 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100787 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000788}
789
790
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000791/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000792
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000793/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100794#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200795#define CTLESC ((unsigned char)'\201') /* escape next character */
796#define CTLVAR ((unsigned char)'\202') /* variable defn */
797#define CTLENDVAR ((unsigned char)'\203')
798#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200799#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
800#define CTLENDARI ((unsigned char)'\207')
801#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100802#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000803
804/* variable substitution byte (follows CTLVAR) */
805#define VSTYPE 0x0f /* type of variable substitution */
806#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000807
808/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000809#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
810#define VSMINUS 0x2 /* ${var-text} */
811#define VSPLUS 0x3 /* ${var+text} */
812#define VSQUESTION 0x4 /* ${var?message} */
813#define VSASSIGN 0x5 /* ${var=text} */
814#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
815#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
816#define VSTRIMLEFT 0x8 /* ${var#pattern} */
817#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
818#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100819#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000820#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100821#endif
822#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000823#define VSREPLACE 0xd /* ${var/pattern/replacement} */
824#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
825#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000826
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000827static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200828 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000829};
Ron Yorston549deab2015-05-18 09:57:51 +0200830#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000831
Denis Vlasenko559691a2008-10-05 18:39:31 +0000832#define NCMD 0
833#define NPIPE 1
834#define NREDIR 2
835#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000836#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000837#define NAND 5
838#define NOR 6
839#define NSEMI 7
840#define NIF 8
841#define NWHILE 9
842#define NUNTIL 10
843#define NFOR 11
844#define NCASE 12
845#define NCLIST 13
846#define NDEFUN 14
847#define NARG 15
848#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100849#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000850#define NTO2 17
851#endif
852#define NCLOBBER 18
853#define NFROM 19
854#define NFROMTO 20
855#define NAPPEND 21
856#define NTOFD 22
857#define NFROMFD 23
858#define NHERE 24
859#define NXHERE 25
860#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000861#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000862
863union node;
864
865struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000866 smallint type; /* Nxxxx */
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100867 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000868 union node *assign;
869 union node *args;
870 union node *redirect;
871};
872
873struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000874 smallint type;
875 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000876 struct nodelist *cmdlist;
877};
878
879struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000880 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100881 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000882 union node *n;
883 union node *redirect;
884};
885
886struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000887 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000888 union node *ch1;
889 union node *ch2;
890};
891
892struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000893 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000894 union node *test;
895 union node *ifpart;
896 union node *elsepart;
897};
898
899struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000900 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100901 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000902 union node *args;
903 union node *body;
904 char *var;
905};
906
907struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000908 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100909 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000910 union node *expr;
911 union node *cases;
912};
913
914struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000915 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000916 union node *next;
917 union node *pattern;
918 union node *body;
919};
920
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100921struct ndefun {
922 smallint type;
923 int linno;
924 char *text;
925 union node *body;
926};
927
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000928struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000929 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000930 union node *next;
931 char *text;
932 struct nodelist *backquote;
933};
934
Denis Vlasenko559691a2008-10-05 18:39:31 +0000935/* nfile and ndup layout must match!
936 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
937 * that it is actually NTO2 (>&file), and change its type.
938 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000939struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000940 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000941 union node *next;
942 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000943 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000944 union node *fname;
945 char *expfname;
946};
947
948struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000949 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000950 union node *next;
951 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000952 int dupfd;
953 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000954 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000955};
956
957struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000958 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000959 union node *next;
960 int fd;
961 union node *doc;
962};
963
964struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000965 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000966 union node *com;
967};
968
969union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000970 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000971 struct ncmd ncmd;
972 struct npipe npipe;
973 struct nredir nredir;
974 struct nbinary nbinary;
975 struct nif nif;
976 struct nfor nfor;
977 struct ncase ncase;
978 struct nclist nclist;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100979 struct ndefun ndefun;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000980 struct narg narg;
981 struct nfile nfile;
982 struct ndup ndup;
983 struct nhere nhere;
984 struct nnot nnot;
985};
986
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200987/*
988 * NODE_EOF is returned by parsecmd when it encounters an end of file.
989 * It must be distinct from NULL.
990 */
991#define NODE_EOF ((union node *) -1L)
992
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000993struct nodelist {
994 struct nodelist *next;
995 union node *n;
996};
997
998struct funcnode {
999 int count;
1000 union node n;
1001};
1002
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001003/*
1004 * Free a parse tree.
1005 */
1006static void
1007freefunc(struct funcnode *f)
1008{
1009 if (f && --f->count < 0)
1010 free(f);
1011}
1012
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001013
1014/* ============ Debugging output */
1015
1016#if DEBUG
1017
1018static FILE *tracefile;
1019
1020static void
1021trace_printf(const char *fmt, ...)
1022{
1023 va_list va;
1024
1025 if (debug != 1)
1026 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00001027 if (DEBUG_TIME)
1028 fprintf(tracefile, "%u ", (int) time(NULL));
1029 if (DEBUG_PID)
1030 fprintf(tracefile, "[%u] ", (int) getpid());
1031 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001032 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001033 va_start(va, fmt);
1034 vfprintf(tracefile, fmt, va);
1035 va_end(va);
1036}
1037
1038static void
1039trace_vprintf(const char *fmt, va_list va)
1040{
1041 if (debug != 1)
1042 return;
1043 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +01001044 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001045}
1046
1047static void
1048trace_puts(const char *s)
1049{
1050 if (debug != 1)
1051 return;
1052 fputs(s, tracefile);
1053}
1054
1055static void
1056trace_puts_quoted(char *s)
1057{
1058 char *p;
1059 char c;
1060
1061 if (debug != 1)
1062 return;
1063 putc('"', tracefile);
1064 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001065 switch ((unsigned char)*p) {
1066 case '\n': c = 'n'; goto backslash;
1067 case '\t': c = 't'; goto backslash;
1068 case '\r': c = 'r'; goto backslash;
1069 case '\"': c = '\"'; goto backslash;
1070 case '\\': c = '\\'; goto backslash;
1071 case CTLESC: c = 'e'; goto backslash;
1072 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001073 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001074 backslash:
1075 putc('\\', tracefile);
1076 putc(c, tracefile);
1077 break;
1078 default:
1079 if (*p >= ' ' && *p <= '~')
1080 putc(*p, tracefile);
1081 else {
1082 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +01001083 putc((*p >> 6) & 03, tracefile);
1084 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001085 putc(*p & 07, tracefile);
1086 }
1087 break;
1088 }
1089 }
1090 putc('"', tracefile);
1091}
1092
1093static void
1094trace_puts_args(char **ap)
1095{
1096 if (debug != 1)
1097 return;
1098 if (!*ap)
1099 return;
1100 while (1) {
1101 trace_puts_quoted(*ap);
1102 if (!*++ap) {
1103 putc('\n', tracefile);
1104 break;
1105 }
1106 putc(' ', tracefile);
1107 }
1108}
1109
1110static void
1111opentrace(void)
1112{
1113 char s[100];
1114#ifdef O_APPEND
1115 int flags;
1116#endif
1117
1118 if (debug != 1) {
1119 if (tracefile)
1120 fflush(tracefile);
1121 /* leave open because libedit might be using it */
1122 return;
1123 }
1124 strcpy(s, "./trace");
1125 if (tracefile) {
1126 if (!freopen(s, "a", tracefile)) {
1127 fprintf(stderr, "Can't re-open %s\n", s);
1128 debug = 0;
1129 return;
1130 }
1131 } else {
1132 tracefile = fopen(s, "a");
1133 if (tracefile == NULL) {
1134 fprintf(stderr, "Can't open %s\n", s);
1135 debug = 0;
1136 return;
1137 }
1138 }
1139#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +00001140 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001141 if (flags >= 0)
1142 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1143#endif
1144 setlinebuf(tracefile);
1145 fputs("\nTracing started.\n", tracefile);
1146}
1147
1148static void
1149indent(int amount, char *pfx, FILE *fp)
1150{
1151 int i;
1152
1153 for (i = 0; i < amount; i++) {
1154 if (pfx && i == amount - 1)
1155 fputs(pfx, fp);
1156 putc('\t', fp);
1157 }
1158}
1159
1160/* little circular references here... */
1161static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1162
1163static void
1164sharg(union node *arg, FILE *fp)
1165{
1166 char *p;
1167 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001168 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001169
1170 if (arg->type != NARG) {
1171 out1fmt("<node type %d>\n", arg->type);
1172 abort();
1173 }
1174 bqlist = arg->narg.backquote;
1175 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001176 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001177 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001178 p++;
1179 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001180 break;
1181 case CTLVAR:
1182 putc('$', fp);
1183 putc('{', fp);
1184 subtype = *++p;
1185 if (subtype == VSLENGTH)
1186 putc('#', fp);
1187
Dan Fandrich77d48722010-09-07 23:38:28 -07001188 while (*p != '=') {
1189 putc(*p, fp);
1190 p++;
1191 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001192
1193 if (subtype & VSNUL)
1194 putc(':', fp);
1195
1196 switch (subtype & VSTYPE) {
1197 case VSNORMAL:
1198 putc('}', fp);
1199 break;
1200 case VSMINUS:
1201 putc('-', fp);
1202 break;
1203 case VSPLUS:
1204 putc('+', fp);
1205 break;
1206 case VSQUESTION:
1207 putc('?', fp);
1208 break;
1209 case VSASSIGN:
1210 putc('=', fp);
1211 break;
1212 case VSTRIMLEFT:
1213 putc('#', fp);
1214 break;
1215 case VSTRIMLEFTMAX:
1216 putc('#', fp);
1217 putc('#', fp);
1218 break;
1219 case VSTRIMRIGHT:
1220 putc('%', fp);
1221 break;
1222 case VSTRIMRIGHTMAX:
1223 putc('%', fp);
1224 putc('%', fp);
1225 break;
1226 case VSLENGTH:
1227 break;
1228 default:
1229 out1fmt("<subtype %d>", subtype);
1230 }
1231 break;
1232 case CTLENDVAR:
1233 putc('}', fp);
1234 break;
1235 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001236 putc('$', fp);
1237 putc('(', fp);
1238 shtree(bqlist->n, -1, NULL, fp);
1239 putc(')', fp);
1240 break;
1241 default:
1242 putc(*p, fp);
1243 break;
1244 }
1245 }
1246}
1247
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001248static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001249shcmd(union node *cmd, FILE *fp)
1250{
1251 union node *np;
1252 int first;
1253 const char *s;
1254 int dftfd;
1255
1256 first = 1;
1257 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001258 if (!first)
1259 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001260 sharg(np, fp);
1261 first = 0;
1262 }
1263 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001264 if (!first)
1265 putc(' ', fp);
1266 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001267 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001268 case NTO: s = ">>"+1; dftfd = 1; break;
1269 case NCLOBBER: s = ">|"; dftfd = 1; break;
1270 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001271#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001272 case NTO2:
1273#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001274 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001275 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001276 case NFROMFD: s = "<&"; break;
1277 case NFROMTO: s = "<>"; break;
1278 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001279 }
1280 if (np->nfile.fd != dftfd)
1281 fprintf(fp, "%d", np->nfile.fd);
1282 fputs(s, fp);
1283 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1284 fprintf(fp, "%d", np->ndup.dupfd);
1285 } else {
1286 sharg(np->nfile.fname, fp);
1287 }
1288 first = 0;
1289 }
1290}
1291
1292static void
1293shtree(union node *n, int ind, char *pfx, FILE *fp)
1294{
1295 struct nodelist *lp;
1296 const char *s;
1297
1298 if (n == NULL)
1299 return;
1300
1301 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001302
1303 if (n == NODE_EOF) {
1304 fputs("<EOF>", fp);
1305 return;
1306 }
1307
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001308 switch (n->type) {
1309 case NSEMI:
1310 s = "; ";
1311 goto binop;
1312 case NAND:
1313 s = " && ";
1314 goto binop;
1315 case NOR:
1316 s = " || ";
1317 binop:
1318 shtree(n->nbinary.ch1, ind, NULL, fp);
1319 /* if (ind < 0) */
1320 fputs(s, fp);
1321 shtree(n->nbinary.ch2, ind, NULL, fp);
1322 break;
1323 case NCMD:
1324 shcmd(n, fp);
1325 if (ind >= 0)
1326 putc('\n', fp);
1327 break;
1328 case NPIPE:
1329 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001330 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001331 if (lp->next)
1332 fputs(" | ", fp);
1333 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001334 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001335 fputs(" &", fp);
1336 if (ind >= 0)
1337 putc('\n', fp);
1338 break;
1339 default:
1340 fprintf(fp, "<node type %d>", n->type);
1341 if (ind >= 0)
1342 putc('\n', fp);
1343 break;
1344 }
1345}
1346
1347static void
1348showtree(union node *n)
1349{
1350 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001351 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001352}
1353
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001354#endif /* DEBUG */
1355
1356
Denis Vlasenkob012b102007-02-19 22:43:01 +00001357/* ============ 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;
Denys Vlasenko965b7952020-11-30 13:03:03 +01002094} varinit_data[] ALIGN_PTR = {
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 }
Denys Vlasenko93e2a222020-12-23 12:23:21 +01004611 retval |= 128;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004612 }
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))
Denys Vlasenko93e2a222020-12-23 12:23:21 +01004677 retval = 128 | WTERMSIG(status);
Denys Vlasenko966f0872019-03-27 15:51:42 +01004678 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:
Denys Vlasenko93e2a222020-12-23 12:23:21 +01004712 retval = 128 | pending_sig;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004713 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{
Denys Vlasenko965b7952020-11-30 13:03:03 +01004814 static const char vstype[VSTYPE + 1][3] ALIGN1 = {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004815 "", "}", "-", "+", "?", "=",
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);
Cristian Ionescu-Idbohrnddfdf682020-11-18 10:41:14 +01007280#if BASH_PATTERN_SUBST
Denys Vlasenko82331882020-02-24 10:02:50 +01007281 out1:
Cristian Ionescu-Idbohrnddfdf682020-11-18 10:41:14 +01007282#endif
Denys Vlasenko82331882020-02-24 10:02:50 +01007283 /* Remove any recorded regions beyond start of variable */
7284 removerecordregions(startloc);
7285
7286 return p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007287}
7288
7289/*
7290 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007291 * name parameter (examples):
7292 * ash -c 'echo $1' name:'1='
7293 * ash -c 'echo $qwe' name:'qwe='
7294 * ash -c 'echo $$' name:'$='
7295 * ash -c 'echo ${$}' name:'$='
7296 * ash -c 'echo ${$##q}' name:'$=q'
7297 * ash -c 'echo ${#$}' name:'$='
7298 * note: examples with bad shell syntax:
7299 * ash -c 'echo ${#$1}' name:'$=1'
7300 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007301 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02007302static NOINLINE ssize_t
Denys Vlasenko440da972018-08-05 14:29:58 +02007303varvalue(char *name, int varflags, int flags, int quoted)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007304{
Mike Frysinger98c52642009-04-02 10:02:37 +00007305 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007306 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007307 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007308 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007309 int sep;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007310 int subtype = varflags & VSTYPE;
Denys Vlasenko82331882020-02-24 10:02:50 +01007311 int discard = (subtype == VSPLUS || subtype == VSLENGTH) | (flags & EXP_DISCARD);
7312
7313 if (!subtype) {
7314 if (discard)
7315 return -1;
7316
7317 raise_error_syntax("bad substitution");
7318 }
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007319
Denys Vlasenkoecc85832020-02-20 10:06:20 +01007320 flags |= EXP_KEEPNUL;
7321 flags &= discard ? ~QUOTES_ESC : ~0;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007322 sep = (flags & EXP_FULL) << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007323
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007324 switch (*name) {
7325 case '$':
7326 num = rootpid;
7327 goto numvar;
7328 case '?':
7329 num = exitstatus;
7330 goto numvar;
7331 case '#':
7332 num = shellparam.nparam;
7333 goto numvar;
7334 case '!':
7335 num = backgndpid;
7336 if (num == 0)
7337 return -1;
7338 numvar:
Denys Vlasenko45dd87a2020-02-21 16:30:44 +01007339 len = cvtnum(num, flags);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007340 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007341 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007342 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007343 for (i = NOPTS - 1; i >= 0; i--) {
Martijn Dekkerad4e9612018-03-31 18:15:59 +02007344 if (optlist[i] && optletters(i)) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007345 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007346 len++;
7347 }
7348 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007349 check_1char_name:
7350#if 0
7351 /* handles cases similar to ${#$1} */
7352 if (name[2] != '\0')
7353 raise_error_syntax("bad substitution");
7354#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007355 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007356 case '@':
7357 if (quoted && sep)
7358 goto param;
7359 /* fall through */
7360 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007361 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007362 char sepc;
Denys Vlasenko440da972018-08-05 14:29:58 +02007363 char c;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007364
Denys Vlasenko440da972018-08-05 14:29:58 +02007365 /* We will set c to 0 or ~0 depending on whether
7366 * we're doing field splitting. We won't do field
7367 * splitting if either we're quoted or sep is zero.
7368 *
7369 * Instead of testing (quoted || !sep) the following
7370 * trick optimises away any branches by using the
7371 * fact that EXP_QUOTED (which is the only bit that
7372 * can be set in quoted) is the same as EXP_FULL <<
7373 * CHAR_BIT (which is the only bit that can be set
7374 * in sep).
7375 */
7376#if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7377#error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7378#endif
7379 c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7380 sep &= ~quoted;
7381 sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007382 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007383 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007384 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007385 if (!ap)
7386 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007387 while ((p = *ap++) != NULL) {
Denys Vlasenkoecc85832020-02-20 10:06:20 +01007388 len += strtodest(p, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007389
7390 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007391 len++;
Denys Vlasenkoecc85832020-02-20 10:06:20 +01007392 memtodest(&sepc, 1, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007393 }
7394 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007395 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007396 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007397 case '0':
7398 case '1':
7399 case '2':
7400 case '3':
7401 case '4':
7402 case '5':
7403 case '6':
7404 case '7':
7405 case '8':
7406 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007407 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007408 if (num < 0 || num > shellparam.nparam)
7409 return -1;
7410 p = num ? shellparam.p[num - 1] : arg0;
7411 goto value;
7412 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007413 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007414 p = lookupvar(name);
7415 value:
7416 if (!p)
7417 return -1;
7418
Denys Vlasenkoecc85832020-02-20 10:06:20 +01007419 len = strtodest(p, flags);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007420#if ENABLE_UNICODE_SUPPORT
7421 if (subtype == VSLENGTH && len > 0) {
7422 reinit_unicode_for_ash();
7423 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007424 STADJUST(-len, expdest);
7425 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007426 len = unicode_strlen(p);
7427 }
7428 }
7429#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007430 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007431 }
7432
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007433 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007434 STADJUST(-len, expdest);
Denys Vlasenko82331882020-02-24 10:02:50 +01007435
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007436 return len;
7437}
7438
7439/*
7440 * Expand a variable, and return a pointer to the next character in the
7441 * input string.
7442 */
7443static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007444evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007445{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007446 char varflags;
7447 char subtype;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007448 char *var;
7449 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007450 int startloc;
7451 ssize_t varlen;
Denys Vlasenko15558952020-02-22 19:38:40 +01007452 int discard;
Denys Vlasenko82331882020-02-24 10:02:50 +01007453 int quoted;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007454
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007455 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007456 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007457
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007458 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007459 var = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007460 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007461 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007462
7463 again:
Denys Vlasenko440da972018-08-05 14:29:58 +02007464 varlen = varvalue(var, varflags, flag, quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007465 if (varflags & VSNUL)
7466 varlen--;
7467
Denys Vlasenko15558952020-02-22 19:38:40 +01007468 discard = varlen < 0 ? EXP_DISCARD : 0;
7469
Denys Vlasenko82331882020-02-24 10:02:50 +01007470 switch (subtype) {
7471 case VSPLUS:
Denys Vlasenko15558952020-02-22 19:38:40 +01007472 discard ^= EXP_DISCARD;
Denys Vlasenko82331882020-02-24 10:02:50 +01007473 /* fall through */
7474 case 0:
7475 case VSMINUS:
Denys Vlasenko15558952020-02-22 19:38:40 +01007476 p = argstr(p, flag | EXP_TILDE | EXP_WORD | (discard ^ EXP_DISCARD));
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007477 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007478
Denys Vlasenko82331882020-02-24 10:02:50 +01007479 case VSASSIGN:
7480 case VSQUESTION:
Denys Vlasenko15558952020-02-22 19:38:40 +01007481 p = subevalvar(p, var, 0, startloc, varflags,
7482 (flag & ~QUOTES_ESC) | (discard ^ EXP_DISCARD));
7483
7484 if ((flag | ~discard) & EXP_DISCARD)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007485 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007486
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007487 varflags &= ~VSNUL;
Denys Vlasenko15558952020-02-22 19:38:40 +01007488 subtype = VSNORMAL;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007489 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007490 }
7491
Denys Vlasenko15558952020-02-22 19:38:40 +01007492 if ((discard & ~flag) && uflag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007493 varunset(p, var, 0, 0);
7494
7495 if (subtype == VSLENGTH) {
Denys Vlasenko82331882020-02-24 10:02:50 +01007496 p++;
7497 if (flag & EXP_DISCARD)
7498 return p;
Denys Vlasenko45dd87a2020-02-21 16:30:44 +01007499 cvtnum(varlen > 0 ? varlen : 0, flag);
Denys Vlasenko15558952020-02-22 19:38:40 +01007500 goto really_record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007501 }
7502
Denys Vlasenko82331882020-02-24 10:02:50 +01007503 if (subtype == VSNORMAL)
7504 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007505
7506#if DEBUG
7507 switch (subtype) {
7508 case VSTRIMLEFT:
7509 case VSTRIMLEFTMAX:
7510 case VSTRIMRIGHT:
7511 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007512#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007513 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007514#endif
7515#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007516 case VSREPLACE:
7517 case VSREPLACEALL:
7518#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007519 break;
7520 default:
7521 abort();
7522 }
7523#endif
7524
Denys Vlasenko15558952020-02-22 19:38:40 +01007525 flag |= discard;
Denys Vlasenko82331882020-02-24 10:02:50 +01007526 if (!(flag & EXP_DISCARD)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007527 /*
7528 * Terminate the string and start recording the pattern
7529 * right after it
7530 */
7531 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007532 }
7533
Denys Vlasenko82331882020-02-24 10:02:50 +01007534 patloc = expdest - (char *)stackblock();
7535 p = subevalvar(p, NULL, patloc, startloc, varflags, flag);
Denys Vlasenko4ace3852020-02-16 18:42:50 +01007536
Denys Vlasenko82331882020-02-24 10:02:50 +01007537 record:
Denys Vlasenko15558952020-02-22 19:38:40 +01007538 if ((flag | discard) & EXP_DISCARD)
Denys Vlasenko82331882020-02-24 10:02:50 +01007539 return p;
7540
Denys Vlasenko15558952020-02-22 19:38:40 +01007541 really_record:
Denys Vlasenko82331882020-02-24 10:02:50 +01007542 if (quoted) {
7543 quoted = *var == '@' && shellparam.nparam;
7544 if (!quoted)
7545 return p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007546 }
Denys Vlasenko82331882020-02-24 10:02:50 +01007547 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007548 return p;
7549}
7550
7551/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007552 * Add a file name to the list.
7553 */
7554static void
7555addfname(const char *name)
7556{
7557 struct strlist *sp;
7558
Denis Vlasenko597906c2008-02-20 16:38:54 +00007559 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007560 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007561 *exparg.lastp = sp;
7562 exparg.lastp = &sp->next;
7563}
7564
Felix Fietkaub5b21122017-01-31 21:58:55 +01007565/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7566static int
7567hasmeta(const char *p)
7568{
7569 static const char chars[] ALIGN1 = {
7570 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7571 };
7572
7573 for (;;) {
7574 p = strpbrk(p, chars);
7575 if (!p)
7576 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007577 switch ((unsigned char)*p) {
Felix Fietkaub5b21122017-01-31 21:58:55 +01007578 case CTLQUOTEMARK:
7579 for (;;) {
7580 p++;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007581 if ((unsigned char)*p == CTLQUOTEMARK)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007582 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007583 if ((unsigned char)*p == CTLESC)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007584 p++;
7585 if (*p == '\0') /* huh? */
7586 return 0;
7587 }
7588 break;
7589 case '\\':
7590 case CTLESC:
7591 p++;
7592 if (*p == '\0')
7593 return 0;
7594 break;
7595 case '[':
7596 if (!strchr(p + 1, ']')) {
7597 /* It's not a properly closed [] pattern,
7598 * but other metas may follow. Continue checking.
7599 * my[file* _is_ globbed by bash
7600 * and matches filenames like "my[file1".
7601 */
7602 break;
7603 }
7604 /* fallthrough */
7605 default:
7606 /* case '*': */
7607 /* case '?': */
7608 return 1;
7609 }
7610 p++;
7611 }
7612
7613 return 0;
7614}
7615
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007616/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007617#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007618
7619/* Add the result of glob() to the list */
7620static void
7621addglob(const glob_t *pglob)
7622{
7623 char **p = pglob->gl_pathv;
7624
7625 do {
7626 addfname(*p);
7627 } while (*++p);
7628}
7629static void
7630expandmeta(struct strlist *str /*, int flag*/)
7631{
7632 /* TODO - EXP_REDIR */
7633
7634 while (str) {
7635 char *p;
7636 glob_t pglob;
7637 int i;
7638
7639 if (fflag)
7640 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007641
Felix Fietkaub5b21122017-01-31 21:58:55 +01007642 if (!hasmeta(str->text))
7643 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007644
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007645 INT_OFF;
7646 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007647// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7648// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7649//
7650// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7651// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7652// Which means you need to unescape the string, right? Not so fast:
7653// if there _is_ a file named "file\?" (with backslash), it is returned
7654// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007655// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007656//
7657// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7658// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7659// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7660// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7661// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7662// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7663 i = glob(p, 0, NULL, &pglob);
7664 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007665 if (p != str->text)
7666 free(p);
7667 switch (i) {
7668 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007669#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007670 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7671 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7672 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007673#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007674 addglob(&pglob);
7675 globfree(&pglob);
7676 INT_ON;
7677 break;
7678 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007679 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007680 globfree(&pglob);
7681 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007682 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007683 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007684 rmescapes(str->text, 0, NULL);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007685 exparg.lastp = &str->next;
7686 break;
7687 default: /* GLOB_NOSPACE */
7688 globfree(&pglob);
7689 INT_ON;
7690 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7691 }
7692 str = str->next;
7693 }
7694}
7695
7696#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007697/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007698
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007699/*
7700 * Do metacharacter (i.e. *, ?, [...]) expansion.
7701 */
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007702typedef struct exp_t {
7703 char *dir;
7704 unsigned dir_max;
7705} exp_t;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007706static void
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007707expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007708{
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007709#define expdir exp->dir
7710#define expdir_max exp->dir_max
7711 char *enddir = expdir + expdir_len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007712 char *p;
7713 const char *cp;
7714 char *start;
7715 char *endname;
7716 int metaflag;
7717 struct stat statb;
7718 DIR *dirp;
7719 struct dirent *dp;
7720 int atend;
7721 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007722 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007723
7724 metaflag = 0;
7725 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007726 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007727 if (*p == '*' || *p == '?')
7728 metaflag = 1;
7729 else if (*p == '[') {
7730 char *q = p + 1;
7731 if (*q == '!')
7732 q++;
7733 for (;;) {
7734 if (*q == '\\')
7735 q++;
7736 if (*q == '/' || *q == '\0')
7737 break;
7738 if (*++q == ']') {
7739 metaflag = 1;
7740 break;
7741 }
7742 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007743 } else {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007744 if (*p == '\\' && p[1])
Ron Yorstonca25af92015-09-04 10:32:41 +01007745 esc++;
7746 if (p[esc] == '/') {
7747 if (metaflag)
7748 break;
7749 start = p + esc + 1;
7750 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007751 }
7752 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007753 if (metaflag == 0) { /* we've reached the end of the file name */
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007754 if (!expdir_len)
7755 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007756 p = name;
7757 do {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007758 if (*p == '\\' && p[1])
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007759 p++;
7760 *enddir++ = *p;
7761 } while (*p++);
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007762 if (lstat(expdir, &statb) == 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007763 addfname(expdir);
7764 return;
7765 }
7766 endname = p;
7767 if (name < start) {
7768 p = name;
7769 do {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007770 if (*p == '\\' && p[1])
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007771 p++;
7772 *enddir++ = *p++;
7773 } while (p < start);
7774 }
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007775 *enddir = '\0';
7776 cp = expdir;
7777 expdir_len = enddir - cp;
7778 if (!expdir_len)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007779 cp = ".";
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007780 dirp = opendir(cp);
7781 if (dirp == NULL)
7782 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007783 if (*endname == 0) {
7784 atend = 1;
7785 } else {
7786 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007787 *endname = '\0';
7788 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007789 }
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007790 name_len -= endname - name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007791 matchdot = 0;
7792 p = start;
7793 if (*p == '\\')
7794 p++;
7795 if (*p == '.')
7796 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007797 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007798 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007799 continue;
7800 if (pmatch(start, dp->d_name)) {
7801 if (atend) {
7802 strcpy(enddir, dp->d_name);
7803 addfname(expdir);
7804 } else {
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007805 unsigned offset;
7806 unsigned len;
7807
7808 p = stpcpy(enddir, dp->d_name);
7809 *p = '/';
7810
7811 offset = p - expdir + 1;
7812 len = offset + name_len + NAME_MAX;
7813 if (len > expdir_max) {
7814 len += PATH_MAX;
7815 expdir = ckrealloc(expdir, len);
7816 expdir_max = len;
7817 }
7818
7819 expmeta(exp, endname, name_len, offset);
7820 enddir = expdir + expdir_len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007821 }
7822 }
7823 }
7824 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007825 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007826 endname[-esc - 1] = esc ? '\\' : '/';
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007827#undef expdir
7828#undef expdir_max
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007829}
7830
7831static struct strlist *
7832msort(struct strlist *list, int len)
7833{
7834 struct strlist *p, *q = NULL;
7835 struct strlist **lpp;
7836 int half;
7837 int n;
7838
7839 if (len <= 1)
7840 return list;
7841 half = len >> 1;
7842 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007843 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007844 q = p;
7845 p = p->next;
7846 }
7847 q->next = NULL; /* terminate first half of list */
7848 q = msort(list, half); /* sort first half of list */
7849 p = msort(p, len - half); /* sort second half */
7850 lpp = &list;
7851 for (;;) {
7852#if ENABLE_LOCALE_SUPPORT
7853 if (strcoll(p->text, q->text) < 0)
7854#else
7855 if (strcmp(p->text, q->text) < 0)
7856#endif
7857 {
7858 *lpp = p;
7859 lpp = &p->next;
7860 p = *lpp;
7861 if (p == NULL) {
7862 *lpp = q;
7863 break;
7864 }
7865 } else {
7866 *lpp = q;
7867 lpp = &q->next;
7868 q = *lpp;
7869 if (q == NULL) {
7870 *lpp = p;
7871 break;
7872 }
7873 }
7874 }
7875 return list;
7876}
7877
7878/*
7879 * Sort the results of file name expansion. It calculates the number of
7880 * strings to sort and then calls msort (short for merge sort) to do the
7881 * work.
7882 */
7883static struct strlist *
7884expsort(struct strlist *str)
7885{
7886 int len;
7887 struct strlist *sp;
7888
7889 len = 0;
7890 for (sp = str; sp; sp = sp->next)
7891 len++;
7892 return msort(str, len);
7893}
7894
7895static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007896expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007897{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007898 /* TODO - EXP_REDIR */
7899
7900 while (str) {
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007901 exp_t exp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007902 struct strlist **savelastp;
7903 struct strlist *sp;
7904 char *p;
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007905 unsigned len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007906
7907 if (fflag)
7908 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007909 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007910 goto nometa;
7911 savelastp = exparg.lastp;
7912
7913 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007914 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007915 len = strlen(p);
7916 exp.dir_max = len + PATH_MAX;
7917 exp.dir = ckmalloc(exp.dir_max);
7918
7919 expmeta(&exp, p, len, 0);
7920 free(exp.dir);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007921 if (p != str->text)
7922 free(p);
7923 INT_ON;
7924 if (exparg.lastp == savelastp) {
7925 /*
7926 * no matches
7927 */
7928 nometa:
7929 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007930 rmescapes(str->text, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007931 exparg.lastp = &str->next;
7932 } else {
7933 *exparg.lastp = NULL;
7934 *savelastp = sp = expsort(*savelastp);
7935 while (sp->next != NULL)
7936 sp = sp->next;
7937 exparg.lastp = &sp->next;
7938 }
7939 str = str->next;
7940 }
7941}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007942#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007943
7944/*
7945 * Perform variable substitution and command substitution on an argument,
7946 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7947 * perform splitting and file name expansion. When arglist is NULL, perform
7948 * here document expansion.
7949 */
7950static void
7951expandarg(union node *arg, struct arglist *arglist, int flag)
7952{
7953 struct strlist *sp;
7954 char *p;
7955
7956 argbackq = arg->narg.backquote;
7957 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007958 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007959 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007960 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007961 /* here document expanded */
7962 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007963 }
Denys Vlasenko82331882020-02-24 10:02:50 +01007964 p = grabstackstr(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007965 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007966 exparg.lastp = &exparg.list;
7967 /*
7968 * TODO - EXP_REDIR
7969 */
7970 if (flag & EXP_FULL) {
7971 ifsbreakup(p, &exparg);
7972 *exparg.lastp = NULL;
7973 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007974 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007975 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007976 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007977 sp->text = p;
7978 *exparg.lastp = sp;
7979 exparg.lastp = &sp->next;
7980 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007981 *exparg.lastp = NULL;
7982 if (exparg.list) {
7983 *arglist->lastp = exparg.list;
7984 arglist->lastp = exparg.lastp;
7985 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007986
7987 out:
7988 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007989}
7990
7991/*
7992 * Expand shell variables and backquotes inside a here document.
7993 */
7994static void
Denys Vlasenkoc2058ec2020-02-22 20:25:03 +01007995expandhere(union node *arg)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007996{
Ron Yorston549deab2015-05-18 09:57:51 +02007997 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007998}
7999
8000/*
8001 * Returns true if the pattern matches the string.
8002 */
8003static int
8004patmatch(char *pattern, const char *string)
8005{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02008006 char *p = preglob(pattern, 0);
Denys Vlasenko4476c702017-08-15 15:27:41 +02008007 int r = pmatch(p, string);
8008 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
8009 return r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008010}
8011
8012/*
8013 * See if a pattern matches in a case statement.
8014 */
8015static int
8016casematch(union node *pattern, char *val)
8017{
8018 struct stackmark smark;
8019 int result;
8020
8021 setstackmark(&smark);
8022 argbackq = pattern->narg.backquote;
8023 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02008024 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02008025 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008026 result = patmatch(stackblock(), val);
8027 popstackmark(&smark);
8028 return result;
8029}
8030
8031
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008032/* ============ find_command */
8033
8034struct builtincmd {
8035 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008036 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008037 /* unsigned flags; */
8038};
8039#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00008040/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008041 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008042#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008043#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008044
8045struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008046 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008047 union param {
8048 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008049 /* index >= 0 for commands without path (slashes) */
8050 /* (TODO: what exactly does the value mean? PATH position?) */
8051 /* index == -1 for commands with slashes */
8052 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008053 const struct builtincmd *cmd;
8054 struct funcnode *func;
8055 } u;
8056};
8057/* values of cmdtype */
8058#define CMDUNKNOWN -1 /* no entry in table for command */
8059#define CMDNORMAL 0 /* command is an executable program */
8060#define CMDFUNCTION 1 /* command is a shell function */
8061#define CMDBUILTIN 2 /* command is a shell builtin */
8062
8063/* action to find_command() */
8064#define DO_ERR 0x01 /* prints errors */
8065#define DO_ABS 0x02 /* checks absolute paths */
8066#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
8067#define DO_ALTPATH 0x08 /* using alternate path */
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008068#define DO_REGBLTIN 0x10 /* regular built-ins and functions only */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008069
8070static void find_command(char *, struct cmdentry *, int, const char *);
8071
8072
8073/* ============ Hashing commands */
8074
8075/*
8076 * When commands are first encountered, they are entered in a hash table.
8077 * This ensures that a full path search will not have to be done for them
8078 * on each invocation.
8079 *
8080 * We should investigate converting to a linear search, even though that
8081 * would make the command name "hash" a misnomer.
8082 */
8083
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008084struct tblentry {
8085 struct tblentry *next; /* next entry in hash chain */
8086 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008087 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008088 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008089 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008090};
8091
Denis Vlasenko01631112007-12-16 17:20:38 +00008092static struct tblentry **cmdtable;
8093#define INIT_G_cmdtable() do { \
8094 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
8095} while (0)
8096
8097static int builtinloc = -1; /* index in path of %builtin, or -1 */
8098
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008099
8100static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008101tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008102{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008103#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00008104 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00008105 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02008106 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00008107 while (*envp)
8108 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02008109 popredir(/*drop:*/ 1);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02008110 run_noexec_applet_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00008111 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00008112 /* re-exec ourselves with the new arguments */
8113 execve(bb_busybox_exec_path, argv, envp);
8114 /* If they called chroot or otherwise made the binary no longer
8115 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008116 }
8117#endif
8118
8119 repeat:
8120#ifdef SYSV
8121 do {
8122 execve(cmd, argv, envp);
8123 } while (errno == EINTR);
8124#else
8125 execve(cmd, argv, envp);
8126#endif
Ron Yorstonca82b532018-11-01 11:45:03 +01008127
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008128 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01008129 /* Run "cmd" as a shell script:
8130 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8131 * "If the execve() function fails with ENOEXEC, the shell
8132 * shall execute a command equivalent to having a shell invoked
8133 * with the command name as its first operand,
8134 * with any remaining arguments passed to the new shell"
8135 *
8136 * That is, do not use $SHELL, user's shell, or /bin/sh;
8137 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01008138 *
8139 * Note that bash reads ~80 chars of the file, and if it sees
8140 * a zero byte before it sees newline, it doesn't try to
8141 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01008142 * message and exit code 126. For one, this prevents attempts
8143 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01008144 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008145 argv[0] = (char*) cmd;
8146 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008147 /* NB: this is only possible because all callers of shellexec()
8148 * ensure that the argv[-1] slot exists!
8149 */
8150 argv--;
8151 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008152 goto repeat;
8153 }
8154}
8155
8156/*
8157 * Exec a program. Never returns. If you change this routine, you may
8158 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008159 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008160 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008161static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8162static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008163{
8164 char *cmdname;
8165 int e;
8166 char **envp;
8167 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008168 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008169
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01008170 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008171 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008172#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008173 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008174#endif
8175 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008176 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008177 if (applet_no >= 0) {
8178 /* We tried execing ourself, but it didn't work.
8179 * Maybe /proc/self/exe doesn't exist?
8180 * Try $PATH search.
8181 */
8182 goto try_PATH;
8183 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008184 e = errno;
8185 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008186 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008187 e = ENOENT;
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01008188 while (padvance(&path, argv[0]) >= 0) {
8189 cmdname = stackblock();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008190 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00008191 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008192 if (errno != ENOENT && errno != ENOTDIR)
8193 e = errno;
8194 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008195 }
8196 }
8197
8198 /* Map to POSIX errors */
8199 switch (e) {
Denys Vlasenko2596f412018-08-05 18:04:09 +02008200 default:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008201 exerrno = 126;
8202 break;
Denys Vlasenko2596f412018-08-05 18:04:09 +02008203 case ELOOP:
8204 case ENAMETOOLONG:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008205 case ENOENT:
Denys Vlasenko2596f412018-08-05 18:04:09 +02008206 case ENOTDIR:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008207 exerrno = 127;
8208 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008209 }
8210 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008211 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008212 prog, e, suppress_int));
Denys Vlasenkof977e002020-02-20 16:54:29 +01008213 ash_msg_and_raise(EXEND, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008214 /* NOTREACHED */
8215}
8216
8217static void
8218printentry(struct tblentry *cmdp)
8219{
8220 int idx;
8221 const char *path;
8222 char *name;
8223
8224 idx = cmdp->param.index;
8225 path = pathval();
8226 do {
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01008227 padvance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008228 } while (--idx >= 0);
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01008229 name = stackblock();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008230 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8231}
8232
8233/*
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008234 * Clear out command entries.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008235 */
8236static void
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008237clearcmdentry(void)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008238{
8239 struct tblentry **tblp;
8240 struct tblentry **pp;
8241 struct tblentry *cmdp;
8242
8243 INT_OFF;
8244 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8245 pp = tblp;
8246 while ((cmdp = *pp) != NULL) {
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008247 if (cmdp->cmdtype == CMDNORMAL
Denys Vlasenko22c75922020-02-17 16:20:05 +01008248 || (cmdp->cmdtype == CMDBUILTIN
8249 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8250 && builtinloc > 0
8251 )
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008252 ) {
8253 *pp = cmdp->next;
8254 free(cmdp);
8255 } else {
8256 pp = &cmdp->next;
8257 }
8258 }
8259 }
8260 INT_ON;
8261}
8262
8263/*
8264 * Locate a command in the command hash table. If "add" is nonzero,
8265 * add the command to the table if it is not already present. The
8266 * variable "lastcmdentry" is set to point to the address of the link
8267 * pointing to the entry, so that delete_cmd_entry can delete the
8268 * entry.
8269 *
8270 * Interrupts must be off if called with add != 0.
8271 */
8272static struct tblentry **lastcmdentry;
8273
8274static struct tblentry *
8275cmdlookup(const char *name, int add)
8276{
8277 unsigned int hashval;
8278 const char *p;
8279 struct tblentry *cmdp;
8280 struct tblentry **pp;
8281
8282 p = name;
8283 hashval = (unsigned char)*p << 4;
8284 while (*p)
8285 hashval += (unsigned char)*p++;
8286 hashval &= 0x7FFF;
8287 pp = &cmdtable[hashval % CMDTABLESIZE];
8288 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8289 if (strcmp(cmdp->cmdname, name) == 0)
8290 break;
8291 pp = &cmdp->next;
8292 }
8293 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008294 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8295 + strlen(name)
8296 /* + 1 - already done because
8297 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00008298 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008299 cmdp->cmdtype = CMDUNKNOWN;
8300 strcpy(cmdp->cmdname, name);
8301 }
8302 lastcmdentry = pp;
8303 return cmdp;
8304}
8305
8306/*
8307 * Delete the command entry returned on the last lookup.
8308 */
8309static void
8310delete_cmd_entry(void)
8311{
8312 struct tblentry *cmdp;
8313
8314 INT_OFF;
8315 cmdp = *lastcmdentry;
8316 *lastcmdentry = cmdp->next;
8317 if (cmdp->cmdtype == CMDFUNCTION)
8318 freefunc(cmdp->param.func);
8319 free(cmdp);
8320 INT_ON;
8321}
8322
8323/*
8324 * Add a new command entry, replacing any existing command entry for
8325 * the same name - except special builtins.
8326 */
8327static void
8328addcmdentry(char *name, struct cmdentry *entry)
8329{
8330 struct tblentry *cmdp;
8331
8332 cmdp = cmdlookup(name, 1);
8333 if (cmdp->cmdtype == CMDFUNCTION) {
8334 freefunc(cmdp->param.func);
8335 }
8336 cmdp->cmdtype = entry->cmdtype;
8337 cmdp->param = entry->u;
8338 cmdp->rehash = 0;
8339}
8340
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008341static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008342hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008343{
8344 struct tblentry **pp;
8345 struct tblentry *cmdp;
8346 int c;
8347 struct cmdentry entry;
8348 char *name;
8349
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008350 if (nextopt("r") != '\0') {
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008351 clearcmdentry();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008352 return 0;
8353 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008354
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008355 if (*argptr == NULL) {
8356 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8357 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8358 if (cmdp->cmdtype == CMDNORMAL)
8359 printentry(cmdp);
8360 }
8361 }
8362 return 0;
8363 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008364
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008365 c = 0;
8366 while ((name = *argptr) != NULL) {
8367 cmdp = cmdlookup(name, 0);
8368 if (cmdp != NULL
8369 && (cmdp->cmdtype == CMDNORMAL
Denys Vlasenko22c75922020-02-17 16:20:05 +01008370 || (cmdp->cmdtype == CMDBUILTIN
8371 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8372 && builtinloc > 0
8373 )
8374 )
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008375 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008376 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008377 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008378 find_command(name, &entry, DO_ERR, pathval());
8379 if (entry.cmdtype == CMDUNKNOWN)
8380 c = 1;
8381 argptr++;
8382 }
8383 return c;
8384}
8385
8386/*
8387 * Called when a cd is done. Marks all commands so the next time they
8388 * are executed they will be rehashed.
8389 */
8390static void
8391hashcd(void)
8392{
8393 struct tblentry **pp;
8394 struct tblentry *cmdp;
8395
8396 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8397 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008398 if (cmdp->cmdtype == CMDNORMAL
8399 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008400 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008401 && builtinloc > 0)
8402 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008403 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008404 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008405 }
8406 }
8407}
8408
8409/*
8410 * Fix command hash table when PATH changed.
8411 * Called before PATH is changed. The argument is the new value of PATH;
8412 * pathval() still returns the old value at this point.
8413 * Called with interrupts off.
8414 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008415static void FAST_FUNC
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008416changepath(const char *newval)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008417{
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008418 const char *new;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008419 int idx;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008420 int bltin;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008421
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008422 new = newval;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008423 idx = 0;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008424 bltin = -1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008425 for (;;) {
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008426 if (*new == '%' && prefix(new + 1, "builtin")) {
8427 bltin = idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008428 break;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008429 }
8430 new = strchr(new, ':');
8431 if (!new)
8432 break;
8433 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008434 new++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008435 }
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +01008436 builtinloc = bltin;
8437 clearcmdentry();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008438}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008439enum {
8440 TEOF,
8441 TNL,
8442 TREDIR,
8443 TWORD,
8444 TSEMI,
8445 TBACKGND,
8446 TAND,
8447 TOR,
8448 TPIPE,
8449 TLP,
8450 TRP,
8451 TENDCASE,
8452 TENDBQUOTE,
8453 TNOT,
8454 TCASE,
8455 TDO,
8456 TDONE,
8457 TELIF,
8458 TELSE,
8459 TESAC,
8460 TFI,
8461 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008462#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008463 TFUNCTION,
8464#endif
8465 TIF,
8466 TIN,
8467 TTHEN,
8468 TUNTIL,
8469 TWHILE,
8470 TBEGIN,
8471 TEND
8472};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008473typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008474
Denys Vlasenko888527c2016-10-02 16:54:17 +02008475/* Nth bit indicates if token marks the end of a list */
8476enum {
8477 tokendlist = 0
8478 /* 0 */ | (1u << TEOF)
8479 /* 1 */ | (0u << TNL)
8480 /* 2 */ | (0u << TREDIR)
8481 /* 3 */ | (0u << TWORD)
8482 /* 4 */ | (0u << TSEMI)
8483 /* 5 */ | (0u << TBACKGND)
8484 /* 6 */ | (0u << TAND)
8485 /* 7 */ | (0u << TOR)
8486 /* 8 */ | (0u << TPIPE)
8487 /* 9 */ | (0u << TLP)
8488 /* 10 */ | (1u << TRP)
8489 /* 11 */ | (1u << TENDCASE)
8490 /* 12 */ | (1u << TENDBQUOTE)
8491 /* 13 */ | (0u << TNOT)
8492 /* 14 */ | (0u << TCASE)
8493 /* 15 */ | (1u << TDO)
8494 /* 16 */ | (1u << TDONE)
8495 /* 17 */ | (1u << TELIF)
8496 /* 18 */ | (1u << TELSE)
8497 /* 19 */ | (1u << TESAC)
8498 /* 20 */ | (1u << TFI)
8499 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008500#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008501 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008502#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008503 /* 23 */ | (0u << TIF)
8504 /* 24 */ | (0u << TIN)
8505 /* 25 */ | (1u << TTHEN)
8506 /* 26 */ | (0u << TUNTIL)
8507 /* 27 */ | (0u << TWHILE)
8508 /* 28 */ | (0u << TBEGIN)
8509 /* 29 */ | (1u << TEND)
8510 , /* thus far 29 bits used */
8511};
8512
Denys Vlasenko965b7952020-11-30 13:03:03 +01008513static const char *const tokname_array[] ALIGN_PTR = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008514 "end of file",
8515 "newline",
8516 "redirection",
8517 "word",
8518 ";",
8519 "&",
8520 "&&",
8521 "||",
8522 "|",
8523 "(",
8524 ")",
8525 ";;",
8526 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008527#define KWDOFFSET 13
8528 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008529 "!",
8530 "case",
8531 "do",
8532 "done",
8533 "elif",
8534 "else",
8535 "esac",
8536 "fi",
8537 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008538#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008539 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008540#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008541 "if",
8542 "in",
8543 "then",
8544 "until",
8545 "while",
8546 "{",
8547 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008548};
8549
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008550/* Wrapper around strcmp for qsort/bsearch/... */
8551static int
8552pstrcmp(const void *a, const void *b)
8553{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008554 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008555}
8556
8557static const char *const *
8558findkwd(const char *s)
8559{
8560 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008561 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8562 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008563}
8564
8565/*
8566 * Locate and print what a word is...
8567 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008568static int
Ron Yorston3f221112015-08-03 13:47:33 +01008569describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008570{
8571 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008572#if ENABLE_ASH_ALIAS
8573 const struct alias *ap;
8574#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008575
8576 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008577
8578 if (describe_command_verbose) {
8579 out1str(command);
8580 }
8581
8582 /* First look at the keywords */
8583 if (findkwd(command)) {
8584 out1str(describe_command_verbose ? " is a shell keyword" : command);
8585 goto out;
8586 }
8587
8588#if ENABLE_ASH_ALIAS
8589 /* Then look at the aliases */
8590 ap = lookupalias(command, 0);
8591 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008592 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008593 out1str("alias ");
8594 printalias(ap);
8595 return 0;
8596 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008597 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008598 goto out;
8599 }
8600#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008601 /* Brute force */
8602 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008603
8604 switch (entry.cmdtype) {
8605 case CMDNORMAL: {
8606 int j = entry.u.index;
8607 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008608 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008609 p = command;
8610 } else {
8611 do {
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01008612 padvance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008613 } while (--j >= 0);
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +01008614 p = stackblock();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008615 }
8616 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008617 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008618 } else {
8619 out1str(p);
8620 }
8621 break;
8622 }
8623
8624 case CMDFUNCTION:
8625 if (describe_command_verbose) {
Denys Vlasenko63c42af2018-07-24 17:08:04 +02008626 /*out1str(" is a shell function");*/
8627 out1str(" is a function"); /* bash says this */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008628 } else {
8629 out1str(command);
8630 }
8631 break;
8632
8633 case CMDBUILTIN:
8634 if (describe_command_verbose) {
8635 out1fmt(" is a %sshell builtin",
8636 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8637 "special " : nullstr
8638 );
8639 } else {
8640 out1str(command);
8641 }
8642 break;
8643
8644 default:
8645 if (describe_command_verbose) {
8646 out1str(": not found\n");
8647 }
8648 return 127;
8649 }
8650 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008651 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008652 return 0;
8653}
8654
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008655static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008656typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008657{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008658 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008659 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008660 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008661
Denis Vlasenko46846e22007-05-20 13:08:31 +00008662 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008663 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008664 i++;
8665 verbose = 0;
8666 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008667 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008668 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008669 }
8670 return err;
8671}
8672
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008673static struct strlist *
8674fill_arglist(struct arglist *arglist, union node **argpp)
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008675{
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008676 struct strlist **lastp = arglist->lastp;
8677 union node *argp;
8678
8679 while ((argp = *argpp) != NULL) {
8680 expandarg(argp, arglist, EXP_FULL | EXP_TILDE);
8681 *argpp = argp->narg.next;
8682 if (*lastp)
8683 break;
8684 }
8685
8686 return *lastp;
8687}
8688
Ron Yorstonda7a6db2020-02-27 09:50:18 +00008689#if ENABLE_ASH_CMDCMD
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008690/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8691static int
8692parse_command_args(struct arglist *arglist, union node **argpp, const char **path)
8693{
8694 struct strlist *sp = arglist->list;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008695 char *cp, c;
8696
8697 for (;;) {
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008698 sp = sp->next ? sp->next : fill_arglist(arglist, argpp);
8699 if (!sp)
8700 return 0;
8701 cp = sp->text;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008702 if (*cp++ != '-')
8703 break;
8704 c = *cp++;
8705 if (!c)
8706 break;
8707 if (c == '-' && !*cp) {
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008708 if (!sp->next && !fill_arglist(arglist, argpp))
8709 return 0;
8710 sp = sp->next;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008711 break;
8712 }
8713 do {
8714 switch (c) {
8715 case 'p':
8716 *path = bb_default_path;
8717 break;
8718 default:
8719 /* run 'typecmd' for other options */
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008720 return 0;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008721 }
8722 c = *cp++;
8723 } while (c);
8724 }
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +01008725
8726 arglist->list = sp;
8727 return DO_NOFUNC;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008728}
8729
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008730static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008731commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008732{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008733 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008734 int c;
8735 enum {
8736 VERIFY_BRIEF = 1,
8737 VERIFY_VERBOSE = 2,
8738 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008739 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008740
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008741 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8742 * never reaches this function.
8743 */
8744
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008745 while ((c = nextopt("pvV")) != '\0')
8746 if (c == 'V')
8747 verify |= VERIFY_VERBOSE;
8748 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008749 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008750#if DEBUG
8751 else if (c != 'p')
8752 abort();
8753#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008754 else
8755 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008756
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008757 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008758 cmd = *argptr;
8759 if (/*verify && */ cmd)
8760 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008761
8762 return 0;
8763}
8764#endif
8765
8766
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008767/*static int funcblocksize; // size of structures in function */
8768/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008769static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008770static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008771
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008772static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008773 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8774 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8775 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8776 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8777 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8778 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8779 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8780 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8781 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8782 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8783 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8784 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8785 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8786 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8787 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8788 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8789 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008790#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008791 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008792#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008793 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8794 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8795 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8796 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8797 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8798 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8799 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8800 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8801 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008802};
8803
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008804static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008805
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008806static int
8807sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008808{
8809 while (lp) {
8810 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008811 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008812 lp = lp->next;
8813 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008814 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008815}
8816
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008817static int
8818calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008819{
8820 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008821 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008822 funcblocksize += nodesize[n->type];
8823 switch (n->type) {
8824 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008825 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8826 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8827 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008828 break;
8829 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008830 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008831 break;
8832 case NREDIR:
8833 case NBACKGND:
8834 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008835 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8836 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008837 break;
8838 case NAND:
8839 case NOR:
8840 case NSEMI:
8841 case NWHILE:
8842 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008843 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8844 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008845 break;
8846 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008847 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8848 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8849 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008850 break;
8851 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008852 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008853 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8854 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008855 break;
8856 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008857 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8858 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008859 break;
8860 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008861 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8862 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8863 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008864 break;
8865 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008866 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8867 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8868 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008869 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008870 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008871 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008872 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008873 break;
8874 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008875#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008876 case NTO2:
8877#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008878 case NCLOBBER:
8879 case NFROM:
8880 case NFROMTO:
8881 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008882 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8883 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008884 break;
8885 case NTOFD:
8886 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008887 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8888 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008889 break;
8890 case NHERE:
8891 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008892 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8893 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008894 break;
8895 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008896 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008897 break;
8898 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008899 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008900}
8901
8902static char *
8903nodeckstrdup(char *s)
8904{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008905 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008906 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008907}
8908
8909static union node *copynode(union node *);
8910
8911static struct nodelist *
8912copynodelist(struct nodelist *lp)
8913{
8914 struct nodelist *start;
8915 struct nodelist **lpp;
8916
8917 lpp = &start;
8918 while (lp) {
8919 *lpp = funcblock;
8920 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8921 (*lpp)->n = copynode(lp->n);
8922 lp = lp->next;
8923 lpp = &(*lpp)->next;
8924 }
8925 *lpp = NULL;
8926 return start;
8927}
8928
8929static union node *
8930copynode(union node *n)
8931{
8932 union node *new;
8933
8934 if (n == NULL)
8935 return NULL;
8936 new = funcblock;
8937 funcblock = (char *) funcblock + nodesize[n->type];
8938
8939 switch (n->type) {
8940 case NCMD:
8941 new->ncmd.redirect = copynode(n->ncmd.redirect);
8942 new->ncmd.args = copynode(n->ncmd.args);
8943 new->ncmd.assign = copynode(n->ncmd.assign);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008944 new->ncmd.linno = n->ncmd.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008945 break;
8946 case NPIPE:
8947 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008948 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008949 break;
8950 case NREDIR:
8951 case NBACKGND:
8952 case NSUBSHELL:
8953 new->nredir.redirect = copynode(n->nredir.redirect);
8954 new->nredir.n = copynode(n->nredir.n);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008955 new->nredir.linno = n->nredir.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008956 break;
8957 case NAND:
8958 case NOR:
8959 case NSEMI:
8960 case NWHILE:
8961 case NUNTIL:
8962 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8963 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8964 break;
8965 case NIF:
8966 new->nif.elsepart = copynode(n->nif.elsepart);
8967 new->nif.ifpart = copynode(n->nif.ifpart);
8968 new->nif.test = copynode(n->nif.test);
8969 break;
8970 case NFOR:
8971 new->nfor.var = nodeckstrdup(n->nfor.var);
8972 new->nfor.body = copynode(n->nfor.body);
8973 new->nfor.args = copynode(n->nfor.args);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008974 new->nfor.linno = n->nfor.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008975 break;
8976 case NCASE:
8977 new->ncase.cases = copynode(n->ncase.cases);
8978 new->ncase.expr = copynode(n->ncase.expr);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008979 new->ncase.linno = n->ncase.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008980 break;
8981 case NCLIST:
8982 new->nclist.body = copynode(n->nclist.body);
8983 new->nclist.pattern = copynode(n->nclist.pattern);
8984 new->nclist.next = copynode(n->nclist.next);
8985 break;
8986 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008987 new->ndefun.body = copynode(n->ndefun.body);
8988 new->ndefun.text = nodeckstrdup(n->ndefun.text);
8989 new->ndefun.linno = n->ndefun.linno;
8990 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008991 case NARG:
8992 new->narg.backquote = copynodelist(n->narg.backquote);
8993 new->narg.text = nodeckstrdup(n->narg.text);
8994 new->narg.next = copynode(n->narg.next);
8995 break;
8996 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008997#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008998 case NTO2:
8999#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009000 case NCLOBBER:
9001 case NFROM:
9002 case NFROMTO:
9003 case NAPPEND:
9004 new->nfile.fname = copynode(n->nfile.fname);
9005 new->nfile.fd = n->nfile.fd;
9006 new->nfile.next = copynode(n->nfile.next);
9007 break;
9008 case NTOFD:
9009 case NFROMFD:
9010 new->ndup.vname = copynode(n->ndup.vname);
9011 new->ndup.dupfd = n->ndup.dupfd;
9012 new->ndup.fd = n->ndup.fd;
9013 new->ndup.next = copynode(n->ndup.next);
9014 break;
9015 case NHERE:
9016 case NXHERE:
9017 new->nhere.doc = copynode(n->nhere.doc);
9018 new->nhere.fd = n->nhere.fd;
9019 new->nhere.next = copynode(n->nhere.next);
9020 break;
9021 case NNOT:
9022 new->nnot.com = copynode(n->nnot.com);
9023 break;
9024 };
9025 new->type = n->type;
9026 return new;
9027}
9028
9029/*
9030 * Make a copy of a parse tree.
9031 */
9032static struct funcnode *
9033copyfunc(union node *n)
9034{
9035 struct funcnode *f;
9036 size_t blocksize;
9037
Denys Vlasenko4c438b52016-10-07 04:05:15 +02009038 /*funcstringsize = 0;*/
9039 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
9040 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009041 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02009042 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009043 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02009044 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009045 return f;
9046}
9047
9048/*
9049 * Define a shell function.
9050 */
9051static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009052defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009053{
9054 struct cmdentry entry;
9055
9056 INT_OFF;
9057 entry.cmdtype = CMDFUNCTION;
9058 entry.u.func = copyfunc(func);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009059 addcmdentry(func->ndefun.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009060 INT_ON;
9061}
9062
Denis Vlasenko4b875702009-03-19 13:30:04 +00009063/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009064#define SKIPBREAK (1 << 0)
9065#define SKIPCONT (1 << 1)
9066#define SKIPFUNC (1 << 2)
Denys Vlasenkocd24a502020-02-20 16:47:01 +01009067#define SKIPFUNCDEF (1 << 3)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009068static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009069static int skipcount; /* number of levels to skip */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00009070static int loopnest; /* current loop nesting level */
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009071static int funcline; /* starting line number of current function, or 0 if not in a function */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009072
Denis Vlasenko4b875702009-03-19 13:30:04 +00009073/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009074static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009075
Denis Vlasenko4b875702009-03-19 13:30:04 +00009076/* Called to execute a trap.
9077 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02009078 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00009079 *
9080 * Perhaps we should avoid entering new trap handlers
9081 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009082 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009083static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009084dotrap(void)
9085{
Denis Vlasenko4b875702009-03-19 13:30:04 +00009086 uint8_t *g;
9087 int sig;
Denys Vlasenko4ccddc82020-02-14 17:27:18 +01009088 int status, last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009089
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009090 if (!pending_sig)
9091 return;
9092
Denys Vlasenko4ccddc82020-02-14 17:27:18 +01009093 status = savestatus;
9094 last_status = status;
9095 if (status < 0) {
9096 status = exitstatus;
9097 savestatus = status;
9098 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009099 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02009100 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009101
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009102 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00009103 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009104 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009105
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009106 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009107 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009108
9109 if (evalskip) {
9110 pending_sig = sig;
9111 break;
9112 }
9113
9114 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00009115 /* non-trapped SIGINT is handled separately by raise_interrupt,
9116 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009117 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009118 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009119
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009120 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00009121 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009122 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009123 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009124 evalstring(p, 0);
Denys Vlasenkocd24a502020-02-20 16:47:01 +01009125 if (evalskip != SKIPFUNC)
9126 exitstatus = status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009127 }
Denys Vlasenko4ccddc82020-02-14 17:27:18 +01009128
9129 savestatus = last_status;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009130 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009131}
9132
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00009133/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009134static int evalloop(union node *, int);
9135static int evalfor(union node *, int);
9136static int evalcase(union node *, int);
9137static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009138static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009139static int evalpipe(union node *, int);
9140static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009141static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009142static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009143
Eric Andersen62483552001-07-10 06:09:16 +00009144/*
Eric Andersenc470f442003-07-28 09:56:35 +00009145 * Evaluate a parse tree. The value is left in the global variable
9146 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00009147 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009148static int
Eric Andersenc470f442003-07-28 09:56:35 +00009149evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00009150{
Eric Andersenc470f442003-07-28 09:56:35 +00009151 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009152 int (*evalfn)(union node *, int);
Ron Yorstonf55161a2019-02-25 08:29:38 +00009153 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009154 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009155
Ron Yorstonf55161a2019-02-25 08:29:38 +00009156 setstackmark(&smark);
9157
Eric Andersenc470f442003-07-28 09:56:35 +00009158 if (n == NULL) {
9159 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009160 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00009161 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009162 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009163
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009164 dotrap();
9165
Eric Andersenc470f442003-07-28 09:56:35 +00009166 switch (n->type) {
9167 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009168#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00009169 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009170 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00009171 break;
9172#endif
9173 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009174 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009175 goto setstatus;
9176 case NREDIR:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009177 errlinno = lineno = n->nredir.linno;
9178 if (funcline)
9179 lineno -= funcline - 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009180 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009181 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00009182 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9183 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009184 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009185 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009186 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02009187 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00009188 goto setstatus;
9189 case NCMD:
9190 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009191 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00009192 if (eflag && !(flags & EV_TESTED))
9193 checkexit = ~0;
9194 goto calleval;
9195 case NFOR:
9196 evalfn = evalfor;
9197 goto calleval;
9198 case NWHILE:
9199 case NUNTIL:
9200 evalfn = evalloop;
9201 goto calleval;
9202 case NSUBSHELL:
9203 case NBACKGND:
9204 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02009205 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00009206 case NPIPE:
9207 evalfn = evalpipe;
9208 goto checkexit;
9209 case NCASE:
9210 evalfn = evalcase;
9211 goto calleval;
9212 case NAND:
9213 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009214 case NSEMI: {
9215
Eric Andersenc470f442003-07-28 09:56:35 +00009216#if NAND + 1 != NOR
9217#error NAND + 1 != NOR
9218#endif
9219#if NOR + 1 != NSEMI
9220#error NOR + 1 != NSEMI
9221#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00009222 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009223 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00009224 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009225 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00009226 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02009227 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00009228 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009229 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009230 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009231 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009232 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009233 status = evalfn(n, flags);
9234 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009235 }
Eric Andersenc470f442003-07-28 09:56:35 +00009236 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009237 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009238 if (evalskip)
9239 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009240 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00009241 n = n->nif.ifpart;
9242 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009243 }
9244 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00009245 n = n->nif.elsepart;
9246 goto evaln;
9247 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009248 status = 0;
9249 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009250 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009251 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009252 /* Not necessary. To test it:
9253 * "false; f() { qwerty; }; echo $?" should print 0.
9254 */
9255 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009256 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00009257 exitstatus = status;
9258 break;
9259 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009260 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02009261 /* Order of checks below is important:
9262 * signal handlers trigger before exit caused by "set -e".
9263 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009264 dotrap();
9265
9266 if (checkexit & status)
Denys Vlasenkof977e002020-02-20 16:54:29 +01009267 raise_exception(EXEND);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009268 if (flags & EV_EXIT)
Denys Vlasenkof977e002020-02-20 16:54:29 +01009269 raise_exception(EXEND);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009270
Ron Yorstonf55161a2019-02-25 08:29:38 +00009271 popstackmark(&smark);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009272 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009273 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00009274}
9275
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02009276static int
9277skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009278{
9279 int skip = evalskip;
9280
9281 switch (skip) {
9282 case 0:
9283 break;
9284 case SKIPBREAK:
9285 case SKIPCONT:
9286 if (--skipcount <= 0) {
9287 evalskip = 0;
9288 break;
9289 }
9290 skip = SKIPBREAK;
9291 break;
9292 }
9293 return skip;
9294}
9295
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009296static int
Eric Andersenc470f442003-07-28 09:56:35 +00009297evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009298{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009299 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00009300 int status;
9301
9302 loopnest++;
9303 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009304 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009305 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009306 int i;
9307
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009308 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009309 skip = skiploop();
9310 if (skip == SKIPFUNC)
9311 status = i;
9312 if (skip)
9313 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00009314 if (n->type != NWHILE)
9315 i = !i;
9316 if (i != 0)
9317 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009318 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009319 skip = skiploop();
9320 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009321 loopnest--;
9322
9323 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009324}
9325
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009326static int
Eric Andersenc470f442003-07-28 09:56:35 +00009327evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009328{
9329 struct arglist arglist;
9330 union node *argp;
9331 struct strlist *sp;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009332 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009333
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009334 errlinno = lineno = n->ncase.linno;
9335 if (funcline)
9336 lineno -= funcline - 1;
9337
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009338 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009339 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009340 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02009341 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00009342 }
9343 *arglist.lastp = NULL;
9344
Eric Andersencb57d552001-06-28 07:25:16 +00009345 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009346 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009347 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009348 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009349 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009350 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00009351 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009352 }
9353 loopnest--;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009354
9355 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009356}
9357
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009358static int
Eric Andersenc470f442003-07-28 09:56:35 +00009359evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009360{
9361 union node *cp;
9362 union node *patp;
9363 struct arglist arglist;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009364 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009365
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009366 errlinno = lineno = n->ncase.linno;
9367 if (funcline)
9368 lineno -= funcline - 1;
9369
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009370 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009371 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009372 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009373 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9374 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009375 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009376 /* Ensure body is non-empty as otherwise
9377 * EV_EXIT may prevent us from setting the
9378 * exit status.
9379 */
9380 if (evalskip == 0 && cp->nclist.body) {
9381 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009382 }
9383 goto out;
9384 }
9385 }
9386 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009387 out:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009388 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009389}
9390
Eric Andersenc470f442003-07-28 09:56:35 +00009391/*
9392 * Kick off a subshell to evaluate a tree.
9393 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009394static int
Eric Andersenc470f442003-07-28 09:56:35 +00009395evalsubshell(union node *n, int flags)
9396{
9397 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009398 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009399 int status;
9400
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009401 errlinno = lineno = n->nredir.linno;
9402 if (funcline)
9403 lineno -= funcline - 1;
9404
Eric Andersenc470f442003-07-28 09:56:35 +00009405 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009406 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009407 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009408 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009409 if (backgnd == FORK_FG)
9410 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009411 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009412 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009413 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009414 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009415 flags |= EV_EXIT;
9416 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009417 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009418 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009419 redirect(n->nredir.redirect, 0);
9420 evaltreenr(n->nredir.n, flags);
9421 /* never returns */
9422 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009423 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009424 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009425 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009426 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009427 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009428 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009429}
9430
Eric Andersenc470f442003-07-28 09:56:35 +00009431/*
9432 * Compute the names of the files in a redirection list.
9433 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009434static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009435static void
9436expredir(union node *n)
9437{
9438 union node *redir;
9439
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009440 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009441 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009442
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009443 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009444 fn.lastp = &fn.list;
9445 switch (redir->type) {
9446 case NFROMTO:
9447 case NFROM:
9448 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009449#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009450 case NTO2:
9451#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009452 case NCLOBBER:
9453 case NAPPEND:
9454 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009455 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009456#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009457 store_expfname:
9458#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009459#if 0
9460// By the design of stack allocator, the loop of this kind:
9461// while true; do while true; do break; done </dev/null; done
9462// will look like a memory leak: ash plans to free expfname's
9463// of "/dev/null" as soon as it finishes running the loop
9464// (in this case, never).
9465// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009466 if (redir->nfile.expfname)
9467 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009468// It results in corrupted state of stacked allocations.
9469#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009470 redir->nfile.expfname = fn.list->text;
9471 break;
9472 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009473 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009474 if (redir->ndup.vname) {
Denys Vlasenkoe368d852020-02-16 19:02:22 +01009475 expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009476 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009477 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009478#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009479 if (!isdigit_str9(fn.list->text)) {
9480 /* >&file, not >&fd */
9481 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9482 ash_msg_and_raise_error("redir error");
9483 redir->type = NTO2;
9484 goto store_expfname;
9485 }
9486#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009487 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009488 }
9489 break;
9490 }
9491 }
9492}
9493
Eric Andersencb57d552001-06-28 07:25:16 +00009494/*
Eric Andersencb57d552001-06-28 07:25:16 +00009495 * Evaluate a pipeline. All the processes in the pipeline are children
9496 * of the process creating the pipeline. (This differs from some versions
9497 * of the shell, which make the last process in a pipeline the parent
9498 * of all the rest.)
9499 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009500static int
Eric Andersenc470f442003-07-28 09:56:35 +00009501evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009502{
9503 struct job *jp;
9504 struct nodelist *lp;
9505 int pipelen;
9506 int prevfd;
9507 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009508 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009509
Eric Andersenc470f442003-07-28 09:56:35 +00009510 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009511 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009512 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009513 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009514 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009515 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009516 if (n->npipe.pipe_backgnd == 0)
9517 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009518 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009519 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009520 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009521 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009522 pip[1] = -1;
9523 if (lp->next) {
9524 if (pipe(pip) < 0) {
9525 close(prevfd);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02009526 ash_msg_and_raise_perror("can't create pipe");
Eric Andersencb57d552001-06-28 07:25:16 +00009527 }
9528 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009529 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009530 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009531 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009532 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009533 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009534 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009535 if (prevfd > 0) {
9536 dup2(prevfd, 0);
9537 close(prevfd);
9538 }
9539 if (pip[1] > 1) {
9540 dup2(pip[1], 1);
9541 close(pip[1]);
9542 }
Eric Andersenc470f442003-07-28 09:56:35 +00009543 evaltreenr(lp->n, flags);
9544 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009545 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009546 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009547 if (prevfd >= 0)
9548 close(prevfd);
9549 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009550 /* Don't want to trigger debugging */
9551 if (pip[1] != -1)
9552 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009553 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009554 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009555 status = waitforjob(jp);
9556 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009557 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009558 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009559
9560 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009561}
9562
Ron Yorston9e2a5662020-01-21 16:01:58 +00009563/* setinteractive needs this forward reference */
9564#if EDITING_HAS_get_exe_name
9565static const char *get_builtin_name(int i) FAST_FUNC;
9566#endif
9567
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009568/*
9569 * Controls whether the shell is interactive or not.
9570 */
9571static void
9572setinteractive(int on)
9573{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009574 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009575
9576 if (++on == is_interactive)
9577 return;
9578 is_interactive = on;
9579 setsignal(SIGINT);
9580 setsignal(SIGQUIT);
9581 setsignal(SIGTERM);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009582 if (is_interactive > 1) {
Denys Vlasenko897475a2019-06-01 16:35:09 +02009583#if !ENABLE_FEATURE_SH_EXTRA_QUIET
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009584 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009585 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009586
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009587 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009588 /* note: ash and hush share this string */
9589 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009590 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9591 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009592 bb_banner,
9593 "built-in shell (ash)"
9594 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009595 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009596 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009597#endif
Denys Vlasenko897475a2019-06-01 16:35:09 +02009598#if ENABLE_FEATURE_EDITING
Ron Yorston9e2a5662020-01-21 16:01:58 +00009599 if (!line_input_state) {
Denys Vlasenko897475a2019-06-01 16:35:09 +02009600 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
Ron Yorston9e2a5662020-01-21 16:01:58 +00009601# if EDITING_HAS_get_exe_name
9602 line_input_state->get_exe_name = get_builtin_name;
9603# endif
9604 }
Denys Vlasenko897475a2019-06-01 16:35:09 +02009605#endif
9606 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009607}
9608
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009609static void
9610optschanged(void)
9611{
9612#if DEBUG
9613 opentrace();
9614#endif
9615 setinteractive(iflag);
9616 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009617#if ENABLE_FEATURE_EDITING_VI
Denys Vlasenko897475a2019-06-01 16:35:09 +02009618 if (line_input_state) {
9619 if (viflag)
9620 line_input_state->flags |= VI_MODE;
9621 else
9622 line_input_state->flags &= ~VI_MODE;
9623 }
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009624#else
9625 viflag = 0; /* forcibly keep the option off */
9626#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009627}
9628
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009629struct localvar_list {
9630 struct localvar_list *next;
9631 struct localvar *lv;
9632};
9633
9634static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009635
9636/*
9637 * Called after a function returns.
9638 * Interrupts must be off.
9639 */
9640static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009641poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009642{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009643 struct localvar_list *ll;
9644 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009645 struct var *vp;
9646
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009647 INT_OFF;
9648 ll = localvar_stack;
9649 localvar_stack = ll->next;
9650
9651 next = ll->lv;
9652 free(ll);
9653
9654 while ((lvp = next) != NULL) {
9655 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009656 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009657 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009658 if (keep) {
9659 int bits = VSTRFIXED;
9660
9661 if (lvp->flags != VUNSET) {
9662 if (vp->var_text == lvp->text)
9663 bits |= VTEXTFIXED;
9664 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9665 free((char*)lvp->text);
9666 }
9667
9668 vp->flags &= ~bits;
9669 vp->flags |= (lvp->flags & bits);
9670
9671 if ((vp->flags &
9672 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9673 unsetvar(vp->var_text);
9674 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009675 memcpy(optlist, lvp->text, sizeof(optlist));
9676 free((char*)lvp->text);
9677 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009678 } else if (lvp->flags == VUNSET) {
9679 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009680 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009681 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009682 if (vp->var_func)
9683 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009684 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009685 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009686 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009687 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009688 }
9689 free(lvp);
9690 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009691 INT_ON;
9692}
9693
9694/*
9695 * Create a new localvar environment.
9696 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009697static struct localvar_list *
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +01009698pushlocalvars(int push)
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009699{
9700 struct localvar_list *ll;
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +01009701 struct localvar_list *top;
9702
9703 top = localvar_stack;
9704 if (!push)
9705 goto out;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009706
9707 INT_OFF;
9708 ll = ckzalloc(sizeof(*ll));
9709 /*ll->lv = NULL; - zalloc did it */
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +01009710 ll->next = top;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009711 localvar_stack = ll;
9712 INT_ON;
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +01009713 out:
9714 return top;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009715}
9716
9717static void
9718unwindlocalvars(struct localvar_list *stop)
9719{
9720 while (localvar_stack != stop)
9721 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009722}
9723
9724static int
9725evalfun(struct funcnode *func, int argc, char **argv, int flags)
9726{
9727 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009728 struct jmploc *volatile savehandler;
9729 struct jmploc jmploc;
9730 int e;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009731 int savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009732
9733 saveparam = shellparam;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009734 savefuncline = funcline;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009735 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009736 e = setjmp(jmploc.loc);
9737 if (e) {
9738 goto funcdone;
9739 }
9740 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009741 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009742 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009743 func->count++;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009744 funcline = func->n.ndefun.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009745 INT_ON;
9746 shellparam.nparam = argc - 1;
9747 shellparam.p = argv + 1;
9748#if ENABLE_ASH_GETOPTS
9749 shellparam.optind = 1;
9750 shellparam.optoff = -1;
9751#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009752 evaltree(func->n.ndefun.body, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009753 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009754 INT_OFF;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009755 funcline = savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009756 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009757 freeparam(&shellparam);
9758 shellparam = saveparam;
9759 exception_handler = savehandler;
9760 INT_ON;
Denys Vlasenkocd24a502020-02-20 16:47:01 +01009761 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009762 return e;
9763}
9764
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009765/*
9766 * Make a variable a local variable. When a variable is made local, it's
9767 * value and flags are saved in a localvar structure. The saved values
9768 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009769 * "-" as a special case: it makes changes to "set +-options" local
9770 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009771 */
9772static void
Denys Vlasenko3e729102020-02-19 17:33:44 +01009773mklocal(char *name, int flags)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009774{
9775 struct localvar *lvp;
9776 struct var **vpp;
9777 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009778 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009779
9780 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009781 /* Cater for duplicate "local". Examples:
9782 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9783 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9784 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009785 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009786 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009787 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009788 if (eq)
9789 setvareq(name, 0);
9790 /* else:
9791 * it's a duplicate "local VAR" declaration, do nothing
9792 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009793 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009794 }
9795 lvp = lvp->next;
9796 }
9797
9798 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009799 if (LONE_DASH(name)) {
9800 char *p;
9801 p = ckmalloc(sizeof(optlist));
9802 lvp->text = memcpy(p, optlist, sizeof(optlist));
9803 vp = NULL;
9804 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009805 vpp = hashvar(name);
9806 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009807 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009808 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009809 if (eq)
Denys Vlasenko3e729102020-02-19 17:33:44 +01009810 vp = setvareq(name, VSTRFIXED | flags);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009811 else
Denys Vlasenko3e729102020-02-19 17:33:44 +01009812 vp = setvar(name, NULL, VSTRFIXED | flags);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009813 lvp->flags = VUNSET;
9814 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009815 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009816 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009817 /* make sure neither "struct var" nor string gets freed
9818 * during (un)setting:
9819 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009820 vp->flags |= VSTRFIXED|VTEXTFIXED;
9821 if (eq)
Denys Vlasenko3e729102020-02-19 17:33:44 +01009822 setvareq(name, flags);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009823 else
9824 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009825 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009826 }
9827 }
9828 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009829 lvp->next = localvar_stack->lv;
9830 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009831 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009832 INT_ON;
9833}
9834
9835/*
9836 * The "local" command.
9837 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009838static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009839localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009840{
9841 char *name;
9842
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009843 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009844 ash_msg_and_raise_error("not in a function");
9845
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009846 argv = argptr;
9847 while ((name = *argv++) != NULL) {
Denys Vlasenko3e729102020-02-19 17:33:44 +01009848 mklocal(name, 0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009849 }
9850 return 0;
9851}
9852
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009853static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009854falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009855{
9856 return 1;
9857}
9858
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009859static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009860truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009861{
9862 return 0;
9863}
9864
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009865static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009866execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009867{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009868 optionarg = NULL;
9869 while (nextopt("a:") != '\0')
9870 /* nextopt() sets optionarg to "-a ARGV0" */;
9871
9872 argv = argptr;
9873 if (argv[0]) {
9874 char *prog;
9875
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009876 iflag = 0; /* exit on error */
9877 mflag = 0;
9878 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009879 /* We should set up signals for "exec CMD"
9880 * the same way as for "CMD" without "exec".
9881 * But optschanged->setinteractive->setsignal
9882 * still thought we are a root shell. Therefore, for example,
9883 * SIGQUIT is still set to IGN. Fix it:
9884 */
9885 shlvl++;
9886 setsignal(SIGQUIT);
9887 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9888 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9889 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9890
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009891 prog = argv[0];
9892 if (optionarg)
9893 argv[0] = optionarg;
9894 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009895 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009896 }
9897 return 0;
9898}
9899
9900/*
9901 * The return command.
9902 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009903static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009904returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009905{
Denys Vlasenkocd24a502020-02-20 16:47:01 +01009906 int skip;
9907 int status;
9908
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009909 /*
9910 * If called outside a function, do what ksh does;
9911 * skip the rest of the file.
9912 */
Denys Vlasenkocd24a502020-02-20 16:47:01 +01009913 if (argv[1]) {
9914 skip = SKIPFUNC;
9915 status = number(argv[1]);
9916 } else {
9917 skip = SKIPFUNCDEF;
9918 status = exitstatus;
9919 }
9920 evalskip = skip;
9921
9922 return status;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009923}
9924
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009925/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009926static int breakcmd(int, char **) FAST_FUNC;
9927static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009928static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009929static int exitcmd(int, char **) FAST_FUNC;
9930static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009931#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009932static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009933#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009934#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009935static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009936#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009937#if MAX_HISTORY
9938static int historycmd(int, char **) FAST_FUNC;
9939#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009940#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009941static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009942#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009943static int readcmd(int, char **) FAST_FUNC;
9944static int setcmd(int, char **) FAST_FUNC;
9945static int shiftcmd(int, char **) FAST_FUNC;
9946static int timescmd(int, char **) FAST_FUNC;
9947static int trapcmd(int, char **) FAST_FUNC;
9948static int umaskcmd(int, char **) FAST_FUNC;
9949static int unsetcmd(int, char **) FAST_FUNC;
9950static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009951
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009952#define BUILTIN_NOSPEC "0"
9953#define BUILTIN_SPECIAL "1"
9954#define BUILTIN_REGULAR "2"
9955#define BUILTIN_SPEC_REG "3"
9956#define BUILTIN_ASSIGN "4"
9957#define BUILTIN_SPEC_ASSG "5"
9958#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009959#define BUILTIN_SPEC_REG_ASSG "7"
9960
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009961/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009962#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009963static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009964#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009965#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009966static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009967#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009968#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009969static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009970#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009971
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009972/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009973static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009974 { BUILTIN_SPEC_REG "." , dotcmd },
9975 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009976#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009977 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009978#endif
9979#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009980 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009981#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009982#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009983 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009984#endif
9985#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009986 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009987#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009988 { BUILTIN_SPEC_REG "break" , breakcmd },
9989 { BUILTIN_REGULAR "cd" , cdcmd },
9990 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009991#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009992 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009993#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009994 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009995#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009996 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009997#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009998 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009999 { BUILTIN_SPEC_REG "exec" , execcmd },
10000 { BUILTIN_SPEC_REG "exit" , exitcmd },
10001 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
10002 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010003#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010004 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010005#endif
10006#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010007 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010008#endif
Denys Vlasenkoa7b97e32020-02-16 18:29:52 +010010009 { BUILTIN_REGULAR "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +020010010#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010011 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010012#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +020010013#if MAX_HISTORY
10014 { BUILTIN_NOSPEC "history" , historycmd },
10015#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010016#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010017 { BUILTIN_REGULAR "jobs" , jobscmd },
10018 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010019#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +010010020#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010021 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010022#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +020010023 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +010010024#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010025 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +000010026#endif
Denys Vlasenkoa7b97e32020-02-16 18:29:52 +010010027 { BUILTIN_REGULAR "pwd" , pwdcmd },
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010028 { BUILTIN_REGULAR "read" , readcmd },
10029 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
10030 { BUILTIN_SPEC_REG "return" , returncmd },
10031 { BUILTIN_SPEC_REG "set" , setcmd },
10032 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010010033#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010034 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +020010035#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +010010036#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010037 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010038#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010039 { BUILTIN_SPEC_REG "times" , timescmd },
10040 { BUILTIN_SPEC_REG "trap" , trapcmd },
10041 { BUILTIN_REGULAR "true" , truecmd },
Denys Vlasenkoa7b97e32020-02-16 18:29:52 +010010042 { BUILTIN_REGULAR "type" , typecmd },
10043 { BUILTIN_REGULAR "ulimit" , ulimitcmd },
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010044 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010045#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010046 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010047#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +010010048 { BUILTIN_SPEC_REG "unset" , unsetcmd },
10049 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010050};
10051
Denis Vlasenko80591b02008-03-25 07:49:43 +000010052/* Should match the above table! */
10053#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +020010054 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +010010055 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010010056 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +020010057 /* alias */ 1 * ENABLE_ASH_ALIAS + \
10058 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
10059 /* break cd cddir */ 3)
10060#define EVALCMD (COMMANDCMD + \
10061 /* command */ 1 * ENABLE_ASH_CMDCMD + \
10062 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +010010063 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +020010064 0)
10065#define EXECCMD (EVALCMD + \
10066 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010067
10068/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000010069 * Search the table of builtin commands.
10070 */
Denys Vlasenko888527c2016-10-02 16:54:17 +020010071static int
10072pstrcmp1(const void *a, const void *b)
10073{
10074 return strcmp((char*)a, *(char**)b + 1);
10075}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000010076static struct builtincmd *
10077find_builtin(const char *name)
10078{
10079 struct builtincmd *bp;
10080
10081 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +000010082 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +020010083 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000010084 );
10085 return bp;
10086}
10087
Ron Yorston9e2a5662020-01-21 16:01:58 +000010088#if EDITING_HAS_get_exe_name
10089static const char * FAST_FUNC
10090get_builtin_name(int i)
10091{
10092 return /*i >= 0 &&*/ i < ARRAY_SIZE(builtintab) ? builtintab[i].name + 1 : NULL;
10093}
10094#endif
10095
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000010096/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010097 * Execute a simple command.
10098 */
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010099static void unwindfiles(struct parsefile *stop);
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010100static int
10101isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +000010102{
10103 const char *q = endofname(p);
10104 if (p == q)
10105 return 0;
10106 return *q == '=';
10107}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010108static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010109bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010110{
10111 /* Preserve exitstatus of a previous possible redirection
10112 * as POSIX mandates */
10113 return back_exitstatus;
10114}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010115static int
Eric Andersenc470f442003-07-28 09:56:35 +000010116evalcommand(union node *cmd, int flags)
10117{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010118 static const struct builtincmd null_bltin = {
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010119 BUILTIN_REGULAR "", bltincmd
Denis Vlasenko4fe15f32007-02-23 01:05:26 +000010120 };
Denys Vlasenko484fc202017-07-26 19:55:31 +020010121 struct localvar_list *localvar_stop;
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010122 struct parsefile *file_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010123 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +000010124 union node *argp;
10125 struct arglist arglist;
10126 struct arglist varlist;
10127 char **argv;
10128 int argc;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010129 struct strlist *osp;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010130 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +000010131 struct cmdentry cmdentry;
10132 struct job *jp;
10133 char *lastarg;
10134 const char *path;
10135 int spclbltin;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010136 int cmd_flag;
Eric Andersenc470f442003-07-28 09:56:35 +000010137 int status;
10138 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +000010139 smallint cmd_is_exec;
Denys Vlasenko3e729102020-02-19 17:33:44 +010010140 int vflags;
10141 int vlocal;
Eric Andersenc470f442003-07-28 09:56:35 +000010142
Denys Vlasenko675d24a2018-01-27 22:02:05 +010010143 errlinno = lineno = cmd->ncmd.linno;
10144 if (funcline)
10145 lineno -= funcline - 1;
10146
Eric Andersenc470f442003-07-28 09:56:35 +000010147 /* First expand the arguments. */
10148 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010149 file_stop = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010150 back_exitstatus = 0;
10151
10152 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010153 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +000010154 varlist.lastp = &varlist.list;
10155 *varlist.lastp = NULL;
10156 arglist.lastp = &arglist.list;
10157 *arglist.lastp = NULL;
10158
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010159 cmd_flag = 0;
10160 cmd_is_exec = 0;
10161 spclbltin = -1;
Denys Vlasenko3e729102020-02-19 17:33:44 +010010162 vflags = 0;
10163 vlocal = 0;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010164 path = NULL;
10165
Eric Andersenc470f442003-07-28 09:56:35 +000010166 argc = 0;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010167 argp = cmd->ncmd.args;
10168 osp = fill_arglist(&arglist, &argp);
10169 if (osp) {
10170 int pseudovarflag = 0;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010171
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010172 for (;;) {
10173 find_command(arglist.list->text, &cmdentry,
10174 cmd_flag | DO_REGBLTIN, pathval());
Paul Foxc3850c82005-07-20 18:23:39 +000010175
Denys Vlasenko3e729102020-02-19 17:33:44 +010010176 vlocal++;
10177
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010178 /* implement bltin and command here */
10179 if (cmdentry.cmdtype != CMDBUILTIN)
10180 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010181
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010182 pseudovarflag = IS_BUILTIN_ASSIGN(cmdentry.u.cmd);
10183 if (spclbltin < 0) {
10184 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
Denys Vlasenko3e729102020-02-19 17:33:44 +010010185 vlocal = !spclbltin;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010186 }
10187 cmd_is_exec = cmdentry.u.cmd == EXECCMD;
Ron Yorstonda7a6db2020-02-27 09:50:18 +000010188#if ENABLE_ASH_CMDCMD
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010189 if (cmdentry.u.cmd != COMMANDCMD)
10190 break;
Paul Foxc3850c82005-07-20 18:23:39 +000010191
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010192 cmd_flag = parse_command_args(&arglist, &argp, &path);
10193 if (!cmd_flag)
Ron Yorstonda7a6db2020-02-27 09:50:18 +000010194#endif
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010195 break;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010196 }
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010197
10198 for (; argp; argp = argp->narg.next)
10199 expandarg(argp, &arglist,
10200 pseudovarflag &&
10201 isassignment(argp->narg.text) ?
10202 EXP_VARTILDE : EXP_FULL | EXP_TILDE);
10203
10204 for (sp = arglist.list; sp; sp = sp->next)
10205 argc++;
Denys Vlasenko3e729102020-02-19 17:33:44 +010010206
10207 if (cmd_is_exec && argc > 1)
10208 vflags = VEXPORT;
Eric Andersenc470f442003-07-28 09:56:35 +000010209 }
10210
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +010010211 localvar_stop = pushlocalvars(vlocal);
10212
Denys Vlasenko65a8b852016-10-26 22:29:11 +020010213 /* Reserve one extra spot at the front for shellexec. */
10214 nargv = stalloc(sizeof(char *) * (argc + 2));
10215 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010216 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +000010217 TRACE(("evalcommand arg: %s\n", sp->text));
10218 *nargv++ = sp->text;
10219 }
10220 *nargv = NULL;
10221
10222 lastarg = NULL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010010223 if (iflag && funcline == 0 && argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010224 lastarg = nargv[-1];
10225
10226 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010227 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010228 preverrout_fd = 2;
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +020010229 if (BASH_XTRACEFD && xflag) {
10230 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10231 * we do not emulate this. We only use its value.
10232 */
10233 const char *xtracefd = lookupvar("BASH_XTRACEFD");
10234 if (xtracefd && is_number(xtracefd))
10235 preverrout_fd = atoi(xtracefd);
10236
10237 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010238 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +000010239
Denys Vlasenko54bef2a2020-02-19 15:30:20 +010010240 if (status) {
10241 bail:
10242 exitstatus = status;
10243
10244 /* We have a redirection error. */
10245 if (spclbltin > 0)
10246 raise_exception(EXERROR);
10247
10248 goto out;
10249 }
10250
Eric Andersenc470f442003-07-28 09:56:35 +000010251 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10252 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +000010253
10254 spp = varlist.lastp;
10255 expandarg(argp, &varlist, EXP_VARTILDE);
10256
Denys Vlasenko3e729102020-02-19 17:33:44 +010010257 if (vlocal)
10258 mklocal((*spp)->text, VEXPORT);
10259 else
10260 setvareq((*spp)->text, vflags);
Eric Andersenc470f442003-07-28 09:56:35 +000010261 }
10262
10263 /* Print the command if xflag is set. */
10264 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010265 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +000010266
Denys Vlasenko46999802017-07-29 21:12:29 +020010267 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010268
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010269 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010270 while (sp) {
10271 char *varval = sp->text;
10272 char *eq = strchrnul(varval, '=');
10273 if (*eq)
10274 eq++;
10275 fdprintf(preverrout_fd, "%s%.*s%s",
10276 pfx,
10277 (int)(eq - varval), varval,
10278 maybe_single_quote(eq)
10279 );
10280 sp = sp->next;
10281 pfx = " ";
10282 }
10283
10284 sp = arglist.list;
10285 while (sp) {
10286 fdprintf(preverrout_fd, "%s%s",
10287 pfx,
10288 /* always quote if matches reserved word: */
10289 findkwd(sp->text)
10290 ? single_quote(sp->text)
10291 : maybe_single_quote(sp->text)
10292 );
10293 sp = sp->next;
10294 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010295 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010296 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010297 }
10298
Eric Andersenc470f442003-07-28 09:56:35 +000010299 /* Now locate the command. */
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010010300 if (cmdentry.cmdtype != CMDBUILTIN
10301 || !(IS_BUILTIN_REGULAR(cmdentry.u.cmd))
10302 ) {
Denys Vlasenko3e729102020-02-19 17:33:44 +010010303 path = path ? path : pathval();
10304 find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path);
Eric Andersenc470f442003-07-28 09:56:35 +000010305 }
10306
Denys Vlasenkod81af722020-02-18 14:28:30 +010010307 jp = NULL;
10308
Eric Andersenc470f442003-07-28 09:56:35 +000010309 /* Execute the command. */
10310 switch (cmdentry.cmdtype) {
Denys Vlasenko54bef2a2020-02-19 15:30:20 +010010311 case CMDUNKNOWN:
10312 status = 127;
10313 flush_stdout_stderr();
10314 goto bail;
10315
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010316 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010317
Denys Vlasenko1750d3a2018-01-15 00:41:04 +010010318#if ENABLE_FEATURE_SH_STANDALONE \
10319 && ENABLE_FEATURE_SH_NOFORK \
10320 && NUM_APPLETS > 1
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010321/* (1) BUG: if variables are set, we need to fork, or save/restore them
10322 * around run_nofork_applet() call.
10323 * (2) Should this check also be done in forkshell()?
10324 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10325 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000010326 /* find_command() encodes applet_no as (-2 - applet_no) */
10327 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010328 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010329 char **sv_environ;
10330
10331 INT_OFF;
10332 sv_environ = environ;
10333 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
Denys Vlasenkod329e342017-08-04 14:50:03 +020010334 /*
10335 * Run <applet>_main().
10336 * Signals (^C) can't interrupt here.
10337 * Otherwise we can mangle stdio or malloc internal state.
10338 * This makes applets which can run for a long time
10339 * and/or wait for user input ineligible for NOFORK:
10340 * for example, "yes" or "rm" (rm -i waits for input).
10341 */
Ron Yorstond5bfe262020-02-20 08:23:03 +000010342 exitstatus = run_nofork_applet(applet_no, argv);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010343 environ = sv_environ;
Denys Vlasenkod329e342017-08-04 14:50:03 +020010344 /*
10345 * Try enabling NOFORK for "yes" applet.
10346 * ^C _will_ stop it (write returns EINTR),
10347 * but this causes stdout FILE to be stuck
10348 * and needing clearerr(). What if other applets
10349 * also can get EINTRs? Do we need to switch
10350 * our signals to SA_RESTART?
10351 */
10352 /*clearerr(stdout);*/
10353 INT_ON;
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010354 break;
10355 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010356#endif
Denys Vlasenkocfd392b2017-08-03 19:56:29 +020010357 /* Can we avoid forking? For example, very last command
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010358 * in a script or a subshell does not need forking,
10359 * we can just exec it.
10360 */
Denys Vlasenko238bf182010-05-18 15:49:07 +020010361 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010362 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010363 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +010010364 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +000010365 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010366 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +020010367 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +000010368 break;
10369 }
Denys Vlasenko238bf182010-05-18 15:49:07 +020010370 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010371 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +020010372 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +000010373 }
Denys Vlasenkoe139ae32017-04-12 21:02:33 +020010374 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +000010375 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010376 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +000010377 case CMDBUILTIN:
Denys Vlasenko97edfc42020-02-18 14:37:56 +010010378 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
10379 && !(exception_type == EXERROR && spclbltin <= 0)
10380 ) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010381 raise:
10382 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010383 }
Denys Vlasenkod81af722020-02-18 14:28:30 +010010384 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010385
10386 case CMDFUNCTION:
Eric Andersenc470f442003-07-28 09:56:35 +000010387 if (evalfun(cmdentry.u.func, argc, argv, flags))
10388 goto raise;
10389 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010390 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +000010391
Denys Vlasenkod81af722020-02-18 14:28:30 +010010392 status = waitforjob(jp);
Ron Yorston6cda0b02020-02-21 16:16:56 +000010393 if (jp)
10394 TRACE(("forked child exited with %d\n", status));
Denys Vlasenko97edfc42020-02-18 14:37:56 +010010395 FORCE_INT_ON;
Denys Vlasenkod81af722020-02-18 14:28:30 +010010396
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010397 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +020010398 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +020010399 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010400 unwindredir(redir_stop);
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010401 unwindfiles(file_stop);
Denys Vlasenkoe2dd2af2020-02-20 10:33:38 +010010402 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010403 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +000010404 /* dsl: I think this is intended to be used to support
10405 * '_' in 'vi' command mode during line editing...
10406 * However I implemented that within libedit itself.
10407 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020010408 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010409 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010410
10411 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000010412}
10413
10414static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010415evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010416{
Eric Andersenc470f442003-07-28 09:56:35 +000010417 char *volatile savecmdname;
10418 struct jmploc *volatile savehandler;
10419 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010420 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010421 int i;
10422
10423 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010424 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010425 i = setjmp(jmploc.loc);
10426 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010427 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010428 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010429 commandname = argv[0];
10430 argptr = argv + 1;
10431 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010432 if (cmd == EVALCMD)
10433 status = evalcmd(argc, argv, flags);
10434 else
10435 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010436 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010437 status |= ferror(stdout);
10438 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010439 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010440 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010441 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010442 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010443
10444 return i;
10445}
10446
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010447static int
10448goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010449{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010450 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010451}
10452
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010453
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010454/*
10455 * Search for a command. This is called before we fork so that the
10456 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010457 * the child. The check for "goodname" is an overly conservative
10458 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010459 */
Eric Andersenc470f442003-07-28 09:56:35 +000010460static void
10461prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010462{
10463 struct cmdentry entry;
10464
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010465 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10466 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010467}
10468
Eric Andersencb57d552001-06-28 07:25:16 +000010469
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010470/* ============ Builtin commands
10471 *
10472 * Builtin commands whose functions are closely tied to evaluation
10473 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010474 */
10475
10476/*
Eric Andersencb57d552001-06-28 07:25:16 +000010477 * Handle break and continue commands. Break, continue, and return are
10478 * all handled by setting the evalskip flag. The evaluation routines
10479 * above all check this flag, and if it is set they start skipping
10480 * commands rather than executing them. The variable skipcount is
10481 * the number of loops to break/continue, or the number of function
10482 * levels to return. (The latter is always 1.) It should probably
10483 * be an error to break out of more loops than exist, but it isn't
10484 * in the standard shell so we don't make it one here.
10485 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010486static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010487breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010488{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010489 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010490
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010491 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010492 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010493 if (n > loopnest)
10494 n = loopnest;
10495 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010496 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010497 skipcount = n;
10498 }
10499 return 0;
10500}
10501
Eric Andersenc470f442003-07-28 09:56:35 +000010502
Denys Vlasenko70392332016-10-27 02:31:55 +020010503/*
Eric Andersen90898442003-08-06 11:20:52 +000010504 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010505 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010506
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010507enum {
10508 INPUT_PUSH_FILE = 1,
10509 INPUT_NOFILE_OK = 2,
10510};
Eric Andersencb57d552001-06-28 07:25:16 +000010511
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010512static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010513/* values of checkkwd variable */
10514#define CHKALIAS 0x1
10515#define CHKKWD 0x2
10516#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010517#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010518
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010519/*
10520 * Push a string back onto the input at this current parsefile level.
10521 * We handle aliases this way.
10522 */
10523#if !ENABLE_ASH_ALIAS
10524#define pushstring(s, ap) pushstring(s)
10525#endif
10526static void
10527pushstring(char *s, struct alias *ap)
10528{
10529 struct strpush *sp;
10530 int len;
10531
10532 len = strlen(s);
10533 INT_OFF;
10534 if (g_parsefile->strpush) {
10535 sp = ckzalloc(sizeof(*sp));
10536 sp->prev = g_parsefile->strpush;
10537 } else {
10538 sp = &(g_parsefile->basestrpush);
10539 }
10540 g_parsefile->strpush = sp;
10541 sp->prev_string = g_parsefile->next_to_pgetc;
10542 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010543 sp->unget = g_parsefile->unget;
10544 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010545#if ENABLE_ASH_ALIAS
10546 sp->ap = ap;
10547 if (ap) {
10548 ap->flag |= ALIASINUSE;
10549 sp->string = s;
10550 }
10551#endif
10552 g_parsefile->next_to_pgetc = s;
10553 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010554 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010555 INT_ON;
10556}
10557
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010558static void
10559popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010560{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010561 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010562
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010563 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010564#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010565 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010566 if (g_parsefile->next_to_pgetc[-1] == ' '
10567 || g_parsefile->next_to_pgetc[-1] == '\t'
10568 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010569 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010570 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010571 if (sp->string != sp->ap->val) {
10572 free(sp->string);
10573 }
10574 sp->ap->flag &= ~ALIASINUSE;
10575 if (sp->ap->flag & ALIASDEAD) {
10576 unalias(sp->ap->name);
10577 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010578 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010579#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010580 g_parsefile->next_to_pgetc = sp->prev_string;
10581 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010582 g_parsefile->unget = sp->unget;
10583 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010584 g_parsefile->strpush = sp->prev;
10585 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010586 free(sp);
10587 INT_ON;
10588}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010589
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010590static int
10591preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010592{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010593 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010594 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010595
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010596 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010597#if ENABLE_FEATURE_EDITING
Denys Vlasenko4ac35a32020-11-16 13:09:37 +010010598 /* retry: */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010599 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010600 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010601 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010602# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010603 int timeout = -1;
Denys Vlasenko897475a2019-06-01 16:35:09 +020010604 const char *tmout_var = lookupvar("TMOUT");
10605 if (tmout_var) {
10606 timeout = atoi(tmout_var) * 1000;
10607 if (timeout <= 0)
10608 timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010609 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010610 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010611# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010612# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010613 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010614# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010615 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010616 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010617 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010618 /* ^C pressed, "convert" to SIGINT */
10619 write(STDOUT_FILENO, "^C", 2);
Denys Vlasenko4ac35a32020-11-16 13:09:37 +010010620 raise(SIGINT);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010621 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010622 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010623 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010624 return 1;
10625 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010626 exitstatus = 128 + SIGINT;
Denys Vlasenko4ac35a32020-11-16 13:09:37 +010010627 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010628 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010629 if (nr < 0) {
10630 if (errno == 0) {
10631 /* Ctrl+D pressed */
10632 nr = 0;
10633 }
10634# if ENABLE_ASH_IDLE_TIMEOUT
10635 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010636 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010637 exitshell();
10638 }
10639# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010640 }
Eric Andersencb57d552001-06-28 07:25:16 +000010641 }
10642#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010643 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010644#endif
10645
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010646#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010647 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010648 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010649 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010650 if (flags >= 0 && (flags & O_NONBLOCK)) {
10651 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010652 if (fcntl(0, F_SETFL, flags) >= 0) {
10653 out2str("sh: turning off NDELAY mode\n");
10654 goto retry;
10655 }
10656 }
10657 }
10658 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010659#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010660 return nr;
10661}
10662
10663/*
10664 * Refill the input buffer and return the next input character:
10665 *
10666 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010667 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10668 * or we are reading from a string so we can't refill the buffer,
10669 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010670 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010671 * 4) Process input up to the next newline, deleting nul characters.
10672 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010673//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10674#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010675static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010676static int
Eric Andersenc470f442003-07-28 09:56:35 +000010677preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010678{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010679 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010680 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010681
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010682 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010683#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010684 if (g_parsefile->left_in_line == -1
10685 && g_parsefile->strpush->ap
10686 && g_parsefile->next_to_pgetc[-1] != ' '
10687 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010688 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010689 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010690 return PEOA;
10691 }
Eric Andersen2870d962001-07-02 17:27:21 +000010692#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010693 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010694 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010695 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010696 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010697 * "pgetc" needs refilling.
10698 */
10699
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010700 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010701 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010702 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010703 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010704 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010705 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010706 /* even in failure keep left_in_line and next_to_pgetc
10707 * in lock step, for correct multi-layer pungetc.
10708 * left_in_line was decremented before preadbuffer(),
10709 * must inc next_to_pgetc: */
10710 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010711 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010712 }
Eric Andersencb57d552001-06-28 07:25:16 +000010713
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010714 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010715 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010716 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010717 again:
10718 more = preadfd();
10719 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010720 /* don't try reading again */
10721 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010722 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010723 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010724 return PEOF;
10725 }
10726 }
10727
Denis Vlasenko727752d2008-11-28 03:41:47 +000010728 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010729 * Set g_parsefile->left_in_line
10730 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010731 * NUL chars are deleted.
10732 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010733 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010734 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010735 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010736
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010737 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010738
Denis Vlasenko727752d2008-11-28 03:41:47 +000010739 c = *q;
10740 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010741 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010742 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010743 q++;
10744 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010745 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010746 break;
10747 }
Eric Andersencb57d552001-06-28 07:25:16 +000010748 }
10749
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010750 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010751 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10752 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010753 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010754 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010755 }
10756 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010757 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010758
Eric Andersencb57d552001-06-28 07:25:16 +000010759 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010760 char save = *q;
10761 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010762 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010763 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010764 }
10765
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010766 pgetc_debug("preadbuffer at %d:%p'%s'",
10767 g_parsefile->left_in_line,
10768 g_parsefile->next_to_pgetc,
10769 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010770 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010771}
10772
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010773static void
10774nlprompt(void)
10775{
10776 g_parsefile->linno++;
10777 setprompt_if(doprompt, 2);
10778}
10779static void
10780nlnoprompt(void)
10781{
10782 g_parsefile->linno++;
10783 needprompt = doprompt;
10784}
10785
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010786static int
10787pgetc(void)
10788{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010789 int c;
10790
10791 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010792 g_parsefile->left_in_line,
10793 g_parsefile->next_to_pgetc,
10794 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010795 if (g_parsefile->unget)
10796 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010797
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010798 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010799 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010800 else
10801 c = preadbuffer();
10802
10803 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10804 g_parsefile->lastc[0] = c;
10805
10806 return c;
10807}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010808
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010809#if ENABLE_ASH_ALIAS
10810static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010811pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010812{
10813 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010814 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010815 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010816 g_parsefile->left_in_line,
10817 g_parsefile->next_to_pgetc,
10818 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010819 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010820 } while (c == PEOA);
10821 return c;
10822}
10823#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010824# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010825#endif
10826
10827/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010828 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010829 * PEOF may be pushed back.
10830 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010831static void
Eric Andersenc470f442003-07-28 09:56:35 +000010832pungetc(void)
10833{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010834 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010835}
10836
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010837/* This one eats backslash+newline */
10838static int
10839pgetc_eatbnl(void)
10840{
10841 int c;
10842
10843 while ((c = pgetc()) == '\\') {
10844 if (pgetc() != '\n') {
10845 pungetc();
10846 break;
10847 }
10848
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010849 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010850 }
10851
10852 return c;
10853}
10854
Denys Vlasenko216913c2018-04-02 12:35:04 +020010855struct synstack {
10856 smalluint syntax;
10857 uint8_t innerdq :1;
10858 uint8_t varpushed :1;
10859 uint8_t dblquote :1;
10860 int varnest; /* levels of variables expansion */
10861 int dqvarnest; /* levels of variables expansion within double quotes */
10862 int parenlevel; /* levels of parens in arithmetic */
10863 struct synstack *prev;
10864 struct synstack *next;
10865};
10866
Denys Vlasenkof7eea8c2020-02-14 16:16:34 +010010867static int
10868pgetc_top(struct synstack *stack)
10869{
10870 return stack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl();
10871}
10872
Denys Vlasenko216913c2018-04-02 12:35:04 +020010873static void
10874synstack_push(struct synstack **stack, struct synstack *next, int syntax)
10875{
10876 memset(next, 0, sizeof(*next));
10877 next->syntax = syntax;
10878 next->next = *stack;
10879 (*stack)->prev = next;
10880 *stack = next;
10881}
10882
10883static ALWAYS_INLINE void
10884synstack_pop(struct synstack **stack)
10885{
10886 *stack = (*stack)->next;
10887}
10888
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010889/*
10890 * To handle the "." command, a stack of input files is used. Pushfile
10891 * adds a new entry to the stack and popfile restores the previous level.
10892 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010893static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010894pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010895{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010896 struct parsefile *pf;
10897
Denis Vlasenko597906c2008-02-20 16:38:54 +000010898 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010899 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010900 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010901 /*pf->strpush = NULL; - ckzalloc did it */
10902 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010903 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010904 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010905}
10906
10907static void
10908popfile(void)
10909{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010910 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010911
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010912 if (pf == &basepf)
10913 return;
10914
Denis Vlasenkob012b102007-02-19 22:43:01 +000010915 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010916 if (pf->pf_fd >= 0)
10917 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010918 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010919 while (pf->strpush)
10920 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010921 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010922 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010923 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010924}
10925
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010926static void
10927unwindfiles(struct parsefile *stop)
10928{
10929 while (g_parsefile != stop)
10930 popfile();
10931}
10932
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010933/*
10934 * Return to top level.
10935 */
10936static void
10937popallfiles(void)
10938{
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010939 unwindfiles(&basepf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010940}
10941
10942/*
10943 * Close the file(s) that the shell is reading commands from. Called
10944 * after a fork is done.
10945 */
10946static void
10947closescript(void)
10948{
10949 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010950 if (g_parsefile->pf_fd > 0) {
10951 close(g_parsefile->pf_fd);
10952 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010953 }
10954}
10955
10956/*
10957 * Like setinputfile, but takes an open file descriptor. Call this with
10958 * interrupts off.
10959 */
10960static void
10961setinputfd(int fd, int push)
10962{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010963 if (push) {
10964 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010965 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010966 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010967 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010968 if (g_parsefile->buf == NULL)
10969 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010970 g_parsefile->left_in_buffer = 0;
10971 g_parsefile->left_in_line = 0;
10972 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010973}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010974
Eric Andersenc470f442003-07-28 09:56:35 +000010975/*
10976 * Set the input to take input from a file. If push is set, push the
10977 * old input onto the stack first.
10978 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010979static int
10980setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010981{
10982 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010983
Denis Vlasenkob012b102007-02-19 22:43:01 +000010984 INT_OFF;
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010985 fd = open(fname, O_RDONLY | O_CLOEXEC);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010986 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010987 if (flags & INPUT_NOFILE_OK)
10988 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010989 exitstatus = 127;
Johannes Schindelin20a63b22017-08-22 22:03:17 +020010990 ash_msg_and_raise_perror("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010991 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010992 if (fd < 10)
10993 fd = savefd(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010994 else if (O_CLOEXEC == 0) /* old libc */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010995 close_on_exec_on(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010996
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010997 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010998 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010999 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011000 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011001}
11002
Eric Andersencb57d552001-06-28 07:25:16 +000011003/*
11004 * Like setinputfile, but takes input from a string.
11005 */
Eric Andersenc470f442003-07-28 09:56:35 +000011006static void
11007setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000011008{
Denis Vlasenkob012b102007-02-19 22:43:01 +000011009 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000011010 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011011 g_parsefile->next_to_pgetc = string;
11012 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011013 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011014 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011015 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000011016}
11017
11018
Denys Vlasenko70392332016-10-27 02:31:55 +020011019/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011020 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000011021 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011022
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011023#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000011024
Denys Vlasenko23841622015-10-09 15:52:03 +020011025/* Hash of mtimes of mailboxes */
11026static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000011027/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011028static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000011029
Eric Andersencb57d552001-06-28 07:25:16 +000011030/*
Eric Andersenc470f442003-07-28 09:56:35 +000011031 * Print appropriate message(s) if mail has arrived.
11032 * If mail_var_path_changed is set,
11033 * then the value of MAIL has mail_var_path_changed,
11034 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000011035 */
Eric Andersenc470f442003-07-28 09:56:35 +000011036static void
11037chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011038{
Eric Andersencb57d552001-06-28 07:25:16 +000011039 const char *mpath;
11040 char *p;
11041 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020011042 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000011043 struct stackmark smark;
11044 struct stat statb;
11045
Eric Andersencb57d552001-06-28 07:25:16 +000011046 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000011047 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020011048 new_hash = 0;
11049 for (;;) {
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010011050 int len;
11051
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010011052 len = padvance_magic(&mpath, nullstr, 2);
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010011053 if (!len)
11054 break;
11055 p = stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011056 break;
11057 if (*p == '\0')
11058 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011059 for (q = p; *q; q++)
11060 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011061#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011062 if (q[-1] != '/')
11063 abort();
11064#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011065 q[-1] = '\0'; /* delete trailing '/' */
11066 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000011067 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000011068 }
Denys Vlasenko23841622015-10-09 15:52:03 +020011069 /* Very simplistic "hash": just a sum of all mtimes */
11070 new_hash += (unsigned)statb.st_mtime;
11071 }
11072 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020011073 if (mailtime_hash != 0)
11074 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020011075 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000011076 }
Eric Andersenc470f442003-07-28 09:56:35 +000011077 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011078 popstackmark(&smark);
11079}
Eric Andersencb57d552001-06-28 07:25:16 +000011080
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011081static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011082changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000011083{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011084 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011085}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011086
Denis Vlasenko131ae172007-02-18 13:00:19 +000011087#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000011088
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011089
11090/* ============ ??? */
11091
Eric Andersencb57d552001-06-28 07:25:16 +000011092/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011093 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000011094 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011095static void
11096setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011097{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011098 char **newparam;
11099 char **ap;
11100 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000011101
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011102 for (nparam = 0; argv[nparam]; nparam++)
11103 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011104 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
11105 while (*argv) {
11106 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000011107 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011108 *ap = NULL;
11109 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000011110 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011111 shellparam.nparam = nparam;
11112 shellparam.p = newparam;
11113#if ENABLE_ASH_GETOPTS
11114 shellparam.optind = 1;
11115 shellparam.optoff = -1;
11116#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011117}
11118
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011119/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000011120 * Process shell options. The global variable argptr contains a pointer
11121 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000011122 *
11123 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
11124 * For a non-interactive shell, an error condition encountered
11125 * by a special built-in ... shall cause the shell to write a diagnostic message
11126 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000011127 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000011128 * ...
11129 * Utility syntax error (option or operand error) Shall exit
11130 * ...
11131 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
11132 * we see that bash does not do that (set "finishes" with error code 1 instead,
11133 * and shell continues), and people rely on this behavior!
11134 * Testcase:
11135 * set -o barfoo 2>/dev/null
11136 * echo $?
11137 *
11138 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011139 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011140static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011141plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000011142{
11143 int i;
11144
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011145 if (name) {
11146 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011147 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000011148 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011149 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000011150 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011151 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011152 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011153 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000011154 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000011155 for (i = 0; i < NOPTS; i++) {
Denys Vlasenko2f9c1242019-08-02 16:43:36 +020011156 if (optnames(i)[0] == '\0')
11157 continue;
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011158 if (val) {
11159 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11160 } else {
11161 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11162 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000011163 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011164 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000011165}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011166static void
11167setoption(int flag, int val)
11168{
11169 int i;
11170
11171 for (i = 0; i < NOPTS; i++) {
Denys Vlasenkof3634582019-06-03 12:21:04 +020011172 if (optletters(i) == flag && optnames(i)[0] != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011173 optlist[i] = val;
11174 return;
11175 }
11176 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011177 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011178 /* NOTREACHED */
11179}
Denys Vlasenko897475a2019-06-01 16:35:09 +020011180/* If login_sh is not NULL, we are called to parse command line opts,
11181 * not "set -opts"
11182 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011183static int
Denys Vlasenko897475a2019-06-01 16:35:09 +020011184options(int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000011185{
11186 char *p;
11187 int val;
11188 int c;
11189
Denys Vlasenko897475a2019-06-01 16:35:09 +020011190 if (login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000011191 minusc = NULL;
11192 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011193 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011194 if (c != '-' && c != '+')
11195 break;
11196 argptr++;
11197 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011198 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000011199 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011200 if (p[0] == '\0' || LONE_DASH(p)) {
Denys Vlasenko897475a2019-06-01 16:35:09 +020011201 if (!login_sh) {
Eric Andersen2870d962001-07-02 17:27:21 +000011202 /* "-" means turn off -x and -v */
11203 if (p[0] == '\0')
11204 xflag = vflag = 0;
11205 /* "--" means reset params */
11206 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011207 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000011208 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011209 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000011210 }
Eric Andersencb57d552001-06-28 07:25:16 +000011211 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011212 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000011213 while ((c = *p++) != '\0') {
Denys Vlasenko897475a2019-06-01 16:35:09 +020011214 if (login_sh) {
11215 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
11216 if (c == 'c') {
11217 minusc = p; /* command is after shell args */
Denys Vlasenkof3634582019-06-03 12:21:04 +020011218 cflag = 1;
11219 continue;
11220 }
11221 if (c == 's') { /* -s, +s */
11222 sflag = 1;
11223 continue;
11224 }
11225 if (c == 'i') { /* -i, +i */
11226 iflag = 1;
Denys Vlasenko897475a2019-06-01 16:35:09 +020011227 continue;
11228 }
11229 if (c == 'l') {
11230 *login_sh = 1; /* -l or +l == --login */
11231 continue;
11232 }
11233 /* bash does not accept +-login, we also won't */
11234 if (val && (c == '-')) { /* long options */
11235 if (strcmp(p, "login") == 0) {
11236 *login_sh = 1;
11237 }
11238 break;
11239 }
11240 }
11241 if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011242 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011243 /* it already printed err message */
11244 return 1; /* error */
11245 }
Eric Andersencb57d552001-06-28 07:25:16 +000011246 if (*argptr)
11247 argptr++;
11248 } else {
11249 setoption(c, val);
11250 }
11251 }
11252 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011253 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011254}
11255
Eric Andersencb57d552001-06-28 07:25:16 +000011256/*
Eric Andersencb57d552001-06-28 07:25:16 +000011257 * The shift builtin command.
11258 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011259static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011260shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011261{
11262 int n;
11263 char **ap1, **ap2;
11264
11265 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000011266 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011267 n = number(argv[1]);
11268 if (n > shellparam.nparam)
Ingo van Lil9c8e94b2018-01-05 15:04:23 +010011269 return 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011270 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000011271 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011272 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000011273 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000011274 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000011275 }
11276 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011277 while ((*ap2++ = *ap1++) != NULL)
11278 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000011279#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011280 shellparam.optind = 1;
11281 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000011282#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000011283 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000011284 return 0;
11285}
11286
Eric Andersencb57d552001-06-28 07:25:16 +000011287/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011288 * POSIX requires that 'set' (but not export or readonly) output the
11289 * variables in lexicographic order - by the locale's collating order (sigh).
11290 * Maybe we could keep them in an ordered balanced binary tree
11291 * instead of hashed lists.
11292 * For now just roll 'em through qsort for printing...
11293 */
11294static int
11295showvars(const char *sep_prefix, int on, int off)
11296{
11297 const char *sep;
11298 char **ep, **epend;
11299
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010011300 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011301 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11302
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011303 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011304
11305 for (; ep < epend; ep++) {
11306 const char *p;
11307 const char *q;
11308
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011309 p = endofname(*ep);
11310/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11311 * makes "export -p" to have output not suitable for "eval":
11312 * import os
11313 * os.environ["test-test"]="test"
11314 * if os.fork() == 0:
11315 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11316 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11317 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011318 q = nullstr;
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011319 if (*p == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011320 q = single_quote(++p);
11321 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11322 }
11323 return 0;
11324}
11325
11326/*
Eric Andersencb57d552001-06-28 07:25:16 +000011327 * The set command builtin.
11328 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011329static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011330setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000011331{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011332 int retval;
11333
Denis Vlasenko68404f12008-03-17 09:00:54 +000011334 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000011335 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011336
Denis Vlasenkob012b102007-02-19 22:43:01 +000011337 INT_OFF;
Denys Vlasenko897475a2019-06-01 16:35:09 +020011338 retval = options(/*login_sh:*/ NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011339 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011340 optschanged();
11341 if (*argptr != NULL) {
11342 setparam(argptr);
11343 }
Eric Andersencb57d552001-06-28 07:25:16 +000011344 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011345 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011346 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000011347}
11348
Denis Vlasenko131ae172007-02-18 13:00:19 +000011349#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011350static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011351change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000011352{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011353 uint32_t t;
11354
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011355 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000011356 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011357 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000011358 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020011359 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000011360 vrandom.flags &= ~VNOFUNC;
11361 } else {
11362 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011363 t = strtoul(value, NULL, 10);
11364 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000011365 }
Eric Andersenef02f822004-03-11 13:34:24 +000011366}
Eric Andersen16767e22004-03-16 05:14:10 +000011367#endif
11368
Ron Yorston1d371862019-04-15 10:52:05 +010011369#if BASH_EPOCH_VARS
11370static void FAST_FUNC
11371change_epoch(struct var *vepoch, const char *fmt)
11372{
11373 struct timeval tv;
Denys Vlasenko3c13da32020-12-30 23:48:01 +010011374 char buffer[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
Ron Yorston1d371862019-04-15 10:52:05 +010011375
Denys Vlasenko3c13da32020-12-30 23:48:01 +010011376 xgettimeofday(&tv);
11377 sprintf(buffer, fmt, (unsigned long long)tv.tv_sec, (unsigned)tv.tv_usec);
Ron Yorston1d371862019-04-15 10:52:05 +010011378 setvar(vepoch->var_text, buffer, VNOFUNC);
11379 vepoch->flags &= ~VNOFUNC;
11380}
11381
11382static void FAST_FUNC
11383change_seconds(const char *value UNUSED_PARAM)
11384{
Denys Vlasenko3c13da32020-12-30 23:48:01 +010011385 change_epoch(&vepochs, "%llu");
Ron Yorston1d371862019-04-15 10:52:05 +010011386}
11387
11388static void FAST_FUNC
11389change_realtime(const char *value UNUSED_PARAM)
11390{
Denys Vlasenko3c13da32020-12-30 23:48:01 +010011391 change_epoch(&vepochr, "%llu.%06u");
Ron Yorston1d371862019-04-15 10:52:05 +010011392}
11393#endif
11394
Denis Vlasenko131ae172007-02-18 13:00:19 +000011395#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011396static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011397getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000011398{
11399 char *p, *q;
11400 char c = '?';
11401 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020011402 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000011403 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011404 int ind = shellparam.optind;
11405 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000011406
Denys Vlasenko9c541002015-10-07 15:44:36 +020011407 sbuf[1] = '\0';
11408
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011409 shellparam.optind = -1;
11410 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000011411
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011412 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000011413 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011414 else
11415 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000011416 if (p == NULL || *p == '\0') {
11417 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000011418 p = *optnext;
11419 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011420 atend:
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011421 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011422 p = NULL;
11423 done = 1;
11424 goto out;
11425 }
11426 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011427 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000011428 goto atend;
11429 }
11430
11431 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000011432 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000011433 if (*q == '\0') {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011434 /* OPTERR is a bashism */
11435 const char *cp = lookupvar("OPTERR");
11436 if ((cp && LONE_CHAR(cp, '0'))
11437 || (optstr[0] == ':')
11438 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011439 sbuf[0] = c;
11440 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011441 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011442 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011443 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011444 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011445 }
11446 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000011447 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011448 }
11449 if (*++q == ':')
11450 q++;
11451 }
11452
11453 if (*++q == ':') {
11454 if (*p == '\0' && (p = *optnext) == NULL) {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011455 /* OPTERR is a bashism */
11456 const char *cp = lookupvar("OPTERR");
11457 if ((cp && LONE_CHAR(cp, '0'))
11458 || (optstr[0] == ':')
11459 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011460 sbuf[0] = c;
11461 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011462 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000011463 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011464 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011465 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011466 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011467 c = '?';
11468 }
Eric Andersenc470f442003-07-28 09:56:35 +000011469 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011470 }
11471
11472 if (p == *optnext)
11473 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011474 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000011475 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011476 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011477 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011478 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011479 ind = optnext - optfirst + 1;
11480 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020011481 sbuf[0] = c;
11482 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011483 setvar0(optvar, sbuf);
11484
11485 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11486 shellparam.optind = ind;
11487
Eric Andersencb57d552001-06-28 07:25:16 +000011488 return done;
11489}
Eric Andersenc470f442003-07-28 09:56:35 +000011490
11491/*
11492 * The getopts builtin. Shellparam.optnext points to the next argument
11493 * to be processed. Shellparam.optptr points to the next character to
11494 * be processed in the current argument. If shellparam.optnext is NULL,
11495 * then it's the first time getopts has been called.
11496 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011497static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000011498getoptscmd(int argc, char **argv)
11499{
11500 char **optbase;
11501
11502 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000011503 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011504 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000011505 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011506 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000011507 shellparam.optind = 1;
11508 shellparam.optoff = -1;
11509 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011510 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011511 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011512 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000011513 shellparam.optind = 1;
11514 shellparam.optoff = -1;
11515 }
11516 }
11517
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011518 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011519}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011520#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011521
Eric Andersencb57d552001-06-28 07:25:16 +000011522
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011523/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011524
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011525struct heredoc {
11526 struct heredoc *next; /* next here document in list */
11527 union node *here; /* redirection node */
11528 char *eofmark; /* string indicating end of input */
11529 smallint striptabs; /* if set, strip leading tabs */
11530};
11531
11532static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011533static smallint quoteflag; /* set if (part of) last token was quoted */
11534static token_id_t lasttoken; /* last token read (integer id Txxx) */
11535static struct heredoc *heredoclist; /* list of here documents to read */
11536static char *wordtext; /* text of last word returned by readtoken */
11537static struct nodelist *backquotelist;
11538static union node *redirnode;
11539static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011540
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011541static const char *
11542tokname(char *buf, int tok)
11543{
11544 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011545 return tokname_array[tok];
11546 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011547 return buf;
11548}
11549
11550/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011551 * Called when an unexpected token is read during the parse. The argument
11552 * is the token that is expected, or -1 if more than one type of token can
11553 * occur at this point.
11554 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011555static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011556static void
11557raise_error_unexpected_syntax(int token)
11558{
11559 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011560 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011561 int l;
11562
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011563 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011564 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011565 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011566 raise_error_syntax(msg);
11567 /* NOTREACHED */
11568}
Eric Andersencb57d552001-06-28 07:25:16 +000011569
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011570/* parsing is heavily cross-recursive, need these forward decls */
11571static union node *andor(void);
11572static union node *pipeline(void);
11573static union node *parse_command(void);
11574static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011575static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011576static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011577
Eric Andersenc470f442003-07-28 09:56:35 +000011578static union node *
11579list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011580{
11581 union node *n1, *n2, *n3;
11582 int tok;
11583
Eric Andersencb57d552001-06-28 07:25:16 +000011584 n1 = NULL;
11585 for (;;) {
Denys Vlasenkoc08993f2020-02-22 17:26:23 +010011586 switch (readtoken()) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011587 case TNL:
11588 if (!(nlflag & 1))
11589 break;
11590 parseheredoc();
11591 return n1;
11592
11593 case TEOF:
11594 if (!n1 && (nlflag & 1))
11595 n1 = NODE_EOF;
11596 parseheredoc();
Denys Vlasenkoc08993f2020-02-22 17:26:23 +010011597 tokpushback++;
11598 lasttoken = TEOF;
Ron Yorstonc0e00762015-10-29 11:30:55 +000011599 return n1;
11600 }
11601
Denys Vlasenkoc08993f2020-02-22 17:26:23 +010011602 tokpushback++;
Ron Yorstonc0e00762015-10-29 11:30:55 +000011603 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011604 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011605 return n1;
11606 nlflag |= 2;
11607
Eric Andersencb57d552001-06-28 07:25:16 +000011608 n2 = andor();
11609 tok = readtoken();
11610 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011611 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011612 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011613 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011614 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011615 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011616 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011617 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011618 n2 = n3;
11619 }
11620 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011621 }
11622 }
11623 if (n1 == NULL) {
11624 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011625 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011626 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011627 n3->type = NSEMI;
11628 n3->nbinary.ch1 = n1;
11629 n3->nbinary.ch2 = n2;
11630 n1 = n3;
11631 }
11632 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011633 case TNL:
11634 case TEOF:
11635 tokpushback = 1;
11636 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011637 case TBACKGND:
11638 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011639 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011640 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011641 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011642 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011643 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011644 return n1;
11645 }
11646 }
11647}
11648
Eric Andersenc470f442003-07-28 09:56:35 +000011649static union node *
11650andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011651{
Eric Andersencb57d552001-06-28 07:25:16 +000011652 union node *n1, *n2, *n3;
11653 int t;
11654
Eric Andersencb57d552001-06-28 07:25:16 +000011655 n1 = pipeline();
11656 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011657 t = readtoken();
11658 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011659 t = NAND;
11660 } else if (t == TOR) {
11661 t = NOR;
11662 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011663 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011664 return n1;
11665 }
Eric Andersenc470f442003-07-28 09:56:35 +000011666 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011667 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011668 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011669 n3->type = t;
11670 n3->nbinary.ch1 = n1;
11671 n3->nbinary.ch2 = n2;
11672 n1 = n3;
11673 }
11674}
11675
Eric Andersenc470f442003-07-28 09:56:35 +000011676static union node *
11677pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011678{
Eric Andersencb57d552001-06-28 07:25:16 +000011679 union node *n1, *n2, *pipenode;
11680 struct nodelist *lp, *prev;
11681 int negate;
11682
11683 negate = 0;
11684 TRACE(("pipeline: entered\n"));
11685 if (readtoken() == TNOT) {
11686 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011687 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011688 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011689 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011690 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011691 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011692 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011693 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011694 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011695 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011696 pipenode->npipe.cmdlist = lp;
11697 lp->n = n1;
11698 do {
11699 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011700 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011701 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011702 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011703 prev->next = lp;
11704 } while (readtoken() == TPIPE);
11705 lp->next = NULL;
11706 n1 = pipenode;
11707 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011708 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011709 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011710 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011711 n2->type = NNOT;
11712 n2->nnot.com = n1;
11713 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011714 }
11715 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011716}
11717
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011718static union node *
11719makename(void)
11720{
11721 union node *n;
11722
Denis Vlasenko597906c2008-02-20 16:38:54 +000011723 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011724 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011725 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011726 n->narg.text = wordtext;
11727 n->narg.backquote = backquotelist;
11728 return n;
11729}
11730
11731static void
11732fixredir(union node *n, const char *text, int err)
11733{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011734 int fd;
11735
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011736 TRACE(("Fix redir %s %d\n", text, err));
11737 if (!err)
11738 n->ndup.vname = NULL;
11739
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011740 fd = bb_strtou(text, NULL, 10);
11741 if (!errno && fd >= 0)
11742 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011743 else if (LONE_DASH(text))
11744 n->ndup.dupfd = -1;
11745 else {
11746 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011747 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011748 n->ndup.vname = makename();
11749 }
11750}
11751
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011752static void
11753parsefname(void)
11754{
11755 union node *n = redirnode;
11756
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011757 if (n->type == NHERE)
11758 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011759 if (readtoken() != TWORD)
11760 raise_error_unexpected_syntax(-1);
11761 if (n->type == NHERE) {
11762 struct heredoc *here = heredoc;
11763 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011764
11765 if (quoteflag == 0)
11766 n->type = NXHERE;
11767 TRACE(("Here document %d\n", n->type));
Denys Vlasenko740058b2018-01-09 17:01:00 +010011768 rmescapes(wordtext, 0, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011769 here->eofmark = wordtext;
11770 here->next = NULL;
11771 if (heredoclist == NULL)
11772 heredoclist = here;
11773 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011774 for (p = heredoclist; p->next; p = p->next)
11775 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011776 p->next = here;
11777 }
11778 } else if (n->type == NTOFD || n->type == NFROMFD) {
11779 fixredir(n, wordtext, 0);
11780 } else {
11781 n->nfile.fname = makename();
11782 }
11783}
Eric Andersencb57d552001-06-28 07:25:16 +000011784
Eric Andersenc470f442003-07-28 09:56:35 +000011785static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011786simplecmd(void)
11787{
11788 union node *args, **app;
11789 union node *n = NULL;
11790 union node *vars, **vpp;
11791 union node **rpp, *redir;
11792 int savecheckkwd;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011793 int savelinno;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011794#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011795 smallint double_brackets_flag = 0;
11796#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011797 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011798
11799 args = NULL;
11800 app = &args;
11801 vars = NULL;
11802 vpp = &vars;
11803 redir = NULL;
11804 rpp = &redir;
11805
11806 savecheckkwd = CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011807 savelinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011808 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011809 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011810 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011811 t = readtoken();
11812 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011813#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011814 case TFUNCTION:
11815 if (peektoken() != TWORD)
11816 raise_error_unexpected_syntax(TWORD);
11817 function_flag = 1;
11818 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011819#endif
11820#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011821 case TAND: /* "&&" */
11822 case TOR: /* "||" */
11823 if (!double_brackets_flag) {
11824 tokpushback = 1;
11825 goto out;
11826 }
Denys Vlasenkod2241f52020-10-31 03:34:07 +010011827 /* pass "&&" or "||" to [[ ]] as literal args */
11828 wordtext = (char *) (t == TAND ? "&&" : "||");
Denis Vlasenko80591b02008-03-25 07:49:43 +000011829#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011830 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011831 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011832 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011833 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011834 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011835#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011836 if (strcmp("[[", wordtext) == 0)
11837 double_brackets_flag = 1;
11838 else if (strcmp("]]", wordtext) == 0)
11839 double_brackets_flag = 0;
11840#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011841 n->narg.backquote = backquotelist;
11842 if (savecheckkwd && isassignment(wordtext)) {
11843 *vpp = n;
11844 vpp = &n->narg.next;
11845 } else {
11846 *app = n;
11847 app = &n->narg.next;
11848 savecheckkwd = 0;
11849 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011850#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011851 if (function_flag) {
11852 checkkwd = CHKNL | CHKKWD;
11853 switch (peektoken()) {
11854 case TBEGIN:
11855 case TIF:
11856 case TCASE:
11857 case TUNTIL:
11858 case TWHILE:
11859 case TFOR:
11860 goto do_func;
11861 case TLP:
11862 function_flag = 0;
11863 break;
Denys Vlasenkoe93031e2018-04-10 01:23:19 +020011864# if BASH_TEST2
Ron Yorston95ebcf72015-11-03 09:42:23 +000011865 case TWORD:
11866 if (strcmp("[[", wordtext) == 0)
11867 goto do_func;
11868 /* fall through */
Denys Vlasenkoe93031e2018-04-10 01:23:19 +020011869# endif
Ron Yorston95ebcf72015-11-03 09:42:23 +000011870 default:
11871 raise_error_unexpected_syntax(-1);
11872 }
11873 }
11874#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011875 break;
11876 case TREDIR:
11877 *rpp = n = redirnode;
11878 rpp = &n->nfile.next;
11879 parsefname(); /* read name of redirection file */
11880 break;
11881 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011882 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011883 if (args && app == &args->narg.next
11884 && !vars && !redir
11885 ) {
11886 struct builtincmd *bcmd;
11887 const char *name;
11888
11889 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011890 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011891 raise_error_unexpected_syntax(TRP);
11892 name = n->narg.text;
11893 if (!goodname(name)
11894 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11895 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011896 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011897 }
11898 n->type = NDEFUN;
11899 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011900 n->ndefun.text = n->narg.text;
11901 n->ndefun.linno = g_parsefile->linno;
11902 n->ndefun.body = parse_command();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011903 return n;
11904 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011905 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011906 /* fall through */
11907 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011908 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011909 goto out;
11910 }
11911 }
11912 out:
11913 *app = NULL;
11914 *vpp = NULL;
11915 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011916 n = stzalloc(sizeof(struct ncmd));
Denys Vlasenko57b7efb2018-04-10 01:20:26 +020011917 if (NCMD != 0)
11918 n->type = NCMD;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011919 n->ncmd.linno = savelinno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011920 n->ncmd.args = args;
11921 n->ncmd.assign = vars;
11922 n->ncmd.redirect = redir;
11923 return n;
11924}
11925
11926static union node *
11927parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011928{
Eric Andersencb57d552001-06-28 07:25:16 +000011929 union node *n1, *n2;
11930 union node *ap, **app;
11931 union node *cp, **cpp;
11932 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011933 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011934 int t;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011935 int savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011936
11937 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011938 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011939
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011940 savelinno = g_parsefile->linno;
11941
Eric Andersencb57d552001-06-28 07:25:16 +000011942 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011943 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011944 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011945 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011946 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011947 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011948 n1->type = NIF;
11949 n1->nif.test = list(0);
11950 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011951 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011952 n1->nif.ifpart = list(0);
11953 n2 = n1;
11954 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011955 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011956 n2 = n2->nif.elsepart;
11957 n2->type = NIF;
11958 n2->nif.test = list(0);
11959 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011960 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011961 n2->nif.ifpart = list(0);
11962 }
11963 if (lasttoken == TELSE)
11964 n2->nif.elsepart = list(0);
11965 else {
11966 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011967 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011968 }
Eric Andersenc470f442003-07-28 09:56:35 +000011969 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011970 break;
11971 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011972 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011973 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011974 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011975 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011976 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011977 got = readtoken();
11978 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011979 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011980 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011981 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011982 }
11983 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011984 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011985 break;
11986 }
11987 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011988 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011989 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011990 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011991 n1->type = NFOR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011992 n1->nfor.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011993 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011994 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011995 if (readtoken() == TIN) {
11996 app = &ap;
11997 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011998 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011999 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012000 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000012001 n2->narg.text = wordtext;
12002 n2->narg.backquote = backquotelist;
12003 *app = n2;
12004 app = &n2->narg.next;
12005 }
12006 *app = NULL;
12007 n1->nfor.args = ap;
12008 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012009 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000012010 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012011 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000012012 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012013 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012014 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012015 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000012016 n1->nfor.args = n2;
12017 /*
12018 * Newline or semicolon here is optional (but note
12019 * that the original Bourne shell only allowed NL).
12020 */
Ron Yorstonab80e012015-08-03 13:46:00 +010012021 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012022 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012023 }
Eric Andersenc470f442003-07-28 09:56:35 +000012024 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000012025 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012026 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000012027 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000012028 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000012029 break;
12030 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012031 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000012032 n1->type = NCASE;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010012033 n1->ncase.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000012034 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012035 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012036 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000012037 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012038 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000012039 n2->narg.text = wordtext;
12040 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010012041 checkkwd = CHKNL | CHKKWD | CHKALIAS;
12042 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012043 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000012044 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012045 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000012046 checkkwd = CHKNL | CHKKWD;
12047 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012048 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000012049 if (lasttoken == TLP)
12050 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012051 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000012052 cp->type = NCLIST;
12053 app = &cp->nclist.pattern;
12054 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012055 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000012056 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012057 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000012058 ap->narg.text = wordtext;
12059 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000012060 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000012061 break;
12062 app = &ap->narg.next;
12063 readtoken();
12064 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000012065 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000012066 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012067 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012068 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000012069
Eric Andersenc470f442003-07-28 09:56:35 +000012070 cpp = &cp->nclist.next;
12071
12072 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012073 t = readtoken();
12074 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000012075 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012076 raise_error_unexpected_syntax(TENDCASE);
12077 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000012078 }
Eric Andersenc470f442003-07-28 09:56:35 +000012079 }
Eric Andersencb57d552001-06-28 07:25:16 +000012080 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000012081 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000012082 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000012083 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000012084 n1->type = NSUBSHELL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010012085 n1->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000012086 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012087 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012088 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000012089 break;
12090 case TBEGIN:
12091 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000012092 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000012093 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012094 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000012095 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000012096 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012097 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000012098 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000012099 }
12100
Eric Andersenc470f442003-07-28 09:56:35 +000012101 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012102 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000012103
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012104 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000012105 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000012106 checkkwd = CHKKWD | CHKALIAS;
12107 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000012108 while (readtoken() == TREDIR) {
12109 *rpp = n2 = redirnode;
12110 rpp = &n2->nfile.next;
12111 parsefname();
12112 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012113 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012114 *rpp = NULL;
12115 if (redir) {
12116 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012117 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000012118 n2->type = NREDIR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010012119 n2->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000012120 n2->nredir.n = n1;
12121 n1 = n2;
12122 }
12123 n1->nredir.redirect = redir;
12124 }
Eric Andersencb57d552001-06-28 07:25:16 +000012125 return n1;
12126}
12127
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012128#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020012129static int
12130decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012131{
12132 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
12133 int c, cnt;
12134 char *p;
12135 char buf[4];
12136
12137 c = pgetc();
12138 p = strchr(C_escapes, c);
12139 if (p) {
12140 buf[0] = c;
12141 p = buf;
12142 cnt = 3;
12143 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
12144 do {
12145 c = pgetc();
12146 *++p = c;
12147 } while ((unsigned char)(c - '0') <= 7 && --cnt);
12148 pungetc();
12149 } else if (c == 'x') { /* \xHH */
12150 do {
12151 c = pgetc();
12152 *++p = c;
12153 } while (isxdigit(c) && --cnt);
12154 pungetc();
12155 if (cnt == 3) { /* \x but next char is "bad" */
12156 c = 'x';
12157 goto unrecognized;
12158 }
12159 } else { /* simple seq like \\ or \t */
12160 p++;
12161 }
12162 *p = '\0';
12163 p = buf;
12164 c = bb_process_escape_sequence((void*)&p);
12165 } else { /* unrecognized "\z": print both chars unless ' or " */
12166 if (c != '\'' && c != '"') {
12167 unrecognized:
12168 c |= 0x100; /* "please encode \, then me" */
12169 }
12170 }
12171 return c;
12172}
12173#endif
12174
Denys Vlasenko46999802017-07-29 21:12:29 +020012175/* Used by expandstr to get here-doc like behaviour. */
12176#define FAKEEOFMARK ((char*)(uintptr_t)1)
12177
12178static ALWAYS_INLINE int
12179realeofmark(const char *eofmark)
12180{
12181 return eofmark && eofmark != FAKEEOFMARK;
12182}
12183
Eric Andersencb57d552001-06-28 07:25:16 +000012184/*
12185 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
12186 * is not NULL, read a here document. In the latter case, eofmark is the
12187 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010012188 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000012189 * is the first character of the input token or document.
12190 *
12191 * Because C does not have internal subroutines, I have simulated them
12192 * using goto's to implement the subroutine linkage. The following macros
12193 * will run code that appears at the end of readtoken1.
12194 */
Eric Andersen2870d962001-07-02 17:27:21 +000012195#define CHECKEND() {goto checkend; checkend_return:;}
12196#define PARSEREDIR() {goto parseredir; parseredir_return:;}
12197#define PARSESUB() {goto parsesub; parsesub_return:;}
12198#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
12199#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
12200#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000012201static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010012202readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000012203{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012204 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010012205 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000012206 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020012207 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012208 struct nodelist *bqlist;
12209 smallint quotef;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012210 smallint oldstyle;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012211 smallint pssyntax; /* we are expanding a prompt string */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012212 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012213 /* syntax stack */
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020012214 struct synstack synbase = { };
Denys Vlasenko216913c2018-04-02 12:35:04 +020012215 struct synstack *synstack = &synbase;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012216
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012217#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000012218 pssyntax = (syntax == PSSYNTAX);
12219 if (pssyntax)
12220 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012221#else
12222 pssyntax = 0; /* constant */
12223#endif
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020012224 synstack->syntax = syntax;
12225
Denys Vlasenko216913c2018-04-02 12:35:04 +020012226 if (syntax == DQSYNTAX)
12227 synstack->dblquote = 1;
12228 quotef = 0;
12229 bqlist = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000012230
12231 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012232 loop:
12233 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012234 CHECKEND(); /* set c to PEOF if at end of here document */
12235 for (;;) { /* until end of line or end of word */
12236 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012237 switch (SIT(c, synstack->syntax)) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012238 case CNL: /* '\n' */
Denys Vlasenko680c3012018-04-11 12:39:18 +020012239 if (synstack->syntax == BASESYNTAX
12240 && !synstack->varnest
12241 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012242 goto endword; /* exit outer loop */
Denys Vlasenko680c3012018-04-11 12:39:18 +020012243 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012244 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012245 nlprompt();
Denys Vlasenkof7eea8c2020-02-14 16:16:34 +010012246 c = pgetc_top(synstack);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012247 goto loop; /* continue outer loop */
12248 case CWORD:
12249 USTPUTC(c, out);
12250 break;
12251 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012252#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020012253 if (c == '\\' && bash_dollar_squote) {
12254 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020012255 if (c == '\0') {
12256 /* skip $'\000', $'\x00' (like bash) */
12257 break;
12258 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012259 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020012260 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012261 c = (unsigned char)c;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012262 if (eofmark == NULL || synstack->dblquote)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012263 USTPUTC(CTLESC, out);
12264 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012265 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012266 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012267#endif
Denys Vlasenkoc4c20122018-04-02 13:29:20 +020012268 if (!eofmark || synstack->dblquote || synstack->varnest)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012269 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012270 USTPUTC(c, out);
12271 break;
12272 case CBACK: /* backslash */
12273 c = pgetc_without_PEOA();
12274 if (c == PEOF) {
12275 USTPUTC(CTLESC, out);
12276 USTPUTC('\\', out);
12277 pungetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012278 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012279 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000012280 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012281 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012282 }
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012283 /* Backslash is retained if we are in "str"
12284 * and next char isn't dquote-special.
12285 */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012286 if (synstack->dblquote
Denys Vlasenko958581a2010-09-12 15:04:27 +020012287 && c != '\\'
12288 && c != '`'
12289 && c != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012290 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12291 && (c != '}' || !synstack->varnest)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012292 ) {
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012293 USTPUTC(CTLESC, out); /* protect '\' from glob */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012294 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012295 }
Ron Yorston549deab2015-05-18 09:57:51 +020012296 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020012297 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012298 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012299 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012300 break;
12301 case CSQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012302 synstack->syntax = SQSYNTAX;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012303 quotemark:
12304 if (eofmark == NULL) {
12305 USTPUTC(CTLQUOTEMARK, out);
12306 }
12307 break;
12308 case CDQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012309 synstack->syntax = DQSYNTAX;
12310 synstack->dblquote = 1;
12311 toggledq:
12312 if (synstack->varnest)
12313 synstack->innerdq ^= 1;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012314 goto quotemark;
12315 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012316 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012317 if (eofmark != NULL && synstack->varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012318 USTPUTC(c, out);
Denys Vlasenko216913c2018-04-02 12:35:04 +020012319 break;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012320 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012321
12322 if (synstack->dqvarnest == 0) {
12323 synstack->syntax = BASESYNTAX;
12324 synstack->dblquote = 0;
12325 }
12326
12327 quotef = 1;
12328
12329 if (c == '"')
12330 goto toggledq;
12331
12332 goto quotemark;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012333 case CVAR: /* '$' */
12334 PARSESUB(); /* parse substitution */
12335 break;
12336 case CENDVAR: /* '}' */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012337 if (!synstack->innerdq && synstack->varnest > 0) {
12338 if (!--synstack->varnest && synstack->varpushed)
12339 synstack_pop(&synstack);
12340 else if (synstack->dqvarnest > 0)
12341 synstack->dqvarnest--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012342 c = CTLENDVAR;
12343 }
12344 USTPUTC(c, out);
12345 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010012346#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020012347 case CLP: /* '(' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012348 synstack->parenlevel++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012349 USTPUTC(c, out);
12350 break;
12351 case CRP: /* ')' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012352 if (synstack->parenlevel > 0) {
12353 synstack->parenlevel--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012354 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012355 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020012356 c = CTLENDARI;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012357 synstack_pop(&synstack);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012358 } else {
12359 /*
12360 * unbalanced parens
12361 * (don't 2nd guess - no error)
12362 */
12363 pungetc();
12364 }
12365 }
12366 USTPUTC(c, out);
12367 break;
12368#endif
12369 case CBQUOTE: /* '`' */
Denys Vlasenko41fddb42018-04-01 16:38:32 +020012370 if (checkkwd & CHKEOFMARK) {
12371 quotef = 1;
12372 USTPUTC('`', out);
12373 break;
12374 }
12375
Denys Vlasenko958581a2010-09-12 15:04:27 +020012376 PARSEBACKQOLD();
12377 break;
12378 case CENDFILE:
12379 goto endword; /* exit outer loop */
12380 case CIGN:
12381 break;
12382 default:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012383 if (synstack->varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012384#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020012385 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012386//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020012387 if (pgetc() == '>')
12388 c = 0x100 + '>'; /* flag &> */
12389 pungetc();
12390 }
12391#endif
12392 goto endword; /* exit outer loop */
12393 }
12394 IF_ASH_ALIAS(if (c != PEOA))
12395 USTPUTC(c, out);
12396 }
Denys Vlasenkof7eea8c2020-02-14 16:16:34 +010012397 c = pgetc_top(synstack);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012398 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012399 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020012400
Denys Vlasenko0b883582016-12-23 16:49:07 +010012401#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko216913c2018-04-02 12:35:04 +020012402 if (synstack->syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012403 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000012404#endif
Denys Vlasenko216913c2018-04-02 12:35:04 +020012405 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012406 raise_error_syntax("unterminated quoted string");
Denys Vlasenko216913c2018-04-02 12:35:04 +020012407 if (synstack->varnest != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012408 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000012409 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000012410 }
12411 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012412 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000012413 out = stackblock();
12414 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012415 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000012416 && quotef == 0
12417 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000012418 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012419 PARSEREDIR(); /* passed as params: out, c */
12420 lasttoken = TREDIR;
12421 return lasttoken;
12422 }
12423 /* else: non-number X seen, interpret it
12424 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000012425 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012426 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012427 }
12428 quoteflag = quotef;
12429 backquotelist = bqlist;
12430 grabstackblock(len);
12431 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012432 lasttoken = TWORD;
12433 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012434/* end of readtoken routine */
12435
Eric Andersencb57d552001-06-28 07:25:16 +000012436/*
12437 * Check to see whether we are at the end of the here document. When this
12438 * is called, c is set to the first character of the next input line. If
12439 * we are at the end of the here document, this routine sets the c to PEOF.
12440 */
Eric Andersenc470f442003-07-28 09:56:35 +000012441checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020012442 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012443 int markloc;
12444 char *p;
12445
Denis Vlasenko131ae172007-02-18 13:00:19 +000012446#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012447 if (c == PEOA)
12448 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000012449#endif
12450 if (striptabs) {
12451 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012452 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000012453 }
Eric Andersenc470f442003-07-28 09:56:35 +000012454 }
Eric Andersencb57d552001-06-28 07:25:16 +000012455
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012456 markloc = out - (char *)stackblock();
12457 for (p = eofmark; STPUTC(c, out), *p; p++) {
12458 if (c != *p)
12459 goto more_heredoc;
Denys Vlasenko35e349d2019-09-05 14:31:49 +020012460 /* FIXME: fails for backslash-newlined terminator:
12461 * cat <<EOF
12462 * ...
12463 * EO\
12464 * F
12465 * (see heredoc_bkslash_newline2.tests)
12466 */
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012467 c = pgetc_without_PEOA();
12468 }
12469
12470 if (c == '\n' || c == PEOF) {
12471 c = PEOF;
12472 g_parsefile->linno++;
12473 needprompt = doprompt;
12474 } else {
12475 int len_here;
12476
12477 more_heredoc:
12478 p = (char *)stackblock() + markloc + 1;
12479 len_here = out - p;
12480
12481 if (len_here) {
12482 len_here -= (c >= PEOF);
12483 c = p[-1];
12484
12485 if (len_here) {
12486 char *str;
12487
12488 str = alloca(len_here + 1);
12489 *(char *)mempcpy(str, p, len_here) = '\0';
12490
12491 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012492 }
12493 }
12494 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012495
12496 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012497 }
Eric Andersenc470f442003-07-28 09:56:35 +000012498 goto checkend_return;
12499}
Eric Andersencb57d552001-06-28 07:25:16 +000012500
Eric Andersencb57d552001-06-28 07:25:16 +000012501/*
12502 * Parse a redirection operator. The variable "out" points to a string
12503 * specifying the fd to be redirected. The variable "c" contains the
12504 * first character of the redirection operator.
12505 */
Eric Andersenc470f442003-07-28 09:56:35 +000012506parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012507 /* out is already checked to be a valid number or "" */
12508 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000012509 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000012510
Denis Vlasenko597906c2008-02-20 16:38:54 +000012511 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000012512 if (c == '>') {
12513 np->nfile.fd = 1;
Denys Vlasenko220be532018-03-31 19:21:31 +020012514 c = pgetc_eatbnl();
Eric Andersenc470f442003-07-28 09:56:35 +000012515 if (c == '>')
12516 np->type = NAPPEND;
12517 else if (c == '|')
12518 np->type = NCLOBBER;
12519 else if (c == '&')
12520 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012521 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000012522 else {
12523 np->type = NTO;
12524 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012525 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000012526 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012527#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012528 else if (c == 0x100 + '>') { /* this flags &> redirection */
12529 np->nfile.fd = 1;
12530 pgetc(); /* this is '>', no need to check */
12531 np->type = NTO2;
12532 }
12533#endif
12534 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000012535 /*np->nfile.fd = 0; - stzalloc did it */
Denys Vlasenko220be532018-03-31 19:21:31 +020012536 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012537 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000012538 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012539 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012540 np = stzalloc(sizeof(struct nhere));
12541 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012542 }
12543 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012544 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000012545 heredoc->here = np;
Denys Vlasenko220be532018-03-31 19:21:31 +020012546 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012547 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000012548 heredoc->striptabs = 1;
12549 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012550 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012551 pungetc();
12552 }
12553 break;
12554
12555 case '&':
12556 np->type = NFROMFD;
12557 break;
12558
12559 case '>':
12560 np->type = NFROMTO;
12561 break;
12562
12563 default:
12564 np->type = NFROM;
12565 pungetc();
12566 break;
12567 }
Eric Andersencb57d552001-06-28 07:25:16 +000012568 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012569 if (fd >= 0)
12570 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012571 redirnode = np;
12572 goto parseredir_return;
12573}
Eric Andersencb57d552001-06-28 07:25:16 +000012574
Eric Andersencb57d552001-06-28 07:25:16 +000012575/*
12576 * Parse a substitution. At this point, we have read the dollar sign
12577 * and nothing else.
12578 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012579
12580/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12581 * (assuming ascii char codes, as the original implementation did) */
12582#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012583 (((unsigned)(c) - 33 < 32) \
12584 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012585parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012586 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012587 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012588
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012589 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012590 if ((checkkwd & CHKEOFMARK)
12591 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012592 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012593 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012594#if BASH_DOLLAR_SQUOTE
Denys Vlasenko216913c2018-04-02 12:35:04 +020012595 if (synstack->syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012596 bash_dollar_squote = 1;
12597 else
12598#endif
12599 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012600 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012601 } else if (c == '(') {
12602 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012603 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012604#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012605 PARSEARITH();
12606#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012607 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012608#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012609 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012610 pungetc();
12611 PARSEBACKQNEW();
12612 }
12613 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012614 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012615 smalluint newsyn = synstack->syntax;
12616
Eric Andersenc470f442003-07-28 09:56:35 +000012617 USTPUTC(CTLVAR, out);
12618 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012619 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012620 subtype = VSNORMAL;
12621 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012622 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012623 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012624 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012625 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012626 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012627 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012628 do {
12629 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012630 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012631 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012632 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012633 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012634 do {
12635 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012636 c = pgetc_eatbnl();
Denys Vlasenkoc2ce8882020-02-17 10:15:35 +010012637 } while (!subtype && isdigit(c));
Denys Vlasenko58eb8052018-08-05 15:58:13 +020012638 } else if (c != '}') {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012639 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012640 int cc = c;
12641
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012642 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012643 if (!subtype && cc == '#') {
12644 subtype = VSLENGTH;
12645 if (c == '_' || isalnum(c))
12646 goto varname;
12647 cc = c;
12648 c = pgetc_eatbnl();
12649 if (cc == '}' || c != '}') {
12650 pungetc();
12651 subtype = 0;
12652 c = cc;
12653 cc = '#';
12654 }
12655 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012656
12657 if (!is_special(cc)) {
12658 if (subtype == VSLENGTH)
12659 subtype = 0;
12660 goto badsub;
12661 }
12662
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012663 USTPUTC(cc, out);
Denys Vlasenko58eb8052018-08-05 15:58:13 +020012664 } else
12665 goto badsub;
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012666
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012667 if (c != '}' && subtype == VSLENGTH) {
12668 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012669 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012670 }
Eric Andersencb57d552001-06-28 07:25:16 +000012671
Eric Andersenc470f442003-07-28 09:56:35 +000012672 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012673 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012674 /* ${VAR...} but not $VAR or ${#VAR} */
12675 /* c == first char after VAR */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012676 int cc = c;
12677
Eric Andersenc470f442003-07-28 09:56:35 +000012678 switch (c) {
12679 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012680 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012681#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012682 /* This check is only needed to not misinterpret
12683 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12684 * constructs.
12685 */
12686 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012687 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012688 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012689 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012690 }
12691#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012692 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012693 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012694 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012695 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012696 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012697 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012698 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012699 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012700 }
Eric Andersenc470f442003-07-28 09:56:35 +000012701 case '%':
Denys Vlasenko216913c2018-04-02 12:35:04 +020012702 case '#':
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012703 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012704 c = pgetc_eatbnl();
Denys Vlasenko216913c2018-04-02 12:35:04 +020012705 if (c == cc)
12706 subtype++;
12707 else
12708 pungetc();
12709
12710 newsyn = BASESYNTAX;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012711 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012712#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012713 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012714 /* ${v/[/]pattern/repl} */
12715//TODO: encode pattern and repl separately.
Denys Vlasenko216913c2018-04-02 12:35:04 +020012716// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12717// are broken (should print "ONE")
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012718 subtype = VSREPLACE;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012719 newsyn = BASESYNTAX;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012720 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012721 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012722 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012723 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012724 break;
12725#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012726 }
Eric Andersenc470f442003-07-28 09:56:35 +000012727 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012728 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012729 pungetc();
12730 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012731
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012732 if (newsyn == ARISYNTAX)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012733 newsyn = DQSYNTAX;
12734
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012735 if ((newsyn != synstack->syntax || synstack->innerdq)
12736 && subtype != VSNORMAL
12737 ) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012738 synstack_push(&synstack,
12739 synstack->prev ?: alloca(sizeof(*synstack)),
12740 newsyn);
12741
12742 synstack->varpushed = 1;
12743 synstack->dblquote = newsyn != BASESYNTAX;
12744 }
12745
Denys Vlasenko3df14102016-10-26 16:41:13 +020012746 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012747 if (subtype != VSNORMAL) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012748 synstack->varnest++;
12749 if (synstack->dblquote)
12750 synstack->dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012751 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012752 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012753 }
Eric Andersenc470f442003-07-28 09:56:35 +000012754 goto parsesub_return;
12755}
Eric Andersencb57d552001-06-28 07:25:16 +000012756
Eric Andersencb57d552001-06-28 07:25:16 +000012757/*
12758 * Called to parse command substitutions. Newstyle is set if the command
12759 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12760 * list of commands (passed by reference), and savelen is the number of
12761 * characters on the top of the stack which must be preserved.
12762 */
Eric Andersenc470f442003-07-28 09:56:35 +000012763parsebackq: {
12764 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012765 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012766 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012767 size_t savelen;
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012768 struct heredoc *saveheredoclist;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012769 smallint saveprompt = 0;
12770
Eric Andersenc470f442003-07-28 09:56:35 +000012771 str = NULL;
12772 savelen = out - (char *)stackblock();
12773 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012774 /*
12775 * FIXME: this can allocate very large block on stack and SEGV.
12776 * Example:
12777 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012778 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012779 * a hundred command substitutions stack overflows.
12780 * With larger prepended string, SEGV happens sooner.
12781 */
Ron Yorston072fc602015-07-01 16:46:18 +010012782 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012783 memcpy(str, stackblock(), savelen);
12784 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012785
Eric Andersenc470f442003-07-28 09:56:35 +000012786 if (oldstyle) {
12787 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012788 * treatment to some slashes, and then push the string and
12789 * reread it as input, interpreting it normally.
12790 */
Eric Andersenc470f442003-07-28 09:56:35 +000012791 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012792 size_t psavelen;
12793 char *pstr;
12794
Eric Andersenc470f442003-07-28 09:56:35 +000012795 STARTSTACKSTR(pout);
12796 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012797 int pc;
12798
12799 setprompt_if(needprompt, 2);
Denys Vlasenko220be532018-03-31 19:21:31 +020012800 pc = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012801 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012802 case '`':
12803 goto done;
12804
12805 case '\\':
Denys Vlasenko777a6352020-09-29 16:25:32 +020012806 pc = pgetc(); /* not pgetc_eatbnl! */
Eric Andersenc470f442003-07-28 09:56:35 +000012807 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012808 && (!synstack->dblquote || pc != '"')
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012809 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012810 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012811 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012812 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012813 break;
12814 }
12815 /* fall through */
12816
12817 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012818 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012819 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012820
12821 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012822 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012823 break;
12824
12825 default:
12826 break;
12827 }
12828 STPUTC(pc, pout);
12829 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012830 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012831 STPUTC('\0', pout);
12832 psavelen = pout - (char *)stackblock();
12833 if (psavelen > 0) {
12834 pstr = grabstackstr(pout);
12835 setinputstring(pstr);
12836 }
12837 }
12838 nlpp = &bqlist;
12839 while (*nlpp)
12840 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012841 *nlpp = stzalloc(sizeof(**nlpp));
12842 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012843
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012844 saveheredoclist = heredoclist;
12845 heredoclist = NULL;
12846
Eric Andersenc470f442003-07-28 09:56:35 +000012847 if (oldstyle) {
12848 saveprompt = doprompt;
12849 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012850 }
12851
Eric Andersenc470f442003-07-28 09:56:35 +000012852 n = list(2);
12853
12854 if (oldstyle)
12855 doprompt = saveprompt;
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012856 else {
12857 if (readtoken() != TRP)
12858 raise_error_unexpected_syntax(TRP);
12859 setinputstring(nullstr);
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012860 }
12861
Denys Vlasenko9a1a6592020-02-22 16:39:27 +010012862 parseheredoc();
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012863 heredoclist = saveheredoclist;
Eric Andersenc470f442003-07-28 09:56:35 +000012864
12865 (*nlpp)->n = n;
Denys Vlasenko74aaf052020-02-17 12:11:26 +010012866 /* Start reading from old file again. */
12867 popfile();
12868 /* Ignore any pushed back tokens left from the backquote parsing. */
12869 if (oldstyle)
Eric Andersenc470f442003-07-28 09:56:35 +000012870 tokpushback = 0;
Denys Vlasenkoc55847f2020-02-17 15:59:08 +010012871 out = growstackto(savelen + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012872 if (str) {
12873 memcpy(out, str, savelen);
12874 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012875 }
Ron Yorston549deab2015-05-18 09:57:51 +020012876 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012877 if (oldstyle)
12878 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012879 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012880}
12881
Denys Vlasenko0b883582016-12-23 16:49:07 +010012882#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012883/*
12884 * Parse an arithmetic expansion (indicate start of one and set state)
12885 */
Eric Andersenc470f442003-07-28 09:56:35 +000012886parsearith: {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012887
12888 synstack_push(&synstack,
12889 synstack->prev ?: alloca(sizeof(*synstack)),
12890 ARISYNTAX);
12891 synstack->dblquote = 1;
Ron Yorstonad88bde2015-05-18 09:56:16 +020012892 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012893 goto parsearith_return;
12894}
12895#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012896} /* end of readtoken */
12897
Eric Andersencb57d552001-06-28 07:25:16 +000012898/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012899 * Read the next input token.
12900 * If the token is a word, we set backquotelist to the list of cmds in
12901 * backquotes. We set quoteflag to true if any part of the word was
12902 * quoted.
12903 * If the token is TREDIR, then we set redirnode to a structure containing
12904 * the redirection.
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012905 *
12906 * [Change comment: here documents and internal procedures]
12907 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12908 * word parsing code into a separate routine. In this case, readtoken
12909 * doesn't need to have any internal procedures, but parseword does.
12910 * We could also make parseoperator in essence the main routine, and
12911 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012912 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012913#define NEW_xxreadtoken
12914#ifdef NEW_xxreadtoken
12915/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012916static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012917 '\n', '(', ')', /* singles */
12918 '&', '|', ';', /* doubles */
12919 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012920};
Eric Andersencb57d552001-06-28 07:25:16 +000012921
Denis Vlasenko834dee72008-10-07 09:18:30 +000012922#define xxreadtoken_singles 3
12923#define xxreadtoken_doubles 3
12924
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012925static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012926 TNL, TLP, TRP, /* only single occurrence allowed */
12927 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12928 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012929 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012930};
12931
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012932static int
12933xxreadtoken(void)
12934{
12935 int c;
12936
12937 if (tokpushback) {
12938 tokpushback = 0;
12939 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012940 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012941 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012942 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012943 c = pgetc_eatbnl();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012944 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012945 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012946
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012947 if (c == '#') {
12948 while ((c = pgetc()) != '\n' && c != PEOF)
12949 continue;
12950 pungetc();
12951 } else if (c == '\\') {
Denys Vlasenko220be532018-03-31 19:21:31 +020012952 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012953 } else {
12954 const char *p;
12955
12956 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12957 if (c != PEOF) {
12958 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012959 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012960 }
12961
12962 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012963 if (p == NULL)
12964 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012965
Denis Vlasenko834dee72008-10-07 09:18:30 +000012966 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
Denys Vlasenko1e5111b2018-04-01 03:04:55 +020012967 int cc = pgetc_eatbnl();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012968 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012969 p += xxreadtoken_doubles + 1;
12970 } else {
12971 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012972#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012973 if (c == '&' && cc == '>') /* &> */
12974 break; /* return readtoken1(...) */
12975#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012976 }
12977 }
12978 }
12979 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12980 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012981 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012982 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012983
12984 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012985}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012986#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012987#define RETURN(token) return lasttoken = token
12988static int
12989xxreadtoken(void)
12990{
12991 int c;
12992
12993 if (tokpushback) {
12994 tokpushback = 0;
12995 return lasttoken;
12996 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012997 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012998 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012999 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013000 switch (c) {
13001 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010013002 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013003 continue;
13004 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000013005 while ((c = pgetc()) != '\n' && c != PEOF)
13006 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013007 pungetc();
13008 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013009 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020013010 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013011 RETURN(TNL);
13012 case PEOF:
13013 RETURN(TEOF);
13014 case '&':
Denys Vlasenko220be532018-03-31 19:21:31 +020013015 if (pgetc_eatbnl() == '&')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013016 RETURN(TAND);
13017 pungetc();
13018 RETURN(TBACKGND);
13019 case '|':
Denys Vlasenko220be532018-03-31 19:21:31 +020013020 if (pgetc_eatbnl() == '|')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013021 RETURN(TOR);
13022 pungetc();
13023 RETURN(TPIPE);
13024 case ';':
Denys Vlasenko220be532018-03-31 19:21:31 +020013025 if (pgetc_eatbnl() == ';')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013026 RETURN(TENDCASE);
13027 pungetc();
13028 RETURN(TSEMI);
13029 case '(':
13030 RETURN(TLP);
13031 case ')':
13032 RETURN(TRP);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013033 }
Denys Vlasenko220be532018-03-31 19:21:31 +020013034 break;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013035 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013036 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
13037#undef RETURN
13038}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000013039#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013040
13041static int
13042readtoken(void)
13043{
13044 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000013045 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013046#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000013047 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013048#endif
13049
13050#if ENABLE_ASH_ALIAS
13051 top:
13052#endif
13053
13054 t = xxreadtoken();
13055
13056 /*
13057 * eat newlines
13058 */
Ron Yorston713f07d2015-10-29 16:44:56 +000013059 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013060 while (t == TNL) {
13061 parseheredoc();
13062 t = xxreadtoken();
13063 }
13064 }
13065
13066 if (t != TWORD || quoteflag) {
13067 goto out;
13068 }
13069
13070 /*
13071 * check for keywords
13072 */
Ron Yorston713f07d2015-10-29 16:44:56 +000013073 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013074 const char *const *pp;
13075
13076 pp = findkwd(wordtext);
13077 if (pp) {
13078 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020013079 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013080 goto out;
13081 }
13082 }
13083
13084 if (checkkwd & CHKALIAS) {
13085#if ENABLE_ASH_ALIAS
13086 struct alias *ap;
13087 ap = lookupalias(wordtext, 1);
13088 if (ap != NULL) {
13089 if (*ap->val) {
13090 pushstring(ap->val, ap);
13091 }
13092 goto top;
13093 }
13094#endif
13095 }
13096 out:
13097 checkkwd = 0;
13098#if DEBUG
13099 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020013100 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013101 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020013102 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013103#endif
13104 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000013105}
13106
Ron Yorstonc0e00762015-10-29 11:30:55 +000013107static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000013108peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013109{
13110 int t;
13111
13112 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000013113 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000013114 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013115}
Eric Andersencb57d552001-06-28 07:25:16 +000013116
13117/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013118 * Read and parse a command. Returns NODE_EOF on end of file.
13119 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000013120 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013121static union node *
13122parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000013123{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013124 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000013125 checkkwd = 0;
13126 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013127 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020013128 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013129 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013130 return list(1);
13131}
13132
13133/*
13134 * Input any here documents.
13135 */
13136static void
13137parseheredoc(void)
13138{
13139 struct heredoc *here;
13140 union node *n;
13141
13142 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000013143 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013144
13145 while (here) {
Christoph Schulz03ad7ae2018-11-20 17:45:52 +010013146 tokpushback = 0;
Denys Vlasenko958581a2010-09-12 15:04:27 +020013147 setprompt_if(needprompt, 2);
Denys Vlasenkoacf79f92020-02-14 16:12:06 +010013148 if (here->here->type == NHERE)
13149 readtoken1(pgetc(), SQSYNTAX, here->eofmark, here->striptabs);
13150 else
13151 readtoken1(pgetc_eatbnl(), DQSYNTAX, here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000013152 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013153 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000013154 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000013155 n->narg.text = wordtext;
13156 n->narg.backquote = backquotelist;
13157 here->here->nhere.doc = n;
13158 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000013159 }
Eric Andersencb57d552001-06-28 07:25:16 +000013160}
13161
13162
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013163static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020013164expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013165{
13166 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020013167 int saveprompt;
Ron Yorston48645b82019-04-18 09:48:13 +010013168 struct parsefile *file_stop = g_parsefile;
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013169 volatile int saveint;
13170 struct jmploc *volatile savehandler = exception_handler;
13171 struct jmploc jmploc;
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013172 const char *volatile result;
13173 int err;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013174
Denys Vlasenko46999802017-07-29 21:12:29 +020013175 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013176 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020013177
13178 saveprompt = doprompt;
13179 doprompt = 0;
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013180 result = ps;
13181
13182 SAVE_INT(saveint);
13183 err = setjmp(jmploc.loc);
13184 if (err)
13185 goto out;
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020013186
13187 /* readtoken1() might die horribly.
Denys Vlasenko3c183a82017-10-12 19:35:42 +020013188 * Try a prompt with syntactically wrong command:
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020013189 * PS1='$(date "+%H:%M:%S) > '
13190 */
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013191 exception_handler = &jmploc;
13192 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013193
13194 n.narg.type = NARG;
13195 n.narg.next = NULL;
13196 n.narg.text = wordtext;
13197 n.narg.backquote = backquotelist;
13198
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013199 /* expandarg() might fail too:
13200 * PS1='$((123+))'
13201 */
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013202 expandarg(&n, NULL, EXP_QUOTED);
13203 result = stackblock();
13204
13205out:
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013206 exception_handler = savehandler;
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013207 if (err && exception_type != EXERROR)
13208 longjmp(exception_handler->loc, 1);
Ron Yorstond1a2fa22019-04-18 09:49:13 +010013209 RESTORE_INT(saveint);
13210
Ron Yorstonb0c711e2020-01-23 11:26:08 +000013211 doprompt = saveprompt;
13212 /* Try: PS1='`xxx(`' */
13213 unwindfiles(file_stop);
13214
13215 return result;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013216}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013217
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013218static inline int
13219parser_eof(void)
13220{
13221 return tokpushback && lasttoken == TEOF;
13222}
13223
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013224/*
13225 * Execute a command or commands contained in a string.
13226 */
13227static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013228evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000013229{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010013230 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013231 struct jmploc jmploc;
13232 int ex;
13233
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013234 union node *n;
13235 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013236 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013237
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013238 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013239 setinputstring(s);
13240 setstackmark(&smark);
13241
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013242 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013243 /* On exception inside execution loop, we must popfile().
13244 * Try interactively:
13245 * readonly a=a
13246 * command eval "a=b" # throws "is read only" error
13247 * "command BLTIN" is not supposed to abort (even in non-interactive use).
13248 * But if we skip popfile(), we hit EOF in eval's string, and exit.
13249 */
13250 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013251 ex = setjmp(jmploc.loc);
13252 if (ex)
13253 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010013254 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013255
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013256 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013257 int i;
13258
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013259 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013260 if (n)
13261 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013262 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013263 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013264 break;
13265 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013266 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013267 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013268 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013269 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013270
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013271 exception_handler = savehandler;
13272 if (ex)
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013273 longjmp(exception_handler->loc, ex);
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013274
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013275 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000013276}
13277
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013278/*
13279 * The eval command.
13280 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013281static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013282evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013283{
13284 char *p;
13285 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013286
Denis Vlasenko68404f12008-03-17 09:00:54 +000013287 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013288 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013289 argv += 2;
13290 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013291 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013292 for (;;) {
13293 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013294 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013295 if (p == NULL)
13296 break;
13297 STPUTC(' ', concat);
13298 }
13299 STPUTC('\0', concat);
13300 p = grabstackstr(concat);
13301 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013302 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013303 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013304 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013305}
13306
13307/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010013308 * Read and execute commands.
13309 * "Top" is nonzero for the top level command loop;
13310 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013311 */
13312static int
13313cmdloop(int top)
13314{
13315 union node *n;
13316 struct stackmark smark;
13317 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013318 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013319 int numeof = 0;
13320
13321 TRACE(("cmdloop(%d) called\n", top));
13322 for (;;) {
13323 int skip;
13324
13325 setstackmark(&smark);
13326#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000013327 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020013328 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013329#endif
13330 inter = 0;
13331 if (iflag && top) {
13332 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013333 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013334 }
13335 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020013336#if DEBUG
13337 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020013338 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000013339#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013340 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013341 if (!top || numeof >= 50)
13342 break;
13343 if (!stoppedjobs()) {
Denys Vlasenko226b8a12020-02-16 18:57:53 +010013344 if (!Iflag) {
13345 if (iflag) {
13346 newline_and_flush(stderr);
13347 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013348 break;
Denys Vlasenko226b8a12020-02-16 18:57:53 +010013349 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013350 out2str("\nUse \"exit\" to leave shell.\n");
13351 }
13352 numeof++;
13353 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013354 int i;
13355
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000013356 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13357 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013358 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013359 i = evaltree(n, 0);
13360 if (n)
13361 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013362 }
13363 popstackmark(&smark);
13364 skip = evalskip;
13365
13366 if (skip) {
Denys Vlasenkocd24a502020-02-20 16:47:01 +010013367 evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
Denys Vlasenko0840c912016-10-01 15:27:44 +020013368 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013369 }
13370 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013371 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013372}
13373
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013374/*
13375 * Take commands from a file. To be compatible we should do a path
13376 * search for the file, which is necessary to find sub-commands.
13377 */
13378static char *
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013379find_dot_file(char *basename)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013380{
13381 char *fullname;
13382 const char *path = pathval();
13383 struct stat statb;
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013384 int len;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013385
13386 /* don't try this for absolute or relative paths */
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013387 if (strchr(basename, '/'))
13388 return basename;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013389
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013390 while ((len = padvance(&path, basename)) >= 0) {
13391 fullname = stackblock();
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010013392 if ((!pathopt || *pathopt == 'f')
13393 && !stat(fullname, &statb) && S_ISREG(statb.st_mode)
13394 ) {
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013395 /* This will be freed by the caller. */
13396 return stalloc(len);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013397 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013398 }
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013399 /* not found in PATH */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013400
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013401#if ENABLE_ASH_BASH_SOURCE_CURDIR
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013402 return basename;
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013403#else
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013404 ash_msg_and_raise_error("%s: not found", basename);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013405 /* NOTREACHED */
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013406#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013407}
13408
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013409static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013410dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013411{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013412 /* "false; . empty_file; echo $?" should print 0, not 1: */
13413 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013414 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013415 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013416 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013417 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013418
Denys Vlasenko981a0562017-07-26 19:53:11 +020013419//???
13420// struct strlist *sp;
13421// for (sp = cmdenviron; sp; sp = sp->next)
13422// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013423
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013424 nextopt(nullstr); /* handle possible "--" */
13425 argv = argptr;
13426
13427 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013428 /* bash says: "bash: .: filename argument required" */
13429 return 2; /* bash compat */
13430 }
13431
Denys Vlasenko091f8312013-03-17 14:25:22 +010013432 /* This aborts if file isn't found, which is POSIXly correct.
13433 * bash returns exitcode 1 instead.
13434 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013435 fullname = find_dot_file(argv[0]);
13436 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013437 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013438 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013439 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013440 saveparam = shellparam;
13441 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013442 argc = 1;
13443 while (argv[argc])
13444 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013445 shellparam.nparam = argc;
13446 shellparam.p = argv;
13447 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013448
Denys Vlasenko091f8312013-03-17 14:25:22 +010013449 /* This aborts if file can't be opened, which is POSIXly correct.
13450 * bash returns exitcode 1 instead.
13451 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013452 setinputfile(fullname, INPUT_PUSH_FILE);
13453 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013454 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013455 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013456
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013457 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013458 freeparam(&shellparam);
13459 shellparam = saveparam;
13460 };
13461
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013462 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013463}
13464
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013465static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013466exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013467{
13468 if (stoppedjobs())
13469 return 0;
Denys Vlasenko4ccddc82020-02-14 17:27:18 +010013470
Denys Vlasenko970470e2020-02-14 17:32:22 +010013471 if (argv[1])
13472 savestatus = number(argv[1]);
Denys Vlasenko4ccddc82020-02-14 17:27:18 +010013473
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013474 raise_exception(EXEXIT);
13475 /* NOTREACHED */
13476}
13477
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013478/*
13479 * Read a file containing shell functions.
13480 */
13481static void
13482readcmdfile(char *name)
13483{
13484 setinputfile(name, INPUT_PUSH_FILE);
13485 cmdloop(0);
13486 popfile();
13487}
13488
13489
Denis Vlasenkocc571512007-02-23 21:10:35 +000013490/* ============ find_command inplementation */
13491
13492/*
13493 * Resolve a command name. If you change this routine, you may have to
13494 * change the shellexec routine as well.
13495 */
13496static void
13497find_command(char *name, struct cmdentry *entry, int act, const char *path)
13498{
13499 struct tblentry *cmdp;
13500 int idx;
13501 int prev;
13502 char *fullname;
13503 struct stat statb;
13504 int e;
13505 int updatetbl;
13506 struct builtincmd *bcmd;
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013507 int len;
Denis Vlasenkocc571512007-02-23 21:10:35 +000013508
13509 /* If name contains a slash, don't use PATH or hash table */
13510 if (strchr(name, '/') != NULL) {
13511 entry->u.index = -1;
13512 if (act & DO_ABS) {
13513 while (stat(name, &statb) < 0) {
13514#ifdef SYSV
13515 if (errno == EINTR)
13516 continue;
13517#endif
13518 entry->cmdtype = CMDUNKNOWN;
13519 return;
13520 }
13521 }
13522 entry->cmdtype = CMDNORMAL;
13523 return;
13524 }
13525
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013526/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013527
13528 updatetbl = (path == pathval());
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013529 if (!updatetbl)
Denis Vlasenkocc571512007-02-23 21:10:35 +000013530 act |= DO_ALTPATH;
Denis Vlasenkocc571512007-02-23 21:10:35 +000013531
13532 /* If name is in the table, check answer will be ok */
13533 cmdp = cmdlookup(name, 0);
13534 if (cmdp != NULL) {
13535 int bit;
13536
13537 switch (cmdp->cmdtype) {
13538 default:
13539#if DEBUG
13540 abort();
13541#endif
13542 case CMDNORMAL:
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013543 bit = DO_ALTPATH | DO_REGBLTIN;
Denis Vlasenkocc571512007-02-23 21:10:35 +000013544 break;
13545 case CMDFUNCTION:
13546 bit = DO_NOFUNC;
13547 break;
13548 case CMDBUILTIN:
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013549 bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_REGBLTIN;
Denis Vlasenkocc571512007-02-23 21:10:35 +000013550 break;
13551 }
13552 if (act & bit) {
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013553 if (act & bit & DO_REGBLTIN)
13554 goto fail;
13555
Denis Vlasenkocc571512007-02-23 21:10:35 +000013556 updatetbl = 0;
13557 cmdp = NULL;
13558 } else if (cmdp->rehash == 0)
13559 /* if not invalidated by cd, we're done */
13560 goto success;
13561 }
13562
13563 /* If %builtin not in path, check for builtin next */
13564 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013565 if (bcmd) {
13566 if (IS_BUILTIN_REGULAR(bcmd))
13567 goto builtin_success;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013568 if (act & DO_ALTPATH)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013569 goto builtin_success;
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013570 if (builtinloc <= 0)
13571 goto builtin_success;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013572 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013573
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013574 if (act & DO_REGBLTIN)
13575 goto fail;
13576
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013577#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000013578 {
13579 int applet_no = find_applet_by_name(name);
13580 if (applet_no >= 0) {
13581 entry->cmdtype = CMDNORMAL;
13582 entry->u.index = -2 - applet_no;
13583 return;
13584 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013585 }
13586#endif
13587
Denis Vlasenkocc571512007-02-23 21:10:35 +000013588 /* We have to search path. */
13589 prev = -1; /* where to start */
13590 if (cmdp && cmdp->rehash) { /* doing a rehash */
13591 if (cmdp->cmdtype == CMDBUILTIN)
13592 prev = builtinloc;
13593 else
13594 prev = cmdp->param.index;
13595 }
13596
13597 e = ENOENT;
13598 idx = -1;
13599 loop:
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013600 while ((len = padvance(&path, name)) >= 0) {
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010013601 const char *lpathopt = pathopt;
13602
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013603 fullname = stackblock();
Denis Vlasenkocc571512007-02-23 21:10:35 +000013604 idx++;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010013605 if (lpathopt) {
13606 if (*lpathopt == 'b') {
Denis Vlasenkocc571512007-02-23 21:10:35 +000013607 if (bcmd)
13608 goto builtin_success;
13609 continue;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010013610 } else if (!(act & DO_NOFUNC)) {
13611 /* handled below */
13612 } else {
13613 /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013614 continue;
13615 }
13616 }
13617 /* if rehash, don't redo absolute path names */
13618 if (fullname[0] == '/' && idx <= prev) {
13619 if (idx < prev)
13620 continue;
13621 TRACE(("searchexec \"%s\": no change\n", name));
13622 goto success;
13623 }
13624 while (stat(fullname, &statb) < 0) {
13625#ifdef SYSV
13626 if (errno == EINTR)
13627 continue;
13628#endif
13629 if (errno != ENOENT && errno != ENOTDIR)
13630 e = errno;
13631 goto loop;
13632 }
13633 e = EACCES; /* if we fail, this will be the error */
13634 if (!S_ISREG(statb.st_mode))
13635 continue;
Denys Vlasenko6c4f87e2020-02-17 16:02:40 +010013636 if (lpathopt) { /* this is a %func directory */
Denys Vlasenkob0d2dc72020-02-17 15:27:41 +010013637 stalloc(len);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013638 /* NB: stalloc will return space pointed by fullname
13639 * (because we don't have any intervening allocations
13640 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013641 readcmdfile(fullname);
13642 cmdp = cmdlookup(name, 0);
13643 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13644 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13645 stunalloc(fullname);
13646 goto success;
13647 }
13648 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13649 if (!updatetbl) {
13650 entry->cmdtype = CMDNORMAL;
13651 entry->u.index = idx;
13652 return;
13653 }
13654 INT_OFF;
13655 cmdp = cmdlookup(name, 1);
13656 cmdp->cmdtype = CMDNORMAL;
13657 cmdp->param.index = idx;
13658 INT_ON;
13659 goto success;
13660 }
13661
13662 /* We failed. If there was an entry for this command, delete it */
13663 if (cmdp && updatetbl)
13664 delete_cmd_entry();
William Pitcockd8fd88a2018-01-24 18:33:18 +010013665 if (act & DO_ERR) {
13666#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13667 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13668 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13669 char *argv[3];
13670 argv[0] = (char*) "command_not_found_handle";
13671 argv[1] = name;
13672 argv[2] = NULL;
13673 evalfun(hookp->param.func, 2, argv, 0);
13674 entry->cmdtype = CMDUNKNOWN;
13675 return;
13676 }
13677#endif
Denis Vlasenkocc571512007-02-23 21:10:35 +000013678 ash_msg("%s: %s", name, errmsg(e, "not found"));
William Pitcockd8fd88a2018-01-24 18:33:18 +010013679 }
Denys Vlasenko7eb8eec2020-02-19 15:15:13 +010013680 fail:
Denis Vlasenkocc571512007-02-23 21:10:35 +000013681 entry->cmdtype = CMDUNKNOWN;
13682 return;
13683
13684 builtin_success:
13685 if (!updatetbl) {
13686 entry->cmdtype = CMDBUILTIN;
13687 entry->u.cmd = bcmd;
13688 return;
13689 }
13690 INT_OFF;
13691 cmdp = cmdlookup(name, 1);
13692 cmdp->cmdtype = CMDBUILTIN;
13693 cmdp->param.cmd = bcmd;
13694 INT_ON;
13695 success:
13696 cmdp->rehash = 0;
13697 entry->cmdtype = cmdp->cmdtype;
13698 entry->u = cmdp->param;
13699}
13700
13701
Eric Andersencb57d552001-06-28 07:25:16 +000013702/*
Eric Andersencb57d552001-06-28 07:25:16 +000013703 * The trap builtin.
13704 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013705static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013706trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013707{
13708 char *action;
13709 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013710 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013711
Eric Andersenc470f442003-07-28 09:56:35 +000013712 nextopt(nullstr);
13713 ap = argptr;
13714 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013715 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013716 char *tr = trap_ptr[signo];
13717 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013718 /* note: bash adds "SIG", but only if invoked
13719 * as "bash". If called as "sh", or if set -o posix,
13720 * then it prints short signal names.
13721 * We are printing short names: */
13722 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013723 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013724 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013725 /* trap_ptr != trap only if we are in special-cased `trap` code.
13726 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013727 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013728 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013729 }
13730 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013731 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013732 if (trap_ptr != trap) {
13733 free(trap_ptr);
13734 trap_ptr = trap;
13735 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013736 */
Eric Andersencb57d552001-06-28 07:25:16 +000013737 return 0;
13738 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013739
Denys Vlasenko86981e32017-07-25 20:06:17 +020013740 /* Why the second check?
13741 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13742 * In this case, NUM is signal no, not an action.
13743 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013744 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013745 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013746 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013747
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013748 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013749 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013750 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013751 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013752 /* Mimic bash message exactly */
13753 ash_msg("%s: invalid signal specification", *ap);
13754 exitcode = 1;
13755 goto next;
13756 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013757 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013758 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013759 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013760 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013761 else {
13762 if (action[0]) /* not NULL and not "" and not "-" */
13763 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013764 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013765 }
Eric Andersencb57d552001-06-28 07:25:16 +000013766 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013767 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013768 trap[signo] = action;
13769 if (signo != 0)
13770 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013771 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013772 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013773 ap++;
13774 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013775 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013776}
13777
Eric Andersenc470f442003-07-28 09:56:35 +000013778
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013779/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013780
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013781#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013782static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013783helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013784{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013785 unsigned col;
13786 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013787
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013788 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013789 "Built-in commands:\n"
13790 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013791 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013792 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013793 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013794 if (col > 60) {
13795 out1fmt("\n");
13796 col = 0;
13797 }
13798 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013799# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013800 {
13801 const char *a = applet_names;
13802 while (*a) {
13803 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13804 if (col > 60) {
13805 out1fmt("\n");
13806 col = 0;
13807 }
Ron Yorston2b919582016-04-08 11:57:20 +010013808 while (*a++ != '\0')
13809 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013810 }
13811 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013812# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013813 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013814 return EXIT_SUCCESS;
13815}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013816#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013817
Flemming Madsend96ffda2013-04-07 18:47:24 +020013818#if MAX_HISTORY
13819static int FAST_FUNC
13820historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13821{
Ron Yorston9f3b4102019-12-16 09:31:10 +000013822 show_history(line_input_state);
Flemming Madsend96ffda2013-04-07 18:47:24 +020013823 return EXIT_SUCCESS;
13824}
13825#endif
13826
Eric Andersencb57d552001-06-28 07:25:16 +000013827/*
Eric Andersencb57d552001-06-28 07:25:16 +000013828 * The export and readonly commands.
13829 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013830static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013831exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013832{
13833 struct var *vp;
13834 char *name;
13835 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013836 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013837 char opt;
13838 int flag;
13839 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013840
Denys Vlasenkod5275882012-10-01 13:41:17 +020013841 /* "readonly" in bash accepts, but ignores -n.
13842 * We do the same: it saves a conditional in nextopt's param.
13843 */
13844 flag_off = 0;
13845 while ((opt = nextopt("np")) != '\0') {
13846 if (opt == 'n')
13847 flag_off = VEXPORT;
13848 }
13849 flag = VEXPORT;
13850 if (argv[0][0] == 'r') {
13851 flag = VREADONLY;
13852 flag_off = 0; /* readonly ignores -n */
13853 }
13854 flag_off = ~flag_off;
13855
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013856 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013857 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013858 aptr = argptr;
13859 name = *aptr;
13860 if (name) {
13861 do {
13862 p = strchr(name, '=');
13863 if (p != NULL) {
13864 p++;
13865 } else {
13866 vp = *findvar(hashvar(name), name);
13867 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013868 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013869 continue;
13870 }
Eric Andersencb57d552001-06-28 07:25:16 +000013871 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013872 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013873 } while ((name = *++aptr) != NULL);
13874 return 0;
13875 }
Eric Andersencb57d552001-06-28 07:25:16 +000013876 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013877
13878 /* No arguments. Show the list of exported or readonly vars.
13879 * -n is ignored.
13880 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013881 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013882 return 0;
13883}
13884
Eric Andersencb57d552001-06-28 07:25:16 +000013885/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013886 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013887 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013888static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013889unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013890{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013891 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013892
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013893 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013894 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013895 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013896}
13897
Eric Andersencb57d552001-06-28 07:25:16 +000013898/*
Eric Andersencb57d552001-06-28 07:25:16 +000013899 * The unset builtin command. We unset the function before we unset the
13900 * variable to allow a function to be unset when there is a readonly variable
13901 * with the same name.
13902 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013903static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013904unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013905{
13906 char **ap;
13907 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013908 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013909
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013910 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013911 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013912 }
Eric Andersencb57d552001-06-28 07:25:16 +000013913
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013914 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013915 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013916 unsetvar(*ap);
13917 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013918 }
13919 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013920 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013921 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013922 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013923}
13924
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013925static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013926 ' ', offsetof(struct tms, tms_utime),
13927 '\n', offsetof(struct tms, tms_stime),
13928 ' ', offsetof(struct tms, tms_cutime),
13929 '\n', offsetof(struct tms, tms_cstime),
13930 0
13931};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013932static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013933timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013934{
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013935 unsigned clk_tck;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013936 const unsigned char *p;
13937 struct tms buf;
13938
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013939 clk_tck = bb_clk_tck();
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013940
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013941 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013942 p = timescmd_str;
13943 do {
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013944 unsigned sec, frac;
13945 unsigned long t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013946 t = *(clock_t *)(((char *) &buf) + p[1]);
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013947 sec = t / clk_tck;
13948 frac = t % clk_tck;
13949 out1fmt("%um%u.%03us%c",
13950 sec / 60, sec % 60,
13951 (frac * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013952 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013953 p += 2;
13954 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013955
Eric Andersencb57d552001-06-28 07:25:16 +000013956 return 0;
13957}
13958
Denys Vlasenko0b883582016-12-23 16:49:07 +010013959#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013960/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013961 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013962 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013963 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013964 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013965 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013966static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013967letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013968{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013969 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013970
Denis Vlasenko68404f12008-03-17 09:00:54 +000013971 argv++;
13972 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013973 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013974 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013975 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013976 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013977
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013978 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013979}
Eric Andersenc470f442003-07-28 09:56:35 +000013980#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013981
Eric Andersenc470f442003-07-28 09:56:35 +000013982/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013983 * The read builtin. Options:
13984 * -r Do not interpret '\' specially
13985 * -s Turn off echo (tty only)
13986 * -n NCHARS Read NCHARS max
13987 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13988 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13989 * -u FD Read from given FD instead of fd 0
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013990 * -d DELIM End on DELIM char, not newline
Eric Andersenc470f442003-07-28 09:56:35 +000013991 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013992 * TODO: bash also has:
13993 * -a ARRAY Read into array[0],[1],etc
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013994 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013995 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013996static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013997readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013998{
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013999 struct builtin_read_params params;
Denys Vlasenko73067272010-01-12 22:11:24 +010014000 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000014001 int i;
14002
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014003 memset(&params, 0, sizeof(params));
14004
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020014005 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000014006 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000014007 case 'p':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014008 params.opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000014009 break;
Paul Fox02eb9342005-09-07 16:56:02 +000014010 case 'n':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014011 params.opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000014012 break;
14013 case 's':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014014 params.read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000014015 break;
Paul Fox02eb9342005-09-07 16:56:02 +000014016 case 't':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014017 params.opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000014018 break;
Paul Fox02eb9342005-09-07 16:56:02 +000014019 case 'r':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014020 params.read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000014021 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000014022 case 'u':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014023 params.opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000014024 break;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020014025#if BASH_READ_D
14026 case 'd':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014027 params.opt_d = optionarg;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020014028 break;
14029#endif
Paul Fox02eb9342005-09-07 16:56:02 +000014030 default:
14031 break;
14032 }
Eric Andersenc470f442003-07-28 09:56:35 +000014033 }
Paul Fox02eb9342005-09-07 16:56:02 +000014034
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014035 params.argv = argptr;
14036 params.setvar = setvar0;
14037 params.ifs = bltinlookup("IFS"); /* can be NULL */
14038
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020014039 /* "read -s" needs to save/restore termios, can't allow ^C
14040 * to jump out of it.
14041 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020014042 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020014043 INT_OFF;
Denys Vlasenko19358cc2018-08-05 15:42:29 +020014044 r = shell_builtin_read(&params);
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020014045 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000014046
Denys Vlasenkof5470412017-05-22 19:34:45 +020014047 if ((uintptr_t)r == 1 && errno == EINTR) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014048 /* To get SIGCHLD: sleep 1 & read x; echo $x
14049 * Correct behavior is to not exit "read"
14050 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020014051 if (pending_sig == 0)
14052 goto again;
14053 }
14054
Denys Vlasenko73067272010-01-12 22:11:24 +010014055 if ((uintptr_t)r > 1)
14056 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000014057
Denys Vlasenko73067272010-01-12 22:11:24 +010014058 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000014059}
14060
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020014061static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020014062umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000014063{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014064 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000014065
Eric Andersenc470f442003-07-28 09:56:35 +000014066 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000014067 int symbolic_mode = 0;
14068
14069 while (nextopt("S") != '\0') {
14070 symbolic_mode = 1;
14071 }
14072
Denis Vlasenkob012b102007-02-19 22:43:01 +000014073 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000014074 mask = umask(0);
14075 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000014076 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000014077
Denys Vlasenko6283f982015-10-07 16:56:20 +020014078 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000014079 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020014080 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000014081 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014082 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000014083
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014084 i = 2;
14085 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020014086 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000014087 *p++ = permuser[i];
14088 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014089 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020014090 if (!(mask & 0400)) *p++ = 'r';
14091 if (!(mask & 0200)) *p++ = 'w';
14092 if (!(mask & 0100)) *p++ = 'x';
14093 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014094 if (--i < 0)
14095 break;
Eric Andersenc470f442003-07-28 09:56:35 +000014096 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020014097 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020014098 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000014099 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020014100 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000014101 }
14102 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020014103 char *modestr = *argptr;
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020014104 /* numeric umasks are taken as-is */
14105 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
Denys Vlasenko6283f982015-10-07 16:56:20 +020014106 if (!isdigit(modestr[0]))
14107 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020014108 mask = bb_parse_mode(modestr, mask);
14109 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020014110 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000014111 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020014112 if (!isdigit(modestr[0]))
14113 mask ^= 0777;
14114 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000014115 }
14116 return 0;
14117}
14118
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020014119static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010014120ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000014121{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010014122 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000014123}
14124
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014125/* ============ main() and helpers */
14126
14127/*
Denys Vlasenkof977e002020-02-20 16:54:29 +010014128 * This routine is called when an error or an interrupt occurs in an
14129 * interactive shell and control is returned to the main command loop
14130 * but prior to exitshell.
14131 */
14132static void
14133exitreset(void)
14134{
14135 /* from eval.c: */
14136 if (savestatus >= 0) {
14137 if (exception_type == EXEXIT || evalskip == SKIPFUNCDEF)
14138 exitstatus = savestatus;
14139 savestatus = -1;
14140 }
14141 evalskip = 0;
14142 loopnest = 0;
14143
14144 /* from expand.c: */
14145 ifsfree();
14146
14147 /* from redir.c: */
14148 unwindredir(NULL);
14149}
14150
14151/*
14152 * This routine is called when an error or an interrupt occurs in an
14153 * interactive shell and control is returned to the main command loop.
14154 * (In dash, this function is auto-generated by build machinery).
14155 */
14156static void
14157reset(void)
14158{
14159 /* from input.c: */
14160 g_parsefile->left_in_buffer = 0;
14161 g_parsefile->left_in_line = 0; /* clear input buffer */
Denys Vlasenko51a471d2020-12-24 00:22:24 +010014162 g_parsefile->unget = 0;
Denys Vlasenkof977e002020-02-20 16:54:29 +010014163 popallfiles();
14164
14165 /* from var.c: */
14166 unwindlocalvars(NULL);
14167}
14168
14169/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014170 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014171 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014172static void
14173exitshell(void)
14174{
14175 struct jmploc loc;
14176 char *p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014177
Denys Vlasenkobede2152011-09-04 16:12:33 +020014178#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
Denys Vlasenko00eb23b2020-12-21 21:36:58 +010014179 save_history(line_input_state); /* may be NULL */
Denys Vlasenkobede2152011-09-04 16:12:33 +020014180#endif
Denys Vlasenko4ccddc82020-02-14 17:27:18 +010014181 savestatus = exitstatus;
14182 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
14183 if (setjmp(loc.loc))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014184 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014185 exception_handler = &loc;
14186 p = trap[0];
14187 if (p) {
14188 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020014189 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014190 evalstring(p, 0);
Denys Vlasenkof977e002020-02-20 16:54:29 +010014191 evalskip = SKIPFUNCDEF;
Denys Vlasenkof37e1152016-10-07 03:17:28 +020014192 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014193 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014194 out:
Denys Vlasenkof977e002020-02-20 16:54:29 +010014195 exitreset();
Denys Vlasenkof37e1152016-10-07 03:17:28 +020014196 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14197 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
14198 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014199 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020014200 flush_stdout_stderr();
Denys Vlasenkof977e002020-02-20 16:54:29 +010014201 _exit(exitstatus);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014202 /* NOTREACHED */
14203}
14204
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014205/* Don't inline: conserve stack of caller from having our locals too */
14206static NOINLINE void
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000014207init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014208{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020014209 /* we will never free this */
14210 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denys Vlasenko0485b672017-08-14 19:46:56 +020014211 basepf.linno = 1;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014212
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014213 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
Denys Vlasenko458c1f22016-10-27 23:51:19 +020014214 setsignal(SIGCHLD);
14215
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014216 {
14217 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014218 const char *p;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014219
14220 initvar();
14221 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010014222/* Used to have
14223 * p = endofname(*envp);
14224 * if (p != *envp && *p == '=') {
14225 * here to weed out badly-named variables, but this breaks
14226 * scenarios where people do want them passed to children:
14227 * import os
14228 * os.environ["test-test"]="test"
14229 * if os.fork() == 0:
14230 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
14231 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
14232 */
14233 if (strchr(*envp, '=')) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014234 setvareq(*envp, VEXPORT|VTEXTFIXED);
14235 }
14236 }
14237
Denys Vlasenko67dae152018-08-05 13:59:35 +020014238 setvareq((char*)defifsvar, VTEXTFIXED);
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020014239 setvareq((char*)defoptindvar, VTEXTFIXED);
14240
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014241 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010014242#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010014243 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010014244 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010014245#endif
14246#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020014247 if (!lookupvar("HOSTNAME")) {
14248 struct utsname uts;
14249 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014250 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020014251 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010014252#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014253 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014254 if (p) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014255 struct stat st1, st2;
Denys Vlasenkoef159702016-09-01 11:16:22 +020014256 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014257 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14258 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020014259 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014260 }
14261 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014262 setpwd(p, 0);
14263 }
14264}
14265
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014266
14267//usage:#define ash_trivial_usage
Denys Vlasenkof2ed39b2018-04-05 16:46:49 +020014268//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014269//usage:#define ash_full_usage "\n\n"
14270//usage: "Unix shell interpreter"
14271
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014272/*
14273 * Process the shell command line arguments.
14274 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014275static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000014276procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014277{
14278 int i;
14279 const char *xminusc;
14280 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014281 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014282
14283 xargv = argv;
Ron Yorston8767c122018-11-05 13:13:08 +000014284 login_sh = xargv[0] && xargv[0][0] == '-';
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014285#if NUM_SCRIPTS > 0
14286 if (minusc)
14287 goto setarg0;
14288#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014289 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000014290 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014291 xargv++;
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014292 argptr = xargv;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014293 for (i = 0; i < NOPTS; i++)
14294 optlist[i] = 2;
Denys Vlasenko897475a2019-06-01 16:35:09 +020014295 if (options(&login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000014296 /* it already printed err message */
14297 raise_exception(EXERROR);
14298 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014299 xargv = argptr;
14300 xminusc = minusc;
14301 if (*xargv == NULL) {
14302 if (xminusc)
14303 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14304 sflag = 1;
14305 }
Denys Vlasenkof3634582019-06-03 12:21:04 +020014306 if (iflag == 2 /* no explicit -i given */
14307 && sflag == 1 /* -s given (or implied) */
14308 && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */
14309 && isatty(0) && isatty(1) /* we are on tty */
14310 ) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014311 iflag = 1;
Denys Vlasenkof3634582019-06-03 12:21:04 +020014312 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014313 if (mflag == 2)
14314 mflag = iflag;
Denys Vlasenko85158b62021-01-03 12:14:58 +010014315 /* Unset options which weren't explicitly set or unset */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014316 for (i = 0; i < NOPTS; i++)
Denys Vlasenko85158b62021-01-03 12:14:58 +010014317 optlist[i] &= 1; /* same effect as "if (optlist[i] == 2) optlist[i] = 0;" */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014318#if DEBUG == 2
14319 debug = 1;
14320#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014321 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014322 if (xminusc) {
14323 minusc = *xargv++;
14324 if (*xargv)
14325 goto setarg0;
14326 } else if (!sflag) {
14327 setinputfile(*xargv, 0);
14328 setarg0:
14329 arg0 = *xargv++;
14330 commandname = arg0;
14331 }
14332
14333 shellparam.p = xargv;
14334#if ENABLE_ASH_GETOPTS
14335 shellparam.optind = 1;
14336 shellparam.optoff = -1;
14337#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014338 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014339 while (*xargv) {
14340 shellparam.nparam++;
14341 xargv++;
14342 }
Denys Vlasenko31df5a32020-12-13 16:36:28 +010014343
14344 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
14345 * Try:
14346 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
14347 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
14348 * NB: must do it before setting up signals (in optschanged())
14349 * and reading .profile etc (after we return from here):
14350 */
14351 if (iflag)
14352 signal(SIGHUP, SIG_DFL);
14353
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014354 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014355
14356 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014357}
14358
14359/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014360 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014361 */
14362static void
14363read_profile(const char *name)
14364{
Denys Vlasenko46999802017-07-29 21:12:29 +020014365 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014366 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14367 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020014368 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014369 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014370}
14371
14372#if PROFILE
14373static short profile_buf[16384];
14374extern int etext();
14375#endif
14376
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014377/*
14378 * Main routine. We initialize things, parse the arguments, execute
14379 * profiles if we're a login shell, and then call cmdloop to execute
14380 * commands. The setjmp call sets up the location to jump to when an
14381 * exception occurs. When an exception occurs the variable "state"
14382 * is used to figure out how far we had gotten.
14383 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000014384int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Ron Yorston8767c122018-11-05 13:13:08 +000014385#if NUM_SCRIPTS > 0
14386int ash_main(int argc, char **argv)
14387#else
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000014388int ash_main(int argc UNUSED_PARAM, char **argv)
Ron Yorston8767c122018-11-05 13:13:08 +000014389#endif
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014390/* note: 'argc' is used only if embedded scripts are enabled */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014391{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014392 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014393 struct jmploc jmploc;
14394 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014395 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014396
Denis Vlasenko01631112007-12-16 17:20:38 +000014397 /* Initialize global data */
14398 INIT_G_misc();
14399 INIT_G_memstack();
14400 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014401#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000014402 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014403#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014404 INIT_G_cmdtable();
14405
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014406#if PROFILE
14407 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14408#endif
14409
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014410 state = 0;
14411 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014412 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014413 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014414
Denys Vlasenkoafc91fa2020-02-17 11:22:59 +010014415 exitreset();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014416
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014417 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014418 s = state;
Denys Vlasenkof977e002020-02-20 16:54:29 +010014419 if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014420 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020014421 }
Denys Vlasenkoafc91fa2020-02-17 11:22:59 +010014422
14423 reset();
14424
Denys Vlasenkob563f622010-09-25 17:15:13 +020014425 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020014426 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020014427 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014428
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014429 popstackmark(&smark);
14430 FORCE_INT_ON; /* enable interrupts */
14431 if (s == 1)
14432 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014433 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014434 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014435 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014436 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014437 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014438 }
14439 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014440 rootpid = getpid();
14441
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014442 init();
14443 setstackmark(&smark);
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014444
14445#if NUM_SCRIPTS > 0
14446 if (argc < 0)
14447 /* Non-NULL minusc tells procargs that an embedded script is being run */
14448 minusc = get_script_content(-argc - 1);
14449#endif
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014450 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010014451#if DEBUG
14452 TRACE(("Shell args: "));
14453 trace_puts_args(argv);
14454#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000014455
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014456 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014457 const char *hp;
14458
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014459 state = 1;
14460 read_profile("/etc/profile");
14461 state1:
14462 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014463 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014464 if (hp)
14465 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014466 }
14467 state2:
14468 state = 3;
14469 if (
14470#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014471 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014472#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014473 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014474 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014475 const char *shinit = lookupvar("ENV");
14476 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014477 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014478 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014479 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014480 state3:
14481 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014482 if (minusc) {
14483 /* evalstring pushes parsefile stack.
14484 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000014485 * is one of stacked source fds.
14486 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenkof3634582019-06-03 12:21:04 +020014487
Denys Vlasenko79b3d422010-06-03 04:29:08 +020014488 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020014489 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020014490 // in save_fd_on_redirect()
Denys Vlasenkof3634582019-06-03 12:21:04 +020014491
14492 // dash: evalstring(minusc, sflag ? 0 : EV_EXIT);
14493 // The above makes
14494 // ash -sc 'echo $-'
14495 // continue reading input from stdin after running 'echo'.
14496 // bash does not do this: it prints "hBcs" and exits.
14497 evalstring(minusc, EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014498 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014499
14500 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020014501#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko3f8ec002021-01-03 10:55:39 +010014502 if (line_input_state) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014503 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014504 if (!hp) {
14505 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014506 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014507 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014508 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014509 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014510 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014511 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014512 hp = lookupvar("HISTFILE");
14513 }
14514 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014515 if (hp)
Denys Vlasenko3f8ec002021-01-03 10:55:39 +010014516 line_input_state->hist_file = xstrdup(hp);
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020014517# if ENABLE_FEATURE_SH_HISTFILESIZE
14518 hp = lookupvar("HISTFILESIZE");
14519 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14520# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014521 }
14522#endif
14523 state4: /* XXX ??? - why isn't this before the "if" statement */
14524 cmdloop(1);
14525 }
14526#if PROFILE
14527 monitor(0);
14528#endif
14529#ifdef GPROF
14530 {
14531 extern void _mcleanup(void);
14532 _mcleanup();
14533 }
14534#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020014535 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014536 exitshell();
14537 /* NOTREACHED */
14538}
14539
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014540
Eric Andersendf82f612001-06-28 07:46:40 +000014541/*-
14542 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000014543 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000014544 *
14545 * This code is derived from software contributed to Berkeley by
14546 * Kenneth Almquist.
14547 *
14548 * Redistribution and use in source and binary forms, with or without
14549 * modification, are permitted provided that the following conditions
14550 * are met:
14551 * 1. Redistributions of source code must retain the above copyright
14552 * notice, this list of conditions and the following disclaimer.
14553 * 2. Redistributions in binary form must reproduce the above copyright
14554 * notice, this list of conditions and the following disclaimer in the
14555 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000014556 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000014557 * may be used to endorse or promote products derived from this software
14558 * without specific prior written permission.
14559 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020014560 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000014561 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14562 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14563 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14564 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14565 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14566 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14567 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14568 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14569 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14570 * SUCH DAMAGE.
14571 */