blob: a01c8fa8b80a3db767bc04309253671b99969749 [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 Vlasenko771f1992010-07-16 14:31:34 +020018//config:config ASH
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020019//config: bool "ash (77 kb)"
Denys Vlasenko771f1992010-07-16 14:31:34 +020020//config: default y
21//config: depends on !NOMMU
22//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020023//config: The most complete and most pedantically correct shell included with
24//config: busybox. This shell is actually a derivative of the Debian 'dash'
25//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
26//config: (written by Kenneth Almquist) from NetBSD.
Denys Vlasenko771f1992010-07-16 14:31:34 +020027//config:
Kang-Che Sung6cd02942017-01-06 17:02:03 +010028//config:# ash options
29//config:# note: Don't remove !NOMMU part in the next line; it would break
30//config:# menuconfig's indenting.
31//config:if !NOMMU && (ASH || SH_IS_ASH || BASH_IS_ASH)
32//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +020033//config:config ASH_OPTIMIZE_FOR_SIZE
34//config: bool "Optimize for size instead of speed"
35//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010036//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020037//config:
38//config:config ASH_INTERNAL_GLOB
39//config: bool "Use internal glob() implementation"
Denys Vlasenko326edc32016-12-22 14:36:49 +010040//config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now
Denys Vlasenko0b883582016-12-23 16:49:07 +010041//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020042//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020043//config: Do not use glob() function from libc, use internal implementation.
44//config: Use this if you are getting "glob.h: No such file or directory"
45//config: or similar build errors.
46//config: Note that as of now (2017-01), uclibc and musl glob() both have bugs
47//config: which would break ash if you select N here.
Denys Vlasenkof5604222017-01-10 14:58:54 +010048//config:
49//config:config ASH_BASH_COMPAT
50//config: bool "bash-compatible extensions"
51//config: default y
52//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
53//config:
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010054//config:config ASH_BASH_SOURCE_CURDIR
55//config: bool "'source' and '.' builtins search current directory after $PATH"
56//config: default n # do not encourage non-standard behavior
Denys Vlasenko54c21112018-01-27 20:46:45 +010057//config: depends on ASH_BASH_COMPAT
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010058//config: help
59//config: This is not compliant with standards. Avoid if possible.
60//config:
William Pitcockd8fd88a2018-01-24 18:33:18 +010061//config:config ASH_BASH_NOT_FOUND_HOOK
62//config: bool "command_not_found_handle hook support"
63//config: default y
Denys Vlasenko54c21112018-01-27 20:46:45 +010064//config: depends on ASH_BASH_COMPAT
William Pitcockd8fd88a2018-01-24 18:33:18 +010065//config: help
66//config: Enable support for the 'command_not_found_handle' hook function,
67//config: from GNU bash, which allows for alternative command not found
68//config: handling.
69//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +010070//config:config ASH_JOB_CONTROL
71//config: bool "Job control"
72//config: default y
73//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
74//config:
75//config:config ASH_ALIAS
76//config: bool "Alias support"
77//config: default y
78//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020079//config:
80//config:config ASH_RANDOM_SUPPORT
81//config: bool "Pseudorandom generator and $RANDOM variable"
82//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010083//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020084//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020085//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
86//config: Each read of "$RANDOM" will generate a new pseudorandom value.
87//config: You can reset the generator by using a specified start value.
88//config: After "unset RANDOM" the generator will switch off and this
89//config: variable will no longer have special treatment.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020090//config:
91//config:config ASH_EXPAND_PRMT
92//config: bool "Expand prompt string"
93//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +010094//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko514b51d2016-10-01 14:33:08 +020095//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020096//config: $PS# may contain volatile content, such as backquote commands.
97//config: This option recreates the prompt string from the environment
98//config: variable each time it is displayed.
Denys Vlasenko514b51d2016-10-01 14:33:08 +020099//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +0100100//config:config ASH_IDLE_TIMEOUT
Denys Vlasenkof5604222017-01-10 14:58:54 +0100101//config: bool "Idle timeout variable $TMOUT"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200102//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100103//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200104//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200105//config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200106//config:
Denys Vlasenkof5604222017-01-10 14:58:54 +0100107//config:config ASH_MAIL
108//config: bool "Check for new mail in interactive shell"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200109//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100110//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200111//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200112//config: Enable "check for new mail" function:
113//config: if set, $MAIL file and $MAILPATH list of files
114//config: are checked for mtime changes, and "you have mail"
115//config: message is printed if change is detected.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200116//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100117//config:config ASH_ECHO
Denys Vlasenkof5604222017-01-10 14:58:54 +0100118//config: bool "echo builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200119//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100120//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200121//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100122//config:config ASH_PRINTF
Denys Vlasenkof5604222017-01-10 14:58:54 +0100123//config: bool "printf builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200124//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100125//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200126//config:
Denys Vlasenko265062d2017-01-10 15:13:30 +0100127//config:config ASH_TEST
Denys Vlasenkof5604222017-01-10 14:58:54 +0100128//config: bool "test builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200129//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100130//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200131//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200132//config:config ASH_HELP
133//config: bool "help builtin"
134//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100135//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenkof5604222017-01-10 14:58:54 +0100136//config:
137//config:config ASH_GETOPTS
138//config: bool "getopts builtin"
139//config: default y
140//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200141//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200142//config:config ASH_CMDCMD
Denys Vlasenkof5604222017-01-10 14:58:54 +0100143//config: bool "command builtin"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200144//config: default y
Denys Vlasenko0b883582016-12-23 16:49:07 +0100145//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
Denys Vlasenko771f1992010-07-16 14:31:34 +0200146//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200147//config: Enable support for the 'command' builtin, which allows
148//config: you to run the specified command or builtin,
149//config: even when there is a function with the same name.
Kang-Che Sung6cd02942017-01-06 17:02:03 +0100150//config:
151//config:endif # ash options
Denys Vlasenko771f1992010-07-16 14:31:34 +0200152
Denys Vlasenko20704f02011-03-23 17:59:27 +0100153//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko205d48e2017-01-29 14:57:33 +0100154// APPLET_ODDNAME:name main location suid_type help
155//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko0b883582016-12-23 16:49:07 +0100156//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
Denys Vlasenko20704f02011-03-23 17:59:27 +0100157
158//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko0b883582016-12-23 16:49:07 +0100159//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
160//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
Denys Vlasenko20704f02011-03-23 17:59:27 +0100161//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
162
Denys Vlasenko67047462016-12-22 15:21:58 +0100163/*
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100164 * DEBUG=1 to compile in debugging ('set -o debug' turns on)
165 * DEBUG=2 to compile in and turn on debugging.
166 * When debugging is on ("set -o debug" was executed, or DEBUG=2),
167 * debugging info is written to ./trace, quit signal generates core dump.
Denys Vlasenko67047462016-12-22 15:21:58 +0100168 */
169#define DEBUG 0
170/* Tweak debug output verbosity here */
171#define DEBUG_TIME 0
172#define DEBUG_PID 1
173#define DEBUG_SIG 1
174#define DEBUG_INTONOFF 0
175
176#define PROFILE 0
177
178#define JOBS ENABLE_ASH_JOB_CONTROL
179
Denys Vlasenko67047462016-12-22 15:21:58 +0100180#include <fnmatch.h>
181#include <sys/times.h>
182#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko67047462016-12-22 15:21:58 +0100183#include "busybox.h" /* for applet_names */
Ron Yorston71df2d32018-11-27 14:34:25 +0000184#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +0100185# include "embedded_scripts.h"
186#else
187# define NUM_SCRIPTS 0
188#endif
Denys Vlasenko67047462016-12-22 15:21:58 +0100189
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100190/* So far, all bash compat is controlled by one config option */
191/* Separate defines document which part of code implements what */
192/* function keyword */
193#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT
194#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT
195/* &>file */
196#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT
197#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT
198/* $'...' */
199#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT
200#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT
201#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT
202#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT
203#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT
204#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200205/* BASH_TEST2: [[ EXPR ]]
206 * Status of [[ support:
207 * We replace && and || with -a and -o
208 * TODO:
209 * singleword+noglob expansion:
210 * v='a b'; [[ $v = 'a b' ]]; echo 0:$?
Denys Vlasenko89e9d552018-04-11 01:15:33 +0200211 * [[ /bin/n* ]]; echo 0:$?
Denys Vlasenko3632cb12018-04-10 15:25:41 +0200212 * -a/-o are not AND/OR ops! (they are just strings)
213 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
214 * = is glob match operator, not equality operator: STR = GLOB
215 * (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
216 * == same as =
217 * add =~ regex match operator: STR =~ REGEX
218 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100219#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST)
220#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT
221#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT
222#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
223#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +0200224#define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT
Johannes Schindelin3bef5d82017-08-08 16:46:39 +0200225#define BASH_READ_D ENABLE_ASH_BASH_COMPAT
226#define IF_BASH_READ_D IF_ASH_BASH_COMPAT
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100227
Denys Vlasenko67047462016-12-22 15:21:58 +0100228#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
229/* Bionic at least up to version 24 has no glob() */
230# undef ENABLE_ASH_INTERNAL_GLOB
231# define ENABLE_ASH_INTERNAL_GLOB 1
232#endif
233
234#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
235# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
236# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
237# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
238# error glob() should unbackslash them and match. uClibc does not unbackslash,
239# error fails to match dirname, subsequently not expanding <pattern> in it.
240// Testcase:
241// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
242// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
243#endif
244
245#if !ENABLE_ASH_INTERNAL_GLOB
246# include <glob.h>
247#endif
248
249#include "unicode.h"
250#include "shell_common.h"
Denys Vlasenko0b883582016-12-23 16:49:07 +0100251#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko67047462016-12-22 15:21:58 +0100252# include "math.h"
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200253#else
254typedef long arith_t;
255# define ARITH_FMT "%ld"
Denys Vlasenko67047462016-12-22 15:21:58 +0100256#endif
257#if ENABLE_ASH_RANDOM_SUPPORT
258# include "random.h"
259#else
260# define CLEAR_RANDOM_T(rnd) ((void)0)
261#endif
262
263#include "NUM_APPLETS.h"
264#if NUM_APPLETS == 1
265/* STANDALONE does not make sense, and won't compile */
266# undef CONFIG_FEATURE_SH_STANDALONE
267# undef ENABLE_FEATURE_SH_STANDALONE
268# undef IF_FEATURE_SH_STANDALONE
269# undef IF_NOT_FEATURE_SH_STANDALONE
270# define ENABLE_FEATURE_SH_STANDALONE 0
271# define IF_FEATURE_SH_STANDALONE(...)
272# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
273#endif
274
Denys Vlasenko9acd63c2018-03-28 18:35:07 +0200275#ifndef F_DUPFD_CLOEXEC
276# define F_DUPFD_CLOEXEC F_DUPFD
277#endif
Denys Vlasenko60fb98e2018-03-30 22:15:14 +0200278#ifndef O_CLOEXEC
279# define O_CLOEXEC 0
280#endif
Denys Vlasenko67047462016-12-22 15:21:58 +0100281#ifndef PIPE_BUF
282# define PIPE_BUF 4096 /* amount of buffering in a pipe */
283#endif
284
285#if !BB_MMU
286# error "Do not even bother, ash will not run on NOMMU machine"
287#endif
288
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100289/* We use a trick to have more optimized code (fewer pointer reloads):
290 * ash.c: extern struct globals *const ash_ptr_to_globals;
291 * ash_ptr_hack.c: struct globals *ash_ptr_to_globals;
292 * This way, compiler in ash.c knows the pointer can not change.
293 *
294 * However, this may break on weird arches or toolchains. In this case,
295 * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable
296 * this optimization.
297 */
298#ifndef BB_GLOBAL_CONST
299# define BB_GLOBAL_CONST const
300#endif
301
Denis Vlasenkob012b102007-02-19 22:43:01 +0000302
Denis Vlasenko01631112007-12-16 17:20:38 +0000303/* ============ Hash table sizes. Configurable. */
304
305#define VTABSIZE 39
306#define ATABSIZE 39
307#define CMDTABLESIZE 31 /* should be prime */
308
309
Denis Vlasenkob012b102007-02-19 22:43:01 +0000310/* ============ Shell options */
311
312static const char *const optletters_optnames[] = {
313 "e" "errexit",
314 "f" "noglob",
315 "I" "ignoreeof",
316 "i" "interactive",
317 "m" "monitor",
318 "n" "noexec",
319 "s" "stdin",
320 "x" "xtrace",
321 "v" "verbose",
322 "C" "noclobber",
323 "a" "allexport",
324 "b" "notify",
325 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100326 "\0" "vi"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100327#if BASH_PIPEFAIL
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100328 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100329#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000330#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000331 ,"\0" "nolog"
332 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000333#endif
334};
335
Denys Vlasenko285ad152009-12-04 23:02:27 +0100336#define optletters(n) optletters_optnames[n][0]
337#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000338
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000339enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000340
Eric Andersenc470f442003-07-28 09:56:35 +0000341
Denis Vlasenkob012b102007-02-19 22:43:01 +0000342/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000343
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200344#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000345
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000346/*
Eric Andersenc470f442003-07-28 09:56:35 +0000347 * We enclose jmp_buf in a structure so that we can declare pointers to
348 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000349 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000350 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000351 * exception handlers, the user should save the value of handler on entry
352 * to an inner scope, set handler to point to a jmploc structure for the
353 * inner scope, and restore handler on exit from the scope.
354 */
Eric Andersenc470f442003-07-28 09:56:35 +0000355struct jmploc {
356 jmp_buf loc;
357};
Denis Vlasenko01631112007-12-16 17:20:38 +0000358
359struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200360 uint8_t exitstatus; /* exit status of last command */
361 uint8_t back_exitstatus;/* exit status of backquoted command */
362 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
363 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000364 /* shell level: 0 for the main shell, 1 for its children, and so on */
365 int shlvl;
366#define rootshell (!shlvl)
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100367 int errlinno;
368
Denis Vlasenko01631112007-12-16 17:20:38 +0000369 char *minusc; /* argument to -c option */
370
371 char *curdir; // = nullstr; /* current working directory */
372 char *physdir; // = nullstr; /* physical working directory */
373
374 char *arg0; /* value of $0 */
375
376 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000377
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200378 volatile int suppress_int; /* counter */
379 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200380 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +0200381 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000382 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000383 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000384#define EXINT 0 /* SIGINT received */
385#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000386#define EXEXIT 4 /* exit the shell */
Eric Andersen2870d962001-07-02 17:27:21 +0000387
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000388 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000389
390 char optlist[NOPTS];
391#define eflag optlist[0]
392#define fflag optlist[1]
393#define Iflag optlist[2]
394#define iflag optlist[3]
395#define mflag optlist[4]
396#define nflag optlist[5]
397#define sflag optlist[6]
398#define xflag optlist[7]
399#define vflag optlist[8]
400#define Cflag optlist[9]
401#define aflag optlist[10]
402#define bflag optlist[11]
403#define uflag optlist[12]
404#define viflag optlist[13]
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100405#if BASH_PIPEFAIL
Michael Abbott359da5e2009-12-04 23:03:29 +0100406# define pipefail optlist[14]
407#else
408# define pipefail 0
409#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000410#if DEBUG
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100411# define nolog optlist[14 + BASH_PIPEFAIL]
412# define debug optlist[15 + BASH_PIPEFAIL]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000413#endif
414
415 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000416 /*
417 * Sigmode records the current value of the signal handlers for the various
418 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000419 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000420 */
421 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000422#define S_DFL 1 /* default signal handling (SIG_DFL) */
423#define S_CATCH 2 /* signal is caught */
424#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenko0f14f412017-08-06 20:06:19 +0200425#define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000426
Denis Vlasenko01631112007-12-16 17:20:38 +0000427 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000428 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200429 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000430 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200431 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000432
433 /* Rarely referenced stuff */
434#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200435 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000436#endif
437 pid_t backgndpid; /* pid of last background process */
Denis Vlasenko01631112007-12-16 17:20:38 +0000438};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +0100439extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000440#define G_misc (*ash_ptr_to_globals_misc)
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200441#define exitstatus (G_misc.exitstatus )
442#define back_exitstatus (G_misc.back_exitstatus )
443#define job_warning (G_misc.job_warning)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000444#define rootpid (G_misc.rootpid )
445#define shlvl (G_misc.shlvl )
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100446#define errlinno (G_misc.errlinno )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000447#define minusc (G_misc.minusc )
448#define curdir (G_misc.curdir )
449#define physdir (G_misc.physdir )
450#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000451#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000452#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200453#define suppress_int (G_misc.suppress_int )
454#define pending_int (G_misc.pending_int )
Denys Vlasenko458c1f22016-10-27 23:51:19 +0200455#define got_sigchld (G_misc.got_sigchld )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200456#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000457#define nullstr (G_misc.nullstr )
458#define optlist (G_misc.optlist )
459#define sigmode (G_misc.sigmode )
460#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200461#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000462#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200463#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200464#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000465#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000466#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000467 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
468 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000469 curdir = nullstr; \
470 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200471 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000472} while (0)
473
474
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000475/* ============ DEBUG */
476#if DEBUG
477static void trace_printf(const char *fmt, ...);
478static void trace_vprintf(const char *fmt, va_list va);
479# define TRACE(param) trace_printf param
480# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000481# define close(fd) do { \
482 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000483 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200484 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000485 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000486} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000487#else
488# define TRACE(param)
489# define TRACEV(param)
490#endif
491
492
Denis Vlasenko559691a2008-10-05 18:39:31 +0000493/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100494#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
495#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
496
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200497static int
498isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000499{
500 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
501 while (--maxlen && isdigit(*str))
502 str++;
503 return (*str == '\0');
504}
Denis Vlasenko01631112007-12-16 17:20:38 +0000505
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200506static const char *
507var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200508{
509 while (*var)
510 if (*var++ == '=')
511 break;
512 return var;
513}
514
Denis Vlasenko559691a2008-10-05 18:39:31 +0000515
516/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100517
518static void exitshell(void) NORETURN;
519
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000520/*
Eric Andersen2870d962001-07-02 17:27:21 +0000521 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000522 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000523 * much more efficient and portable. (But hacking the kernel is so much
524 * more fun than worrying about efficiency and portability. :-))
525 */
Denys Vlasenko06b11492016-11-04 16:43:18 +0100526#if DEBUG_INTONOFF
527# define INT_OFF do { \
528 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200529 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200530 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000531} while (0)
Denys Vlasenko06b11492016-11-04 16:43:18 +0100532#else
533# define INT_OFF do { \
534 suppress_int++; \
535 barrier(); \
536} while (0)
537#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000538
539/*
540 * Called to raise an exception. Since C doesn't include exceptions, we
541 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000542 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000543 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000544static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000545static void
546raise_exception(int e)
547{
548#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000549 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000550 abort();
551#endif
552 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000553 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000554 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000555}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000556#if DEBUG
557#define raise_exception(e) do { \
558 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
559 raise_exception(e); \
560} while (0)
561#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000562
563/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200564 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000565 * that SIGINT is to be trapped or ignored using the trap builtin, then
566 * this routine is not called.) Suppressint is nonzero when interrupts
567 * are held using the INT_OFF macro. (The test for iflag is just
568 * defensive programming.)
569 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000570static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000571static void
572raise_interrupt(void)
573{
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200574 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000575 /* Signal is not automatically unmasked after it is raised,
576 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000577 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200578 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000579
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200580 if (!(rootshell && iflag)) {
581 /* Kill ourself with SIGINT */
582 signal(SIGINT, SIG_DFL);
583 raise(SIGINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000584 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200585 /* bash: ^C even on empty command line sets $? */
586 exitstatus = SIGINT + 128;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +0200587 raise_exception(EXINT);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000588 /* NOTREACHED */
589}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000590#if DEBUG
591#define raise_interrupt() do { \
592 TRACE(("raising interrupt on line %d\n", __LINE__)); \
593 raise_interrupt(); \
594} while (0)
595#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000596
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000597static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000598int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000599{
Denys Vlasenkode892052016-10-02 01:49:13 +0200600 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200601 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000602 raise_interrupt();
603 }
604}
Denys Vlasenko06b11492016-11-04 16:43:18 +0100605#if DEBUG_INTONOFF
606# define INT_ON do { \
607 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
608 int_on(); \
609} while (0)
610#else
611# define INT_ON int_on()
612#endif
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000613static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000614force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000615{
Denys Vlasenkode892052016-10-02 01:49:13 +0200616 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200617 suppress_int = 0;
618 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000619 raise_interrupt();
620}
621#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000622
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200623#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000624
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000625#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200626 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200627 suppress_int = (v); \
628 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000629 raise_interrupt(); \
630} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000631
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000632
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000633/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000634
Eric Andersenc470f442003-07-28 09:56:35 +0000635static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000636outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000637{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000638 INT_OFF;
639 fputs(p, file);
640 INT_ON;
641}
642
643static void
644flush_stdout_stderr(void)
645{
646 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100647 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000648 INT_ON;
649}
650
Denys Vlasenko9c541002015-10-07 15:44:36 +0200651/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000652static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200653newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000654{
655 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200656 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000657 fflush(dest);
658 INT_ON;
659}
660
661static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
662static int
663out1fmt(const char *fmt, ...)
664{
665 va_list ap;
666 int r;
667
668 INT_OFF;
669 va_start(ap, fmt);
670 r = vprintf(fmt, ap);
671 va_end(ap);
672 INT_ON;
673 return r;
674}
675
676static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
677static int
678fmtstr(char *outbuf, size_t length, const char *fmt, ...)
679{
680 va_list ap;
681 int ret;
682
Denis Vlasenkob012b102007-02-19 22:43:01 +0000683 INT_OFF;
Denys Vlasenkocf3a7962017-07-26 14:38:19 +0200684 va_start(ap, fmt);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000685 ret = vsnprintf(outbuf, length, fmt, ap);
686 va_end(ap);
687 INT_ON;
688 return ret;
689}
690
691static void
692out1str(const char *p)
693{
694 outstr(p, stdout);
695}
696
697static void
698out2str(const char *p)
699{
700 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100701 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000702}
703
704
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000705/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000706
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000707/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100708#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200709#define CTLESC ((unsigned char)'\201') /* escape next character */
710#define CTLVAR ((unsigned char)'\202') /* variable defn */
711#define CTLENDVAR ((unsigned char)'\203')
712#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200713#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
714#define CTLENDARI ((unsigned char)'\207')
715#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100716#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000717
718/* variable substitution byte (follows CTLVAR) */
719#define VSTYPE 0x0f /* type of variable substitution */
720#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000721
722/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000723#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
724#define VSMINUS 0x2 /* ${var-text} */
725#define VSPLUS 0x3 /* ${var+text} */
726#define VSQUESTION 0x4 /* ${var?message} */
727#define VSASSIGN 0x5 /* ${var=text} */
728#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
729#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
730#define VSTRIMLEFT 0x8 /* ${var#pattern} */
731#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
732#define VSLENGTH 0xa /* ${#var} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100733#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000734#define VSSUBSTR 0xc /* ${var:position:length} */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100735#endif
736#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000737#define VSREPLACE 0xd /* ${var/pattern/replacement} */
738#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
739#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000740
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000741static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200742 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000743};
Ron Yorston549deab2015-05-18 09:57:51 +0200744#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000745
Denis Vlasenko559691a2008-10-05 18:39:31 +0000746#define NCMD 0
747#define NPIPE 1
748#define NREDIR 2
749#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000750#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000751#define NAND 5
752#define NOR 6
753#define NSEMI 7
754#define NIF 8
755#define NWHILE 9
756#define NUNTIL 10
757#define NFOR 11
758#define NCASE 12
759#define NCLIST 13
760#define NDEFUN 14
761#define NARG 15
762#define NTO 16
Denys Vlasenko7d4aec02017-01-11 14:00:38 +0100763#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +0000764#define NTO2 17
765#endif
766#define NCLOBBER 18
767#define NFROM 19
768#define NFROMTO 20
769#define NAPPEND 21
770#define NTOFD 22
771#define NFROMFD 23
772#define NHERE 24
773#define NXHERE 25
774#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000775#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000776
777union node;
778
779struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000780 smallint type; /* Nxxxx */
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100781 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000782 union node *assign;
783 union node *args;
784 union node *redirect;
785};
786
787struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000788 smallint type;
789 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000790 struct nodelist *cmdlist;
791};
792
793struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000794 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100795 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000796 union node *n;
797 union node *redirect;
798};
799
800struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000801 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000802 union node *ch1;
803 union node *ch2;
804};
805
806struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000807 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000808 union node *test;
809 union node *ifpart;
810 union node *elsepart;
811};
812
813struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000814 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100815 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000816 union node *args;
817 union node *body;
818 char *var;
819};
820
821struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000822 smallint type;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100823 int linno;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000824 union node *expr;
825 union node *cases;
826};
827
828struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000829 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000830 union node *next;
831 union node *pattern;
832 union node *body;
833};
834
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100835struct ndefun {
836 smallint type;
837 int linno;
838 char *text;
839 union node *body;
840};
841
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000842struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000843 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000844 union node *next;
845 char *text;
846 struct nodelist *backquote;
847};
848
Denis Vlasenko559691a2008-10-05 18:39:31 +0000849/* nfile and ndup layout must match!
850 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
851 * that it is actually NTO2 (>&file), and change its type.
852 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000853struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000854 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000855 union node *next;
856 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000857 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000858 union node *fname;
859 char *expfname;
860};
861
862struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000863 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000864 union node *next;
865 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000866 int dupfd;
867 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000868 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000869};
870
871struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000872 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000873 union node *next;
874 int fd;
875 union node *doc;
876};
877
878struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000879 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000880 union node *com;
881};
882
883union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000884 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000885 struct ncmd ncmd;
886 struct npipe npipe;
887 struct nredir nredir;
888 struct nbinary nbinary;
889 struct nif nif;
890 struct nfor nfor;
891 struct ncase ncase;
892 struct nclist nclist;
Denys Vlasenko675d24a2018-01-27 22:02:05 +0100893 struct ndefun ndefun;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000894 struct narg narg;
895 struct nfile nfile;
896 struct ndup ndup;
897 struct nhere nhere;
898 struct nnot nnot;
899};
900
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200901/*
902 * NODE_EOF is returned by parsecmd when it encounters an end of file.
903 * It must be distinct from NULL.
904 */
905#define NODE_EOF ((union node *) -1L)
906
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000907struct nodelist {
908 struct nodelist *next;
909 union node *n;
910};
911
912struct funcnode {
913 int count;
914 union node n;
915};
916
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000917/*
918 * Free a parse tree.
919 */
920static void
921freefunc(struct funcnode *f)
922{
923 if (f && --f->count < 0)
924 free(f);
925}
926
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000927
928/* ============ Debugging output */
929
930#if DEBUG
931
932static FILE *tracefile;
933
934static void
935trace_printf(const char *fmt, ...)
936{
937 va_list va;
938
939 if (debug != 1)
940 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000941 if (DEBUG_TIME)
942 fprintf(tracefile, "%u ", (int) time(NULL));
943 if (DEBUG_PID)
944 fprintf(tracefile, "[%u] ", (int) getpid());
945 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200946 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000947 va_start(va, fmt);
948 vfprintf(tracefile, fmt, va);
949 va_end(va);
950}
951
952static void
953trace_vprintf(const char *fmt, va_list va)
954{
955 if (debug != 1)
956 return;
957 vfprintf(tracefile, fmt, va);
Denys Vlasenko474ed062016-10-30 18:30:29 +0100958 fprintf(tracefile, "\n");
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000959}
960
961static void
962trace_puts(const char *s)
963{
964 if (debug != 1)
965 return;
966 fputs(s, tracefile);
967}
968
969static void
970trace_puts_quoted(char *s)
971{
972 char *p;
973 char c;
974
975 if (debug != 1)
976 return;
977 putc('"', tracefile);
978 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100979 switch ((unsigned char)*p) {
980 case '\n': c = 'n'; goto backslash;
981 case '\t': c = 't'; goto backslash;
982 case '\r': c = 'r'; goto backslash;
983 case '\"': c = '\"'; goto backslash;
984 case '\\': c = '\\'; goto backslash;
985 case CTLESC: c = 'e'; goto backslash;
986 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100987 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000988 backslash:
989 putc('\\', tracefile);
990 putc(c, tracefile);
991 break;
992 default:
993 if (*p >= ' ' && *p <= '~')
994 putc(*p, tracefile);
995 else {
996 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100997 putc((*p >> 6) & 03, tracefile);
998 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000999 putc(*p & 07, tracefile);
1000 }
1001 break;
1002 }
1003 }
1004 putc('"', tracefile);
1005}
1006
1007static void
1008trace_puts_args(char **ap)
1009{
1010 if (debug != 1)
1011 return;
1012 if (!*ap)
1013 return;
1014 while (1) {
1015 trace_puts_quoted(*ap);
1016 if (!*++ap) {
1017 putc('\n', tracefile);
1018 break;
1019 }
1020 putc(' ', tracefile);
1021 }
1022}
1023
1024static void
1025opentrace(void)
1026{
1027 char s[100];
1028#ifdef O_APPEND
1029 int flags;
1030#endif
1031
1032 if (debug != 1) {
1033 if (tracefile)
1034 fflush(tracefile);
1035 /* leave open because libedit might be using it */
1036 return;
1037 }
1038 strcpy(s, "./trace");
1039 if (tracefile) {
1040 if (!freopen(s, "a", tracefile)) {
1041 fprintf(stderr, "Can't re-open %s\n", s);
1042 debug = 0;
1043 return;
1044 }
1045 } else {
1046 tracefile = fopen(s, "a");
1047 if (tracefile == NULL) {
1048 fprintf(stderr, "Can't open %s\n", s);
1049 debug = 0;
1050 return;
1051 }
1052 }
1053#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +00001054 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001055 if (flags >= 0)
1056 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
1057#endif
1058 setlinebuf(tracefile);
1059 fputs("\nTracing started.\n", tracefile);
1060}
1061
1062static void
1063indent(int amount, char *pfx, FILE *fp)
1064{
1065 int i;
1066
1067 for (i = 0; i < amount; i++) {
1068 if (pfx && i == amount - 1)
1069 fputs(pfx, fp);
1070 putc('\t', fp);
1071 }
1072}
1073
1074/* little circular references here... */
1075static void shtree(union node *n, int ind, char *pfx, FILE *fp);
1076
1077static void
1078sharg(union node *arg, FILE *fp)
1079{
1080 char *p;
1081 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001082 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001083
1084 if (arg->type != NARG) {
1085 out1fmt("<node type %d>\n", arg->type);
1086 abort();
1087 }
1088 bqlist = arg->narg.backquote;
1089 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01001090 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001091 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -07001092 p++;
1093 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001094 break;
1095 case CTLVAR:
1096 putc('$', fp);
1097 putc('{', fp);
1098 subtype = *++p;
1099 if (subtype == VSLENGTH)
1100 putc('#', fp);
1101
Dan Fandrich77d48722010-09-07 23:38:28 -07001102 while (*p != '=') {
1103 putc(*p, fp);
1104 p++;
1105 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001106
1107 if (subtype & VSNUL)
1108 putc(':', fp);
1109
1110 switch (subtype & VSTYPE) {
1111 case VSNORMAL:
1112 putc('}', fp);
1113 break;
1114 case VSMINUS:
1115 putc('-', fp);
1116 break;
1117 case VSPLUS:
1118 putc('+', fp);
1119 break;
1120 case VSQUESTION:
1121 putc('?', fp);
1122 break;
1123 case VSASSIGN:
1124 putc('=', fp);
1125 break;
1126 case VSTRIMLEFT:
1127 putc('#', fp);
1128 break;
1129 case VSTRIMLEFTMAX:
1130 putc('#', fp);
1131 putc('#', fp);
1132 break;
1133 case VSTRIMRIGHT:
1134 putc('%', fp);
1135 break;
1136 case VSTRIMRIGHTMAX:
1137 putc('%', fp);
1138 putc('%', fp);
1139 break;
1140 case VSLENGTH:
1141 break;
1142 default:
1143 out1fmt("<subtype %d>", subtype);
1144 }
1145 break;
1146 case CTLENDVAR:
1147 putc('}', fp);
1148 break;
1149 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001150 putc('$', fp);
1151 putc('(', fp);
1152 shtree(bqlist->n, -1, NULL, fp);
1153 putc(')', fp);
1154 break;
1155 default:
1156 putc(*p, fp);
1157 break;
1158 }
1159 }
1160}
1161
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001162static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001163shcmd(union node *cmd, FILE *fp)
1164{
1165 union node *np;
1166 int first;
1167 const char *s;
1168 int dftfd;
1169
1170 first = 1;
1171 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001172 if (!first)
1173 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001174 sharg(np, fp);
1175 first = 0;
1176 }
1177 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001178 if (!first)
1179 putc(' ', fp);
1180 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001181 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001182 case NTO: s = ">>"+1; dftfd = 1; break;
1183 case NCLOBBER: s = ">|"; dftfd = 1; break;
1184 case NAPPEND: s = ">>"; dftfd = 1; break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01001185#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00001186 case NTO2:
1187#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001188 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001189 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001190 case NFROMFD: s = "<&"; break;
1191 case NFROMTO: s = "<>"; break;
1192 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001193 }
1194 if (np->nfile.fd != dftfd)
1195 fprintf(fp, "%d", np->nfile.fd);
1196 fputs(s, fp);
1197 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1198 fprintf(fp, "%d", np->ndup.dupfd);
1199 } else {
1200 sharg(np->nfile.fname, fp);
1201 }
1202 first = 0;
1203 }
1204}
1205
1206static void
1207shtree(union node *n, int ind, char *pfx, FILE *fp)
1208{
1209 struct nodelist *lp;
1210 const char *s;
1211
1212 if (n == NULL)
1213 return;
1214
1215 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001216
1217 if (n == NODE_EOF) {
1218 fputs("<EOF>", fp);
1219 return;
1220 }
1221
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001222 switch (n->type) {
1223 case NSEMI:
1224 s = "; ";
1225 goto binop;
1226 case NAND:
1227 s = " && ";
1228 goto binop;
1229 case NOR:
1230 s = " || ";
1231 binop:
1232 shtree(n->nbinary.ch1, ind, NULL, fp);
1233 /* if (ind < 0) */
1234 fputs(s, fp);
1235 shtree(n->nbinary.ch2, ind, NULL, fp);
1236 break;
1237 case NCMD:
1238 shcmd(n, fp);
1239 if (ind >= 0)
1240 putc('\n', fp);
1241 break;
1242 case NPIPE:
1243 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001244 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001245 if (lp->next)
1246 fputs(" | ", fp);
1247 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001248 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001249 fputs(" &", fp);
1250 if (ind >= 0)
1251 putc('\n', fp);
1252 break;
1253 default:
1254 fprintf(fp, "<node type %d>", n->type);
1255 if (ind >= 0)
1256 putc('\n', fp);
1257 break;
1258 }
1259}
1260
1261static void
1262showtree(union node *n)
1263{
1264 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001265 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001266}
1267
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001268#endif /* DEBUG */
1269
1270
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001271/* ============ Parser data */
1272
1273/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001274 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1275 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001276struct strlist {
1277 struct strlist *next;
1278 char *text;
1279};
1280
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001281struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001282
Denis Vlasenkob012b102007-02-19 22:43:01 +00001283struct strpush {
1284 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001285 char *prev_string;
1286 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001287#if ENABLE_ASH_ALIAS
1288 struct alias *ap; /* if push was associated with an alias */
1289#endif
1290 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001291
1292 /* Remember last two characters for pungetc. */
1293 int lastc[2];
1294
1295 /* Number of outstanding calls to pungetc. */
1296 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001297};
1298
Denys Vlasenko0485b672017-08-14 19:46:56 +02001299/*
1300 * The parsefile structure pointed to by the global variable parsefile
1301 * contains information about the current file being read.
1302 */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001303struct parsefile {
1304 struct parsefile *prev; /* preceding file on stack */
1305 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001306 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001307 int left_in_line; /* number of chars left in this line */
1308 int left_in_buffer; /* number of chars left in this buffer past the line */
1309 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001310 char *buf; /* input buffer */
1311 struct strpush *strpush; /* for pushing strings at this level */
1312 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001313
1314 /* Remember last two characters for pungetc. */
1315 int lastc[2];
1316
1317 /* Number of outstanding calls to pungetc. */
1318 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001319};
1320
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001321static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001322static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001323static char *commandname; /* currently executing command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001324
1325
1326/* ============ Message printing */
1327
1328static void
1329ash_vmsg(const char *msg, va_list ap)
1330{
1331 fprintf(stderr, "%s: ", arg0);
1332 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001333 if (strcmp(arg0, commandname))
1334 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001335 if (!iflag || g_parsefile->pf_fd > 0)
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001336 fprintf(stderr, "line %d: ", errlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001337 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001338 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001339 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001340}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001341
1342/*
1343 * Exverror is called to raise the error exception. If the second argument
1344 * is not NULL then error prints an error message using printf style
1345 * formatting. It then raises the error exception.
1346 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001347static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001348static void
1349ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001350{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001351#if DEBUG
1352 if (msg) {
Denys Vlasenko474ed062016-10-30 18:30:29 +01001353 TRACE(("ash_vmsg_and_raise(%d):", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001354 TRACEV((msg, ap));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001355 } else
Denys Vlasenko474ed062016-10-30 18:30:29 +01001356 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
Denis Vlasenkob012b102007-02-19 22:43:01 +00001357 if (msg)
1358#endif
1359 ash_vmsg(msg, ap);
1360
1361 flush_stdout_stderr();
1362 raise_exception(cond);
1363 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001364}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001365
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001366static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001367static void
1368ash_msg_and_raise_error(const char *msg, ...)
1369{
1370 va_list ap;
1371
Ron Yorstonea7d2f62017-01-03 11:18:23 +01001372 exitstatus = 2;
1373
Denis Vlasenkob012b102007-02-19 22:43:01 +00001374 va_start(ap, msg);
1375 ash_vmsg_and_raise(EXERROR, msg, ap);
1376 /* NOTREACHED */
1377 va_end(ap);
1378}
1379
Ron Yorstonbe366e52017-07-27 13:53:39 +01001380/*
Ron Yorstonbe366e52017-07-27 13:53:39 +01001381 * 'fmt' must be a string literal.
1382 */
Denys Vlasenko6f97b302017-09-29 18:17:25 +02001383#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 +01001384
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001385static void raise_error_syntax(const char *) NORETURN;
1386static void
1387raise_error_syntax(const char *msg)
1388{
Denys Vlasenko675d24a2018-01-27 22:02:05 +01001389 errlinno = g_parsefile->linno;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001390 ash_msg_and_raise_error("syntax error: %s", msg);
1391 /* NOTREACHED */
1392}
1393
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001394static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001395static void
1396ash_msg_and_raise(int cond, const char *msg, ...)
1397{
1398 va_list ap;
1399
1400 va_start(ap, msg);
1401 ash_vmsg_and_raise(cond, msg, ap);
1402 /* NOTREACHED */
1403 va_end(ap);
1404}
1405
1406/*
1407 * error/warning routines for external builtins
1408 */
1409static void
1410ash_msg(const char *fmt, ...)
1411{
1412 va_list ap;
1413
1414 va_start(ap, fmt);
1415 ash_vmsg(fmt, ap);
1416 va_end(ap);
1417}
1418
1419/*
1420 * Return a string describing an error. The returned string may be a
1421 * pointer to a static buffer that will be overwritten on the next call.
1422 * Action describes the operation that got the error.
1423 */
1424static const char *
1425errmsg(int e, const char *em)
1426{
1427 if (e == ENOENT || e == ENOTDIR) {
1428 return em;
1429 }
1430 return strerror(e);
1431}
1432
1433
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001434/* ============ Memory allocation */
1435
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001436#if 0
1437/* I consider these wrappers nearly useless:
1438 * ok, they return you to nearest exception handler, but
1439 * how much memory do you leak in the process, making
1440 * memory starvation worse?
1441 */
1442static void *
1443ckrealloc(void * p, size_t nbytes)
1444{
1445 p = realloc(p, nbytes);
1446 if (!p)
1447 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1448 return p;
1449}
1450
1451static void *
1452ckmalloc(size_t nbytes)
1453{
1454 return ckrealloc(NULL, nbytes);
1455}
1456
1457static void *
1458ckzalloc(size_t nbytes)
1459{
1460 return memset(ckmalloc(nbytes), 0, nbytes);
1461}
1462
1463static char *
1464ckstrdup(const char *s)
1465{
1466 char *p = strdup(s);
1467 if (!p)
1468 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1469 return p;
1470}
1471#else
1472/* Using bbox equivalents. They exit if out of memory */
1473# define ckrealloc xrealloc
1474# define ckmalloc xmalloc
1475# define ckzalloc xzalloc
1476# define ckstrdup xstrdup
1477#endif
1478
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001479/*
1480 * It appears that grabstackstr() will barf with such alignments
1481 * because stalloc() will return a string allocated in a new stackblock.
1482 */
1483#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1484enum {
1485 /* Most machines require the value returned from malloc to be aligned
1486 * in some way. The following macro will get this right
1487 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001488 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001489 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001490 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001491};
1492
1493struct stack_block {
1494 struct stack_block *prev;
1495 char space[MINSIZE];
1496};
1497
1498struct stackmark {
1499 struct stack_block *stackp;
1500 char *stacknxt;
1501 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001502};
1503
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001504
Denis Vlasenko01631112007-12-16 17:20:38 +00001505struct globals_memstack {
1506 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001507 char *g_stacknxt; // = stackbase.space;
1508 char *sstrend; // = stackbase.space + MINSIZE;
1509 size_t g_stacknleft; // = MINSIZE;
Denis Vlasenko01631112007-12-16 17:20:38 +00001510 struct stack_block stackbase;
1511};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01001512extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001513#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001514#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001515#define g_stacknxt (G_memstack.g_stacknxt )
1516#define sstrend (G_memstack.sstrend )
1517#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001518#define stackbase (G_memstack.stackbase )
1519#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001520 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1521 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001522 g_stackp = &stackbase; \
1523 g_stacknxt = stackbase.space; \
1524 g_stacknleft = MINSIZE; \
1525 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001526} while (0)
1527
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001528
Denis Vlasenko01631112007-12-16 17:20:38 +00001529#define stackblock() ((void *)g_stacknxt)
1530#define stackblocksize() g_stacknleft
1531
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001532/*
1533 * Parse trees for commands are allocated in lifo order, so we use a stack
1534 * to make this more efficient, and also to avoid all sorts of exception
1535 * handling code to handle interrupts in the middle of a parse.
1536 *
1537 * The size 504 was chosen because the Ultrix malloc handles that size
1538 * well.
1539 */
1540static void *
1541stalloc(size_t nbytes)
1542{
1543 char *p;
1544 size_t aligned;
1545
1546 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001547 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001548 size_t len;
1549 size_t blocksize;
1550 struct stack_block *sp;
1551
1552 blocksize = aligned;
1553 if (blocksize < MINSIZE)
1554 blocksize = MINSIZE;
1555 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1556 if (len < blocksize)
1557 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1558 INT_OFF;
1559 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001560 sp->prev = g_stackp;
1561 g_stacknxt = sp->space;
1562 g_stacknleft = blocksize;
1563 sstrend = g_stacknxt + blocksize;
1564 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001565 INT_ON;
1566 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001567 p = g_stacknxt;
1568 g_stacknxt += aligned;
1569 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001570 return p;
1571}
1572
Denis Vlasenko597906c2008-02-20 16:38:54 +00001573static void *
1574stzalloc(size_t nbytes)
1575{
1576 return memset(stalloc(nbytes), 0, nbytes);
1577}
1578
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001579static void
1580stunalloc(void *p)
1581{
1582#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001583 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001584 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001585 abort();
1586 }
1587#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001588 g_stacknleft += g_stacknxt - (char *)p;
1589 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001590}
1591
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001592/*
1593 * Like strdup but works with the ash stack.
1594 */
1595static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001596sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001597{
1598 size_t len = strlen(p) + 1;
1599 return memcpy(stalloc(len), p, len);
1600}
1601
Denys Vlasenko03c36e02018-01-10 15:18:35 +01001602static ALWAYS_INLINE void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001603grabstackblock(size_t len)
1604{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001605 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001606}
1607
1608static void
1609pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001610{
Denis Vlasenko01631112007-12-16 17:20:38 +00001611 mark->stackp = g_stackp;
1612 mark->stacknxt = g_stacknxt;
1613 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001614 grabstackblock(len);
1615}
1616
1617static void
1618setstackmark(struct stackmark *mark)
1619{
1620 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001621}
1622
1623static void
1624popstackmark(struct stackmark *mark)
1625{
1626 struct stack_block *sp;
1627
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001628 if (!mark->stackp)
1629 return;
1630
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001631 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001632 while (g_stackp != mark->stackp) {
1633 sp = g_stackp;
1634 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001635 free(sp);
1636 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001637 g_stacknxt = mark->stacknxt;
1638 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001639 sstrend = mark->stacknxt + mark->stacknleft;
1640 INT_ON;
1641}
1642
1643/*
1644 * When the parser reads in a string, it wants to stick the string on the
1645 * stack and only adjust the stack pointer when it knows how big the
1646 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1647 * of space on top of the stack and stackblocklen returns the length of
1648 * this block. Growstackblock will grow this space by at least one byte,
1649 * possibly moving it (like realloc). Grabstackblock actually allocates the
1650 * part of the block that has been used.
1651 */
1652static void
1653growstackblock(void)
1654{
1655 size_t newlen;
1656
Denis Vlasenko01631112007-12-16 17:20:38 +00001657 newlen = g_stacknleft * 2;
1658 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001659 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1660 if (newlen < 128)
1661 newlen += 128;
1662
Denis Vlasenko01631112007-12-16 17:20:38 +00001663 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001664 struct stack_block *sp;
1665 struct stack_block *prevstackp;
1666 size_t grosslen;
1667
1668 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001669 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001670 prevstackp = sp->prev;
1671 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1672 sp = ckrealloc(sp, grosslen);
1673 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001674 g_stackp = sp;
1675 g_stacknxt = sp->space;
1676 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001677 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001678 INT_ON;
1679 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001680 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001681 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001682 char *p = stalloc(newlen);
1683
1684 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001685 g_stacknxt = memcpy(p, oldspace, oldlen);
1686 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001687 }
1688}
1689
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001690/*
1691 * The following routines are somewhat easier to use than the above.
1692 * The user declares a variable of type STACKSTR, which may be declared
1693 * to be a register. The macro STARTSTACKSTR initializes things. Then
1694 * the user uses the macro STPUTC to add characters to the string. In
1695 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1696 * grown as necessary. When the user is done, she can just leave the
1697 * string there and refer to it using stackblock(). Or she can allocate
1698 * the space for it using grabstackstr(). If it is necessary to allow
1699 * someone else to use the stack temporarily and then continue to grow
1700 * the string, the user should use grabstack to allocate the space, and
1701 * then call ungrabstr(p) to return to the previous mode of operation.
1702 *
1703 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1704 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1705 * is space for at least one character.
1706 */
1707static void *
1708growstackstr(void)
1709{
1710 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001711 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001712 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001713}
1714
1715/*
1716 * Called from CHECKSTRSPACE.
1717 */
1718static char *
1719makestrspace(size_t newlen, char *p)
1720{
Denis Vlasenko01631112007-12-16 17:20:38 +00001721 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001722 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001723
1724 for (;;) {
1725 size_t nleft;
1726
1727 size = stackblocksize();
1728 nleft = size - len;
1729 if (nleft >= newlen)
1730 break;
1731 growstackblock();
1732 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001733 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001734}
1735
1736static char *
1737stack_nputstr(const char *s, size_t n, char *p)
1738{
1739 p = makestrspace(n, p);
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001740 p = (char *)mempcpy(p, s, n);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001741 return p;
1742}
1743
1744static char *
1745stack_putstr(const char *s, char *p)
1746{
1747 return stack_nputstr(s, strlen(s), p);
1748}
1749
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001750static char *
1751_STPUTC(int c, char *p)
1752{
1753 if (p == sstrend)
1754 p = growstackstr();
1755 *p++ = c;
1756 return p;
1757}
1758
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001759#define STARTSTACKSTR(p) ((p) = stackblock())
1760#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001761#define CHECKSTRSPACE(n, p) do { \
1762 char *q = (p); \
1763 size_t l = (n); \
1764 size_t m = sstrend - q; \
1765 if (l > m) \
1766 (p) = makestrspace(l, q); \
1767} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001768#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001769#define STACKSTRNUL(p) do { \
1770 if ((p) == sstrend) \
1771 (p) = growstackstr(); \
1772 *(p) = '\0'; \
1773} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001774#define STUNPUTC(p) (--(p))
1775#define STTOPC(p) ((p)[-1])
1776#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001777
1778#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001779#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001780#define stackstrend() ((void *)sstrend)
1781
1782
1783/* ============ String helpers */
1784
1785/*
1786 * prefix -- see if pfx is a prefix of string.
1787 */
1788static char *
1789prefix(const char *string, const char *pfx)
1790{
1791 while (*pfx) {
1792 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001793 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001794 }
1795 return (char *) string;
1796}
1797
1798/*
1799 * Check for a valid number. This should be elsewhere.
1800 */
1801static int
1802is_number(const char *p)
1803{
1804 do {
1805 if (!isdigit(*p))
1806 return 0;
1807 } while (*++p != '\0');
1808 return 1;
1809}
1810
1811/*
1812 * Convert a string of digits to an integer, printing an error message on
1813 * failure.
1814 */
1815static int
1816number(const char *s)
1817{
1818 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001819 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001820 return atoi(s);
1821}
1822
1823/*
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001824 * Produce a single quoted string suitable as input to the shell.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001825 * The return string is allocated on the stack.
1826 */
1827static char *
1828single_quote(const char *s)
1829{
1830 char *p;
1831
1832 STARTSTACKSTR(p);
1833
1834 do {
1835 char *q;
1836 size_t len;
1837
1838 len = strchrnul(s, '\'') - s;
1839
1840 q = p = makestrspace(len + 3, p);
1841
1842 *q++ = '\'';
Denys Vlasenko94af83e2017-07-23 21:55:40 +02001843 q = (char *)mempcpy(q, s, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001844 *q++ = '\'';
1845 s += len;
1846
1847 STADJUST(q - p, p);
1848
Denys Vlasenkocd716832009-11-28 22:14:02 +01001849 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001850 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001851 len = 0;
1852 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001853
1854 q = p = makestrspace(len + 3, p);
1855
1856 *q++ = '"';
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02001857 q = (char *)mempcpy(q, s - len, len);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001858 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001859
1860 STADJUST(q - p, p);
1861 } while (*s);
1862
Denys Vlasenkocd716832009-11-28 22:14:02 +01001863 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001864
1865 return stackblock();
1866}
1867
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001868/*
1869 * Produce a possibly single quoted string suitable as input to the shell.
Denys Vlasenko42ba7572017-07-21 13:20:14 +02001870 * If quoting was done, the return string is allocated on the stack,
1871 * otherwise a pointer to the original string is returned.
1872 */
1873static const char *
1874maybe_single_quote(const char *s)
1875{
1876 const char *p = s;
1877
1878 while (*p) {
1879 /* Assuming ACSII */
1880 /* quote ctrl_chars space !"#$%&'()* */
1881 if (*p < '+')
1882 goto need_quoting;
1883 /* quote ;<=>? */
1884 if (*p >= ';' && *p <= '?')
1885 goto need_quoting;
1886 /* quote `[\ */
1887 if (*p == '`')
1888 goto need_quoting;
1889 if (*p == '[')
1890 goto need_quoting;
1891 if (*p == '\\')
1892 goto need_quoting;
1893 /* quote {|}~ DEL and high bytes */
1894 if (*p > 'z')
1895 goto need_quoting;
1896 /* Not quoting these: +,-./ 0-9 :@ A-Z ]^_ a-z */
1897 /* TODO: maybe avoid quoting % */
1898 p++;
1899 }
1900 return s;
1901
1902 need_quoting:
1903 return single_quote(s);
1904}
1905
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001906
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001907/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001908
1909static char **argptr; /* argument list for builtin commands */
1910static char *optionarg; /* set by nextopt (like getopt) */
1911static char *optptr; /* used by nextopt */
1912
1913/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001914 * XXX - should get rid of. Have all builtins use getopt(3).
1915 * The library getopt must have the BSD extension static variable
1916 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001917 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001918 * Standard option processing (a la getopt) for builtin routines.
1919 * The only argument that is passed to nextopt is the option string;
1920 * the other arguments are unnecessary. It returns the character,
1921 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001922 */
1923static int
1924nextopt(const char *optstring)
1925{
1926 char *p;
1927 const char *q;
1928 char c;
1929
1930 p = optptr;
1931 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001932 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001933 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001934 if (p == NULL)
1935 return '\0';
1936 if (*p != '-')
1937 return '\0';
1938 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001939 return '\0';
1940 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001941 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001942 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001943 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001944 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001945 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001946 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001947 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001948 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001949 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001950 if (*++q == ':')
1951 q++;
1952 }
1953 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001954 if (*p == '\0') {
1955 p = *argptr++;
1956 if (p == NULL)
1957 ash_msg_and_raise_error("no arg for -%c option", c);
1958 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001959 optionarg = p;
1960 p = NULL;
1961 }
1962 optptr = p;
1963 return c;
1964}
1965
1966
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001967/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001968
Denis Vlasenko01631112007-12-16 17:20:38 +00001969struct shparam {
1970 int nparam; /* # of positional parameters (without $0) */
1971#if ENABLE_ASH_GETOPTS
1972 int optind; /* next parameter to be processed by getopts */
1973 int optoff; /* used by getopts */
1974#endif
1975 unsigned char malloced; /* if parameter list dynamically allocated */
1976 char **p; /* parameter list */
1977};
1978
1979/*
1980 * Free the list of positional parameters.
1981 */
1982static void
1983freeparam(volatile struct shparam *param)
1984{
Denis Vlasenko01631112007-12-16 17:20:38 +00001985 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001986 char **ap, **ap1;
1987 ap = ap1 = param->p;
1988 while (*ap)
1989 free(*ap++);
1990 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001991 }
1992}
1993
1994#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001995static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001996#endif
1997
1998struct var {
1999 struct var *next; /* next entry in hash list */
2000 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002001 const char *var_text; /* name=value */
2002 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00002003 /* the variable gets set/unset */
2004};
2005
2006struct localvar {
2007 struct localvar *next; /* next local variable in list */
2008 struct var *vp; /* the variable that was made local */
2009 int flags; /* saved flags */
2010 const char *text; /* saved text */
2011};
2012
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002013/* flags */
2014#define VEXPORT 0x01 /* variable is exported */
2015#define VREADONLY 0x02 /* variable cannot be modified */
2016#define VSTRFIXED 0x04 /* variable struct is statically allocated */
2017#define VTEXTFIXED 0x08 /* text is statically allocated */
2018#define VSTACK 0x10 /* text is allocated on the stack */
2019#define VUNSET 0x20 /* the variable is not set */
2020#define VNOFUNC 0x40 /* don't call the callback function */
2021#define VNOSET 0x80 /* do not set variable - just readonly test */
2022#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002023#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002024# define VDYNAMIC 0x200 /* dynamic variable */
2025#else
2026# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002027#endif
2028
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002029
Denis Vlasenko01631112007-12-16 17:20:38 +00002030/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002031#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002032static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002033change_lc_all(const char *value)
2034{
2035 if (value && *value != '\0')
2036 setlocale(LC_ALL, value);
2037}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02002038static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00002039change_lc_ctype(const char *value)
2040{
2041 if (value && *value != '\0')
2042 setlocale(LC_CTYPE, value);
2043}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00002044#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002045#if ENABLE_ASH_MAIL
2046static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01002047static void changemail(const char *var_value) FAST_FUNC;
2048#else
2049# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002050#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002051static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002052#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002053static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002054#endif
2055
Denis Vlasenko01631112007-12-16 17:20:38 +00002056static const struct {
2057 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002058 const char *var_text;
2059 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00002060} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02002061 /*
2062 * Note: VEXPORT would not work correctly here for NOFORK applets:
2063 * some environment strings may be constant.
2064 */
Denis Vlasenko01631112007-12-16 17:20:38 +00002065 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002066#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002067 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
2068 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002069#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00002070 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
2071 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
2072 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
2073 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002074#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02002075 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002076#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002077 { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002078#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002079 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002080#endif
2081#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002082 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
2083 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002084#endif
2085#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002086 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002087#endif
2088};
2089
Denis Vlasenko0b769642008-07-24 07:54:57 +00002090struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00002091
2092struct globals_var {
2093 struct shparam shellparam; /* $@ current positional parameters */
2094 struct redirtab *redirlist;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02002095 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
Denis Vlasenko01631112007-12-16 17:20:38 +00002096 struct var *vartab[VTABSIZE];
2097 struct var varinit[ARRAY_SIZE(varinit_data)];
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002098 int lineno;
2099 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
Denis Vlasenko01631112007-12-16 17:20:38 +00002100};
Denys Vlasenko6f9442f2018-01-28 20:41:23 +01002101extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
Denis Vlasenko574f2f42008-02-27 18:41:59 +00002102#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00002103#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00002104//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00002105#define preverrout_fd (G_var.preverrout_fd)
2106#define vartab (G_var.vartab )
2107#define varinit (G_var.varinit )
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002108#define lineno (G_var.lineno )
2109#define linenovar (G_var.linenovar )
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002110#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002111#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002112# define vmail (&vifs)[1]
2113# define vmpath (&vmail)[1]
2114# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002115#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002116# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002117#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002118#define vps1 (&vpath)[1]
2119#define vps2 (&vps1)[1]
2120#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002121#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002122# define voptind (&vps4)[1]
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002123# define vlineno (&voptind)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002124# if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002125# define vrandom (&vlineno)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002126# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002127#else
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002128# define vlineno (&vps4)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002129# if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002130# define vrandom (&vlineno)[1]
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002131# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002132#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002133#define INIT_G_var() do { \
2134 unsigned i; \
2135 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2136 barrier(); \
2137 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2138 varinit[i].flags = varinit_data[i].flags; \
2139 varinit[i].var_text = varinit_data[i].var_text; \
2140 varinit[i].var_func = varinit_data[i].var_func; \
2141 } \
2142 strcpy(linenovar, "LINENO="); \
2143 vlineno.var_text = linenovar; \
2144} while (0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002145
2146/*
2147 * The following macros access the values of the above variables.
2148 * They have to skip over the name. They return the null string
2149 * for unset variables.
2150 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002151#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002152#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002153#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002154# define mailval() (vmail.var_text + 5)
2155# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002156# define mpathset() ((vmpath.flags & VUNSET) == 0)
2157#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002158#define pathval() (vpath.var_text + 5)
2159#define ps1val() (vps1.var_text + 4)
2160#define ps2val() (vps2.var_text + 4)
2161#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002162#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002163# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002164#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002165
Denis Vlasenko01631112007-12-16 17:20:38 +00002166#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002167static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002168getoptsreset(const char *value)
2169{
Denys Vlasenko46289452017-08-11 00:59:36 +02002170 shellparam.optind = 1;
2171 if (is_number(value))
2172 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002173 shellparam.optoff = -1;
2174}
2175#endif
2176
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002177/*
2178 * Compares two strings up to the first = or '\0'. The first
2179 * string must be terminated by '='; the second may be terminated by
2180 * either '=' or '\0'.
2181 */
2182static int
2183varcmp(const char *p, const char *q)
2184{
2185 int c, d;
2186
2187 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002188 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002189 goto out;
2190 p++;
2191 q++;
2192 }
2193 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002194 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002195 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002196 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002197 out:
2198 return c - d;
2199}
2200
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002201/*
2202 * Find the appropriate entry in the hash table from the name.
2203 */
2204static struct var **
2205hashvar(const char *p)
2206{
2207 unsigned hashval;
2208
2209 hashval = ((unsigned char) *p) << 4;
2210 while (*p && *p != '=')
2211 hashval += (unsigned char) *p++;
2212 return &vartab[hashval % VTABSIZE];
2213}
2214
2215static int
2216vpcmp(const void *a, const void *b)
2217{
2218 return varcmp(*(const char **)a, *(const char **)b);
2219}
2220
2221/*
2222 * This routine initializes the builtin variables.
2223 */
2224static void
2225initvar(void)
2226{
2227 struct var *vp;
2228 struct var *end;
2229 struct var **vpp;
2230
2231 /*
2232 * PS1 depends on uid
2233 */
2234#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002235 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002236#else
2237 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002238 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002239#endif
2240 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002241 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002242 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002243 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002244 vp->next = *vpp;
2245 *vpp = vp;
2246 } while (++vp < end);
2247}
2248
2249static struct var **
2250findvar(struct var **vpp, const char *name)
2251{
2252 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002253 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002254 break;
2255 }
2256 }
2257 return vpp;
2258}
2259
2260/*
2261 * Find the value of a variable. Returns NULL if not set.
2262 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002263static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002264lookupvar(const char *name)
2265{
2266 struct var *v;
2267
2268 v = *findvar(hashvar(name), name);
2269 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002270#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002271 /*
2272 * Dynamic variables are implemented roughly the same way they are
2273 * in bash. Namely, they're "special" so long as they aren't unset.
2274 * As soon as they're unset, they're no longer dynamic, and dynamic
2275 * lookup will no longer happen at that point. -- PFM.
2276 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002277 if (v->flags & VDYNAMIC)
2278 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002279#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002280 if (!(v->flags & VUNSET)) {
2281 if (v == &vlineno && v->var_text == linenovar) {
2282 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2283 }
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002284 return var_end(v->var_text);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01002285 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002286 }
2287 return NULL;
2288}
2289
Denys Vlasenko0b883582016-12-23 16:49:07 +01002290#if ENABLE_UNICODE_SUPPORT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002291static void
2292reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002293{
2294 /* Unicode support should be activated even if LANG is set
2295 * _during_ shell execution, not only if it was set when
2296 * shell was started. Therefore, re-check LANG every time:
2297 */
2298 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2299 || ENABLE_UNICODE_USING_LOCALE
2300 ) {
2301 const char *s = lookupvar("LC_ALL");
2302 if (!s) s = lookupvar("LC_CTYPE");
2303 if (!s) s = lookupvar("LANG");
2304 reinit_unicode(s);
2305 }
2306}
Denys Vlasenko0b883582016-12-23 16:49:07 +01002307#else
2308# define reinit_unicode_for_ash() ((void)0)
2309#endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002310
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002311/*
2312 * Search the environment of a builtin command.
2313 */
Denys Vlasenko488e6092017-07-26 23:08:36 +02002314static ALWAYS_INLINE const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002315bltinlookup(const char *name)
2316{
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002317 return lookupvar(name);
2318}
2319
2320/*
2321 * Same as setvar except that the variable and value are passed in
2322 * the first argument as name=value. Since the first argument will
2323 * be actually stored in the table, it should not be a string that
2324 * will go away.
2325 * Called with interrupts off.
2326 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002327static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002328setvareq(char *s, int flags)
2329{
2330 struct var *vp, **vpp;
2331
2332 vpp = hashvar(s);
2333 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002334 vpp = findvar(vpp, s);
2335 vp = *vpp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002336 if (vp) {
2337 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2338 const char *n;
2339
2340 if (flags & VNOSAVE)
2341 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002342 n = vp->var_text;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +02002343 exitstatus = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002344 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2345 }
2346
2347 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002348 goto out;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002349
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002350 if (vp->var_func && !(flags & VNOFUNC))
2351 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002352
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002353 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2354 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002355
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002356 if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
2357 *vpp = vp->next;
2358 free(vp);
2359 out_free:
2360 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2361 free(s);
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002362 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002363 }
2364
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002365 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2366 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002367 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002368 if (flags & VNOSET)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002369 goto out;
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002370 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2371 goto out_free;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002372 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002373 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002374 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002375 *vpp = vp;
2376 }
2377 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2378 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002379 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002380 vp->flags = flags;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002381
2382 out:
2383 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002384}
2385
2386/*
2387 * Set the value of a variable. The flags argument is ored with the
2388 * flags of the variable. If val is NULL, the variable is unset.
2389 */
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002390static struct var *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002391setvar(const char *name, const char *val, int flags)
2392{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002393 const char *q;
2394 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002395 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002396 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002397 size_t vallen;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002398 struct var *vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002399
2400 q = endofname(name);
2401 p = strchrnul(q, '=');
2402 namelen = p - name;
2403 if (!namelen || p != q)
2404 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2405 vallen = 0;
2406 if (val == NULL) {
2407 flags |= VUNSET;
2408 } else {
2409 vallen = strlen(val);
2410 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002411
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002412 INT_OFF;
Ron Yorstone6a63bf2018-11-12 21:10:54 +00002413 nameeq = ckzalloc(namelen + vallen + 2);
Denys Vlasenkoda2244f2017-07-21 18:51:29 +02002414 p = mempcpy(nameeq, name, namelen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002415 if (val) {
2416 *p++ = '=';
Ron Yorstone6a63bf2018-11-12 21:10:54 +00002417 memcpy(p, val, vallen);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002418 }
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002419 vp = setvareq(nameeq, flags | VNOSAVE);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002420 INT_ON;
Denys Vlasenkod04fc712017-07-26 20:06:48 +02002421
2422 return vp;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002423}
2424
Denys Vlasenko03dad222010-01-12 23:29:57 +01002425static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002426setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002427{
2428 setvar(name, val, 0);
2429}
2430
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002431/*
2432 * Unset the specified variable.
2433 */
Denys Vlasenkob28d4c32017-07-25 16:29:36 +02002434static void
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002435unsetvar(const char *s)
2436{
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02002437 setvar(s, NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002438}
2439
2440/*
2441 * Process a linked list of variable assignments.
2442 */
2443static void
2444listsetvar(struct strlist *list_set_var, int flags)
2445{
2446 struct strlist *lp = list_set_var;
2447
2448 if (!lp)
2449 return;
2450 INT_OFF;
2451 do {
2452 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002453 lp = lp->next;
2454 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002455 INT_ON;
2456}
2457
2458/*
2459 * Generate a list of variables satisfying the given conditions.
2460 */
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002461#if !ENABLE_FEATURE_SH_NOFORK
2462# define listvars(on, off, lp, end) listvars(on, off, end)
2463#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002464static char **
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002465listvars(int on, int off, struct strlist *lp, char ***end)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002466{
2467 struct var **vpp;
2468 struct var *vp;
2469 char **ep;
2470 int mask;
2471
2472 STARTSTACKSTR(ep);
2473 vpp = vartab;
2474 mask = on | off;
2475 do {
2476 for (vp = *vpp; vp; vp = vp->next) {
2477 if ((vp->flags & mask) == on) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002478#if ENABLE_FEATURE_SH_NOFORK
2479 /* If variable with the same name is both
2480 * exported and temporarily set for a command:
2481 * export ZVAR=5
2482 * ZVAR=6 printenv
2483 * then "ZVAR=6" will be both in vartab and
2484 * lp lists. Do not pass it twice to printenv.
2485 */
2486 struct strlist *lp1 = lp;
2487 while (lp1) {
2488 if (strcmp(lp1->text, vp->var_text) == 0)
2489 goto skip;
2490 lp1 = lp1->next;
2491 }
2492#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002493 if (ep == stackstrend())
2494 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002495 *ep++ = (char*)vp->var_text;
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002496#if ENABLE_FEATURE_SH_NOFORK
2497 skip: ;
2498#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002499 }
2500 }
2501 } while (++vpp < vartab + VTABSIZE);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01002502
2503#if ENABLE_FEATURE_SH_NOFORK
2504 while (lp) {
2505 if (ep == stackstrend())
2506 ep = growstackstr();
2507 *ep++ = lp->text;
2508 lp = lp->next;
2509 }
2510#endif
2511
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002512 if (ep == stackstrend())
2513 ep = growstackstr();
2514 if (end)
2515 *end = ep;
2516 *ep++ = NULL;
2517 return grabstackstr(ep);
2518}
2519
2520
2521/* ============ Path search helper
2522 *
2523 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002524 * of the path before the first call; path_advance will update
2525 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002526 * the possible path expansions in sequence. If an option (indicated by
2527 * a percent sign) appears in the path entry then the global variable
2528 * pathopt will be set to point to it; otherwise pathopt will be set to
2529 * NULL.
2530 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002531static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002532
2533static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002534path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002535{
2536 const char *p;
2537 char *q;
2538 const char *start;
2539 size_t len;
2540
2541 if (*path == NULL)
2542 return NULL;
2543 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002544 for (p = start; *p && *p != ':' && *p != '%'; p++)
2545 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002546 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2547 while (stackblocksize() < len)
2548 growstackblock();
2549 q = stackblock();
2550 if (p != start) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02002551 q = mempcpy(q, start, p - start);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002552 *q++ = '/';
2553 }
2554 strcpy(q, name);
2555 pathopt = NULL;
2556 if (*p == '%') {
2557 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002558 while (*p && *p != ':')
2559 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002560 }
2561 if (*p == ':')
2562 *path = p + 1;
2563 else
2564 *path = NULL;
2565 return stalloc(len);
2566}
2567
2568
2569/* ============ Prompt */
2570
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002571static smallint doprompt; /* if set, prompt the user */
2572static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002573
2574#if ENABLE_FEATURE_EDITING
2575static line_input_t *line_input_state;
2576static const char *cmdedit_prompt;
2577static void
2578putprompt(const char *s)
2579{
2580 if (ENABLE_ASH_EXPAND_PRMT) {
2581 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002582 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002583 return;
2584 }
2585 cmdedit_prompt = s;
2586}
2587#else
2588static void
2589putprompt(const char *s)
2590{
2591 out2str(s);
2592}
2593#endif
2594
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002595/* expandstr() needs parsing machinery, so it is far away ahead... */
Denys Vlasenko46999802017-07-29 21:12:29 +02002596static const char *expandstr(const char *ps, int syntax_type);
2597/* Values for syntax param */
2598#define BASESYNTAX 0 /* not in quotes */
2599#define DQSYNTAX 1 /* in double quotes */
2600#define SQSYNTAX 2 /* in single quotes */
2601#define ARISYNTAX 3 /* in arithmetic */
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +02002602#if ENABLE_ASH_EXPAND_PRMT
2603# define PSSYNTAX 4 /* prompt. never passed to SIT() */
2604#endif
Denys Vlasenko46999802017-07-29 21:12:29 +02002605/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002606
Denys Vlasenko46999802017-07-29 21:12:29 +02002607/*
2608 * called by editline -- any expansions to the prompt should be added here.
2609 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002610static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002611setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002612{
2613 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002614 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2615
2616 if (!do_set)
2617 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002618
2619 needprompt = 0;
2620
2621 switch (whichprompt) {
2622 case 1:
2623 prompt = ps1val();
2624 break;
2625 case 2:
2626 prompt = ps2val();
2627 break;
2628 default: /* 0 */
2629 prompt = nullstr;
2630 }
2631#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002632 pushstackmark(&smark, stackblocksize());
Denys Vlasenko46999802017-07-29 21:12:29 +02002633 putprompt(expandstr(prompt, PSSYNTAX));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002634 popstackmark(&smark);
Denys Vlasenko48c803a2017-07-01 23:24:48 +02002635#else
2636 putprompt(prompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002637#endif
2638}
2639
2640
2641/* ============ The cd and pwd commands */
2642
2643#define CD_PHYSICAL 1
2644#define CD_PRINT 2
2645
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002646static int
2647cdopt(void)
2648{
2649 int flags = 0;
2650 int i, j;
2651
2652 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002653 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002654 if (i != j) {
2655 flags ^= CD_PHYSICAL;
2656 j = i;
2657 }
2658 }
2659
2660 return flags;
2661}
2662
2663/*
2664 * Update curdir (the name of the current directory) in response to a
2665 * cd command.
2666 */
2667static const char *
2668updatepwd(const char *dir)
2669{
2670 char *new;
2671 char *p;
2672 char *cdcomppath;
2673 const char *lim;
2674
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002675 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002676 STARTSTACKSTR(new);
2677 if (*dir != '/') {
2678 if (curdir == nullstr)
2679 return 0;
2680 new = stack_putstr(curdir, new);
2681 }
2682 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002683 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002684 if (*dir != '/') {
2685 if (new[-1] != '/')
2686 USTPUTC('/', new);
2687 if (new > lim && *lim == '/')
2688 lim++;
2689 } else {
2690 USTPUTC('/', new);
2691 cdcomppath++;
2692 if (dir[1] == '/' && dir[2] != '/') {
2693 USTPUTC('/', new);
2694 cdcomppath++;
2695 lim++;
2696 }
2697 }
2698 p = strtok(cdcomppath, "/");
2699 while (p) {
2700 switch (*p) {
2701 case '.':
2702 if (p[1] == '.' && p[2] == '\0') {
2703 while (new > lim) {
2704 STUNPUTC(new);
2705 if (new[-1] == '/')
2706 break;
2707 }
2708 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002709 }
2710 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002711 break;
2712 /* fall through */
2713 default:
2714 new = stack_putstr(p, new);
2715 USTPUTC('/', new);
2716 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002717 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002718 }
2719 if (new > lim)
2720 STUNPUTC(new);
2721 *new = 0;
2722 return stackblock();
2723}
2724
2725/*
2726 * Find out what the current directory is. If we already know the current
2727 * directory, this routine returns immediately.
2728 */
2729static char *
2730getpwd(void)
2731{
Denis Vlasenko01631112007-12-16 17:20:38 +00002732 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002733 return dir ? dir : nullstr;
2734}
2735
2736static void
2737setpwd(const char *val, int setold)
2738{
2739 char *oldcur, *dir;
2740
2741 oldcur = dir = curdir;
2742
2743 if (setold) {
2744 setvar("OLDPWD", oldcur, VEXPORT);
2745 }
2746 INT_OFF;
2747 if (physdir != nullstr) {
2748 if (physdir != oldcur)
2749 free(physdir);
2750 physdir = nullstr;
2751 }
2752 if (oldcur == val || !val) {
2753 char *s = getpwd();
2754 physdir = s;
2755 if (!val)
2756 dir = s;
2757 } else
2758 dir = ckstrdup(val);
2759 if (oldcur != dir && oldcur != nullstr) {
2760 free(oldcur);
2761 }
2762 curdir = dir;
2763 INT_ON;
2764 setvar("PWD", dir, VEXPORT);
2765}
2766
2767static void hashcd(void);
2768
2769/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002770 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002771 * know that the current directory has changed.
2772 */
2773static int
2774docd(const char *dest, int flags)
2775{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002776 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002777 int err;
2778
2779 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2780
2781 INT_OFF;
2782 if (!(flags & CD_PHYSICAL)) {
2783 dir = updatepwd(dest);
2784 if (dir)
2785 dest = dir;
2786 }
2787 err = chdir(dest);
2788 if (err)
2789 goto out;
2790 setpwd(dir, 1);
2791 hashcd();
2792 out:
2793 INT_ON;
2794 return err;
2795}
2796
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002797static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002798cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002799{
2800 const char *dest;
2801 const char *path;
2802 const char *p;
2803 char c;
2804 struct stat statb;
2805 int flags;
2806
2807 flags = cdopt();
2808 dest = *argptr;
2809 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002810 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002811 else if (LONE_DASH(dest)) {
2812 dest = bltinlookup("OLDPWD");
2813 flags |= CD_PRINT;
2814 }
2815 if (!dest)
2816 dest = nullstr;
2817 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002818 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002819 if (*dest == '.') {
2820 c = dest[1];
2821 dotdot:
2822 switch (c) {
2823 case '\0':
2824 case '/':
2825 goto step6;
2826 case '.':
2827 c = dest[2];
2828 if (c != '.')
2829 goto dotdot;
2830 }
2831 }
2832 if (!*dest)
2833 dest = ".";
2834 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002835 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002836 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002837 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002838 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2839 if (c && c != ':')
2840 flags |= CD_PRINT;
2841 docd:
2842 if (!docd(p, flags))
2843 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002844 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002845 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002846 }
2847
2848 step6:
2849 p = dest;
2850 goto docd;
2851
2852 err:
Johannes Schindelin687aac02017-08-22 22:03:22 +02002853 ash_msg_and_raise_perror("can't cd to %s", dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002854 /* NOTREACHED */
2855 out:
2856 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002857 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002858 return 0;
2859}
2860
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002861static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002862pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002863{
2864 int flags;
2865 const char *dir = curdir;
2866
2867 flags = cdopt();
2868 if (flags) {
2869 if (physdir == nullstr)
2870 setpwd(dir, 0);
2871 dir = physdir;
2872 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002873 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002874 return 0;
2875}
2876
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002877
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002878/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002879
Denis Vlasenko834dee72008-10-07 09:18:30 +00002880
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002881#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002882
Eric Andersenc470f442003-07-28 09:56:35 +00002883/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002884#define CWORD 0 /* character is nothing special */
2885#define CNL 1 /* newline character */
2886#define CBACK 2 /* a backslash character */
2887#define CSQUOTE 3 /* single quote */
2888#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002889#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002890#define CBQUOTE 6 /* backwards single quote */
2891#define CVAR 7 /* a dollar sign */
2892#define CENDVAR 8 /* a '}' character */
2893#define CLP 9 /* a left paren in arithmetic */
2894#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002895#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002896#define CCTL 12 /* like CWORD, except it must be escaped */
2897#define CSPCL 13 /* these terminate a word */
2898#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002899
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002900#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002901#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002902# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002903#endif
2904
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002905#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002906
Denys Vlasenko0b883582016-12-23 16:49:07 +01002907#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002908# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002909#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002910# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002911#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002912static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002913#if ENABLE_ASH_ALIAS
2914 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2915#endif
2916 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2917 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2918 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2919 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2920 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2921 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2922 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2923 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2924 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2925 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2926 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002927#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002928 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2929 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2930 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2931#endif
2932#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002933};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002934/* Constants below must match table above */
2935enum {
2936#if ENABLE_ASH_ALIAS
2937 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2938#endif
2939 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2940 CNL_CNL_CNL_CNL , /* 2 */
2941 CWORD_CCTL_CCTL_CWORD , /* 3 */
2942 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2943 CVAR_CVAR_CWORD_CVAR , /* 5 */
2944 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2945 CSPCL_CWORD_CWORD_CLP , /* 7 */
2946 CSPCL_CWORD_CWORD_CRP , /* 8 */
2947 CBACK_CBACK_CCTL_CBACK , /* 9 */
2948 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2949 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2950 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2951 CWORD_CWORD_CWORD_CWORD , /* 13 */
2952 CCTL_CCTL_CCTL_CCTL , /* 14 */
2953};
Eric Andersen2870d962001-07-02 17:27:21 +00002954
Denys Vlasenkocd716832009-11-28 22:14:02 +01002955/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2956 * caller must ensure proper cast on it if c is *char_ptr!
2957 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002958#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002959
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002960static int
2961SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002962{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002963 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2964 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2965 /*
2966 * This causes '/' to be prepended with CTLESC in dquoted string,
2967 * making "./file"* treated incorrectly because we feed
2968 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2969 * The "homegrown" glob implementation is okay with that,
2970 * but glibc one isn't. With '/' always treated as CWORD,
2971 * both work fine.
2972 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002973# if ENABLE_ASH_ALIAS
2974 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002975 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002976 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002977 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2978 11, 3 /* "}~" */
2979 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002980# else
2981 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002982 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002983 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002984 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2985 10, 2 /* "}~" */
2986 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002987# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002988 const char *s;
2989 int indx;
2990
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002991 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002992 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002993# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002994 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002995 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002996 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002997# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002998 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002999 /* Cast is purely for paranoia here,
3000 * just in case someone passed signed char to us */
3001 if ((unsigned char)c >= CTL_FIRST
3002 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003003 ) {
3004 return CCTL;
3005 }
3006 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003007 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003008 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00003009 indx = syntax_index_table[s - spec_symbls];
3010 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003011 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003012}
3013
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003014#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00003015
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02003016static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003017 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01003018 /* 0 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 1 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 2 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 3 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 4 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 5 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 6 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 7 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 8 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
3028 /* 10 "\n" */ CNL_CNL_CNL_CNL,
3029 /* 11 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 12 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 13 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 14 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 15 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 16 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 17 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 18 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 19 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 20 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 21 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 22 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 23 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 24 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 25 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 26 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 27 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 28 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 29 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 30 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 31 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
3051 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
3052 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
3053 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
3054 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
3055 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
3056 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
3057 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
3058 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
3059 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
3060 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
3061 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
3062 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
3063 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
3064 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02003065/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
3066 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003067 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
3068 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
3069 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
3070 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
3071 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
3072 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
3073 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
3074 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
3075 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
3076 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
3077 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
3078 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
3079 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
3080 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
3081 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
3082 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
3083 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
3084 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
3085 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
3086 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
3087 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
3088 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
3089 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
3090 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
3091 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
3092 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
3093 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
3094 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
3095 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
3096 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
3097 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
3098 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
3099 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
3100 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
3101 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
3102 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
3103 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
3104 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
3105 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
3106 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
3107 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
3108 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
3109 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
3110 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
3111 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
3112 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
3113 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
3114 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
3115 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
3116 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
3117 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
3118 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
3119 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
3120 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
3121 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
3122 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
3123 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
3124 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
3125 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
3126 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
3127 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
3128 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
3129 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3130 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3131 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3132 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3133 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3134 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3135 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3136 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3137 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3138 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3139 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3140 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3141 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3142 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3143 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3144 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3145 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3146 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3147 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3148 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3149 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3150 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3151 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3152 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3153 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3154 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3155 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3156 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3157 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3158 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3159 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3160 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3161 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3162 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3163 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3164 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3165 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3166 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3167 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3168 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3169 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3170 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3171 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3172 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3173 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3174 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3175 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3176 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3177 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3178 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3179 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3180 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3181 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3182 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3183 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3184 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3185 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3186 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3187 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3188 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3189 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3190 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3191 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3192 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3193 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3194 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3195 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3196 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3197 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3198 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3199 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3200 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3201 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3202 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3203 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3204 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3205 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3206 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3207 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3208 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3209 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3210 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3211 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3212 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3213 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3214 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3215 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3216 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3217 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3218 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3219 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3220 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3221 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3222 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3223 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3224 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3225 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3226 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3227 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3228 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3229 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3230 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3231 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3232 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3233 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3234 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3235 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3236 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3237 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3238 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3239 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3240 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3241 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3242 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3243 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3244 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3245 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3246 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3247 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3248 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3249 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3250 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3251 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3252 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3253 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3254 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3255 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3256 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3257 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3258 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3259 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3260 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3261 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3262 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3263 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3264 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3265 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3266 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3267 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3268 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3269 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3270 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3271 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3272 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3273 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3274 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003275 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003276# if ENABLE_ASH_ALIAS
3277 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3278# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003279};
3280
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003281#if 1
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003282# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003283#else /* debug version, caught one signed char bug */
3284# define SIT(c, syntax) \
3285 ({ \
3286 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3287 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
Denys Vlasenko0b883582016-12-23 16:49:07 +01003288 if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01003289 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3290 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3291 })
3292#endif
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003293
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003294#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003295
Eric Andersen2870d962001-07-02 17:27:21 +00003296
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003297/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003298
Denis Vlasenko131ae172007-02-18 13:00:19 +00003299#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003300
3301#define ALIASINUSE 1
3302#define ALIASDEAD 2
3303
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003304struct alias {
3305 struct alias *next;
3306 char *name;
3307 char *val;
3308 int flag;
3309};
3310
Denis Vlasenko01631112007-12-16 17:20:38 +00003311
3312static struct alias **atab; // [ATABSIZE];
3313#define INIT_G_alias() do { \
3314 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3315} while (0)
3316
Eric Andersen2870d962001-07-02 17:27:21 +00003317
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003318static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003319__lookupalias(const char *name)
3320{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003321 unsigned int hashval;
3322 struct alias **app;
3323 const char *p;
3324 unsigned int ch;
3325
3326 p = name;
3327
3328 ch = (unsigned char)*p;
3329 hashval = ch << 4;
3330 while (ch) {
3331 hashval += ch;
3332 ch = (unsigned char)*++p;
3333 }
3334 app = &atab[hashval % ATABSIZE];
3335
3336 for (; *app; app = &(*app)->next) {
3337 if (strcmp(name, (*app)->name) == 0) {
3338 break;
3339 }
3340 }
3341
3342 return app;
3343}
3344
3345static struct alias *
3346lookupalias(const char *name, int check)
3347{
3348 struct alias *ap = *__lookupalias(name);
3349
3350 if (check && ap && (ap->flag & ALIASINUSE))
3351 return NULL;
3352 return ap;
3353}
3354
3355static struct alias *
3356freealias(struct alias *ap)
3357{
3358 struct alias *next;
3359
3360 if (ap->flag & ALIASINUSE) {
3361 ap->flag |= ALIASDEAD;
3362 return ap;
3363 }
3364
3365 next = ap->next;
3366 free(ap->name);
3367 free(ap->val);
3368 free(ap);
3369 return next;
3370}
Eric Andersencb57d552001-06-28 07:25:16 +00003371
Eric Andersenc470f442003-07-28 09:56:35 +00003372static void
3373setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003374{
3375 struct alias *ap, **app;
3376
3377 app = __lookupalias(name);
3378 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003379 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003380 if (ap) {
3381 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003382 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003383 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003384 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003385 ap->flag &= ~ALIASDEAD;
3386 } else {
3387 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003388 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003389 ap->name = ckstrdup(name);
3390 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003391 /*ap->flag = 0; - ckzalloc did it */
3392 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003393 *app = ap;
3394 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003395 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003396}
3397
Eric Andersenc470f442003-07-28 09:56:35 +00003398static int
3399unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003400{
Eric Andersencb57d552001-06-28 07:25:16 +00003401 struct alias **app;
3402
3403 app = __lookupalias(name);
3404
3405 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003406 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003407 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003408 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003409 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003410 }
3411
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003412 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003413}
3414
Eric Andersenc470f442003-07-28 09:56:35 +00003415static void
3416rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003417{
Eric Andersencb57d552001-06-28 07:25:16 +00003418 struct alias *ap, **app;
3419 int i;
3420
Denis Vlasenkob012b102007-02-19 22:43:01 +00003421 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003422 for (i = 0; i < ATABSIZE; i++) {
3423 app = &atab[i];
3424 for (ap = *app; ap; ap = *app) {
3425 *app = freealias(*app);
3426 if (ap == *app) {
3427 app = &ap->next;
3428 }
3429 }
3430 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003431 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003432}
3433
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003434static void
3435printalias(const struct alias *ap)
3436{
3437 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3438}
3439
Eric Andersencb57d552001-06-28 07:25:16 +00003440/*
3441 * TODO - sort output
3442 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003443static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003444aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003445{
3446 char *n, *v;
3447 int ret = 0;
3448 struct alias *ap;
3449
Denis Vlasenko68404f12008-03-17 09:00:54 +00003450 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003451 int i;
3452
Denis Vlasenko68404f12008-03-17 09:00:54 +00003453 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003454 for (ap = atab[i]; ap; ap = ap->next) {
3455 printalias(ap);
3456 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003457 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003458 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003459 }
3460 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003461 v = strchr(n+1, '=');
3462 if (v == NULL) { /* n+1: funny ksh stuff */
3463 ap = *__lookupalias(n);
3464 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003465 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003466 ret = 1;
3467 } else
3468 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003469 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003470 *v++ = '\0';
3471 setalias(n, v);
3472 }
3473 }
3474
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003475 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003476}
3477
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003478static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003479unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003480{
3481 int i;
3482
Denys Vlasenko6c149f42017-04-12 21:31:32 +02003483 while (nextopt("a") != '\0') {
3484 rmaliases();
3485 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003486 }
3487 for (i = 0; *argptr; argptr++) {
3488 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003489 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003490 i = 1;
3491 }
3492 }
3493
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003494 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003495}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003496
Denis Vlasenko131ae172007-02-18 13:00:19 +00003497#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003498
Eric Andersenc470f442003-07-28 09:56:35 +00003499
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003500/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003501#define FORK_FG 0
3502#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003503#define FORK_NOJOB 2
3504
3505/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003506#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3507#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3508#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003509#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003510
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003511/*
3512 * A job structure contains information about a job. A job is either a
3513 * single process or a set of processes contained in a pipeline. In the
3514 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3515 * array of pids.
3516 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003517struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003518 pid_t ps_pid; /* process id */
3519 int ps_status; /* last process status from wait() */
3520 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003521};
3522
3523struct job {
3524 struct procstat ps0; /* status of process */
3525 struct procstat *ps; /* status or processes when more than one */
3526#if JOBS
3527 int stopstatus; /* status of a stopped job */
3528#endif
Denys Vlasenko4c179372017-01-11 18:44:15 +01003529 unsigned nprocs; /* number of processes */
3530
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531#define JOBRUNNING 0 /* at least one proc running */
3532#define JOBSTOPPED 1 /* all procs are stopped */
3533#define JOBDONE 2 /* all procs are completed */
Denys Vlasenko4c179372017-01-11 18:44:15 +01003534 unsigned
3535 state: 8,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003536#if JOBS
3537 sigint: 1, /* job was killed by SIGINT */
3538 jobctl: 1, /* job running under job control */
3539#endif
3540 waited: 1, /* true if this entry has been waited for */
3541 used: 1, /* true if this entry is in used */
3542 changed: 1; /* true if status has changed */
3543 struct job *prev_job; /* previous job */
3544};
3545
Denis Vlasenko68404f12008-03-17 09:00:54 +00003546static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003547static int forkshell(struct job *, union node *, int);
3548static int waitforjob(struct job *);
3549
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003550#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003551enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003552#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003553#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003554static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003555static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003556#endif
3557
3558/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003559 * Ignore a signal.
3560 */
3561static void
3562ignoresig(int signo)
3563{
3564 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3565 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3566 /* No, need to do it */
3567 signal(signo, SIG_IGN);
3568 }
3569 sigmode[signo - 1] = S_HARD_IGN;
3570}
3571
3572/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003573 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003574 */
3575static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003576signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003577{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003578 if (signo == SIGCHLD) {
3579 got_sigchld = 1;
3580 if (!trap[SIGCHLD])
3581 return;
3582 }
3583
Denis Vlasenko4b875702009-03-19 13:30:04 +00003584 gotsig[signo - 1] = 1;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003585 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003586
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003587 if (signo == SIGINT && !trap[SIGINT]) {
3588 if (!suppress_int) {
3589 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003590 raise_interrupt(); /* does not return */
3591 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003592 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003593 }
3594}
3595
3596/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003597 * Set the signal handler for the specified signal. The routine figures
3598 * out what it should be set to.
3599 */
3600static void
3601setsignal(int signo)
3602{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003603 char *t;
3604 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003605 struct sigaction act;
3606
3607 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003608 new_act = S_DFL;
3609 if (t != NULL) { /* trap for this sig is set */
3610 new_act = S_CATCH;
3611 if (t[0] == '\0') /* trap is "": ignore this sig */
3612 new_act = S_IGN;
3613 }
3614
3615 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003616 switch (signo) {
3617 case SIGINT:
3618 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003619 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003620 break;
3621 case SIGQUIT:
3622#if DEBUG
3623 if (debug)
3624 break;
3625#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003626 /* man bash:
3627 * "In all cases, bash ignores SIGQUIT. Non-builtin
3628 * commands run by bash have signal handlers
3629 * set to the values inherited by the shell
3630 * from its parent". */
3631 new_act = S_IGN;
3632 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003633 case SIGTERM:
3634 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003635 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003636 break;
3637#if JOBS
3638 case SIGTSTP:
3639 case SIGTTOU:
3640 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003641 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003642 break;
3643#endif
3644 }
3645 }
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003646 /* if !rootshell, we reset SIGQUIT to DFL,
3647 * whereas we have to restore it to what shell got on entry.
3648 * This is handled by the fact that if signal was IGNored on entry,
3649 * then cur_act is S_HARD_IGN and we never change its sigaction
3650 * (see code below).
3651 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003652
Denys Vlasenko458c1f22016-10-27 23:51:19 +02003653 if (signo == SIGCHLD)
3654 new_act = S_CATCH;
3655
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003656 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003657 cur_act = *t;
3658 if (cur_act == 0) {
3659 /* current setting is not yet known */
3660 if (sigaction(signo, NULL, &act)) {
3661 /* pretend it worked; maybe we should give a warning,
3662 * but other shells don't. We don't alter sigmode,
3663 * so we retry every time.
3664 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003665 return;
3666 }
3667 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003668 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003669 if (mflag
3670 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3671 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003672 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003673 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003674 }
Denys Vlasenko0f14f412017-08-06 20:06:19 +02003675 if (act.sa_handler == SIG_DFL && new_act == S_DFL) {
3676 /* installing SIG_DFL over SIG_DFL is a no-op */
3677 /* saves one sigaction call in each "sh -c SCRIPT" invocation */
3678 *t = S_DFL;
3679 return;
3680 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003681 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003682 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003683 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003684
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003685 *t = new_act;
3686
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003687 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003688 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003689 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003690 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003691 break;
3692 case S_IGN:
3693 act.sa_handler = SIG_IGN;
3694 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003695 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003696 /* flags and mask matter only if !DFL and !IGN, but we do it
3697 * for all cases for more deterministic behavior:
3698 */
Denys Vlasenko49e6bf22017-08-04 14:28:16 +02003699 act.sa_flags = 0; //TODO: why not SA_RESTART?
Ian Wienand89b3cba2011-04-16 20:05:14 +02003700 sigfillset(&act.sa_mask);
3701
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003702 sigaction_set(signo, &act);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003703}
3704
3705/* mode flags for set_curjob */
3706#define CUR_DELETE 2
3707#define CUR_RUNNING 1
3708#define CUR_STOPPED 0
3709
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003710#if JOBS
3711/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003712static int initialpgrp; //references:2
3713static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003714#endif
3715/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003716static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003717/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003718static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003719/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003720static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003721/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003722static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003723
Denys Vlasenko098b7132017-01-11 19:59:03 +01003724#if 0
3725/* Bash has a feature: it restores termios after a successful wait for
3726 * a foreground job which had at least one stopped or sigkilled member.
3727 * The probable rationale is that SIGSTOP and SIGKILL can preclude task from
3728 * properly restoring tty state. Should we do this too?
3729 * A reproducer: ^Z an interactive python:
3730 *
3731 * # python
3732 * Python 2.7.12 (...)
3733 * >>> ^Z
3734 * { python leaves tty in -icanon -echo state. We do survive that... }
3735 * [1]+ Stopped python
3736 * { ...however, next program (python #2) does not survive it well: }
3737 * # python
3738 * Python 2.7.12 (...)
3739 * >>> Traceback (most recent call last):
3740 * { above, I typed "qwerty<CR>", but -echo state is still in effect }
3741 * File "<stdin>", line 1, in <module>
3742 * NameError: name 'qwerty' is not defined
3743 *
3744 * The implementation below is modeled on bash code and seems to work.
3745 * However, I'm not sure we should do this. For one: what if I'd fg
3746 * the stopped python instead? It'll be confused by "restored" tty state.
3747 */
3748static struct termios shell_tty_info;
3749static void
3750get_tty_state(void)
3751{
3752 if (rootshell && ttyfd >= 0)
3753 tcgetattr(ttyfd, &shell_tty_info);
3754}
3755static void
3756set_tty_state(void)
3757{
3758 /* if (rootshell) - caller ensures this */
3759 if (ttyfd >= 0)
3760 tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info);
3761}
3762static int
3763job_signal_status(struct job *jp)
3764{
3765 int status;
3766 unsigned i;
3767 struct procstat *ps = jp->ps;
3768 for (i = 0; i < jp->nprocs; i++) {
3769 status = ps[i].ps_status;
3770 if (WIFSIGNALED(status) || WIFSTOPPED(status))
3771 return status;
3772 }
3773 return 0;
3774}
3775static void
3776restore_tty_if_stopped_or_signaled(struct job *jp)
3777{
3778//TODO: check what happens if we come from waitforjob() in expbackq()
3779 if (rootshell) {
3780 int s = job_signal_status(jp);
3781 if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */
3782 set_tty_state();
3783 }
3784}
3785#else
3786# define get_tty_state() ((void)0)
3787# define restore_tty_if_stopped_or_signaled(jp) ((void)0)
3788#endif
3789
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003790static void
3791set_curjob(struct job *jp, unsigned mode)
3792{
3793 struct job *jp1;
3794 struct job **jpp, **curp;
3795
3796 /* first remove from list */
3797 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003798 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003799 jp1 = *jpp;
3800 if (jp1 == jp)
3801 break;
3802 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003803 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003804 *jpp = jp1->prev_job;
3805
3806 /* Then re-insert in correct position */
3807 jpp = curp;
3808 switch (mode) {
3809 default:
3810#if DEBUG
3811 abort();
3812#endif
3813 case CUR_DELETE:
3814 /* job being deleted */
3815 break;
3816 case CUR_RUNNING:
3817 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003818 * put after all stopped jobs.
3819 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003820 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003821 jp1 = *jpp;
3822#if JOBS
3823 if (!jp1 || jp1->state != JOBSTOPPED)
3824#endif
3825 break;
3826 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003827 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003828 /* FALLTHROUGH */
3829#if JOBS
3830 case CUR_STOPPED:
3831#endif
3832 /* newly stopped job - becomes curjob */
3833 jp->prev_job = *jpp;
3834 *jpp = jp;
3835 break;
3836 }
3837}
3838
3839#if JOBS || DEBUG
3840static int
3841jobno(const struct job *jp)
3842{
3843 return jp - jobtab + 1;
3844}
3845#endif
3846
3847/*
3848 * Convert a job name to a job structure.
3849 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003850#if !JOBS
3851#define getjob(name, getctl) getjob(name)
3852#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003853static struct job *
3854getjob(const char *name, int getctl)
3855{
3856 struct job *jp;
3857 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003858 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003859 unsigned num;
3860 int c;
3861 const char *p;
3862 char *(*match)(const char *, const char *);
3863
3864 jp = curjob;
3865 p = name;
3866 if (!p)
3867 goto currentjob;
3868
3869 if (*p != '%')
3870 goto err;
3871
3872 c = *++p;
3873 if (!c)
3874 goto currentjob;
3875
3876 if (!p[1]) {
3877 if (c == '+' || c == '%') {
3878 currentjob:
3879 err_msg = "No current job";
3880 goto check;
3881 }
3882 if (c == '-') {
3883 if (jp)
3884 jp = jp->prev_job;
3885 err_msg = "No previous job";
3886 check:
3887 if (!jp)
3888 goto err;
3889 goto gotit;
3890 }
3891 }
3892
3893 if (is_number(p)) {
3894 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003895 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003896 jp = jobtab + num - 1;
3897 if (jp->used)
3898 goto gotit;
3899 goto err;
3900 }
3901 }
3902
3903 match = prefix;
3904 if (*p == '?') {
3905 match = strstr;
3906 p++;
3907 }
3908
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003909 found = NULL;
3910 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003911 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003912 if (found)
3913 goto err;
3914 found = jp;
3915 err_msg = "%s: ambiguous";
3916 }
3917 jp = jp->prev_job;
3918 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003919 if (!found)
3920 goto err;
3921 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003922
3923 gotit:
3924#if JOBS
3925 err_msg = "job %s not created under job control";
3926 if (getctl && jp->jobctl == 0)
3927 goto err;
3928#endif
3929 return jp;
3930 err:
3931 ash_msg_and_raise_error(err_msg, name);
3932}
3933
3934/*
3935 * Mark a job structure as unused.
3936 */
3937static void
3938freejob(struct job *jp)
3939{
3940 struct procstat *ps;
3941 int i;
3942
3943 INT_OFF;
3944 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003945 if (ps->ps_cmd != nullstr)
3946 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003947 }
3948 if (jp->ps != &jp->ps0)
3949 free(jp->ps);
3950 jp->used = 0;
3951 set_curjob(jp, CUR_DELETE);
3952 INT_ON;
3953}
3954
3955#if JOBS
3956static void
3957xtcsetpgrp(int fd, pid_t pgrp)
3958{
3959 if (tcsetpgrp(fd, pgrp))
Ron Yorstonbe366e52017-07-27 13:53:39 +01003960 ash_msg_and_raise_perror("can't set tty process group");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003961}
3962
3963/*
3964 * Turn job control on and off.
3965 *
3966 * Note: This code assumes that the third arg to ioctl is a character
3967 * pointer, which is true on Berkeley systems but not System V. Since
3968 * System V doesn't have job control yet, this isn't a problem now.
3969 *
3970 * Called with interrupts off.
3971 */
3972static void
3973setjobctl(int on)
3974{
3975 int fd;
3976 int pgrp;
3977
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003978 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003979 return;
3980 if (on) {
3981 int ofd;
3982 ofd = fd = open(_PATH_TTY, O_RDWR);
3983 if (fd < 0) {
3984 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3985 * That sometimes helps to acquire controlling tty.
3986 * Obviously, a workaround for bugs when someone
3987 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003988 fd = 2;
3989 while (!isatty(fd))
3990 if (--fd < 0)
3991 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003992 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003993 /* fd is a tty at this point */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02003994 fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
Denys Vlasenko10ad6222017-04-17 16:13:32 +02003995 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003996 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003997 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003998 goto out; /* F_DUPFD failed */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02003999 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
4000 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01004001 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004002 pgrp = tcgetpgrp(fd);
4003 if (pgrp < 0) {
4004 out:
4005 ash_msg("can't access tty; job control turned off");
4006 mflag = on = 0;
4007 goto close;
4008 }
4009 if (pgrp == getpgrp())
4010 break;
4011 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01004012 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004013 initialpgrp = pgrp;
4014
4015 setsignal(SIGTSTP);
4016 setsignal(SIGTTOU);
4017 setsignal(SIGTTIN);
4018 pgrp = rootpid;
4019 setpgid(0, pgrp);
4020 xtcsetpgrp(fd, pgrp);
4021 } else {
4022 /* turning job control off */
4023 fd = ttyfd;
4024 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004025 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004026 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00004027 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004028 setpgid(0, pgrp);
4029 setsignal(SIGTSTP);
4030 setsignal(SIGTTOU);
4031 setsignal(SIGTTIN);
4032 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00004033 if (fd >= 0)
4034 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004035 fd = -1;
4036 }
4037 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004038 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004039}
4040
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004041static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004042killcmd(int argc, char **argv)
4043{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004044 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004045 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004046 do {
4047 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004048 /*
4049 * "kill %N" - job kill
4050 * Converting to pgrp / pid kill
4051 */
4052 struct job *jp;
4053 char *dst;
4054 int j, n;
4055
4056 jp = getjob(argv[i], 0);
4057 /*
4058 * In jobs started under job control, we signal
4059 * entire process group by kill -PGRP_ID.
4060 * This happens, f.e., in interactive shell.
4061 *
4062 * Otherwise, we signal each child via
4063 * kill PID1 PID2 PID3.
4064 * Testcases:
4065 * sh -c 'sleep 1|sleep 1 & kill %1'
4066 * sh -c 'true|sleep 2 & sleep 1; kill %1'
4067 * sh -c 'true|sleep 1 & sleep 2; kill %1'
4068 */
4069 n = jp->nprocs; /* can't be 0 (I hope) */
4070 if (jp->jobctl)
4071 n = 1;
4072 dst = alloca(n * sizeof(int)*4);
4073 argv[i] = dst;
4074 for (j = 0; j < n; j++) {
4075 struct procstat *ps = &jp->ps[j];
4076 /* Skip non-running and not-stopped members
4077 * (i.e. dead members) of the job
4078 */
4079 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
4080 continue;
4081 /*
4082 * kill_main has matching code to expect
4083 * leading space. Needed to not confuse
4084 * negative pids with "kill -SIGNAL_NO" syntax
4085 */
4086 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
4087 }
4088 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004089 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004090 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004091 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004092 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004093}
4094
4095static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01004096showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004097{
Denys Vlasenko285ad152009-12-04 23:02:27 +01004098 struct procstat *ps;
4099 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004100
Denys Vlasenko285ad152009-12-04 23:02:27 +01004101 psend = jp->ps + jp->nprocs;
4102 for (ps = jp->ps + 1; ps < psend; ps++)
4103 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004104 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004105 flush_stdout_stderr();
4106}
4107
4108
4109static int
4110restartjob(struct job *jp, int mode)
4111{
4112 struct procstat *ps;
4113 int i;
4114 int status;
4115 pid_t pgid;
4116
4117 INT_OFF;
4118 if (jp->state == JOBDONE)
4119 goto out;
4120 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004121 pgid = jp->ps[0].ps_pid;
Denys Vlasenko098b7132017-01-11 19:59:03 +01004122 if (mode == FORK_FG) {
4123 get_tty_state();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004124 xtcsetpgrp(ttyfd, pgid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01004125 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004126 killpg(pgid, SIGCONT);
4127 ps = jp->ps;
4128 i = jp->nprocs;
4129 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004130 if (WIFSTOPPED(ps->ps_status)) {
4131 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004132 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00004133 ps++;
4134 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004135 out:
4136 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
4137 INT_ON;
4138 return status;
4139}
4140
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004141static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004142fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004143{
4144 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004145 int mode;
4146 int retval;
4147
4148 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
4149 nextopt(nullstr);
4150 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004151 do {
4152 jp = getjob(*argv, 1);
4153 if (mode == FORK_BG) {
4154 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004155 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004156 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004157 out1str(jp->ps[0].ps_cmd);
4158 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004159 retval = restartjob(jp, mode);
4160 } while (*argv && *++argv);
4161 return retval;
4162}
4163#endif
4164
4165static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02004166sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004167{
4168 int col;
4169 int st;
4170
4171 col = 0;
4172 if (!WIFEXITED(status)) {
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004173#if JOBS
4174 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004175 st = WSTOPSIG(status);
4176 else
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004177#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004178 st = WTERMSIG(status);
4179 if (sigonly) {
4180 if (st == SIGINT || st == SIGPIPE)
4181 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004182#if JOBS
4183 if (WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004184 goto out;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004185#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004186 }
4187 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01004188//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004189 col = fmtstr(s, 32, strsignal(st));
4190 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004191 strcpy(s + col, " (core dumped)");
4192 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004193 }
4194 } else if (!sigonly) {
4195 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004196 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004197 }
4198 out:
4199 return col;
4200}
4201
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004202static int
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004203wait_block_or_sig(int *status)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004204{
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004205 int pid;
4206
4207 do {
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004208 sigset_t mask;
4209
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004210 /* Poll all children for changes in their state */
4211 got_sigchld = 0;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004212 /* if job control is active, accept stopped processes too */
4213 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004214 if (pid != 0)
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004215 break; /* Error (e.g. EINTR, ECHILD) or pid */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004216
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004217 /* Children exist, but none are ready. Sleep until interesting signal */
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004218#if 1
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004219 sigfillset(&mask);
Denys Vlasenkob437df12018-12-08 15:35:24 +01004220 sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004221 while (!got_sigchld && !pending_sig)
4222 sigsuspend(&mask);
4223 sigprocmask(SIG_SETMASK, &mask, NULL);
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004224#else /* unsafe: a signal can set pending_sig after check, but before pause() */
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004225 while (!got_sigchld && !pending_sig)
4226 pause();
4227#endif
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004228
4229 /* If it was SIGCHLD, poll children again */
4230 } while (got_sigchld);
4231
4232 return pid;
4233}
4234
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004235#define DOWAIT_NONBLOCK 0
4236#define DOWAIT_BLOCK 1
4237#define DOWAIT_BLOCK_OR_SIG 2
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004238
4239static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004240dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004241{
4242 int pid;
4243 int status;
4244 struct job *jp;
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004245 struct job *thisjob = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004246
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004247 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00004248
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004249 /* It's wrong to call waitpid() outside of INT_OFF region:
4250 * signal can arrive just after syscall return and handler can
4251 * longjmp away, losing stop/exit notification processing.
4252 * Thus, for "jobs" builtin, and for waiting for a fg job,
4253 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4254 *
4255 * However, for "wait" builtin it is wrong to simply call waitpid()
4256 * in INT_OFF region: "wait" needs to wait for any running job
4257 * to change state, but should exit on any trap too.
4258 * In INT_OFF region, a signal just before syscall entry can set
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004259 * pending_sig variables, but we can't check them, and we would
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004260 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004261 *
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004262 * Because of this, we run inside INT_OFF, but use a special routine
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004263 * which combines waitpid() and sigsuspend().
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004264 * This is the reason why we need to have a handler for SIGCHLD:
Denys Vlasenko1ab7c2f2016-11-03 20:17:23 +01004265 * SIG_DFL handler does not wake sigsuspend().
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004266 */
4267 INT_OFF;
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004268 if (block == DOWAIT_BLOCK_OR_SIG) {
4269 pid = wait_block_or_sig(&status);
4270 } else {
4271 int wait_flags = 0;
4272 if (block == DOWAIT_NONBLOCK)
4273 wait_flags = WNOHANG;
4274 /* if job control is active, accept stopped processes too */
4275 if (doing_jobctl)
4276 wait_flags |= WUNTRACED;
4277 /* NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004278 pid = waitpid(-1, &status, wait_flags);
Denys Vlasenko8f7b0242016-10-28 17:16:11 +02004279 }
Denis Vlasenkob21f3792009-03-19 23:09:58 +00004280 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4281 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004282 if (pid <= 0)
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004283 goto out;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004284
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004285 thisjob = NULL;
4286 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004287 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004288 struct procstat *ps;
4289 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004290 if (jp->state == JOBDONE)
4291 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004292 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004293 ps = jp->ps;
4294 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004295 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004296 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004297 TRACE(("Job %d: changing status of proc %d "
4298 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004299 jobno(jp), pid, ps->ps_status, status));
4300 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004301 thisjob = jp;
4302 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004303 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004304 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004305#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004306 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004307 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004308 if (WIFSTOPPED(ps->ps_status)) {
4309 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004310 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004311 }
4312#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004313 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004314 if (!thisjob)
4315 continue;
4316
4317 /* Found the job where one of its processes changed its state.
4318 * Is there at least one live and running process in this job? */
4319 if (jobstate != JOBRUNNING) {
4320 /* No. All live processes in the job are stopped
4321 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4322 */
4323 thisjob->changed = 1;
4324 if (thisjob->state != jobstate) {
4325 TRACE(("Job %d: changing state from %d to %d\n",
4326 jobno(thisjob), thisjob->state, jobstate));
4327 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004328#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004329 if (jobstate == JOBSTOPPED)
4330 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004331#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004332 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004333 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004334 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004335 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004336 /* The process wasn't found in job list */
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004337#if JOBS
4338 if (!WIFSTOPPED(status))
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004339 jobless--;
Johannes Schindelin9d4dc842017-07-14 22:25:58 +02004340#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004341 out:
4342 INT_ON;
4343
4344 if (thisjob && thisjob == job) {
4345 char s[48 + 1];
4346 int len;
4347
Denys Vlasenko9c541002015-10-07 15:44:36 +02004348 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004349 if (len) {
4350 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004351 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004352 out2str(s);
4353 }
4354 }
4355 return pid;
4356}
4357
4358#if JOBS
4359static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004360showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004361{
4362 struct procstat *ps;
4363 struct procstat *psend;
4364 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004365 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004366 char s[16 + 16 + 48];
4367 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004368
4369 ps = jp->ps;
4370
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004371 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004372 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004373 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004374 return;
4375 }
4376
4377 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004378 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004379
4380 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004381 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004382 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004383 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004384
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004385 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004386 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004387
4388 psend = ps + jp->nprocs;
4389
4390 if (jp->state == JOBRUNNING) {
4391 strcpy(s + col, "Running");
4392 col += sizeof("Running") - 1;
4393 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004394 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004395 if (jp->state == JOBSTOPPED)
4396 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004397 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004398 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004399 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004400
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004401 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4402 * or prints several "PID | <cmdN>" lines,
4403 * depending on SHOW_PIDS bit.
4404 * We do not print status of individual processes
4405 * between PID and <cmdN>. bash does it, but not very well:
4406 * first line shows overall job status, not process status,
4407 * making it impossible to know 1st process status.
4408 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004409 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004410 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004411 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004412 s[0] = '\0';
4413 col = 33;
4414 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004415 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004416 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004417 fprintf(out, "%s%*c%s%s",
4418 s,
4419 33 - col >= 0 ? 33 - col : 0, ' ',
4420 ps == jp->ps ? "" : "| ",
4421 ps->ps_cmd
4422 );
4423 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004424 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004425
4426 jp->changed = 0;
4427
4428 if (jp->state == JOBDONE) {
4429 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4430 freejob(jp);
4431 }
4432}
4433
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004434/*
4435 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4436 * statuses have changed since the last call to showjobs.
4437 */
4438static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004439showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004440{
4441 struct job *jp;
4442
Denys Vlasenko883cea42009-07-11 15:31:59 +02004443 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004444
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004445 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004446 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004447 continue;
4448
4449 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004450 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004451 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004452 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004453 }
4454}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004455
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004456static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004457jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004458{
4459 int mode, m;
4460
4461 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004462 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004463 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004464 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004465 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004466 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004467 }
4468
4469 argv = argptr;
4470 if (*argv) {
4471 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004472 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004473 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004474 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004475 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004476 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004477
4478 return 0;
4479}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004480#endif /* JOBS */
4481
Michael Abbott359da5e2009-12-04 23:03:29 +01004482/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004483static int
4484getstatus(struct job *job)
4485{
4486 int status;
4487 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004488 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004489
Michael Abbott359da5e2009-12-04 23:03:29 +01004490 /* Fetch last member's status */
4491 ps = job->ps + job->nprocs - 1;
4492 status = ps->ps_status;
4493 if (pipefail) {
4494 /* "set -o pipefail" mode: use last _nonzero_ status */
4495 while (status == 0 && --ps >= job->ps)
4496 status = ps->ps_status;
4497 }
4498
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004499 retval = WEXITSTATUS(status);
4500 if (!WIFEXITED(status)) {
4501#if JOBS
4502 retval = WSTOPSIG(status);
4503 if (!WIFSTOPPED(status))
4504#endif
4505 {
4506 /* XXX: limits number of signals */
4507 retval = WTERMSIG(status);
4508#if JOBS
4509 if (retval == SIGINT)
4510 job->sigint = 1;
4511#endif
4512 }
4513 retval += 128;
4514 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004515 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004516 jobno(job), job->nprocs, status, retval));
4517 return retval;
4518}
4519
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004520static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004521waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004522{
4523 struct job *job;
4524 int retval;
4525 struct job *jp;
4526
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004527 nextopt(nullstr);
4528 retval = 0;
4529
4530 argv = argptr;
4531 if (!*argv) {
4532 /* wait for all jobs */
4533 for (;;) {
4534 jp = curjob;
4535 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004536 if (!jp) /* no running procs */
4537 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004538 if (jp->state == JOBRUNNING)
4539 break;
4540 jp->waited = 1;
4541 jp = jp->prev_job;
4542 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004543 /* man bash:
4544 * "When bash is waiting for an asynchronous command via
4545 * the wait builtin, the reception of a signal for which a trap
4546 * has been set will cause the wait builtin to return immediately
4547 * with an exit status greater than 128, immediately after which
4548 * the trap is executed."
Denys Vlasenko69188112016-10-27 20:18:18 +02004549 */
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004550 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004551 /* if child sends us a signal *and immediately exits*,
4552 * dowait() returns pid > 0. Check this case,
4553 * not "if (dowait() < 0)"!
4554 */
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004555 if (pending_sig)
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004556 goto sigout;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004557 }
4558 }
4559
4560 retval = 127;
4561 do {
4562 if (**argv != '%') {
4563 pid_t pid = number(*argv);
4564 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004565 while (1) {
4566 if (!job)
4567 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004568 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004569 break;
4570 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004571 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004572 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004573 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004574 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004575 /* loop until process terminated or stopped */
Denys Vlasenko69188112016-10-27 20:18:18 +02004576 while (job->state == JOBRUNNING) {
Denys Vlasenko458c1f22016-10-27 23:51:19 +02004577 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004578 if (pending_sig)
4579 goto sigout;
Denys Vlasenko69188112016-10-27 20:18:18 +02004580 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004581 job->waited = 1;
4582 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004583 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004584 } while (*++argv);
4585
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004586 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004587 return retval;
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02004588 sigout:
4589 retval = 128 + pending_sig;
4590 return retval;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004591}
4592
4593static struct job *
4594growjobtab(void)
4595{
4596 size_t len;
4597 ptrdiff_t offset;
4598 struct job *jp, *jq;
4599
4600 len = njobs * sizeof(*jp);
4601 jq = jobtab;
4602 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4603
4604 offset = (char *)jp - (char *)jq;
4605 if (offset) {
4606 /* Relocate pointers */
4607 size_t l = len;
4608
4609 jq = (struct job *)((char *)jq + l);
4610 while (l) {
4611 l -= sizeof(*jp);
4612 jq--;
4613#define joff(p) ((struct job *)((char *)(p) + l))
4614#define jmove(p) (p) = (void *)((char *)(p) + offset)
4615 if (joff(jp)->ps == &jq->ps0)
4616 jmove(joff(jp)->ps);
4617 if (joff(jp)->prev_job)
4618 jmove(joff(jp)->prev_job);
4619 }
4620 if (curjob)
4621 jmove(curjob);
4622#undef joff
4623#undef jmove
4624 }
4625
4626 njobs += 4;
4627 jobtab = jp;
4628 jp = (struct job *)((char *)jp + len);
4629 jq = jp + 3;
4630 do {
4631 jq->used = 0;
4632 } while (--jq >= jp);
4633 return jp;
4634}
4635
4636/*
4637 * Return a new job structure.
4638 * Called with interrupts off.
4639 */
4640static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004641makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004642{
4643 int i;
4644 struct job *jp;
4645
4646 for (i = njobs, jp = jobtab; ; jp++) {
4647 if (--i < 0) {
4648 jp = growjobtab();
4649 break;
4650 }
4651 if (jp->used == 0)
4652 break;
4653 if (jp->state != JOBDONE || !jp->waited)
4654 continue;
4655#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004656 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004657 continue;
4658#endif
4659 freejob(jp);
4660 break;
4661 }
4662 memset(jp, 0, sizeof(*jp));
4663#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004664 /* jp->jobctl is a bitfield.
Denys Vlasenko098b7132017-01-11 19:59:03 +01004665 * "jp->jobctl |= doing_jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004666 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004667 jp->jobctl = 1;
4668#endif
4669 jp->prev_job = curjob;
4670 curjob = jp;
4671 jp->used = 1;
4672 jp->ps = &jp->ps0;
4673 if (nprocs > 1) {
4674 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4675 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004676 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004677 jobno(jp)));
4678 return jp;
4679}
4680
4681#if JOBS
4682/*
4683 * Return a string identifying a command (to be printed by the
4684 * jobs command).
4685 */
4686static char *cmdnextc;
4687
4688static void
4689cmdputs(const char *s)
4690{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004691 static const char vstype[VSTYPE + 1][3] = {
4692 "", "}", "-", "+", "?", "=",
4693 "%", "%%", "#", "##"
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004694 IF_BASH_SUBSTR(, ":")
4695 IF_BASH_PATTERN_SUBST(, "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004696 };
4697
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004698 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004699 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004700 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004701 unsigned char c;
4702 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004703 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004704
Denys Vlasenko46a14772009-12-10 21:27:13 +01004705 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004706 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4707 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004708 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004709 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004710 switch (c) {
4711 case CTLESC:
4712 c = *p++;
4713 break;
4714 case CTLVAR:
4715 subtype = *p++;
4716 if ((subtype & VSTYPE) == VSLENGTH)
4717 str = "${#";
4718 else
4719 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004720 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004721 case CTLENDVAR:
4722 str = "\"}" + !(quoted & 1);
4723 quoted >>= 1;
4724 subtype = 0;
4725 goto dostr;
4726 case CTLBACKQ:
4727 str = "$(...)";
4728 goto dostr;
Denys Vlasenko0b883582016-12-23 16:49:07 +01004729#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004730 case CTLARI:
4731 str = "$((";
4732 goto dostr;
4733 case CTLENDARI:
4734 str = "))";
4735 goto dostr;
4736#endif
4737 case CTLQUOTEMARK:
4738 quoted ^= 1;
4739 c = '"';
4740 break;
4741 case '=':
4742 if (subtype == 0)
4743 break;
4744 if ((subtype & VSTYPE) != VSNORMAL)
4745 quoted <<= 1;
4746 str = vstype[subtype & VSTYPE];
4747 if (subtype & VSNUL)
4748 c = ':';
4749 else
4750 goto checkstr;
4751 break;
4752 case '\'':
4753 case '\\':
4754 case '"':
4755 case '$':
4756 /* These can only happen inside quotes */
4757 cc[0] = c;
4758 str = cc;
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004759//FIXME:
4760// $ true $$ &
4761// $ <cr>
4762// [1]+ Done true ${\$} <<=== BUG: ${\$} is not a valid way to write $$ (${$} would be ok)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004763 c = '\\';
4764 break;
4765 default:
4766 break;
4767 }
4768 USTPUTC(c, nextc);
4769 checkstr:
4770 if (!str)
4771 continue;
4772 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004773 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004774 USTPUTC(c, nextc);
4775 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004776 } /* while *p++ not NUL */
4777
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004778 if (quoted & 1) {
4779 USTPUTC('"', nextc);
4780 }
4781 *nextc = 0;
4782 cmdnextc = nextc;
4783}
4784
4785/* cmdtxt() and cmdlist() call each other */
4786static void cmdtxt(union node *n);
4787
4788static void
4789cmdlist(union node *np, int sep)
4790{
4791 for (; np; np = np->narg.next) {
4792 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004793 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004794 cmdtxt(np);
4795 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004796 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004797 }
4798}
4799
4800static void
4801cmdtxt(union node *n)
4802{
4803 union node *np;
4804 struct nodelist *lp;
4805 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004806
4807 if (!n)
4808 return;
4809 switch (n->type) {
4810 default:
4811#if DEBUG
4812 abort();
4813#endif
4814 case NPIPE:
4815 lp = n->npipe.cmdlist;
4816 for (;;) {
4817 cmdtxt(lp->n);
4818 lp = lp->next;
4819 if (!lp)
4820 break;
4821 cmdputs(" | ");
4822 }
4823 break;
4824 case NSEMI:
4825 p = "; ";
4826 goto binop;
4827 case NAND:
4828 p = " && ";
4829 goto binop;
4830 case NOR:
4831 p = " || ";
4832 binop:
4833 cmdtxt(n->nbinary.ch1);
4834 cmdputs(p);
4835 n = n->nbinary.ch2;
4836 goto donode;
4837 case NREDIR:
4838 case NBACKGND:
4839 n = n->nredir.n;
4840 goto donode;
4841 case NNOT:
4842 cmdputs("!");
4843 n = n->nnot.com;
4844 donode:
4845 cmdtxt(n);
4846 break;
4847 case NIF:
4848 cmdputs("if ");
4849 cmdtxt(n->nif.test);
4850 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004851 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004852 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004853 cmdputs("; else ");
4854 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004855 } else {
4856 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004857 }
4858 p = "; fi";
4859 goto dotail;
4860 case NSUBSHELL:
4861 cmdputs("(");
4862 n = n->nredir.n;
4863 p = ")";
4864 goto dotail;
4865 case NWHILE:
4866 p = "while ";
4867 goto until;
4868 case NUNTIL:
4869 p = "until ";
4870 until:
4871 cmdputs(p);
4872 cmdtxt(n->nbinary.ch1);
4873 n = n->nbinary.ch2;
4874 p = "; done";
4875 dodo:
4876 cmdputs("; do ");
4877 dotail:
4878 cmdtxt(n);
4879 goto dotail2;
4880 case NFOR:
4881 cmdputs("for ");
4882 cmdputs(n->nfor.var);
4883 cmdputs(" in ");
4884 cmdlist(n->nfor.args, 1);
4885 n = n->nfor.body;
4886 p = "; done";
4887 goto dodo;
4888 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01004889 cmdputs(n->ndefun.text);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004890 p = "() { ... }";
4891 goto dotail2;
4892 case NCMD:
4893 cmdlist(n->ncmd.args, 1);
4894 cmdlist(n->ncmd.redirect, 0);
4895 break;
4896 case NARG:
4897 p = n->narg.text;
4898 dotail2:
4899 cmdputs(p);
4900 break;
4901 case NHERE:
4902 case NXHERE:
4903 p = "<<...";
4904 goto dotail2;
4905 case NCASE:
4906 cmdputs("case ");
4907 cmdputs(n->ncase.expr->narg.text);
4908 cmdputs(" in ");
4909 for (np = n->ncase.cases; np; np = np->nclist.next) {
4910 cmdtxt(np->nclist.pattern);
4911 cmdputs(") ");
4912 cmdtxt(np->nclist.body);
4913 cmdputs(";; ");
4914 }
4915 p = "esac";
4916 goto dotail2;
4917 case NTO:
4918 p = ">";
4919 goto redir;
4920 case NCLOBBER:
4921 p = ">|";
4922 goto redir;
4923 case NAPPEND:
4924 p = ">>";
4925 goto redir;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01004926#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00004927 case NTO2:
4928#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004929 case NTOFD:
4930 p = ">&";
4931 goto redir;
4932 case NFROM:
4933 p = "<";
4934 goto redir;
4935 case NFROMFD:
4936 p = "<&";
4937 goto redir;
4938 case NFROMTO:
4939 p = "<>";
4940 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004941 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004942 cmdputs(p);
4943 if (n->type == NTOFD || n->type == NFROMFD) {
Denys Vlasenkod0fff912017-07-31 14:32:18 +02004944 if (n->ndup.dupfd >= 0)
4945 cmdputs(utoa(n->ndup.dupfd));
4946 else
4947 cmdputs("-");
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004948 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004949 }
4950 n = n->nfile.fname;
4951 goto donode;
4952 }
4953}
4954
4955static char *
4956commandtext(union node *n)
4957{
4958 char *name;
4959
4960 STARTSTACKSTR(cmdnextc);
4961 cmdtxt(n);
4962 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004963 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004964 return ckstrdup(name);
4965}
4966#endif /* JOBS */
4967
4968/*
4969 * Fork off a subshell. If we are doing job control, give the subshell its
4970 * own process group. Jp is a job structure that the job is to be added to.
4971 * N is the command that will be evaluated by the child. Both jp and n may
4972 * be NULL. The mode parameter can be one of the following:
4973 * FORK_FG - Fork off a foreground process.
4974 * FORK_BG - Fork off a background process.
4975 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4976 * process group even if job control is on.
4977 *
4978 * When job control is turned off, background processes have their standard
4979 * input redirected to /dev/null (except for the second and later processes
4980 * in a pipeline).
4981 *
4982 * Called with interrupts off.
4983 */
4984/*
4985 * Clear traps on a fork.
4986 */
4987static void
4988clear_traps(void)
4989{
4990 char **tp;
4991
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004992 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004993 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004994 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004995 if (trap_ptr == trap)
4996 free(*tp);
4997 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004998 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004999 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005000 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005001 }
5002 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02005003 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02005004 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005005}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005006
5007/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005008static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00005009
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005010/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02005011/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02005012static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005013forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005014{
5015 int oldlvl;
5016
5017 TRACE(("Child shell %d\n", getpid()));
5018 oldlvl = shlvl;
5019 shlvl++;
5020
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005021 /* man bash: "Non-builtin commands run by bash have signal handlers
5022 * set to the values inherited by the shell from its parent".
5023 * Do we do it correctly? */
5024
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005025 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02005026
5027 if (mode == FORK_NOJOB /* is it `xxx` ? */
5028 && n && n->type == NCMD /* is it single cmd? */
5029 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01005030 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005031 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
5032 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
5033 ) {
5034 TRACE(("Trap hack\n"));
5035 /* Awful hack for `trap` or $(trap).
5036 *
5037 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
5038 * contains an example where "trap" is executed in a subshell:
5039 *
5040 * save_traps=$(trap)
5041 * ...
5042 * eval "$save_traps"
5043 *
5044 * Standard does not say that "trap" in subshell shall print
5045 * parent shell's traps. It only says that its output
5046 * must have suitable form, but then, in the above example
5047 * (which is not supposed to be normative), it implies that.
5048 *
5049 * bash (and probably other shell) does implement it
5050 * (traps are reset to defaults, but "trap" still shows them),
5051 * but as a result, "trap" logic is hopelessly messed up:
5052 *
5053 * # trap
5054 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
5055 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
5056 * # true | trap <--- trap is in subshell - no output (ditto)
5057 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
5058 * trap -- 'echo Ho' SIGWINCH
5059 * # echo `(trap)` <--- in subshell in subshell - output
5060 * trap -- 'echo Ho' SIGWINCH
5061 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
5062 * trap -- 'echo Ho' SIGWINCH
5063 *
5064 * The rules when to forget and when to not forget traps
5065 * get really complex and nonsensical.
5066 *
5067 * Our solution: ONLY bare $(trap) or `trap` is special.
5068 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005069 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02005070 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02005071 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02005072 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02005073 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005074#if JOBS
5075 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005076 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005077 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005078 pid_t pgrp;
5079
5080 if (jp->nprocs == 0)
5081 pgrp = getpid();
5082 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005083 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005084 /* this can fail because we are doing it in the parent also */
5085 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005086 if (mode == FORK_FG)
5087 xtcsetpgrp(ttyfd, pgrp);
5088 setsignal(SIGTSTP);
5089 setsignal(SIGTTOU);
5090 } else
5091#endif
5092 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005093 /* man bash: "When job control is not in effect,
5094 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005095 ignoresig(SIGINT);
5096 ignoresig(SIGQUIT);
5097 if (jp->nprocs == 0) {
5098 close(0);
5099 if (open(bb_dev_null, O_RDONLY) != 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005100 ash_msg_and_raise_perror("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005101 }
5102 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01005103 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005104 if (iflag) { /* why if iflag only? */
5105 setsignal(SIGINT);
5106 setsignal(SIGTERM);
5107 }
5108 /* man bash:
5109 * "In all cases, bash ignores SIGQUIT. Non-builtin
5110 * commands run by bash have signal handlers
5111 * set to the values inherited by the shell
5112 * from its parent".
5113 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005114 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005115 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005116#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02005117 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01005118 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02005119 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005120 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02005121 /* "jobs": we do not want to clear job list for it,
5122 * instead we remove only _its_ own_ job from job list.
5123 * This makes "jobs .... | cat" more useful.
5124 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005125 freejob(curjob);
5126 return;
5127 }
5128#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005129 for (jp = curjob; jp; jp = jp->prev_job)
5130 freejob(jp);
5131 jobless = 0;
5132}
5133
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00005134/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00005135#if !JOBS
5136#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5137#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005138static void
5139forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5140{
5141 TRACE(("In parent shell: child = %d\n", pid));
5142 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005143 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00005144 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5145 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005146 jobless++;
5147 return;
5148 }
5149#if JOBS
5150 if (mode != FORK_NOJOB && jp->jobctl) {
5151 int pgrp;
5152
5153 if (jp->nprocs == 0)
5154 pgrp = pid;
5155 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01005156 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005157 /* This can fail because we are doing it in the child also */
5158 setpgid(pid, pgrp);
5159 }
5160#endif
5161 if (mode == FORK_BG) {
5162 backgndpid = pid; /* set $! */
5163 set_curjob(jp, CUR_RUNNING);
5164 }
5165 if (jp) {
5166 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01005167 ps->ps_pid = pid;
5168 ps->ps_status = -1;
5169 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005170#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005171 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01005172 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005173#endif
5174 }
5175}
5176
Denys Vlasenko70392332016-10-27 02:31:55 +02005177/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005178static int
5179forkshell(struct job *jp, union node *n, int mode)
5180{
5181 int pid;
5182
5183 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5184 pid = fork();
5185 if (pid < 0) {
5186 TRACE(("Fork failed, errno=%d", errno));
5187 if (jp)
5188 freejob(jp);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005189 ash_msg_and_raise_perror("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005190 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02005191 if (pid == 0) {
5192 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02005193 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005194 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005195 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02005196 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005197 return pid;
5198}
5199
5200/*
5201 * Wait for job to finish.
5202 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005203 * Under job control we have the problem that while a child process
5204 * is running interrupts generated by the user are sent to the child
5205 * but not to the shell. This means that an infinite loop started by
5206 * an interactive user may be hard to kill. With job control turned off,
5207 * an interactive user may place an interactive program inside a loop.
5208 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005209 * these interrupts to also abort the loop. The approach we take here
5210 * is to have the shell ignore interrupt signals while waiting for a
5211 * foreground process to terminate, and then send itself an interrupt
5212 * signal if the child process was terminated by an interrupt signal.
5213 * Unfortunately, some programs want to do a bit of cleanup and then
5214 * exit on interrupt; unless these processes terminate themselves by
5215 * sending a signal to themselves (instead of calling exit) they will
5216 * confuse this approach.
5217 *
5218 * Called with interrupts off.
5219 */
5220static int
5221waitforjob(struct job *jp)
5222{
5223 int st;
5224
5225 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005226
5227 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005228 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005229 /* In non-interactive shells, we _can_ get
5230 * a keyboard signal here and be EINTRed,
5231 * but we just loop back, waiting for command to complete.
5232 *
5233 * man bash:
5234 * "If bash is waiting for a command to complete and receives
5235 * a signal for which a trap has been set, the trap
5236 * will not be executed until the command completes."
5237 *
5238 * Reality is that even if trap is not set, bash
5239 * will not act on the signal until command completes.
5240 * Try this. sleep5intoff.c:
5241 * #include <signal.h>
5242 * #include <unistd.h>
5243 * int main() {
5244 * sigset_t set;
5245 * sigemptyset(&set);
5246 * sigaddset(&set, SIGINT);
5247 * sigaddset(&set, SIGQUIT);
5248 * sigprocmask(SIG_BLOCK, &set, NULL);
5249 * sleep(5);
5250 * return 0;
5251 * }
5252 * $ bash -c './sleep5intoff; echo hi'
5253 * ^C^C^C^C <--- pressing ^C once a second
5254 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005255 * $ bash -c './sleep5intoff; echo hi'
5256 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5257 * $ _
5258 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005259 dowait(DOWAIT_BLOCK, jp);
5260 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005261 INT_ON;
5262
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005263 st = getstatus(jp);
5264#if JOBS
5265 if (jp->jobctl) {
5266 xtcsetpgrp(ttyfd, rootpid);
Denys Vlasenko098b7132017-01-11 19:59:03 +01005267 restore_tty_if_stopped_or_signaled(jp);
5268
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005269 /*
5270 * This is truly gross.
5271 * If we're doing job control, then we did a TIOCSPGRP which
5272 * caused us (the shell) to no longer be in the controlling
5273 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5274 * intuit from the subprocess exit status whether a SIGINT
5275 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5276 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00005277 if (jp->sigint) /* TODO: do the same with all signals */
5278 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00005279 }
5280 if (jp->state == JOBDONE)
5281#endif
5282 freejob(jp);
5283 return st;
5284}
5285
5286/*
5287 * return 1 if there are stopped jobs, otherwise 0
5288 */
5289static int
5290stoppedjobs(void)
5291{
5292 struct job *jp;
5293 int retval;
5294
5295 retval = 0;
5296 if (job_warning)
5297 goto out;
5298 jp = curjob;
5299 if (jp && jp->state == JOBSTOPPED) {
5300 out2str("You have stopped jobs.\n");
5301 job_warning = 2;
5302 retval++;
5303 }
5304 out:
5305 return retval;
5306}
5307
5308
Denys Vlasenko70392332016-10-27 02:31:55 +02005309/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005310 * Code for dealing with input/output redirection.
5311 */
5312
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005313#undef EMPTY
5314#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005315#define EMPTY -2 /* marks an unused slot in redirtab */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005316#define CLOSED -1 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005317
5318/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005319 * Handle here documents. Normally we fork off a process to write the
5320 * data to a pipe. If the document is short, we can stuff the data in
5321 * the pipe without forking.
5322 */
5323/* openhere needs this forward reference */
5324static void expandhere(union node *arg, int fd);
5325static int
5326openhere(union node *redir)
5327{
5328 int pip[2];
5329 size_t len = 0;
5330
5331 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02005332 ash_msg_and_raise_perror("can't create pipe");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005333 if (redir->type == NHERE) {
5334 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005335 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005336 full_write(pip[1], redir->nhere.doc->narg.text, len);
5337 goto out;
5338 }
5339 }
5340 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005341 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005342 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005343 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5344 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5345 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5346 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005347 signal(SIGPIPE, SIG_DFL);
5348 if (redir->type == NHERE)
5349 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005350 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005351 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005352 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005353 }
5354 out:
5355 close(pip[1]);
5356 return pip[0];
5357}
5358
5359static int
5360openredirect(union node *redir)
5361{
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005362 struct stat sb;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005363 char *fname;
5364 int f;
5365
5366 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005367/* Can't happen, our single caller does this itself */
5368// case NTOFD:
5369// case NFROMFD:
5370// return -1;
5371 case NHERE:
5372 case NXHERE:
5373 return openhere(redir);
5374 }
5375
5376 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5377 * allocated space. Do it only when we know it is safe.
5378 */
5379 fname = redir->nfile.expfname;
5380
5381 switch (redir->nfile.type) {
5382 default:
5383#if DEBUG
5384 abort();
5385#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005386 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005387 f = open(fname, O_RDONLY);
5388 if (f < 0)
5389 goto eopen;
5390 break;
5391 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005392 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005393 if (f < 0)
5394 goto ecreate;
5395 break;
5396 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005397#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00005398 case NTO2:
5399#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005400 /* Take care of noclobber mode. */
5401 if (Cflag) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005402 if (stat(fname, &sb) < 0) {
5403 f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5404 if (f < 0)
5405 goto ecreate;
5406 } else if (!S_ISREG(sb.st_mode)) {
5407 f = open(fname, O_WRONLY, 0666);
5408 if (f < 0)
5409 goto ecreate;
Denys Vlasenko355ec352018-04-02 13:34:57 +02005410 if (!fstat(f, &sb) && S_ISREG(sb.st_mode)) {
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005411 close(f);
5412 errno = EEXIST;
5413 goto ecreate;
5414 }
5415 } else {
5416 errno = EEXIST;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005417 goto ecreate;
Denys Vlasenkof1a5cb02017-07-25 17:47:48 +02005418 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005419 break;
5420 }
5421 /* FALLTHROUGH */
5422 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005423 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5424 if (f < 0)
5425 goto ecreate;
5426 break;
5427 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005428 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5429 if (f < 0)
5430 goto ecreate;
5431 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005432 }
5433
5434 return f;
5435 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005436 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005437 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005438 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005439}
5440
5441/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005442 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005443 */
5444static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005445savefd(int from)
5446{
5447 int newfd;
5448 int err;
5449
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005450 newfd = fcntl(from, F_DUPFD_CLOEXEC, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02005451 err = newfd < 0 ? errno : 0;
5452 if (err != EBADF) {
5453 if (err)
Ron Yorstonbe366e52017-07-27 13:53:39 +01005454 ash_msg_and_raise_perror("%d", from);
Denys Vlasenko64774602016-10-26 15:24:30 +02005455 close(from);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005456 if (F_DUPFD_CLOEXEC == F_DUPFD)
5457 close_on_exec_on(newfd);
Denys Vlasenko64774602016-10-26 15:24:30 +02005458 }
5459
5460 return newfd;
5461}
5462static int
5463dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005464{
5465 int newfd;
5466
Denys Vlasenko64774602016-10-26 15:24:30 +02005467 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005468 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005469 /* Happens when source fd is not open: try "echo >&99" */
Ron Yorstonbe366e52017-07-27 13:53:39 +01005470 ash_msg_and_raise_perror("%d", from);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005471 }
5472 return newfd;
5473}
Denys Vlasenko035486c2017-07-31 04:09:19 +02005474static int
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005475dup_CLOEXEC(int fd, int avoid_fd)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005476{
5477 int newfd;
5478 repeat:
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005479 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
5480 if (newfd >= 0) {
5481 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005482 close_on_exec_on(newfd);
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005483 } else { /* newfd < 0 */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005484 if (errno == EBUSY)
5485 goto repeat;
5486 if (errno == EINTR)
5487 goto repeat;
5488 }
5489 return newfd;
5490}
5491static int
5492xdup_CLOEXEC_and_close(int fd, int avoid_fd)
5493{
5494 int newfd;
5495 repeat:
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005496 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005497 if (newfd < 0) {
5498 if (errno == EBUSY)
5499 goto repeat;
5500 if (errno == EINTR)
5501 goto repeat;
5502 /* fd was not open? */
5503 if (errno == EBADF)
5504 return fd;
5505 ash_msg_and_raise_perror("%d", newfd);
5506 }
Denys Vlasenko60fb98e2018-03-30 22:15:14 +02005507 if (F_DUPFD_CLOEXEC == F_DUPFD)
5508 close_on_exec_on(newfd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005509 close(fd);
5510 return newfd;
5511}
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005512
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005513/* Struct def and variable are moved down to the first usage site */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005514struct squirrel {
5515 int orig_fd;
5516 int moved_to;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005517};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005518struct redirtab {
5519 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005520 int pair_count;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005521 struct squirrel two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005522};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005523#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005524
Denys Vlasenko035486c2017-07-31 04:09:19 +02005525static void
5526add_squirrel_closed(struct redirtab *sq, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005527{
5528 int i;
5529
Denys Vlasenko035486c2017-07-31 04:09:19 +02005530 if (!sq)
5531 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005532
Denys Vlasenko035486c2017-07-31 04:09:19 +02005533 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5534 /* If we collide with an already moved fd... */
5535 if (fd == sq->two_fd[i].orig_fd) {
5536 /* Examples:
5537 * "echo 3>FILE 3>&- 3>FILE"
5538 * "echo 3>&- 3>FILE"
5539 * No need for last redirect to insert
5540 * another "need to close 3" indicator.
5541 */
5542 TRACE(("redirect_fd %d: already moved or closed\n", fd));
5543 return;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005544 }
5545 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005546 TRACE(("redirect_fd %d: previous fd was closed\n", fd));
5547 sq->two_fd[i].orig_fd = fd;
5548 sq->two_fd[i].moved_to = CLOSED;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005549}
5550
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005551static int
Denys Vlasenko035486c2017-07-31 04:09:19 +02005552save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005553{
Denys Vlasenko035486c2017-07-31 04:09:19 +02005554 int i, new_fd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005555
Denys Vlasenko035486c2017-07-31 04:09:19 +02005556 if (avoid_fd < 9) /* the important case here is that it can be -1 */
5557 avoid_fd = 9;
5558
5559#if JOBS
5560 if (fd == ttyfd) {
5561 /* Testcase: "ls -l /proc/$$/fd 10>&-" should work */
5562 ttyfd = xdup_CLOEXEC_and_close(ttyfd, avoid_fd);
5563 TRACE(("redirect_fd %d: matches ttyfd, moving it to %d\n", fd, ttyfd));
5564 return 1; /* "we closed fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005565 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005566#endif
5567 /* Are we called from redirect(0)? E.g. redirect
5568 * in a forked child. No need to save fds,
5569 * we aren't going to use them anymore, ok to trash.
5570 */
5571 if (!sq)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005572 return 0;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005573
5574 /* If this one of script's fds? */
5575 if (fd != 0) {
5576 struct parsefile *pf = g_parsefile;
5577 while (pf) {
5578 /* We skip fd == 0 case because of the following:
5579 * $ ash # running ash interactively
5580 * $ . ./script.sh
5581 * and in script.sh: "exec 9>&0".
5582 * Even though top-level pf_fd _is_ 0,
5583 * it's still ok to use it: "read" builtin uses it,
5584 * why should we cripple "exec" builtin?
5585 */
5586 if (fd == pf->pf_fd) {
5587 pf->pf_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
5588 return 1; /* "we closed fd" */
5589 }
5590 pf = pf->prev;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005591 }
5592 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005593
5594 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
5595
5596 /* First: do we collide with some already moved fds? */
5597 for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) {
5598 /* If we collide with an already moved fd... */
5599 if (fd == sq->two_fd[i].moved_to) {
Denys Vlasenko9acd63c2018-03-28 18:35:07 +02005600 new_fd = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005601 sq->two_fd[i].moved_to = new_fd;
5602 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5603 if (new_fd < 0) /* what? */
5604 xfunc_die();
5605 return 0; /* "we did not close fd" */
5606 }
5607 if (fd == sq->two_fd[i].orig_fd) {
5608 /* Example: echo Hello >/dev/null 1>&2 */
5609 TRACE(("redirect_fd %d: already moved\n", fd));
5610 return 0; /* "we did not close fd" */
5611 }
5612 }
5613
5614 /* 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 +02005615 new_fd = dup_CLOEXEC(fd, avoid_fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005616 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5617 if (new_fd < 0) {
5618 if (errno != EBADF)
5619 xfunc_die();
5620 /* new_fd = CLOSED; - already is -1 */
5621 }
5622 sq->two_fd[i].moved_to = new_fd;
5623 sq->two_fd[i].orig_fd = fd;
5624
5625 /* if we move stderr, let "set -x" code know */
5626 if (fd == preverrout_fd)
5627 preverrout_fd = new_fd;
5628
5629 return 0; /* "we did not close fd" */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005630}
5631
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005632static int
5633internally_opened_fd(int fd, struct redirtab *sq)
5634{
5635 int i;
5636#if JOBS
5637 if (fd == ttyfd)
5638 return 1;
5639#endif
5640 /* If this one of script's fds? */
5641 if (fd != 0) {
5642 struct parsefile *pf = g_parsefile;
5643 while (pf) {
5644 if (fd == pf->pf_fd)
5645 return 1;
5646 pf = pf->prev;
5647 }
5648 }
5649
5650 if (sq) for (i = 0; i < sq->pair_count && sq->two_fd[i].orig_fd != EMPTY; i++) {
5651 if (fd == sq->two_fd[i].moved_to)
5652 return 1;
5653 }
5654 return 0;
5655}
5656
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005657/*
5658 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5659 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005660 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005661 */
5662/* flags passed to redirect */
5663#define REDIR_PUSH 01 /* save previous values of file descriptors */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005664static void
5665redirect(union node *redir, int flags)
5666{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005667 struct redirtab *sv;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005668
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005669 if (!redir)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005670 return;
Denys Vlasenko035486c2017-07-31 04:09:19 +02005671
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005672 sv = NULL;
5673 INT_OFF;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005674 if (flags & REDIR_PUSH)
5675 sv = redirlist;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005676 do {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005677 int fd;
5678 int newfd;
5679 int close_fd;
5680 int closed;
5681
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005682 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005683 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005684 //bb_error_msg("doing %d > %d", fd, newfd);
5685 newfd = redir->ndup.dupfd;
5686 close_fd = -1;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005687 } else {
5688 newfd = openredirect(redir); /* always >= 0 */
5689 if (fd == newfd) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005690 /* open() gave us precisely the fd we wanted.
5691 * This means that this fd was not busy
5692 * (not opened to anywhere).
5693 * Remember to close it on restore:
5694 */
5695 add_squirrel_closed(sv, fd);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005696 continue;
5697 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005698 close_fd = newfd;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005699 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005700
5701 if (fd == newfd)
5702 continue;
5703
5704 /* if "N>FILE": move newfd to fd */
5705 /* if "N>&M": dup newfd to fd */
5706 /* if "N>&-": close fd (newfd is -1) */
5707
5708 IF_BASH_REDIR_OUTPUT(redirect_more:)
5709
5710 closed = save_fd_on_redirect(fd, /*avoid:*/ newfd, sv);
5711 if (newfd == -1) {
5712 /* "N>&-" means "close me" */
5713 if (!closed) {
5714 /* ^^^ optimization: saving may already
5715 * have closed it. If not... */
5716 close(fd);
Denis Vlasenko22f74142008-07-24 22:34:43 +00005717 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005718 } else {
Denys Vlasenko32fdf2f2017-07-31 04:32:06 +02005719 /* if newfd is a script fd or saved fd, simulate EBADF */
5720 if (internally_opened_fd(newfd, sv)) {
5721 errno = EBADF;
5722 ash_msg_and_raise_perror("%d", newfd);
5723 }
Denys Vlasenko64774602016-10-26 15:24:30 +02005724 dup2_or_raise(newfd, fd);
Denys Vlasenko035486c2017-07-31 04:09:19 +02005725 if (close_fd >= 0) /* "N>FILE" or ">&FILE" or heredoc? */
5726 close(close_fd);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01005727#if BASH_REDIR_OUTPUT
Denys Vlasenko035486c2017-07-31 04:09:19 +02005728 if (redir->nfile.type == NTO2 && fd == 1) {
5729 /* ">&FILE". we already redirected to 1, now copy 1 to 2 */
5730 fd = 2;
5731 newfd = 1;
5732 close_fd = -1;
5733 goto redirect_more;
5734 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005735#endif
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005736 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005737 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005738 INT_ON;
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005739
5740//dash:#define REDIR_SAVEFD2 03 /* set preverrout */
5741#define REDIR_SAVEFD2 0
5742 // dash has a bug: since REDIR_SAVEFD2=3 and REDIR_PUSH=1, this test
5743 // triggers for pure REDIR_PUSH too. Thus, this is done almost always,
5744 // not only for calls with flags containing REDIR_SAVEFD2.
Denys Vlasenko035486c2017-07-31 04:09:19 +02005745 // We do this unconditionally (see save_fd_on_redirect()).
Denys Vlasenkod07a15b2017-07-30 16:51:05 +02005746 //if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5747 // preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005748}
5749
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005750static int
5751redirectsafe(union node *redir, int flags)
5752{
5753 int err;
5754 volatile int saveint;
5755 struct jmploc *volatile savehandler = exception_handler;
5756 struct jmploc jmploc;
5757
5758 SAVE_INT(saveint);
5759 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
Denys Vlasenko035486c2017-07-31 04:09:19 +02005760 err = setjmp(jmploc.loc); /* was = setjmp(jmploc.loc) * 2; */
Denys Vlasenko170f93e2017-07-29 18:54:53 +02005761 if (!err) {
5762 exception_handler = &jmploc;
5763 redirect(redir, flags);
5764 }
5765 exception_handler = savehandler;
5766 if (err && exception_type != EXERROR)
5767 longjmp(exception_handler->loc, 1);
5768 RESTORE_INT(saveint);
5769 return err;
5770}
5771
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005772static struct redirtab*
5773pushredir(union node *redir)
5774{
5775 struct redirtab *sv;
5776 int i;
5777
5778 if (!redir)
5779 return redirlist;
5780
5781 i = 0;
5782 do {
5783 i++;
5784#if BASH_REDIR_OUTPUT
5785 if (redir->nfile.type == NTO2)
5786 i++;
5787#endif
5788 redir = redir->nfile.next;
5789 } while (redir);
5790
5791 sv = ckzalloc(sizeof(*sv) + i * sizeof(sv->two_fd[0]));
5792 sv->pair_count = i;
5793 while (--i >= 0)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005794 sv->two_fd[i].orig_fd = sv->two_fd[i].moved_to = EMPTY;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005795 sv->next = redirlist;
5796 redirlist = sv;
5797 return sv->next;
5798}
5799
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005800/*
5801 * Undo the effects of the last redirection.
5802 */
5803static void
Denys Vlasenko035486c2017-07-31 04:09:19 +02005804popredir(int drop)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005805{
5806 struct redirtab *rp;
5807 int i;
5808
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005809 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005810 return;
5811 INT_OFF;
5812 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005813 for (i = 0; i < rp->pair_count; i++) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005814 int fd = rp->two_fd[i].orig_fd;
5815 int copy = rp->two_fd[i].moved_to;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005816 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005817 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005818 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005819 continue;
5820 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005821 if (copy != EMPTY) {
Denys Vlasenko035486c2017-07-31 04:09:19 +02005822 if (!drop) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005823 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005824 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005825 }
Denys Vlasenko035486c2017-07-31 04:09:19 +02005826 close(copy);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005827 }
5828 }
5829 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005830 free(rp);
5831 INT_ON;
5832}
5833
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005834static void
5835unwindredir(struct redirtab *stop)
5836{
5837 while (redirlist != stop)
Denys Vlasenko035486c2017-07-31 04:09:19 +02005838 popredir(/*drop:*/ 0);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02005839}
5840
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005841
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005842/* ============ Routines to expand arguments to commands
5843 *
5844 * We have to deal with backquotes, shell variables, and file metacharacters.
5845 */
5846
Denys Vlasenko0b883582016-12-23 16:49:07 +01005847#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005848static arith_t
5849ash_arith(const char *s)
5850{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005851 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005852 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005853
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005854 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005855 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005856 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005857
5858 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005859 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005860 if (math_state.errmsg)
5861 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005862 INT_ON;
5863
5864 return result;
5865}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005866#endif
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01005867#if BASH_SUBSTR
5868# if ENABLE_FEATURE_SH_MATH
5869static int substr_atoi(const char *s)
5870{
5871 arith_t t = ash_arith(s);
5872 if (sizeof(t) > sizeof(int)) {
5873 /* clamp very large or very large negative nums for ${v:N:M}:
5874 * else "${v:0:0x100000001}" would work as "${v:0:1}"
5875 */
5876 if (t > INT_MAX)
5877 t = INT_MAX;
5878 if (t < INT_MIN)
5879 t = INT_MIN;
5880 }
5881 return t;
5882}
5883# else
5884# define substr_atoi(s) number(s)
5885# endif
5886#endif
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005887
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005888/*
5889 * expandarg flags
5890 */
5891#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5892#define EXP_TILDE 0x2 /* do normal tilde expansion */
5893#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5894#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005895/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5896 * POSIX says for this case:
5897 * Pathname expansion shall not be performed on the word by a
5898 * non-interactive shell; an interactive shell may perform it, but shall
5899 * do so only when the expansion would result in one word.
5900 * Currently, our code complies to the above rule by never globbing
5901 * redirection filenames.
5902 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5903 * (this means that on a typical Linux distro, bash almost always
5904 * performs globbing, and thus diverges from what we do).
5905 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005906#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Denys Vlasenko216913c2018-04-02 12:35:04 +02005907#define EXP_VARTILDE2 0x20 /* expand tildes after colons only */
5908#define EXP_WORD 0x40 /* expand word in parameter expansion */
Denys Vlasenko440da972018-08-05 14:29:58 +02005909#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005910/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005911 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005912 */
5913#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5914#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005915#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5916#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5917
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005918/* Add CTLESC when necessary. */
Denys Vlasenko216913c2018-04-02 12:35:04 +02005919#define QUOTES_ESC (EXP_FULL | EXP_CASE)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005920/* Do not skip NUL characters. */
5921#define QUOTES_KEEPNUL EXP_TILDE
5922
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005923/*
5924 * Structure specifying which parts of the string should be searched
5925 * for IFS characters.
5926 */
5927struct ifsregion {
5928 struct ifsregion *next; /* next region in list */
5929 int begoff; /* offset of start of region */
5930 int endoff; /* offset of end of region */
5931 int nulonly; /* search for nul bytes only */
5932};
5933
5934struct arglist {
5935 struct strlist *list;
5936 struct strlist **lastp;
5937};
5938
5939/* output of current string */
5940static char *expdest;
5941/* list of back quote expressions */
5942static struct nodelist *argbackq;
5943/* first struct in list of ifs regions */
5944static struct ifsregion ifsfirst;
5945/* last struct in list */
5946static struct ifsregion *ifslastp;
5947/* holds expanded arg list */
5948static struct arglist exparg;
5949
5950/*
5951 * Our own itoa().
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005952 * cvtnum() is used even if math support is off (to prepare $? values and such).
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005953 */
5954static int
5955cvtnum(arith_t num)
5956{
5957 int len;
5958
Denys Vlasenkocf3a7962017-07-26 14:38:19 +02005959 /* 32-bit and wider ints require buffer size of bytes*3 (or less) */
5960 len = sizeof(arith_t) * 3;
5961 /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127<NUL>" */
5962 if (sizeof(arith_t) < 4) len += 2;
5963
5964 expdest = makestrspace(len, expdest);
5965 len = fmtstr(expdest, len, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005966 STADJUST(len, expdest);
5967 return len;
5968}
5969
Denys Vlasenko455e4222016-10-27 14:45:13 +02005970/*
5971 * Break the argument string into pieces based upon IFS and add the
5972 * strings to the argument list. The regions of the string to be
5973 * searched for IFS characters have been stored by recordregion.
5974 */
5975static void
5976ifsbreakup(char *string, struct arglist *arglist)
5977{
5978 struct ifsregion *ifsp;
5979 struct strlist *sp;
5980 char *start;
5981 char *p;
5982 char *q;
5983 const char *ifs, *realifs;
5984 int ifsspc;
5985 int nulonly;
5986
5987 start = string;
5988 if (ifslastp != NULL) {
5989 ifsspc = 0;
5990 nulonly = 0;
5991 realifs = ifsset() ? ifsval() : defifs;
5992 ifsp = &ifsfirst;
5993 do {
Denys Vlasenko9a95df92018-04-02 14:27:50 +02005994 int afternul;
5995
Denys Vlasenko455e4222016-10-27 14:45:13 +02005996 p = string + ifsp->begoff;
Denys Vlasenko9a95df92018-04-02 14:27:50 +02005997 afternul = nulonly;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005998 nulonly = ifsp->nulonly;
5999 ifs = nulonly ? nullstr : realifs;
6000 ifsspc = 0;
6001 while (p < string + ifsp->endoff) {
6002 q = p;
6003 if ((unsigned char)*p == CTLESC)
6004 p++;
6005 if (!strchr(ifs, *p)) {
6006 p++;
6007 continue;
6008 }
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006009 if (!(afternul || nulonly))
Denys Vlasenko455e4222016-10-27 14:45:13 +02006010 ifsspc = (strchr(defifs, *p) != NULL);
6011 /* Ignore IFS whitespace at start */
6012 if (q == start && ifsspc) {
6013 p++;
6014 start = p;
6015 continue;
6016 }
6017 *q = '\0';
6018 sp = stzalloc(sizeof(*sp));
6019 sp->text = start;
6020 *arglist->lastp = sp;
6021 arglist->lastp = &sp->next;
6022 p++;
6023 if (!nulonly) {
6024 for (;;) {
6025 if (p >= string + ifsp->endoff) {
6026 break;
6027 }
6028 q = p;
6029 if ((unsigned char)*p == CTLESC)
6030 p++;
6031 if (strchr(ifs, *p) == NULL) {
6032 p = q;
6033 break;
6034 }
6035 if (strchr(defifs, *p) == NULL) {
6036 if (ifsspc) {
6037 p++;
6038 ifsspc = 0;
6039 } else {
6040 p = q;
6041 break;
6042 }
6043 } else
6044 p++;
6045 }
6046 }
6047 start = p;
6048 } /* while */
6049 ifsp = ifsp->next;
6050 } while (ifsp != NULL);
6051 if (nulonly)
6052 goto add;
6053 }
6054
6055 if (!*start)
6056 return;
6057
6058 add:
6059 sp = stzalloc(sizeof(*sp));
6060 sp->text = start;
6061 *arglist->lastp = sp;
6062 arglist->lastp = &sp->next;
6063}
6064
6065static void
6066ifsfree(void)
6067{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006068 struct ifsregion *p = ifsfirst.next;
6069
6070 if (!p)
6071 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006072
6073 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006074 do {
6075 struct ifsregion *ifsp;
6076 ifsp = p->next;
6077 free(p);
6078 p = ifsp;
6079 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02006080 ifsfirst.next = NULL;
6081 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006082 out:
6083 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02006084}
6085
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006086static size_t
6087esclen(const char *start, const char *p)
6088{
6089 size_t esc = 0;
6090
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006091 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006092 esc++;
6093 }
6094 return esc;
6095}
6096
6097/*
6098 * Remove any CTLESC characters from a string.
6099 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006100#if !BASH_PATTERN_SUBST
6101#define rmescapes(str, flag, slash_position) \
6102 rmescapes(str, flag)
6103#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006104static char *
Denys Vlasenko740058b2018-01-09 17:01:00 +01006105rmescapes(char *str, int flag, int *slash_position)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006106{
Ron Yorston417622c2015-05-18 09:59:14 +02006107 static const char qchars[] ALIGN1 = {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006108 IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00006109
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006110 char *p, *q, *r;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006111 unsigned protect_against_glob;
6112 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006113
Denys Vlasenko740058b2018-01-09 17:01:00 +01006114 p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006115 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006116 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006117
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006118 q = p;
6119 r = str;
6120 if (flag & RMESCAPE_ALLOC) {
6121 size_t len = p - str;
6122 size_t fulllen = len + strlen(p) + 1;
6123
6124 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02006125 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006126 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02006127 /* p and str may be invalidated by makestrspace */
6128 str = (char *)stackblock() + strloc;
6129 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006130 } else if (flag & RMESCAPE_HEAP) {
6131 r = ckmalloc(fulllen);
6132 } else {
6133 r = stalloc(fulllen);
6134 }
6135 q = r;
6136 if (len > 0) {
Denys Vlasenko5ace96a2017-07-23 21:46:02 +02006137 q = (char *)mempcpy(q, str, len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006138 }
6139 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006140
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006141 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006142 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006143 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006144 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenko216913c2018-04-02 12:35:04 +02006145// Note: protect_against_glob only affect whether
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006146// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006147 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006148 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006149 continue;
6150 }
Denys Vlasenko216913c2018-04-02 12:35:04 +02006151 if (*p == '\\') {
6152 /* naked back slash */
6153 protect_against_glob = 0;
6154 goto copy;
6155 }
Ron Yorston549deab2015-05-18 09:57:51 +02006156 if ((unsigned char)*p == CTLESC) {
6157 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02006158#if DEBUG
6159 if (*p == '\0')
6160 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
6161#endif
Ron Yorston549deab2015-05-18 09:57:51 +02006162 if (protect_against_glob) {
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006163 /*
6164 * We used to trust glob() and fnmatch() to eat
6165 * superfluous escapes (\z where z has no
6166 * special meaning anyway). But this causes
6167 * bugs such as string of one greek letter rho
Denys Vlasenkoed79a632017-07-05 19:20:43 +02006168 * (unicode-encoded as two bytes "cf,81")
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006169 * getting encoded as "cf,CTLESC,81"
6170 * and here, converted to "cf,\,81" -
6171 * which does not go well with some flavors
Denys Vlasenko92b8d9c2017-07-05 19:13:44 +02006172 * of fnmatch() in unicode locales
6173 * (for example, glibc <= 2.22).
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006174 *
6175 * Lets add "\" only on the chars which need it.
Denys Vlasenko4142f012017-07-05 22:19:28 +02006176 * Testcases for less obvious chars are shown.
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006177 */
6178 if (*p == '*'
6179 || *p == '?'
6180 || *p == '['
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006181 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6182 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6183 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6184 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenko4142f012017-07-05 22:19:28 +02006185 /* Some libc support [^negate], that's why "^" also needs love */
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +01006186 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
Denys Vlasenkofda9faf2017-07-05 19:10:21 +02006187 ) {
6188 *q++ = '\\';
6189 }
Ron Yorston549deab2015-05-18 09:57:51 +02006190 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006191 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006192#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006193 else if (slash_position && p == str + *slash_position) {
6194 /* stop handling globbing */
6195 globbing = 0;
6196 *slash_position = q - r;
6197 slash_position = NULL;
Ron Yorston417622c2015-05-18 09:59:14 +02006198 }
6199#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006200 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006201 copy:
6202 *q++ = *p++;
6203 }
6204 *q = '\0';
6205 if (flag & RMESCAPE_GROW) {
6206 expdest = r;
6207 STADJUST(q - r + 1, expdest);
6208 }
6209 return r;
6210}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006211#define pmatch(a, b) !fnmatch((a), (b), 0)
6212
6213/*
6214 * Prepare a pattern for a expmeta (internal glob(3)) call.
6215 *
6216 * Returns an stalloced string.
6217 */
6218static char *
Ron Yorston549deab2015-05-18 09:57:51 +02006219preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006220{
Denys Vlasenko740058b2018-01-09 17:01:00 +01006221 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006222}
6223
6224/*
6225 * Put a string on the stack.
6226 */
6227static void
6228memtodest(const char *p, size_t len, int syntax, int quotes)
6229{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006230 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006231
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006232 if (!len)
6233 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006234
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006235 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
6236
6237 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006238 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006239 if (c) {
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006240 if (quotes & QUOTES_ESC) {
6241 int n = SIT(c, syntax);
6242 if (n == CCTL
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02006243 || (syntax != BASESYNTAX && n == CBACK)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +01006244 ) {
6245 USTPUTC(CTLESC, q);
6246 }
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006247 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006248 } else if (!(quotes & QUOTES_KEEPNUL))
6249 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006250 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006251 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006252
6253 expdest = q;
6254}
6255
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006256static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006257strtodest(const char *p, int syntax, int quotes)
6258{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006259 size_t len = strlen(p);
6260 memtodest(p, len, syntax, quotes);
6261 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006262}
6263
6264/*
6265 * Record the fact that we have to scan this region of the
6266 * string for IFS characters.
6267 */
6268static void
6269recordregion(int start, int end, int nulonly)
6270{
6271 struct ifsregion *ifsp;
6272
6273 if (ifslastp == NULL) {
6274 ifsp = &ifsfirst;
6275 } else {
6276 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006277 ifsp = ckzalloc(sizeof(*ifsp));
6278 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006279 ifslastp->next = ifsp;
6280 INT_ON;
6281 }
6282 ifslastp = ifsp;
6283 ifslastp->begoff = start;
6284 ifslastp->endoff = end;
6285 ifslastp->nulonly = nulonly;
6286}
6287
6288static void
6289removerecordregions(int endoff)
6290{
6291 if (ifslastp == NULL)
6292 return;
6293
6294 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006295 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006296 struct ifsregion *ifsp;
6297 INT_OFF;
6298 ifsp = ifsfirst.next->next;
6299 free(ifsfirst.next);
6300 ifsfirst.next = ifsp;
6301 INT_ON;
6302 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006303 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006304 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006305 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006306 ifslastp = &ifsfirst;
6307 ifsfirst.endoff = endoff;
6308 }
6309 return;
6310 }
6311
6312 ifslastp = &ifsfirst;
6313 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006314 ifslastp = ifslastp->next;
6315 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006316 struct ifsregion *ifsp;
6317 INT_OFF;
6318 ifsp = ifslastp->next->next;
6319 free(ifslastp->next);
6320 ifslastp->next = ifsp;
6321 INT_ON;
6322 }
6323 if (ifslastp->endoff > endoff)
6324 ifslastp->endoff = endoff;
6325}
6326
6327static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006328exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006329{
Denys Vlasenkocd716832009-11-28 22:14:02 +01006330 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006331 char *name;
6332 struct passwd *pw;
6333 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006334 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006335
6336 name = p + 1;
6337
6338 while ((c = *++p) != '\0') {
6339 switch (c) {
6340 case CTLESC:
6341 return startp;
6342 case CTLQUOTEMARK:
6343 return startp;
6344 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006345 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006346 goto done;
6347 break;
6348 case '/':
6349 case CTLENDVAR:
6350 goto done;
6351 }
6352 }
6353 done:
6354 *p = '\0';
6355 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02006356 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006357 } else {
6358 pw = getpwnam(name);
6359 if (pw == NULL)
6360 goto lose;
6361 home = pw->pw_dir;
6362 }
6363 if (!home || !*home)
6364 goto lose;
6365 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006366 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006367 return p;
6368 lose:
6369 *p = c;
6370 return startp;
6371}
6372
6373/*
6374 * Execute a command inside back quotes. If it's a builtin command, we
6375 * want to save its output in a block obtained from malloc. Otherwise
6376 * we fork off a subprocess and get the output of the command via a pipe.
6377 * Should be called with interrupts off.
6378 */
6379struct backcmd { /* result of evalbackcmd */
6380 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006381 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00006382 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006383 struct job *jp; /* job structure for command */
6384};
6385
6386/* These forward decls are needed to use "eval" code for backticks handling: */
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +02006387/* flags in argument to evaltree */
6388#define EV_EXIT 01 /* exit after evaluating tree */
6389#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02006390static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006391
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006392/* An evaltree() which is known to never return.
6393 * Used to use an alias:
6394 * static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
6395 * but clang was reported to "transfer" noreturn-ness to evaltree() as well.
6396 */
6397static ALWAYS_INLINE NORETURN void
6398evaltreenr(union node *n, int flags)
6399{
6400 evaltree(n, flags);
6401 bb_unreachable(abort());
6402 /* NOTREACHED */
6403}
6404
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02006405static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006406evalbackcmd(union node *n, struct backcmd *result)
6407{
Denys Vlasenko579ad102016-10-25 21:10:20 +02006408 int pip[2];
6409 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006410
6411 result->fd = -1;
6412 result->buf = NULL;
6413 result->nleft = 0;
6414 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006415 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006416 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02006417 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006418
Denys Vlasenko579ad102016-10-25 21:10:20 +02006419 if (pipe(pip) < 0)
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02006420 ash_msg_and_raise_perror("can't create pipe");
Denys Vlasenko579ad102016-10-25 21:10:20 +02006421 jp = makejob(/*n,*/ 1);
6422 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02006423 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006424 FORCE_INT_ON;
6425 close(pip[0]);
6426 if (pip[1] != 1) {
6427 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02006428 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006429 close(pip[1]);
6430 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02006431/* TODO: eflag clearing makes the following not abort:
6432 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6433 * which is what bash does (unless it is in POSIX mode).
6434 * dash deleted "eflag = 0" line in the commit
6435 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6436 * [EVAL] Don't clear eflag in evalbackcmd
6437 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6438 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006439 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006440 ifsfree();
Denys Vlasenko619d9b52017-07-28 15:28:33 +02006441 evaltreenr(n, EV_EXIT);
Denys Vlasenko579ad102016-10-25 21:10:20 +02006442 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006443 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006444 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006445 close(pip[1]);
6446 result->fd = pip[0];
6447 result->jp = jp;
6448
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006449 out:
6450 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6451 result->fd, result->buf, result->nleft, result->jp));
6452}
6453
6454/*
6455 * Expand stuff in backwards quotes.
6456 */
6457static void
Ron Yorston549deab2015-05-18 09:57:51 +02006458expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006459{
6460 struct backcmd in;
6461 int i;
6462 char buf[128];
6463 char *p;
6464 char *dest;
6465 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006466 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006467 struct stackmark smark;
6468
6469 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006470 startloc = expdest - (char *)stackblock();
6471 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006472 evalbackcmd(cmd, &in);
6473 popstackmark(&smark);
6474
6475 p = in.buf;
6476 i = in.nleft;
6477 if (i == 0)
6478 goto read;
6479 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006480 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006481 read:
6482 if (in.fd < 0)
6483 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006484 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006485 TRACE(("expbackq: read returns %d\n", i));
6486 if (i <= 0)
6487 break;
6488 p = buf;
6489 }
6490
Denis Vlasenko60818682007-09-28 22:07:23 +00006491 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006492 if (in.fd >= 0) {
6493 close(in.fd);
6494 back_exitstatus = waitforjob(in.jp);
6495 }
6496 INT_ON;
6497
6498 /* Eat all trailing newlines */
6499 dest = expdest;
6500 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6501 STUNPUTC(dest);
6502 expdest = dest;
6503
Ron Yorston549deab2015-05-18 09:57:51 +02006504 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006505 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006506 TRACE(("evalbackq: size:%d:'%.*s'\n",
6507 (int)((dest - (char *)stackblock()) - startloc),
6508 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006509 stackblock() + startloc));
6510}
6511
Denys Vlasenko0b883582016-12-23 16:49:07 +01006512#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006513/*
6514 * Expand arithmetic expression. Backup to start of expression,
6515 * evaluate, place result in (backed up) result, adjust string position.
6516 */
6517static void
Ron Yorston549deab2015-05-18 09:57:51 +02006518expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006519{
6520 char *p, *start;
6521 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006522 int len;
6523
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006524 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006525
6526 /*
6527 * This routine is slightly over-complicated for
6528 * efficiency. Next we scan backwards looking for the
6529 * start of arithmetic.
6530 */
6531 start = stackblock();
6532 p = expdest - 1;
6533 *p = '\0';
6534 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006535 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006536 int esc;
6537
Denys Vlasenkocd716832009-11-28 22:14:02 +01006538 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006539 p--;
6540#if DEBUG
6541 if (p < start) {
6542 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6543 }
6544#endif
6545 }
6546
6547 esc = esclen(start, p);
6548 if (!(esc % 2)) {
6549 break;
6550 }
6551
6552 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006553 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006554
6555 begoff = p - start;
6556
6557 removerecordregions(begoff);
6558
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006559 expdest = p;
6560
Ron Yorston549deab2015-05-18 09:57:51 +02006561 if (flag & QUOTES_ESC)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006562 rmescapes(p + 1, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006563
Ron Yorston549deab2015-05-18 09:57:51 +02006564 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006565
Ron Yorston549deab2015-05-18 09:57:51 +02006566 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006567 recordregion(begoff, begoff + len, 0);
6568}
6569#endif
6570
6571/* argstr needs it */
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006572static char *evalvar(char *p, int flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006573
6574/*
6575 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6576 * characters to allow for further processing. Otherwise treat
6577 * $@ like $* since no splitting will be performed.
6578 */
6579static void
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006580argstr(char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006581{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006582 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006583 '=',
6584 ':',
6585 CTLQUOTEMARK,
6586 CTLENDVAR,
6587 CTLESC,
6588 CTLVAR,
6589 CTLBACKQ,
Denys Vlasenko0b883582016-12-23 16:49:07 +01006590#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006591 CTLENDARI,
6592#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006593 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006594 };
6595 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006596 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006597 int inquotes;
6598 size_t length;
6599 int startloc;
6600
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006601 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006602 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006603 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006604 reject++;
6605 }
6606 inquotes = 0;
6607 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006608 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006609 char *q;
6610
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006611 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006612 tilde:
6613 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006614 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006615 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006616 }
6617 start:
6618 startloc = expdest - (char *)stackblock();
6619 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006620 unsigned char c;
6621
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006622 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006623 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006624 if (c) {
6625 if (!(c & 0x80)
Denys Vlasenko0b883582016-12-23 16:49:07 +01006626 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006627 ) {
6628 /* c == '=' || c == ':' || c == CTLENDARI */
6629 length++;
6630 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006631 }
6632 if (length > 0) {
6633 int newloc;
6634 expdest = stack_nputstr(p, length, expdest);
6635 newloc = expdest - (char *)stackblock();
6636 if (breakall && !inquotes && newloc > startloc) {
6637 recordregion(startloc, newloc, 0);
6638 }
6639 startloc = newloc;
6640 }
6641 p += length + 1;
6642 length = 0;
6643
6644 switch (c) {
6645 case '\0':
6646 goto breakloop;
6647 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006648 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006649 p--;
6650 continue;
6651 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006652 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006653 reject++;
6654 /* fall through */
6655 case ':':
6656 /*
6657 * sort of a hack - expand tildes in variable
6658 * assignments (after the first '=' and after ':'s).
6659 */
6660 if (*--p == '~') {
6661 goto tilde;
6662 }
6663 continue;
6664 }
6665
6666 switch (c) {
6667 case CTLENDVAR: /* ??? */
6668 goto breakloop;
6669 case CTLQUOTEMARK:
6670 /* "$@" syntax adherence hack */
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006671 if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6672 p = evalvar(p + 1, flags | EXP_QUOTED) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006673 goto start;
6674 }
Denys Vlasenko9a95df92018-04-02 14:27:50 +02006675 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006676 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006677 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006678 p--;
6679 length++;
6680 startloc++;
6681 }
6682 break;
6683 case CTLESC:
6684 startloc++;
6685 length++;
6686 goto addquote;
6687 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006688 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006689 p = evalvar(p, flags | inquotes);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006690 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006691 goto start;
6692 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006693 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006694 argbackq = argbackq->next;
6695 goto start;
Denys Vlasenko0b883582016-12-23 16:49:07 +01006696#if ENABLE_FEATURE_SH_MATH
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006697 case CTLENDARI:
6698 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006699 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006700 goto start;
6701#endif
6702 }
6703 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006704 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006705}
6706
6707static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006708scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6709 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006710{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006711 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006712 char c;
6713
6714 loc = startp;
6715 loc2 = rmesc;
6716 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006717 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006718 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006719
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006720 c = *loc2;
6721 if (zero) {
6722 *loc2 = '\0';
6723 s = rmesc;
6724 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006725 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006726
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006727 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006728 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006729 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006730 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006731 loc++;
6732 loc++;
6733 loc2++;
6734 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006735 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006736}
6737
6738static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006739scanright(char *startp, char *rmesc, char *rmescend,
6740 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006741{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006742#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6743 int try2optimize = match_at_start;
6744#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006745 int esc = 0;
6746 char *loc;
6747 char *loc2;
6748
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006749 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6750 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6751 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6752 * Logic:
6753 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6754 * and on each iteration they go back two/one char until they reach the beginning.
6755 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6756 */
6757 /* TODO: document in what other circumstances we are called. */
6758
6759 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006760 int match;
6761 char c = *loc2;
6762 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006763 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006764 *loc2 = '\0';
6765 s = rmesc;
6766 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006767 match = pmatch(pattern, s);
6768 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006769 *loc2 = c;
6770 if (match)
6771 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006772#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6773 if (try2optimize) {
6774 /* Maybe we can optimize this:
6775 * if pattern ends with unescaped *, we can avoid checking
Denys Vlasenko10ad6222017-04-17 16:13:32 +02006776 * shorter strings: if "foo*" doesn't match "raw_value_of_v",
6777 * it won't match truncated "raw_value_of_" strings too.
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006778 */
6779 unsigned plen = strlen(pattern);
6780 /* Does it end with "*"? */
6781 if (plen != 0 && pattern[--plen] == '*') {
6782 /* "xxxx*" is not escaped */
6783 /* "xxx\*" is escaped */
6784 /* "xx\\*" is not escaped */
6785 /* "x\\\*" is escaped */
6786 int slashes = 0;
6787 while (plen != 0 && pattern[--plen] == '\\')
6788 slashes++;
6789 if (!(slashes & 1))
6790 break; /* ends with unescaped "*" */
6791 }
6792 try2optimize = 0;
6793 }
6794#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006795 loc--;
6796 if (quotes) {
6797 if (--esc < 0) {
6798 esc = esclen(startp, loc);
6799 }
6800 if (esc % 2) {
6801 esc--;
6802 loc--;
6803 }
6804 }
6805 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006806 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006807}
6808
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006809static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006810static void
6811varunset(const char *end, const char *var, const char *umsg, int varflags)
6812{
6813 const char *msg;
6814 const char *tail;
6815
6816 tail = nullstr;
6817 msg = "parameter not set";
6818 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006819 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006820 if (varflags & VSNUL)
6821 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006822 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006823 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006824 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006825 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006826 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006827}
6828
6829static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006830subevalvar(char *p, char *varname, int strloc, int subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02006831 int startloc, int varflags, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006832{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006833 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006834 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006835 char *startp;
6836 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006837 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006838 char *str;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006839 int amount, resetloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006840 int argstr_flags;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006841 IF_BASH_PATTERN_SUBST(int workloc;)
Denys Vlasenko740058b2018-01-09 17:01:00 +01006842 IF_BASH_PATTERN_SUBST(int slash_pos;)
6843 IF_BASH_PATTERN_SUBST(char *repl;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006844 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006845 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006846
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006847 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6848 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006849
Denys Vlasenko740058b2018-01-09 17:01:00 +01006850#if BASH_PATTERN_SUBST
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006851 /* For "${v/pattern/repl}", we must find the delimiter _before_
6852 * argstr() call expands possible variable references in pattern:
6853 * think about "v=a; a=a/; echo ${v/$a/r}" case.
6854 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006855 repl = NULL;
6856 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6857 /* Find '/' and replace with NUL */
6858 repl = p;
Denys Vlasenkoc2aa2182018-08-04 22:25:28 +02006859 /* The pattern can't be empty.
6860 * IOW: if the first char after "${v//" is a slash,
6861 * it does not terminate the pattern - it's the first char of the pattern:
6862 * v=/dev/ram; echo ${v////-} prints -dev-ram (pattern is "/")
6863 * v=/dev/ram; echo ${v///r/-} prints /dev-am (pattern is "/r")
6864 */
6865 if (*repl == '/')
6866 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006867 for (;;) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01006868 if (*repl == '\0') {
6869 repl = NULL;
6870 break;
6871 }
6872 if (*repl == '/') {
6873 *repl = '\0';
6874 break;
6875 }
Denys Vlasenkoc2aa2182018-08-04 22:25:28 +02006876 /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01006877 if ((unsigned char)*repl == CTLESC && repl[1])
Denys Vlasenko740058b2018-01-09 17:01:00 +01006878 repl++;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006879 repl++;
6880 }
6881 }
6882#endif
6883 argstr_flags = EXP_TILDE;
Denys Vlasenko216913c2018-04-02 12:35:04 +02006884 if (subtype != VSASSIGN
6885 && subtype != VSQUESTION
6886#if BASH_SUBSTR
6887 && subtype != VSSUBSTR
6888#endif
6889 ) {
6890 /* EXP_CASE keeps CTLESC's */
6891 argstr_flags = EXP_TILDE | EXP_CASE;
6892 }
Denys Vlasenko740058b2018-01-09 17:01:00 +01006893 argstr(p, argstr_flags);
Denys Vlasenko216913c2018-04-02 12:35:04 +02006894 //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc);
Denys Vlasenko740058b2018-01-09 17:01:00 +01006895#if BASH_PATTERN_SUBST
6896 slash_pos = -1;
6897 if (repl) {
6898 slash_pos = expdest - ((char *)stackblock() + strloc);
6899 STPUTC('/', expdest);
Denys Vlasenko216913c2018-04-02 12:35:04 +02006900 //bb_error_msg("repl+1:'%s'", repl + 1);
6901 argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
Denys Vlasenko740058b2018-01-09 17:01:00 +01006902 *repl = '/';
6903 }
6904#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006905 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006906 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006907 startp = (char *)stackblock() + startloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01006908 //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006909
6910 switch (subtype) {
6911 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006912 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006913 amount = startp - expdest;
6914 STADJUST(amount, expdest);
6915 return startp;
6916
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006917 case VSQUESTION:
6918 varunset(p, varname, startp, varflags);
6919 /* NOTREACHED */
6920
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006921#if BASH_SUBSTR
Denys Vlasenko826360f2017-07-17 17:49:11 +02006922 case VSSUBSTR: {
6923 int pos, len, orig_len;
6924 char *colon;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006925
Denys Vlasenko826360f2017-07-17 17:49:11 +02006926 loc = str = stackblock() + strloc;
6927
Denys Vlasenko826360f2017-07-17 17:49:11 +02006928 /* Read POS in ${var:POS:LEN} */
6929 colon = strchr(loc, ':');
6930 if (colon) *colon = '\0';
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006931 pos = substr_atoi(loc);
Denys Vlasenko826360f2017-07-17 17:49:11 +02006932 if (colon) *colon = ':';
6933
6934 /* Read LEN in ${var:POS:LEN} */
6935 len = str - startp - 1;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006936 /* *loc != '\0', guaranteed by parser */
6937 if (quotes) {
6938 char *ptr;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006939 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006940 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006941 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006942 len--;
6943 ptr++;
6944 }
6945 }
6946 }
6947 orig_len = len;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006948 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006949 /* ${var::LEN} */
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006950 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006951 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006952 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006953 len = orig_len;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006954 while (*loc && *loc != ':')
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006955 loc++;
Denys Vlasenkobaa41c72018-01-10 13:22:25 +01006956 if (*loc++ == ':')
6957 len = substr_atoi(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006958 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006959 if (pos < 0) {
6960 /* ${VAR:$((-n)):l} starts n chars from the end */
6961 pos = orig_len + pos;
6962 }
6963 if ((unsigned)pos >= orig_len) {
6964 /* apart from obvious ${VAR:999999:l},
6965 * covers ${VAR:$((-9999999)):l} - result is ""
Denys Vlasenko826360f2017-07-17 17:49:11 +02006966 * (bash compat)
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006967 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006968 pos = 0;
6969 len = 0;
6970 }
Denys Vlasenko826360f2017-07-17 17:49:11 +02006971 if (len < 0) {
6972 /* ${VAR:N:-M} sets LEN to strlen()-M */
6973 len = (orig_len - pos) + len;
6974 }
6975 if ((unsigned)len > (orig_len - pos))
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006976 len = orig_len - pos;
6977
6978 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006979 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006980 str++;
6981 }
6982 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006983 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006984 *loc++ = *str++;
6985 *loc++ = *str++;
6986 }
6987 *loc = '\0';
6988 amount = loc - expdest;
6989 STADJUST(amount, expdest);
6990 return loc;
Denys Vlasenko826360f2017-07-17 17:49:11 +02006991 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006992#endif /* BASH_SUBSTR */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006993 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006994
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006995 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006996
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01006997#if BASH_PATTERN_SUBST
Denys Vlasenko740058b2018-01-09 17:01:00 +01006998 repl = NULL;
6999
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007000 /* We'll comeback here if we grow the stack while handling
7001 * a VSREPLACE or VSREPLACEALL, since our pointers into the
7002 * stack will need rebasing, and we'll need to remove our work
7003 * areas each time
7004 */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007005 restart:
7006#endif
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007007
7008 amount = expdest - ((char *)stackblock() + resetloc);
7009 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007010 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007011
7012 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007013 rmescend = (char *)stackblock() + strloc;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007014 //bb_error_msg("str7:'%s'", rmescend);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007015 if (quotes) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007016//TODO: how to handle slash_pos here if string changes (shortens?)
7017 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007018 if (rmesc != startp) {
7019 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007020 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007021 }
7022 }
7023 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00007024 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02007025 /*
7026 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
7027 * The result is a_\_z_c (not a\_\_z_c)!
7028 *
7029 * The search pattern and replace string treat backslashes differently!
Denys Vlasenko740058b2018-01-09 17:01:00 +01007030 * "&slash_pos" causes rmescapes() to work differently on the pattern
Ron Yorston417622c2015-05-18 09:59:14 +02007031 * and string. It's only used on the first call.
7032 */
Denys Vlasenko740058b2018-01-09 17:01:00 +01007033 //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos);
7034 rmescapes(str, RMESCAPE_GLOB,
7035 repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
7036 );
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007037
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007038#if BASH_PATTERN_SUBST
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02007039 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007040 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenko826360f2017-07-17 17:49:11 +02007041 int len;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007042 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007043
Denis Vlasenkod6855d12008-09-27 14:03:25 +00007044 if (!repl) {
Denys Vlasenko740058b2018-01-09 17:01:00 +01007045 //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos);
Denys Vlasenkod1df1a72018-01-09 17:25:58 +01007046 repl = nullstr;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007047 if (slash_pos >= 0) {
7048 repl = str + slash_pos;
Ron Yorston417622c2015-05-18 09:59:14 +02007049 *repl++ = '\0';
Denys Vlasenko740058b2018-01-09 17:01:00 +01007050 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007051 }
Ron Yorston417622c2015-05-18 09:59:14 +02007052 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007053
7054 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007055 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007056 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007057
7058 len = 0;
7059 idx = startp;
7060 end = str - 1;
7061 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007062 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007063 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007064 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007065 if (!loc) {
7066 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007067 char *restart_detect = stackblock();
7068 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007069 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01007070 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007071 idx++;
7072 len++;
7073 STPUTC(*idx, expdest);
7074 }
7075 if (stackblock() != restart_detect)
7076 goto restart;
7077 idx++;
7078 len++;
7079 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007080 /* continue; - prone to quadratic behavior, smarter code: */
7081 if (idx >= end)
7082 break;
7083 if (str[0] == '*') {
7084 /* Pattern is "*foo". If "*foo" does not match "long_string",
7085 * it would never match "ong_string" etc, no point in trying.
7086 */
7087 goto skip_matching;
7088 }
7089 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007090 }
7091
7092 if (subtype == VSREPLACEALL) {
7093 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007094 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007095 idx++;
7096 idx++;
7097 rmesc++;
7098 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007099 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007100 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00007101 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007102
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007103 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007104 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007105 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007106 if (quotes && *loc == '\\') {
7107 STPUTC(CTLESC, expdest);
7108 len++;
7109 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007110 STPUTC(*loc, expdest);
7111 if (stackblock() != restart_detect)
7112 goto restart;
7113 len++;
7114 }
7115
7116 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02007117 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007118 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007119 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007120 STPUTC(*idx, expdest);
7121 if (stackblock() != restart_detect)
7122 goto restart;
7123 len++;
7124 idx++;
7125 }
7126 break;
7127 }
7128 }
7129
7130 /* We've put the replaced text into a buffer at workloc, now
7131 * move it to the right place and adjust the stack.
7132 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007133 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007134 startp = (char *)stackblock() + startloc;
7135 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007136 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007137 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007138 STADJUST(-amount, expdest);
7139 return startp;
7140 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007141#endif /* BASH_PATTERN_SUBST */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007142
7143 subtype -= VSTRIMRIGHT;
7144#if DEBUG
7145 if (subtype < 0 || subtype > 7)
7146 abort();
7147#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01007148 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007149 zero = subtype >> 1;
7150 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
7151 scan = (subtype & 1) ^ zero ? scanleft : scanright;
7152
7153 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
7154 if (loc) {
7155 if (zero) {
7156 memmove(startp, loc, str - loc);
7157 loc = startp + (str - loc) - 1;
7158 }
7159 *loc = '\0';
7160 amount = loc - expdest;
7161 STADJUST(amount, expdest);
7162 }
7163 return loc;
7164}
7165
7166/*
7167 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007168 * name parameter (examples):
7169 * ash -c 'echo $1' name:'1='
7170 * ash -c 'echo $qwe' name:'qwe='
7171 * ash -c 'echo $$' name:'$='
7172 * ash -c 'echo ${$}' name:'$='
7173 * ash -c 'echo ${$##q}' name:'$=q'
7174 * ash -c 'echo ${#$}' name:'$='
7175 * note: examples with bad shell syntax:
7176 * ash -c 'echo ${#$1}' name:'$=1'
7177 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007178 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02007179static NOINLINE ssize_t
Denys Vlasenko440da972018-08-05 14:29:58 +02007180varvalue(char *name, int varflags, int flags, int quoted)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007181{
Mike Frysinger98c52642009-04-02 10:02:37 +00007182 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007183 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007184 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007185 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007186 int sep;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007187 int subtype = varflags & VSTYPE;
7188 int discard = subtype == VSPLUS || subtype == VSLENGTH;
7189 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007190 int syntax;
7191
7192 sep = (flags & EXP_FULL) << CHAR_BIT;
7193 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007194
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007195 switch (*name) {
7196 case '$':
7197 num = rootpid;
7198 goto numvar;
7199 case '?':
7200 num = exitstatus;
7201 goto numvar;
7202 case '#':
7203 num = shellparam.nparam;
7204 goto numvar;
7205 case '!':
7206 num = backgndpid;
7207 if (num == 0)
7208 return -1;
7209 numvar:
7210 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007211 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007212 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00007213 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007214 for (i = NOPTS - 1; i >= 0; i--) {
Martijn Dekkerad4e9612018-03-31 18:15:59 +02007215 if (optlist[i] && optletters(i)) {
Mike Frysinger98c52642009-04-02 10:02:37 +00007216 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007217 len++;
7218 }
7219 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02007220 check_1char_name:
7221#if 0
7222 /* handles cases similar to ${#$1} */
7223 if (name[2] != '\0')
7224 raise_error_syntax("bad substitution");
7225#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007226 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007227 case '@':
7228 if (quoted && sep)
7229 goto param;
7230 /* fall through */
7231 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007232 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007233 char sepc;
Denys Vlasenko440da972018-08-05 14:29:58 +02007234 char c;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01007235
Denys Vlasenko440da972018-08-05 14:29:58 +02007236 /* We will set c to 0 or ~0 depending on whether
7237 * we're doing field splitting. We won't do field
7238 * splitting if either we're quoted or sep is zero.
7239 *
7240 * Instead of testing (quoted || !sep) the following
7241 * trick optimises away any branches by using the
7242 * fact that EXP_QUOTED (which is the only bit that
7243 * can be set in quoted) is the same as EXP_FULL <<
7244 * CHAR_BIT (which is the only bit that can be set
7245 * in sep).
7246 */
7247#if EXP_QUOTED >> CHAR_BIT != EXP_FULL
7248#error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT
7249#endif
7250 c = !((quoted | ~sep) & EXP_QUOTED) - 1;
7251 sep &= ~quoted;
7252 sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007253 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007254 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007255 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007256 if (!ap)
7257 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007258 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007259 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007260
7261 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007262 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007263 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007264 }
7265 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007266 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02007267 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007268 case '0':
7269 case '1':
7270 case '2':
7271 case '3':
7272 case '4':
7273 case '5':
7274 case '6':
7275 case '7':
7276 case '8':
7277 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02007278 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007279 if (num < 0 || num > shellparam.nparam)
7280 return -1;
7281 p = num ? shellparam.p[num - 1] : arg0;
7282 goto value;
7283 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007284 /* NB: name has form "VAR=..." */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007285 p = lookupvar(name);
7286 value:
7287 if (!p)
7288 return -1;
7289
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007290 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007291#if ENABLE_UNICODE_SUPPORT
7292 if (subtype == VSLENGTH && len > 0) {
7293 reinit_unicode_for_ash();
7294 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00007295 STADJUST(-len, expdest);
7296 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007297 len = unicode_strlen(p);
7298 }
7299 }
7300#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007301 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007302 }
7303
Ron Yorstond68d1fb2015-05-18 09:49:28 +02007304 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007305 STADJUST(-len, expdest);
7306 return len;
7307}
7308
7309/*
7310 * Expand a variable, and return a pointer to the next character in the
7311 * input string.
7312 */
7313static char *
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007314evalvar(char *p, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007315{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007316 char varflags;
7317 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02007318 int quoted;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007319 char *var;
7320 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007321 int startloc;
7322 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007323
Denys Vlasenkob0d63382009-09-16 16:18:32 +02007324 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007325 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02007326
7327 if (!subtype)
7328 raise_error_syntax("bad substitution");
7329
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007330 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007331 var = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007332 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02007333 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007334
7335 again:
Denys Vlasenko440da972018-08-05 14:29:58 +02007336 varlen = varvalue(var, varflags, flag, quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007337 if (varflags & VSNUL)
7338 varlen--;
7339
7340 if (subtype == VSPLUS) {
7341 varlen = -1 - varlen;
7342 goto vsplus;
7343 }
7344
7345 if (subtype == VSMINUS) {
7346 vsplus:
7347 if (varlen < 0) {
7348 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02007349 p,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007350 flag | EXP_TILDE | EXP_WORD
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007351 );
7352 goto end;
7353 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007354 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007355 }
7356
7357 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007358 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007359 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007360
7361 subevalvar(p, var, 0, subtype, startloc, varflags,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007362 flag & ~QUOTES_ESC);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007363 varflags &= ~VSNUL;
7364 /*
7365 * Remove any recorded regions beyond
7366 * start of variable
7367 */
7368 removerecordregions(startloc);
7369 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007370 }
7371
7372 if (varlen < 0 && uflag)
7373 varunset(p, var, 0, 0);
7374
7375 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01007376 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007377 goto record;
7378 }
7379
7380 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007381 record:
Denys Vlasenko440da972018-08-05 14:29:58 +02007382 if (quoted) {
7383 quoted = *var == '@' && shellparam.nparam;
7384 if (!quoted)
7385 goto end;
7386 }
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02007387 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007388 goto end;
7389 }
7390
7391#if DEBUG
7392 switch (subtype) {
7393 case VSTRIMLEFT:
7394 case VSTRIMLEFTMAX:
7395 case VSTRIMRIGHT:
7396 case VSTRIMRIGHTMAX:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007397#if BASH_SUBSTR
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007398 case VSSUBSTR:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01007399#endif
7400#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +00007401 case VSREPLACE:
7402 case VSREPLACEALL:
7403#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007404 break;
7405 default:
7406 abort();
7407 }
7408#endif
7409
7410 if (varlen >= 0) {
7411 /*
7412 * Terminate the string and start recording the pattern
7413 * right after it
7414 */
7415 STPUTC('\0', expdest);
7416 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02007417 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007418 startloc, varflags, flag)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007419 int amount = expdest - (
7420 (char *)stackblock() + patloc - 1
7421 );
7422 STADJUST(-amount, expdest);
7423 }
7424 /* Remove any recorded regions beyond start of variable */
7425 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02007426 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007427 }
7428
7429 end:
7430 if (subtype != VSNORMAL) { /* skip to end of alternative */
7431 int nesting = 1;
7432 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01007433 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007434 if (c == CTLESC)
7435 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02007436 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007437 if (varlen >= 0)
7438 argbackq = argbackq->next;
7439 } else if (c == CTLVAR) {
7440 if ((*p++ & VSTYPE) != VSNORMAL)
7441 nesting++;
7442 } else if (c == CTLENDVAR) {
7443 if (--nesting == 0)
7444 break;
7445 }
7446 }
7447 }
7448 return p;
7449}
7450
7451/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007452 * Add a file name to the list.
7453 */
7454static void
7455addfname(const char *name)
7456{
7457 struct strlist *sp;
7458
Denis Vlasenko597906c2008-02-20 16:38:54 +00007459 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007460 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007461 *exparg.lastp = sp;
7462 exparg.lastp = &sp->next;
7463}
7464
Felix Fietkaub5b21122017-01-31 21:58:55 +01007465/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7466static int
7467hasmeta(const char *p)
7468{
7469 static const char chars[] ALIGN1 = {
7470 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7471 };
7472
7473 for (;;) {
7474 p = strpbrk(p, chars);
7475 if (!p)
7476 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007477 switch ((unsigned char)*p) {
Felix Fietkaub5b21122017-01-31 21:58:55 +01007478 case CTLQUOTEMARK:
7479 for (;;) {
7480 p++;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007481 if ((unsigned char)*p == CTLQUOTEMARK)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007482 break;
Denys Vlasenkoac61f442018-03-30 23:03:29 +02007483 if ((unsigned char)*p == CTLESC)
Felix Fietkaub5b21122017-01-31 21:58:55 +01007484 p++;
7485 if (*p == '\0') /* huh? */
7486 return 0;
7487 }
7488 break;
7489 case '\\':
7490 case CTLESC:
7491 p++;
7492 if (*p == '\0')
7493 return 0;
7494 break;
7495 case '[':
7496 if (!strchr(p + 1, ']')) {
7497 /* It's not a properly closed [] pattern,
7498 * but other metas may follow. Continue checking.
7499 * my[file* _is_ globbed by bash
7500 * and matches filenames like "my[file1".
7501 */
7502 break;
7503 }
7504 /* fallthrough */
7505 default:
7506 /* case '*': */
7507 /* case '?': */
7508 return 1;
7509 }
7510 p++;
7511 }
7512
7513 return 0;
7514}
7515
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007516/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007517#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007518
7519/* Add the result of glob() to the list */
7520static void
7521addglob(const glob_t *pglob)
7522{
7523 char **p = pglob->gl_pathv;
7524
7525 do {
7526 addfname(*p);
7527 } while (*++p);
7528}
7529static void
7530expandmeta(struct strlist *str /*, int flag*/)
7531{
7532 /* TODO - EXP_REDIR */
7533
7534 while (str) {
7535 char *p;
7536 glob_t pglob;
7537 int i;
7538
7539 if (fflag)
7540 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007541
Felix Fietkaub5b21122017-01-31 21:58:55 +01007542 if (!hasmeta(str->text))
7543 goto nometa;
Denys Vlasenkod4f3db92016-10-30 18:41:01 +01007544
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007545 INT_OFF;
7546 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007547// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7548// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7549//
7550// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7551// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7552// Which means you need to unescape the string, right? Not so fast:
7553// if there _is_ a file named "file\?" (with backslash), it is returned
7554// as "file\?" too (whichever pattern you used to find it, say, "file*").
Denys Vlasenko10ad6222017-04-17 16:13:32 +02007555// You DON'T KNOW by looking at the result whether you need to unescape it.
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007556//
7557// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7558// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7559// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7560// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7561// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7562// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7563 i = glob(p, 0, NULL, &pglob);
7564 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007565 if (p != str->text)
7566 free(p);
7567 switch (i) {
7568 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007569#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007570 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7571 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7572 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007573#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007574 addglob(&pglob);
7575 globfree(&pglob);
7576 INT_ON;
7577 break;
7578 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007579 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007580 globfree(&pglob);
7581 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007582 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007583 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007584 rmescapes(str->text, 0, NULL);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007585 exparg.lastp = &str->next;
7586 break;
7587 default: /* GLOB_NOSPACE */
7588 globfree(&pglob);
7589 INT_ON;
7590 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7591 }
7592 str = str->next;
7593 }
7594}
7595
7596#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007597/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007598
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007599/*
7600 * Do metacharacter (i.e. *, ?, [...]) expansion.
7601 */
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007602typedef struct exp_t {
7603 char *dir;
7604 unsigned dir_max;
7605} exp_t;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007606static void
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007607expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007608{
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007609#define expdir exp->dir
7610#define expdir_max exp->dir_max
7611 char *enddir = expdir + expdir_len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007612 char *p;
7613 const char *cp;
7614 char *start;
7615 char *endname;
7616 int metaflag;
7617 struct stat statb;
7618 DIR *dirp;
7619 struct dirent *dp;
7620 int atend;
7621 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007622 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007623
7624 metaflag = 0;
7625 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007626 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007627 if (*p == '*' || *p == '?')
7628 metaflag = 1;
7629 else if (*p == '[') {
7630 char *q = p + 1;
7631 if (*q == '!')
7632 q++;
7633 for (;;) {
7634 if (*q == '\\')
7635 q++;
7636 if (*q == '/' || *q == '\0')
7637 break;
7638 if (*++q == ']') {
7639 metaflag = 1;
7640 break;
7641 }
7642 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007643 } else {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007644 if (*p == '\\' && p[1])
Ron Yorstonca25af92015-09-04 10:32:41 +01007645 esc++;
7646 if (p[esc] == '/') {
7647 if (metaflag)
7648 break;
7649 start = p + esc + 1;
7650 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007651 }
7652 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007653 if (metaflag == 0) { /* we've reached the end of the file name */
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007654 if (!expdir_len)
7655 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007656 p = name;
7657 do {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007658 if (*p == '\\' && p[1])
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007659 p++;
7660 *enddir++ = *p;
7661 } while (*p++);
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007662 if (lstat(expdir, &statb) == 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007663 addfname(expdir);
7664 return;
7665 }
7666 endname = p;
7667 if (name < start) {
7668 p = name;
7669 do {
Denys Vlasenkoeb54ca82018-08-07 18:54:52 +02007670 if (*p == '\\' && p[1])
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007671 p++;
7672 *enddir++ = *p++;
7673 } while (p < start);
7674 }
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007675 *enddir = '\0';
7676 cp = expdir;
7677 expdir_len = enddir - cp;
7678 if (!expdir_len)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007679 cp = ".";
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007680 dirp = opendir(cp);
7681 if (dirp == NULL)
7682 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007683 if (*endname == 0) {
7684 atend = 1;
7685 } else {
7686 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007687 *endname = '\0';
7688 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007689 }
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007690 name_len -= endname - name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007691 matchdot = 0;
7692 p = start;
7693 if (*p == '\\')
7694 p++;
7695 if (*p == '.')
7696 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007697 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007698 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007699 continue;
7700 if (pmatch(start, dp->d_name)) {
7701 if (atend) {
7702 strcpy(enddir, dp->d_name);
7703 addfname(expdir);
7704 } else {
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007705 unsigned offset;
7706 unsigned len;
7707
7708 p = stpcpy(enddir, dp->d_name);
7709 *p = '/';
7710
7711 offset = p - expdir + 1;
7712 len = offset + name_len + NAME_MAX;
7713 if (len > expdir_max) {
7714 len += PATH_MAX;
7715 expdir = ckrealloc(expdir, len);
7716 expdir_max = len;
7717 }
7718
7719 expmeta(exp, endname, name_len, offset);
7720 enddir = expdir + expdir_len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007721 }
7722 }
7723 }
7724 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007725 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007726 endname[-esc - 1] = esc ? '\\' : '/';
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007727#undef expdir
7728#undef expdir_max
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007729}
7730
7731static struct strlist *
7732msort(struct strlist *list, int len)
7733{
7734 struct strlist *p, *q = NULL;
7735 struct strlist **lpp;
7736 int half;
7737 int n;
7738
7739 if (len <= 1)
7740 return list;
7741 half = len >> 1;
7742 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007743 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007744 q = p;
7745 p = p->next;
7746 }
7747 q->next = NULL; /* terminate first half of list */
7748 q = msort(list, half); /* sort first half of list */
7749 p = msort(p, len - half); /* sort second half */
7750 lpp = &list;
7751 for (;;) {
7752#if ENABLE_LOCALE_SUPPORT
7753 if (strcoll(p->text, q->text) < 0)
7754#else
7755 if (strcmp(p->text, q->text) < 0)
7756#endif
7757 {
7758 *lpp = p;
7759 lpp = &p->next;
7760 p = *lpp;
7761 if (p == NULL) {
7762 *lpp = q;
7763 break;
7764 }
7765 } else {
7766 *lpp = q;
7767 lpp = &q->next;
7768 q = *lpp;
7769 if (q == NULL) {
7770 *lpp = p;
7771 break;
7772 }
7773 }
7774 }
7775 return list;
7776}
7777
7778/*
7779 * Sort the results of file name expansion. It calculates the number of
7780 * strings to sort and then calls msort (short for merge sort) to do the
7781 * work.
7782 */
7783static struct strlist *
7784expsort(struct strlist *str)
7785{
7786 int len;
7787 struct strlist *sp;
7788
7789 len = 0;
7790 for (sp = str; sp; sp = sp->next)
7791 len++;
7792 return msort(str, len);
7793}
7794
7795static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007796expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007797{
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007798 /* TODO - EXP_REDIR */
7799
7800 while (str) {
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007801 exp_t exp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007802 struct strlist **savelastp;
7803 struct strlist *sp;
7804 char *p;
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007805 unsigned len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007806
7807 if (fflag)
7808 goto nometa;
Felix Fietkaub5b21122017-01-31 21:58:55 +01007809 if (!hasmeta(str->text))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007810 goto nometa;
7811 savelastp = exparg.lastp;
7812
7813 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007814 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenkod5f50452018-04-14 14:50:47 +02007815 len = strlen(p);
7816 exp.dir_max = len + PATH_MAX;
7817 exp.dir = ckmalloc(exp.dir_max);
7818
7819 expmeta(&exp, p, len, 0);
7820 free(exp.dir);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007821 if (p != str->text)
7822 free(p);
7823 INT_ON;
7824 if (exparg.lastp == savelastp) {
7825 /*
7826 * no matches
7827 */
7828 nometa:
7829 *exparg.lastp = str;
Denys Vlasenko740058b2018-01-09 17:01:00 +01007830 rmescapes(str->text, 0, NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007831 exparg.lastp = &str->next;
7832 } else {
7833 *exparg.lastp = NULL;
7834 *savelastp = sp = expsort(*savelastp);
7835 while (sp->next != NULL)
7836 sp = sp->next;
7837 exparg.lastp = &sp->next;
7838 }
7839 str = str->next;
7840 }
7841}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007842#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007843
7844/*
7845 * Perform variable substitution and command substitution on an argument,
7846 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7847 * perform splitting and file name expansion. When arglist is NULL, perform
7848 * here document expansion.
7849 */
7850static void
7851expandarg(union node *arg, struct arglist *arglist, int flag)
7852{
7853 struct strlist *sp;
7854 char *p;
7855
7856 argbackq = arg->narg.backquote;
7857 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007858 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007859 argstr(arg->narg.text, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007860 p = _STPUTC('\0', expdest);
7861 expdest = p - 1;
7862 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007863 /* here document expanded */
7864 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007865 }
7866 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007867 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007868 exparg.lastp = &exparg.list;
7869 /*
7870 * TODO - EXP_REDIR
7871 */
7872 if (flag & EXP_FULL) {
7873 ifsbreakup(p, &exparg);
7874 *exparg.lastp = NULL;
7875 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007876 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007877 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +00007878 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007879 sp->text = p;
7880 *exparg.lastp = sp;
7881 exparg.lastp = &sp->next;
7882 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007883 *exparg.lastp = NULL;
7884 if (exparg.list) {
7885 *arglist->lastp = exparg.list;
7886 arglist->lastp = exparg.lastp;
7887 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007888
7889 out:
7890 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007891}
7892
7893/*
7894 * Expand shell variables and backquotes inside a here document.
7895 */
7896static void
7897expandhere(union node *arg, int fd)
7898{
Ron Yorston549deab2015-05-18 09:57:51 +02007899 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007900 full_write(fd, stackblock(), expdest - (char *)stackblock());
7901}
7902
7903/*
7904 * Returns true if the pattern matches the string.
7905 */
7906static int
7907patmatch(char *pattern, const char *string)
7908{
Denys Vlasenkobd43c672017-07-05 23:12:15 +02007909 char *p = preglob(pattern, 0);
Denys Vlasenko4476c702017-08-15 15:27:41 +02007910 int r = pmatch(p, string);
7911 //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r);
7912 return r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007913}
7914
7915/*
7916 * See if a pattern matches in a case statement.
7917 */
7918static int
7919casematch(union node *pattern, char *val)
7920{
7921 struct stackmark smark;
7922 int result;
7923
7924 setstackmark(&smark);
7925 argbackq = pattern->narg.backquote;
7926 STARTSTACKSTR(expdest);
Denys Vlasenkob8c0bc12017-07-26 23:03:21 +02007927 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007928 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007929 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007930 result = patmatch(stackblock(), val);
7931 popstackmark(&smark);
7932 return result;
7933}
7934
7935
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007936/* ============ find_command */
7937
7938struct builtincmd {
7939 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007940 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007941 /* unsigned flags; */
7942};
7943#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007944/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007945 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007946#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007947#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007948
7949struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007950 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007951 union param {
7952 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007953 /* index >= 0 for commands without path (slashes) */
7954 /* (TODO: what exactly does the value mean? PATH position?) */
7955 /* index == -1 for commands with slashes */
7956 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007957 const struct builtincmd *cmd;
7958 struct funcnode *func;
7959 } u;
7960};
7961/* values of cmdtype */
7962#define CMDUNKNOWN -1 /* no entry in table for command */
7963#define CMDNORMAL 0 /* command is an executable program */
7964#define CMDFUNCTION 1 /* command is a shell function */
7965#define CMDBUILTIN 2 /* command is a shell builtin */
7966
7967/* action to find_command() */
7968#define DO_ERR 0x01 /* prints errors */
7969#define DO_ABS 0x02 /* checks absolute paths */
7970#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7971#define DO_ALTPATH 0x08 /* using alternate path */
7972#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7973
7974static void find_command(char *, struct cmdentry *, int, const char *);
7975
7976
7977/* ============ Hashing commands */
7978
7979/*
7980 * When commands are first encountered, they are entered in a hash table.
7981 * This ensures that a full path search will not have to be done for them
7982 * on each invocation.
7983 *
7984 * We should investigate converting to a linear search, even though that
7985 * would make the command name "hash" a misnomer.
7986 */
7987
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007988struct tblentry {
7989 struct tblentry *next; /* next entry in hash chain */
7990 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007991 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007992 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007993 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007994};
7995
Denis Vlasenko01631112007-12-16 17:20:38 +00007996static struct tblentry **cmdtable;
7997#define INIT_G_cmdtable() do { \
7998 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7999} while (0)
8000
8001static int builtinloc = -1; /* index in path of %builtin, or -1 */
8002
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008003
8004static void
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008005tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008006{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008007#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00008008 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00008009 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02008010 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00008011 while (*envp)
8012 putenv(*envp++);
Denys Vlasenko035486c2017-07-31 04:09:19 +02008013 popredir(/*drop:*/ 1);
Denys Vlasenko80e8e3c2017-08-07 19:24:57 +02008014 run_noexec_applet_and_exit(applet_no, cmd, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00008015 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00008016 /* re-exec ourselves with the new arguments */
8017 execve(bb_busybox_exec_path, argv, envp);
8018 /* If they called chroot or otherwise made the binary no longer
8019 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008020 }
8021#endif
8022
8023 repeat:
8024#ifdef SYSV
8025 do {
8026 execve(cmd, argv, envp);
8027 } while (errno == EINTR);
8028#else
8029 execve(cmd, argv, envp);
8030#endif
Ron Yorstonca82b532018-11-01 11:45:03 +01008031
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008032 if (cmd != bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01008033 /* Run "cmd" as a shell script:
8034 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
8035 * "If the execve() function fails with ENOEXEC, the shell
8036 * shall execute a command equivalent to having a shell invoked
8037 * with the command name as its first operand,
8038 * with any remaining arguments passed to the new shell"
8039 *
8040 * That is, do not use $SHELL, user's shell, or /bin/sh;
8041 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01008042 *
8043 * Note that bash reads ~80 chars of the file, and if it sees
8044 * a zero byte before it sees newline, it doesn't try to
8045 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01008046 * message and exit code 126. For one, this prevents attempts
8047 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01008048 */
Denys Vlasenko00a1dbd2017-07-29 01:20:53 +02008049 argv[0] = (char*) cmd;
8050 cmd = bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008051 /* NB: this is only possible because all callers of shellexec()
8052 * ensure that the argv[-1] slot exists!
8053 */
8054 argv--;
8055 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008056 goto repeat;
8057 }
8058}
8059
8060/*
8061 * Exec a program. Never returns. If you change this routine, you may
8062 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02008063 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008064 */
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008065static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8066static void shellexec(char *prog, char **argv, const char *path, int idx)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008067{
8068 char *cmdname;
8069 int e;
8070 char **envp;
8071 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008072 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008073
Denys Vlasenkoa5060b82017-11-03 14:16:25 +01008074 envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008075 if (strchr(prog, '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00008076#if ENABLE_FEATURE_SH_STANDALONE
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008077 || (applet_no = find_applet_by_name(prog)) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008078#endif
8079 ) {
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008080 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008081 if (applet_no >= 0) {
8082 /* We tried execing ourself, but it didn't work.
8083 * Maybe /proc/self/exe doesn't exist?
8084 * Try $PATH search.
8085 */
8086 goto try_PATH;
8087 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008088 e = errno;
8089 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01008090 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008091 e = ENOENT;
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008092 while ((cmdname = path_advance(&path, prog)) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008093 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00008094 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008095 if (errno != ENOENT && errno != ENOTDIR)
8096 e = errno;
8097 }
8098 stunalloc(cmdname);
8099 }
8100 }
8101
8102 /* Map to POSIX errors */
8103 switch (e) {
Denys Vlasenko2596f412018-08-05 18:04:09 +02008104 default:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008105 exerrno = 126;
8106 break;
Denys Vlasenko2596f412018-08-05 18:04:09 +02008107 case ELOOP:
8108 case ENAMETOOLONG:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008109 case ENOENT:
Denys Vlasenko2596f412018-08-05 18:04:09 +02008110 case ENOTDIR:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008111 exerrno = 127;
8112 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008113 }
8114 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008115 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
Denys Vlasenkoe139ae32017-04-12 21:02:33 +02008116 prog, e, suppress_int));
8117 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008118 /* NOTREACHED */
8119}
8120
8121static void
8122printentry(struct tblentry *cmdp)
8123{
8124 int idx;
8125 const char *path;
8126 char *name;
8127
8128 idx = cmdp->param.index;
8129 path = pathval();
8130 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008131 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008132 stunalloc(name);
8133 } while (--idx >= 0);
8134 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
8135}
8136
8137/*
8138 * Clear out command entries. The argument specifies the first entry in
8139 * PATH which has changed.
8140 */
8141static void
8142clearcmdentry(int firstchange)
8143{
8144 struct tblentry **tblp;
8145 struct tblentry **pp;
8146 struct tblentry *cmdp;
8147
8148 INT_OFF;
8149 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8150 pp = tblp;
8151 while ((cmdp = *pp) != NULL) {
8152 if ((cmdp->cmdtype == CMDNORMAL &&
8153 cmdp->param.index >= firstchange)
8154 || (cmdp->cmdtype == CMDBUILTIN &&
8155 builtinloc >= firstchange)
8156 ) {
8157 *pp = cmdp->next;
8158 free(cmdp);
8159 } else {
8160 pp = &cmdp->next;
8161 }
8162 }
8163 }
8164 INT_ON;
8165}
8166
8167/*
8168 * Locate a command in the command hash table. If "add" is nonzero,
8169 * add the command to the table if it is not already present. The
8170 * variable "lastcmdentry" is set to point to the address of the link
8171 * pointing to the entry, so that delete_cmd_entry can delete the
8172 * entry.
8173 *
8174 * Interrupts must be off if called with add != 0.
8175 */
8176static struct tblentry **lastcmdentry;
8177
8178static struct tblentry *
8179cmdlookup(const char *name, int add)
8180{
8181 unsigned int hashval;
8182 const char *p;
8183 struct tblentry *cmdp;
8184 struct tblentry **pp;
8185
8186 p = name;
8187 hashval = (unsigned char)*p << 4;
8188 while (*p)
8189 hashval += (unsigned char)*p++;
8190 hashval &= 0x7FFF;
8191 pp = &cmdtable[hashval % CMDTABLESIZE];
8192 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8193 if (strcmp(cmdp->cmdname, name) == 0)
8194 break;
8195 pp = &cmdp->next;
8196 }
8197 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008198 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
8199 + strlen(name)
8200 /* + 1 - already done because
8201 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00008202 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008203 cmdp->cmdtype = CMDUNKNOWN;
8204 strcpy(cmdp->cmdname, name);
8205 }
8206 lastcmdentry = pp;
8207 return cmdp;
8208}
8209
8210/*
8211 * Delete the command entry returned on the last lookup.
8212 */
8213static void
8214delete_cmd_entry(void)
8215{
8216 struct tblentry *cmdp;
8217
8218 INT_OFF;
8219 cmdp = *lastcmdentry;
8220 *lastcmdentry = cmdp->next;
8221 if (cmdp->cmdtype == CMDFUNCTION)
8222 freefunc(cmdp->param.func);
8223 free(cmdp);
8224 INT_ON;
8225}
8226
8227/*
8228 * Add a new command entry, replacing any existing command entry for
8229 * the same name - except special builtins.
8230 */
8231static void
8232addcmdentry(char *name, struct cmdentry *entry)
8233{
8234 struct tblentry *cmdp;
8235
8236 cmdp = cmdlookup(name, 1);
8237 if (cmdp->cmdtype == CMDFUNCTION) {
8238 freefunc(cmdp->param.func);
8239 }
8240 cmdp->cmdtype = entry->cmdtype;
8241 cmdp->param = entry->u;
8242 cmdp->rehash = 0;
8243}
8244
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008245static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008246hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008247{
8248 struct tblentry **pp;
8249 struct tblentry *cmdp;
8250 int c;
8251 struct cmdentry entry;
8252 char *name;
8253
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008254 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008255 clearcmdentry(0);
8256 return 0;
8257 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008258
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008259 if (*argptr == NULL) {
8260 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8261 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
8262 if (cmdp->cmdtype == CMDNORMAL)
8263 printentry(cmdp);
8264 }
8265 }
8266 return 0;
8267 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008268
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008269 c = 0;
8270 while ((name = *argptr) != NULL) {
8271 cmdp = cmdlookup(name, 0);
8272 if (cmdp != NULL
8273 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008274 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
8275 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008276 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008277 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008278 find_command(name, &entry, DO_ERR, pathval());
8279 if (entry.cmdtype == CMDUNKNOWN)
8280 c = 1;
8281 argptr++;
8282 }
8283 return c;
8284}
8285
8286/*
8287 * Called when a cd is done. Marks all commands so the next time they
8288 * are executed they will be rehashed.
8289 */
8290static void
8291hashcd(void)
8292{
8293 struct tblentry **pp;
8294 struct tblentry *cmdp;
8295
8296 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
8297 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008298 if (cmdp->cmdtype == CMDNORMAL
8299 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02008300 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008301 && builtinloc > 0)
8302 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008303 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008304 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008305 }
8306 }
8307}
8308
8309/*
8310 * Fix command hash table when PATH changed.
8311 * Called before PATH is changed. The argument is the new value of PATH;
8312 * pathval() still returns the old value at this point.
8313 * Called with interrupts off.
8314 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008315static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008316changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008317{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008318 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008319 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008320 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008321 int idx_bltin;
8322
8323 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008324 firstchange = 9999; /* assume no change */
8325 idx = 0;
8326 idx_bltin = -1;
8327 for (;;) {
8328 if (*old != *new) {
8329 firstchange = idx;
8330 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008331 || (*old == ':' && *new == '\0')
8332 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008333 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008334 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008335 old = new; /* ignore subsequent differences */
8336 }
8337 if (*new == '\0')
8338 break;
8339 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
8340 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00008341 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008342 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02008343 new++;
8344 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008345 }
8346 if (builtinloc < 0 && idx_bltin >= 0)
8347 builtinloc = idx_bltin; /* zap builtins */
8348 if (builtinloc >= 0 && idx_bltin < 0)
8349 firstchange = 0;
8350 clearcmdentry(firstchange);
8351 builtinloc = idx_bltin;
8352}
Ron Yorston95ebcf72015-11-03 09:42:23 +00008353enum {
8354 TEOF,
8355 TNL,
8356 TREDIR,
8357 TWORD,
8358 TSEMI,
8359 TBACKGND,
8360 TAND,
8361 TOR,
8362 TPIPE,
8363 TLP,
8364 TRP,
8365 TENDCASE,
8366 TENDBQUOTE,
8367 TNOT,
8368 TCASE,
8369 TDO,
8370 TDONE,
8371 TELIF,
8372 TELSE,
8373 TESAC,
8374 TFI,
8375 TFOR,
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008376#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +00008377 TFUNCTION,
8378#endif
8379 TIF,
8380 TIN,
8381 TTHEN,
8382 TUNTIL,
8383 TWHILE,
8384 TBEGIN,
8385 TEND
8386};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008387typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008388
Denys Vlasenko888527c2016-10-02 16:54:17 +02008389/* Nth bit indicates if token marks the end of a list */
8390enum {
8391 tokendlist = 0
8392 /* 0 */ | (1u << TEOF)
8393 /* 1 */ | (0u << TNL)
8394 /* 2 */ | (0u << TREDIR)
8395 /* 3 */ | (0u << TWORD)
8396 /* 4 */ | (0u << TSEMI)
8397 /* 5 */ | (0u << TBACKGND)
8398 /* 6 */ | (0u << TAND)
8399 /* 7 */ | (0u << TOR)
8400 /* 8 */ | (0u << TPIPE)
8401 /* 9 */ | (0u << TLP)
8402 /* 10 */ | (1u << TRP)
8403 /* 11 */ | (1u << TENDCASE)
8404 /* 12 */ | (1u << TENDBQUOTE)
8405 /* 13 */ | (0u << TNOT)
8406 /* 14 */ | (0u << TCASE)
8407 /* 15 */ | (1u << TDO)
8408 /* 16 */ | (1u << TDONE)
8409 /* 17 */ | (1u << TELIF)
8410 /* 18 */ | (1u << TELSE)
8411 /* 19 */ | (1u << TESAC)
8412 /* 20 */ | (1u << TFI)
8413 /* 21 */ | (0u << TFOR)
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008414#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008415 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02008416#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008417 /* 23 */ | (0u << TIF)
8418 /* 24 */ | (0u << TIN)
8419 /* 25 */ | (1u << TTHEN)
8420 /* 26 */ | (0u << TUNTIL)
8421 /* 27 */ | (0u << TWHILE)
8422 /* 28 */ | (0u << TBEGIN)
8423 /* 29 */ | (1u << TEND)
8424 , /* thus far 29 bits used */
8425};
8426
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008427static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02008428 "end of file",
8429 "newline",
8430 "redirection",
8431 "word",
8432 ";",
8433 "&",
8434 "&&",
8435 "||",
8436 "|",
8437 "(",
8438 ")",
8439 ";;",
8440 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008441#define KWDOFFSET 13
8442 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02008443 "!",
8444 "case",
8445 "do",
8446 "done",
8447 "elif",
8448 "else",
8449 "esac",
8450 "fi",
8451 "for",
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008452#if BASH_FUNCTION
Denys Vlasenko888527c2016-10-02 16:54:17 +02008453 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00008454#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02008455 "if",
8456 "in",
8457 "then",
8458 "until",
8459 "while",
8460 "{",
8461 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008462};
8463
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008464/* Wrapper around strcmp for qsort/bsearch/... */
8465static int
8466pstrcmp(const void *a, const void *b)
8467{
Denys Vlasenko888527c2016-10-02 16:54:17 +02008468 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008469}
8470
8471static const char *const *
8472findkwd(const char *s)
8473{
8474 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00008475 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8476 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008477}
8478
8479/*
8480 * Locate and print what a word is...
8481 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008482static int
Ron Yorston3f221112015-08-03 13:47:33 +01008483describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008484{
8485 struct cmdentry entry;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008486#if ENABLE_ASH_ALIAS
8487 const struct alias *ap;
8488#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008489
8490 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008491
8492 if (describe_command_verbose) {
8493 out1str(command);
8494 }
8495
8496 /* First look at the keywords */
8497 if (findkwd(command)) {
8498 out1str(describe_command_verbose ? " is a shell keyword" : command);
8499 goto out;
8500 }
8501
8502#if ENABLE_ASH_ALIAS
8503 /* Then look at the aliases */
8504 ap = lookupalias(command, 0);
8505 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008506 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008507 out1str("alias ");
8508 printalias(ap);
8509 return 0;
8510 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008511 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008512 goto out;
8513 }
8514#endif
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008515 /* Brute force */
8516 find_command(command, &entry, DO_ABS, path);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008517
8518 switch (entry.cmdtype) {
8519 case CMDNORMAL: {
8520 int j = entry.u.index;
8521 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008522 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008523 p = command;
8524 } else {
8525 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008526 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008527 stunalloc(p);
8528 } while (--j >= 0);
8529 }
8530 if (describe_command_verbose) {
Youfu Zhang6683d1c2017-05-26 15:31:29 +08008531 out1fmt(" is %s", p);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008532 } else {
8533 out1str(p);
8534 }
8535 break;
8536 }
8537
8538 case CMDFUNCTION:
8539 if (describe_command_verbose) {
Denys Vlasenko63c42af2018-07-24 17:08:04 +02008540 /*out1str(" is a shell function");*/
8541 out1str(" is a function"); /* bash says this */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008542 } else {
8543 out1str(command);
8544 }
8545 break;
8546
8547 case CMDBUILTIN:
8548 if (describe_command_verbose) {
8549 out1fmt(" is a %sshell builtin",
8550 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8551 "special " : nullstr
8552 );
8553 } else {
8554 out1str(command);
8555 }
8556 break;
8557
8558 default:
8559 if (describe_command_verbose) {
8560 out1str(": not found\n");
8561 }
8562 return 127;
8563 }
8564 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008565 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008566 return 0;
8567}
8568
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008569static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008570typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008571{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008572 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008573 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008574 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008575
Denis Vlasenko46846e22007-05-20 13:08:31 +00008576 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008577 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008578 i++;
8579 verbose = 0;
8580 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008581 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008582 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008583 }
8584 return err;
8585}
8586
8587#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008588/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8589static char **
8590parse_command_args(char **argv, const char **path)
8591{
8592 char *cp, c;
8593
8594 for (;;) {
8595 cp = *++argv;
8596 if (!cp)
8597 return NULL;
8598 if (*cp++ != '-')
8599 break;
8600 c = *cp++;
8601 if (!c)
8602 break;
8603 if (c == '-' && !*cp) {
8604 if (!*++argv)
8605 return NULL;
8606 break;
8607 }
8608 do {
8609 switch (c) {
8610 case 'p':
8611 *path = bb_default_path;
8612 break;
8613 default:
8614 /* run 'typecmd' for other options */
8615 return NULL;
8616 }
8617 c = *cp++;
8618 } while (c);
8619 }
8620 return argv;
8621}
8622
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008623static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008624commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008625{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008626 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008627 int c;
8628 enum {
8629 VERIFY_BRIEF = 1,
8630 VERIFY_VERBOSE = 2,
8631 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008632 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008633
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008634 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8635 * never reaches this function.
8636 */
8637
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008638 while ((c = nextopt("pvV")) != '\0')
8639 if (c == 'V')
8640 verify |= VERIFY_VERBOSE;
8641 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008642 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008643#if DEBUG
8644 else if (c != 'p')
8645 abort();
8646#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008647 else
8648 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008649
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008650 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008651 cmd = *argptr;
8652 if (/*verify && */ cmd)
8653 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008654
8655 return 0;
8656}
8657#endif
8658
8659
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008660/*static int funcblocksize; // size of structures in function */
8661/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008662static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008663static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008664
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008665static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008666 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8667 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8668 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8669 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8670 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8671 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8672 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8673 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8674 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8675 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8676 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8677 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8678 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8679 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8680 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8681 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8682 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008683#if BASH_REDIR_OUTPUT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008684 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008685#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008686 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8687 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8688 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8689 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8690 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8691 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8692 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8693 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8694 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008695};
8696
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008697static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008698
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008699static int
8700sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008701{
8702 while (lp) {
8703 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008704 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008705 lp = lp->next;
8706 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008707 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008708}
8709
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008710static int
8711calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008712{
8713 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008714 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008715 funcblocksize += nodesize[n->type];
8716 switch (n->type) {
8717 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008718 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8719 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8720 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008721 break;
8722 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008723 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008724 break;
8725 case NREDIR:
8726 case NBACKGND:
8727 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008728 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8729 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008730 break;
8731 case NAND:
8732 case NOR:
8733 case NSEMI:
8734 case NWHILE:
8735 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008736 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8737 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008738 break;
8739 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008740 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8741 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8742 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008743 break;
8744 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008745 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008746 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8747 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008748 break;
8749 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008750 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8751 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008752 break;
8753 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008754 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8755 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8756 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008757 break;
8758 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008759 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8760 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8761 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008762 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008763 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008764 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008765 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008766 break;
8767 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008768#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008769 case NTO2:
8770#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008771 case NCLOBBER:
8772 case NFROM:
8773 case NFROMTO:
8774 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008775 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8776 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008777 break;
8778 case NTOFD:
8779 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008780 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8781 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008782 break;
8783 case NHERE:
8784 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008785 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8786 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008787 break;
8788 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008789 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008790 break;
8791 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008792 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008793}
8794
8795static char *
8796nodeckstrdup(char *s)
8797{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008798 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008799 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008800}
8801
8802static union node *copynode(union node *);
8803
8804static struct nodelist *
8805copynodelist(struct nodelist *lp)
8806{
8807 struct nodelist *start;
8808 struct nodelist **lpp;
8809
8810 lpp = &start;
8811 while (lp) {
8812 *lpp = funcblock;
8813 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8814 (*lpp)->n = copynode(lp->n);
8815 lp = lp->next;
8816 lpp = &(*lpp)->next;
8817 }
8818 *lpp = NULL;
8819 return start;
8820}
8821
8822static union node *
8823copynode(union node *n)
8824{
8825 union node *new;
8826
8827 if (n == NULL)
8828 return NULL;
8829 new = funcblock;
8830 funcblock = (char *) funcblock + nodesize[n->type];
8831
8832 switch (n->type) {
8833 case NCMD:
8834 new->ncmd.redirect = copynode(n->ncmd.redirect);
8835 new->ncmd.args = copynode(n->ncmd.args);
8836 new->ncmd.assign = copynode(n->ncmd.assign);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008837 new->ncmd.linno = n->ncmd.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008838 break;
8839 case NPIPE:
8840 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008841 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008842 break;
8843 case NREDIR:
8844 case NBACKGND:
8845 case NSUBSHELL:
8846 new->nredir.redirect = copynode(n->nredir.redirect);
8847 new->nredir.n = copynode(n->nredir.n);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008848 new->nredir.linno = n->nredir.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008849 break;
8850 case NAND:
8851 case NOR:
8852 case NSEMI:
8853 case NWHILE:
8854 case NUNTIL:
8855 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8856 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8857 break;
8858 case NIF:
8859 new->nif.elsepart = copynode(n->nif.elsepart);
8860 new->nif.ifpart = copynode(n->nif.ifpart);
8861 new->nif.test = copynode(n->nif.test);
8862 break;
8863 case NFOR:
8864 new->nfor.var = nodeckstrdup(n->nfor.var);
8865 new->nfor.body = copynode(n->nfor.body);
8866 new->nfor.args = copynode(n->nfor.args);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008867 new->nfor.linno = n->nfor.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008868 break;
8869 case NCASE:
8870 new->ncase.cases = copynode(n->ncase.cases);
8871 new->ncase.expr = copynode(n->ncase.expr);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008872 new->ncase.linno = n->ncase.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008873 break;
8874 case NCLIST:
8875 new->nclist.body = copynode(n->nclist.body);
8876 new->nclist.pattern = copynode(n->nclist.pattern);
8877 new->nclist.next = copynode(n->nclist.next);
8878 break;
8879 case NDEFUN:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008880 new->ndefun.body = copynode(n->ndefun.body);
8881 new->ndefun.text = nodeckstrdup(n->ndefun.text);
8882 new->ndefun.linno = n->ndefun.linno;
8883 break;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008884 case NARG:
8885 new->narg.backquote = copynodelist(n->narg.backquote);
8886 new->narg.text = nodeckstrdup(n->narg.text);
8887 new->narg.next = copynode(n->narg.next);
8888 break;
8889 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01008890#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00008891 case NTO2:
8892#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008893 case NCLOBBER:
8894 case NFROM:
8895 case NFROMTO:
8896 case NAPPEND:
8897 new->nfile.fname = copynode(n->nfile.fname);
8898 new->nfile.fd = n->nfile.fd;
8899 new->nfile.next = copynode(n->nfile.next);
8900 break;
8901 case NTOFD:
8902 case NFROMFD:
8903 new->ndup.vname = copynode(n->ndup.vname);
8904 new->ndup.dupfd = n->ndup.dupfd;
8905 new->ndup.fd = n->ndup.fd;
8906 new->ndup.next = copynode(n->ndup.next);
8907 break;
8908 case NHERE:
8909 case NXHERE:
8910 new->nhere.doc = copynode(n->nhere.doc);
8911 new->nhere.fd = n->nhere.fd;
8912 new->nhere.next = copynode(n->nhere.next);
8913 break;
8914 case NNOT:
8915 new->nnot.com = copynode(n->nnot.com);
8916 break;
8917 };
8918 new->type = n->type;
8919 return new;
8920}
8921
8922/*
8923 * Make a copy of a parse tree.
8924 */
8925static struct funcnode *
8926copyfunc(union node *n)
8927{
8928 struct funcnode *f;
8929 size_t blocksize;
8930
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008931 /*funcstringsize = 0;*/
8932 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8933 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008934 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008935 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008936 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008937 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008938 return f;
8939}
8940
8941/*
8942 * Define a shell function.
8943 */
8944static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008945defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008946{
8947 struct cmdentry entry;
8948
8949 INT_OFF;
8950 entry.cmdtype = CMDFUNCTION;
8951 entry.u.func = copyfunc(func);
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008952 addcmdentry(func->ndefun.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008953 INT_ON;
8954}
8955
Denis Vlasenko4b875702009-03-19 13:30:04 +00008956/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008957#define SKIPBREAK (1 << 0)
8958#define SKIPCONT (1 << 1)
8959#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008960static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008961static int skipcount; /* number of levels to skip */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008962static int loopnest; /* current loop nesting level */
Denys Vlasenko675d24a2018-01-27 22:02:05 +01008963static int funcline; /* starting line number of current function, or 0 if not in a function */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008964
Denis Vlasenko4b875702009-03-19 13:30:04 +00008965/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008966static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008967
Denis Vlasenko4b875702009-03-19 13:30:04 +00008968/* Called to execute a trap.
8969 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008970 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008971 *
8972 * Perhaps we should avoid entering new trap handlers
8973 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008974 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008975static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008976dotrap(void)
8977{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008978 uint8_t *g;
8979 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008980 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008981
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008982 if (!pending_sig)
8983 return;
8984
8985 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008986 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008987 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008988
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008989 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008990 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008991 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008992
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008993 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008994 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008995
8996 if (evalskip) {
8997 pending_sig = sig;
8998 break;
8999 }
9000
9001 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00009002 /* non-trapped SIGINT is handled separately by raise_interrupt,
9003 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009004 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009005 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009006
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009007 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00009008 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009009 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00009010 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009011 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009012 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009013 exitstatus = last_status;
9014 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00009015}
9016
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00009017/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009018static int evalloop(union node *, int);
9019static int evalfor(union node *, int);
9020static int evalcase(union node *, int);
9021static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009022static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009023static int evalpipe(union node *, int);
9024static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009025static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009026static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009027
Eric Andersen62483552001-07-10 06:09:16 +00009028/*
Eric Andersenc470f442003-07-28 09:56:35 +00009029 * Evaluate a parse tree. The value is left in the global variable
9030 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00009031 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009032static int
Eric Andersenc470f442003-07-28 09:56:35 +00009033evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00009034{
Eric Andersenc470f442003-07-28 09:56:35 +00009035 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009036 int (*evalfn)(union node *, int);
9037 int status = 0;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009038
Eric Andersenc470f442003-07-28 09:56:35 +00009039 if (n == NULL) {
9040 TRACE(("evaltree(NULL) called\n"));
Denys Vlasenkoc0663c72016-10-27 21:09:01 +02009041 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00009042 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009043 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009044
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009045 dotrap();
9046
Eric Andersenc470f442003-07-28 09:56:35 +00009047 switch (n->type) {
9048 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009049#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00009050 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009051 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00009052 break;
9053#endif
9054 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009055 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009056 goto setstatus;
9057 case NREDIR:
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009058 errlinno = lineno = n->nredir.linno;
9059 if (funcline)
9060 lineno -= funcline - 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009061 expredir(n->nredir.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009062 pushredir(n->nredir.redirect);
Eric Andersenc470f442003-07-28 09:56:35 +00009063 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
9064 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009065 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009066 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009067 if (n->nredir.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +02009068 popredir(/*drop:*/ 0);
Eric Andersenc470f442003-07-28 09:56:35 +00009069 goto setstatus;
9070 case NCMD:
9071 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009072 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00009073 if (eflag && !(flags & EV_TESTED))
9074 checkexit = ~0;
9075 goto calleval;
9076 case NFOR:
9077 evalfn = evalfor;
9078 goto calleval;
9079 case NWHILE:
9080 case NUNTIL:
9081 evalfn = evalloop;
9082 goto calleval;
9083 case NSUBSHELL:
9084 case NBACKGND:
9085 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02009086 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00009087 case NPIPE:
9088 evalfn = evalpipe;
9089 goto checkexit;
9090 case NCASE:
9091 evalfn = evalcase;
9092 goto calleval;
9093 case NAND:
9094 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009095 case NSEMI: {
9096
Eric Andersenc470f442003-07-28 09:56:35 +00009097#if NAND + 1 != NOR
9098#error NAND + 1 != NOR
9099#endif
9100#if NOR + 1 != NSEMI
9101#error NOR + 1 != NSEMI
9102#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00009103 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009104 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00009105 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009106 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00009107 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02009108 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00009109 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009110 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009111 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009112 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009113 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009114 status = evalfn(n, flags);
9115 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00009116 }
Eric Andersenc470f442003-07-28 09:56:35 +00009117 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009118 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00009119 if (evalskip)
9120 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009121 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00009122 n = n->nif.ifpart;
9123 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009124 }
9125 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00009126 n = n->nif.elsepart;
9127 goto evaln;
9128 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009129 status = 0;
9130 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009131 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009132 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009133 /* Not necessary. To test it:
9134 * "false; f() { qwerty; }; echo $?" should print 0.
9135 */
9136 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009137 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00009138 exitstatus = status;
9139 break;
9140 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009141 out:
Denys Vlasenkob563f622010-09-25 17:15:13 +02009142 /* Order of checks below is important:
9143 * signal handlers trigger before exit caused by "set -e".
9144 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009145 dotrap();
9146
9147 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009148 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02009149 if (flags & EV_EXIT)
9150 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009151
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009152 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009153 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00009154}
9155
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02009156static int
9157skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009158{
9159 int skip = evalskip;
9160
9161 switch (skip) {
9162 case 0:
9163 break;
9164 case SKIPBREAK:
9165 case SKIPCONT:
9166 if (--skipcount <= 0) {
9167 evalskip = 0;
9168 break;
9169 }
9170 skip = SKIPBREAK;
9171 break;
9172 }
9173 return skip;
9174}
9175
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009176static int
Eric Andersenc470f442003-07-28 09:56:35 +00009177evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009178{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009179 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00009180 int status;
9181
9182 loopnest++;
9183 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009184 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009185 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009186 int i;
9187
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009188 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009189 skip = skiploop();
9190 if (skip == SKIPFUNC)
9191 status = i;
9192 if (skip)
9193 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00009194 if (n->type != NWHILE)
9195 i = !i;
9196 if (i != 0)
9197 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009198 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009199 skip = skiploop();
9200 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009201 loopnest--;
9202
9203 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009204}
9205
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009206static int
Eric Andersenc470f442003-07-28 09:56:35 +00009207evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009208{
9209 struct arglist arglist;
9210 union node *argp;
9211 struct strlist *sp;
9212 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009213 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009214
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009215 errlinno = lineno = n->ncase.linno;
9216 if (funcline)
9217 lineno -= funcline - 1;
9218
Eric Andersencb57d552001-06-28 07:25:16 +00009219 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009220 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009221 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009222 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02009223 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00009224 }
9225 *arglist.lastp = NULL;
9226
Eric Andersencb57d552001-06-28 07:25:16 +00009227 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009228 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009229 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009230 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009231 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02009232 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00009233 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009234 }
9235 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00009236 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009237
9238 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009239}
9240
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009241static int
Eric Andersenc470f442003-07-28 09:56:35 +00009242evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009243{
9244 union node *cp;
9245 union node *patp;
9246 struct arglist arglist;
9247 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009248 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009249
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009250 errlinno = lineno = n->ncase.linno;
9251 if (funcline)
9252 lineno -= funcline - 1;
9253
Eric Andersencb57d552001-06-28 07:25:16 +00009254 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009255 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00009256 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00009257 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009258 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
9259 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00009260 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009261 /* Ensure body is non-empty as otherwise
9262 * EV_EXIT may prevent us from setting the
9263 * exit status.
9264 */
9265 if (evalskip == 0 && cp->nclist.body) {
9266 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00009267 }
9268 goto out;
9269 }
9270 }
9271 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009272 out:
Eric Andersencb57d552001-06-28 07:25:16 +00009273 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009274
9275 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009276}
9277
Eric Andersenc470f442003-07-28 09:56:35 +00009278/*
9279 * Kick off a subshell to evaluate a tree.
9280 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009281static int
Eric Andersenc470f442003-07-28 09:56:35 +00009282evalsubshell(union node *n, int flags)
9283{
9284 struct job *jp;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009285 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
Eric Andersenc470f442003-07-28 09:56:35 +00009286 int status;
9287
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009288 errlinno = lineno = n->nredir.linno;
9289 if (funcline)
9290 lineno -= funcline - 1;
9291
Eric Andersenc470f442003-07-28 09:56:35 +00009292 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02009293 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00009294 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009295 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009296 if (backgnd == FORK_FG)
9297 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009298 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009299 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009300 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009301 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009302 flags |= EV_EXIT;
9303 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02009304 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00009305 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00009306 redirect(n->nredir.redirect, 0);
9307 evaltreenr(n->nredir.n, flags);
9308 /* never returns */
9309 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009310 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009311 status = 0;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009312 if (backgnd == FORK_FG)
Eric Andersenc470f442003-07-28 09:56:35 +00009313 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009314 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009315 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009316}
9317
Eric Andersenc470f442003-07-28 09:56:35 +00009318/*
9319 * Compute the names of the files in a redirection list.
9320 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009321static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00009322static void
9323expredir(union node *n)
9324{
9325 union node *redir;
9326
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009327 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009328 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009329
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00009330 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009331 fn.lastp = &fn.list;
9332 switch (redir->type) {
9333 case NFROMTO:
9334 case NFROM:
9335 case NTO:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009336#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009337 case NTO2:
9338#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009339 case NCLOBBER:
9340 case NAPPEND:
9341 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02009342 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009343#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009344 store_expfname:
9345#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009346#if 0
9347// By the design of stack allocator, the loop of this kind:
9348// while true; do while true; do break; done </dev/null; done
9349// will look like a memory leak: ash plans to free expfname's
9350// of "/dev/null" as soon as it finishes running the loop
9351// (in this case, never).
9352// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01009353 if (redir->nfile.expfname)
9354 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01009355// It results in corrupted state of stacked allocations.
9356#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009357 redir->nfile.expfname = fn.list->text;
9358 break;
9359 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00009360 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00009361 if (redir->ndup.vname) {
9362 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009363 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009364 ash_msg_and_raise_error("redir error");
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009365#if BASH_REDIR_OUTPUT
Denis Vlasenko559691a2008-10-05 18:39:31 +00009366//FIXME: we used expandarg with different args!
9367 if (!isdigit_str9(fn.list->text)) {
9368 /* >&file, not >&fd */
9369 if (redir->nfile.fd != 1) /* 123>&file - BAD */
9370 ash_msg_and_raise_error("redir error");
9371 redir->type = NTO2;
9372 goto store_expfname;
9373 }
9374#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009375 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009376 }
9377 break;
9378 }
9379 }
9380}
9381
Eric Andersencb57d552001-06-28 07:25:16 +00009382/*
Eric Andersencb57d552001-06-28 07:25:16 +00009383 * Evaluate a pipeline. All the processes in the pipeline are children
9384 * of the process creating the pipeline. (This differs from some versions
9385 * of the shell, which make the last process in a pipeline the parent
9386 * of all the rest.)
9387 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009388static int
Eric Andersenc470f442003-07-28 09:56:35 +00009389evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00009390{
9391 struct job *jp;
9392 struct nodelist *lp;
9393 int pipelen;
9394 int prevfd;
9395 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009396 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009397
Eric Andersenc470f442003-07-28 09:56:35 +00009398 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00009399 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009400 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00009401 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009402 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009403 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +01009404 if (n->npipe.pipe_backgnd == 0)
9405 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +00009406 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00009407 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009408 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009409 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00009410 pip[1] = -1;
9411 if (lp->next) {
9412 if (pipe(pip) < 0) {
9413 close(prevfd);
Denys Vlasenko12ffefb2017-08-23 14:52:56 +02009414 ash_msg_and_raise_perror("can't create pipe");
Eric Andersencb57d552001-06-28 07:25:16 +00009415 }
9416 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009417 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02009418 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009419 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00009420 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009421 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00009422 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009423 if (prevfd > 0) {
9424 dup2(prevfd, 0);
9425 close(prevfd);
9426 }
9427 if (pip[1] > 1) {
9428 dup2(pip[1], 1);
9429 close(pip[1]);
9430 }
Eric Andersenc470f442003-07-28 09:56:35 +00009431 evaltreenr(lp->n, flags);
9432 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00009433 }
Denys Vlasenko70392332016-10-27 02:31:55 +02009434 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00009435 if (prevfd >= 0)
9436 close(prevfd);
9437 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00009438 /* Don't want to trigger debugging */
9439 if (pip[1] != -1)
9440 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009441 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00009442 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009443 status = waitforjob(jp);
9444 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00009445 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009446 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009447
9448 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00009449}
9450
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009451/*
9452 * Controls whether the shell is interactive or not.
9453 */
9454static void
9455setinteractive(int on)
9456{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009457 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009458
9459 if (++on == is_interactive)
9460 return;
9461 is_interactive = on;
9462 setsignal(SIGINT);
9463 setsignal(SIGQUIT);
9464 setsignal(SIGTERM);
9465#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9466 if (is_interactive > 1) {
9467 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009468 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009469
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009470 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009471 /* note: ash and hush share this string */
9472 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009473 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9474 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02009475 bb_banner,
9476 "built-in shell (ash)"
9477 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00009478 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009479 }
9480 }
9481#endif
9482}
9483
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009484static void
9485optschanged(void)
9486{
9487#if DEBUG
9488 opentrace();
9489#endif
9490 setinteractive(iflag);
9491 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009492#if ENABLE_FEATURE_EDITING_VI
9493 if (viflag)
9494 line_input_state->flags |= VI_MODE;
9495 else
9496 line_input_state->flags &= ~VI_MODE;
9497#else
9498 viflag = 0; /* forcibly keep the option off */
9499#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009500}
9501
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009502struct localvar_list {
9503 struct localvar_list *next;
9504 struct localvar *lv;
9505};
9506
9507static struct localvar_list *localvar_stack;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009508
9509/*
9510 * Called after a function returns.
9511 * Interrupts must be off.
9512 */
9513static void
Denys Vlasenko981a0562017-07-26 19:53:11 +02009514poplocalvars(int keep)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009515{
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009516 struct localvar_list *ll;
9517 struct localvar *lvp, *next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009518 struct var *vp;
9519
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009520 INT_OFF;
9521 ll = localvar_stack;
9522 localvar_stack = ll->next;
9523
9524 next = ll->lv;
9525 free(ll);
9526
9527 while ((lvp = next) != NULL) {
9528 next = lvp->next;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009529 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009530 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denys Vlasenko981a0562017-07-26 19:53:11 +02009531 if (keep) {
9532 int bits = VSTRFIXED;
9533
9534 if (lvp->flags != VUNSET) {
9535 if (vp->var_text == lvp->text)
9536 bits |= VTEXTFIXED;
9537 else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
9538 free((char*)lvp->text);
9539 }
9540
9541 vp->flags &= ~bits;
9542 vp->flags |= (lvp->flags & bits);
9543
9544 if ((vp->flags &
9545 (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
9546 unsetvar(vp->var_text);
9547 } else if (vp == NULL) { /* $- saved */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009548 memcpy(optlist, lvp->text, sizeof(optlist));
9549 free((char*)lvp->text);
9550 optschanged();
Denys Vlasenkod5b500c2017-07-26 19:25:40 +02009551 } else if (lvp->flags == VUNSET) {
9552 vp->flags &= ~(VSTRFIXED|VREADONLY);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009553 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009554 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009555 if (vp->var_func)
9556 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009557 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009558 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009559 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009560 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009561 }
9562 free(lvp);
9563 }
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009564 INT_ON;
9565}
9566
9567/*
9568 * Create a new localvar environment.
9569 */
Denys Vlasenko484fc202017-07-26 19:55:31 +02009570static struct localvar_list *
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009571pushlocalvars(void)
9572{
9573 struct localvar_list *ll;
9574
9575 INT_OFF;
9576 ll = ckzalloc(sizeof(*ll));
9577 /*ll->lv = NULL; - zalloc did it */
9578 ll->next = localvar_stack;
9579 localvar_stack = ll;
9580 INT_ON;
Denys Vlasenko484fc202017-07-26 19:55:31 +02009581
9582 return ll->next;
9583}
9584
9585static void
9586unwindlocalvars(struct localvar_list *stop)
9587{
9588 while (localvar_stack != stop)
9589 poplocalvars(0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009590}
9591
9592static int
9593evalfun(struct funcnode *func, int argc, char **argv, int flags)
9594{
9595 volatile struct shparam saveparam;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009596 struct jmploc *volatile savehandler;
9597 struct jmploc jmploc;
9598 int e;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009599 int savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009600
9601 saveparam = shellparam;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009602 savefuncline = funcline;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009603 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009604 e = setjmp(jmploc.loc);
9605 if (e) {
9606 goto funcdone;
9607 }
9608 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009609 exception_handler = &jmploc;
Denis Vlasenko01631112007-12-16 17:20:38 +00009610 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009611 func->count++;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009612 funcline = func->n.ndefun.linno;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009613 INT_ON;
9614 shellparam.nparam = argc - 1;
9615 shellparam.p = argv + 1;
9616#if ENABLE_ASH_GETOPTS
9617 shellparam.optind = 1;
9618 shellparam.optoff = -1;
9619#endif
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009620 evaltree(func->n.ndefun.body, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009621 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009622 INT_OFF;
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009623 funcline = savefuncline;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009624 freefunc(func);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009625 freeparam(&shellparam);
9626 shellparam = saveparam;
9627 exception_handler = savehandler;
9628 INT_ON;
9629 evalskip &= ~SKIPFUNC;
9630 return e;
9631}
9632
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009633/*
9634 * Make a variable a local variable. When a variable is made local, it's
9635 * value and flags are saved in a localvar structure. The saved values
9636 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009637 * "-" as a special case: it makes changes to "set +-options" local
9638 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009639 */
9640static void
9641mklocal(char *name)
9642{
9643 struct localvar *lvp;
9644 struct var **vpp;
9645 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009646 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009647
9648 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009649 /* Cater for duplicate "local". Examples:
9650 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9651 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9652 */
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009653 lvp = localvar_stack->lv;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009654 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009655 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009656 if (eq)
9657 setvareq(name, 0);
9658 /* else:
9659 * it's a duplicate "local VAR" declaration, do nothing
9660 */
Denys Vlasenko06b11492016-11-04 16:43:18 +01009661 goto ret;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009662 }
9663 lvp = lvp->next;
9664 }
9665
9666 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009667 if (LONE_DASH(name)) {
9668 char *p;
9669 p = ckmalloc(sizeof(optlist));
9670 lvp->text = memcpy(p, optlist, sizeof(optlist));
9671 vp = NULL;
9672 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009673 vpp = hashvar(name);
9674 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009675 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009676 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009677 if (eq)
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009678 vp = setvareq(name, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009679 else
Denys Vlasenkod04fc712017-07-26 20:06:48 +02009680 vp = setvar(name, NULL, VSTRFIXED);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009681 lvp->flags = VUNSET;
9682 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009683 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009684 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009685 /* make sure neither "struct var" nor string gets freed
9686 * during (un)setting:
9687 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009688 vp->flags |= VSTRFIXED|VTEXTFIXED;
9689 if (eq)
9690 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009691 else
9692 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009693 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009694 }
9695 }
9696 lvp->vp = vp;
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009697 lvp->next = localvar_stack->lv;
9698 localvar_stack->lv = lvp;
Denys Vlasenko06b11492016-11-04 16:43:18 +01009699 ret:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009700 INT_ON;
9701}
9702
9703/*
9704 * The "local" command.
9705 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009706static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009707localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009708{
9709 char *name;
9710
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +02009711 if (!localvar_stack)
Ron Yorstonef2386b2015-10-29 16:19:14 +00009712 ash_msg_and_raise_error("not in a function");
9713
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009714 argv = argptr;
9715 while ((name = *argv++) != NULL) {
9716 mklocal(name);
9717 }
9718 return 0;
9719}
9720
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009721static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009722falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009723{
9724 return 1;
9725}
9726
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009727static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009728truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009729{
9730 return 0;
9731}
9732
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009733static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009734execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009735{
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009736 optionarg = NULL;
9737 while (nextopt("a:") != '\0')
9738 /* nextopt() sets optionarg to "-a ARGV0" */;
9739
9740 argv = argptr;
9741 if (argv[0]) {
9742 char *prog;
9743
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009744 iflag = 0; /* exit on error */
9745 mflag = 0;
9746 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009747 /* We should set up signals for "exec CMD"
9748 * the same way as for "CMD" without "exec".
9749 * But optschanged->setinteractive->setsignal
9750 * still thought we are a root shell. Therefore, for example,
9751 * SIGQUIT is still set to IGN. Fix it:
9752 */
9753 shlvl++;
9754 setsignal(SIGQUIT);
9755 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9756 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9757 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9758
Denys Vlasenko6c149f42017-04-12 21:31:32 +02009759 prog = argv[0];
9760 if (optionarg)
9761 argv[0] = optionarg;
9762 shellexec(prog, argv, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009763 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009764 }
9765 return 0;
9766}
9767
9768/*
9769 * The return command.
9770 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009771static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009772returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009773{
9774 /*
9775 * If called outside a function, do what ksh does;
9776 * skip the rest of the file.
9777 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009778 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009779 return argv[1] ? number(argv[1]) : exitstatus;
9780}
9781
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009782/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009783static int breakcmd(int, char **) FAST_FUNC;
9784static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009785static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009786static int exitcmd(int, char **) FAST_FUNC;
9787static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009788#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009789static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009790#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009791#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009792static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009793#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009794#if MAX_HISTORY
9795static int historycmd(int, char **) FAST_FUNC;
9796#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009797#if ENABLE_FEATURE_SH_MATH
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009798static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009799#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009800static int readcmd(int, char **) FAST_FUNC;
9801static int setcmd(int, char **) FAST_FUNC;
9802static int shiftcmd(int, char **) FAST_FUNC;
9803static int timescmd(int, char **) FAST_FUNC;
9804static int trapcmd(int, char **) FAST_FUNC;
9805static int umaskcmd(int, char **) FAST_FUNC;
9806static int unsetcmd(int, char **) FAST_FUNC;
9807static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009808
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009809#define BUILTIN_NOSPEC "0"
9810#define BUILTIN_SPECIAL "1"
9811#define BUILTIN_REGULAR "2"
9812#define BUILTIN_SPEC_REG "3"
9813#define BUILTIN_ASSIGN "4"
9814#define BUILTIN_SPEC_ASSG "5"
9815#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009816#define BUILTIN_SPEC_REG_ASSG "7"
9817
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009818/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko265062d2017-01-10 15:13:30 +01009819#if ENABLE_ASH_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009820static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009821#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009822#if ENABLE_ASH_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009823static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009824#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009825#if ENABLE_ASH_TEST || BASH_TEST2
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009826static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009827#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009828
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009829/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009830static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009831 { BUILTIN_SPEC_REG "." , dotcmd },
9832 { BUILTIN_SPEC_REG ":" , truecmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009833#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009834 { BUILTIN_REGULAR "[" , testcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009835#endif
9836#if BASH_TEST2
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009837 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009838#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009839#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009840 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009841#endif
9842#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009843 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009844#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009845 { BUILTIN_SPEC_REG "break" , breakcmd },
9846 { BUILTIN_REGULAR "cd" , cdcmd },
9847 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009848#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009849 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009850#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009851 { BUILTIN_SPEC_REG "continue", breakcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009852#if ENABLE_ASH_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009853 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009854#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009855 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009856 { BUILTIN_SPEC_REG "exec" , execcmd },
9857 { BUILTIN_SPEC_REG "exit" , exitcmd },
9858 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9859 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009860#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009861 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009862#endif
9863#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009864 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009865#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009866 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009867#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009868 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009869#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009870#if MAX_HISTORY
9871 { BUILTIN_NOSPEC "history" , historycmd },
9872#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009873#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009874 { BUILTIN_REGULAR "jobs" , jobscmd },
9875 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009876#endif
Denys Vlasenko0b883582016-12-23 16:49:07 +01009877#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009878 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009879#endif
Denys Vlasenko85241c72017-07-26 20:00:08 +02009880 { BUILTIN_SPEC_REG_ASSG "local" , localcmd },
Denys Vlasenko265062d2017-01-10 15:13:30 +01009881#if ENABLE_ASH_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009882 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009883#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009884 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9885 { BUILTIN_REGULAR "read" , readcmd },
9886 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9887 { BUILTIN_SPEC_REG "return" , returncmd },
9888 { BUILTIN_SPEC_REG "set" , setcmd },
9889 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009890#if BASH_SOURCE
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009891 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009892#endif
Denys Vlasenko265062d2017-01-10 15:13:30 +01009893#if ENABLE_ASH_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009894 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009895#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009896 { BUILTIN_SPEC_REG "times" , timescmd },
9897 { BUILTIN_SPEC_REG "trap" , trapcmd },
9898 { BUILTIN_REGULAR "true" , truecmd },
9899 { BUILTIN_NOSPEC "type" , typecmd },
9900 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9901 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009902#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009903 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009904#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009905 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9906 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009907};
9908
Denis Vlasenko80591b02008-03-25 07:49:43 +00009909/* Should match the above table! */
9910#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009911 /* . : */ 2 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009912 /* [ */ 1 * ENABLE_ASH_TEST + \
Denys Vlasenko7d4aec02017-01-11 14:00:38 +01009913 /* [[ */ 1 * BASH_TEST2 + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009914 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9915 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9916 /* break cd cddir */ 3)
9917#define EVALCMD (COMMANDCMD + \
9918 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9919 /* continue */ 1 + \
Denys Vlasenko265062d2017-01-10 15:13:30 +01009920 /* echo */ 1 * ENABLE_ASH_ECHO + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009921 0)
9922#define EXECCMD (EVALCMD + \
9923 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009924
9925/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009926 * Search the table of builtin commands.
9927 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009928static int
9929pstrcmp1(const void *a, const void *b)
9930{
9931 return strcmp((char*)a, *(char**)b + 1);
9932}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009933static struct builtincmd *
9934find_builtin(const char *name)
9935{
9936 struct builtincmd *bp;
9937
9938 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009939 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009940 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009941 );
9942 return bp;
9943}
9944
9945/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009946 * Execute a simple command.
9947 */
Denys Vlasenko1c5eb882018-08-05 17:07:26 +02009948static void unwindfiles(struct parsefile *stop);
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009949static int
9950isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009951{
9952 const char *q = endofname(p);
9953 if (p == q)
9954 return 0;
9955 return *q == '=';
9956}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009957static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009958bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009959{
9960 /* Preserve exitstatus of a previous possible redirection
9961 * as POSIX mandates */
9962 return back_exitstatus;
9963}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009964static int
Eric Andersenc470f442003-07-28 09:56:35 +00009965evalcommand(union node *cmd, int flags)
9966{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009967 static const struct builtincmd null_bltin = {
9968 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009969 };
Denys Vlasenko484fc202017-07-26 19:55:31 +02009970 struct localvar_list *localvar_stop;
Denys Vlasenko1c5eb882018-08-05 17:07:26 +02009971 struct parsefile *file_stop;
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +02009972 struct redirtab *redir_stop;
Eric Andersenc470f442003-07-28 09:56:35 +00009973 struct stackmark smark;
9974 union node *argp;
9975 struct arglist arglist;
9976 struct arglist varlist;
9977 char **argv;
9978 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009979 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009980 struct cmdentry cmdentry;
9981 struct job *jp;
9982 char *lastarg;
9983 const char *path;
9984 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009985 int status;
9986 char **nargv;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009987 smallint cmd_is_exec;
Eric Andersenc470f442003-07-28 09:56:35 +00009988
Denys Vlasenko675d24a2018-01-27 22:02:05 +01009989 errlinno = lineno = cmd->ncmd.linno;
9990 if (funcline)
9991 lineno -= funcline - 1;
9992
Eric Andersenc470f442003-07-28 09:56:35 +00009993 /* First expand the arguments. */
9994 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9995 setstackmark(&smark);
Denys Vlasenko484fc202017-07-26 19:55:31 +02009996 localvar_stop = pushlocalvars();
Denys Vlasenko1c5eb882018-08-05 17:07:26 +02009997 file_stop = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +00009998 back_exitstatus = 0;
9999
10000 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010001 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +000010002 varlist.lastp = &varlist.list;
10003 *varlist.lastp = NULL;
10004 arglist.lastp = &arglist.list;
10005 *arglist.lastp = NULL;
10006
10007 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010008 if (cmd->ncmd.args) {
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010009 struct builtincmd *bcmd;
10010 smallint pseudovarflag;
10011
Paul Foxc3850c82005-07-20 18:23:39 +000010012 bcmd = find_builtin(cmd->ncmd.args->narg.text);
10013 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Paul Foxc3850c82005-07-20 18:23:39 +000010014
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010015 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
10016 struct strlist **spp;
Eric Andersenc470f442003-07-28 09:56:35 +000010017
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010018 spp = arglist.lastp;
10019 if (pseudovarflag && isassignment(argp->narg.text))
10020 expandarg(argp, &arglist, EXP_VARTILDE);
10021 else
10022 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Paul Foxc3850c82005-07-20 18:23:39 +000010023
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010024 for (sp = *spp; sp; sp = sp->next)
10025 argc++;
10026 }
Eric Andersenc470f442003-07-28 09:56:35 +000010027 }
10028
Denys Vlasenko65a8b852016-10-26 22:29:11 +020010029 /* Reserve one extra spot at the front for shellexec. */
10030 nargv = stalloc(sizeof(char *) * (argc + 2));
10031 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010032 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +000010033 TRACE(("evalcommand arg: %s\n", sp->text));
10034 *nargv++ = sp->text;
10035 }
10036 *nargv = NULL;
10037
10038 lastarg = NULL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010010039 if (iflag && funcline == 0 && argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010040 lastarg = nargv[-1];
10041
10042 expredir(cmd->ncmd.redirect);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010043 redir_stop = pushredir(cmd->ncmd.redirect);
Denys Vlasenkod07a15b2017-07-30 16:51:05 +020010044 preverrout_fd = 2;
Denys Vlasenkof8cdc7a2017-08-04 15:24:49 +020010045 if (BASH_XTRACEFD && xflag) {
10046 /* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
10047 * we do not emulate this. We only use its value.
10048 */
10049 const char *xtracefd = lookupvar("BASH_XTRACEFD");
10050 if (xtracefd && is_number(xtracefd))
10051 preverrout_fd = atoi(xtracefd);
10052
10053 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010054 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +000010055
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010056 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +000010057 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
10058 struct strlist **spp;
10059 char *p;
10060
10061 spp = varlist.lastp;
10062 expandarg(argp, &varlist, EXP_VARTILDE);
10063
Denys Vlasenko981a0562017-07-26 19:53:11 +020010064 mklocal((*spp)->text);
10065
Eric Andersenc470f442003-07-28 09:56:35 +000010066 /*
10067 * Modify the command lookup path, if a PATH= assignment
10068 * is present
10069 */
10070 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010071 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010072 path = p;
10073 }
10074
10075 /* Print the command if xflag is set. */
10076 if (xflag) {
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010077 const char *pfx = "";
Eric Andersenc470f442003-07-28 09:56:35 +000010078
Denys Vlasenko46999802017-07-29 21:12:29 +020010079 fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX));
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010080
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010081 sp = varlist.list;
Denys Vlasenko42ba7572017-07-21 13:20:14 +020010082 while (sp) {
10083 char *varval = sp->text;
10084 char *eq = strchrnul(varval, '=');
10085 if (*eq)
10086 eq++;
10087 fdprintf(preverrout_fd, "%s%.*s%s",
10088 pfx,
10089 (int)(eq - varval), varval,
10090 maybe_single_quote(eq)
10091 );
10092 sp = sp->next;
10093 pfx = " ";
10094 }
10095
10096 sp = arglist.list;
10097 while (sp) {
10098 fdprintf(preverrout_fd, "%s%s",
10099 pfx,
10100 /* always quote if matches reserved word: */
10101 findkwd(sp->text)
10102 ? single_quote(sp->text)
10103 : maybe_single_quote(sp->text)
10104 );
10105 sp = sp->next;
10106 pfx = " ";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010107 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000010108 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010109 }
10110
10111 cmd_is_exec = 0;
10112 spclbltin = -1;
10113
10114 /* Now locate the command. */
10115 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +000010116 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +020010117#if ENABLE_ASH_CMDCMD
10118 const char *oldpath = path + 5;
10119#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010120 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +000010121 for (;;) {
10122 find_command(argv[0], &cmdentry, cmd_flag, path);
10123 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +010010124 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010125 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +000010126 goto bail;
10127 }
10128
10129 /* implement bltin and command here */
10130 if (cmdentry.cmdtype != CMDBUILTIN)
10131 break;
10132 if (spclbltin < 0)
10133 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
10134 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +000010135 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010136#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +000010137 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +000010138 path = oldpath;
10139 nargv = parse_command_args(argv, &path);
10140 if (!nargv)
10141 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +020010142 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
10143 * nargv => "PROG". path is updated if -p.
10144 */
Eric Andersenc470f442003-07-28 09:56:35 +000010145 argc -= nargv - argv;
10146 argv = nargv;
10147 cmd_flag |= DO_NOFUNC;
10148 } else
10149#endif
10150 break;
10151 }
10152 }
10153
10154 if (status) {
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010155 bail:
10156 exitstatus = status;
10157
Eric Andersenc470f442003-07-28 09:56:35 +000010158 /* We have a redirection error. */
10159 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010160 raise_exception(EXERROR);
Ron Yorstonea7d2f62017-01-03 11:18:23 +010010161
Eric Andersenc470f442003-07-28 09:56:35 +000010162 goto out;
10163 }
10164
10165 /* Execute the command. */
10166 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010167 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010168
Denys Vlasenko1750d3a2018-01-15 00:41:04 +010010169#if ENABLE_FEATURE_SH_STANDALONE \
10170 && ENABLE_FEATURE_SH_NOFORK \
10171 && NUM_APPLETS > 1
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010172/* (1) BUG: if variables are set, we need to fork, or save/restore them
10173 * around run_nofork_applet() call.
10174 * (2) Should this check also be done in forkshell()?
10175 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
10176 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000010177 /* find_command() encodes applet_no as (-2 - applet_no) */
10178 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010179 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010180 char **sv_environ;
10181
10182 INT_OFF;
10183 sv_environ = environ;
10184 environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
Denys Vlasenkod329e342017-08-04 14:50:03 +020010185 /*
10186 * Run <applet>_main().
10187 * Signals (^C) can't interrupt here.
10188 * Otherwise we can mangle stdio or malloc internal state.
10189 * This makes applets which can run for a long time
10190 * and/or wait for user input ineligible for NOFORK:
10191 * for example, "yes" or "rm" (rm -i waits for input).
10192 */
Ron Yorston5ccb0e92016-10-20 12:24:02 +010010193 status = run_nofork_applet(applet_no, argv);
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010010194 environ = sv_environ;
Denys Vlasenkod329e342017-08-04 14:50:03 +020010195 /*
10196 * Try enabling NOFORK for "yes" applet.
10197 * ^C _will_ stop it (write returns EINTR),
10198 * but this causes stdout FILE to be stuck
10199 * and needing clearerr(). What if other applets
10200 * also can get EINTRs? Do we need to switch
10201 * our signals to SA_RESTART?
10202 */
10203 /*clearerr(stdout);*/
10204 INT_ON;
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010205 break;
10206 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +000010207#endif
Denys Vlasenkocfd392b2017-08-03 19:56:29 +020010208 /* Can we avoid forking? For example, very last command
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010209 * in a script or a subshell does not need forking,
10210 * we can just exec it.
10211 */
Denys Vlasenko238bf182010-05-18 15:49:07 +020010212 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010213 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010214 INT_OFF;
Denys Vlasenko098b7132017-01-11 19:59:03 +010010215 get_tty_state();
Denis Vlasenko68404f12008-03-17 09:00:54 +000010216 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010217 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +020010218 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010219 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010220 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010221 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +000010222 break;
10223 }
Denys Vlasenko238bf182010-05-18 15:49:07 +020010224 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010225 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +020010226 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +000010227 }
10228 listsetvar(varlist.list, VEXPORT|VSTACK);
Denys Vlasenkoe139ae32017-04-12 21:02:33 +020010229 shellexec(argv[0], argv, path, cmdentry.u.index);
Eric Andersenc470f442003-07-28 09:56:35 +000010230 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010231 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +000010232 case CMDBUILTIN:
Denys Vlasenko85241c72017-07-26 20:00:08 +020010233 if (spclbltin > 0 || argc == 0) {
10234 poplocalvars(1);
10235 if (cmd_is_exec && argc > 1)
10236 listsetvar(varlist.list, VEXPORT);
10237 }
Denys Vlasenko981a0562017-07-26 19:53:11 +020010238
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010239 /* Tight loop with builtins only:
10240 * "while kill -0 $child; do true; done"
10241 * will never exit even if $child died, unless we do this
10242 * to reap the zombie and make kill detect that it's gone: */
10243 dowait(DOWAIT_NONBLOCK, NULL);
10244
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010245 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010246 if (exception_type == EXERROR && spclbltin <= 0) {
10247 FORCE_INT_ON;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020010248 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010249 }
Denys Vlasenkoc0663c72016-10-27 21:09:01 +020010250 raise:
10251 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010252 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010253 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010254
10255 case CMDFUNCTION:
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +000010256 /* See above for the rationale */
10257 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +000010258 if (evalfun(cmdentry.u.func, argc, argv, flags))
10259 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010260 readstatus:
10261 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000010262 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +020010263 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +000010264
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010265 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +020010266 if (cmd->ncmd.redirect)
Denys Vlasenko035486c2017-07-31 04:09:19 +020010267 popredir(/*drop:*/ cmd_is_exec);
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020010268 unwindredir(redir_stop);
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010269 unwindfiles(file_stop);
Denys Vlasenko484fc202017-07-26 19:55:31 +020010270 unwindlocalvars(localvar_stop);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010271 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +000010272 /* dsl: I think this is intended to be used to support
10273 * '_' in 'vi' command mode during line editing...
10274 * However I implemented that within libedit itself.
10275 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020010276 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +000010277 }
Eric Andersenc470f442003-07-28 09:56:35 +000010278 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020010279
10280 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000010281}
10282
10283static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010284evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010285{
Eric Andersenc470f442003-07-28 09:56:35 +000010286 char *volatile savecmdname;
10287 struct jmploc *volatile savehandler;
10288 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010289 int status;
Eric Andersenc470f442003-07-28 09:56:35 +000010290 int i;
10291
10292 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +020010293 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010294 i = setjmp(jmploc.loc);
10295 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +000010296 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010297 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +000010298 commandname = argv[0];
10299 argptr = argv + 1;
10300 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010301 if (cmd == EVALCMD)
10302 status = evalcmd(argc, argv, flags);
10303 else
10304 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010305 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020010306 status |= ferror(stdout);
10307 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010308 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +000010309 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000010310 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010311 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010312
10313 return i;
10314}
10315
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010316static int
10317goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010318{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +020010319 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010320}
10321
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010322
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010323/*
10324 * Search for a command. This is called before we fork so that the
10325 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010326 * the child. The check for "goodname" is an overly conservative
10327 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010328 */
Eric Andersenc470f442003-07-28 09:56:35 +000010329static void
10330prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010331{
10332 struct cmdentry entry;
10333
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010334 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
10335 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010336}
10337
Eric Andersencb57d552001-06-28 07:25:16 +000010338
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010339/* ============ Builtin commands
10340 *
10341 * Builtin commands whose functions are closely tied to evaluation
10342 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +000010343 */
10344
10345/*
Eric Andersencb57d552001-06-28 07:25:16 +000010346 * Handle break and continue commands. Break, continue, and return are
10347 * all handled by setting the evalskip flag. The evaluation routines
10348 * above all check this flag, and if it is set they start skipping
10349 * commands rather than executing them. The variable skipcount is
10350 * the number of loops to break/continue, or the number of function
10351 * levels to return. (The latter is always 1.) It should probably
10352 * be an error to break out of more loops than exist, but it isn't
10353 * in the standard shell so we don't make it one here.
10354 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010355static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010356breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010357{
Denis Vlasenko68404f12008-03-17 09:00:54 +000010358 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010359
Aaron Lehmann2aef3a62001-12-31 06:03:12 +000010360 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020010361 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +000010362 if (n > loopnest)
10363 n = loopnest;
10364 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000010365 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +000010366 skipcount = n;
10367 }
10368 return 0;
10369}
10370
Eric Andersenc470f442003-07-28 09:56:35 +000010371
Denys Vlasenko70392332016-10-27 02:31:55 +020010372/*
Eric Andersen90898442003-08-06 11:20:52 +000010373 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +000010374 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010375
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010376enum {
10377 INPUT_PUSH_FILE = 1,
10378 INPUT_NOFILE_OK = 2,
10379};
Eric Andersencb57d552001-06-28 07:25:16 +000010380
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010381static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010382/* values of checkkwd variable */
10383#define CHKALIAS 0x1
10384#define CHKKWD 0x2
10385#define CHKNL 0x4
Denys Vlasenkoa7328982017-07-29 19:57:28 +020010386#define CHKEOFMARK 0x8
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010387
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010388/*
10389 * Push a string back onto the input at this current parsefile level.
10390 * We handle aliases this way.
10391 */
10392#if !ENABLE_ASH_ALIAS
10393#define pushstring(s, ap) pushstring(s)
10394#endif
10395static void
10396pushstring(char *s, struct alias *ap)
10397{
10398 struct strpush *sp;
10399 int len;
10400
10401 len = strlen(s);
10402 INT_OFF;
10403 if (g_parsefile->strpush) {
10404 sp = ckzalloc(sizeof(*sp));
10405 sp->prev = g_parsefile->strpush;
10406 } else {
10407 sp = &(g_parsefile->basestrpush);
10408 }
10409 g_parsefile->strpush = sp;
10410 sp->prev_string = g_parsefile->next_to_pgetc;
10411 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010412 sp->unget = g_parsefile->unget;
10413 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010414#if ENABLE_ASH_ALIAS
10415 sp->ap = ap;
10416 if (ap) {
10417 ap->flag |= ALIASINUSE;
10418 sp->string = s;
10419 }
10420#endif
10421 g_parsefile->next_to_pgetc = s;
10422 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010423 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010424 INT_ON;
10425}
10426
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010427static void
10428popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010429{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010430 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +000010431
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010432 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010433#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010434 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010435 if (g_parsefile->next_to_pgetc[-1] == ' '
10436 || g_parsefile->next_to_pgetc[-1] == '\t'
10437 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010438 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010439 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010440 if (sp->string != sp->ap->val) {
10441 free(sp->string);
10442 }
10443 sp->ap->flag &= ~ALIASINUSE;
10444 if (sp->ap->flag & ALIASDEAD) {
10445 unalias(sp->ap->name);
10446 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +000010447 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010448#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010449 g_parsefile->next_to_pgetc = sp->prev_string;
10450 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010451 g_parsefile->unget = sp->unget;
10452 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010453 g_parsefile->strpush = sp->prev;
10454 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010455 free(sp);
10456 INT_ON;
10457}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010458
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010459static int
10460preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010461{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010462 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +000010463 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010464
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010465 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +000010466#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +000010467 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010468 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +010010469 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +000010470 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010471# if ENABLE_ASH_IDLE_TIMEOUT
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010472 int timeout = -1;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010473 if (iflag) {
10474 const char *tmout_var = lookupvar("TMOUT");
10475 if (tmout_var) {
10476 timeout = atoi(tmout_var) * 1000;
10477 if (timeout <= 0)
10478 timeout = -1;
10479 }
10480 }
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010481 line_input_state->timeout = timeout;
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010482# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010483# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010484 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +010010485# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +020010486 reinit_unicode_for_ash();
Denys Vlasenko84ea60e2017-08-02 17:27:28 +020010487 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010488 if (nr == 0) {
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010489 /* ^C pressed, "convert" to SIGINT */
10490 write(STDOUT_FILENO, "^C", 2);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010491 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010492 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000010493 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010494 raise(SIGINT);
10495 return 1;
10496 }
Denys Vlasenko8660aeb2016-11-24 17:44:02 +010010497 exitstatus = 128 + SIGINT;
Denys Vlasenko4b89d512016-11-25 03:41:03 +010010498 bb_putchar('\n');
Eric Andersenc470f442003-07-28 09:56:35 +000010499 goto retry;
10500 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010501 if (nr < 0) {
10502 if (errno == 0) {
10503 /* Ctrl+D pressed */
10504 nr = 0;
10505 }
10506# if ENABLE_ASH_IDLE_TIMEOUT
10507 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +020010508 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +010010509 exitshell();
10510 }
10511# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010512 }
Eric Andersencb57d552001-06-28 07:25:16 +000010513 }
10514#else
Ron Yorston61d6ae22015-04-19 10:50:25 +010010515 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +000010516#endif
10517
Denys Vlasenko80c5b682011-05-08 21:21:10 +020010518#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +000010519 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010520 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +000010521 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +000010522 if (flags >= 0 && (flags & O_NONBLOCK)) {
10523 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +000010524 if (fcntl(0, F_SETFL, flags) >= 0) {
10525 out2str("sh: turning off NDELAY mode\n");
10526 goto retry;
10527 }
10528 }
10529 }
10530 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +000010531#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010532 return nr;
10533}
10534
10535/*
10536 * Refill the input buffer and return the next input character:
10537 *
10538 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010539 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
10540 * or we are reading from a string so we can't refill the buffer,
10541 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +020010542 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +000010543 * 4) Process input up to the next newline, deleting nul characters.
10544 */
Denis Vlasenko727752d2008-11-28 03:41:47 +000010545//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
10546#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010547static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010548static int
Eric Andersenc470f442003-07-28 09:56:35 +000010549preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010550{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010551 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010552 int more;
Eric Andersencb57d552001-06-28 07:25:16 +000010553
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010554 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000010555#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010556 if (g_parsefile->left_in_line == -1
10557 && g_parsefile->strpush->ap
10558 && g_parsefile->next_to_pgetc[-1] != ' '
10559 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +000010560 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010561 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +000010562 return PEOA;
10563 }
Eric Andersen2870d962001-07-02 17:27:21 +000010564#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010565 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010566 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010567 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010568 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010569 * "pgetc" needs refilling.
10570 */
10571
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010572 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010573 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +000010574 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010575 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010576 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010577 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010578 /* even in failure keep left_in_line and next_to_pgetc
10579 * in lock step, for correct multi-layer pungetc.
10580 * left_in_line was decremented before preadbuffer(),
10581 * must inc next_to_pgetc: */
10582 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010583 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010584 }
Eric Andersencb57d552001-06-28 07:25:16 +000010585
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010586 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010587 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010588 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010589 again:
10590 more = preadfd();
10591 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010592 /* don't try reading again */
10593 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +000010594 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010595 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010596 return PEOF;
10597 }
10598 }
10599
Denis Vlasenko727752d2008-11-28 03:41:47 +000010600 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010601 * Set g_parsefile->left_in_line
10602 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +000010603 * NUL chars are deleted.
10604 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010605 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010606 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010607 char c;
Eric Andersencb57d552001-06-28 07:25:16 +000010608
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010609 more--;
Eric Andersenc470f442003-07-28 09:56:35 +000010610
Denis Vlasenko727752d2008-11-28 03:41:47 +000010611 c = *q;
10612 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010613 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010614 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010615 q++;
10616 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010617 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010618 break;
10619 }
Eric Andersencb57d552001-06-28 07:25:16 +000010620 }
10621
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010622 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010623 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10624 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010625 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010626 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010627 }
10628 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010629 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010630
Eric Andersencb57d552001-06-28 07:25:16 +000010631 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010632 char save = *q;
10633 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010634 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010635 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010636 }
10637
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010638 pgetc_debug("preadbuffer at %d:%p'%s'",
10639 g_parsefile->left_in_line,
10640 g_parsefile->next_to_pgetc,
10641 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010642 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010643}
10644
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010645static void
10646nlprompt(void)
10647{
10648 g_parsefile->linno++;
10649 setprompt_if(doprompt, 2);
10650}
10651static void
10652nlnoprompt(void)
10653{
10654 g_parsefile->linno++;
10655 needprompt = doprompt;
10656}
10657
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010658static int
10659pgetc(void)
10660{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010661 int c;
10662
10663 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010664 g_parsefile->left_in_line,
10665 g_parsefile->next_to_pgetc,
10666 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010667 if (g_parsefile->unget)
10668 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010669
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010670 if (--g_parsefile->left_in_line >= 0)
Denys Vlasenko2fe66b12016-12-12 17:39:12 +010010671 c = (unsigned char)*g_parsefile->next_to_pgetc++;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010672 else
10673 c = preadbuffer();
10674
10675 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10676 g_parsefile->lastc[0] = c;
10677
10678 return c;
10679}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010680
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010681#if ENABLE_ASH_ALIAS
10682static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010683pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010684{
10685 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010686 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010687 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010688 g_parsefile->left_in_line,
10689 g_parsefile->next_to_pgetc,
10690 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010691 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010692 } while (c == PEOA);
10693 return c;
10694}
10695#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010696# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010697#endif
10698
10699/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010700 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010701 * PEOF may be pushed back.
10702 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010703static void
Eric Andersenc470f442003-07-28 09:56:35 +000010704pungetc(void)
10705{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010706 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010707}
10708
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010709/* This one eats backslash+newline */
10710static int
10711pgetc_eatbnl(void)
10712{
10713 int c;
10714
10715 while ((c = pgetc()) == '\\') {
10716 if (pgetc() != '\n') {
10717 pungetc();
10718 break;
10719 }
10720
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010721 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010722 }
10723
10724 return c;
10725}
10726
Denys Vlasenko216913c2018-04-02 12:35:04 +020010727struct synstack {
10728 smalluint syntax;
10729 uint8_t innerdq :1;
10730 uint8_t varpushed :1;
10731 uint8_t dblquote :1;
10732 int varnest; /* levels of variables expansion */
10733 int dqvarnest; /* levels of variables expansion within double quotes */
10734 int parenlevel; /* levels of parens in arithmetic */
10735 struct synstack *prev;
10736 struct synstack *next;
10737};
10738
10739static void
10740synstack_push(struct synstack **stack, struct synstack *next, int syntax)
10741{
10742 memset(next, 0, sizeof(*next));
10743 next->syntax = syntax;
10744 next->next = *stack;
10745 (*stack)->prev = next;
10746 *stack = next;
10747}
10748
10749static ALWAYS_INLINE void
10750synstack_pop(struct synstack **stack)
10751{
10752 *stack = (*stack)->next;
10753}
10754
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010755/*
10756 * To handle the "." command, a stack of input files is used. Pushfile
10757 * adds a new entry to the stack and popfile restores the previous level.
10758 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010759static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010760pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010761{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010762 struct parsefile *pf;
10763
Denis Vlasenko597906c2008-02-20 16:38:54 +000010764 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010765 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010766 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010767 /*pf->strpush = NULL; - ckzalloc did it */
10768 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010769 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010770 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010771}
10772
10773static void
10774popfile(void)
10775{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010776 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010777
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010010778 if (pf == &basepf)
10779 return;
10780
Denis Vlasenkob012b102007-02-19 22:43:01 +000010781 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010782 if (pf->pf_fd >= 0)
10783 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010784 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010785 while (pf->strpush)
10786 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010787 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010788 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010789 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010790}
10791
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010792static void
10793unwindfiles(struct parsefile *stop)
10794{
10795 while (g_parsefile != stop)
10796 popfile();
10797}
10798
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010799/*
10800 * Return to top level.
10801 */
10802static void
10803popallfiles(void)
10804{
Denys Vlasenko1c5eb882018-08-05 17:07:26 +020010805 unwindfiles(&basepf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010806}
10807
10808/*
10809 * Close the file(s) that the shell is reading commands from. Called
10810 * after a fork is done.
10811 */
10812static void
10813closescript(void)
10814{
10815 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010816 if (g_parsefile->pf_fd > 0) {
10817 close(g_parsefile->pf_fd);
10818 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010819 }
10820}
10821
10822/*
10823 * Like setinputfile, but takes an open file descriptor. Call this with
10824 * interrupts off.
10825 */
10826static void
10827setinputfd(int fd, int push)
10828{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010829 if (push) {
10830 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010831 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010832 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010833 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010834 if (g_parsefile->buf == NULL)
10835 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010836 g_parsefile->left_in_buffer = 0;
10837 g_parsefile->left_in_line = 0;
10838 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010839}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010840
Eric Andersenc470f442003-07-28 09:56:35 +000010841/*
10842 * Set the input to take input from a file. If push is set, push the
10843 * old input onto the stack first.
10844 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010845static int
10846setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010847{
10848 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010849
Denis Vlasenkob012b102007-02-19 22:43:01 +000010850 INT_OFF;
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010851 fd = open(fname, O_RDONLY | O_CLOEXEC);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010852 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010853 if (flags & INPUT_NOFILE_OK)
10854 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010855 exitstatus = 127;
Johannes Schindelin20a63b22017-08-22 22:03:17 +020010856 ash_msg_and_raise_perror("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010857 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010858 if (fd < 10)
10859 fd = savefd(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010860 else if (O_CLOEXEC == 0) /* old libc */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010861 close_on_exec_on(fd);
Denys Vlasenko60fb98e2018-03-30 22:15:14 +020010862
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010863 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010864 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010865 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010866 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010867}
10868
Eric Andersencb57d552001-06-28 07:25:16 +000010869/*
10870 * Like setinputfile, but takes input from a string.
10871 */
Eric Andersenc470f442003-07-28 09:56:35 +000010872static void
10873setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010874{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010875 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010876 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010877 g_parsefile->next_to_pgetc = string;
10878 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010879 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010880 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010881 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010882}
10883
10884
Denys Vlasenko70392332016-10-27 02:31:55 +020010885/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010886 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010887 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010888
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010889#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010890
Denys Vlasenko23841622015-10-09 15:52:03 +020010891/* Hash of mtimes of mailboxes */
10892static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010893/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010894static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010895
Eric Andersencb57d552001-06-28 07:25:16 +000010896/*
Eric Andersenc470f442003-07-28 09:56:35 +000010897 * Print appropriate message(s) if mail has arrived.
10898 * If mail_var_path_changed is set,
10899 * then the value of MAIL has mail_var_path_changed,
10900 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010901 */
Eric Andersenc470f442003-07-28 09:56:35 +000010902static void
10903chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010904{
Eric Andersencb57d552001-06-28 07:25:16 +000010905 const char *mpath;
10906 char *p;
10907 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010908 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010909 struct stackmark smark;
10910 struct stat statb;
10911
Eric Andersencb57d552001-06-28 07:25:16 +000010912 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010913 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010914 new_hash = 0;
10915 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010916 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010917 if (p == NULL)
10918 break;
10919 if (*p == '\0')
10920 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010921 for (q = p; *q; q++)
10922 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010923#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010924 if (q[-1] != '/')
10925 abort();
10926#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010927 q[-1] = '\0'; /* delete trailing '/' */
10928 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010929 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010930 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010931 /* Very simplistic "hash": just a sum of all mtimes */
10932 new_hash += (unsigned)statb.st_mtime;
10933 }
10934 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010935 if (mailtime_hash != 0)
10936 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010937 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010938 }
Eric Andersenc470f442003-07-28 09:56:35 +000010939 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010940 popstackmark(&smark);
10941}
Eric Andersencb57d552001-06-28 07:25:16 +000010942
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010943static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010944changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010945{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010946 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010947}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010948
Denis Vlasenko131ae172007-02-18 13:00:19 +000010949#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010950
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010951
10952/* ============ ??? */
10953
Eric Andersencb57d552001-06-28 07:25:16 +000010954/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010955 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010956 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010957static void
10958setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010959{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010960 char **newparam;
10961 char **ap;
10962 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010963
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010964 for (nparam = 0; argv[nparam]; nparam++)
10965 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010966 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10967 while (*argv) {
10968 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010969 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010970 *ap = NULL;
10971 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010972 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010973 shellparam.nparam = nparam;
10974 shellparam.p = newparam;
10975#if ENABLE_ASH_GETOPTS
10976 shellparam.optind = 1;
10977 shellparam.optoff = -1;
10978#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010979}
10980
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010981/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010982 * Process shell options. The global variable argptr contains a pointer
10983 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010984 *
10985 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10986 * For a non-interactive shell, an error condition encountered
10987 * by a special built-in ... shall cause the shell to write a diagnostic message
10988 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010989 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010990 * ...
10991 * Utility syntax error (option or operand error) Shall exit
10992 * ...
10993 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10994 * we see that bash does not do that (set "finishes" with error code 1 instead,
10995 * and shell continues), and people rely on this behavior!
10996 * Testcase:
10997 * set -o barfoo 2>/dev/null
10998 * echo $?
10999 *
11000 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000011001 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011002static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011003plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000011004{
11005 int i;
11006
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011007 if (name) {
11008 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011009 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000011010 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011011 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000011012 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011013 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011014 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011015 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000011016 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000011017 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011018 if (val) {
11019 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
11020 } else {
11021 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
11022 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000011023 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011024 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000011025}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011026static void
11027setoption(int flag, int val)
11028{
11029 int i;
11030
11031 for (i = 0; i < NOPTS; i++) {
11032 if (optletters(i) == flag) {
11033 optlist[i] = val;
11034 return;
11035 }
11036 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011037 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011038 /* NOTREACHED */
11039}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011040static int
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011041options(int cmdline, int *login_sh)
Eric Andersencb57d552001-06-28 07:25:16 +000011042{
11043 char *p;
11044 int val;
11045 int c;
11046
11047 if (cmdline)
11048 minusc = NULL;
11049 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011050 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011051 if (c != '-' && c != '+')
11052 break;
11053 argptr++;
11054 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011055 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000011056 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011057 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000011058 if (!cmdline) {
11059 /* "-" means turn off -x and -v */
11060 if (p[0] == '\0')
11061 xflag = vflag = 0;
11062 /* "--" means reset params */
11063 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000011064 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000011065 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011066 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000011067 }
Eric Andersencb57d552001-06-28 07:25:16 +000011068 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011069 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000011070 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011071 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000011072 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011073 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000011074 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000011075 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011076 /* it already printed err message */
11077 return 1; /* error */
11078 }
Eric Andersencb57d552001-06-28 07:25:16 +000011079 if (*argptr)
11080 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011081 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011082 if (login_sh)
11083 *login_sh = 1;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000011084 /* bash does not accept +-login, we also won't */
11085 } else if (cmdline && val && (c == '-')) { /* long options */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011086 if (strcmp(p, "login") == 0) {
11087 if (login_sh)
11088 *login_sh = 1;
11089 }
Robert Griebl64f70cc2002-05-14 23:22:06 +000011090 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011091 } else {
11092 setoption(c, val);
11093 }
11094 }
11095 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011096 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011097}
11098
Eric Andersencb57d552001-06-28 07:25:16 +000011099/*
Eric Andersencb57d552001-06-28 07:25:16 +000011100 * The shift builtin command.
11101 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011102static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011103shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011104{
11105 int n;
11106 char **ap1, **ap2;
11107
11108 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000011109 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011110 n = number(argv[1]);
11111 if (n > shellparam.nparam)
Ingo van Lil9c8e94b2018-01-05 15:04:23 +010011112 return 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011113 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000011114 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011115 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000011116 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000011117 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000011118 }
11119 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011120 while ((*ap2++ = *ap1++) != NULL)
11121 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000011122#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011123 shellparam.optind = 1;
11124 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000011125#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000011126 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000011127 return 0;
11128}
11129
Eric Andersencb57d552001-06-28 07:25:16 +000011130/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011131 * POSIX requires that 'set' (but not export or readonly) output the
11132 * variables in lexicographic order - by the locale's collating order (sigh).
11133 * Maybe we could keep them in an ordered balanced binary tree
11134 * instead of hashed lists.
11135 * For now just roll 'em through qsort for printing...
11136 */
11137static int
11138showvars(const char *sep_prefix, int on, int off)
11139{
11140 const char *sep;
11141 char **ep, **epend;
11142
Denys Vlasenkoa5060b82017-11-03 14:16:25 +010011143 ep = listvars(on, off, /*strlist:*/ NULL, &epend);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011144 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11145
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000011146 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011147
11148 for (; ep < epend; ep++) {
11149 const char *p;
11150 const char *q;
11151
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011152 p = endofname(*ep);
11153/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this
11154 * makes "export -p" to have output not suitable for "eval":
11155 * import os
11156 * os.environ["test-test"]="test"
11157 * if os.fork() == 0:
11158 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
11159 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ])
11160 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011161 q = nullstr;
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010011162 if (*p == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011163 q = single_quote(++p);
11164 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11165 }
11166 return 0;
11167}
11168
11169/*
Eric Andersencb57d552001-06-28 07:25:16 +000011170 * The set command builtin.
11171 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011172static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011173setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000011174{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011175 int retval;
11176
Denis Vlasenko68404f12008-03-17 09:00:54 +000011177 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000011178 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011179
Denis Vlasenkob012b102007-02-19 22:43:01 +000011180 INT_OFF;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020011181 retval = options(/*cmdline:*/ 0, NULL);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010011182 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011183 optschanged();
11184 if (*argptr != NULL) {
11185 setparam(argptr);
11186 }
Eric Andersencb57d552001-06-28 07:25:16 +000011187 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011188 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000011189 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000011190}
11191
Denis Vlasenko131ae172007-02-18 13:00:19 +000011192#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011193static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000011194change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000011195{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011196 uint32_t t;
11197
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011198 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000011199 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011200 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000011201 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020011202 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000011203 vrandom.flags &= ~VNOFUNC;
11204 } else {
11205 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020011206 t = strtoul(value, NULL, 10);
11207 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000011208 }
Eric Andersenef02f822004-03-11 13:34:24 +000011209}
Eric Andersen16767e22004-03-16 05:14:10 +000011210#endif
11211
Denis Vlasenko131ae172007-02-18 13:00:19 +000011212#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011213static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011214getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000011215{
11216 char *p, *q;
11217 char c = '?';
11218 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020011219 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000011220 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011221 int ind = shellparam.optind;
11222 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000011223
Denys Vlasenko9c541002015-10-07 15:44:36 +020011224 sbuf[1] = '\0';
11225
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011226 shellparam.optind = -1;
11227 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000011228
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011229 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000011230 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011231 else
11232 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000011233 if (p == NULL || *p == '\0') {
11234 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000011235 p = *optnext;
11236 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011237 atend:
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011238 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011239 p = NULL;
11240 done = 1;
11241 goto out;
11242 }
11243 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000011244 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000011245 goto atend;
11246 }
11247
11248 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000011249 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000011250 if (*q == '\0') {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011251 /* OPTERR is a bashism */
11252 const char *cp = lookupvar("OPTERR");
11253 if ((cp && LONE_CHAR(cp, '0'))
11254 || (optstr[0] == ':')
11255 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011256 sbuf[0] = c;
11257 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011258 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011259 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011260 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011261 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011262 }
11263 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000011264 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011265 }
11266 if (*++q == ':')
11267 q++;
11268 }
11269
11270 if (*++q == ':') {
11271 if (*p == '\0' && (p = *optnext) == NULL) {
Denys Vlasenko9832bba2017-08-15 15:44:41 +020011272 /* OPTERR is a bashism */
11273 const char *cp = lookupvar("OPTERR");
11274 if ((cp && LONE_CHAR(cp, '0'))
11275 || (optstr[0] == ':')
11276 ) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020011277 sbuf[0] = c;
11278 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011279 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000011280 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011281 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011282 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011283 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000011284 c = '?';
11285 }
Eric Andersenc470f442003-07-28 09:56:35 +000011286 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011287 }
11288
11289 if (p == *optnext)
11290 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011291 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000011292 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011293 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011294 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011295 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011296 ind = optnext - optfirst + 1;
11297 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020011298 sbuf[0] = c;
11299 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011300 setvar0(optvar, sbuf);
11301
11302 shellparam.optoff = p ? p - *(optnext - 1) : -1;
11303 shellparam.optind = ind;
11304
Eric Andersencb57d552001-06-28 07:25:16 +000011305 return done;
11306}
Eric Andersenc470f442003-07-28 09:56:35 +000011307
11308/*
11309 * The getopts builtin. Shellparam.optnext points to the next argument
11310 * to be processed. Shellparam.optptr points to the next character to
11311 * be processed in the current argument. If shellparam.optnext is NULL,
11312 * then it's the first time getopts has been called.
11313 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020011314static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000011315getoptscmd(int argc, char **argv)
11316{
11317 char **optbase;
11318
11319 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000011320 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011321 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000011322 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011323 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000011324 shellparam.optind = 1;
11325 shellparam.optoff = -1;
11326 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011327 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011328 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020011329 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000011330 shellparam.optind = 1;
11331 shellparam.optoff = -1;
11332 }
11333 }
11334
Denys Vlasenko35c2a132016-10-26 17:34:26 +020011335 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000011336}
Denis Vlasenko131ae172007-02-18 13:00:19 +000011337#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000011338
Eric Andersencb57d552001-06-28 07:25:16 +000011339
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011340/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000011341
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011342struct heredoc {
11343 struct heredoc *next; /* next here document in list */
11344 union node *here; /* redirection node */
11345 char *eofmark; /* string indicating end of input */
11346 smallint striptabs; /* if set, strip leading tabs */
11347};
11348
11349static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000011350static smallint quoteflag; /* set if (part of) last token was quoted */
11351static token_id_t lasttoken; /* last token read (integer id Txxx) */
11352static struct heredoc *heredoclist; /* list of here documents to read */
11353static char *wordtext; /* text of last word returned by readtoken */
11354static struct nodelist *backquotelist;
11355static union node *redirnode;
11356static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011357
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011358static const char *
11359tokname(char *buf, int tok)
11360{
11361 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020011362 return tokname_array[tok];
11363 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011364 return buf;
11365}
11366
11367/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011368 * Called when an unexpected token is read during the parse. The argument
11369 * is the token that is expected, or -1 if more than one type of token can
11370 * occur at this point.
11371 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000011372static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011373static void
11374raise_error_unexpected_syntax(int token)
11375{
11376 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011377 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011378 int l;
11379
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011380 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011381 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011382 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011383 raise_error_syntax(msg);
11384 /* NOTREACHED */
11385}
Eric Andersencb57d552001-06-28 07:25:16 +000011386
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011387/* parsing is heavily cross-recursive, need these forward decls */
11388static union node *andor(void);
11389static union node *pipeline(void);
11390static union node *parse_command(void);
11391static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000011392static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011393static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000011394
Eric Andersenc470f442003-07-28 09:56:35 +000011395static union node *
11396list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000011397{
11398 union node *n1, *n2, *n3;
11399 int tok;
11400
Eric Andersencb57d552001-06-28 07:25:16 +000011401 n1 = NULL;
11402 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011403 switch (peektoken()) {
11404 case TNL:
11405 if (!(nlflag & 1))
11406 break;
11407 parseheredoc();
11408 return n1;
11409
11410 case TEOF:
11411 if (!n1 && (nlflag & 1))
11412 n1 = NODE_EOF;
11413 parseheredoc();
11414 return n1;
11415 }
11416
11417 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020011418 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000011419 return n1;
11420 nlflag |= 2;
11421
Eric Andersencb57d552001-06-28 07:25:16 +000011422 n2 = andor();
11423 tok = readtoken();
11424 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000011425 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011426 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011427 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011428 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011429 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000011430 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011431 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011432 n2 = n3;
11433 }
11434 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000011435 }
11436 }
11437 if (n1 == NULL) {
11438 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011439 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011440 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011441 n3->type = NSEMI;
11442 n3->nbinary.ch1 = n1;
11443 n3->nbinary.ch2 = n2;
11444 n1 = n3;
11445 }
11446 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000011447 case TNL:
11448 case TEOF:
11449 tokpushback = 1;
11450 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000011451 case TBACKGND:
11452 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000011453 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011454 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000011455 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011456 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011457 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011458 return n1;
11459 }
11460 }
11461}
11462
Eric Andersenc470f442003-07-28 09:56:35 +000011463static union node *
11464andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011465{
Eric Andersencb57d552001-06-28 07:25:16 +000011466 union node *n1, *n2, *n3;
11467 int t;
11468
Eric Andersencb57d552001-06-28 07:25:16 +000011469 n1 = pipeline();
11470 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011471 t = readtoken();
11472 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000011473 t = NAND;
11474 } else if (t == TOR) {
11475 t = NOR;
11476 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011477 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011478 return n1;
11479 }
Eric Andersenc470f442003-07-28 09:56:35 +000011480 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011481 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011482 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000011483 n3->type = t;
11484 n3->nbinary.ch1 = n1;
11485 n3->nbinary.ch2 = n2;
11486 n1 = n3;
11487 }
11488}
11489
Eric Andersenc470f442003-07-28 09:56:35 +000011490static union node *
11491pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011492{
Eric Andersencb57d552001-06-28 07:25:16 +000011493 union node *n1, *n2, *pipenode;
11494 struct nodelist *lp, *prev;
11495 int negate;
11496
11497 negate = 0;
11498 TRACE(("pipeline: entered\n"));
11499 if (readtoken() == TNOT) {
11500 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000011501 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011502 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011503 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011504 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011505 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011506 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000011507 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011508 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011509 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000011510 pipenode->npipe.cmdlist = lp;
11511 lp->n = n1;
11512 do {
11513 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011514 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000011515 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011516 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000011517 prev->next = lp;
11518 } while (readtoken() == TPIPE);
11519 lp->next = NULL;
11520 n1 = pipenode;
11521 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011522 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011523 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011524 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000011525 n2->type = NNOT;
11526 n2->nnot.com = n1;
11527 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011528 }
11529 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000011530}
11531
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011532static union node *
11533makename(void)
11534{
11535 union node *n;
11536
Denis Vlasenko597906c2008-02-20 16:38:54 +000011537 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011538 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011539 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011540 n->narg.text = wordtext;
11541 n->narg.backquote = backquotelist;
11542 return n;
11543}
11544
11545static void
11546fixredir(union node *n, const char *text, int err)
11547{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011548 int fd;
11549
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011550 TRACE(("Fix redir %s %d\n", text, err));
11551 if (!err)
11552 n->ndup.vname = NULL;
11553
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011554 fd = bb_strtou(text, NULL, 10);
11555 if (!errno && fd >= 0)
11556 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011557 else if (LONE_DASH(text))
11558 n->ndup.dupfd = -1;
11559 else {
11560 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011561 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011562 n->ndup.vname = makename();
11563 }
11564}
11565
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011566static void
11567parsefname(void)
11568{
11569 union node *n = redirnode;
11570
Denys Vlasenkoa7328982017-07-29 19:57:28 +020011571 if (n->type == NHERE)
11572 checkkwd = CHKEOFMARK;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011573 if (readtoken() != TWORD)
11574 raise_error_unexpected_syntax(-1);
11575 if (n->type == NHERE) {
11576 struct heredoc *here = heredoc;
11577 struct heredoc *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011578
11579 if (quoteflag == 0)
11580 n->type = NXHERE;
11581 TRACE(("Here document %d\n", n->type));
Denys Vlasenko740058b2018-01-09 17:01:00 +010011582 rmescapes(wordtext, 0, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011583 here->eofmark = wordtext;
11584 here->next = NULL;
11585 if (heredoclist == NULL)
11586 heredoclist = here;
11587 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011588 for (p = heredoclist; p->next; p = p->next)
11589 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011590 p->next = here;
11591 }
11592 } else if (n->type == NTOFD || n->type == NFROMFD) {
11593 fixredir(n, wordtext, 0);
11594 } else {
11595 n->nfile.fname = makename();
11596 }
11597}
Eric Andersencb57d552001-06-28 07:25:16 +000011598
Eric Andersenc470f442003-07-28 09:56:35 +000011599static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011600simplecmd(void)
11601{
11602 union node *args, **app;
11603 union node *n = NULL;
11604 union node *vars, **vpp;
11605 union node **rpp, *redir;
11606 int savecheckkwd;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011607 int savelinno;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011608#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011609 smallint double_brackets_flag = 0;
11610#endif
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011611 IF_BASH_FUNCTION(smallint function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011612
11613 args = NULL;
11614 app = &args;
11615 vars = NULL;
11616 vpp = &vars;
11617 redir = NULL;
11618 rpp = &redir;
11619
11620 savecheckkwd = CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011621 savelinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011622 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011623 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011624 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011625 t = readtoken();
11626 switch (t) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011627#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011628 case TFUNCTION:
11629 if (peektoken() != TWORD)
11630 raise_error_unexpected_syntax(TWORD);
11631 function_flag = 1;
11632 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011633#endif
11634#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011635 case TAND: /* "&&" */
11636 case TOR: /* "||" */
11637 if (!double_brackets_flag) {
11638 tokpushback = 1;
11639 goto out;
11640 }
11641 wordtext = (char *) (t == TAND ? "-a" : "-o");
11642#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011643 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011644 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011645 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011646 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011647 n->narg.text = wordtext;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011648#if BASH_TEST2
Denis Vlasenko80591b02008-03-25 07:49:43 +000011649 if (strcmp("[[", wordtext) == 0)
11650 double_brackets_flag = 1;
11651 else if (strcmp("]]", wordtext) == 0)
11652 double_brackets_flag = 0;
11653#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011654 n->narg.backquote = backquotelist;
11655 if (savecheckkwd && isassignment(wordtext)) {
11656 *vpp = n;
11657 vpp = &n->narg.next;
11658 } else {
11659 *app = n;
11660 app = &n->narg.next;
11661 savecheckkwd = 0;
11662 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011663#if BASH_FUNCTION
Ron Yorston95ebcf72015-11-03 09:42:23 +000011664 if (function_flag) {
11665 checkkwd = CHKNL | CHKKWD;
11666 switch (peektoken()) {
11667 case TBEGIN:
11668 case TIF:
11669 case TCASE:
11670 case TUNTIL:
11671 case TWHILE:
11672 case TFOR:
11673 goto do_func;
11674 case TLP:
11675 function_flag = 0;
11676 break;
Denys Vlasenkoe93031e2018-04-10 01:23:19 +020011677# if BASH_TEST2
Ron Yorston95ebcf72015-11-03 09:42:23 +000011678 case TWORD:
11679 if (strcmp("[[", wordtext) == 0)
11680 goto do_func;
11681 /* fall through */
Denys Vlasenkoe93031e2018-04-10 01:23:19 +020011682# endif
Ron Yorston95ebcf72015-11-03 09:42:23 +000011683 default:
11684 raise_error_unexpected_syntax(-1);
11685 }
11686 }
11687#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011688 break;
11689 case TREDIR:
11690 *rpp = n = redirnode;
11691 rpp = &n->nfile.next;
11692 parsefname(); /* read name of redirection file */
11693 break;
11694 case TLP:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011695 IF_BASH_FUNCTION(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011696 if (args && app == &args->narg.next
11697 && !vars && !redir
11698 ) {
11699 struct builtincmd *bcmd;
11700 const char *name;
11701
11702 /* We have a function */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011703 if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011704 raise_error_unexpected_syntax(TRP);
11705 name = n->narg.text;
11706 if (!goodname(name)
11707 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11708 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011709 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011710 }
11711 n->type = NDEFUN;
11712 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011713 n->ndefun.text = n->narg.text;
11714 n->ndefun.linno = g_parsefile->linno;
11715 n->ndefun.body = parse_command();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011716 return n;
11717 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011718 IF_BASH_FUNCTION(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011719 /* fall through */
11720 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011721 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011722 goto out;
11723 }
11724 }
11725 out:
11726 *app = NULL;
11727 *vpp = NULL;
11728 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011729 n = stzalloc(sizeof(struct ncmd));
Denys Vlasenko57b7efb2018-04-10 01:20:26 +020011730 if (NCMD != 0)
11731 n->type = NCMD;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011732 n->ncmd.linno = savelinno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011733 n->ncmd.args = args;
11734 n->ncmd.assign = vars;
11735 n->ncmd.redirect = redir;
11736 return n;
11737}
11738
11739static union node *
11740parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011741{
Eric Andersencb57d552001-06-28 07:25:16 +000011742 union node *n1, *n2;
11743 union node *ap, **app;
11744 union node *cp, **cpp;
11745 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011746 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011747 int t;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011748 int savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011749
11750 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011751 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011752
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011753 savelinno = g_parsefile->linno;
11754
Eric Andersencb57d552001-06-28 07:25:16 +000011755 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011756 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011757 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011758 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011759 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011760 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011761 n1->type = NIF;
11762 n1->nif.test = list(0);
11763 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011764 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011765 n1->nif.ifpart = list(0);
11766 n2 = n1;
11767 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011768 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011769 n2 = n2->nif.elsepart;
11770 n2->type = NIF;
11771 n2->nif.test = list(0);
11772 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011773 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011774 n2->nif.ifpart = list(0);
11775 }
11776 if (lasttoken == TELSE)
11777 n2->nif.elsepart = list(0);
11778 else {
11779 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011780 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011781 }
Eric Andersenc470f442003-07-28 09:56:35 +000011782 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011783 break;
11784 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011785 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011786 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011787 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011788 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011789 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011790 got = readtoken();
11791 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011792 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011793 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011794 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011795 }
11796 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011797 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011798 break;
11799 }
11800 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011801 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011802 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011803 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011804 n1->type = NFOR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011805 n1->nfor.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011806 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011807 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011808 if (readtoken() == TIN) {
11809 app = &ap;
11810 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011811 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011812 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011813 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011814 n2->narg.text = wordtext;
11815 n2->narg.backquote = backquotelist;
11816 *app = n2;
11817 app = &n2->narg.next;
11818 }
11819 *app = NULL;
11820 n1->nfor.args = ap;
11821 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011822 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011823 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011824 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011825 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011826 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011827 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011828 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011829 n1->nfor.args = n2;
11830 /*
11831 * Newline or semicolon here is optional (but note
11832 * that the original Bourne shell only allowed NL).
11833 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011834 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011835 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011836 }
Eric Andersenc470f442003-07-28 09:56:35 +000011837 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011838 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011839 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011840 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011841 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011842 break;
11843 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011844 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011845 n1->type = NCASE;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011846 n1->ncase.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011847 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011848 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011849 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011850 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011851 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011852 n2->narg.text = wordtext;
11853 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011854 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11855 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011856 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011857 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011858 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011859 checkkwd = CHKNL | CHKKWD;
11860 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011861 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011862 if (lasttoken == TLP)
11863 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011864 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011865 cp->type = NCLIST;
11866 app = &cp->nclist.pattern;
11867 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011868 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011869 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011870 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011871 ap->narg.text = wordtext;
11872 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011873 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011874 break;
11875 app = &ap->narg.next;
11876 readtoken();
11877 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011878 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011879 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011880 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011881 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011882
Eric Andersenc470f442003-07-28 09:56:35 +000011883 cpp = &cp->nclist.next;
11884
11885 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011886 t = readtoken();
11887 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011888 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011889 raise_error_unexpected_syntax(TENDCASE);
11890 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011891 }
Eric Andersenc470f442003-07-28 09:56:35 +000011892 }
Eric Andersencb57d552001-06-28 07:25:16 +000011893 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011894 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011895 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011896 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011897 n1->type = NSUBSHELL;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011898 n1->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011899 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011900 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011901 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011902 break;
11903 case TBEGIN:
11904 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011905 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011906 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011907 IF_BASH_FUNCTION(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011908 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011909 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011910 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011911 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011912 }
11913
Eric Andersenc470f442003-07-28 09:56:35 +000011914 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011915 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011916
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011917 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011918 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011919 checkkwd = CHKKWD | CHKALIAS;
11920 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011921 while (readtoken() == TREDIR) {
11922 *rpp = n2 = redirnode;
11923 rpp = &n2->nfile.next;
11924 parsefname();
11925 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011926 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011927 *rpp = NULL;
11928 if (redir) {
11929 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011930 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011931 n2->type = NREDIR;
Denys Vlasenko675d24a2018-01-27 22:02:05 +010011932 n2->nredir.linno = savelinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011933 n2->nredir.n = n1;
11934 n1 = n2;
11935 }
11936 n1->nredir.redirect = redir;
11937 }
Eric Andersencb57d552001-06-28 07:25:16 +000011938 return n1;
11939}
11940
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010011941#if BASH_DOLLAR_SQUOTE
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011942static int
11943decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011944{
11945 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11946 int c, cnt;
11947 char *p;
11948 char buf[4];
11949
11950 c = pgetc();
11951 p = strchr(C_escapes, c);
11952 if (p) {
11953 buf[0] = c;
11954 p = buf;
11955 cnt = 3;
11956 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11957 do {
11958 c = pgetc();
11959 *++p = c;
11960 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11961 pungetc();
11962 } else if (c == 'x') { /* \xHH */
11963 do {
11964 c = pgetc();
11965 *++p = c;
11966 } while (isxdigit(c) && --cnt);
11967 pungetc();
11968 if (cnt == 3) { /* \x but next char is "bad" */
11969 c = 'x';
11970 goto unrecognized;
11971 }
11972 } else { /* simple seq like \\ or \t */
11973 p++;
11974 }
11975 *p = '\0';
11976 p = buf;
11977 c = bb_process_escape_sequence((void*)&p);
11978 } else { /* unrecognized "\z": print both chars unless ' or " */
11979 if (c != '\'' && c != '"') {
11980 unrecognized:
11981 c |= 0x100; /* "please encode \, then me" */
11982 }
11983 }
11984 return c;
11985}
11986#endif
11987
Denys Vlasenko46999802017-07-29 21:12:29 +020011988/* Used by expandstr to get here-doc like behaviour. */
11989#define FAKEEOFMARK ((char*)(uintptr_t)1)
11990
11991static ALWAYS_INLINE int
11992realeofmark(const char *eofmark)
11993{
11994 return eofmark && eofmark != FAKEEOFMARK;
11995}
11996
Eric Andersencb57d552001-06-28 07:25:16 +000011997/*
11998 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11999 * is not NULL, read a here document. In the latter case, eofmark is the
12000 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010012001 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000012002 * is the first character of the input token or document.
12003 *
12004 * Because C does not have internal subroutines, I have simulated them
12005 * using goto's to implement the subroutine linkage. The following macros
12006 * will run code that appears at the end of readtoken1.
12007 */
Eric Andersen2870d962001-07-02 17:27:21 +000012008#define CHECKEND() {goto checkend; checkend_return:;}
12009#define PARSEREDIR() {goto parseredir; parseredir_return:;}
12010#define PARSESUB() {goto parsesub; parsesub_return:;}
12011#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
12012#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
12013#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000012014static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010012015readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000012016{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012017 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010012018 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000012019 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020012020 size_t len;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012021 struct nodelist *bqlist;
12022 smallint quotef;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012023 smallint oldstyle;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012024 smallint pssyntax; /* we are expanding a prompt string */
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012025 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012026 /* syntax stack */
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020012027 struct synstack synbase = { };
Denys Vlasenko216913c2018-04-02 12:35:04 +020012028 struct synstack *synstack = &synbase;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012029
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012030#if ENABLE_ASH_EXPAND_PRMT
Denis Vlasenko46a53062007-09-24 18:30:02 +000012031 pssyntax = (syntax == PSSYNTAX);
12032 if (pssyntax)
12033 syntax = DQSYNTAX;
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012034#else
12035 pssyntax = 0; /* constant */
12036#endif
Denys Vlasenkoee1fd122018-04-04 13:59:53 +020012037 synstack->syntax = syntax;
12038
Denys Vlasenko216913c2018-04-02 12:35:04 +020012039 if (syntax == DQSYNTAX)
12040 synstack->dblquote = 1;
12041 quotef = 0;
12042 bqlist = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000012043
12044 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012045 loop:
12046 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012047 CHECKEND(); /* set c to PEOF if at end of here document */
12048 for (;;) { /* until end of line or end of word */
12049 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012050 switch (SIT(c, synstack->syntax)) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012051 case CNL: /* '\n' */
Denys Vlasenko680c3012018-04-11 12:39:18 +020012052 if (synstack->syntax == BASESYNTAX
12053 && !synstack->varnest
12054 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012055 goto endword; /* exit outer loop */
Denys Vlasenko680c3012018-04-11 12:39:18 +020012056 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012057 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012058 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012059 c = pgetc();
12060 goto loop; /* continue outer loop */
12061 case CWORD:
12062 USTPUTC(c, out);
12063 break;
12064 case CCTL:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012065#if BASH_DOLLAR_SQUOTE
Denys Vlasenko958581a2010-09-12 15:04:27 +020012066 if (c == '\\' && bash_dollar_squote) {
12067 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020012068 if (c == '\0') {
12069 /* skip $'\000', $'\x00' (like bash) */
12070 break;
12071 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012072 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020012073 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012074 c = (unsigned char)c;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012075 if (eofmark == NULL || synstack->dblquote)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012076 USTPUTC(CTLESC, out);
12077 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012078 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012079 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012080#endif
Denys Vlasenkoc4c20122018-04-02 13:29:20 +020012081 if (!eofmark || synstack->dblquote || synstack->varnest)
Denys Vlasenko13f20912016-09-25 20:54:25 +020012082 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012083 USTPUTC(c, out);
12084 break;
12085 case CBACK: /* backslash */
12086 c = pgetc_without_PEOA();
12087 if (c == PEOF) {
12088 USTPUTC(CTLESC, out);
12089 USTPUTC('\\', out);
12090 pungetc();
12091 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012092 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012093 } else {
Denys Vlasenko5f0a75f2017-07-29 22:58:44 +020012094 if (pssyntax && c == '$') {
Eric Andersenc470f442003-07-28 09:56:35 +000012095 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012096 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012097 }
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012098 /* Backslash is retained if we are in "str"
12099 * and next char isn't dquote-special.
12100 */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012101 if (synstack->dblquote
Denys Vlasenko958581a2010-09-12 15:04:27 +020012102 && c != '\\'
12103 && c != '`'
12104 && c != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012105 && (c != '"' || (eofmark != NULL && !synstack->varnest))
12106 && (c != '}' || !synstack->varnest)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012107 ) {
Denys Vlasenko8de5b9f2018-02-13 14:43:29 +010012108 USTPUTC(CTLESC, out); /* protect '\' from glob */
Denys Vlasenko958581a2010-09-12 15:04:27 +020012109 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012110 }
Ron Yorston549deab2015-05-18 09:57:51 +020012111 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020012112 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012113 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012114 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012115 break;
12116 case CSQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012117 synstack->syntax = SQSYNTAX;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012118 quotemark:
12119 if (eofmark == NULL) {
12120 USTPUTC(CTLQUOTEMARK, out);
12121 }
12122 break;
12123 case CDQUOTE:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012124 synstack->syntax = DQSYNTAX;
12125 synstack->dblquote = 1;
12126 toggledq:
12127 if (synstack->varnest)
12128 synstack->innerdq ^= 1;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012129 goto quotemark;
12130 case CENDQUOTE:
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012131 IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012132 if (eofmark != NULL && synstack->varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012133 USTPUTC(c, out);
Denys Vlasenko216913c2018-04-02 12:35:04 +020012134 break;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012135 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012136
12137 if (synstack->dqvarnest == 0) {
12138 synstack->syntax = BASESYNTAX;
12139 synstack->dblquote = 0;
12140 }
12141
12142 quotef = 1;
12143
12144 if (c == '"')
12145 goto toggledq;
12146
12147 goto quotemark;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012148 case CVAR: /* '$' */
12149 PARSESUB(); /* parse substitution */
12150 break;
12151 case CENDVAR: /* '}' */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012152 if (!synstack->innerdq && synstack->varnest > 0) {
12153 if (!--synstack->varnest && synstack->varpushed)
12154 synstack_pop(&synstack);
12155 else if (synstack->dqvarnest > 0)
12156 synstack->dqvarnest--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012157 c = CTLENDVAR;
12158 }
12159 USTPUTC(c, out);
12160 break;
Denys Vlasenko0b883582016-12-23 16:49:07 +010012161#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko958581a2010-09-12 15:04:27 +020012162 case CLP: /* '(' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012163 synstack->parenlevel++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012164 USTPUTC(c, out);
12165 break;
12166 case CRP: /* ')' in arithmetic */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012167 if (synstack->parenlevel > 0) {
12168 synstack->parenlevel--;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012169 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012170 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020012171 c = CTLENDARI;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012172 synstack_pop(&synstack);
Denys Vlasenko958581a2010-09-12 15:04:27 +020012173 } else {
12174 /*
12175 * unbalanced parens
12176 * (don't 2nd guess - no error)
12177 */
12178 pungetc();
12179 }
12180 }
12181 USTPUTC(c, out);
12182 break;
12183#endif
12184 case CBQUOTE: /* '`' */
Denys Vlasenko41fddb42018-04-01 16:38:32 +020012185 if (checkkwd & CHKEOFMARK) {
12186 quotef = 1;
12187 USTPUTC('`', out);
12188 break;
12189 }
12190
Denys Vlasenko958581a2010-09-12 15:04:27 +020012191 PARSEBACKQOLD();
12192 break;
12193 case CENDFILE:
12194 goto endword; /* exit outer loop */
12195 case CIGN:
12196 break;
12197 default:
Denys Vlasenko216913c2018-04-02 12:35:04 +020012198 if (synstack->varnest == 0) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012199#if BASH_REDIR_OUTPUT
Denys Vlasenko958581a2010-09-12 15:04:27 +020012200 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020012201//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020012202 if (pgetc() == '>')
12203 c = 0x100 + '>'; /* flag &> */
12204 pungetc();
12205 }
12206#endif
12207 goto endword; /* exit outer loop */
12208 }
12209 IF_ASH_ALIAS(if (c != PEOA))
12210 USTPUTC(c, out);
12211 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012212 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020012213 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012214 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020012215
Denys Vlasenko0b883582016-12-23 16:49:07 +010012216#if ENABLE_FEATURE_SH_MATH
Denys Vlasenko216913c2018-04-02 12:35:04 +020012217 if (synstack->syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012218 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000012219#endif
Denys Vlasenko216913c2018-04-02 12:35:04 +020012220 if (synstack->syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000012221 raise_error_syntax("unterminated quoted string");
Denys Vlasenko216913c2018-04-02 12:35:04 +020012222 if (synstack->varnest != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012223 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000012224 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000012225 }
12226 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012227 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000012228 out = stackblock();
12229 if (eofmark == NULL) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012230 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000012231 && quotef == 0
12232 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000012233 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012234 PARSEREDIR(); /* passed as params: out, c */
12235 lasttoken = TREDIR;
12236 return lasttoken;
12237 }
12238 /* else: non-number X seen, interpret it
12239 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000012240 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012241 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012242 }
12243 quoteflag = quotef;
12244 backquotelist = bqlist;
12245 grabstackblock(len);
12246 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012247 lasttoken = TWORD;
12248 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012249/* end of readtoken routine */
12250
Eric Andersencb57d552001-06-28 07:25:16 +000012251/*
12252 * Check to see whether we are at the end of the here document. When this
12253 * is called, c is set to the first character of the next input line. If
12254 * we are at the end of the here document, this routine sets the c to PEOF.
12255 */
Eric Andersenc470f442003-07-28 09:56:35 +000012256checkend: {
Denys Vlasenko46999802017-07-29 21:12:29 +020012257 if (realeofmark(eofmark)) {
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012258 int markloc;
12259 char *p;
12260
Denis Vlasenko131ae172007-02-18 13:00:19 +000012261#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012262 if (c == PEOA)
12263 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000012264#endif
12265 if (striptabs) {
12266 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012267 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000012268 }
Eric Andersenc470f442003-07-28 09:56:35 +000012269 }
Eric Andersencb57d552001-06-28 07:25:16 +000012270
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012271 markloc = out - (char *)stackblock();
12272 for (p = eofmark; STPUTC(c, out), *p; p++) {
12273 if (c != *p)
12274 goto more_heredoc;
12275
12276 c = pgetc_without_PEOA();
12277 }
12278
12279 if (c == '\n' || c == PEOF) {
12280 c = PEOF;
12281 g_parsefile->linno++;
12282 needprompt = doprompt;
12283 } else {
12284 int len_here;
12285
12286 more_heredoc:
12287 p = (char *)stackblock() + markloc + 1;
12288 len_here = out - p;
12289
12290 if (len_here) {
12291 len_here -= (c >= PEOF);
12292 c = p[-1];
12293
12294 if (len_here) {
12295 char *str;
12296
12297 str = alloca(len_here + 1);
12298 *(char *)mempcpy(str, p, len_here) = '\0';
12299
12300 pushstring(str, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012301 }
12302 }
12303 }
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012304
12305 STADJUST((char *)stackblock() + markloc - out, out);
Eric Andersencb57d552001-06-28 07:25:16 +000012306 }
Eric Andersenc470f442003-07-28 09:56:35 +000012307 goto checkend_return;
12308}
Eric Andersencb57d552001-06-28 07:25:16 +000012309
Eric Andersencb57d552001-06-28 07:25:16 +000012310/*
12311 * Parse a redirection operator. The variable "out" points to a string
12312 * specifying the fd to be redirected. The variable "c" contains the
12313 * first character of the redirection operator.
12314 */
Eric Andersenc470f442003-07-28 09:56:35 +000012315parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012316 /* out is already checked to be a valid number or "" */
12317 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000012318 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000012319
Denis Vlasenko597906c2008-02-20 16:38:54 +000012320 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000012321 if (c == '>') {
12322 np->nfile.fd = 1;
Denys Vlasenko220be532018-03-31 19:21:31 +020012323 c = pgetc_eatbnl();
Eric Andersenc470f442003-07-28 09:56:35 +000012324 if (c == '>')
12325 np->type = NAPPEND;
12326 else if (c == '|')
12327 np->type = NCLOBBER;
12328 else if (c == '&')
12329 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000012330 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000012331 else {
12332 np->type = NTO;
12333 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000012334 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000012335 }
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012336#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012337 else if (c == 0x100 + '>') { /* this flags &> redirection */
12338 np->nfile.fd = 1;
12339 pgetc(); /* this is '>', no need to check */
12340 np->type = NTO2;
12341 }
12342#endif
12343 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000012344 /*np->nfile.fd = 0; - stzalloc did it */
Denys Vlasenko220be532018-03-31 19:21:31 +020012345 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012346 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000012347 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000012348 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000012349 np = stzalloc(sizeof(struct nhere));
12350 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012351 }
12352 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012353 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000012354 heredoc->here = np;
Denys Vlasenko220be532018-03-31 19:21:31 +020012355 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012356 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000012357 heredoc->striptabs = 1;
12358 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012359 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012360 pungetc();
12361 }
12362 break;
12363
12364 case '&':
12365 np->type = NFROMFD;
12366 break;
12367
12368 case '>':
12369 np->type = NFROMTO;
12370 break;
12371
12372 default:
12373 np->type = NFROM;
12374 pungetc();
12375 break;
12376 }
Eric Andersencb57d552001-06-28 07:25:16 +000012377 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000012378 if (fd >= 0)
12379 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000012380 redirnode = np;
12381 goto parseredir_return;
12382}
Eric Andersencb57d552001-06-28 07:25:16 +000012383
Eric Andersencb57d552001-06-28 07:25:16 +000012384/*
12385 * Parse a substitution. At this point, we have read the dollar sign
12386 * and nothing else.
12387 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012388
12389/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
12390 * (assuming ascii char codes, as the original implementation did) */
12391#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012392 (((unsigned)(c) - 33 < 32) \
12393 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000012394parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010012395 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012396 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000012397
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012398 c = pgetc_eatbnl();
Denys Vlasenkoa7328982017-07-29 19:57:28 +020012399 if ((checkkwd & CHKEOFMARK)
12400 || c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012401 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000012402 ) {
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012403#if BASH_DOLLAR_SQUOTE
Denys Vlasenko216913c2018-04-02 12:35:04 +020012404 if (synstack->syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000012405 bash_dollar_squote = 1;
12406 else
12407#endif
12408 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000012409 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012410 } else if (c == '(') {
12411 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012412 if (pgetc_eatbnl() == '(') {
Denys Vlasenko0b883582016-12-23 16:49:07 +010012413#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000012414 PARSEARITH();
12415#else
Denys Vlasenko4f8079d2017-07-17 17:11:48 +020012416 raise_error_syntax("support for $((arith)) is disabled");
Eric Andersenc470f442003-07-28 09:56:35 +000012417#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012418 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012419 pungetc();
12420 PARSEBACKQNEW();
12421 }
12422 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012423 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012424 smalluint newsyn = synstack->syntax;
12425
Eric Andersenc470f442003-07-28 09:56:35 +000012426 USTPUTC(CTLVAR, out);
12427 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012428 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012429 subtype = VSNORMAL;
12430 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012431 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012432 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012433 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012434 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020012435 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012436 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012437 do {
12438 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012439 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020012440 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012441 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012442 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000012443 do {
12444 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012445 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012446 } while (isdigit(c));
Denys Vlasenko58eb8052018-08-05 15:58:13 +020012447 } else if (c != '}') {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012448 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012449 int cc = c;
12450
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012451 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012452 if (!subtype && cc == '#') {
12453 subtype = VSLENGTH;
12454 if (c == '_' || isalnum(c))
12455 goto varname;
12456 cc = c;
12457 c = pgetc_eatbnl();
12458 if (cc == '}' || c != '}') {
12459 pungetc();
12460 subtype = 0;
12461 c = cc;
12462 cc = '#';
12463 }
12464 }
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012465
12466 if (!is_special(cc)) {
12467 if (subtype == VSLENGTH)
12468 subtype = 0;
12469 goto badsub;
12470 }
12471
Denys Vlasenkof15aa572016-10-26 15:56:53 +020012472 USTPUTC(cc, out);
Denys Vlasenko58eb8052018-08-05 15:58:13 +020012473 } else
12474 goto badsub;
Denys Vlasenko452cc1d2017-08-14 14:23:45 +020012475
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012476 if (c != '}' && subtype == VSLENGTH) {
12477 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020012478 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012479 }
Eric Andersencb57d552001-06-28 07:25:16 +000012480
Eric Andersenc470f442003-07-28 09:56:35 +000012481 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012482 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012483 /* ${VAR...} but not $VAR or ${#VAR} */
12484 /* c == first char after VAR */
Denys Vlasenko216913c2018-04-02 12:35:04 +020012485 int cc = c;
12486
Eric Andersenc470f442003-07-28 09:56:35 +000012487 switch (c) {
12488 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012489 c = pgetc_eatbnl();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012490#if BASH_SUBSTR
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020012491 /* This check is only needed to not misinterpret
12492 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
12493 * constructs.
12494 */
12495 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012496 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012497 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020012498 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012499 }
12500#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020012501 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000012502 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012503 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012504 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000012505 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020012506 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020012507 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000012508 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012509 }
Eric Andersenc470f442003-07-28 09:56:35 +000012510 case '%':
Denys Vlasenko216913c2018-04-02 12:35:04 +020012511 case '#':
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012512 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012513 c = pgetc_eatbnl();
Denys Vlasenko216913c2018-04-02 12:35:04 +020012514 if (c == cc)
12515 subtype++;
12516 else
12517 pungetc();
12518
12519 newsyn = BASESYNTAX;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012520 break;
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012521#if BASH_PATTERN_SUBST
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012522 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020012523 /* ${v/[/]pattern/repl} */
12524//TODO: encode pattern and repl separately.
Denys Vlasenko216913c2018-04-02 12:35:04 +020012525// Currently cases like: v=1;echo ${v/$((1/1))/ONE}
12526// are broken (should print "ONE")
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012527 subtype = VSREPLACE;
Denys Vlasenko216913c2018-04-02 12:35:04 +020012528 newsyn = BASESYNTAX;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020012529 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012530 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020012531 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020012532 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000012533 break;
12534#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012535 }
Eric Andersenc470f442003-07-28 09:56:35 +000012536 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020012537 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000012538 pungetc();
12539 }
Denys Vlasenko216913c2018-04-02 12:35:04 +020012540
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012541 if (newsyn == ARISYNTAX)
Denys Vlasenko216913c2018-04-02 12:35:04 +020012542 newsyn = DQSYNTAX;
12543
Denys Vlasenkof50e1462018-04-02 21:00:59 +020012544 if ((newsyn != synstack->syntax || synstack->innerdq)
12545 && subtype != VSNORMAL
12546 ) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012547 synstack_push(&synstack,
12548 synstack->prev ?: alloca(sizeof(*synstack)),
12549 newsyn);
12550
12551 synstack->varpushed = 1;
12552 synstack->dblquote = newsyn != BASESYNTAX;
12553 }
12554
Denys Vlasenko3df14102016-10-26 16:41:13 +020012555 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000012556 if (subtype != VSNORMAL) {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012557 synstack->varnest++;
12558 if (synstack->dblquote)
12559 synstack->dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000012560 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020012561 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000012562 }
Eric Andersenc470f442003-07-28 09:56:35 +000012563 goto parsesub_return;
12564}
Eric Andersencb57d552001-06-28 07:25:16 +000012565
Eric Andersencb57d552001-06-28 07:25:16 +000012566/*
12567 * Called to parse command substitutions. Newstyle is set if the command
12568 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
12569 * list of commands (passed by reference), and savelen is the number of
12570 * characters on the top of the stack which must be preserved.
12571 */
Eric Andersenc470f442003-07-28 09:56:35 +000012572parsebackq: {
12573 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012574 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010012575 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000012576 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012577 smallint saveprompt = 0;
12578
Eric Andersenc470f442003-07-28 09:56:35 +000012579 str = NULL;
12580 savelen = out - (char *)stackblock();
12581 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012582 /*
12583 * FIXME: this can allocate very large block on stack and SEGV.
12584 * Example:
12585 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020012586 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012587 * a hundred command substitutions stack overflows.
12588 * With larger prepended string, SEGV happens sooner.
12589 */
Ron Yorston072fc602015-07-01 16:46:18 +010012590 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000012591 memcpy(str, stackblock(), savelen);
12592 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020012593
Eric Andersenc470f442003-07-28 09:56:35 +000012594 if (oldstyle) {
12595 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010012596 * treatment to some slashes, and then push the string and
12597 * reread it as input, interpreting it normally.
12598 */
Eric Andersenc470f442003-07-28 09:56:35 +000012599 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000012600 size_t psavelen;
12601 char *pstr;
12602
Eric Andersenc470f442003-07-28 09:56:35 +000012603 STARTSTACKSTR(pout);
12604 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012605 int pc;
12606
12607 setprompt_if(needprompt, 2);
Denys Vlasenko220be532018-03-31 19:21:31 +020012608 pc = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012609 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000012610 case '`':
12611 goto done;
12612
12613 case '\\':
Denys Vlasenko220be532018-03-31 19:21:31 +020012614 pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
Eric Andersenc470f442003-07-28 09:56:35 +000012615 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko216913c2018-04-02 12:35:04 +020012616 && (!synstack->dblquote || pc != '"')
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012617 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000012618 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010012619 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010012620 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000012621 break;
12622 }
12623 /* fall through */
12624
12625 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012626 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012627 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000012628
12629 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012630 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000012631 break;
12632
12633 default:
12634 break;
12635 }
12636 STPUTC(pc, pout);
12637 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012638 done:
Eric Andersenc470f442003-07-28 09:56:35 +000012639 STPUTC('\0', pout);
12640 psavelen = pout - (char *)stackblock();
12641 if (psavelen > 0) {
12642 pstr = grabstackstr(pout);
12643 setinputstring(pstr);
12644 }
12645 }
12646 nlpp = &bqlist;
12647 while (*nlpp)
12648 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012649 *nlpp = stzalloc(sizeof(**nlpp));
12650 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000012651
12652 if (oldstyle) {
12653 saveprompt = doprompt;
12654 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012655 }
12656
Eric Andersenc470f442003-07-28 09:56:35 +000012657 n = list(2);
12658
12659 if (oldstyle)
12660 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012661 else if (readtoken() != TRP)
12662 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000012663
12664 (*nlpp)->n = n;
12665 if (oldstyle) {
12666 /*
12667 * Start reading from old file again, ignoring any pushed back
12668 * tokens left from the backquote parsing
12669 */
12670 popfile();
12671 tokpushback = 0;
12672 }
12673 while (stackblocksize() <= savelen)
12674 growstackblock();
12675 STARTSTACKSTR(out);
12676 if (str) {
12677 memcpy(out, str, savelen);
12678 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012679 }
Ron Yorston549deab2015-05-18 09:57:51 +020012680 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012681 if (oldstyle)
12682 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012683 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000012684}
12685
Denys Vlasenko0b883582016-12-23 16:49:07 +010012686#if ENABLE_FEATURE_SH_MATH
Eric Andersencb57d552001-06-28 07:25:16 +000012687/*
12688 * Parse an arithmetic expansion (indicate start of one and set state)
12689 */
Eric Andersenc470f442003-07-28 09:56:35 +000012690parsearith: {
Denys Vlasenko216913c2018-04-02 12:35:04 +020012691
12692 synstack_push(&synstack,
12693 synstack->prev ?: alloca(sizeof(*synstack)),
12694 ARISYNTAX);
12695 synstack->dblquote = 1;
Ron Yorstonad88bde2015-05-18 09:56:16 +020012696 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012697 goto parsearith_return;
12698}
12699#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012700} /* end of readtoken */
12701
Eric Andersencb57d552001-06-28 07:25:16 +000012702/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012703 * Read the next input token.
12704 * If the token is a word, we set backquotelist to the list of cmds in
12705 * backquotes. We set quoteflag to true if any part of the word was
12706 * quoted.
12707 * If the token is TREDIR, then we set redirnode to a structure containing
12708 * the redirection.
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012709 *
12710 * [Change comment: here documents and internal procedures]
12711 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12712 * word parsing code into a separate routine. In this case, readtoken
12713 * doesn't need to have any internal procedures, but parseword does.
12714 * We could also make parseoperator in essence the main routine, and
12715 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012716 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012717#define NEW_xxreadtoken
12718#ifdef NEW_xxreadtoken
12719/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012720static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012721 '\n', '(', ')', /* singles */
12722 '&', '|', ';', /* doubles */
12723 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012724};
Eric Andersencb57d552001-06-28 07:25:16 +000012725
Denis Vlasenko834dee72008-10-07 09:18:30 +000012726#define xxreadtoken_singles 3
12727#define xxreadtoken_doubles 3
12728
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012729static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012730 TNL, TLP, TRP, /* only single occurrence allowed */
12731 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12732 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012733 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012734};
12735
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012736static int
12737xxreadtoken(void)
12738{
12739 int c;
12740
12741 if (tokpushback) {
12742 tokpushback = 0;
12743 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012744 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012745 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012746 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012747 c = pgetc_eatbnl();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012748 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012749 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012750
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012751 if (c == '#') {
12752 while ((c = pgetc()) != '\n' && c != PEOF)
12753 continue;
12754 pungetc();
12755 } else if (c == '\\') {
Denys Vlasenko220be532018-03-31 19:21:31 +020012756 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012757 } else {
12758 const char *p;
12759
12760 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12761 if (c != PEOF) {
12762 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012763 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012764 }
12765
12766 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012767 if (p == NULL)
12768 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012769
Denis Vlasenko834dee72008-10-07 09:18:30 +000012770 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
Denys Vlasenko1e5111b2018-04-01 03:04:55 +020012771 int cc = pgetc_eatbnl();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012772 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012773 p += xxreadtoken_doubles + 1;
12774 } else {
12775 pungetc();
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010012776#if BASH_REDIR_OUTPUT
Denis Vlasenko834dee72008-10-07 09:18:30 +000012777 if (c == '&' && cc == '>') /* &> */
12778 break; /* return readtoken1(...) */
12779#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012780 }
12781 }
12782 }
12783 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12784 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012785 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012786 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012787
12788 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012789}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012790#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012791#define RETURN(token) return lasttoken = token
12792static int
12793xxreadtoken(void)
12794{
12795 int c;
12796
12797 if (tokpushback) {
12798 tokpushback = 0;
12799 return lasttoken;
12800 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012801 setprompt_if(needprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012802 for (;;) { /* until token or start of word found */
Denys Vlasenko220be532018-03-31 19:21:31 +020012803 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012804 switch (c) {
12805 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012806 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012807 continue;
12808 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012809 while ((c = pgetc()) != '\n' && c != PEOF)
12810 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012811 pungetc();
12812 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012813 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012814 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012815 RETURN(TNL);
12816 case PEOF:
12817 RETURN(TEOF);
12818 case '&':
Denys Vlasenko220be532018-03-31 19:21:31 +020012819 if (pgetc_eatbnl() == '&')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012820 RETURN(TAND);
12821 pungetc();
12822 RETURN(TBACKGND);
12823 case '|':
Denys Vlasenko220be532018-03-31 19:21:31 +020012824 if (pgetc_eatbnl() == '|')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012825 RETURN(TOR);
12826 pungetc();
12827 RETURN(TPIPE);
12828 case ';':
Denys Vlasenko220be532018-03-31 19:21:31 +020012829 if (pgetc_eatbnl() == ';')
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012830 RETURN(TENDCASE);
12831 pungetc();
12832 RETURN(TSEMI);
12833 case '(':
12834 RETURN(TLP);
12835 case ')':
12836 RETURN(TRP);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012837 }
Denys Vlasenko220be532018-03-31 19:21:31 +020012838 break;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012839 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012840 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12841#undef RETURN
12842}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012843#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012844
12845static int
12846readtoken(void)
12847{
12848 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012849 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012850#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012851 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012852#endif
12853
12854#if ENABLE_ASH_ALIAS
12855 top:
12856#endif
12857
12858 t = xxreadtoken();
12859
12860 /*
12861 * eat newlines
12862 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012863 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012864 while (t == TNL) {
12865 parseheredoc();
12866 t = xxreadtoken();
12867 }
12868 }
12869
12870 if (t != TWORD || quoteflag) {
12871 goto out;
12872 }
12873
12874 /*
12875 * check for keywords
12876 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012877 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012878 const char *const *pp;
12879
12880 pp = findkwd(wordtext);
12881 if (pp) {
12882 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012883 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012884 goto out;
12885 }
12886 }
12887
12888 if (checkkwd & CHKALIAS) {
12889#if ENABLE_ASH_ALIAS
12890 struct alias *ap;
12891 ap = lookupalias(wordtext, 1);
12892 if (ap != NULL) {
12893 if (*ap->val) {
12894 pushstring(ap->val, ap);
12895 }
12896 goto top;
12897 }
12898#endif
12899 }
12900 out:
12901 checkkwd = 0;
12902#if DEBUG
12903 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012904 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012905 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012906 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012907#endif
12908 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012909}
12910
Ron Yorstonc0e00762015-10-29 11:30:55 +000012911static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012912peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012913{
12914 int t;
12915
12916 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012917 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012918 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012919}
Eric Andersencb57d552001-06-28 07:25:16 +000012920
12921/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012922 * Read and parse a command. Returns NODE_EOF on end of file.
12923 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012924 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012925static union node *
12926parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012927{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012928 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012929 checkkwd = 0;
12930 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012931 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012932 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012933 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012934 return list(1);
12935}
12936
12937/*
12938 * Input any here documents.
12939 */
12940static void
12941parseheredoc(void)
12942{
12943 struct heredoc *here;
12944 union node *n;
12945
12946 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012947 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012948
12949 while (here) {
Christoph Schulz03ad7ae2018-11-20 17:45:52 +010012950 tokpushback = 0;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012951 setprompt_if(needprompt, 2);
12952 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012953 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012954 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012955 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012956 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012957 n->narg.text = wordtext;
12958 n->narg.backquote = backquotelist;
12959 here->here->nhere.doc = n;
12960 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012961 }
Eric Andersencb57d552001-06-28 07:25:16 +000012962}
12963
12964
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012965static const char *
Denys Vlasenko46999802017-07-29 21:12:29 +020012966expandstr(const char *ps, int syntax_type)
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012967{
12968 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012969 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012970
Denys Vlasenko46999802017-07-29 21:12:29 +020012971 /* XXX Fix (char *) cast. */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012972 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012973
12974 saveprompt = doprompt;
12975 doprompt = 0;
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012976
12977 /* readtoken1() might die horribly.
Denys Vlasenko3c183a82017-10-12 19:35:42 +020012978 * Try a prompt with syntactically wrong command:
Denys Vlasenkoa2e32b32017-10-12 19:20:13 +020012979 * PS1='$(date "+%H:%M:%S) > '
12980 */
12981 {
12982 volatile int saveint;
12983 struct jmploc *volatile savehandler = exception_handler;
12984 struct jmploc jmploc;
12985 SAVE_INT(saveint);
12986 if (setjmp(jmploc.loc) == 0) {
12987 exception_handler = &jmploc;
12988 readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0);
12989 }
12990 exception_handler = savehandler;
12991 RESTORE_INT(saveint);
12992 }
12993
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012994 doprompt = saveprompt;
12995
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012996 popfile();
12997
12998 n.narg.type = NARG;
12999 n.narg.next = NULL;
13000 n.narg.text = wordtext;
13001 n.narg.backquote = backquotelist;
13002
Ron Yorston549deab2015-05-18 09:57:51 +020013003 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013004 return stackblock();
13005}
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013006
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013007static inline int
13008parser_eof(void)
13009{
13010 return tokpushback && lasttoken == TEOF;
13011}
13012
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013013/*
13014 * Execute a command or commands contained in a string.
13015 */
13016static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013017evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000013018{
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010013019 struct jmploc *volatile savehandler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013020 struct jmploc jmploc;
13021 int ex;
13022
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013023 union node *n;
13024 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013025 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013026
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013027 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013028 setinputstring(s);
13029 setstackmark(&smark);
13030
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013031 status = 0;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013032 /* On exception inside execution loop, we must popfile().
13033 * Try interactively:
13034 * readonly a=a
13035 * command eval "a=b" # throws "is read only" error
13036 * "command BLTIN" is not supposed to abort (even in non-interactive use).
13037 * But if we skip popfile(), we hit EOF in eval's string, and exit.
13038 */
13039 savehandler = exception_handler;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013040 ex = setjmp(jmploc.loc);
13041 if (ex)
13042 goto out;
Denys Vlasenko493b9ca2016-10-30 18:27:14 +010013043 exception_handler = &jmploc;
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013044
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013045 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013046 int i;
13047
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020013048 i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013049 if (n)
13050 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013051 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013052 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013053 break;
13054 }
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013055 out:
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013056 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013057 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020013058 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013059
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013060 exception_handler = savehandler;
13061 if (ex)
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013062 longjmp(exception_handler->loc, ex);
Denys Vlasenkod81e9f52016-10-28 15:43:50 +020013063
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013064 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000013065}
13066
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013067/*
13068 * The eval command.
13069 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013070static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013071evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013072{
13073 char *p;
13074 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013075
Denis Vlasenko68404f12008-03-17 09:00:54 +000013076 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013077 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013078 argv += 2;
13079 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013080 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013081 for (;;) {
13082 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013083 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013084 if (p == NULL)
13085 break;
13086 STPUTC(' ', concat);
13087 }
13088 STPUTC('\0', concat);
13089 p = grabstackstr(concat);
13090 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013091 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013092 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020013093 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013094}
13095
13096/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010013097 * Read and execute commands.
13098 * "Top" is nonzero for the top level command loop;
13099 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013100 */
13101static int
13102cmdloop(int top)
13103{
13104 union node *n;
13105 struct stackmark smark;
13106 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013107 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013108 int numeof = 0;
13109
13110 TRACE(("cmdloop(%d) called\n", top));
13111 for (;;) {
13112 int skip;
13113
13114 setstackmark(&smark);
13115#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000013116 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020013117 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013118#endif
13119 inter = 0;
13120 if (iflag && top) {
13121 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013122 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013123 }
13124 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020013125#if DEBUG
13126 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020013127 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000013128#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020013129 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013130 if (!top || numeof >= 50)
13131 break;
13132 if (!stoppedjobs()) {
13133 if (!Iflag)
13134 break;
13135 out2str("\nUse \"exit\" to leave shell.\n");
13136 }
13137 numeof++;
13138 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013139 int i;
13140
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000013141 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
13142 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013143 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013144 i = evaltree(n, 0);
13145 if (n)
13146 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013147 }
13148 popstackmark(&smark);
13149 skip = evalskip;
13150
13151 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020013152 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013153 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013154 }
13155 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020013156 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013157}
13158
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013159/*
13160 * Take commands from a file. To be compatible we should do a path
13161 * search for the file, which is necessary to find sub-commands.
13162 */
13163static char *
13164find_dot_file(char *name)
13165{
13166 char *fullname;
13167 const char *path = pathval();
13168 struct stat statb;
13169
13170 /* don't try this for absolute or relative paths */
13171 if (strchr(name, '/'))
13172 return name;
13173
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013174 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013175 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
13176 /*
13177 * Don't bother freeing here, since it will
13178 * be freed by the caller.
13179 */
13180 return fullname;
13181 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013182 if (fullname != name)
13183 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013184 }
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013185 /* not found in PATH */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013186
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013187#if ENABLE_ASH_BASH_SOURCE_CURDIR
13188 return name;
13189#else
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013190 ash_msg_and_raise_error("%s: not found", name);
13191 /* NOTREACHED */
Denys Vlasenko01f7b9e2018-01-26 15:15:43 +010013192#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000013193}
13194
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013195static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013196dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013197{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013198 /* "false; . empty_file; echo $?" should print 0, not 1: */
13199 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013200 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013201 char **argv;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013202 char *args_need_save;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013203 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013204
Denys Vlasenko981a0562017-07-26 19:53:11 +020013205//???
13206// struct strlist *sp;
13207// for (sp = cmdenviron; sp; sp = sp->next)
13208// setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013209
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013210 nextopt(nullstr); /* handle possible "--" */
13211 argv = argptr;
13212
13213 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013214 /* bash says: "bash: .: filename argument required" */
13215 return 2; /* bash compat */
13216 }
13217
Denys Vlasenko091f8312013-03-17 14:25:22 +010013218 /* This aborts if file isn't found, which is POSIXly correct.
13219 * bash returns exitcode 1 instead.
13220 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013221 fullname = find_dot_file(argv[0]);
13222 argv++;
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013223 args_need_save = argv[0];
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010013224 if (args_need_save) { /* ". FILE ARGS", and ARGS are not empty */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013225 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013226 saveparam = shellparam;
13227 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013228 argc = 1;
13229 while (argv[argc])
13230 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013231 shellparam.nparam = argc;
13232 shellparam.p = argv;
13233 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013234
Denys Vlasenko091f8312013-03-17 14:25:22 +010013235 /* This aborts if file can't be opened, which is POSIXly correct.
13236 * bash returns exitcode 1 instead.
13237 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013238 setinputfile(fullname, INPUT_PUSH_FILE);
13239 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013240 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013241 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013242
Denys Vlasenkofb87d932017-01-09 08:22:06 +010013243 if (args_need_save) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020013244 freeparam(&shellparam);
13245 shellparam = saveparam;
13246 };
13247
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020013248 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013249}
13250
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013251static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013252exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013253{
13254 if (stoppedjobs())
13255 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000013256 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013257 exitstatus = number(argv[1]);
13258 raise_exception(EXEXIT);
13259 /* NOTREACHED */
13260}
13261
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013262/*
13263 * Read a file containing shell functions.
13264 */
13265static void
13266readcmdfile(char *name)
13267{
13268 setinputfile(name, INPUT_PUSH_FILE);
13269 cmdloop(0);
13270 popfile();
13271}
13272
13273
Denis Vlasenkocc571512007-02-23 21:10:35 +000013274/* ============ find_command inplementation */
13275
13276/*
13277 * Resolve a command name. If you change this routine, you may have to
13278 * change the shellexec routine as well.
13279 */
13280static void
13281find_command(char *name, struct cmdentry *entry, int act, const char *path)
13282{
13283 struct tblentry *cmdp;
13284 int idx;
13285 int prev;
13286 char *fullname;
13287 struct stat statb;
13288 int e;
13289 int updatetbl;
13290 struct builtincmd *bcmd;
13291
13292 /* If name contains a slash, don't use PATH or hash table */
13293 if (strchr(name, '/') != NULL) {
13294 entry->u.index = -1;
13295 if (act & DO_ABS) {
13296 while (stat(name, &statb) < 0) {
13297#ifdef SYSV
13298 if (errno == EINTR)
13299 continue;
13300#endif
13301 entry->cmdtype = CMDUNKNOWN;
13302 return;
13303 }
13304 }
13305 entry->cmdtype = CMDNORMAL;
13306 return;
13307 }
13308
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013309/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013310
13311 updatetbl = (path == pathval());
13312 if (!updatetbl) {
13313 act |= DO_ALTPATH;
13314 if (strstr(path, "%builtin") != NULL)
13315 act |= DO_ALTBLTIN;
13316 }
13317
13318 /* If name is in the table, check answer will be ok */
13319 cmdp = cmdlookup(name, 0);
13320 if (cmdp != NULL) {
13321 int bit;
13322
13323 switch (cmdp->cmdtype) {
13324 default:
13325#if DEBUG
13326 abort();
13327#endif
13328 case CMDNORMAL:
13329 bit = DO_ALTPATH;
13330 break;
13331 case CMDFUNCTION:
13332 bit = DO_NOFUNC;
13333 break;
13334 case CMDBUILTIN:
13335 bit = DO_ALTBLTIN;
13336 break;
13337 }
13338 if (act & bit) {
13339 updatetbl = 0;
13340 cmdp = NULL;
13341 } else if (cmdp->rehash == 0)
13342 /* if not invalidated by cd, we're done */
13343 goto success;
13344 }
13345
13346 /* If %builtin not in path, check for builtin next */
13347 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013348 if (bcmd) {
13349 if (IS_BUILTIN_REGULAR(bcmd))
13350 goto builtin_success;
13351 if (act & DO_ALTPATH) {
13352 if (!(act & DO_ALTBLTIN))
13353 goto builtin_success;
13354 } else if (builtinloc <= 0) {
13355 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000013356 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000013357 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013358
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013359#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000013360 {
13361 int applet_no = find_applet_by_name(name);
13362 if (applet_no >= 0) {
13363 entry->cmdtype = CMDNORMAL;
13364 entry->u.index = -2 - applet_no;
13365 return;
13366 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000013367 }
13368#endif
13369
Denis Vlasenkocc571512007-02-23 21:10:35 +000013370 /* We have to search path. */
13371 prev = -1; /* where to start */
13372 if (cmdp && cmdp->rehash) { /* doing a rehash */
13373 if (cmdp->cmdtype == CMDBUILTIN)
13374 prev = builtinloc;
13375 else
13376 prev = cmdp->param.index;
13377 }
13378
13379 e = ENOENT;
13380 idx = -1;
13381 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020013382 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000013383 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013384 /* NB: code below will still use fullname
13385 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013386 idx++;
13387 if (pathopt) {
13388 if (prefix(pathopt, "builtin")) {
13389 if (bcmd)
13390 goto builtin_success;
13391 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000013392 }
13393 if ((act & DO_NOFUNC)
13394 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020013395 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013396 continue;
13397 }
13398 }
13399 /* if rehash, don't redo absolute path names */
13400 if (fullname[0] == '/' && idx <= prev) {
13401 if (idx < prev)
13402 continue;
13403 TRACE(("searchexec \"%s\": no change\n", name));
13404 goto success;
13405 }
13406 while (stat(fullname, &statb) < 0) {
13407#ifdef SYSV
13408 if (errno == EINTR)
13409 continue;
13410#endif
13411 if (errno != ENOENT && errno != ENOTDIR)
13412 e = errno;
13413 goto loop;
13414 }
13415 e = EACCES; /* if we fail, this will be the error */
13416 if (!S_ISREG(statb.st_mode))
13417 continue;
13418 if (pathopt) { /* this is a %func directory */
13419 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000013420 /* NB: stalloc will return space pointed by fullname
13421 * (because we don't have any intervening allocations
13422 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000013423 readcmdfile(fullname);
13424 cmdp = cmdlookup(name, 0);
13425 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
13426 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
13427 stunalloc(fullname);
13428 goto success;
13429 }
13430 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13431 if (!updatetbl) {
13432 entry->cmdtype = CMDNORMAL;
13433 entry->u.index = idx;
13434 return;
13435 }
13436 INT_OFF;
13437 cmdp = cmdlookup(name, 1);
13438 cmdp->cmdtype = CMDNORMAL;
13439 cmdp->param.index = idx;
13440 INT_ON;
13441 goto success;
13442 }
13443
13444 /* We failed. If there was an entry for this command, delete it */
13445 if (cmdp && updatetbl)
13446 delete_cmd_entry();
William Pitcockd8fd88a2018-01-24 18:33:18 +010013447 if (act & DO_ERR) {
13448#if ENABLE_ASH_BASH_NOT_FOUND_HOOK
13449 struct tblentry *hookp = cmdlookup("command_not_found_handle", 0);
13450 if (hookp && hookp->cmdtype == CMDFUNCTION) {
13451 char *argv[3];
13452 argv[0] = (char*) "command_not_found_handle";
13453 argv[1] = name;
13454 argv[2] = NULL;
13455 evalfun(hookp->param.func, 2, argv, 0);
13456 entry->cmdtype = CMDUNKNOWN;
13457 return;
13458 }
13459#endif
Denis Vlasenkocc571512007-02-23 21:10:35 +000013460 ash_msg("%s: %s", name, errmsg(e, "not found"));
William Pitcockd8fd88a2018-01-24 18:33:18 +010013461 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000013462 entry->cmdtype = CMDUNKNOWN;
13463 return;
13464
13465 builtin_success:
13466 if (!updatetbl) {
13467 entry->cmdtype = CMDBUILTIN;
13468 entry->u.cmd = bcmd;
13469 return;
13470 }
13471 INT_OFF;
13472 cmdp = cmdlookup(name, 1);
13473 cmdp->cmdtype = CMDBUILTIN;
13474 cmdp->param.cmd = bcmd;
13475 INT_ON;
13476 success:
13477 cmdp->rehash = 0;
13478 entry->cmdtype = cmdp->cmdtype;
13479 entry->u = cmdp->param;
13480}
13481
13482
Eric Andersencb57d552001-06-28 07:25:16 +000013483/*
Eric Andersencb57d552001-06-28 07:25:16 +000013484 * The trap builtin.
13485 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013486static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013487trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013488{
13489 char *action;
13490 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013491 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013492
Eric Andersenc470f442003-07-28 09:56:35 +000013493 nextopt(nullstr);
13494 ap = argptr;
13495 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013496 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013497 char *tr = trap_ptr[signo];
13498 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013499 /* note: bash adds "SIG", but only if invoked
13500 * as "bash". If called as "sh", or if set -o posix,
13501 * then it prints short signal names.
13502 * We are printing short names: */
13503 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013504 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013505 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013506 /* trap_ptr != trap only if we are in special-cased `trap` code.
13507 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020013508 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013509 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000013510 }
13511 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013512 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013513 if (trap_ptr != trap) {
13514 free(trap_ptr);
13515 trap_ptr = trap;
13516 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020013517 */
Eric Andersencb57d552001-06-28 07:25:16 +000013518 return 0;
13519 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020013520
Denys Vlasenko86981e32017-07-25 20:06:17 +020013521 /* Why the second check?
13522 * "trap NUM [sig2]..." is the same as "trap - NUM [sig2]..."
13523 * In this case, NUM is signal no, not an action.
13524 */
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000013525 action = NULL;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013526 if (ap[1] && !is_number(ap[0]))
Eric Andersencb57d552001-06-28 07:25:16 +000013527 action = *ap++;
Denys Vlasenko86981e32017-07-25 20:06:17 +020013528
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013529 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013530 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000013531 signo = get_signum(*ap);
Denys Vlasenko86981e32017-07-25 20:06:17 +020013532 if (signo < 0) {
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013533 /* Mimic bash message exactly */
13534 ash_msg("%s: invalid signal specification", *ap);
13535 exitcode = 1;
13536 goto next;
13537 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000013538 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000013539 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000013540 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000013541 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013542 else {
13543 if (action[0]) /* not NULL and not "" and not "-" */
13544 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013545 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020013546 }
Eric Andersencb57d552001-06-28 07:25:16 +000013547 }
Denis Vlasenko60818682007-09-28 22:07:23 +000013548 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000013549 trap[signo] = action;
13550 if (signo != 0)
13551 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013552 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013553 next:
Eric Andersencb57d552001-06-28 07:25:16 +000013554 ap++;
13555 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010013556 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000013557}
13558
Eric Andersenc470f442003-07-28 09:56:35 +000013559
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013560/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000013561
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013562#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013563static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013564helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013565{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000013566 unsigned col;
13567 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000013568
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020013569 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000013570 "Built-in commands:\n"
13571 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000013572 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013573 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000013574 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013575 if (col > 60) {
13576 out1fmt("\n");
13577 col = 0;
13578 }
13579 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013580# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000013581 {
13582 const char *a = applet_names;
13583 while (*a) {
13584 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
13585 if (col > 60) {
13586 out1fmt("\n");
13587 col = 0;
13588 }
Ron Yorston2b919582016-04-08 11:57:20 +010013589 while (*a++ != '\0')
13590 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013591 }
13592 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013593# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020013594 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000013595 return EXIT_SUCCESS;
13596}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020013597#endif
Eric Andersenc470f442003-07-28 09:56:35 +000013598
Flemming Madsend96ffda2013-04-07 18:47:24 +020013599#if MAX_HISTORY
13600static int FAST_FUNC
13601historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13602{
13603 show_history(line_input_state);
13604 return EXIT_SUCCESS;
13605}
13606#endif
13607
Eric Andersencb57d552001-06-28 07:25:16 +000013608/*
Eric Andersencb57d552001-06-28 07:25:16 +000013609 * The export and readonly commands.
13610 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013611static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013612exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000013613{
13614 struct var *vp;
13615 char *name;
13616 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000013617 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020013618 char opt;
13619 int flag;
13620 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000013621
Denys Vlasenkod5275882012-10-01 13:41:17 +020013622 /* "readonly" in bash accepts, but ignores -n.
13623 * We do the same: it saves a conditional in nextopt's param.
13624 */
13625 flag_off = 0;
13626 while ((opt = nextopt("np")) != '\0') {
13627 if (opt == 'n')
13628 flag_off = VEXPORT;
13629 }
13630 flag = VEXPORT;
13631 if (argv[0][0] == 'r') {
13632 flag = VREADONLY;
13633 flag_off = 0; /* readonly ignores -n */
13634 }
13635 flag_off = ~flag_off;
13636
Denys Vlasenko10ad6222017-04-17 16:13:32 +020013637 /*if (opt_p_not_specified) - bash doesn't check this. Try "export -p NAME" */
Denys Vlasenkod5275882012-10-01 13:41:17 +020013638 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013639 aptr = argptr;
13640 name = *aptr;
13641 if (name) {
13642 do {
13643 p = strchr(name, '=');
13644 if (p != NULL) {
13645 p++;
13646 } else {
13647 vp = *findvar(hashvar(name), name);
13648 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020013649 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013650 continue;
13651 }
Eric Andersencb57d552001-06-28 07:25:16 +000013652 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013653 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013654 } while ((name = *++aptr) != NULL);
13655 return 0;
13656 }
Eric Andersencb57d552001-06-28 07:25:16 +000013657 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020013658
13659 /* No arguments. Show the list of exported or readonly vars.
13660 * -n is ignored.
13661 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013662 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000013663 return 0;
13664}
13665
Eric Andersencb57d552001-06-28 07:25:16 +000013666/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013667 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000013668 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013669static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013670unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000013671{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013672 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000013673
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013674 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013675 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000013676 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000013677}
13678
Eric Andersencb57d552001-06-28 07:25:16 +000013679/*
Eric Andersencb57d552001-06-28 07:25:16 +000013680 * The unset builtin command. We unset the function before we unset the
13681 * variable to allow a function to be unset when there is a readonly variable
13682 * with the same name.
13683 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013684static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013685unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000013686{
13687 char **ap;
13688 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013689 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013690
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013691 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000013692 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000013693 }
Eric Andersencb57d552001-06-28 07:25:16 +000013694
Denis Vlasenko2da584f2007-02-19 22:44:05 +000013695 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000013696 if (flag != 'f') {
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013697 unsetvar(*ap);
13698 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000013699 }
13700 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000013701 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000013702 }
Denys Vlasenkob28d4c32017-07-25 16:29:36 +020013703 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000013704}
13705
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000013706static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013707 ' ', offsetof(struct tms, tms_utime),
13708 '\n', offsetof(struct tms, tms_stime),
13709 ' ', offsetof(struct tms, tms_cutime),
13710 '\n', offsetof(struct tms, tms_cstime),
13711 0
13712};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013713static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013714timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013715{
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013716 unsigned clk_tck;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013717 const unsigned char *p;
13718 struct tms buf;
13719
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020013720 clk_tck = bb_clk_tck();
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013721
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013722 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013723 p = timescmd_str;
13724 do {
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013725 unsigned sec, frac;
13726 unsigned long t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013727 t = *(clock_t *)(((char *) &buf) + p[1]);
Denys Vlasenko11f2e992017-08-10 16:34:03 +020013728 sec = t / clk_tck;
13729 frac = t % clk_tck;
13730 out1fmt("%um%u.%03us%c",
13731 sec / 60, sec % 60,
13732 (frac * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013733 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013734 p += 2;
13735 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000013736
Eric Andersencb57d552001-06-28 07:25:16 +000013737 return 0;
13738}
13739
Denys Vlasenko0b883582016-12-23 16:49:07 +010013740#if ENABLE_FEATURE_SH_MATH
Eric Andersenc470f442003-07-28 09:56:35 +000013741/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013742 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013743 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013744 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013745 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013746 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013747static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013748letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013749{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013750 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013751
Denis Vlasenko68404f12008-03-17 09:00:54 +000013752 argv++;
13753 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013754 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013755 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013756 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013757 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013758
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013759 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013760}
Eric Andersenc470f442003-07-28 09:56:35 +000013761#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013762
Eric Andersenc470f442003-07-28 09:56:35 +000013763/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013764 * The read builtin. Options:
13765 * -r Do not interpret '\' specially
13766 * -s Turn off echo (tty only)
13767 * -n NCHARS Read NCHARS max
13768 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13769 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13770 * -u FD Read from given FD instead of fd 0
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013771 * -d DELIM End on DELIM char, not newline
Eric Andersenc470f442003-07-28 09:56:35 +000013772 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013773 * TODO: bash also has:
13774 * -a ARRAY Read into array[0],[1],etc
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013775 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013776 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013777static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013778readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013779{
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013780 struct builtin_read_params params;
Denys Vlasenko73067272010-01-12 22:11:24 +010013781 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013782 int i;
13783
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013784 memset(&params, 0, sizeof(params));
13785
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013786 while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013787 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013788 case 'p':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013789 params.opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013790 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013791 case 'n':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013792 params.opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013793 break;
13794 case 's':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013795 params.read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013796 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013797 case 't':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013798 params.opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013799 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013800 case 'r':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013801 params.read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013802 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013803 case 'u':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013804 params.opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013805 break;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013806#if BASH_READ_D
13807 case 'd':
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013808 params.opt_d = optionarg;
Johannes Schindelin3bef5d82017-08-08 16:46:39 +020013809 break;
13810#endif
Paul Fox02eb9342005-09-07 16:56:02 +000013811 default:
13812 break;
13813 }
Eric Andersenc470f442003-07-28 09:56:35 +000013814 }
Paul Fox02eb9342005-09-07 16:56:02 +000013815
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013816 params.argv = argptr;
13817 params.setvar = setvar0;
13818 params.ifs = bltinlookup("IFS"); /* can be NULL */
13819
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013820 /* "read -s" needs to save/restore termios, can't allow ^C
13821 * to jump out of it.
13822 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013823 again:
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013824 INT_OFF;
Denys Vlasenko19358cc2018-08-05 15:42:29 +020013825 r = shell_builtin_read(&params);
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013826 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013827
Denys Vlasenkof5470412017-05-22 19:34:45 +020013828 if ((uintptr_t)r == 1 && errno == EINTR) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013829 /* To get SIGCHLD: sleep 1 & read x; echo $x
13830 * Correct behavior is to not exit "read"
13831 */
Denys Vlasenkof5470412017-05-22 19:34:45 +020013832 if (pending_sig == 0)
13833 goto again;
13834 }
13835
Denys Vlasenko73067272010-01-12 22:11:24 +010013836 if ((uintptr_t)r > 1)
13837 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013838
Denys Vlasenko73067272010-01-12 22:11:24 +010013839 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013840}
13841
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013842static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013843umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013844{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013845 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013846
Eric Andersenc470f442003-07-28 09:56:35 +000013847 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013848 int symbolic_mode = 0;
13849
13850 while (nextopt("S") != '\0') {
13851 symbolic_mode = 1;
13852 }
13853
Denis Vlasenkob012b102007-02-19 22:43:01 +000013854 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013855 mask = umask(0);
13856 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013857 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013858
Denys Vlasenko6283f982015-10-07 16:56:20 +020013859 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013860 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013861 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013862 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013863 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013864
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013865 i = 2;
13866 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013867 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013868 *p++ = permuser[i];
13869 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013870 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013871 if (!(mask & 0400)) *p++ = 'r';
13872 if (!(mask & 0200)) *p++ = 'w';
13873 if (!(mask & 0100)) *p++ = 'x';
13874 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013875 if (--i < 0)
13876 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013877 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013878 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013879 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013880 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013881 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013882 }
13883 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013884 char *modestr = *argptr;
Denys Vlasenko14c85eb2017-10-12 19:40:47 +020013885 /* numeric umasks are taken as-is */
13886 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
Denys Vlasenko6283f982015-10-07 16:56:20 +020013887 if (!isdigit(modestr[0]))
13888 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013889 mask = bb_parse_mode(modestr, mask);
13890 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013891 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013892 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013893 if (!isdigit(modestr[0]))
13894 mask ^= 0777;
13895 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013896 }
13897 return 0;
13898}
13899
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013900static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013901ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013902{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013903 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013904}
13905
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013906/* ============ main() and helpers */
13907
13908/*
13909 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013910 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013911static void
13912exitshell(void)
13913{
13914 struct jmploc loc;
13915 char *p;
13916 int status;
13917
Denys Vlasenkobede2152011-09-04 16:12:33 +020013918#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13919 save_history(line_input_state);
13920#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013921 status = exitstatus;
13922 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13923 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013924 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013925 status = exitstatus;
13926 goto out;
13927 }
13928 exception_handler = &loc;
13929 p = trap[0];
13930 if (p) {
13931 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013932 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013933 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013934 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013935 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013936 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013937 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13938 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13939 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013940 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013941 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013942 _exit(status);
13943 /* NOTREACHED */
13944}
13945
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013946/* Don't inline: conserve stack of caller from having our locals too */
13947static NOINLINE void
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013948init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013949{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013950 /* we will never free this */
13951 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denys Vlasenko0485b672017-08-14 19:46:56 +020013952 basepf.linno = 1;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013953
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020013954 sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
Denys Vlasenko458c1f22016-10-27 23:51:19 +020013955 setsignal(SIGCHLD);
13956
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013957 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13958 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13959 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013960 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013961
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013962 {
13963 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013964 const char *p;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013965
13966 initvar();
13967 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenko9c143ce2017-11-02 12:56:24 +010013968/* Used to have
13969 * p = endofname(*envp);
13970 * if (p != *envp && *p == '=') {
13971 * here to weed out badly-named variables, but this breaks
13972 * scenarios where people do want them passed to children:
13973 * import os
13974 * os.environ["test-test"]="test"
13975 * if os.fork() == 0:
13976 * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this
13977 * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this
13978 */
13979 if (strchr(*envp, '=')) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013980 setvareq(*envp, VEXPORT|VTEXTFIXED);
13981 }
13982 }
13983
Denys Vlasenko67dae152018-08-05 13:59:35 +020013984 setvareq((char*)defifsvar, VTEXTFIXED);
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013985 setvareq((char*)defoptindvar, VTEXTFIXED);
13986
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013987 setvar0("PPID", utoa(getppid()));
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013988#if BASH_SHLVL_VAR
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013989 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013990 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko7d4aec02017-01-11 14:00:38 +010013991#endif
13992#if BASH_HOSTNAME_VAR
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013993 if (!lookupvar("HOSTNAME")) {
13994 struct utsname uts;
13995 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013996 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013997 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013998#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013999 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014000 if (p) {
Denys Vlasenko49e6bf22017-08-04 14:28:16 +020014001 struct stat st1, st2;
Denys Vlasenkoef159702016-09-01 11:16:22 +020014002 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014003 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
14004 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020014005 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014006 }
14007 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014008 setpwd(p, 0);
14009 }
14010}
14011
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014012
14013//usage:#define ash_trivial_usage
Denys Vlasenkof2ed39b2018-04-05 16:46:49 +020014014//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010014015//usage:#define ash_full_usage "\n\n"
14016//usage: "Unix shell interpreter"
14017
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014018/*
14019 * Process the shell command line arguments.
14020 */
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014021static int
Denis Vlasenko68404f12008-03-17 09:00:54 +000014022procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014023{
14024 int i;
14025 const char *xminusc;
14026 char **xargv;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014027 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014028
14029 xargv = argv;
Ron Yorston8767c122018-11-05 13:13:08 +000014030 login_sh = xargv[0] && xargv[0][0] == '-';
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014031#if NUM_SCRIPTS > 0
14032 if (minusc)
14033 goto setarg0;
14034#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014035 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000014036 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014037 xargv++;
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014038 argptr = xargv;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014039 for (i = 0; i < NOPTS; i++)
14040 optlist[i] = 2;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014041 if (options(/*cmdline:*/ 1, &login_sh)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000014042 /* it already printed err message */
14043 raise_exception(EXERROR);
14044 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014045 xargv = argptr;
14046 xminusc = minusc;
14047 if (*xargv == NULL) {
14048 if (xminusc)
14049 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
14050 sflag = 1;
14051 }
14052 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
14053 iflag = 1;
14054 if (mflag == 2)
14055 mflag = iflag;
14056 for (i = 0; i < NOPTS; i++)
14057 if (optlist[i] == 2)
14058 optlist[i] = 0;
14059#if DEBUG == 2
14060 debug = 1;
14061#endif
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014062 /* POSIX 1003.2: first arg after "-c CMD" is $0, remainder $1... */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014063 if (xminusc) {
14064 minusc = *xargv++;
14065 if (*xargv)
14066 goto setarg0;
14067 } else if (!sflag) {
14068 setinputfile(*xargv, 0);
14069 setarg0:
14070 arg0 = *xargv++;
14071 commandname = arg0;
14072 }
14073
14074 shellparam.p = xargv;
14075#if ENABLE_ASH_GETOPTS
14076 shellparam.optind = 1;
14077 shellparam.optoff = -1;
14078#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014079 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014080 while (*xargv) {
14081 shellparam.nparam++;
14082 xargv++;
14083 }
14084 optschanged();
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014085
14086 return login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014087}
14088
14089/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014090 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014091 */
14092static void
14093read_profile(const char *name)
14094{
Denys Vlasenko46999802017-07-29 21:12:29 +020014095 name = expandstr(name, DQSYNTAX);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014096 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
14097 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020014098 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014099 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014100}
14101
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014102/*
14103 * This routine is called when an error or an interrupt occurs in an
14104 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014105 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014106 */
14107static void
14108reset(void)
14109{
14110 /* from eval.c: */
14111 evalskip = 0;
14112 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014113
14114 /* from expand.c: */
14115 ifsfree();
14116
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014117 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000014118 g_parsefile->left_in_buffer = 0;
14119 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014120 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020014121
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014122 /* from redir.c: */
Denys Vlasenko1c79aeb2017-07-29 22:51:52 +020014123 unwindredir(NULL);
Denys Vlasenkob8ab27b2017-07-26 19:22:34 +020014124
14125 /* from var.c: */
Denys Vlasenko484fc202017-07-26 19:55:31 +020014126 unwindlocalvars(NULL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014127}
14128
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014129#if PROFILE
14130static short profile_buf[16384];
14131extern int etext();
14132#endif
14133
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000014134/*
14135 * Main routine. We initialize things, parse the arguments, execute
14136 * profiles if we're a login shell, and then call cmdloop to execute
14137 * commands. The setjmp call sets up the location to jump to when an
14138 * exception occurs. When an exception occurs the variable "state"
14139 * is used to figure out how far we had gotten.
14140 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000014141int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Ron Yorston8767c122018-11-05 13:13:08 +000014142#if NUM_SCRIPTS > 0
14143int ash_main(int argc, char **argv)
14144#else
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000014145int ash_main(int argc UNUSED_PARAM, char **argv)
Ron Yorston8767c122018-11-05 13:13:08 +000014146#endif
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014147/* note: 'argc' is used only if embedded scripts are enabled */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014148{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014149 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014150 struct jmploc jmploc;
14151 struct stackmark smark;
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014152 int login_sh;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014153
Denis Vlasenko01631112007-12-16 17:20:38 +000014154 /* Initialize global data */
14155 INIT_G_misc();
14156 INIT_G_memstack();
14157 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014158#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000014159 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000014160#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000014161 INIT_G_cmdtable();
14162
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014163#if PROFILE
14164 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
14165#endif
14166
14167#if ENABLE_FEATURE_EDITING
14168 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
14169#endif
14170 state = 0;
14171 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014172 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000014173 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014174
14175 reset();
14176
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014177 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014178 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020014179 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014180 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020014181 }
14182 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020014183 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020014184 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000014185
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014186 popstackmark(&smark);
14187 FORCE_INT_ON; /* enable interrupts */
14188 if (s == 1)
14189 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014190 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014191 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014192 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014193 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000014194 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014195 }
14196 exception_handler = &jmploc;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014197 rootpid = getpid();
14198
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014199 init();
14200 setstackmark(&smark);
Denys Vlasenko4f2ef4a2018-11-01 09:53:25 +010014201
14202#if NUM_SCRIPTS > 0
14203 if (argc < 0)
14204 /* Non-NULL minusc tells procargs that an embedded script is being run */
14205 minusc = get_script_content(-argc - 1);
14206#endif
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014207 login_sh = procargs(argv);
Denys Vlasenko474ed062016-10-30 18:30:29 +010014208#if DEBUG
14209 TRACE(("Shell args: "));
14210 trace_puts_args(argv);
14211#endif
Denis Vlasenko68404f12008-03-17 09:00:54 +000014212
Denys Vlasenkoec05df12017-07-31 19:43:47 +020014213 if (login_sh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014214 const char *hp;
14215
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014216 state = 1;
14217 read_profile("/etc/profile");
14218 state1:
14219 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014220 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014221 if (hp)
14222 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014223 }
14224 state2:
14225 state = 3;
14226 if (
14227#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014228 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014229#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000014230 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014231 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014232 const char *shinit = lookupvar("ENV");
14233 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014234 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014235 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020014236 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014237 state3:
14238 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014239 if (minusc) {
14240 /* evalstring pushes parsefile stack.
14241 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000014242 * is one of stacked source fds.
14243 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020014244 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020014245 // ^^ not necessary since now we special-case fd 0
Denys Vlasenko035486c2017-07-31 04:09:19 +020014246 // in save_fd_on_redirect()
Denys Vlasenko1e3e2cc2017-07-25 20:31:14 +020014247 evalstring(minusc, sflag ? 0 : EV_EXIT);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014248 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014249
14250 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020014251#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000014252 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014253 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014254 if (!hp) {
14255 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010014256 if (hp) {
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014257 INT_OFF;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014258 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020014259 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014260 free((char*)hp);
Denys Vlasenko5f7c82b2017-02-03 13:00:06 +010014261 INT_ON;
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010014262 hp = lookupvar("HISTFILE");
14263 }
14264 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000014265 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014266 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020014267# if ENABLE_FEATURE_SH_HISTFILESIZE
14268 hp = lookupvar("HISTFILESIZE");
14269 line_input_state->max_history = size_from_HISTFILESIZE(hp);
14270# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014271 }
14272#endif
14273 state4: /* XXX ??? - why isn't this before the "if" statement */
14274 cmdloop(1);
14275 }
14276#if PROFILE
14277 monitor(0);
14278#endif
14279#ifdef GPROF
14280 {
14281 extern void _mcleanup(void);
14282 _mcleanup();
14283 }
14284#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020014285 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014286 exitshell();
14287 /* NOTREACHED */
14288}
14289
Denis Vlasenkoa624c112007-02-19 22:45:43 +000014290
Eric Andersendf82f612001-06-28 07:46:40 +000014291/*-
14292 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000014293 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000014294 *
14295 * This code is derived from software contributed to Berkeley by
14296 * Kenneth Almquist.
14297 *
14298 * Redistribution and use in source and binary forms, with or without
14299 * modification, are permitted provided that the following conditions
14300 * are met:
14301 * 1. Redistributions of source code must retain the above copyright
14302 * notice, this list of conditions and the following disclaimer.
14303 * 2. Redistributions in binary form must reproduce the above copyright
14304 * notice, this list of conditions and the following disclaimer in the
14305 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000014306 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000014307 * may be used to endorse or promote products derived from this software
14308 * without specific prior written permission.
14309 *
Denys Vlasenko95f79532017-08-02 14:26:33 +020014310 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
Eric Andersendf82f612001-06-28 07:46:40 +000014311 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14312 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14313 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14314 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14315 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14316 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14317 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14318 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14319 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14320 * SUCH DAMAGE.
14321 */